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)
This commit is contained in:
jirogit 2026-03-24 23:11:29 -07:00
parent 309a090958
commit 7bae0d8405

View file

@ -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