API Reference

LoRa Radio Public API

class LoraRadio

Public Types

enum class State : uint8_t

Radio state machine states. Exposed publicly so tests can observe state without an accessor. Production callers have no reason to read this value.

Values:

enumerator IDLE
enumerator CAD
enumerator TX_WAIT
enumerator WAIT_ACK
enumerator RX
enumerator SLEEPING
using RxCallback = void (*)(const PacketHeader &header, const uint8_t *payload, float rssi, float snr)

Callback invoked (from the radio task) on every received packet. Must be safe to call from a non-ISR FreeRTOS task context.

Public Functions

explicit LoraRadio(const LoraRadioConfig &cfg = LoraRadioConfig{})

Construct a LoraRadio with the given (or default Kconfig) configuration.

Parameters:

cfg – Radio and task configuration. Defaults to Kconfig values.

~LoraRadio()

RAII destructor — calls deinit() automatically.

esp_err_t init()

Initialise hardware (SPI, GPIO, RadioLib, FreeRTOS objects).

Must be called once from app_main before any send or receive operations. Calling this a second time is a no-op.

Returns:

  • ESP_OK on success

  • ESP_FAIL if the radio modem could not be initialised

void deinit()

Gracefully shut down: stop the radio task, put the modem to sleep, and free the SPI bus.

Safe to call even if init() was never called or already failed.

esp_err_t send(uint16_t dstId, uint8_t msgType, const uint8_t *data, size_t len, bool requestAck = false)

Queue a packet for transmission.

The payload is copied into an internal buffer so the caller may free data immediately after this call returns.

Parameters:
  • dstId – Destination node ID (0xFFFF for broadcast).

  • msgType – Caller-defined message type byte (0x04 is reserved for link-layer ACK and must not be used by callers).

  • data – Pointer to the payload bytes to transmit.

  • len – Payload length in bytes (max LORA_MAX_PAYLOAD).

  • requestAck – If true the radio waits for an ACK and retransmits up to maxRetries times on timeout.

Returns:

  • ESP_OK on success

  • ESP_ERR_INVALID_SIZE if len exceeds LORA_MAX_PAYLOAD

  • ESP_ERR_NO_MEM if the transmit queue is full

void setRxCallback(RxCallback cb)

Register a callback that is invoked for every received packet.

Parameters:

cb – Function to call. Pass nullptr to disable.

size_t getNeighbors(NeighborEntry *out, size_t maxCount) const

Copy valid entries from the internal neighbour table into out.

Parameters:
  • out – Output buffer to receive neighbour entries. Must be at least maxCount elements long.

  • maxCount – Maximum number of entries to copy.

Returns:

Number of valid entries written to out.

esp_err_t initForTest(IRadioBackend *backend)

Initialise with an externally supplied (mock) backend instead of a real SX1278. No EspHal or Module is created. The caller retains ownership of backend and must keep it alive until deinit().

void injectNeighborUpdate(uint16_t nodeId, float rssi, float snr)

Directly invoke the neighbour-table update path (bypasses radio).

inline State getState() const

Expose the current state-machine state for assertion in tests. NOTE: Reading this from a different task is inherently racy; always add a short vTaskDelay before asserting to let the radio task settle.

struct LoraRadioConfig

Runtime configuration for LoraRadio.

All fields carry Kconfig defaults, so LoraRadioConfig{} is a valid, board-independent configuration. Override individual members to adapt to a specific board without touching sdkconfig.

Public Members

int spiHost = CONFIG_LORA_SPI_HOST

ESP-IDF SPI host identifier (e.g. SPI2_HOST)

int pinSck = CONFIG_LORA_PIN_SCK

GPIO number for the SPI clock line.

int pinMiso = CONFIG_LORA_PIN_MISO

GPIO number for the MISO line.

int pinMosi = CONFIG_LORA_PIN_MOSI

GPIO number for the MOSI line.

int pinNss = CONFIG_LORA_PIN_NSS

GPIO number for chip-select (NSS / CS)

int pinRst = CONFIG_LORA_PIN_RST

GPIO number for hardware reset.

int pinDio0 = CONFIG_LORA_PIN_DIO0

GPIO number for DIO0 interrupt (TX-done / RX-done / CAD-clear)

int pinDio1 = CONFIG_LORA_PIN_DIO1

GPIO number for DIO1 interrupt (CAD-busy); use RADIO_PIN_NC if not connected.

float frequencyMHz = CONFIG_LORA_FREQUENCY_HZ / 1e6f

Centre frequency in MHz.

