Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
8a6f72f
Initial commit of additional nodes for ESP32S3 chips.
h3lix1 Sep 23, 2025
c47ff75
Updating to 800 if psram_size is >4MB.
h3lix1 Sep 23, 2025
3ab8f31
Merge branch 'develop' into moar_nodes_esp32_s3
h3lix1 Sep 23, 2025
5e15067
Renaming node to coldNode to avoid shadowing.
h3lix1 Sep 23, 2025
fb9c31d
Merge branch 'develop' into moar_nodes_esp32_s3
h3lix1 Sep 25, 2025
8472b5b
Update to include heltec lora32 v4 nodes with 2MB psram
h3lix1 Sep 27, 2025
439b13b
Merge branch 'meshtastic:develop' into moar_nodes_esp32_s3
h3lix1 Sep 27, 2025
6cecf6f
Add moar stored messages when oflfine as well. Also using psram.
h3lix1 Sep 28, 2025
c457a83
Merge branch 'meshtastic:develop' into moar_nodes_esp32_s3
h3lix1 Sep 30, 2025
b206a69
Value updates to find the optimum size for memory available.
h3lix1 Sep 30, 2025
ba72308
Update when and how memory is allocated.
h3lix1 Oct 1, 2025
f1248ab
Merge branch 'meshtastic:develop' into moar_nodes_esp32_s3
h3lix1 Oct 2, 2025
196be39
Reduced phone rx backlog to 100 due to slowness of bluetooth
h3lix1 Oct 2, 2025
446b5d3
Adding PacketRecord to PSRAM as well as part of this change.
h3lix1 Oct 3, 2025
b3ad956
Merge branch 'develop' into moar_nodes_esp32_s3
h3lix1 Oct 3, 2025
59e8366
Added more logging around packet history, to show where memory is all…
h3lix1 Oct 3, 2025
9540b4a
Merge branch 'develop' into moar_nodes_esp32_s3
thebentern Oct 3, 2025
566775b
Merge branch 'moar_nodes_esp32_s3' of github.com:h3lix1/mesh-firmware…
h3lix1 Oct 3, 2025
804aa21
Merge branch 'meshtastic:develop' into moar_nodes_esp32_s3
h3lix1 Oct 5, 2025
c894e47
Merge branch 'develop' into moar_nodes_esp32_s3
h3lix1 Oct 8, 2025
825d333
Saving node role as a NodeHotentry
h3lix1 Oct 13, 2025
6b1662f
removing bitfield and making its only entry a flag. (saves 4 bits)
h3lix1 Oct 13, 2025
8807abf
Merge branch 'develop' into moar_nodes_esp32_s3
h3lix1 Oct 14, 2025
954788a
Initial commit of additional nodes for ESP32S3 chips.
h3lix1 Sep 23, 2025
19d59a1
Updating to 800 if psram_size is >4MB.
h3lix1 Sep 23, 2025
1d896f1
Renaming node to coldNode to avoid shadowing.
h3lix1 Sep 23, 2025
344263d
Update to include heltec lora32 v4 nodes with 2MB psram
h3lix1 Sep 27, 2025
2e4f1a0
Add moar stored messages when oflfine as well. Also using psram.
h3lix1 Sep 28, 2025
131c949
Value updates to find the optimum size for memory available.
h3lix1 Sep 30, 2025
01a848c
Update when and how memory is allocated.
h3lix1 Oct 1, 2025
05c05ac
Reduced phone rx backlog to 100 due to slowness of bluetooth
h3lix1 Oct 2, 2025
6611087
Adding PacketRecord to PSRAM as well as part of this change.
h3lix1 Oct 3, 2025
659e559
Added more logging around packet history, to show where memory is all…
h3lix1 Oct 3, 2025
790ab9b
Saving node role as a NodeHotentry
h3lix1 Oct 13, 2025
26daa3d
removing bitfield and making its only entry a flag. (saves 4 bits)
h3lix1 Oct 13, 2025
5ae3cb6
Merge branch 'meshtastic:develop' into moar_nodes_esp32_s3
h3lix1 Oct 21, 2025
3dcbada
Merge branch 'moar_nodes_esp32_s3' of github.com:h3lix1/mesh-firmware…
h3lix1 Oct 22, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 43 additions & 8 deletions src/DebugConfiguration.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,12 +53,42 @@ extern MemGet memGet;
#define LOG_TRACE(...) SEGGER_RTT_printf(0, __VA_ARGS__)
#else
#if defined(DEBUG_PORT) && !defined(DEBUG_MUTE)
#define LOG_DEBUG(...) DEBUG_PORT.log(MESHTASTIC_LOG_LEVEL_DEBUG, __VA_ARGS__)
#define LOG_INFO(...) DEBUG_PORT.log(MESHTASTIC_LOG_LEVEL_INFO, __VA_ARGS__)
#define LOG_WARN(...) DEBUG_PORT.log(MESHTASTIC_LOG_LEVEL_WARN, __VA_ARGS__)
#define LOG_ERROR(...) DEBUG_PORT.log(MESHTASTIC_LOG_LEVEL_ERROR, __VA_ARGS__)
#define LOG_CRIT(...) DEBUG_PORT.log(MESHTASTIC_LOG_LEVEL_CRIT, __VA_ARGS__)
#define LOG_TRACE(...) DEBUG_PORT.log(MESHTASTIC_LOG_LEVEL_TRACE, __VA_ARGS__)
#define LOG_DEBUG(...) \
do { \
if (console) { \
console->log(MESHTASTIC_LOG_LEVEL_DEBUG, __VA_ARGS__); \
} \
} while (0)
#define LOG_INFO(...) \
do { \
if (console) { \
console->log(MESHTASTIC_LOG_LEVEL_INFO, __VA_ARGS__); \
} \
} while (0)
#define LOG_WARN(...) \
do { \
if (console) { \
console->log(MESHTASTIC_LOG_LEVEL_WARN, __VA_ARGS__); \
} \
} while (0)
#define LOG_ERROR(...) \
do { \
if (console) { \
console->log(MESHTASTIC_LOG_LEVEL_ERROR, __VA_ARGS__); \
} \
} while (0)
#define LOG_CRIT(...) \
do { \
if (console) { \
console->log(MESHTASTIC_LOG_LEVEL_CRIT, __VA_ARGS__); \
} \
} while (0)
#define LOG_TRACE(...) \
do { \
if (console) { \
console->log(MESHTASTIC_LOG_LEVEL_TRACE, __VA_ARGS__); \
} \
} while (0)
#else
#define LOG_DEBUG(...)
#define LOG_INFO(...)
Expand All @@ -70,7 +100,12 @@ extern MemGet memGet;
#endif

