Component Overview
This page includes the component-level overview maintained in:
components/lora_radio/README.rst.
LoRa Radio Component
Overview
The lora_radio componant provides a FreeRTOS-based LoRa V2V/V2X link-layer driver for ESP32-S3
(and other ESP32 variants) using the RadioLib SX1278 driver.
A single LoraRadio instance manages one SX1278 transceiver over SPI. All radio
hardware access is abstracted behind the IRadioBackend pure-virtual interface, which
makes it possible to inject a mock backend for unit-testing without any real hardware.
Features
Thread-safe transmit queue – call
LoraRadio::send()from any FreeRTOS task.Channel Activity Detection (CAD) – every outgoing frame waits for a clear channel before transmitting, with configurable retry-and-backoff.
Optional ACK with retransmission – set
requestAck = trueinLoraRadio::send()to enable link-layer acknowledged delivery with configurable timeout and retry count.Continuous receive with callback – register a callback with
LoraRadio::setRxCallback()to be notified of every received packet.Neighbour RSSI/SNR table – the component maintains a per-node signal-quality table updated on every received frame, readable via
LoraRadio::getNeighbors().Modem power-save sleep – the radio enters low-power sleep automatically after a configurable idle period and wakes on the next transmit request.
Static FreeRTOS allocation – all FreeRTOS objects (task, queue) use static storage so that no heap allocation occurs after initialisation.
Architecture
┌─────────────────────────────────────────────────────────────────────┐
│ Caller (application) │
│ LoraRadio::send() / setRxCallback() │
└───────────────────────┬─────────────────────────────────────────────┘
│ thread-safe queue push + task notify
┌───────────────────────▼─────────────────────────────────────────────┐
│ FreeRTOS Radio Task (taskLoop) │
│ State machine: IDLE → CAD → TX_WAIT → WAIT_ACK → RX → SLEEPING │
│ All SPI work, IRadioBackend calls, ACK logic live here. │
└───────────────────────▲─────────────────────────────────────────────┘
│ xTaskNotifyFromISR (bitmask)
┌───────────────────────┴─────────────────────────────────────────────┐
│ ISRs: dio0Isr / dio1Isr (IRAM, zero SPI contact) │
│ Only post a notification bit and yield — nothing else. │
└─────────────────────────────────────────────────────────────────────┘
State-machine states:
IDLE – decides whether to dequeue a TX item (→ CAD) or enter receive mode (→ RX).
CAD – performs Channel Activity Detection before each transmission.
TX_WAIT – waits for DIO0 (TX-done interrupt) after starting a transmission.
WAIT_ACK – waits for a link-layer ACK after an acknowledged transmission.
RX – radio in continuous receive; fires the RX callback on each packet.
SLEEPING – radio in low-power modem sleep; woken by a transmit request.
Wire Packet Format
Each frame starts with an 8-byte packed header (PacketHeader) followed by up to
LORA_MAX_PAYLOAD (247) bytes of application payload.
Field |
Size |
Description |
|---|---|---|
|
2 B |
Source node ID. |
|
2 B |
Destination node ID; |
|
1 B |
Rolling sequence number used for ACK matching and deduplication. |
|
1 B |
Caller-defined message type; |
|
1 B |
Bitmask of |
|
1 B |
Number of payload bytes that follow this header. |
Configuration
All tunable parameters are exposed as Kconfig symbols in
components/lora_radio/Kconfig and are mirrored as fields of
LoraRadioConfig. Using the default-constructed
LoraRadioConfig{} selects all Kconfig values so the driver is
board-independent without any code changes.
Key symbols:
Kconfig symbol |
Description |
|---|---|
|
SPI and control GPIO assignments. |
|
RF centre frequency in Hz. |
|
LoRa spreading factor (6–12). |
|
Timeout waiting for a link-layer ACK. |
|
Exposes |
Dependencies
RadioLib (jgromes/radiolib >= 7.6.0) is declared in
components/lora_radio/idf_component.yml and fetched automatically by the
IDF Component Manager. Do not add it to main/idf_component.yml; it is
already transitively available.
ESP Component Registry
This component is structured for direct upload to the ESP Component Registry.
Registry metadata (
version,repository,repository_info.path, and tags) is defined incomponents/lora_radio/idf_component.yml.Component examples are included under
components/lora_radio/examplesso they are packaged with the uploaded component.Example manifests use:
taruntom1/lora_radiofor registry resolution.override_path: ../../for local development before publishing.
Typical upload command (run from components/lora_radio):
compote component upload --namespace taruntom1
Usage Example
#include "lora_radio.hpp"
static void rx_handler(const PacketHeader& hdr,
const uint8_t* payload,
float rssi,
float snr)
{
ESP_LOGI("app", "RX from 0x%04X RSSI=%.1f SNR=%.1f", hdr.srcId, rssi, snr);
}
void app_main(void)
{
LoraRadio radio; // uses Kconfig defaults
radio.setRxCallback(rx_handler);
ESP_ERROR_CHECK(radio.init());
const uint8_t msg[] = "hello";
radio.send(0xFFFF, 0x01, msg, sizeof(msg) - 1);
}
Generating Documentation
The project uses an ESP-IDF-style Sphinx + Doxygen pipeline.
From the repository root:
python -m pip install -r docs/requirements.txt
doxygen docs/doxygen/Doxyfile
build-docs --project-path docs --source-dir docs/en --doxyfile_dir . -t esp32s3 -l en build
Generated outputs:
Doxygen HTML:
docs/doxygen/html/index.htmlDoxygen XML:
docs/doxygen/xmlSphinx HTML:
_build/en/esp32s3/html/index.html