float bandwidthKHz = CONFIG_LORA_BANDWIDTH_HZ / 1e3f

Signal bandwidth in kHz.

uint8_t spreadingFactor = CONFIG_LORA_SPREADING_FACTOR

LoRa spreading factor (6–12)

uint8_t codingRate = CONFIG_LORA_CODING_RATE

Coding-rate denominator (5–8, meaning 4/5 … 4/8)

int8_t txPowerDbm = CONFIG_LORA_TX_POWER_DBM

TX output power in dBm.

uint8_t syncWord = CONFIG_LORA_SYNC_WORD

1-byte LoRa sync word (0x12 = private, 0x34 = LoRaWAN)

uint16_t nodeId = CONFIG_LORA_NODE_ID

This node’s 16-bit network identifier.

uint32_t taskStackSize = 4096

Radio task stack size in bytes.

uint32_t taskPriority = CONFIG_LORA_TASK_PRIORITY

Radio task FreeRTOS priority.

uint32_t txQueueDepth = 4

Depth of the transmit queue (in TxItem units)

uint32_t maxNeighbors = 16

Maximum number of neighbour table entries.

uint32_t maxRetries = CONFIG_LORA_MAX_RETRIES

Maximum ACK retransmission attempts.

uint32_t ackTimeoutMs = CONFIG_LORA_ACK_TIMEOUT_MS

Timeout waiting for a link-layer ACK (ms)

uint32_t sleepIdleMs = CONFIG_LORA_SLEEP_IDLE_MS

Idle time before entering modem sleep (ms)

uint32_t cadRetries = CONFIG_LORA_CAD_RETRIES

Maximum CAD retries before dropping a packet.

class IRadioBackend

Pure-virtual interface that abstracts all radio hardware operations.

Every method maps 1-to-1 onto a RadioLib SX1278 API call. Concrete implementations include Sx1278Backend (production) and MockRadioBackend (unit tests). LoraRadio’s state machine holds an IRadioBackend* and never calls RadioLib or touches SPI directly.

Subclassed by Sx1278Backend

Public Functions

virtual int16_t begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t power) = 0

Configure the radio modem with the given RF parameters. Equivalent to SX1278::begin().

Parameters:
  • freq – Centre frequency in MHz.

  • bw – Signal bandwidth in kHz.

  • sf – Spreading factor (6–12).

  • cr – Coding-rate denominator (5–8, meaning 4/5 … 4/8).

  • syncWord – 1-byte sync word (0x12 = private, 0x34 = LoRaWAN).

  • power – TX power in dBm.

Returns:

RADIO_ERR_NONE on success, negative error code on failure.

virtual void setDio0Action(void (*cb)(void), uint32_t dir) = 0

Attach the DIO0 interrupt callback.

Parameters:
  • cb – Function to call when DIO0 fires.

  • dir – Trigger direction (e.g. RADIO_RISING).

virtual void clearDio0Action() = 0

Detach the DIO0 interrupt callback.

virtual void setDio1Action(void (*cb)(void), uint32_t dir) = 0

Attach the DIO1 interrupt callback.

Parameters:
  • cb – Function to call when DIO1 fires.

  • dir – Trigger direction (e.g. RADIO_RISING).

virtual void clearDio1Action() = 0

Detach the DIO1 interrupt callback.

virtual int16_t startChannelScan() = 0

Begin a CAD scan. DIO0 fires when the scan finishes (channel clear); DIO1 fires if busy.

Returns:

RADIO_ERR_NONE on success, negative error code on failure.

virtual int16_t getChannelScanResult() = 0

Read the CAD result after DIO0 fires.

Returns:

RADIO_LORA_DETECTED (channel busy) or RADIO_CHANNEL_FREE.

virtual int16_t startTransmit(uint8_t *data, size_t len) = 0

Begin an asynchronous transmission. DIO0 fires when TX is complete.

Parameters:
  • data – Pointer to the frame bytes to transmit.

  • len – Number of bytes to transmit.

Returns:

RADIO_ERR_NONE on success, negative error code on failure.

virtual int16_t finishTransmit() = 0

Finalise a completed transmission. Must be called after DIO0 fires for TX-done to reset modem state.

Returns:

RADIO_ERR_NONE on success, negative error code on failure.

virtual int16_t startReceive() = 0

Enter continuous receive mode. DIO0 fires when a packet is ready to read.

Returns:

RADIO_ERR_NONE on success, negative error code on failure.

virtual size_t getPacketLength() = 0

Return the byte-length of the most recently received packet.

