defer MQTT connect publish to main loop (uplink cross-thread fix)

This commit is contained in:
liquidraver
2026-06-11 12:32:37 +02:00
parent a03390baa7
commit 966bf24c96
4 changed files with 31 additions and 9 deletions
+1
View File
@@ -106,3 +106,4 @@ CRYPTO_AUDIT_INDEX.md
AUDIT_MASTER_PLAN.md
usb_companion_probe.py
CORE_MESH_AUDIT_INDEX.md
UPLINK_AUDIT_INDEX.md
+11 -1
View File
@@ -935,6 +935,7 @@ RepeaterMesh::RepeaterMesh(mesh::MainBoard& board, mesh::Radio& radio, mesh::Mil
_uplink_last_rssi = 0.0f;
_uplink_last_raw_len = 0;
_uplink_next_status_at = 0;
atomic_set(&_uplink_connect_pending, 0);
#endif
}
@@ -992,8 +993,12 @@ void RepeaterMesh::begin(RepeaterDataStore* store) {
mqtt_publisher_start(&_uplink_creds, _prefs.node_name,
_uplink_status_topic, _uplink_packets_topic);
mqtt_publisher_set_connect_cb([]() {
/* Runs on the MQTT publisher thread — DON'T publish here. It would
* race the main-thread status path on the shared static JSON buffer
* and toggle the battery-ADC regulator off-main. Defer to the main
* loop via an atomic flag drained in maintenanceLoop(). */
if (s_uplink_mesh) {
s_uplink_mesh->publishUplinkStatus("online");
atomic_set(&s_uplink_mesh->_uplink_connect_pending, 1);
}
});
_uplink_next_status_at = futureMillis(300000);
@@ -1346,6 +1351,11 @@ void RepeaterMesh::loop() {
}
#if IS_ENABLED(CONFIG_ZEPHCORE_REPEATER_UPLINK) && IS_ENABLED(CONFIG_MQTT_LIB)
/* MQTT (re)connected — publish the initial "online" status here on the main
* thread (the CONNACK callback only sets this flag, off-main). */
if (atomic_cas(&_uplink_connect_pending, 1, 0)) {
publishUplinkStatus("online");
}
if (_uplink_next_status_at && millisHasNowPassed(_uplink_next_status_at)) {
publishUplinkStatus("online");
_uplink_next_status_at = futureMillis(300000);
+6
View File
@@ -12,6 +12,7 @@
#pragma once
#include <zephyr/sys/atomic.h>
#include <mesh/Mesh.h>
#include <mesh/StaticPoolPacketManager.h>
#include <mesh/SimpleMeshTables.h>
@@ -122,6 +123,11 @@ class RepeaterMesh : public mesh::Mesh, public CommonCLICallbacks {
uint8_t _uplink_last_raw[MAX_TRANS_UNIT];
int _uplink_last_raw_len;
unsigned long _uplink_next_status_at;
/* Set by the MQTT CONNACK callback (runs on the MQTT publisher thread);
* drained on the main thread in maintenanceLoop() so the "online" status
* publish never runs off-main (avoids the shared static-JSON-buffer race
* and off-main battery-ADC regulator toggling). */
atomic_t _uplink_connect_pending;
#endif
void putNeighbour(const mesh::Identity& id, uint32_t timestamp, float snr);
+13 -8
View File
@@ -49,10 +49,11 @@ static const struct gpio_dt_spec led0 = GPIO_DT_SPEC_GET(LED0_NODE, gpios);
/* ========== Event loop bits ========== */
#define MESH_EVENT_LORA_RX BIT(0)
#define MESH_EVENT_CLI_RX BIT(1)
#define MESH_EVENT_STATUS BIT(2)
#define MESH_EVENT_ALL (MESH_EVENT_LORA_RX | MESH_EVENT_CLI_RX | MESH_EVENT_STATUS)
#define MESH_EVENT_LORA_RX BIT(0)
#define MESH_EVENT_CLI_RX BIT(1)
#define MESH_EVENT_STATUS BIT(2)
#define MESH_EVENT_MQTT_CONNECT BIT(3) /* MQTT (re)connected — publish status+self-advert on main */
#define MESH_EVENT_ALL (MESH_EVENT_LORA_RX | MESH_EVENT_CLI_RX | MESH_EVENT_STATUS | MESH_EVENT_MQTT_CONNECT)
static struct k_event mesh_events;
@@ -343,10 +344,10 @@ int main(void)
/* Publish self-advert once on each MQTT connect so CoreScope can pin
* this observer on the map (requires lat/lon to be configured). */
mqtt_publisher_set_connect_cb([]() {
if (s_mesh_ptr) {
s_mesh_ptr->publishStatus("online");
s_mesh_ptr->publishSelfAdvert();
}
/* Runs on the MQTT publisher thread — defer to the main loop. Publishing
* here would race the periodic-status path on publishStatus()'s shared
* static JSON buffer; publishSelfAdvert() also signs + formats. */
k_event_post(&mesh_events, MESH_EVENT_MQTT_CONNECT);
});
k_timer_start(&status_timer, K_SECONDS(300), K_SECONDS(300));
@@ -368,6 +369,10 @@ int main(void)
if (ev & MESH_EVENT_STATUS) {
observer_mesh.publishStatus("online");
}
if (ev & MESH_EVENT_MQTT_CONNECT) {
observer_mesh.publishStatus("online");
observer_mesh.publishSelfAdvert();
}
}
return 0;