Switch LoRa batch payload to present-mask schema v3
BREAKING CHANGE: schema v2 is no longer supported. Replaces fixed dt_s timing with a 30-bit present_mask while keeping MQTT JSON unchanged.
This commit is contained in:
@@ -2,9 +2,11 @@
|
||||
#include <limits.h>
|
||||
|
||||
static constexpr uint16_t kMagic = 0xDDB3;
|
||||
static constexpr uint8_t kSchema = 2;
|
||||
// Breaking change: schema v3 replaces fixed dt_s spacing with a 30-bit present_mask.
|
||||
static constexpr uint8_t kSchema = 3;
|
||||
static constexpr uint8_t kFlags = 0x01;
|
||||
static constexpr size_t kMaxSamples = 30;
|
||||
static constexpr uint32_t kPresentMaskValidBits = 0x3FFFFFFFUL;
|
||||
|
||||
static void write_u16_le(uint8_t *dst, uint16_t value) {
|
||||
dst[0] = static_cast<uint8_t>(value & 0xFF);
|
||||
@@ -97,6 +99,15 @@ static bool ensure_capacity(size_t needed, size_t cap, size_t pos) {
|
||||
return pos + needed <= cap;
|
||||
}
|
||||
|
||||
static uint8_t bit_count32(uint32_t value) {
|
||||
uint8_t count = 0;
|
||||
while (value != 0) {
|
||||
value &= (value - 1);
|
||||
count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
bool encode_batch(const BatchInput &in, uint8_t *out, size_t out_cap, size_t *out_len) {
|
||||
if (!out || !out_len) {
|
||||
return false;
|
||||
@@ -104,11 +115,17 @@ bool encode_batch(const BatchInput &in, uint8_t *out, size_t out_cap, size_t *ou
|
||||
if (in.n > kMaxSamples) {
|
||||
return false;
|
||||
}
|
||||
if (in.dt_s == 0) {
|
||||
if ((in.present_mask & ~kPresentMaskValidBits) != 0) {
|
||||
return false;
|
||||
}
|
||||
if (bit_count32(in.present_mask) != in.n) {
|
||||
return false;
|
||||
}
|
||||
if (in.n == 0 && in.present_mask != 0) {
|
||||
return false;
|
||||
}
|
||||
size_t pos = 0;
|
||||
if (!ensure_capacity(21, out_cap, pos)) {
|
||||
if (!ensure_capacity(24, out_cap, pos)) {
|
||||
return false;
|
||||
}
|
||||
write_u16_le(&out[pos], kMagic);
|
||||
@@ -121,7 +138,8 @@ bool encode_batch(const BatchInput &in, uint8_t *out, size_t out_cap, size_t *ou
|
||||
pos += 2;
|
||||
write_u32_le(&out[pos], in.t_last);
|
||||
pos += 4;
|
||||
out[pos++] = in.dt_s;
|
||||
write_u32_le(&out[pos], in.present_mask);
|
||||
pos += 4;
|
||||
out[pos++] = in.n;
|
||||
write_u16_le(&out[pos], in.battery_mV);
|
||||
pos += 2;
|
||||
@@ -189,7 +207,7 @@ bool decode_batch(const uint8_t *buf, size_t len, BatchInput *out) {
|
||||
return false;
|
||||
}
|
||||
size_t pos = 0;
|
||||
if (len < 21) {
|
||||
if (len < 24) {
|
||||
return false;
|
||||
}
|
||||
uint16_t magic = read_u16_le(&buf[pos]);
|
||||
@@ -205,7 +223,8 @@ bool decode_batch(const uint8_t *buf, size_t len, BatchInput *out) {
|
||||
pos += 2;
|
||||
out->t_last = read_u32_le(&buf[pos]);
|
||||
pos += 4;
|
||||
out->dt_s = buf[pos++];
|
||||
out->present_mask = read_u32_le(&buf[pos]);
|
||||
pos += 4;
|
||||
out->n = buf[pos++];
|
||||
out->battery_mV = read_u16_le(&buf[pos]);
|
||||
pos += 2;
|
||||
@@ -215,7 +234,16 @@ bool decode_batch(const uint8_t *buf, size_t len, BatchInput *out) {
|
||||
out->err_last = buf[pos++];
|
||||
out->err_rx_reject = buf[pos++];
|
||||
|
||||
if (out->n > kMaxSamples || out->dt_s == 0) {
|
||||
if (out->n > kMaxSamples) {
|
||||
return false;
|
||||
}
|
||||
if ((out->present_mask & ~kPresentMaskValidBits) != 0) {
|
||||
return false;
|
||||
}
|
||||
if (bit_count32(out->present_mask) != out->n) {
|
||||
return false;
|
||||
}
|
||||
if (out->n == 0 && out->present_mask != 0) {
|
||||
return false;
|
||||
}
|
||||
if (out->n == 0) {
|
||||
@@ -292,7 +320,7 @@ bool payload_codec_self_test() {
|
||||
in.sender_id = 1;
|
||||
in.batch_id = 42;
|
||||
in.t_last = 1700000000;
|
||||
in.dt_s = 1;
|
||||
in.present_mask = (1UL << 0) | (1UL << 2) | (1UL << 3) | (1UL << 10) | (1UL << 29);
|
||||
in.n = 5;
|
||||
in.battery_mV = 3750;
|
||||
in.err_m = 2;
|
||||
@@ -335,7 +363,7 @@ bool payload_codec_self_test() {
|
||||
}
|
||||
|
||||
if (out.sender_id != in.sender_id || out.batch_id != in.batch_id || out.t_last != in.t_last ||
|
||||
out.dt_s != in.dt_s || out.n != in.n || out.battery_mV != in.battery_mV ||
|
||||
out.present_mask != in.present_mask || out.n != in.n || out.battery_mV != in.battery_mV ||
|
||||
out.err_m != in.err_m || out.err_d != in.err_d || out.err_tx != in.err_tx || out.err_last != in.err_last ||
|
||||
out.err_rx_reject != in.err_rx_reject) {
|
||||
Serial.println("payload_codec_self_test: header mismatch");
|
||||
|
||||
Reference in New Issue
Block a user