Refactor LoRa protocol to batch+ack with ACK-based time bootstrap
This commit is contained in:
@@ -1,15 +1,9 @@
|
||||
#include "time_manager.h"
|
||||
#include "compressor.h"
|
||||
#include "config.h"
|
||||
#include "rtc_ds3231.h"
|
||||
#include <time.h>
|
||||
|
||||
static bool g_time_synced = false;
|
||||
static bool g_tz_set = false;
|
||||
static bool g_rtc_present = false;
|
||||
static uint32_t g_last_sync_utc = 0;
|
||||
static constexpr uint32_t kMinValidEpoch = 1672531200UL; // 2023-01-01
|
||||
static constexpr uint32_t kMaxValidEpoch = 4102444800UL; // 2100-01-01
|
||||
|
||||
static void note_last_sync(uint32_t epoch) {
|
||||
if (epoch == 0) {
|
||||
@@ -57,63 +51,6 @@ void time_set_utc(uint32_t epoch) {
|
||||
settimeofday(&tv, nullptr);
|
||||
g_time_synced = true;
|
||||
note_last_sync(epoch);
|
||||
|
||||
if (g_rtc_present) {
|
||||
rtc_ds3231_set_epoch(epoch);
|
||||
}
|
||||
}
|
||||
|
||||
bool time_send_timesync(uint16_t device_id_short) {
|
||||
uint32_t epoch = time_get_utc();
|
||||
if (epoch == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
char payload_str[32];
|
||||
snprintf(payload_str, sizeof(payload_str), "T:%lu", static_cast<unsigned long>(epoch));
|
||||
|
||||
uint8_t compressed[LORA_MAX_PAYLOAD];
|
||||
size_t compressed_len = 0;
|
||||
if (!compressBuffer(reinterpret_cast<const uint8_t *>(payload_str), strlen(payload_str), compressed, sizeof(compressed), compressed_len)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
LoraPacket pkt = {};
|
||||
pkt.protocol_version = PROTOCOL_VERSION;
|
||||
pkt.role = DeviceRole::Receiver;
|
||||
pkt.device_id_short = device_id_short;
|
||||
pkt.payload_type = PayloadType::TimeSync;
|
||||
pkt.payload_len = compressed_len;
|
||||
memcpy(pkt.payload, compressed, compressed_len);
|
||||
bool ok = lora_send(pkt);
|
||||
if (ok) {
|
||||
lora_receive_continuous();
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
bool time_handle_timesync_payload(const uint8_t *payload, size_t len) {
|
||||
uint8_t decompressed[64];
|
||||
size_t decompressed_len = 0;
|
||||
if (!decompressBuffer(payload, len, decompressed, sizeof(decompressed), decompressed_len)) {
|
||||
return false;
|
||||
}
|
||||
if (decompressed_len >= sizeof(decompressed)) {
|
||||
return false;
|
||||
}
|
||||
decompressed[decompressed_len] = '\0';
|
||||
|
||||
if (decompressed_len < 3 || decompressed[0] != 'T' || decompressed[1] != ':') {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t epoch = static_cast<uint32_t>(strtoul(reinterpret_cast<const char *>(decompressed + 2), nullptr, 10));
|
||||
if (epoch == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
time_set_utc(epoch);
|
||||
return true;
|
||||
}
|
||||
|
||||
void time_get_local_hhmm(char *out, size_t out_len) {
|
||||
@@ -127,43 +64,6 @@ void time_get_local_hhmm(char *out, size_t out_len) {
|
||||
snprintf(out, out_len, "%02d:%02d", timeinfo.tm_hour, timeinfo.tm_min);
|
||||
}
|
||||
|
||||
void time_rtc_init() {
|
||||
if (!ENABLE_DS3231) {
|
||||
g_rtc_present = false;
|
||||
return;
|
||||
}
|
||||
g_rtc_present = rtc_ds3231_init();
|
||||
}
|
||||
|
||||
bool time_try_load_from_rtc() {
|
||||
if (!g_rtc_present) {
|
||||
return false;
|
||||
}
|
||||
if (time_is_synced()) {
|
||||
return true;
|
||||
}
|
||||
uint32_t epoch = 0;
|
||||
if (!rtc_ds3231_read_epoch(epoch) || epoch == 0) {
|
||||
if (SERIAL_DEBUG_MODE) {
|
||||
Serial.println("rtc: read failed");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool valid = epoch >= kMinValidEpoch && epoch <= kMaxValidEpoch;
|
||||
if (SERIAL_DEBUG_MODE) {
|
||||
Serial.printf("rtc: epoch=%lu %s\n", static_cast<unsigned long>(epoch), valid ? "accepted" : "rejected");
|
||||
}
|
||||
if (!valid) {
|
||||
return false;
|
||||
}
|
||||
time_set_utc(epoch);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool time_rtc_present() {
|
||||
return g_rtc_present;
|
||||
}
|
||||
|
||||
uint32_t time_get_last_sync_utc() {
|
||||
return g_last_sync_utc;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user