meshtimesync p1

This commit is contained in:
liquidraver
2026-07-03 09:11:43 +02:00
parent fc940d27ba
commit 14cb8c61f9
30 changed files with 1231 additions and 3 deletions
+92
View File
@@ -9,6 +9,8 @@
#include <mesh/Utils.h>
#include <mesh/LoRaConfig.h>
#include <adapters/radio/LoRaRadioBase.h>
#include <adapters/clock/ZephyrRTCDiscover.h>
#include <adapters/gps/ZephyrGPSManager.h>
#include <helpers/MeshcoreJson.h>
#include <zephyr/logging/log.h>
@@ -217,9 +219,80 @@ DispatcherAction ObserverMesh::onRecvPacket(Packet *pkt)
* The same flood packet heard from different repeaters is published
* separately, each with its own SNR/RSSI (propagation data). */
enqueuePacket(pkt);
harvestTimeSample(pkt);
return ACTION_RELEASE; /* never retransmit */
}
/* ========== Mesh time sync ========== */
void ObserverMesh::harvestTimeSample(Packet *pkt)
{
if (pkt->getPayloadType() != PAYLOAD_TYPE_ADVERT) return;
if (pkt->getPathHashCount() > MeshTimeSync::HOP_CAP) return;
if (pkt->payload_len < PUB_KEY_SIZE + 4 + SIGNATURE_SIZE) return;
int i = 0;
Identity id;
memcpy(id.pub_key, &pkt->payload[i], PUB_KEY_SIZE);
i += PUB_KEY_SIZE;
uint32_t timestamp;
memcpy(&timestamp, &pkt->payload[i], 4);
i += 4;
const uint8_t *signature = &pkt->payload[i];
i += SIGNATURE_SIZE;
size_t app_data_len = pkt->payload_len - (size_t)i;
if (app_data_len > MAX_ADVERT_DATA_SIZE) app_data_len = MAX_ADVERT_DATA_SIZE;
uint8_t message[PUB_KEY_SIZE + 4 + MAX_ADVERT_DATA_SIZE];
int msg_len = 0;
memcpy(&message[msg_len], id.pub_key, PUB_KEY_SIZE); msg_len += PUB_KEY_SIZE;
memcpy(&message[msg_len], &timestamp, 4); msg_len += 4;
memcpy(&message[msg_len], &pkt->payload[i], app_data_len); msg_len += app_data_len;
if (!id.verify(signature, message, msg_len)) return;
_timesync.onAdvertHeard(id.pub_key, timestamp, pkt->getPathHashCount(),
(uint32_t)(k_uptime_get() / 1000));
}
void ObserverMesh::timeSyncTick()
{
if (!_prefs.meshtimesync || !_rtc) return;
uint32_t up = (uint32_t)(k_uptime_get() / 1000);
uint32_t now = _rtc->getCurrentTime();
MeshTimeSync::Verdict v = _timesync.tick(now, up);
if (v.type != MeshTimeSync::VERDICT_STEP) return;
/* GPS gate: sense only while GPS owns the clock. */
if (gps_is_available() && gps_is_enabled()) {
LOG_INF("meshtimesync: step %+d s wanted, GPS gate active - not applied",
(int)v.delta);
return;
}
applyTimeSyncStep(v, now, up);
}
void ObserverMesh::noteTrustedTimeSync()
{
_timesync.noteManualSync((uint32_t)(k_uptime_get() / 1000));
}
void ObserverMesh::applyTimeSyncStep(const MeshTimeSync::Verdict &v, uint32_t now,
uint32_t uptime_secs)
{
uint32_t new_time = (uint32_t)((int64_t)now + v.delta);
_rtc->setCurrentTime(new_time);
zephcore_rtc_save(new_time);
_timesync.noteStepApplied(v.delta, new_time, uptime_secs, v.bootstrap);
LOG_WRN("meshtimesync: stepped clock %+d s (%s, votes %u/%u) -> %u",
(int)v.delta, v.bootstrap ? "bootstrap" : "consensus",
(unsigned)v.consensus.votes_for, (unsigned)v.consensus.votes_against,
(unsigned)new_time);
}
/* ========== Serial CLI ========== */
#define CLI_REPLY_SIZE 256
@@ -289,6 +362,12 @@ bool ObserverMesh::handleCLI(const char *command, char *reply, int reply_size)
snprintf(reply, reply_size, "%u",
(_creds) ? (unsigned)_creds->mqtt_port : 8883u);
} else if (strcmp(key, "meshtimesync") == 0) {
_timesync.formatStatus(reply, reply_size,
_rtc ? _rtc->getCurrentTime() : 0,
(uint32_t)(k_uptime_get() / 1000),
_prefs.meshtimesync != 0);
} else if (strcmp(key, "mqtt.tls") == 0) {
snprintf(reply, reply_size, "%u",
(_creds) ? (unsigned)_creds->mqtt_tls : 1u);
@@ -392,6 +471,19 @@ bool ObserverMesh::handleCLI(const char *command, char *reply, int reply_size)
snprintf(reply, reply_size, "ERR cr must be 5-8");
}
} else if ((val = find_val(rest, "meshtimesync")) != nullptr) {
if (strcmp(val, "on") == 0) {
_prefs.meshtimesync = 1;
_store->savePrefs(_prefs);
snprintf(reply, reply_size, "meshtimesync=on");
} else if (strcmp(val, "off") == 0) {
_prefs.meshtimesync = 0;
_store->savePrefs(_prefs);
snprintf(reply, reply_size, "meshtimesync=off");
} else {
snprintf(reply, reply_size, "ERR must be on or off");
}
} else if (!_creds) {
snprintf(reply, reply_size, "ERR creds not initialized");