23 static constexpr uint8_t REG_FIFO = 0x00;
24 static constexpr uint8_t REG_OP_MODE = 0x01;
25 static constexpr uint8_t REG_FRF_MSB = 0x06;
26 static constexpr uint8_t REG_FRF_MID = 0x07;
27 static constexpr uint8_t REG_FRF_LSB = 0x08;
28 static constexpr uint8_t REG_PA_CONFIG = 0x09;
29 static constexpr uint8_t REG_FIFO_ADDR_PTR = 0x0D;
30 static constexpr uint8_t REG_FIFO_TX_BASE = 0x0E;
31 static constexpr uint8_t REG_FIFO_RX_BASE = 0x0F;
32 static constexpr uint8_t REG_FIFO_RX_CURRENT = 0x10;
33 static constexpr uint8_t REG_IRQ_FLAGS = 0x12;
34 static constexpr uint8_t REG_RX_NB_BYTES = 0x13;
35 static constexpr uint8_t REG_PKT_RSSI = 0x1A;
36 static constexpr uint8_t REG_MODEM_CONFIG1 = 0x1D;
37 static constexpr uint8_t REG_MODEM_CONFIG2 = 0x1E;
38 static constexpr uint8_t REG_PREAMBLE_MSB = 0x20;
39 static constexpr uint8_t REG_PREAMBLE_LSB = 0x21;
40 static constexpr uint8_t REG_PAYLOAD_LENGTH = 0x22;
41 static constexpr uint8_t REG_MODEM_CONFIG3 = 0x26;
42 static constexpr uint8_t REG_SYNC_WORD = 0x39;
43 static constexpr uint8_t REG_VERSION = 0x42;
49 static constexpr uint8_t MODE_LORA = 0x80;
50 static constexpr uint8_t MODE_SLEEP = 0x00;
51 static constexpr uint8_t MODE_STDBY = 0x01;
52 static constexpr uint8_t MODE_TX = 0x03;
53 static constexpr uint8_t MODE_RX_CONT = 0x05;
59 static constexpr uint8_t IRQ_TX_DONE = 0x08;
60 static constexpr uint8_t IRQ_PAYLOAD_CRC_ERROR = 0x20;
61 static constexpr uint8_t IRQ_RX_DONE = 0x40;
64const uint8_t SX127X_VERSION = 0x12;
66inline uint8_t rd(
const lora_bus *b, uint8_t reg)
68 return b->read(reg, b->ctx);
70inline void wr(
const lora_bus *b, uint8_t reg, uint8_t val)
72 b->write(reg, val, b->ctx);
76bool lora_frame_parse(
const uint8_t *raw, uint16_t len, lora_header *hdr,
const uint8_t **payload,
77 uint16_t *payload_len)
79 if (!raw || !hdr || len < 4)
88 *payload_len = (uint16_t)(len - 4);
92uint16_t lora_frame_build(
const lora_header *hdr,
const uint8_t *payload, uint16_t len, uint8_t *out, uint16_t cap)
100 for (uint16_t i = 0; i < len; i++)
101 out[4 + i] = payload[i];
102 return (uint16_t)(len + 4);
105bool lora_init(
const lora_bus *bus,
const lora_config *cfg)
107 if (!bus || !bus->read || !bus->write || !cfg)
109 if (rd(bus, LoraReg::REG_VERSION) != SX127X_VERSION)
113 wr(bus, LoraReg::REG_OP_MODE, LoraMode::MODE_SLEEP);
114 wr(bus, LoraReg::REG_OP_MODE, LoraMode::MODE_LORA | LoraMode::MODE_SLEEP);
115 wr(bus, LoraReg::REG_OP_MODE, LoraMode::MODE_LORA | LoraMode::MODE_STDBY);
118 uint32_t frf = (uint32_t)(((uint64_t)cfg->freq_hz << 19) / 32000000UL);
119 wr(bus, LoraReg::REG_FRF_MSB, (uint8_t)(frf >> 16));
120 wr(bus, LoraReg::REG_FRF_MID, (uint8_t)(frf >> 8));
121 wr(bus, LoraReg::REG_FRF_LSB, (uint8_t)frf);
123 wr(bus, LoraReg::REG_FIFO_TX_BASE, 0x00);
124 wr(bus, LoraReg::REG_FIFO_RX_BASE, 0x00);
127 wr(bus, LoraReg::REG_MODEM_CONFIG1, (uint8_t)((cfg->bandwidth << 4) | (cfg->coding_rate << 1)));
128 wr(bus, LoraReg::REG_MODEM_CONFIG2, (uint8_t)((cfg->spreading << 4) | 0x04));
129 wr(bus, LoraReg::REG_MODEM_CONFIG3, (uint8_t)((cfg->spreading >= 11 ? 0x08 : 0x00) | 0x04));
131 wr(bus, LoraReg::REG_PREAMBLE_MSB, 0x00);
132 wr(bus, LoraReg::REG_PREAMBLE_LSB, 0x08);
133 wr(bus, LoraReg::REG_SYNC_WORD, cfg->sync_word);
134 wr(bus, LoraReg::REG_PA_CONFIG, (uint8_t)(0x80 | ((cfg->tx_power - 2) & 0x0F)));
136 wr(bus, LoraReg::REG_OP_MODE, LoraMode::MODE_LORA | LoraMode::MODE_STDBY);
140bool lora_send(
const lora_bus *bus,
const uint8_t *frame, uint8_t len)
144 wr(bus, LoraReg::REG_OP_MODE, LoraMode::MODE_LORA | LoraMode::MODE_STDBY);
145 wr(bus, LoraReg::REG_FIFO_ADDR_PTR, 0x00);
146 for (uint8_t i = 0; i < len; i++)
147 wr(bus, LoraReg::REG_FIFO, frame[i]);
148 wr(bus, LoraReg::REG_PAYLOAD_LENGTH, len);
149 wr(bus, LoraReg::REG_OP_MODE, LoraMode::MODE_LORA | LoraMode::MODE_TX);
153bool lora_tx_done(
const lora_bus *bus)
157 if (rd(bus, LoraReg::REG_IRQ_FLAGS) & LoraIrq::IRQ_TX_DONE)
159 wr(bus, LoraReg::REG_IRQ_FLAGS, 0xFF);
165void lora_set_rx(
const lora_bus *bus)
169 wr(bus, LoraReg::REG_FIFO_ADDR_PTR, 0x00);
170 wr(bus, LoraReg::REG_OP_MODE, LoraMode::MODE_LORA | LoraMode::MODE_RX_CONT);
173int lora_recv(
const lora_bus *bus, uint8_t *buf, uint8_t cap, int16_t *rssi)
177 uint8_t flags = rd(bus, LoraReg::REG_IRQ_FLAGS);
178 if (!(flags & LoraIrq::IRQ_RX_DONE))
180 if (flags & LoraIrq::IRQ_PAYLOAD_CRC_ERROR)
182 wr(bus, LoraReg::REG_IRQ_FLAGS, 0xFF);
185 uint8_t len = rd(bus, LoraReg::REG_RX_NB_BYTES);
186 wr(bus, LoraReg::REG_FIFO_ADDR_PTR, rd(bus, LoraReg::REG_FIFO_RX_CURRENT));
188 for (uint8_t i = 0; i < len; i++)
190 uint8_t b = rd(bus, LoraReg::REG_FIFO);
195 *rssi = (int16_t)(-157 + rd(bus, LoraReg::REG_PKT_RSSI));
196 wr(bus, LoraReg::REG_IRQ_FLAGS, 0xFF);
#define DETWS_LORA_MAX_PAYLOAD
Max LoRa payload bytes (SX127x FIFO is 256; RadioHead uses 251 + 4 header).
LoRa radio codec + driver (DETWS_ENABLE_LORA) - Semtech SX127x / RFM95-96.