Skip to content

Add Japan LoRa LBT compliance (ARIB STD-T108) with runtime frequency detection#2218

Open
jirogit wants to merge 13 commits intomeshcore-dev:devfrom
jirogit:feature/jp-lbt
Open

Add Japan LoRa LBT compliance (ARIB STD-T108) with runtime frequency detection#2218
jirogit wants to merge 13 commits intomeshcore-dev:devfrom
jirogit:feature/jp-lbt

Conversation

@jirogit
Copy link
Copy Markdown

@jirogit jirogit commented Apr 1, 2026

Closes #2079

Summary

This PR implements Listen-Before-Talk (LBT) for Japan LoRa operation, as required by ARIB STD-T108 / Giteki (技適) certification. Activation is automatic based on operating frequency — no build flags required.

Changes

Radio accessor methods (RadioLibWrappers.h/cpp, Wrapper classes):

  • getCodingRate() — returns current LoRa coding rate at runtime
  • getFreqMHz() — returns operating frequency in MHz
  • getMaxTextLen() — returns dynamic DM message length limit based on CR
  • getMaxGroupTextLen() — returns dynamic channel message length limit based on CR
  • isJapanMode() — returns true when operating on JP LoRa frequencies (920.800 / 921.000 / 921.200 MHz)

Japan LBT (BaseChatMesh.cpp, RadioLibWrappers.cpp):

  • 5ms continuous RSSI sensing before TX (−80dBm absolute threshold, ARIB STD-T108 §4.4)
  • Exponential backoff when channel busy (base 2000ms, max 16000ms)
  • Small jitter on channel-free detection (0–500ms) to desynchronize simultaneous TX
  • 50ms post-TX wait
  • Dynamic message length limits per coding rate, derived from ARIB STD-T108 4-second maximum TX time limit, verified by measuring getTimeOnAir() on RAK WisMesh Tag (SF12/BW125):
CR DM limit airtime Channel limit airtime
4/5 64 bytes 3874ms 64 bytes 3710ms
4/6 48 bytes 3874ms 48 bytes 3678ms
4/7 32 bytes 3678ms 39 bytes 3907ms
4/8 24 bytes 3547ms 29 bytes 3809ms

DM and channel packets differ by 1 byte overhead, warranting separate limits for CR4/7 and CR4/8. Non-JP returns default bytes unchanged.

Build:

  • Fix build for non-FreeRTOS and non-SX1262 platforms (YIELD_TASK() macro)

Note on commit history

Early commits include CAD-based channel detection based on weebl2000's work (PR #1727). This was subsequently replaced with RSSI-based LBT, as ARIB STD-T108 requires energy detection, not LoRa preamble detection. The final code does not use CAD. The commit history reflects this exploration path.

Testing

Devices: RAK WisMesh Tag (SX1262), Wio Tracker L1 Pro (SX1262)
Settings: SF12 / BW125 / CR4-8 (JP standard)

  • 16-byte simultaneous DM: 3/3 success

  • 48-byte simultaneous DM: 3/3 success

  • Channel messages: all CR rates confirmed (CR4/5–CR4/8).
    Effective text limit is (channel_limit - 2 - sender_name_length) bytes,
    where 2 bytes are consumed by the ": " separator.
    Example (8-byte sender name): CR4/5=54B, CR4/6=38B, CR4/7=29B, CR4/8=19B

Known limitations

  • In Japan mode, the UI does not reflect the reduced message length limits. Channel messages longer than the CR-dependent limit will be silently truncated at send time. DM messages exceeding the limit will fail to send. A UI-level fix requires exposing getMaxTextLen()/getMaxGroupTextLen() to the UI layer and is left for a follow-up.
  • TX power limit (≤13dBm, ARIB STD-T108) is not enforced — relies on user configuration.

weebl2000 and others added 13 commits March 31, 2026 21:57
JP_STRICT limits MAX_TEXT_LEN to 1*CIPHER_BLOCK_SIZE (16 bytes) to keep
TX time under 4 seconds on SF12/BW125/CR4-8 (Japan LoRa settings).

SF12/BW125/CR4-8 airtime:
  60 bytes total packet = ~3809ms (within 4s limit)
  packet overhead ~44 bytes, leaving 16 bytes for text payload

Enabled only for WioTrackerL1 and RAK_WisMesh_Tag builds.
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)
Replace relative threshold (_noise_floor + _threshold) with absolute
-80dBm as specified by ARIB STD-T108 for carrier sense detection.

