adjust batch ack timing and rename e_wh field
This commit is contained in:
@@ -207,7 +207,7 @@ MeterBatch JSON (compressed over LoRa) uses per-field arrays with integer units
|
|||||||
"t_last": 1738288030,
|
"t_last": 1738288030,
|
||||||
"dt_s": 1,
|
"dt_s": 1,
|
||||||
"n": 3,
|
"n": 3,
|
||||||
"energy_wh": [123456700, 123456701, 123456701],
|
"e_wh": [123456700, 123456701, 123456701],
|
||||||
"p_w": [930, 940, 950],
|
"p_w": [930, 940, 950],
|
||||||
"p1_w": [480, 490, 500],
|
"p1_w": [480, 490, 500],
|
||||||
"p2_w": [450, 450, 450],
|
"p2_w": [450, 450, 450],
|
||||||
|
|||||||
@@ -205,7 +205,7 @@ bool meterBatchToJson(const MeterData *samples, size_t count, uint16_t batch_id,
|
|||||||
doc["bat_v"] = serialized(bat_buf);
|
doc["bat_v"] = serialized(bat_buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
JsonArray energy = doc.createNestedArray("energy_wh");
|
JsonArray energy = doc.createNestedArray("e_wh");
|
||||||
JsonArray p_w = doc.createNestedArray("p_w");
|
JsonArray p_w = doc.createNestedArray("p_w");
|
||||||
JsonArray p1_w = doc.createNestedArray("p1_w");
|
JsonArray p1_w = doc.createNestedArray("p1_w");
|
||||||
JsonArray p2_w = doc.createNestedArray("p2_w");
|
JsonArray p2_w = doc.createNestedArray("p2_w");
|
||||||
@@ -258,7 +258,7 @@ bool jsonToMeterBatch(const String &json, MeterData *out_samples, size_t max_cou
|
|||||||
uint32_t t_first = doc["t_first"] | t0;
|
uint32_t t_first = doc["t_first"] | t0;
|
||||||
uint32_t t_last = doc["t_last"] | t_first;
|
uint32_t t_last = doc["t_last"] | t_first;
|
||||||
uint32_t dt_s = doc["dt_s"] | 1;
|
uint32_t dt_s = doc["dt_s"] | 1;
|
||||||
JsonArray energy = doc["energy_wh"].as<JsonArray>();
|
JsonArray energy = doc["e_wh"].as<JsonArray>();
|
||||||
JsonArray p_w = doc["p_w"].as<JsonArray>();
|
JsonArray p_w = doc["p_w"].as<JsonArray>();
|
||||||
JsonArray p1_w = doc["p1_w"].as<JsonArray>();
|
JsonArray p1_w = doc["p1_w"].as<JsonArray>();
|
||||||
JsonArray p2_w = doc["p2_w"].as<JsonArray>();
|
JsonArray p2_w = doc["p2_w"].as<JsonArray>();
|
||||||
|
|||||||
38
src/main.cpp
38
src/main.cpp
@@ -81,6 +81,7 @@ static uint16_t g_last_sent_batch_id = 0;
|
|||||||
static uint16_t g_last_acked_batch_id = 0;
|
static uint16_t g_last_acked_batch_id = 0;
|
||||||
static uint8_t g_batch_retry_count = 0;
|
static uint8_t g_batch_retry_count = 0;
|
||||||
static bool g_batch_ack_pending = false;
|
static bool g_batch_ack_pending = false;
|
||||||
|
static uint32_t g_batch_ack_timeout_ms = BATCH_ACK_TIMEOUT_MS;
|
||||||
static MeterData g_inflight_samples[METER_BATCH_MAX_SAMPLES];
|
static MeterData g_inflight_samples[METER_BATCH_MAX_SAMPLES];
|
||||||
static uint8_t g_inflight_count = 0;
|
static uint8_t g_inflight_count = 0;
|
||||||
static uint16_t g_inflight_batch_id = 0;
|
static uint16_t g_inflight_batch_id = 0;
|
||||||
@@ -294,6 +295,17 @@ static uint32_t compute_batch_rx_timeout_ms(uint16_t total_len, uint8_t chunk_co
|
|||||||
return timeout_ms < 10000 ? 10000 : timeout_ms;
|
return timeout_ms < 10000 ? 10000 : timeout_ms;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static uint32_t compute_batch_ack_timeout_ms(size_t payload_len) {
|
||||||
|
if (payload_len == 0) {
|
||||||
|
return 10000;
|
||||||
|
}
|
||||||
|
uint8_t chunk_count = static_cast<uint8_t>((payload_len + BATCH_CHUNK_PAYLOAD - 1) / BATCH_CHUNK_PAYLOAD);
|
||||||
|
size_t packet_len = 5 + BATCH_HEADER_SIZE + (payload_len > BATCH_CHUNK_PAYLOAD ? BATCH_CHUNK_PAYLOAD : payload_len) + 2;
|
||||||
|
uint32_t per_chunk_toa_ms = lora_airtime_ms(packet_len);
|
||||||
|
uint32_t timeout_ms = static_cast<uint32_t>(chunk_count) * per_chunk_toa_ms + BATCH_RX_MARGIN_MS;
|
||||||
|
return timeout_ms < 10000 ? 10000 : timeout_ms;
|
||||||
|
}
|
||||||
|
|
||||||
static bool inject_batch_meta(String &json, int16_t rssi_dbm, float snr_db, uint32_t rx_ts_utc) {
|
static bool inject_batch_meta(String &json, int16_t rssi_dbm, float snr_db, uint32_t rx_ts_utc) {
|
||||||
DynamicJsonDocument doc(8192);
|
DynamicJsonDocument doc(8192);
|
||||||
DeserializationError err = deserializeJson(doc, json);
|
DeserializationError err = deserializeJson(doc, json);
|
||||||
@@ -423,6 +435,7 @@ static bool send_inflight_batch(uint32_t ts_for_display) {
|
|||||||
if (SERIAL_DEBUG_MODE && compress_ms > 200) {
|
if (SERIAL_DEBUG_MODE && compress_ms > 200) {
|
||||||
serial_debug_printf("tx: compress took %lums", static_cast<unsigned long>(compress_ms));
|
serial_debug_printf("tx: compress took %lums", static_cast<unsigned long>(compress_ms));
|
||||||
}
|
}
|
||||||
|
g_batch_ack_timeout_ms = compute_batch_ack_timeout_ms(compressed_len);
|
||||||
|
|
||||||
uint32_t send_start = millis();
|
uint32_t send_start = millis();
|
||||||
bool ok = send_batch_payload(compressed, compressed_len, ts_for_display, g_inflight_batch_id);
|
bool ok = send_batch_payload(compressed, compressed_len, ts_for_display, g_inflight_batch_id);
|
||||||
@@ -668,6 +681,29 @@ static void sender_loop() {
|
|||||||
send_meter_batch(last_sample_ts());
|
send_meter_batch(last_sample_ts());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (g_batch_ack_pending) {
|
||||||
|
uint32_t end_ms = millis() + 400;
|
||||||
|
while (millis() < end_ms) {
|
||||||
|
LoraPacket ack_pkt = {};
|
||||||
|
if (!lora_receive(ack_pkt, 0) || ack_pkt.protocol_version != PROTOCOL_VERSION) {
|
||||||
|
delay(5);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (ack_pkt.payload_type == PayloadType::Ack && ack_pkt.payload_len >= 6 && ack_pkt.role == DeviceRole::Receiver) {
|
||||||
|
uint16_t ack_id = read_u16_le(ack_pkt.payload);
|
||||||
|
uint16_t ack_sender = read_u16_le(&ack_pkt.payload[2]);
|
||||||
|
uint16_t ack_receiver = read_u16_le(&ack_pkt.payload[4]);
|
||||||
|
if (ack_sender == g_short_id && ack_receiver == ack_pkt.device_id_short &&
|
||||||
|
g_batch_ack_pending && ack_id == g_last_sent_batch_id) {
|
||||||
|
g_last_acked_batch_id = ack_id;
|
||||||
|
serial_debug_printf("ack: ok batch_id=%u", ack_id);
|
||||||
|
finish_inflight_batch();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
LoraPacket rx = {};
|
LoraPacket rx = {};
|
||||||
if (lora_receive(rx, 0) && rx.protocol_version == PROTOCOL_VERSION) {
|
if (lora_receive(rx, 0) && rx.protocol_version == PROTOCOL_VERSION) {
|
||||||
if (rx.payload_type == PayloadType::TimeSync) {
|
if (rx.payload_type == PayloadType::TimeSync) {
|
||||||
@@ -685,7 +721,7 @@ static void sender_loop() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (g_batch_ack_pending && (now_ms - g_last_batch_send_ms >= BATCH_ACK_TIMEOUT_MS)) {
|
if (g_batch_ack_pending && (now_ms - g_last_batch_send_ms >= g_batch_ack_timeout_ms)) {
|
||||||
if (g_batch_retry_count < BATCH_MAX_RETRIES) {
|
if (g_batch_retry_count < BATCH_MAX_RETRIES) {
|
||||||
g_batch_retry_count++;
|
g_batch_retry_count++;
|
||||||
serial_debug_printf("ack: timeout batch_id=%u retry=%u", g_inflight_batch_id, g_batch_retry_count);
|
serial_debug_printf("ack: timeout batch_id=%u retry=%u", g_inflight_batch_id, g_batch_retry_count);
|
||||||
|
|||||||
Reference in New Issue
Block a user