diff --git a/zephcore/ARCHITECTURE.md b/zephcore/ARCHITECTURE.md index 3d40a53..3395486 100644 --- a/zephcore/ARCHITECTURE.md +++ b/zephcore/ARCHITECTURE.md @@ -687,7 +687,7 @@ DIO1 interrupt → Zephyr lora driver → async RX callback → k_event_post(MESH_EVENT_LORA_RX) → main thread wakes → Dispatcher::loop() → checkRecv() → drain ring buffer → tryParsePacket() → score + airtime calc - → flood: calcRxDelay() → queue inbound or process immediately + → flood: dedup + adaptive contention delay → queue for retransmit → direct: process immediately → Mesh::onRecvPacket() → decrypt → dispatch by type → BaseChatMesh::onPeerDataRecv() → onMessageRecv() diff --git a/zephcore/adapters/radio/LoRaRadioBase.cpp b/zephcore/adapters/radio/LoRaRadioBase.cpp index 760b68e..819d014 100644 --- a/zephcore/adapters/radio/LoRaRadioBase.cpp +++ b/zephcore/adapters/radio/LoRaRadioBase.cpp @@ -598,7 +598,11 @@ uint32_t LoRaRadioBase::getEstAirtimeFor(int len_bytes) float t_sym = (float)(1 << sf) / (bw * 1000.0f); float t_preamble = (preambleLengthForSF(sf) + 4.25f) * t_sym; - float de = (sf >= 11) ? 1.0f : 0.0f; + /* LDRO threshold must track the SX126x driver's should_enable_ldro() + * exactly (symbol time > 16.38 ms) so this estimate's DE matches the + * hardware's DE on every SF/BW pair. The old `sf >= 11` was only + * correct at BW 125 kHz and diverged on every other bandwidth. */ + float de = (t_sym > 0.01638f) ? 1.0f : 0.0f; float num = 8.0f * len_bytes - 4.0f * sf + 28.0f + 16.0f; float den = 4.0f * (sf - 2.0f * de); if (den < 1.0f) den = 4.0f; diff --git a/zephcore/include/mesh/Dispatcher.h b/zephcore/include/mesh/Dispatcher.h index 8f53aa4..f39fc86 100644 --- a/zephcore/include/mesh/Dispatcher.h +++ b/zephcore/include/mesh/Dispatcher.h @@ -84,7 +84,6 @@ protected: virtual const char *getLogDateTime() { return ""; } virtual uint8_t getDutyCyclePercent() const; static bool isAdminPacket(const Packet *pkt); - virtual int calcRxDelay(float score, uint32_t air_time) const; virtual uint32_t getCADFailRetryDelay() const; virtual uint32_t getCADFailMaxDuration() const; virtual int getInterferenceThreshold() const { return 0; } diff --git a/zephcore/src/Dispatcher.cpp b/zephcore/src/Dispatcher.cpp index 6172c1b..1ba2512 100644 --- a/zephcore/src/Dispatcher.cpp +++ b/zephcore/src/Dispatcher.cpp @@ -21,7 +21,6 @@ LOG_MODULE_REGISTER(zephcore_dispatcher, CONFIG_ZEPHCORE_LORA_LOG_LEVEL); namespace mesh { -#define MAX_RX_DELAY_MILLIS 32000 /* upper bound for score-based RX delay */ #define MIN_TX_BUDGET_AIRTIME_DIV 2 /* require at least 1/N MTU airtime as budget before TX */ Dispatcher::Dispatcher(Radio &radio, MillisecondClock &ms, PacketManager &mgr) @@ -105,22 +104,6 @@ bool Dispatcher::isAdminPacket(const Packet *pkt) t == PAYLOAD_TYPE_ANON_REQ || t == PAYLOAD_TYPE_CONTROL; } -int Dispatcher::calcRxDelay(float score, uint32_t air_time) const -{ - /* LUT: 10^(0.85 - i*0.1) - 1, i=0..10; replaces powf() (~1.9KB saved) */ - static const float lut[11] = { - 6.0793f, 4.6236f, 3.4674f, 2.5489f, 1.8184f, 1.2389f, - 0.7783f, 0.4125f, 0.1220f, -0.1089f, -0.2921f - }; - if (score <= 0.0f) return (int)(lut[0] * (float)air_time); - if (score >= 1.0f) return (int)(lut[10] * (float)air_time); - float idx = score * 10.0f; - int i = (int)idx; - float frac = idx - (float)i; - float val = lut[i] + frac * (lut[i + 1] - lut[i]); - return (int)(val * (float)air_time); -} - uint32_t Dispatcher::getCADFailRetryDelay() const { /* 100-200ms jittered retry: tighter than one SF8 flood airtime so we