Fast Long-Range Protocol (FLRP-burst)
LR2021 · Sub-GHz & 2.4 GHz
Overview
FLRP-burst (Fast Long-Range Protocol) is a high-throughput wireless transfer protocol built on top of FLRC (PHY layer). It pairs a LoRa® wake-up phase with a high-speed FLRC burst, optimized for the transfer of large files with no strong latency requirements. The current release supports point-to-point communication; one-to-many and many-to-one topologies are under development.
| Protocol | FLRP-burst Connection setup · Adaptive link selection · Burst segmentation · ACK + retry · Optional AES-CMAC integrity |
|
| PHY | LoRa® Wake-on-Radio (WOR) · CAD · Frequency offset measurement · Time synchronization |
FLRC High-speed data burst · Raw packet TX/RX · 0.26–2.6 Mbps · CR 1/2, 2/3, 3/4 · Sub-GHz & 2.4 GHz |
Why FLRP-burst?
As detailed in AN 1200.101, in order to maximize performance, FLRC usage must cope with two main requirements:
| Limitation | Mitigation | Cost |
|---|---|---|
| Tight frequency tolerance at low data rates | TCXO, or ≥ 1.0 Mbps only | +$0.20–0.50 BOM, warm-up delay, or range reduction |
| Wake-on-Noise (false detection) at CR 1/2 & 2/3 | Max preamble + CR 3/4 | Higher TOA, 1–2 dB sensitivity loss |
Each mitigation applied independently introduces trade-offs in sensitivity, data throughput, or BOM cost.
→ The proposed protocol-level approach embodied by FLRP-burst provides a holistic solution, maximizing data throughput and sensitivity with the lowest impact on BOM cost and energy efficiency
FLRP-burst resolves both at protocol level:
- One LoRa WOR exchange compensates the frequency offset so FLRC is aligned before the first bit
→ no TCXO required · up to 4× tolerance at low data rates (±17.5 → ±71 ppm at 325 kbps) - LoRa timing sync collapses the FLRC Rx window to minimum
→ wake-on-noise eliminated · 17% lower Rx power from fewer correlators - LoRa periodic CAD enables always-on listening at as low as ~100 µA
→ not achievable with standalone FLRC continuous RX
Key capabilities
- Up to 1.7 Mbps effective payload baud rate @ 2.6 MHz FLRC PHY
- 1 km+ range at 1 Mbps (Sub-GHz/22 dBm)
- Adaptive link with up to 16 channel selection and automatic datarate adaptation
- Reliable delivery: per-burst ACK with selective retransmit over lossy links
- Optional AES-CMAC per-packet integrity, replacing the radio CRC
- Sub-GHz and 2.4 GHz frequency bands
AN1200.112 defines, for each supported region, the recommended radio settings (channel plan, data rates, EIRP) and regulatory constraints (duty cycle, dwell time, LBT/CCA). The FLRP-burst API does not currently enforce these constraints; compliance remains the responsibility of the application. Region-specific configurations and LBT support are planned for a future release.
Roles
Each device has a fixed session role (Slave or Initiator) and a per-exchange data direction (who transmits the payload).
Session roles
| Role | Description |
|---|---|
| Initiator | Always starts the exchange by sending the WOR. Addresses the slave by DevEUI. |
| Slave | Waits in periodic LoRa periodic CAD sleep. Wakes up and answers the WOR. |
Data-direction roles (set per exchange)
| Transfer Direction | Initiator | Slave | Use case |
|---|---|---|---|
0: initiator receives | Receiver | Transmitter | Sensor data upload |
1: initiator sends | Transmitter | Receiver | Firmware / config download |
Packet Transaction
Every FLRP-burst exchange follows the same four-phase sequence regardless of transfer direction. The slave does not stay in continuous RX; it periodically checks for a LoRa preamble and sleeps in between.
- Initiator sends a long-preamble WOR (≥ slave sleep period); slave catches it during periodic CAD, verifies DevEUI, replies, and both devices become time and frequency aligned.
- Transmitter probes each enabled channel (up to 16); receiver selects the best channel and datarate from measured RSSI and frequency offset.
- Can be fully disabled, or limited to channel-only selection or datarate-only selection.
- Back-to-back FLRC packets, hard-capped at 400 ms per burst. If the payload exceeds that at the selected datarate, the stack automatically splits it into consecutive bursts, each with its own BURST ACK + retry cycle.
- When
crypto_enabled, a per-packet AES-CMAC MIC replaces the radio CRC.
- Triggered when residual loss exceeds
burst_target_per(0 = disabled by default). - Only missing packets are retransmitted.
- No retry when loss is within target or BURST ACK is disabled.
Getting Started
The official, up-to-date documentation is maintained alongside the source in the USP repositories:
github.com/Lora-net/USP · Doc: doc/
The quick-start below shows the minimal code needed to get a first integration running. Include smtc_flrp_api/smtc_flrp_api.h and link against the FLRP-burst library.
Common Setup
Call smtc_rac_init() first, then smtc_flrp_init() once on startup, before any role-specific call.
smtc_rac_init();
smtc_flrp_api_config_t cfg = {
.dev_eui = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 },
.crypto_enabled = false, /* true enables AES-CMAC MIC per packet */
.freq_plan = SMTC_FLRP_FREQ_865MHz,
.crystal_error = 20, /* local oscillator accuracy in ppm */
};
smtc_flrp_init( cfg, on_tx_done, on_rx_done, NULL );
Optionally override the default radio parameters after init:
smtc_flrp_radio_config_t radio = smtc_flrp_get_current_radio_config();
radio.flrc.tx_power_in_dbm = 14;
radio.flrc.raw_bit_rate = RAL_FLRC_RAW_BIT_RATE_2_600_MBPS;
smtc_flrp_set_new_radio_config( radio );
Initiator
The initiator wakes the slave with a WOR, runs the adaptive link, then performs the FLRC burst. Both transmit and receive directions are supported.
Configure the communication parameters, then call the transfer direction once per exchange.
smtc_flrp_com_config_t com = {
.com_mode = SMTC_FLRP_BIDIRECTIONAL,
.slave_dev_eui = { 0x10, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 },
.filter_len = 0, /* EUI prefix bits for ONE_WAY broadcast */
.link_adaptation_mode = SMTC_FLRP_LINK_ADAPTATION_FULLY_ENABLED,
};
/* Send data to slave */
smtc_flrp_initiate_transmission( tx_buf, tx_size, com );
/* Request data from slave */
smtc_flrp_initiate_reception( rx_buf, sizeof( rx_buf ), com );
com_mode | Call | Direction | Behavior |
|---|---|---|---|
BIDIRECTIONAL | initiate_transmission() | Initiator → Slave | BURST ACK + retry; slave can piggyback a reply |
BIDIRECTIONAL | initiate_reception() | Initiator ← Slave | Slave must have data armed via slave_prepare_data_to_send() |
Either call can be made while the device is also running slave periodic listening; the initiated exchange takes priority.
Run the same engine loop as the slave.
while( 1 )
{
if( smtc_flrp_call_run() )
smtc_flrp_run_engine();
}
tx_callback (or rx_callback) fires on exchange completion with the status, byte count, and link statistics.
Slave
The slave stays in LoRa periodic CAD active-sleep and wakes automatically when an initiator WOR matches its DevEUI. No polling loop needed.
Start periodic listening with a receive buffer.
static uint8_t rx_buf[20 * 1024];
smtc_flrp_start_periodic_listening( rx_buf, sizeof( rx_buf ) );
Optional: pre-arm data to send when the initiator polls. The payload stays armed until replaced or cleared.
smtc_flrp_slave_prepare_data_to_send( tx_buf, tx_size );
/* Clear with tx_size = 0 */
Run the engine. smtc_flrp_call_run() returns true only when a time-critical radio operation is pending; use it to sleep the CPU otherwise.
while( 1 )
{
if( smtc_flrp_call_run() )
smtc_flrp_run_engine();
/* sleep / idle until next radio event */
}
rx_callback fires with the received payload; tx_callback fires once the armed data has been delivered to the initiator. To stop listening, call smtc_flrp_stop_periodic_listening().
Common Callbacks
Both callbacks are registered once in smtc_flrp_init() and are shared by both roles. on_tx_done fires on any completed transmission; on_rx_done fires on any completed reception. Check status first: payload data is only valid when SMTC_FLRP_RC_OK.
void on_tx_done( const void* ctx, smtc_flrp_return_code_t status,
bool send_successful, uint8_t* dest_eui )
{
if( status == SMTC_FLRP_RC_OK && send_successful )
/* data delivered to dest_eui */
}
void on_rx_done( const void* ctx, smtc_flrp_return_code_t status,
uint32_t payload_size, uint8_t* src_eui,
smtc_flrp_rx_stats_t stats )
{
if( status == SMTC_FLRP_RC_OK )
/* rx_buf holds payload_size bytes from src_eui; stats has RSSI and burst PER */
}
Sample Projects
Two ready-to-run sample projects are available, covering both bare-metal and Zephyr environments. Each project supports both roles on a single binary; the active role is selected at compile time.
Bare-Metal
Repository: github.com/Lora-net/USP ·
Source: examples/main_examples/flrp_api_example/ ·
Board: NUCLEO-L476 + LR2021
Demonstrates periodic initiator-to-slave transfer (every 20 s by default) and on-demand transfer triggered by a button press on either device. Both roles listen for incoming transfers from the other side, so the example exercises the full bidirectional flow.
Zephyr
Repository: github.com/Lora-net/USP_Zephyr ·
Source: samples/usp/rac/flrp_api/ ·
Board: XIAO nRF54L15 + LoRa Plus EVK (LR2021)
Same behaviour as the bare-metal example: periodic and button-triggered transfers in both directions, ported to the Zephyr RTOS. Demonstrates integration with the Zephyr radio driver abstraction and west build system.
Power Profiler
The interactive power profiler below estimates the energy consumption of each node for a given FLRP-burst configuration. Adjust the TX interval, WOR preset, FLRC burst parameters, and idle/sleep current to see average current, energy per cycle, and a zoomed current waveform in real time.
In the typical FLRP-burst deployment, each node operates simultaneously as initiator and slave: it transmits data on its own schedule while sleeping between transmissions, and wakes up via periodic CAD whenever the other node initiates a transfer. Either node can start an exchange at any time; the initiated transfer takes priority over the idle/sleep cycle. This gives a fully bidirectional link with no dedicated polling master.
The WOR preset controls the trade-off between wake-up latency and receive duty cycle: a longer WOR preamble means the listening node can sleep longer between CAD pulses (lower power), but the initiator takes longer to wake the peer. The two nodes can use different presets independently, allowing an asymmetric design matched to the application.
Node A is a battery-powered camera. TX on event every ~120 s using Preset B (WOR 100 ms): short preamble minimizes TX energy. CAD period ~950 ms (set by Node B's 1 s WOR), receive duty cycle below 2%.
Node B is a mains-powered gateway using Preset A (WOR 1 s). It can reach Node A with under 1 s latency at any time. CAD every ~90 ms (set by Node A's 100 ms WOR): higher receive duty cycle, acceptable on mains.