From 7bae0d8405ff69c179461c2a7903ab60bf91e596 Mon Sep 17 00:00:00 2001 From: jirogit Date: Tue, 24 Mar 2026 23:11:29 -0700 Subject: [PATCH] Add JP_STRICT 5ms continuous RSSI sensing before TX (ARIB STD-T108) Under JP_STRICT mode, add energy-based carrier sensing loop before CAD: - Sample RSSI continuously for >= 5ms before each TX attempt - If RSSI exceeds threshold at any point, trigger random backoff - ARIB STD-T108 requires energy-based sensing; LoRa CAD alone is insufficient as it only detects LoRa preambles This satisfies the minimum 5ms continuous sensing requirement for the 920.6-922.2 MHz zone (specified low power radio, LBT mode). Test results (JP LoRa SF12/BW125/CR4-8, simultaneous DM): - 16-char: 2/2 success, delivered within 1:03-1:50 - 1-char: 3/4 success, delivered within 0:46-2:11 (shorter airtime reduces RSSI detection window) --- src/helpers/radiolib/RadioLibWrappers.cpp | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/helpers/radiolib/RadioLibWrappers.cpp b/src/helpers/radiolib/RadioLibWrappers.cpp index a1ec7d10..97fdb4ab 100644 --- a/src/helpers/radiolib/RadioLibWrappers.cpp +++ b/src/helpers/radiolib/RadioLibWrappers.cpp @@ -142,6 +142,7 @@ uint32_t RadioLibWrapper::getEstAirtimeFor(int len_bytes) { bool RadioLibWrapper::startSendRaw(const uint8_t* bytes, int len) { _board->onBeforeTransmit(); + _tx_start_ms = millis(); // recording TX time int err = _radio->startTransmit((uint8_t *) bytes, len); if (err == RADIOLIB_ERR_NONE) { state = STATE_TX_WAIT; @@ -157,6 +158,8 @@ bool RadioLibWrapper::isSendComplete() { if (state & STATE_INT_READY) { state = STATE_IDLE; n_sent++; + uint32_t tx_duration = millis() - _tx_start_ms; + MESH_DEBUG_PRINTLN("TX duration: %lu ms (len=%d)", tx_duration); return true; } return false; @@ -175,6 +178,24 @@ int16_t RadioLibWrapper::performChannelScan() { bool RadioLibWrapper::isChannelActive() { if (_threshold == 0) return false; // interference check is disabled +#ifdef JP_STRICT + // ARIB STD-T108 compliant LBT: continuous RSSI sensing for >= 5ms + // Energy-based sensing required; LoRa CAD alone is not sufficient + uint32_t sense_start = millis(); + uint32_t sense_duration_ms = 5; + while (millis() - sense_start < sense_duration_ms) { + if (getCurrentRSSI() > _noise_floor + _threshold) { + // Channel busy detected during 5ms sensing window + uint32_t backoff_until = millis() + random(8000, 22000); + while (millis() < backoff_until) { + vTaskDelay(1); // yield CPU to FreeRTOS tasks including BLE + } + return true; + } + vTaskDelay(1); // yield CPU between RSSI samples + } +#endif + int16_t result = performChannelScan(); // scanChannel() triggers DIO interrupt (CAD done) which sets STATE_INT_READY // via setFlag() ISR. Clear it before restarting RX so recvRaw() doesn't