#if defined(DEBUG_HEAP)
#define LOG_HEAP(...) DEBUG_PORT.log(MESHTASTIC_LOG_LEVEL_HEAP, __VA_ARGS__)
#define LOG_HEAP(...) \
do { \
if (console) { \
console->log(MESHTASTIC_LOG_LEVEL_HEAP, __VA_ARGS__); \
} \
} while (0)

// Macro-based heap debugging
#define DEBUG_HEAP_BEFORE auto heapBefore = memGet.getFreeHeap();
Expand Down Expand Up @@ -195,4 +230,4 @@ class Syslog
bool vlogf(uint16_t pri, const char *appName, const char *fmt, va_list args) __attribute__((format(printf, 3, 0)));
};

#endif // HAS_NETWORKING
#endif // HAS_NETWORKING
16 changes: 8 additions & 8 deletions src/NodeStatus.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,16 @@ class NodeStatus : public Status
CallbackObserver<NodeStatus, const NodeStatus *> statusObserver =
CallbackObserver<NodeStatus, const NodeStatus *>(this, &NodeStatus::updateStatus);

uint8_t numOnline = 0;
uint8_t numTotal = 0;
uint16_t numOnline = 0;
uint16_t numTotal = 0;

uint8_t lastNumTotal = 0;
uint16_t lastNumTotal = 0;