Previous relative threshold (~-99dBm) caused false busy detection
from environmental noise. -80dBm matches the legal requirement and
reduces spurious backoff.
MAX_TEXT_LEN is automatically selected based on the LORA_CR build flag
defined in platformio.ini (e.g. -D LORA_CR=5).

CR4/5: 48 bytes (~16 JP chars, TX ~3808ms)
CR4/6: 32 bytes (~10 JP chars)
CR4/7: 24 bytes (~8 JP chars)
CR4/8: 16 bytes (~5 JP chars, default)

To enable CR4/5 for Japan, add -D LORA_CR=5 to your board's
build_flags in platformio.ini. Set LORA_CR=5 for WioTrackerL1 and RAK WisMesh Tag.
Instead of compile-time LORA_CR define, MAX_TEXT_LEN is now determined
at runtime by reading the actual coding rate from the radio hardware.

Added getMaxTextLen() to RadioLibWrapper and Dispatcher:
- CR4/5: 48 bytes (~16 JP chars, TX ~3808ms)
- CR4/6: 32 bytes (~10 JP chars)
- CR4/7: 24 bytes (~8 JP chars)
- CR4/8: 16 bytes (~5 JP chars, default)

getCodingRate() added to CustomSX1262Wrapper to read codingRate
from RadioLib PhysicalLayer at runtime.

Tested: 48-byte limit with LORA_CR=5, 16-byte limit with LORA_CR=8.
Replace fixed random(8000-22000ms) backoff with exponential backoff:
- 1st busy: 3-6s
- 2nd busy: 6-12s
- 3rd+ busy: 12-20s (capped)
- Reset counter on channel free

Results (48-byte simultaneous DM, JP SF12/BW125/CR4-5):
- 3/3 success, delivered within 0:23-0:45
- Previous fixed backoff: 1:03-3:55
LR1110 has codingRate as protected field in LR_common.h, so
getCodingRate() is implemented in CustomLR1110 class directly,
and exposed via CustomLR1110Wrapper override.

This enables dynamic MAX_TEXT_LEN calculation for T1000-E
under JP_STRICT mode.
JP LBT mode now activates automatically based on operating frequency:
- CH25: 920.800MHz
- CH26: 921.000MHz
- CH27: 921.200MHz (ARIB STD-T108, 200kHz grid)

Changes:
- Add isJapanMode() to RadioLibWrapper using getFreqMHz()
- Add getFreqMHz() to CustomSX1262Wrapper and CustomLR1110Wrapper
- Remove #ifdef JP_STRICT throughout, replaced by isJapanMode()
- Remove -D JP_STRICT build flag from platformio.ini
- MAX_TEXT_LEN dynamically determined by CR at runtime via getMaxTextLen()

No build flags required: JP compliance activates automatically
when device is configured to Japan 3 frequencies.
_tx_start_ms and TX duration logging were added for 4-second
airtime verification and are no longer needed.
- Replace vTaskDelay(1) with YIELD_TASK() macro for platform compatibility
  (FreeRTOS: vTaskDelay, others: delay)
- Make getCodingRate() and getFreqMHz() non-pure virtual with defaults
  (default CR4/8, default freq 0.0f for unknown platforms)
- Add getCodingRate() and getFreqMHz() to CustomSTM32WLxWrapper

All environments now build successfully.
…GroupTextLen()

Measured actual TimeOnAir via RadioLib getTimeOnAir() on RAK WisMesh Tag
(SF12/BW125, CR4/5-8) to verify ARIB STD-T108 4-second TX limit compliance.

DM limits (getMaxTextLen):
  CR4/5: 64 bytes (3874ms)
  CR4/6: 48 bytes (3874ms)
  CR4/7: 32 bytes (3678ms)
  CR4/8: 24 bytes (3547ms)

Channel message limits (getMaxGroupTextLen):
  CR4/5: 64 bytes (3710ms)
  CR4/6: 48 bytes (3678ms)
  CR4/7: 39 bytes (3907ms)
  CR4/8: 29 bytes (3809ms)

DM and channel packets differ by 1 byte overhead, warranting separate
limits for CR4/7 and CR4/8. Non-JP returns default 160 bytes unchanged.

Also apply dynamic limit to sendCommandData() and sendGroupMessage()
via getMaxTextLen()/getMaxGroupTextLen() instead of hardcoded MAX_TEXT_LEN.
@jirogit jirogit marked this pull request as ready for review April 1, 2026 09:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants