From 7e5e23e56c4e499878ae94f3a6be114b50b2e6a8 Mon Sep 17 00:00:00 2001 From: acidburns Date: Wed, 4 Feb 2026 01:21:42 +0100 Subject: [PATCH] Scale ACK RX window to LoRa airtime - Compute ACK receive window from airtime with bounds and margin - Retry once if initial window misses - Document ACK window sizing --- README.md | 1 + src/main.cpp | 18 +++++++++++++++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index a9ea7dd..59060c7 100644 --- a/README.md +++ b/README.md @@ -244,6 +244,7 @@ Notes: - Sender error counters are carried in the batch header and applied to all samples. - Receiver ACKs MeterBatch as soon as the batch is reassembled, before MQTT/web/UI work, to avoid missing the sender ACK window. - Receiver repeats ACKs (`ACK_REPEAT_COUNT`) spaced by `ACK_REPEAT_DELAY_MS` to cover sender RX latency. +- Sender ACK RX window is derived from LoRa airtime (bounded min/max) and retried once if the first window misses. ## Device IDs - Derived from WiFi STA MAC. diff --git a/src/main.cpp b/src/main.cpp index 4b1e145..392235f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -862,8 +862,24 @@ static void sender_loop() { if (g_batch_ack_pending) { LoraPacket ack_pkt = {}; + const uint32_t ack_len = 5 + 6 + 2; + uint32_t ack_air_ms = lora_airtime_ms(ack_len); + uint32_t ack_window_ms = ack_air_ms + 300; + if (ack_window_ms < 1200) { + ack_window_ms = 1200; + } + if (ack_window_ms > 4000) { + ack_window_ms = 4000; + } + if (SERIAL_DEBUG_MODE) { + serial_debug_printf("ack: rx window=%lu airtime=%lu", static_cast(ack_window_ms), + static_cast(ack_air_ms)); + } uint32_t rx_start = millis(); - bool got_ack = lora_receive_window(ack_pkt, 400); + bool got_ack = lora_receive_window(ack_pkt, ack_window_ms); + if (!got_ack) { + got_ack = lora_receive_window(ack_pkt, ack_window_ms / 2); + } uint32_t rx_elapsed = millis() - rx_start; if (SERIAL_DEBUG_MODE) { g_sender_rx_window_ms += rx_elapsed;