Enhance MQTTBridge to manage active connection slots based on available memory. Introduced psram_calloc for memory allocation with PSRAM support, limiting active slots to 3 with PSRAM and 2 without. Updated slot setup logic to prevent exceeding active slot limits during MQTT operations.

This commit is contained in:
agessaman
2026-03-20 22:50:39 -07:00
parent b43e9618db
commit 542f8a31ee
2 changed files with 50 additions and 3 deletions
+49 -3
View File
@@ -11,6 +11,7 @@
#include <freertos/task.h>
#include <freertos/queue.h>
#include <freertos/semphr.h>
#include <mbedtls/platform.h>
#endif
// Helper function to strip quotes from strings (both single and double quotes)
@@ -60,6 +61,17 @@ static void* psram_malloc(size_t size) {
#endif
}
static void* psram_calloc(size_t n, size_t size) {
if (n == 0 || size == 0) return nullptr;
#if defined(ESP_PLATFORM) && defined(BOARD_HAS_PSRAM)
void* p = heap_caps_calloc(n, size, MALLOC_CAP_SPIRAM);
if (p != nullptr) return p;
return heap_caps_calloc(n, size, MALLOC_CAP_INTERNAL);
#else
return calloc(n, size);
#endif
}
static void psram_free(void* ptr) {
if (ptr == nullptr) return;
#if defined(ESP_PLATFORM)
@@ -107,7 +119,10 @@ void MQTTBridge::formatMqttStatusReply(char* buf, size_t bufsize, const NodePref
char slot_info[3][48];
for (int i = 0; i < MAX_MQTT_SLOTS; i++) {
const MQTTSlot& slot = b->_slots[i];
if (!slot.enabled) {
if (!slot.enabled && slot.preset) {
// Configured but disabled (e.g., no PSRAM, slot limit reached)
snprintf(slot_info[i], sizeof(slot_info[i]), "slot%d: %s (inactive)", i + 1, slot.preset->name);
} else if (!slot.enabled) {
snprintf(slot_info[i], sizeof(slot_info[i]), "slot%d: none", i + 1);
} else if (slot.preset) {
snprintf(slot_info[i], sizeof(slot_info[i]), "slot%d: %s (%s)", i + 1,
@@ -139,7 +154,7 @@ MQTTBridge::MQTTBridge(NodePrefs *prefs, mesh::PacketManager *mgr, mesh::RTCCloc
: BridgeBase(prefs, mgr, rtc),
_queue_count(0),
_last_status_publish(0), _last_status_retry(0), _status_interval(300000),
_ntp_client(_ntp_udp, "pool.ntp.org", 0, 60000), _last_ntp_sync(0), _ntp_synced(false), _ntp_sync_pending(false), _slots_setup_done(false),
_ntp_client(_ntp_udp, "pool.ntp.org", 0, 60000), _last_ntp_sync(0), _ntp_synced(false), _ntp_sync_pending(false), _slots_setup_done(false), _max_active_slots(MAX_MQTT_SLOTS),
_timezone(nullptr), _last_raw_len(0), _last_snr(0), _last_rssi(0), _last_raw_timestamp(0),
_identity(identity),
_cached_has_connected_slots(false),
@@ -241,6 +256,16 @@ void MQTTBridge::begin() {
MQTT_DEBUG_PRINTLN("PSRAM: not configured for this board (no BOARD_HAS_PSRAM)");
#endif
// Limit active slots based on available memory.
// Each WSS/TLS connection needs ~40KB for mbedTLS buffers.
// Without PSRAM, 3 concurrent connections would exhaust internal heap.
#if defined(ESP_PLATFORM) && defined(BOARD_HAS_PSRAM)
_max_active_slots = psramFound() ? MAX_MQTT_SLOTS : 2;
#else
_max_active_slots = 2;
#endif
MQTT_DEBUG_PRINTLN("Max active slots: %d", _max_active_slots);
// Check if WiFi credentials are configured first
if (!isWiFiConfigValid(_prefs)) {
MQTT_DEBUG_PRINTLN("MQTT Bridge initialization skipped - WiFi credentials not configured");
@@ -575,10 +600,25 @@ void MQTTBridge::mqttTaskLoop() {
// This avoids wasted TLS handshakes that get rejected due to bad token times.
if (_ntp_synced && !_slots_setup_done) {
_slots_setup_done = true;
MQTT_DEBUG_PRINTLN("NTP synced, setting up MQTT slots...");
// Redirect mbedTLS allocations to PSRAM to save ~40KB internal heap per TLS connection.
// This is critical when running 3 concurrent WSS connections.
#if defined(BOARD_HAS_PSRAM)
mbedtls_platform_set_calloc_free(psram_calloc, psram_free);
MQTT_DEBUG_PRINTLN("mbedTLS allocator redirected to PSRAM");
#endif
MQTT_DEBUG_PRINTLN("NTP synced, setting up MQTT slots (max %d active)...", _max_active_slots);
int active_count = 0;
for (int i = 0; i < MAX_MQTT_SLOTS; i++) {
if (_slots[i].enabled) {
if (active_count >= _max_active_slots) {
MQTT_DEBUG_PRINTLN("Slot %d skipped: max active slots (%d) reached (no PSRAM)", i, _max_active_slots);
_slots[i].enabled = false; // Disable so other loops skip it
continue;
}
setupSlot(i);
active_count++;
// Stagger connections: 5s between slots to avoid simultaneous TLS handshakes
// which compete for ~40KB internal heap each
if (i < MAX_MQTT_SLOTS - 1) {
@@ -1260,9 +1300,15 @@ void MQTTBridge::loop() {
// Deferred slot setup after NTP sync (non-ESP32 path)
if (_ntp_synced && !_slots_setup_done) {
_slots_setup_done = true;
int active_count = 0;
for (int i = 0; i < MAX_MQTT_SLOTS; i++) {
if (_slots[i].enabled) {
if (active_count >= _max_active_slots) {
_slots[i].enabled = false;
continue;
}
setupSlot(i);
active_count++;
}
}
}
+1
View File
@@ -139,6 +139,7 @@ private:
bool _ntp_synced;
bool _ntp_sync_pending; // Flag to trigger NTP sync from loop() instead of event handler
bool _slots_setup_done; // Deferred: slots set up after NTP sync
int _max_active_slots; // Runtime limit: 3 with PSRAM, 2 without
// Timezone handling
Timezone* _timezone;