From 957fbd3f5bc504c93ea9f682ce171287eb730ae5 Mon Sep 17 00:00:00 2001 From: nomdetom Date: Sat, 3 Oct 2026 10:21:35 +0100 Subject: [PATCH] LoRa LBT: take out the preamble hold on a seen preamble Revert be3bf1f38. receiveDetected() judges a preamble by its two-preamble deadline again, and the SX126x IRQ poll clears a bare preamble directly. hasQueuedTx() stays: periodicRadioMaintenance() still uses it. --- src/mesh/RadioLibInterface.cpp | 58 +++++++++++----------------------- src/mesh/RadioLibInterface.h | 8 ----- src/mesh/SX126xInterface.cpp | 8 ++--- 3 files changed, 23 insertions(+), 51 deletions(-) diff --git a/src/mesh/RadioLibInterface.cpp b/src/mesh/RadioLibInterface.cpp index 28d113190b..20fa72655f 100644 --- a/src/mesh/RadioLibInterface.cpp +++ b/src/mesh/RadioLibInterface.cpp @@ -119,50 +119,31 @@ bool RadioLibInterface::canSendImmediately() return true; } -bool RadioLibInterface::preambleHoldActive() -{ - // Whatever sent the cleared preamble is off the air one max packet later. - if (preambleHoldStart && !Throttle::isWithinTimespanMs( - preambleHoldStart, getPacketTime(meshtastic_Constants_DATA_PAYLOAD_LEN + sizeof(PacketHeader)))) - preambleHoldStart = 0; - return preambleHoldStart != 0; -} - -void RadioLibInterface::holdOnPreamble() -{ - // During a hold a refire stays latched, so the first look after it sees an external source and holds again. - if (preambleHoldActive()) - return; - iface->clearIrq(1UL << RADIOLIB_IRQ_PREAMBLE_DETECTED); - preambleHoldStart = Time::skipZero(Time::getMillis()); - LOG_TRACE("Preamble seen, cleared, holding TX"); -} - bool RadioLibInterface::receiveDetected(uint16_t irq, unsigned long syncWordHeaderValidFlag, unsigned long preambleDetectedFlag) { - if (preambleHoldActive()) - return true; - - if (irq & syncWordHeaderValidFlag) { + bool detected = (irq & (syncWordHeaderValidFlag | preambleDetectedFlag)); + // Handle false detections + if (detected) { if (!activeReceiveStart) { activeReceiveStart = Time::skipZero(Time::getMillis()); - } else if (!Throttle::isWithinTimespanMs(activeReceiveStart, - getPacketTime(meshtastic_Constants_DATA_PAYLOAD_LEN + sizeof(PacketHeader)))) { - // We should have gotten an RX_DONE IRQ by now if it was really a packet, so ignore HEADER_VALID flag - activeReceiveStart = 0; - LOG_TRACE("Ignore false header detection"); - return false; + } else if (!Throttle::isWithinTimespanMs(activeReceiveStart, 2 * preambleTimeMsec)) { + if (!(irq & syncWordHeaderValidFlag)) { + // The HEADER_VALID flag should be set by now if it was really a packet, so ignore PREAMBLE_DETECTED flag + activeReceiveStart = 0; + LOG_TRACE("Ignore false preamble detection"); + return false; + } else { + uint32_t maxPacketTimeMsec = getPacketTime(meshtastic_Constants_DATA_PAYLOAD_LEN + sizeof(PacketHeader)); + if (!Throttle::isWithinTimespanMs(activeReceiveStart, maxPacketTimeMsec)) { + // We should have gotten an RX_DONE IRQ by now if it was really a packet, so ignore HEADER_VALID flag + activeReceiveStart = 0; + LOG_TRACE("Ignore false header detection"); + return false; + } + } } - return true; } - - if (irq & preambleDetectedFlag) { - // Looks come once per CSMA backoff, too rarely to judge a preamble by symbol-time deadline (#11933). - // Clear it so the next look sees only a fresh one, and hold TX meanwhile; a clear never aborts RX. - holdOnPreamble(); - return true; - } - return false; + return detected; } /// Send a packet (possibly by enquing in a private fifo). This routine will @@ -646,7 +627,6 @@ void RadioLibInterface::handleReceiveInterrupt() // Condition? const bool wasCadHandoff = cadHandoffRxStart != 0; cadHandoffRxStart = 0; // this RX ends the wait either way; the outcome is logged below - preambleHoldStart = 0; // likewise the reception a held preamble announced if (!isReceiving) { LOG_ERROR("handleReceiveInterrupt called while not in rx mode"); diff --git a/src/mesh/RadioLibInterface.h b/src/mesh/RadioLibInterface.h index 29a597998a..c1cf0e7244 100644 --- a/src/mesh/RadioLibInterface.h +++ b/src/mesh/RadioLibInterface.h @@ -353,14 +353,6 @@ class RadioLibInterface : public RadioInterface, protected concurrency::Notified protected: uint32_t activeReceiveStart = 0; - // Time::getMillis() when a look cleared PREAMBLE_DETECTED and began holding TX, or 0 if no hold. - uint32_t preambleHoldStart = 0; - - /** True while a cleared preamble still holds TX; ends the hold once one max packet has passed. */ - bool preambleHoldActive(); - - /** Clear a bare PREAMBLE_DETECTED and hold TX one max packet, unless a hold is already running. */ - void holdOnPreamble(); /** Whether a packet is waiting to transmit; txQueue itself stays private. */ bool hasQueuedTx() { return !txQueue.empty(); } diff --git a/src/mesh/SX126xInterface.cpp b/src/mesh/SX126xInterface.cpp index c5f706b490..d65b993661 100644 --- a/src/mesh/SX126xInterface.cpp +++ b/src/mesh/SX126xInterface.cpp @@ -379,11 +379,11 @@ template void SX126xInterface::handleSoftwareLoraIrqPoll() RADIOLIB_SX126X_IRQ_RX_DONE | RADIOLIB_SX126X_IRQ_TIMEOUT | RADIOLIB_SX126X_IRQ_CRC_ERR | RADIOLIB_SX126X_IRQ_HEADER_ERR; const uint16_t noisyRxMask = RADIOLIB_SX126X_IRQ_PREAMBLE_DETECTED | RADIOLIB_SX126X_IRQ_HEADER_VALID; - // A bare PREAMBLE is mid-reception, not an RX event: readData() here would run on nothing. With a TX - // queued it goes through the same hold as the TX-path look; HEADER_VALID stays latched for readData(). + // A bare PREAMBLE is mid-reception, not an RX event. With a TX queued clear only it, so a noise preamble + // can't block TX; keep HEADER_VALID latched, as it marks a real frame. const bool preambleOnly = (irq & RADIOLIB_SX126X_IRQ_PREAMBLE_DETECTED) && !(irq & RADIOLIB_SX126X_IRQ_HEADER_VALID); - if (!pollTxMode && hasQueuedTx() && preambleOnly && ((irq & ~noisyRxMask) == 0U)) { - holdOnPreamble(); + if (!pollTxMode && !txQueue.empty() && preambleOnly && ((irq & ~noisyRxMask) == 0U)) { + lora.clearIrqFlags(RADIOLIB_SX126X_IRQ_PREAMBLE_DETECTED); scheduleIrqPollTick(); return; }