From d7b5bb0f0ba75de70e651202deaee86ab0f3cc6b Mon Sep 17 00:00:00 2001 From: acidburns Date: Tue, 17 Feb 2026 01:14:38 +0100 Subject: [PATCH] Adapt sender ACK receive window based on observed timing --- src/main.cpp | 51 +++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 41 insertions(+), 10 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index fa3218a..85c13b2 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -105,6 +105,7 @@ static uint32_t g_sender_ack_timeout_total = 0; static uint32_t g_sender_ack_retry_total = 0; static uint32_t g_sender_ack_rtt_last_ms = 0; static uint32_t g_sender_ack_rtt_ewma_ms = 0; +static uint32_t g_sender_ack_miss_streak = 0; static RxRejectReason g_sender_rx_reject_reason = RxRejectReason::None; static uint32_t g_sender_rx_reject_log_ms = 0; static RxRejectReason g_receiver_rx_reject_reason = RxRejectReason::None; @@ -203,7 +204,7 @@ static void sender_log_diagnostics(uint32_t now_ms) { } serial_debug_printf( - "diag: q_depth=%lu q_hi=%lu q_drop=%lu batch_q=%u build=%u ack_pending=%u ack_retry_cur=%u ack_retry_total=%lu ack_timeout_total=%lu ack_rtt_last_ms=%lu ack_rtt_ewma_ms=%lu meter_ok=%lu meter_fail=%lu meter_ovf=%lu meter_timeout=%lu meter_age_ms=%lu rx_win_ms=%lu sleep_ms=%lu", + "diag: q_depth=%lu q_hi=%lu q_drop=%lu batch_q=%u build=%u ack_pending=%u ack_retry_cur=%u ack_retry_total=%lu ack_timeout_total=%lu ack_rtt_last_ms=%lu ack_rtt_ewma_ms=%lu ack_miss_streak=%lu meter_ok=%lu meter_fail=%lu meter_ovf=%lu meter_timeout=%lu meter_age_ms=%lu rx_win_ms=%lu sleep_ms=%lu", static_cast(queue_depth), static_cast(g_meter_queue_high_water), static_cast(g_meter_queue_drop_count), @@ -215,6 +216,7 @@ static void sender_log_diagnostics(uint32_t now_ms) { static_cast(g_sender_ack_timeout_total), static_cast(g_sender_ack_rtt_last_ms), static_cast(g_sender_ack_rtt_ewma_ms), + static_cast(g_sender_ack_miss_streak), static_cast(meter_stats.frames_ok), static_cast(meter_stats.frames_parse_fail), static_cast(meter_stats.rx_overflow), @@ -1384,26 +1386,49 @@ static void sender_loop() { LoraPacket ack_pkt = {}; constexpr size_t ack_len = lora_frame_size(LORA_ACK_DOWN_PAYLOAD_LEN); 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; + uint32_t ack_window_first_ms = ack_air_ms + 200; + if (g_sender_ack_rtt_ewma_ms > 0) { + uint32_t rtt_based_ms = g_sender_ack_rtt_ewma_ms + 150; + if (rtt_based_ms > ack_window_first_ms) { + ack_window_first_ms = rtt_based_ms; + } } - if (ack_window_ms > 4000) { - ack_window_ms = 4000; + uint32_t miss_boost_ms = g_sender_ack_miss_streak * 150; + if (miss_boost_ms > 1200) { + miss_boost_ms = 1200; + } + ack_window_first_ms += miss_boost_ms; + if (ack_window_first_ms < 600) { + ack_window_first_ms = 600; + } + if (ack_window_first_ms > 2500) { + ack_window_first_ms = 2500; + } + uint32_t ack_window_second_ms = ack_window_first_ms + (ack_window_first_ms / 2); + uint32_t min_second_ms = ack_air_ms + 400; + if (ack_window_second_ms < min_second_ms) { + ack_window_second_ms = min_second_ms; + } + if (ack_window_second_ms > 5000) { + ack_window_second_ms = 5000; } if (SERIAL_DEBUG_MODE) { - serial_debug_printf("ack: rx window=%lu airtime=%lu", static_cast(ack_window_ms), - static_cast(ack_air_ms)); + serial_debug_printf("ack: rx windows=%lu/%lu airtime=%lu miss_streak=%lu", + static_cast(ack_window_first_ms), + static_cast(ack_window_second_ms), + static_cast(ack_air_ms), + static_cast(g_sender_ack_miss_streak)); } uint32_t rx_start = millis(); - bool got_ack = lora_receive_window(ack_pkt, ack_window_ms); + bool got_ack = lora_receive_window(ack_pkt, ack_window_first_ms); if (!got_ack) { - got_ack = lora_receive_window(ack_pkt, ack_window_ms / 2); + got_ack = lora_receive_window(ack_pkt, ack_window_second_ms); } uint32_t rx_elapsed = millis() - rx_start; if (SERIAL_DEBUG_MODE) { g_sender_rx_window_ms += rx_elapsed; } + bool ack_accepted = false; if (!got_ack) { RxRejectReason reason = lora_get_last_rx_reject_reason(); sender_note_rx_reject(reason, "ack"); @@ -1445,6 +1470,7 @@ static void sender_loop() { uint32_t ack_epoch = read_u32_be(&ack_pkt.payload[3]); bool set_time = false; if (g_batch_ack_pending && ack_id == g_last_sent_batch_id) { + ack_accepted = true; g_sender_ack_rtt_last_ms = rx_elapsed; if (g_sender_ack_rtt_ewma_ms == 0) { g_sender_ack_rtt_ewma_ms = rx_elapsed; @@ -1475,6 +1501,11 @@ static void sender_loop() { } } } + if (ack_accepted) { + g_sender_ack_miss_streak = 0; + } else if (g_sender_ack_miss_streak < UINT32_MAX) { + g_sender_ack_miss_streak++; + } } if (!g_batch_ack_pending) { lora_sleep();