diff --git a/zephcore/adapters/radio/LoRaRadioBase.cpp b/zephcore/adapters/radio/LoRaRadioBase.cpp index 7b6983a..53f1c80 100644 --- a/zephcore/adapters/radio/LoRaRadioBase.cpp +++ b/zephcore/adapters/radio/LoRaRadioBase.cpp @@ -256,7 +256,8 @@ static bool configParamsEqual(const struct lora_modem_config &a, a.tx_power == b.tx_power && a.tx == b.tx && a.iq_inverted == b.iq_inverted && - a.public_network == b.public_network; + a.public_network == b.public_network && + a.cad.mode == b.cad.mode; } /** @@ -275,6 +276,7 @@ static bool onlyDirectionDiffers(const struct lora_modem_config &a, a.tx_power == b.tx_power && a.iq_inverted == b.iq_inverted && a.public_network == b.public_network && + a.cad.mode == b.cad.mode && a.tx != b.tx; } @@ -363,6 +365,13 @@ void LoRaRadioBase::begin() startReceive(); + /* Sync _rx_boost_enabled to the driver. The driver initialises its own + * rx_boost_enabled flag from DTS (rx-boosted property), which may differ + * from our constructor default (true). Push our intent now so the + * hardware state matches _rx_boost_enabled from the moment begin() + * returns, before the caller applies prefs via setRxBoost(). */ + hwSetRxBoost(_rx_boost_enabled); + uint32_t freq = _prefs ? (uint32_t)(_prefs->freq * 1000000.0f) : LoRaConfig::FREQ_HZ; uint8_t sf = _prefs ? _prefs->sf : LoRaConfig::SPREADING_FACTOR; diff --git a/zephcore/include/mesh/Dispatcher.h b/zephcore/include/mesh/Dispatcher.h index 723de92..f57bc43 100644 --- a/zephcore/include/mesh/Dispatcher.h +++ b/zephcore/include/mesh/Dispatcher.h @@ -28,6 +28,7 @@ public: virtual Packet *removeOutboundByIdx(int i) = 0; virtual uint32_t getOutboundSchedule(int i) const = 0; virtual bool rescheduleOutbound(int i, uint32_t new_scheduled_for) = 0; + virtual uint8_t peekNextOutboundPriority(uint32_t now) const = 0; virtual void queueInbound(Packet *packet, uint32_t scheduled_for) = 0; virtual Packet *getNextInbound(uint32_t now) = 0; }; @@ -48,6 +49,7 @@ typedef uint32_t DispatcherAction; class Dispatcher { Packet *outbound; + uint8_t outbound_priority; uint32_t outbound_expiry, outbound_start, total_air_time, rx_air_time; uint32_t next_tx_time; uint32_t cad_busy_start; diff --git a/zephcore/include/mesh/StaticPoolPacketManager.h b/zephcore/include/mesh/StaticPoolPacketManager.h index 7ea35f1..00ef4a3 100644 --- a/zephcore/include/mesh/StaticPoolPacketManager.h +++ b/zephcore/include/mesh/StaticPoolPacketManager.h @@ -22,6 +22,7 @@ public: Packet *removeOutboundByIdx(int i) override; uint32_t getOutboundSchedule(int i) const override; bool rescheduleOutbound(int i, uint32_t new_scheduled_for) override; + uint8_t peekNextOutboundPriority(uint32_t now) const override; void queueInbound(Packet *packet, uint32_t scheduled_for) override; Packet *getNextInbound(uint32_t now) override; }; diff --git a/zephcore/src/Dispatcher.cpp b/zephcore/src/Dispatcher.cpp index 5217949..d8a38be 100644 --- a/zephcore/src/Dispatcher.cpp +++ b/zephcore/src/Dispatcher.cpp @@ -28,6 +28,7 @@ Dispatcher::Dispatcher(Radio &radio, MillisecondClock &ms, PacketManager &mgr) : _radio(&radio), _ms(&ms), _mgr(&mgr) { outbound = nullptr; + outbound_priority = 0; total_air_time = rx_air_time = 0; next_tx_time = 0; cad_busy_start = 0; @@ -410,6 +411,10 @@ void Dispatcher::checkSend() } cad_busy_start = 0; + /* Snapshot the priority of the packet we're about to dequeue so it + * can be preserved if the send attempt fails and we need to re-queue. + * Must be called before getNextOutbound() removes the entry. */ + outbound_priority = _mgr->peekNextOutboundPriority(now); outbound = _mgr->getNextOutbound(now); if (outbound) { uint8_t raw[MAX_TRANS_UNIT]; @@ -460,7 +465,7 @@ void Dispatcher::checkSend() LOG_DBG("checkSend: final gate blocked TX (isReceiving=%d, isRadioReady=%d, inRecvMode=%d)", (int)final_is_receiving, (int)final_is_radio_ready, (int)_radio->isInRecvMode()); - _mgr->queueOutbound(outbound, 0, futureMillis((int)retry)); + _mgr->queueOutbound(outbound, outbound_priority, futureMillis((int)retry)); outbound = nullptr; if (_tx_queued_cb) { _tx_queued_cb(retry, _tx_queued_user_data); @@ -473,7 +478,7 @@ void Dispatcher::checkSend() uint32_t retry = getCADFailRetryDelay(); LOG_ERR("checkSend: startSendRaw failed! re-queuing delay=%u", retry); logTxFail(outbound, outbound->getRawLength()); - _mgr->queueOutbound(outbound, 0, futureMillis((int)retry)); + _mgr->queueOutbound(outbound, outbound_priority, futureMillis((int)retry)); outbound = nullptr; if (_tx_queued_cb) { _tx_queued_cb(retry, _tx_queued_user_data); diff --git a/zephcore/src/StaticPoolPacketManager.cpp b/zephcore/src/StaticPoolPacketManager.cpp index 922ca00..96b2471 100644 --- a/zephcore/src/StaticPoolPacketManager.cpp +++ b/zephcore/src/StaticPoolPacketManager.cpp @@ -96,6 +96,17 @@ struct PacketQueue { return (i < _num) ? _schedule_table[i] : 0; } + /* Priority of the next packet that get(now) would return, without + * removing it. Returns 0xFF if no due packet exists. */ + uint8_t peekPriority(uint32_t now) const { + uint8_t best = 0xFF; + for (int j = 0; j < _num; j++) { + if ((int32_t)(_schedule_table[j] - now) > 0) continue; + if (_pri_table[j] < best) best = _pri_table[j]; + } + return best; + } + bool reschedule(int i, uint32_t new_scheduled_for) { if (i >= _num) return false; _schedule_table[i] = new_scheduled_for; @@ -193,6 +204,11 @@ bool StaticPoolPacketManager::rescheduleOutbound(int i, uint32_t new_scheduled_f return _send_queue.reschedule(i, new_scheduled_for); } +uint8_t StaticPoolPacketManager::peekNextOutboundPriority(uint32_t now) const +{ + return _send_queue.peekPriority(now); +} + void StaticPoolPacketManager::queueInbound(Packet *packet, uint32_t scheduled_for) { if (!_rx_queue.add(packet, 0, scheduled_for)) {