mirror of
https://github.com/meshtastic/firmware.git
synced 2025-10-27 15:02:41 +00:00
Add moar stored messages when oflfine as well. Also using psram.
This commit is contained in:
parent
344263de86
commit
2e4f1a0216
@ -8,6 +8,10 @@
|
|||||||
#include "PointerQueue.h"
|
#include "PointerQueue.h"
|
||||||
#include "configuration.h" // For LOG_WARN, LOG_DEBUG, LOG_HEAP
|
#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
|
template <class T> class Allocator
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -159,3 +163,69 @@ template <class T, int MaxSize> class MemoryPool : public Allocator<T>
|
|||||||
return nullptr;
|
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;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|||||||
@ -305,15 +305,21 @@ void MeshService::sendToPhone(meshtastic_MeshPacket *p)
|
|||||||
#endif
|
#endif
|
||||||
#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 ||
|
if (p->decoded.portnum == meshtastic_PortNum_TEXT_MESSAGE_APP ||
|
||||||
p->decoded.portnum == meshtastic_PortNum_RANGE_TEST_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);
|
meshtastic_MeshPacket *d = toPhoneQueue.dequeuePtr(0);
|
||||||
if (d)
|
if (d)
|
||||||
releaseToPool(d);
|
releaseToPool(d);
|
||||||
} else {
|
} else {
|
||||||
LOG_WARN("ToPhone queue is full, drop packet");
|
LOG_WARN("ToPhone queue %s, drop packet", runtimeControlled ? "reached runtime limit" : "is full");
|
||||||
releaseToPool(p);
|
releaseToPool(p);
|
||||||
fromNum++; // Make sure to notify observers in case they are reconnected so they can get the packets
|
fromNum++; // Make sure to notify observers in case they are reconnected so they can get the packets
|
||||||
return;
|
return;
|
||||||
|
|||||||
@ -43,9 +43,19 @@ Allocator<meshtastic_MeshPacket> &packetPool = dynamicPool;
|
|||||||
(MAX_RX_TOPHONE + MAX_RX_FROMRADIO + 2 * MAX_TX_QUEUE + \
|
(MAX_RX_TOPHONE + MAX_RX_FROMRADIO + 2 * MAX_TX_QUEUE + \
|
||||||
2) // max number of packets which can be in flight (either queued from reception or queued for sending)
|
2) // max number of packets which can be in flight (either queued from reception or queued for sending)
|
||||||
|
|
||||||
|
#if defined(CONFIG_IDF_TARGET_ESP32S3)
|
||||||
|
// Try to put the heavy MeshPacket pool into PSRAM. If that fails we fall back to
|
||||||
|
// heap allocation so the radio stays functional (at the cost of fewer packets).
|
||||||
|
static PsramMemoryPool<meshtastic_MeshPacket, MAX_PACKETS_STATIC> psramPool;
|
||||||
|
static MemoryDynamic<meshtastic_MeshPacket> fallbackPool;
|
||||||
|
Allocator<meshtastic_MeshPacket> &packetPool = psramPool.isValid()
|
||||||
|
? static_cast<Allocator<meshtastic_MeshPacket> &>(psramPool)
|
||||||
|
: static_cast<Allocator<meshtastic_MeshPacket> &>(fallbackPool);
|
||||||
|
#else
|
||||||
static MemoryPool<meshtastic_MeshPacket, MAX_PACKETS_STATIC> staticPool;
|
static MemoryPool<meshtastic_MeshPacket, MAX_PACKETS_STATIC> staticPool;
|
||||||
Allocator<meshtastic_MeshPacket> &packetPool = staticPool;
|
Allocator<meshtastic_MeshPacket> &packetPool = staticPool;
|
||||||
#endif
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
static uint8_t bytes[MAX_LORA_PAYLOAD_LEN + 1] __attribute__((__aligned__));
|
static uint8_t bytes[MAX_LORA_PAYLOAD_LEN + 1] __attribute__((__aligned__));
|
||||||
|
|
||||||
@ -56,6 +66,14 @@ static uint8_t bytes[MAX_LORA_PAYLOAD_LEN + 1] __attribute__((__aligned__));
|
|||||||
*/
|
*/
|
||||||
Router::Router() : concurrency::OSThread("Router"), fromRadioQueue(MAX_RX_FROMRADIO)
|
Router::Router() : concurrency::OSThread("Router"), fromRadioQueue(MAX_RX_FROMRADIO)
|
||||||
{
|
{
|
||||||
|
#if defined(CONFIG_IDF_TARGET_ESP32S3)
|
||||||
|
if (!psramPool.isValid()) {
|
||||||
|
LOG_WARN("PSRAM packet pool unavailable, falling back to heap allocations");
|
||||||
|
}
|
||||||
|
if (!has_psram() && MAX_RX_TOPHONE > get_rx_tophone_limit()) {
|
||||||
|
LOG_WARN("Detected <2MB PSRAM, limiting phone queue to %d packets", get_rx_tophone_limit());
|
||||||
|
}
|
||||||
|
#endif
|
||||||
// This is called pre main(), don't touch anything here, the following code is not safe
|
// This is called pre main(), don't touch anything here, the following code is not safe
|
||||||
|
|
||||||
/* LOG_DEBUG("Size of NodeInfo %d", sizeof(NodeInfo));
|
/* LOG_DEBUG("Size of NodeInfo %d", sizeof(NodeInfo));
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include "memGet.h"
|
||||||
#include "mesh/generated/meshtastic/admin.pb.h"
|
#include "mesh/generated/meshtastic/admin.pb.h"
|
||||||
#include "mesh/generated/meshtastic/deviceonly.pb.h"
|
#include "mesh/generated/meshtastic/deviceonly.pb.h"
|
||||||
#include "mesh/generated/meshtastic/localonly.pb.h"
|
#include "mesh/generated/meshtastic/localonly.pb.h"
|
||||||
@ -11,11 +12,42 @@
|
|||||||
// Tricky macro to let you find the sizeof a type member
|
// Tricky macro to let you find the sizeof a type member
|
||||||
#define member_size(type, member) sizeof(((type *)0)->member)
|
#define member_size(type, member) sizeof(((type *)0)->member)
|
||||||
|
|
||||||
|
// Minimum PSRAM the firmware expects before enabling the "expanded" queues that
|
||||||
|
// rely on off-chip RAM instead of internal DRAM. Currently set to 2MB to
|
||||||
|
// accommodate Heltec WiFi LoRa 32 V4 boards (and others)
|
||||||
|
static constexpr size_t PSRAM_LARGE_THRESHOLD_BYTES = 2 * 1024 * 1024;
|
||||||
|
|
||||||
|
inline bool has_psram(size_t minimumBytes = PSRAM_LARGE_THRESHOLD_BYTES)
|
||||||
|
{
|
||||||
|
#if defined(ARCH_ESP32) || defined(ARCH_PORTDUINO)
|
||||||
|
return memGet.getPsramSize() >= minimumBytes;
|
||||||
|
#else
|
||||||
|
(void)minimumBytes;
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// Runtime cap used to keep the BLE message queue from overflowing low-memory
|
||||||
|
// S3 variants if PSRAM is smaller than expected or temporarily unavailable.
|
||||||
|
inline int get_rx_tophone_limit()
|
||||||
|
{
|
||||||
|
#if defined(CONFIG_IDF_TARGET_ESP32S3)
|
||||||
|
return has_psram() ? 200 : 32;
|
||||||
|
#elif defined(ARCH_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||||
|
return 8;
|
||||||
|
#else
|
||||||
|
return 32;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
/// max number of packets which can be waiting for delivery to android - note, this value comes from mesh.options protobuf
|
/// max number of packets which can be waiting for delivery to android - note, this value comes from mesh.options protobuf
|
||||||
// FIXME - max_count is actually 32 but we save/load this as one long string of preencoded MeshPacket bytes - not a big array in
|
// FIXME - max_count is actually 32 but we save/load this as one long string of preencoded MeshPacket bytes - not a big array in
|
||||||
// RAM #define MAX_RX_TOPHONE (member_size(DeviceState, receive_queue) / member_size(DeviceState, receive_queue[0]))
|
// RAM #define MAX_RX_TOPHONE (member_size(DeviceState, receive_queue) / member_size(DeviceState, receive_queue[0]))
|
||||||
#ifndef MAX_RX_TOPHONE
|
#ifndef MAX_RX_TOPHONE
|
||||||
#if defined(ARCH_ESP32) && !(defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32S3))
|
#if defined(CONFIG_IDF_TARGET_ESP32S3)
|
||||||
|
static constexpr int MAX_RX_TOPHONE_WITH_PSRAM = 200;
|
||||||
|
#define MAX_RX_TOPHONE MAX_RX_TOPHONE_WITH_PSRAM
|
||||||
|
#elif defined(ARCH_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||||
#define MAX_RX_TOPHONE 8
|
#define MAX_RX_TOPHONE 8
|
||||||
#else
|
#else
|
||||||
#define MAX_RX_TOPHONE 32
|
#define MAX_RX_TOPHONE 32
|
||||||
@ -51,9 +83,8 @@ static_assert(sizeof(meshtastic_NodeInfoLite) <= 200, "NodeInfoLite size increas
|
|||||||
#include "Esp.h"
|
#include "Esp.h"
|
||||||
static inline int get_max_num_nodes()
|
static inline int get_max_num_nodes()
|
||||||
{
|
{
|
||||||
uint32_t psram_size = ESP.getPsramSize() / (1024 * 1024); // Convert Bytes to MB
|
if (has_psram()) {
|
||||||
if (psram_size >= 2) {
|
return 5000;
|
||||||
return 800;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t flash_size = ESP.getFlashChipSize() / (1024 * 1024); // Fallback based on flash size
|
uint32_t flash_size = ESP.getFlashChipSize() / (1024 * 1024); // Fallback based on flash size
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user