diff --git a/src/mesh/MemoryPool.h b/src/mesh/MemoryPool.h index c77227904..0784d8c94 100644 --- a/src/mesh/MemoryPool.h +++ b/src/mesh/MemoryPool.h @@ -228,4 +228,27 @@ template class PsramMemoryPool : public Allocator return nullptr; } }; + +// Utility helpers for PSRAM-backed array allocations on ESP32 targets. +template inline T *psramAllocArray(size_t count) +{ + return static_cast(heap_caps_malloc(sizeof(T) * count, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT)); +} + +template inline void psramFreeArray(T *ptr) +{ + if (ptr) + heap_caps_free(ptr); +} +#else +template inline T *psramAllocArray(size_t count) +{ + (void)count; + return nullptr; +} + +template inline void psramFreeArray(T *ptr) +{ + (void)ptr; +} #endif diff --git a/src/mesh/PacketHistory.cpp b/src/mesh/PacketHistory.cpp index 49d581d9a..0c3736faf 100644 --- a/src/mesh/PacketHistory.cpp +++ b/src/mesh/PacketHistory.cpp @@ -1,4 +1,5 @@ #include "PacketHistory.h" +#include "MemoryPool.h" #include "configuration.h" #include "mesh-pb-constants.h" @@ -16,7 +17,8 @@ #define VERBOSE_PACKET_HISTORY 0 // Set to 1 for verbose logging, 2 for heavy debugging #define PACKET_HISTORY_TRACE_AGING 1 // Set to 1 to enable logging of the age of re/used history slots -PacketHistory::PacketHistory(uint32_t size) : recentPacketsCapacity(0), recentPackets(NULL) // Initialize members +PacketHistory::PacketHistory(uint32_t size) + : recentPacketsCapacity(0), recentPackets(NULL), recentPacketsInPsram(false) // Initialize members { if (size < 4 || size > PACKETHISTORY_MAX) { // Copilot suggested - makes sense LOG_WARN("Packet History - Invalid size %d, using default %d", size, PACKETHISTORY_MAX); @@ -25,23 +27,45 @@ PacketHistory::PacketHistory(uint32_t size) : recentPacketsCapacity(0), recentPa // Allocate memory for the recent packets array recentPacketsCapacity = size; - recentPackets = new PacketRecord[recentPacketsCapacity]; - if (!recentPackets) { // No logging here, console/log probably uninitialized yet. - LOG_ERROR("Packet History - Memory allocation failed for size=%d entries / %d Bytes", size, - sizeof(PacketRecord) * recentPacketsCapacity); - recentPacketsCapacity = 0; // mark allocation fail - return; // return early + if (has_psram()) { + // Prefer PSRAM so the large history pool stays out of internal RAM on ESP32-S3 builds. + recentPackets = psramAllocArray(recentPacketsCapacity); + if (recentPackets) { + memset(recentPackets, 0, sizeof(PacketRecord) * recentPacketsCapacity); + recentPacketsInPsram = true; + } else { + LOG_WARN("Packet History - PSRAM allocation failed, falling back to DRAM"); + } } - // Initialize the recent packets array to zero - memset(recentPackets, 0, sizeof(PacketRecord) * recentPacketsCapacity); + if (!recentPackets) { + // Fall back to DRAM if PSRAM is unavailable or exhausted. + recentPackets = new PacketRecord[recentPacketsCapacity]; + if (!recentPackets) { // No logging here, console/log probably uninitialized yet. + LOG_ERROR("Packet History - Memory allocation failed for size=%d entries / %d Bytes", size, + sizeof(PacketRecord) * recentPacketsCapacity); + recentPacketsCapacity = 0; // mark allocation fail + return; // return early + } + + // Initialize the recent packets array to zero + memset(recentPackets, 0, sizeof(PacketRecord) * recentPacketsCapacity); + } } PacketHistory::~PacketHistory() { - recentPacketsCapacity = 0; - delete[] recentPackets; + if (recentPackets) { + // Release via the allocator that produced the buffer. + if (recentPacketsInPsram) + psramFreeArray(recentPackets); + else + delete[] recentPackets; + } + recentPackets = NULL; + recentPacketsCapacity = 0; + recentPacketsInPsram = false; } /** Update recentPackets and return true if we have already seen this packet */ @@ -458,4 +482,4 @@ inline uint8_t PacketHistory::getOurTxHopLimit(PacketRecord &r) inline void PacketHistory::setOurTxHopLimit(PacketRecord &r, uint8_t hopLimit) { r.hop_limit = (r.hop_limit & ~HOP_LIMIT_OUR_TX_MASK) | ((hopLimit << HOP_LIMIT_OUR_TX_SHIFT) & HOP_LIMIT_OUR_TX_MASK); -} \ No newline at end of file +} diff --git a/src/mesh/PacketHistory.h b/src/mesh/PacketHistory.h index 5fbad2dc9..4f06ed4e0 100644 --- a/src/mesh/PacketHistory.h +++ b/src/mesh/PacketHistory.h @@ -27,6 +27,7 @@ class PacketHistory uint32_t recentPacketsCapacity = 0; // Can be set in constructor, no need to recompile. Used to allocate memory for mx_recentPackets. PacketRecord *recentPackets = NULL; // Simple and fixed in size. Debloat. + bool recentPacketsInPsram = false; // Remember backing store so we free via the matching allocator. /** Find a packet record in history. * @param sender NodeNum