ProtoCore v1.0.16
Deterministic, zero-heap network stack for embedded targets
Loading...
Searching...
No Matches
lora.h
Go to the documentation of this file.
1// ProtoCore v1.0.16 - Copyright (C) 2026 Douglas Quigg (dstroy0) <dquigg123@gmail.com>
2// SPDX-License-Identifier: AGPL-3.0-or-later
3
4#ifndef PROTOCORE_LORA_H
5#define PROTOCORE_LORA_H
6
7#include "protocore_config.h" // the entry point: protocore_types.h for the widths
8
10
11/**
12 * @file lora.h
13 * @brief LoRa radio codec + driver (PROTOCORE_ENABLE_LORA) - Semtech SX127x / RFM95-96.
14 *
15 * A per-radio plugin for the gateway (PROTOCORE_ENABLE_GATEWAY): the southbound-radio half of
16 * a LoRa-to-web bridge. Two layers:
17 *
18 * - **Codec** - the RadioHead-compatible 4-byte frame header (`to` / `from` / `id` /
19 * `flags`) that virtually every hobby / sensor LoRa deployment uses on top of the
20 * header-less LoRa PHY. protocore_lora_frame_parse() splits a received frame into that header and
21 * the payload; protocore_lora_frame_build() prepends it. Pure, no hardware.
22 * - **Driver** - the SX127x register protocol (init / send / receive / enter-RX) over a
23 * caller-supplied register-access **bus** (@ref protocore_lora_bus). The SPI transfer and the
24 * chip-select / reset GPIOs are the integration's - you implement two callbacks that
25 * read and write a chip register - so the register sequence is host-testable with a mock
26 * bus and portable across whatever SPI peripheral you wire the module to.
27 *
28 * Wiring to the gateway (see example LoRaGateway): poll protocore_lora_recv(); on a frame,
29 * protocore_lora_frame_parse() then protocore_gateway_uplink(port, header.from, payload, len, rssi). A downlink
30 * builds a frame with protocore_lora_frame_build() and protocore_lora_send()s it. The codec + register protocol
31 * are verified on the host; the RF link itself needs the module.
32 *
33 * @c work is bytes the CALLER holds. This module reads none of them: it carries nothing
34 * between calls, so there is no state to keep and nothing to wipe. The parameter is there so
35 * a caller drives every namespace the same way.
36 *
37 * @author Douglas Quigg (dstroy0)
38 * @date 2026
39 */
40
41// PROTOCORE_LORA_BORROW - the bytes this module runs out of - is stated in protocore_config.h, which sums
42// it into its arena. Its size and its offset are each a static_assert, so a feature
43// combination that does not fit fails to compile rather than overrunning at run time.
44
45/** @brief RadioHead-compatible LoRa frame header (precedes the payload). */
46typedef struct
47{
48 uint8_t to; ///< destination node address (0xFF = broadcast)
49 uint8_t from; ///< source node address
50 uint8_t id; ///< sequence / message id
51 uint8_t flags; ///< application flags
53
54/** @brief Read one SX127x register (@p reg is the bare 7-bit address). */
55typedef uint8_t (*protocore_lora_reg_read_fn)(uint8_t reg, void *ctx);
56
57/** @brief Write one SX127x register (@p reg is the bare 7-bit address). */
58typedef void (*protocore_lora_reg_write_fn)(uint8_t reg, uint8_t val, void *ctx);
59
60/** @brief The register-access bus a driver call uses (your SPI + chip-select behind it). */
67
68/** @brief Radio configuration applied by protocore_lora_init(). */
69typedef struct
70{
71 uint32_t freq_hz; ///< carrier frequency in Hz (e.g. 868100000 / 915000000).
72 uint8_t spreading; ///< spreading factor 6..12 (SF7 default is a good start).
73 uint8_t bandwidth; ///< bandwidth code 0..9 (7 = 125 kHz - the common default).
74 uint8_t coding_rate; ///< coding rate 1..4 (1 = 4/5).
75 uint8_t sync_word; ///< 0x12 private / 0x34 LoRaWAN.
76 uint8_t tx_power; ///< PA_BOOST power 2..17 dBm.
78
79/** @brief Dispatch table. Addressed by offset, so the layout is asserted below. */
80typedef struct
81{
82 proto_bool (*frame_parse)(uint8_t *, const uint8_t *, uint16_t, protocore_lora_header *, const uint8_t **,
83 uint16_t *);
84 uint16_t (*frame_build)(uint8_t *, const protocore_lora_header *, const uint8_t *, uint16_t, uint8_t *, uint16_t);
85 proto_bool (*init)(uint8_t *, const protocore_lora_bus *, const protocore_lora_config *);
86 proto_bool (*send)(uint8_t *, const protocore_lora_bus *, const uint8_t *, uint8_t);
87 proto_bool (*tx_done)(uint8_t *, const protocore_lora_bus *);
88 void (*set_rx)(uint8_t *, const protocore_lora_bus *);
89 int (*recv)(uint8_t *, const protocore_lora_bus *, uint8_t *, uint8_t, int16_t *);
90} LoraNs;
91PROTOCORE_NS_LAYOUT(LoraNs, frame_parse, frame_build, init, send, tx_done, set_rx, recv);
92
93/**
94 * @brief Split a received frame into its header and payload.
95 * @param work PROTOCORE_LORA_BORROW bytes the caller took. Not held past the call.
96 * @param raw Raw
97 * @param len Len
98 * @param hdr Hdr
99 * @param payload Payload
100 * @param payload_len Payload len
101 * @return PROTO_TRUE on success.
102 */
103proto_bool protocore_lora_frame_parse(uint8_t *work, const uint8_t *raw, uint16_t len, protocore_lora_header *hdr,
104 const uint8_t **payload, uint16_t *payload_len);
105/**
106 * @brief Build a frame (header + payload) into out.
107 * @param work PROTOCORE_LORA_BORROW bytes the caller took. Not held past the call.
108 * @param hdr Hdr
109 * @param payload Payload
110 * @param len Len
111 * @param out Out
112 * @param cap Cap
113 * @return The uint16_t.
114 */
115uint16_t protocore_lora_frame_build(uint8_t *work, const protocore_lora_header *hdr, const uint8_t *payload,
116 uint16_t len, uint8_t *out, uint16_t cap);
117/**
118 * @brief Initialize the SX127x: verify the chip, switch to LoRa mode, and .
119 * @param work PROTOCORE_LORA_BORROW bytes the caller took. Not held past the call.
120 * @param bus Bus
121 * @param cfg Cfg
122 * @return PROTO_TRUE on success.
123 */
125/**
126 * @brief Load frame into the FIFO and start a transmit (the radio returns to .
127 * @param work PROTOCORE_LORA_BORROW bytes the caller took. Not held past the call.
128 * @param bus Bus
129 * @param frame Frame
130 * @param len Len
131 * @return PROTO_TRUE on success.
132 */
133proto_bool protocore_lora_send(uint8_t *work, const protocore_lora_bus *bus, const uint8_t *frame, uint8_t len);
134/**
135 * @brief True once a transmit has finished (RegIrqFlags TxDone); clears the .
136 * @param work PROTOCORE_LORA_BORROW bytes the caller took. Not held past the call.
137 * @param bus Bus
138 * @return PROTO_TRUE on success.
139 */
141/**
142 * @brief Put the radio in continuous-receive mode (call once, then poll .
143 * @param work PROTOCORE_LORA_BORROW bytes the caller took. Not held past the call.
144 * @param bus Bus
145 */
146void protocore_lora_set_rx(uint8_t *work, const protocore_lora_bus *bus);
147/**
148 * @brief If a frame has been received, copy it into buf and report its RSSI.
149 * @param work PROTOCORE_LORA_BORROW bytes the caller took. Not held past the call.
150 * @param bus Bus
151 * @param buf Buf
152 * @param cap Cap
153 * @param rssi Rssi
154 * @return The int.
155 */
156int protocore_lora_recv(uint8_t *work, const protocore_lora_bus *bus, uint8_t *buf, uint8_t cap, int16_t *rssi);
157
158/** @brief Read one SX127x register (@p reg is the bare 7-bit address). */
159typedef uint8_t (*protocore_lora_reg_read_fn)(uint8_t reg, void *ctx);
160/** @brief Write one SX127x register (@p reg is the bare 7-bit address). */
161typedef void (*protocore_lora_reg_write_fn)(uint8_t reg, uint8_t val, void *ctx);
162
163/** @brief Module namespace. */
171
173
174#endif // PROTOCORE_LORA_H
int protocore_lora_recv(uint8_t *work, const protocore_lora_bus *bus, uint8_t *buf, uint8_t cap, int16_t *rssi)
If a frame has been received, copy it into buf and report its RSSI.
void protocore_lora_set_rx(uint8_t *work, const protocore_lora_bus *bus)
Put the radio in continuous-receive mode (call once, then poll .
proto_bool protocore_lora_tx_done(uint8_t *work, const protocore_lora_bus *bus)
True once a transmit has finished (RegIrqFlags TxDone); clears the .
proto_bool protocore_lora_init(uint8_t *work, const protocore_lora_bus *bus, const protocore_lora_config *cfg)
Initialize the SX127x: verify the chip, switch to LoRa mode, and .
uint16_t protocore_lora_frame_build(uint8_t *work, const protocore_lora_header *hdr, const uint8_t *payload, uint16_t len, uint8_t *out, uint16_t cap)
Build a frame (header + payload) into out.
uint8_t(* protocore_lora_reg_read_fn)(uint8_t reg, void *ctx)
Read one SX127x register (reg is the bare 7-bit address).
Definition lora.h:55
proto_bool protocore_lora_send(uint8_t *work, const protocore_lora_bus *bus, const uint8_t *frame, uint8_t len)
Load frame into the FIFO and start a transmit (the radio returns to .
PROTOCORE_NS LoraNs Lora PROTOCORE_UNUSED
Module namespace.
Definition lora.h:164
proto_bool protocore_lora_frame_parse(uint8_t *work, const uint8_t *raw, uint16_t len, protocore_lora_header *hdr, const uint8_t **payload, uint16_t *payload_len)
Split a received frame into its header and payload.
void(* protocore_lora_reg_write_fn)(uint8_t reg, uint8_t val, void *ctx)
Write one SX127x register (reg is the bare 7-bit address).
Definition lora.h:58
#define PROTOCORE_NS_LAYOUT(T,...)
Pin every dispatch slot of a table that is nothing but function pointers.
#define PROTOCORE_NS
Storage for a dispatch table. The const is load bearing.
Dispatch table. Addressed by offset, so the layout is asserted below.
Definition lora.h:81
proto_bool(* frame_parse)(uint8_t *, const uint8_t *, uint16_t, protocore_lora_header *, const uint8_t **, uint16_t *)
Definition lora.h:82
The register-access bus a driver call uses (your SPI + chip-select behind it).
Definition lora.h:62
protocore_lora_reg_write_fn write
Definition lora.h:64
protocore_lora_reg_read_fn read
Definition lora.h:63
Radio configuration applied by protocore_lora_init().
Definition lora.h:70
uint32_t freq_hz
carrier frequency in Hz (e.g. 868100000 / 915000000).
Definition lora.h:71
uint8_t bandwidth
bandwidth code 0..9 (7 = 125 kHz - the common default).
Definition lora.h:73
uint8_t sync_word
0x12 private / 0x34 LoRaWAN.
Definition lora.h:75
uint8_t spreading
spreading factor 6..12 (SF7 default is a good start).
Definition lora.h:72
uint8_t tx_power
PA_BOOST power 2..17 dBm.
Definition lora.h:76
uint8_t coding_rate
coding rate 1..4 (1 = 4/5).
Definition lora.h:74
RadioHead-compatible LoRa frame header (precedes the payload).
Definition lora.h:47
uint8_t flags
application flags
Definition lora.h:51
uint8_t from
source node address
Definition lora.h:49
uint8_t id
sequence / message id
Definition lora.h:50
uint8_t to
destination node address (0xFF = broadcast)
Definition lora.h:48
#define PROTOCORE_BEGIN_DECLS
Give a header's declarations C linkage, so their symbol names carry no parameter types.
Definition types.h:96
_Bool proto_bool
The truth value.
Definition types.h:64
#define PROTOCORE_END_DECLS
Definition types.h:97