fix(mqtt): Netzwerk-Objekte per new auf Core 0 anlegen - Heap-Korruption behoben
- WiFiClient, WiFiClientSecure, PubSubClient als Pointer deklariert (nullptr init) - Objekte werden erst in _taskLoop() auf Core 0 per 'new' erstellt - mbedtls bindet Heap-Allokationen an den erstellenden Core/Task -> Anlegen auf Core 1 (globaler Konstruktor) + Nutzung auf Core 0 = Heap-Korruption -> Fix: Anlegen UND Nutzung ausschliesslich auf Core 0 - isConnected(), printToSerial(): Null-Checks ergaenzt
This commit is contained in:
parent
eeede50f1c
commit
b91b3ca96f
|
|
@ -52,9 +52,13 @@ public:
|
|||
void printToSerial();
|
||||
|
||||
private:
|
||||
WiFiClient _wifiClient;
|
||||
WiFiClientSecure _secureClient; // fuer TLS (Port 8883)
|
||||
PubSubClient _client;
|
||||
// WICHTIG: Diese Objekte werden als nullptr initialisiert und erst in
|
||||
// _taskLoop() auf Core 0 per 'new' angelegt. mbedtls/WiFiClientSecure
|
||||
// bindet Heap-Kontexte an den erstellenden Task/Core – daher KEIN
|
||||
// Anlegen im globalen Konstruktor (Core 1)!
|
||||
WiFiClient* _wifiClient;
|
||||
WiFiClientSecure* _secureClient;
|
||||
PubSubClient* _client;
|
||||
|
||||
uint32_t _lastReconnectMs;
|
||||
uint32_t _lastHeartbeatMs;
|
||||
|
|
|
|||
|
|
@ -16,7 +16,9 @@ MqttClient mqttClient;
|
|||
// Konstruktor
|
||||
// --------------------------------------------------------------------------
|
||||
MqttClient::MqttClient()
|
||||
: _client(_wifiClient)
|
||||
: _wifiClient(nullptr)
|
||||
, _secureClient(nullptr)
|
||||
, _client(nullptr)
|
||||
, _lastReconnectMs(0)
|
||||
, _lastHeartbeatMs(0)
|
||||
, _taskHandle(nullptr)
|
||||
|
|
@ -80,7 +82,7 @@ void MqttClient::publishSession(int lastSessionSec, int gratisSec) {
|
|||
// _doPublishSession() - eigentlicher Publish, wird aus MQTT-Task aufgerufen
|
||||
// --------------------------------------------------------------------------
|
||||
void MqttClient::_doPublishSession(int lastSessionSec, int gratisSec) {
|
||||
if (!_client.connected()) {
|
||||
if (!_client->connected()) {
|
||||
LOG_E("MQTT", "_doPublishSession: nicht verbunden, uebersprungen");
|
||||
return;
|
||||
}
|
||||
|
|
@ -106,7 +108,7 @@ void MqttClient::_doPublishSession(int lastSessionSec, int gratisSec) {
|
|||
char buf[128];
|
||||
serializeJson(doc, buf, sizeof(buf));
|
||||
|
||||
bool ok = _client.publish(MQTT_TOPIC_SESSION, buf, /*retained=*/false);
|
||||
bool ok = _client->publish(MQTT_TOPIC_SESSION, buf, /*retained=*/false);
|
||||
LOG_I("MQTT", "publishSession: %s -> %s", buf, ok ? "OK" : "FEHLER");
|
||||
}
|
||||
|
||||
|
|
@ -125,7 +127,7 @@ void MqttClient::publishHeartbeat() {
|
|||
char buf[220];
|
||||
serializeJson(doc, buf, sizeof(buf));
|
||||
|
||||
bool ok = _client.publish(MQTT_TOPIC_STATUS, buf, /*retained=*/true);
|
||||
bool ok = _client->publish(MQTT_TOPIC_STATUS, buf, /*retained=*/true);
|
||||
LOG_I("MQTT", "Heartbeat: %s -> %s", buf, ok ? "OK" : "FEHLER");
|
||||
}
|
||||
|
||||
|
|
@ -133,38 +135,34 @@ void MqttClient::publishHeartbeat() {
|
|||
// reconnect() - Verbindungsaufbau, non-blocking
|
||||
// --------------------------------------------------------------------------
|
||||
bool MqttClient::reconnect() {
|
||||
if (_client.connected()) return true;
|
||||
if (_client->connected()) return true;
|
||||
|
||||
const auto& cfg = settings.get();
|
||||
const char* user = cfg.mqttUser[0] != '\0' ? cfg.mqttUser : nullptr;
|
||||
const char* pass = cfg.mqttPassword[0] != '\0' ? cfg.mqttPassword : nullptr;
|
||||
|
||||
// Offline-LWT (Last Will and Testament)
|
||||
const char* lwtPayload = "{\"online\":false}";
|
||||
|
||||
LOG_I("MQTT", "Verbinde als '%s'...", _clientId);
|
||||
// TLS-Handshake kann 2-15 s dauern. Laeuft auf Core 0 (MQTT-Task),
|
||||
// blockiert Core 1 (loop/LaserTracker/Display) nicht mehr.
|
||||
|
||||
bool ok;
|
||||
if (user && pass) {
|
||||
ok = _client.connect(_clientId, user, pass,
|
||||
MQTT_TOPIC_STATUS, 0, true, lwtPayload);
|
||||
ok = _client->connect(_clientId, user, pass,
|
||||
MQTT_TOPIC_STATUS, 0, true, lwtPayload);
|
||||
} else {
|
||||
ok = _client.connect(_clientId,
|
||||
nullptr, nullptr,
|
||||
MQTT_TOPIC_STATUS, 0, true, lwtPayload);
|
||||
ok = _client->connect(_clientId,
|
||||
nullptr, nullptr,
|
||||
MQTT_TOPIC_STATUS, 0, true, lwtPayload);
|
||||
}
|
||||
|
||||
if (ok) {
|
||||
LOG_I("MQTT", "Verbunden!");
|
||||
_client.subscribe(MQTT_TOPIC_RESET);
|
||||
_client->subscribe(MQTT_TOPIC_RESET);
|
||||
LOG_I("MQTT", "Abonniert: %s", MQTT_TOPIC_RESET);
|
||||
// Sofortigen Heartbeat senden
|
||||
publishHeartbeat();
|
||||
_lastHeartbeatMs = millis();
|
||||
} else {
|
||||
LOG_E("MQTT", "Verbindung fehlgeschlagen, rc=%d", _client.state());
|
||||
LOG_E("MQTT", "Verbindung fehlgeschlagen, rc=%d", _client->state());
|
||||
}
|
||||
|
||||
return ok;
|
||||
|
|
@ -188,17 +186,22 @@ void MqttClient::_taskLoop() {
|
|||
const char* broker = cfg.mqttBroker[0] != '\0' ? cfg.mqttBroker : DEFAULT_MQTT_BROKER;
|
||||
uint16_t port = cfg.mqttPort > 0 ? cfg.mqttPort : DEFAULT_MQTT_PORT;
|
||||
|
||||
// Netzwerk-Objekte auf Core 0 anlegen (mbedtls/WiFiClientSecure bindet
|
||||
// Heap-Kontexte an den erstellenden Task/Core -> kein Cross-Core-Zugriff).
|
||||
_wifiClient = new WiFiClient();
|
||||
_secureClient = new WiFiClientSecure();
|
||||
|
||||
if (port == 8883) {
|
||||
_secureClient.setInsecure();
|
||||
_client.setClient(_secureClient);
|
||||
_secureClient->setInsecure();
|
||||
_client = new PubSubClient(*_secureClient);
|
||||
LOG_I("MQTT", "TLS aktiv (setInsecure, Core 0)");
|
||||
} else {
|
||||
_client.setClient(_wifiClient);
|
||||
_client = new PubSubClient(*_wifiClient);
|
||||
}
|
||||
_client.setServer(broker, port);
|
||||
_client.setCallback(MqttClient::onMessage);
|
||||
_client.setKeepAlive(60);
|
||||
_client.setBufferSize(512);
|
||||
_client->setServer(broker, port);
|
||||
_client->setCallback(MqttClient::onMessage);
|
||||
_client->setKeepAlive(60);
|
||||
_client->setBufferSize(512);
|
||||
|
||||
for (;;) {
|
||||
// Kein WiFi: warten
|
||||
|
|
@ -208,7 +211,7 @@ void MqttClient::_taskLoop() {
|
|||
}
|
||||
|
||||
// Nicht verbunden: Reconnect-Intervall abwarten, dann versuchen
|
||||
if (!_client.connected()) {
|
||||
if (!_client->connected()) {
|
||||
uint32_t now = millis();
|
||||
if (now - _lastReconnectMs >= MQTT_RECONNECT_MS) {
|
||||
_lastReconnectMs = now;
|
||||
|
|
@ -219,7 +222,7 @@ void MqttClient::_taskLoop() {
|
|||
}
|
||||
|
||||
// PubSubClient-interne Verarbeitung (eingehende Nachrichten)
|
||||
_client.loop();
|
||||
_client->loop();
|
||||
|
||||
// Pending Session-Publish (von Core 1 via volatile Flag gesetzt)
|
||||
if (_pendingSession) {
|
||||
|
|
@ -299,7 +302,7 @@ void MqttClient::onMessage(const char* topic, byte* payload, unsigned int length
|
|||
// isConnected()
|
||||
// --------------------------------------------------------------------------
|
||||
bool MqttClient::isConnected() {
|
||||
return _client.connected();
|
||||
return _client != nullptr && _client->connected();
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
|
|
@ -311,7 +314,7 @@ void MqttClient::printToSerial() {
|
|||
LOG_I("MQTT", " Broker : %s", cfg.mqttBroker[0] ? cfg.mqttBroker : DEFAULT_MQTT_BROKER);
|
||||
LOG_I("MQTT", " Port : %u", cfg.mqttPort > 0 ? cfg.mqttPort : DEFAULT_MQTT_PORT);
|
||||
LOG_I("MQTT", " ClientID : %s", _clientId[0] ? _clientId : MQTT_CLIENT_ID);
|
||||
LOG_I("MQTT", " Verbunden: %s", _client.connected() ? "JA" : "NEIN");
|
||||
LOG_I("MQTT", " rc : %d", _client.state());
|
||||
LOG_I("MQTT", " Verbunden: %s", (_client && _client->connected()) ? "JA" : "NEIN");
|
||||
LOG_I("MQTT", " rc : %d", _client ? _client->state() : -1);
|
||||
LOG_I("MQTT", "==================");
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user