public:
bool forceUpdate = false;

NodeStatus() { statusType = STATUS_TYPE_NODE; }
NodeStatus(uint8_t numOnline, uint8_t numTotal, bool forceUpdate = false) : Status()
NodeStatus(uint16_t numOnline, uint16_t numTotal, bool forceUpdate = false) : Status()
{
this->forceUpdate = forceUpdate;
this->numOnline = numOnline;
Expand All @@ -34,11 +34,11 @@ class NodeStatus : public Status

void observe(Observable<const NodeStatus *> *source) { statusObserver.observe(source); }

uint8_t getNumOnline() const { return numOnline; }
uint16_t getNumOnline() const { return numOnline; }

uint8_t getNumTotal() const { return numTotal; }
uint16_t getNumTotal() const { return numTotal; }

uint8_t getLastNumTotal() const { return lastNumTotal; }
uint16_t getLastNumTotal() const { return lastNumTotal; }

bool matches(const NodeStatus *newStatus) const
{
Expand All @@ -65,4 +65,4 @@ class NodeStatus : public Status

} // namespace meshtastic

extern meshtastic::NodeStatus *nodeStatus;
extern meshtastic::NodeStatus *nodeStatus;
6 changes: 3 additions & 3 deletions src/graphics/niche/InkHUD/Applets/Bases/Map/MapApplet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,7 @@ void InkHUD::MapApplet::getMapCenter(float *lat, float *lng)
float easternmost = lngCenter;
float westernmost = lngCenter;

for (uint8_t i = 0; i < nodeDB->getNumMeshNodes(); i++) {
for (size_t i = 0; i < nodeDB->getNumMeshNodes(); i++) {
meshtastic_NodeInfoLite *node = nodeDB->getMeshNodeByIndex(i);

// Skip if no position
Expand Down Expand Up @@ -475,7 +475,7 @@ void InkHUD::MapApplet::drawLabeledMarker(meshtastic_NodeInfoLite *node)
bool InkHUD::MapApplet::enoughMarkers()
{
uint8_t count = 0;
for (uint8_t i = 0; i < nodeDB->getNumMeshNodes(); i++) {
for (size_t i = 0; i < nodeDB->getNumMeshNodes(); i++) {
meshtastic_NodeInfoLite *node = nodeDB->getMeshNodeByIndex(i);

// Count nodes
Expand Down Expand Up @@ -555,4 +555,4 @@ void InkHUD::MapApplet::drawCross(int16_t x, int16_t y, uint8_t size)
drawLine(x0, y1, x1, y0, BLACK);
}

#endif
#endif
4 changes: 2 additions & 2 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -295,7 +295,7 @@ void printInfo()
{
LOG_INFO("S:B:%d,%s,%s,%s", HW_VENDOR, optstr(APP_VERSION), optstr(APP_ENV), optstr(APP_REPO));
}
#ifndef PIO_UNIT_TESTING
#if !defined(PIO_UNIT_TESTING) || !(PIO_UNIT_TESTING)
void setup()
{
#if defined(R1_NEO)
Expand Down Expand Up @@ -1573,7 +1573,7 @@ void scannerToSensorsMap(const std::unique_ptr<ScanI2CTwoWire> &i2cScanner, Scan
}
#endif

#ifndef PIO_UNIT_TESTING
#if !defined(PIO_UNIT_TESTING) || !(PIO_UNIT_TESTING)
void loop()
{
runASAP = false;
Expand Down
93 changes: 93 additions & 0 deletions src/mesh/MemoryPool.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@
#include "PointerQueue.h"
#include "configuration.h" // For LOG_WARN, LOG_DEBUG, LOG_HEAP

#if defined(ARCH_ESP32)
#include <esp_heap_caps.h>
#endif

template <class T> class Allocator
{

Expand Down Expand Up @@ -159,3 +163,92 @@ template <class T, int MaxSize> class MemoryPool : public Allocator<T>
return nullptr;
}
};

#if defined(ARCH_ESP32)
// Simple fixed-size allocator that uses PSRAM. Used on ESP32-S3 builds so the
// large MeshPacket pool can live off-chip and free internal RAM.
template <class T, int MaxSize> class PsramMemoryPool : public Allocator<T>
{
private:
T *pool;
bool used[MaxSize];

public:
PsramMemoryPool() : pool(nullptr), used{}
{
pool = static_cast<T *>(heap_caps_malloc(sizeof(T) * MaxSize, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT));
if (pool) {
memset(pool, 0, sizeof(T) * MaxSize);
} else {
LOG_WARN("Failed to allocate PSRAM pool of %d elements", MaxSize);
}
}

~PsramMemoryPool() override
{
if (pool) {
heap_caps_free(pool);
}
}

bool isValid() const { return pool != nullptr; }

void release(T *p) override
{
if (!pool || !p) {
LOG_DEBUG("Failed to release PSRAM memory, pointer is null or pool unavailable");
return;
}

int index = static_cast<int>(p - pool);
if (index >= 0 && index < MaxSize) {
assert(used[index]);
used[index] = false;
LOG_HEAP("Released PSRAM pool item %d at 0x%x", index, p);
} else {
LOG_WARN("Pointer 0x%x not from PSRAM pool!", p);
}
}

protected:
T *alloc(TickType_t maxWait) override
{
if (!pool)
return nullptr;

for (int i = 0; i < MaxSize; i++) {
if (!used[i]) {
used[i] = true;
LOG_HEAP("Allocated PSRAM pool item %d at 0x%x", i, &pool[i]);
return &pool[i];
}
}

LOG_WARN("No free slots available in PSRAM memory pool!");
return nullptr;
}
};

// Utility helpers for PSRAM-backed array allocations on ESP32 targets.
template <typename T> inline T *psramAllocArray(size_t count)
{
return static_cast<T *>(heap_caps_malloc(sizeof(T) * count, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT));
}

template <typename T> inline void psramFreeArray(T *ptr)
{
if (ptr)
heap_caps_free(ptr);
}
#else
template <typename T> inline T *psramAllocArray(size_t count)
{
(void)count;
return nullptr;
}

template <typename T> inline void psramFreeArray(T *ptr)
{
(void)ptr;
}
#endif
12 changes: 9 additions & 3 deletions src/mesh/MeshService.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -305,15 +305,21 @@ void MeshService::sendToPhone(meshtastic_MeshPacket *p)
#endif
#endif

if (toPhoneQueue.numFree() == 0) {
// MAX_RX_TOPHONE is sized for PSRAM-backed builds. Fall back to a smaller
// runtime limit if the helper detects <2MB of PSRAM at boot.
const int queueLimit = get_rx_tophone_limit();
const bool runtimeLimitReached = queueLimit > 0 && toPhoneQueue.numUsed() >= queueLimit;

if (toPhoneQueue.numFree() == 0 || runtimeLimitReached) {
const bool runtimeControlled = runtimeLimitReached && queueLimit < MAX_RX_TOPHONE;
if (p->decoded.portnum == meshtastic_PortNum_TEXT_MESSAGE_APP ||
p->decoded.portnum == meshtastic_PortNum_RANGE_TEST_APP) {
LOG_WARN("ToPhone queue is full, discard oldest");
LOG_WARN("ToPhone queue %s, discard oldest", runtimeControlled ? "reached runtime limit" : "is full");
meshtastic_MeshPacket *d = toPhoneQueue.dequeuePtr(0);
if (d)
releaseToPool(d);
} else {
LOG_WARN("ToPhone queue is full, drop packet");
LOG_WARN("ToPhone queue %s, drop packet", runtimeControlled ? "reached runtime limit" : "is full");
releaseToPool(p);
fromNum++; // Make sure to notify observers in case they are reconnected so they can get the packets
return;
Expand Down
Loading