Fix trace TX stalls from invalid radio airtime

This commit is contained in:
mikecarper committed 2026-08-10 23:47:02 -07:00
1 parent e6664127b6
commit 48a5d5b4cd
9 files changed
+99 -5

No files matched your search

+22
View File
@@ -6,6 +6,28 @@
namespace mesh {
static constexpr uint32_t TERMINAL_TRACE_TIMEOUT_MARGIN_PERCENT = 200UL;
static constexpr uint32_t TERMINAL_TRACE_MAX_TIMEOUT_MILLIS = 0x7FFFFFFFUL;
// Terminal trace timeouts add a 200% margin to the direct-send estimate. Keep
// the arithmetic wide because futureMillis() accepts a signed millisecond
// delta and rollover-safe comparisons require the result to stay in range.
inline bool calculateTerminalTraceTimeoutMillis(uint32_t base_timeout_millis,
uint32_t& timeout_millis) {
timeout_millis = 0;
if (base_timeout_millis == 0) return false;
const uint64_t margin =
static_cast<uint64_t>(base_timeout_millis)
* TERMINAL_TRACE_TIMEOUT_MARGIN_PERCENT / 100UL;
const uint64_t total =
static_cast<uint64_t>(base_timeout_millis) + margin;
if (total > TERMINAL_TRACE_MAX_TIMEOUT_MILLIS) return false;
timeout_millis = static_cast<uint32_t>(total);
return true;
}
struct RoundTripTracePath {
uint8_t hash_size;
uint8_t hop_count;
+9
View File
@@ -18,6 +18,15 @@ class CustomLR1110 : public LR1110 {
public:
CustomLR1110(Module *mod) : LR1110(mod) { }
// MeshCore keeps the LR1110 in LoRa mode. Calculate from RadioLib's cached
// parameters so an airtime query never issues GetPacketType while RX duty
// cycling has the chip asleep. RadioLib's LR11x0 implementation ignores a
// failed modem query and can otherwise return an encoded negative error as
// a multi-million-millisecond airtime.
RadioLibTime_t getTimeOnAir(size_t len) override {
return getToA(len, ModemType_t::RADIOLIB_MODEM_LORA);
}
// RadioLib waits without a deadline for BUSY to fall after SetTx. Bound
// that wait so a failed LR1110 transition can reach the wrapper's hard
// recovery path instead of hanging the firmware indefinitely.
@@ -55,6 +55,7 @@ public:
uint32_t getEstAirtimeFor(int len_bytes) override {
auto airtime = RadioLibWrapper::getEstAirtimeFor(len_bytes);
if (airtime == 0) return 0;
return airtime < 200 ? 200 : airtime; // at least 200 millis
}
+17
View File
@@ -0,0 +1,17 @@
#pragma once
#include <stdint.h>
namespace mesh {
// RadioLib time-on-air APIs use an unsigned return type even though some
// implementations return negative RADIOLIB_ERR_* values on failure. Those
// errors therefore appear immediately below UINT32_MAX.
static constexpr uint32_t RADIOLIB_AIRTIME_ERROR_WINDOW_US = 4096UL;
inline bool isEncodedRadioLibAirtimeError(uint32_t airtime_us) {
return airtime_us
>= UINT32_MAX - (RADIOLIB_AIRTIME_ERROR_WINDOW_US - 1UL);
}
} // namespace mesh
+9 -1
View File
@@ -632,7 +632,15 @@ void RadioLibWrapper::finishReceiveProcessing() {
}
uint32_t RadioLibWrapper::getEstAirtimeFor(int len_bytes) {
return _radio->getTimeOnAir(len_bytes) / 1000;
const uint32_t airtime_us =
static_cast<uint32_t>(_radio->getTimeOnAir(len_bytes));
if (mesh::isEncodedRadioLibAirtimeError(airtime_us)) {
MESH_DEBUG_PRINTLN(
"RadioLibWrapper: invalid time-on-air estimate (0x%08lX)",
(unsigned long)airtime_us);
return 0;
}
return airtime_us / 1000;
}
bool RadioLibWrapper::startSendRaw(const uint8_t* bytes, int len) {
+1
View File
@@ -3,6 +3,7 @@
#include <Mesh.h>
#include <RadioLib.h>
#include "CadTiming.h"
#include "RadioAirtime.h"
// Fallback RX powersaving timings, only used until setRxPowerSaving() is called
// (begin() always applies the persisted values). The authoritative defaults live