Rev. 0.5  ·  2026
User Guide  ·  Rev. 0.5

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:

LimitationMitigationCost
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:

Key capabilities

Regulatory compliance

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

RoleDescription
InitiatorAlways starts the exchange by sending the WOR. Addresses the slave by DevEUI.
SlaveWaits in periodic LoRa periodic CAD sleep. Wakes up and answers the WOR.

Data-direction roles (set per exchange)

Transfer DirectionInitiatorSlaveUse case
0: initiator receivesReceiverTransmitterSensor data upload
1: initiator sendsTransmitterReceiverFirmware / 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.

FLRC LoRa
Data direction: Slave → Initiator  ·  mode 0
1. CONNECTION SETUP 2. ADAPTIVE LINK 3. DATA BURST 4. DATA INTEGRITY CHECK INITIATOR WOR FLRC ACK FLRC ACK FLRC ACK BURST ACK BURST ACK SLAVE Periodic CAD WOR ACK FLRC REQ FLRC REQ FLRC REQ FLRC BURST Max 400 ms FLRC BURST (retry)
Data direction: Initiator → Slave  ·  mode 1
INITIATOR WOR FLRC REQ FLRC REQ FLRC REQ FLRC BURST Max 400 ms FLRC BURST (retry) SLAVE Periodic CAD WOR ACK FLRC ACK FLRC ACK FLRC ACK BURST ACK BURST ACK
Figure 1: FLRP-burst protocol timing. Phases 1–2 are identical for both directions. In Phase 3–4 the data flow (FLRC BURST / BURST ACK) swaps lanes. Time flows left → right.
WORtarget DevEUI · channels · default DR
WOR ACKselected DR · min interframe delay
  • 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.
FLRC REQ × 3 (up to 16)one per enabled channel
FLRC ACK × 3 (up to 16)best channel · DR · burst params
  • 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.
FLRC BURSTup to 255 packets · 300–400 B each
  • 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.
BURST ACKmissing-packet bitmap · link quality
FLRC BURST (retry)missing packets only
BURST ACKall received
  • 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

FLRP-burst API documentation

The official, up-to-date documentation is maintained alongside the source in the USP repositories:

github.com/Lora-net/USP · Doc: doc/

github.com/Lora-net/USP_Zephyr · 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.

1

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_modeCallDirectionBehavior
BIDIRECTIONALinitiate_transmission()Initiator → SlaveBURST ACK + retry; slave can piggyback a reply
BIDIRECTIONALinitiate_reception()Initiator ← SlaveSlave must have data armed via slave_prepare_data_to_send()
Note

Either call can be made while the device is also running slave periodic listening; the initiated exchange takes priority.

2

Run the same engine loop as the slave.

while( 1 )
{
    if( smtc_flrp_call_run() )
        smtc_flrp_run_engine();
}
3

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.

1

Start periodic listening with a receive buffer.

static uint8_t rx_buf[20 * 1024];

smtc_flrp_start_periodic_listening( rx_buf, sizeof( rx_buf ) );
2

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 */
3

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 */
}
4

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.

Example use case (Default settings): security camera / gateway

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.

General TX Power +14 dBm Supply 3.3 V
Node A
Schedule
s
WOR TX Duration 27 mA
ms
FLRC TX 26 mA
B
µs
TOA: ms · 26 mA
Idle / Sleep 2 µA default
µA
Avg current
Energy / cycle µAh
TX duration · duty cycle
Latency
FLRC burst eff. baud rate
Net throughput
Node A: TX + CAD
WOR TX ACK + CH Sel FLRC TX CAD Sleep
Node B
Schedule
s
WOR TX Duration 27 mA
ms
FLRC TX 26 mA
B
µs
TOA: ms · 26 mA
Idle / Sleep 2 µA default
µA
Avg current
Energy / cycle µAh
TX duration · duty cycle
Latency
FLRC burst eff. baud rate
Net throughput
Node B: TX + CAD
WOR TX ACK + CH Sel FLRC TX CAD Sleep