Refactor LoRa protocol to batch+ack with ACK-based time bootstrap

This commit is contained in:
2026-02-04 11:57:49 +01:00
parent f08d9a34d3
commit f0503af8c7
20 changed files with 326 additions and 1048 deletions

View File

@@ -1,6 +0,0 @@
#pragma once
#include <Arduino.h>
bool compressBuffer(const uint8_t *in, size_t in_len, uint8_t *out, size_t out_max, size_t &out_len);
bool decompressBuffer(const uint8_t *in, size_t in_len, uint8_t *out, size_t out_max, size_t &out_len);

View File

@@ -7,21 +7,11 @@ enum class DeviceRole : uint8_t {
Receiver = 1
};
enum class PayloadType : uint8_t {
MeterData = 0,
TestCode = 1,
TimeSync = 2,
MeterBatch = 3,
Ack = 4
};
enum class BatchRetryPolicy : uint8_t {
Keep = 0,
Drop = 1
};
constexpr uint8_t PROTOCOL_VERSION = 1;
// Pin definitions
constexpr uint8_t PIN_LORA_SCK = 5;
constexpr uint8_t PIN_LORA_MISO = 19;
@@ -57,17 +47,7 @@ constexpr uint8_t LORA_PREAMBLE_LEN = 8;
// Timing
constexpr uint32_t SENDER_WAKE_INTERVAL_SEC = 30;
constexpr uint32_t TIME_SYNC_INTERVAL_SEC = 60;
constexpr uint32_t TIME_SYNC_SLOW_INTERVAL_SEC = 3600;
constexpr uint32_t TIME_SYNC_FAST_WINDOW_MS = 10UL * 60UL * 1000UL;
constexpr uint32_t SENDER_TIMESYNC_WINDOW_MS = 300;
constexpr uint32_t SENDER_TIMESYNC_CHECK_SEC_FAST = 60;
constexpr uint32_t SENDER_TIMESYNC_CHECK_SEC_SLOW = 3600;
constexpr uint32_t TIME_SYNC_DRIFT_THRESHOLD_SEC = 10;
constexpr uint32_t TIME_SYNC_BURST_INTERVAL_MS = 10000;
constexpr uint32_t TIME_SYNC_BURST_DURATION_MS = 10UL * 60UL * 1000UL;
constexpr uint32_t TIME_SYNC_ERROR_TIMEOUT_MS = 2UL * 24UL * 60UL * 60UL * 1000UL;
constexpr bool ENABLE_DS3231 = true;
constexpr uint32_t SYNC_REQUEST_INTERVAL_MS = 15000;
constexpr uint32_t OLED_PAGE_INTERVAL_MS = 4000;
constexpr uint32_t OLED_AUTO_OFF_MS = 10UL * 60UL * 1000UL;
constexpr uint32_t SENDER_OLED_READ_MS = 10000;
@@ -107,6 +87,7 @@ constexpr const char *WEB_AUTH_DEFAULT_USER = "admin";
constexpr const char *WEB_AUTH_DEFAULT_PASS = "admin";
constexpr uint8_t NUM_SENDERS = 1;
constexpr uint32_t MIN_ACCEPTED_EPOCH_UTC = 1769904000UL; // 2026-02-01 00:00:00 UTC
inline constexpr uint16_t EXPECTED_SENDER_IDS[NUM_SENDERS] = {
0xF19C //433mhz sender
//0x7EB4 //868mhz sender

View File

@@ -6,19 +6,16 @@ enum class FaultType : uint8_t {
None = 0,
MeterRead = 1,
Decode = 2,
LoraTx = 3,
TimeSync = 4
LoraTx = 3
};
enum class RxRejectReason : uint8_t {
None = 0,
CrcFail = 1,
BadProtocol = 2,
WrongRole = 3,
WrongPayloadType = 4,
LengthMismatch = 5,
DeviceIdMismatch = 6,
BatchIdMismatch = 7
InvalidMsgKind = 2,
LengthMismatch = 3,
DeviceIdMismatch = 4,
BatchIdMismatch = 5
};
struct FaultCounters {

View File

@@ -4,7 +4,3 @@
#include "data_model.h"
bool meterDataToJson(const MeterData &data, String &out_json);
bool jsonToMeterData(const String &json, MeterData &data);
bool meterBatchToJson(const MeterData *samples, size_t count, uint16_t batch_id, String &out_json,
const FaultCounters *faults = nullptr, FaultType last_error = FaultType::None);
bool jsonToMeterBatch(const String &json, MeterData *out_samples, size_t max_count, size_t &out_count);

View File

@@ -6,11 +6,14 @@
constexpr size_t LORA_MAX_PAYLOAD = 230;
enum class LoraMsgKind : uint8_t {
BatchUp = 0,
AckDown = 1
};
struct LoraPacket {
uint8_t protocol_version;
DeviceRole role;
LoraMsgKind msg_kind;
uint16_t device_id_short;
PayloadType payload_type;
uint8_t payload[LORA_MAX_PAYLOAD];
size_t payload_len;
int16_t rssi_dbm;

View File

@@ -1,8 +0,0 @@
#pragma once
#include <Arduino.h>
bool rtc_ds3231_init();
bool rtc_ds3231_is_present();
bool rtc_ds3231_read_epoch(uint32_t &epoch_utc);
bool rtc_ds3231_set_epoch(uint32_t epoch_utc);

View File

@@ -1,17 +1,11 @@
#pragma once
#include <Arduino.h>
#include "lora_transport.h"
void time_receiver_init(const char *ntp_server_1, const char *ntp_server_2);
uint32_t time_get_utc();
bool time_is_synced();
void time_set_utc(uint32_t epoch);
bool time_send_timesync(uint16_t device_id_short);
bool time_handle_timesync_payload(const uint8_t *payload, size_t len);
void time_get_local_hhmm(char *out, size_t out_len);
void time_rtc_init();
bool time_try_load_from_rtc();
bool time_rtc_present();
uint32_t time_get_last_sync_utc();
uint32_t time_get_last_sync_age_sec();