virtual int16_t readData(uint8_t *data, size_t len) = 0

Copy the received packet bytes into data.

Parameters:
  • data – Output buffer (must be at least len bytes).

  • len – Number of bytes to read.

Returns:

RADIO_ERR_NONE on success, negative error code on CRC failure etc.

virtual float getRSSI() = 0

RSSI of the most recently received packet (dBm).

virtual float getSNR() = 0

SNR of the most recently received packet (dB).

virtual int16_t sleep() = 0

Enter low-power modem sleep.

Returns:

RADIO_ERR_NONE on success, negative error code on failure.

virtual int16_t standby() = 0

Return to standby mode (cancels sleep or continuous receive).

Returns:

RADIO_ERR_NONE on success, negative error code on failure.

class Sx1278Backend : public IRadioBackend

IRadioBackend adapter for the RadioLib SX1278 driver.

Forwards every IRadioBackend virtual call directly to the underlying SX1278 instance. The SX1278 object is created and owned by LoraRadio::init(); this class only holds a non-owning pointer.

Public Functions

inline explicit Sx1278Backend(SX1278 *radio)

Construct the backend around an already-created SX1278 object.

Parameters:

radio – Non-owning pointer to the SX1278 instance. Must remain valid for the lifetime of this Sx1278Backend.

inline virtual int16_t begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t power) override

Configure the radio modem with the given RF parameters. Equivalent to SX1278::begin().

Parameters:
  • freq – Centre frequency in MHz.

  • bw – Signal bandwidth in kHz.

  • sf – Spreading factor (6–12).

  • cr – Coding-rate denominator (5–8, meaning 4/5 … 4/8).

  • syncWord – 1-byte sync word (0x12 = private, 0x34 = LoRaWAN).

  • power – TX power in dBm.

Returns:

RADIO_ERR_NONE on success, negative error code on failure.

inline virtual void setDio0Action(void (*cb)(void), uint32_t dir) override

Attach the DIO0 interrupt callback.

Parameters:
  • cb – Function to call when DIO0 fires.

  • dir – Trigger direction (e.g. RADIO_RISING).

inline virtual void clearDio0Action() override

Detach the DIO0 interrupt callback.

inline virtual void setDio1Action(void (*cb)(void), uint32_t dir) override

Attach the DIO1 interrupt callback.

Parameters:
  • cb – Function to call when DIO1 fires.

  • dir – Trigger direction (e.g. RADIO_RISING).

inline virtual void clearDio1Action() override

Detach the DIO1 interrupt callback.

inline virtual int16_t startChannelScan() override

Begin a CAD scan. DIO0 fires when the scan finishes (channel clear); DIO1 fires if busy.

Returns:

RADIO_ERR_NONE on success, negative error code on failure.

inline virtual int16_t getChannelScanResult() override

Read the CAD result after DIO0 fires.

Returns:

RADIO_LORA_DETECTED (channel busy) or RADIO_CHANNEL_FREE.

inline virtual int16_t startTransmit(uint8_t *data, size_t len) override

Begin an asynchronous transmission. DIO0 fires when TX is complete.

Parameters:
  • data – Pointer to the frame bytes to transmit.

  • len – Number of bytes to transmit.

Returns:

RADIO_ERR_NONE on success, negative error code on failure.

inline virtual int16_t finishTransmit() override

Finalise a completed transmission. Must be called after DIO0 fires for TX-done to reset modem state.

Returns:

RADIO_ERR_NONE on success, negative error code on failure.

inline virtual int16_t startReceive() override

Enter continuous receive mode. DIO0 fires when a packet is ready to read.

Returns:

RADIO_ERR_NONE on success, negative error code on failure.

inline virtual size_t getPacketLength() override

Return the byte-length of the most recently received packet.

inline virtual int16_t readData(uint8_t *data, size_t len) override

Copy the received packet bytes into data.

Parameters:
  • data – Output buffer (must be at least len bytes).

  • len – Number of bytes to read.

Returns:

RADIO_ERR_NONE on success, negative error code on CRC failure etc.

inline virtual float getRSSI() override

RSSI of the most recently received packet (dBm).

inline virtual float getSNR() override

SNR of the most recently received packet (dB).

inline virtual int16_t sleep() override

Enter low-power modem sleep.

Returns:

RADIO_ERR_NONE on success, negative error code on failure.

inline virtual int16_t standby() override

Return to standby mode (cancels sleep or continuous receive).

Returns:

RADIO_ERR_NONE on success, negative error code on failure.