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.
This commit is contained in:
nomdetom committed 2026-10-03 10:21:35 +01:00
1 parent 08fb5c8437
commit 957fbd3f5b
3 files changed
+23 -51

No files matched your search

+19 -39
View File
@@ -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");
-8
View File
@@ -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(); }
+4 -4
View File
@@ -379,11 +379,11 @@ template <typename T> void SX126xInterface<T>::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;
}