diff --git a/src/DebugConfiguration.h b/src/DebugConfiguration.h index 26f2db1f4..98bbe0f72 100644 --- a/src/DebugConfiguration.h +++ b/src/DebugConfiguration.h @@ -2,6 +2,12 @@ #include "configuration.h" +// Forward declarations +#if defined(DEBUG_HEAP) +class MemGet; +extern MemGet memGet; +#endif + // DEBUG LED #ifndef LED_STATE_ON #define LED_STATE_ON 1 @@ -65,8 +71,21 @@ #if defined(DEBUG_HEAP) #define LOG_HEAP(...) DEBUG_PORT.log(MESHTASTIC_LOG_LEVEL_HEAP, __VA_ARGS__) + +// Macro-based heap debugging +#define DEBUG_HEAP_BEFORE auto heapBefore = memGet.getFreeHeap(); +#define DEBUG_HEAP_AFTER(context, ptr) \ + do { \ + auto heapAfter = memGet.getFreeHeap(); \ + if (heapBefore != heapAfter) { \ + LOG_HEAP("Alloc in %s pointer 0x%x, size: %u, free: %u", context, ptr, heapBefore - heapAfter, heapAfter); \ + } \ + } while (0) + #else #define LOG_HEAP(...) +#define DEBUG_HEAP_BEFORE +#define DEBUG_HEAP_AFTER(context, ptr) #endif /// A C wrapper for LOG_DEBUG that can be used from arduino C libs that don't know about C++ or meshtastic diff --git a/src/memGet.cpp b/src/memGet.cpp index e8cd177dd..14e614014 100644 --- a/src/memGet.cpp +++ b/src/memGet.cpp @@ -88,4 +88,16 @@ uint32_t MemGet::getPsramSize() #else return 0; #endif +} + +void displayPercentHeapFree() +{ + uint32_t freeHeap = memGet.getFreeHeap(); + uint32_t totalHeap = memGet.getHeapSize(); + if (totalHeap == 0 || totalHeap == UINT32_MAX) { + LOG_INFO("Heap size unavailable"); + return; + } + int percent = (int)((freeHeap * 100) / totalHeap); + LOG_INFO("Heap free: %d%% (%u/%u bytes)", percent, freeHeap, totalHeap); } \ No newline at end of file diff --git a/src/mesh/MeshService.cpp b/src/mesh/MeshService.cpp index 157a2eda3..607766ab6 100644 --- a/src/mesh/MeshService.cpp +++ b/src/mesh/MeshService.cpp @@ -193,11 +193,9 @@ void MeshService::handleToRadio(meshtastic_MeshPacket &p) // (so we update our nodedb for the local node) // Send the packet into the mesh - auto heapBefore = memGet.getFreeHeap(); + DEBUG_HEAP_BEFORE; auto a = packetPool.allocCopy(p); - auto heapAfter = memGet.getFreeHeap(); - LOG_HEAP("Alloc in MeshService::handleToRadio() pointer 0x%x, size: %u, free: %u", a, heapBefore - heapAfter, heapAfter); - + DEBUG_HEAP_AFTER("MeshService::handleToRadio", a); sendToMesh(a, RX_SRC_USER); bool loopback = false; // if true send any packet the phone sends back itself (for testing) @@ -254,10 +252,9 @@ void MeshService::sendToMesh(meshtastic_MeshPacket *p, RxSource src, bool ccToPh } if ((res == ERRNO_OK || res == ERRNO_SHOULD_RELEASE) && ccToPhone) { // Check if p is not released in case it couldn't be sent - auto heapBefore = memGet.getFreeHeap(); + DEBUG_HEAP_BEFORE; auto a = packetPool.allocCopy(*p); - auto heapAfter = memGet.getFreeHeap(); - LOG_HEAP("Alloc in MeshService::sendToMesh() pointer 0x%x, size: %u, free: %u", a, heapBefore - heapAfter, heapAfter); + DEBUG_HEAP_AFTER("MeshService::sendToMesh", a); sendToPhone(a); } diff --git a/src/mesh/ReliableRouter.cpp b/src/mesh/ReliableRouter.cpp index 890d42b00..6d098b669 100644 --- a/src/mesh/ReliableRouter.cpp +++ b/src/mesh/ReliableRouter.cpp @@ -22,10 +22,9 @@ ErrorCode ReliableRouter::send(meshtastic_MeshPacket *p) if (p->hop_limit == 0) { p->hop_limit = Default::getConfiguredOrDefaultHopLimit(config.lora.hop_limit); } - auto heapBefore = memGet.getFreeHeap(); + DEBUG_HEAP_BEFORE; auto copy = packetPool.allocCopy(*p); - auto heapAfter = memGet.getFreeHeap(); - LOG_HEAP("Alloc in ReliableRouter::send() pointer 0x%x, size: %u, free: %u", copy, heapBefore - heapAfter, heapAfter); + DEBUG_HEAP_AFTER("ReliableRouter::send", copy); startRetransmission(copy, NUM_RELIABLE_RETX); } diff --git a/src/mesh/Router.cpp b/src/mesh/Router.cpp index 603dfda4a..4442b5d50 100644 --- a/src/mesh/Router.cpp +++ b/src/mesh/Router.cpp @@ -276,11 +276,9 @@ ErrorCode Router::send(meshtastic_MeshPacket *p) if (p->which_payload_variant == meshtastic_MeshPacket_decoded_tag) { ChannelIndex chIndex = p->channel; // keep as a local because we are about to change it - auto heapBefore = memGet.getFreeHeap(); + DEBUG_HEAP_BEFORE; meshtastic_MeshPacket *p_decoded = packetPool.allocCopy(*p); - auto heapAfter = memGet.getFreeHeap(); - - LOG_HEAP("Alloc in Router::send pointer 0x%x, size: %u, free: %u", p_decoded, heapBefore - heapAfter, heapAfter); + DEBUG_HEAP_AFTER("Router::send", p_decoded); auto encodeResult = perhapsEncode(p); if (encodeResult != meshtastic_Routing_Error_NONE) { @@ -612,11 +610,11 @@ void Router::handleReceived(meshtastic_MeshPacket *p, RxSource src) bool skipHandle = false; // Also, we should set the time from the ISR and it should have msec level resolution p->rx_time = getValidTime(RTCQualityFromNet); // store the arrival timestamp for the phone + // Store a copy of encrypted packet for MQTT - auto heapBefore = memGet.getFreeHeap(); + DEBUG_HEAP_BEFORE; meshtastic_MeshPacket *p_encrypted = packetPool.allocCopy(*p); - auto heapAfter = memGet.getFreeHeap(); - LOG_HEAP("Alloc in Router::handleReceived pointer 0x%x, size: %u, free: %u", p_encrypted, heapBefore - heapAfter, heapAfter); + DEBUG_HEAP_AFTER("Router::handleReceived", p_encrypted); // Take those raw bytes and convert them back into a well structured protobuf we can understand auto decodedState = perhapsDecode(p); diff --git a/src/modules/NodeInfoModule.cpp b/src/modules/NodeInfoModule.cpp index 82632f667..86ceaae24 100644 --- a/src/modules/NodeInfoModule.cpp +++ b/src/modules/NodeInfoModule.cpp @@ -44,11 +44,10 @@ void NodeInfoModule::sendOurNodeInfo(NodeNum dest, bool wantReplies, uint8_t cha if (prevPacketId) // if we wrap around to zero, we'll simply fail to cancel in that rare case (no big deal) service->cancelSending(prevPacketId); shorterTimeout = _shorterTimeout; - auto heapBefore = memGet.getFreeHeap(); + DEBUG_HEAP_BEFORE; meshtastic_MeshPacket *p = allocReply(); - auto heapAfter = memGet.getFreeHeap(); + DEBUG_HEAP_AFTER("NodeInfoModule::sendOurNodeInfo", p); - LOG_HEAP("Alloc in NodeInfoModule::sendOurNodeInfo pointer 0x%x, size: %u, free: %u", p, heapBefore - heapAfter, heapAfter); if (p) { // Check whether we didn't ignore it p->to = dest; p->decoded.want_response = (config.device.role != meshtastic_Config_DeviceConfig_Role_TRACKER && diff --git a/src/modules/Telemetry/DeviceTelemetry.cpp b/src/modules/Telemetry/DeviceTelemetry.cpp index 8694de993..98d5b19d0 100644 --- a/src/modules/Telemetry/DeviceTelemetry.cpp +++ b/src/modules/Telemetry/DeviceTelemetry.cpp @@ -172,11 +172,9 @@ bool DeviceTelemetryModule::sendTelemetry(NodeNum dest, bool phoneOnly) telemetry.variant.device_metrics.battery_level, telemetry.variant.device_metrics.voltage, telemetry.variant.device_metrics.uptime_seconds); - auto heapBefore = memGet.getFreeHeap(); + DEBUG_HEAP_BEFORE; meshtastic_MeshPacket *p = allocDataProtobuf(telemetry); - auto heapAfter = memGet.getFreeHeap(); - LOG_HEAP("Alloc in DeviceTelemetryModule::sendTelemetry() pointer 0x%x, size: %u, free: %u", p, heapBefore - heapAfter, - heapAfter); + DEBUG_HEAP_AFTER("DeviceTelemetryModule::sendTelemetry", p); p->to = dest; p->decoded.want_response = false;