1 /*
2 * Copyright (c) 2019 Manivannan Sadhasivam
3 * Copyright (c) 2020 Grinn
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 */
7
8 #include <zephyr/drivers/gpio.h>
9 #include <zephyr/drivers/lora.h>
10 #include <zephyr/logging/log.h>
11 #include <zephyr/sys/atomic.h>
12 #include <zephyr/kernel.h>
13
14 /* LoRaMac-node specific includes */
15 #include <radio.h>
16
17 #include "sx12xx_common.h"
18
19 #define STATE_FREE 0
20 #define STATE_BUSY 1
21 #define STATE_CLEANUP 2
22
23 LOG_MODULE_REGISTER(sx12xx_common, CONFIG_LORA_LOG_LEVEL);
24
25 struct sx12xx_rx_params {
26 uint8_t *buf;
27 uint8_t *size;
28 int16_t *rssi;
29 int8_t *snr;
30 };
31
32 static struct sx12xx_data {
33 const struct device *dev;
34 struct k_poll_signal *operation_done;
35 lora_recv_cb async_rx_cb;
36 void *async_user_data;
37 RadioEvents_t events;
38 struct lora_modem_config tx_cfg;
39 atomic_t modem_usage;
40 struct sx12xx_rx_params rx_params;
41 } dev_data;
42
__sx12xx_configure_pin(const struct gpio_dt_spec * gpio,gpio_flags_t flags)43 int __sx12xx_configure_pin(const struct gpio_dt_spec *gpio, gpio_flags_t flags)
44 {
45 int err;
46
47 if (!device_is_ready(gpio->port)) {
48 LOG_ERR("GPIO device not ready %s", gpio->port->name);
49 return -ENODEV;
50 }
51
52 err = gpio_pin_configure_dt(gpio, flags);
53 if (err) {
54 LOG_ERR("Cannot configure gpio %s %d: %d", gpio->port->name,
55 gpio->pin, err);
56 return err;
57 }
58
59 return 0;
60 }
61
62 /**
63 * @brief Attempt to acquire the modem for operations
64 *
65 * @param data common sx12xx data struct
66 *
67 * @retval true if modem was acquired
68 * @retval false otherwise
69 */
modem_acquire(struct sx12xx_data * data)70 static inline bool modem_acquire(struct sx12xx_data *data)
71 {
72 return atomic_cas(&data->modem_usage, STATE_FREE, STATE_BUSY);
73 }
74
75 /**
76 * @brief Safely release the modem from any context
77 *
78 * This function can be called from any context and guarantees that the
79 * release operations will only be run once.
80 *
81 * @param data common sx12xx data struct
82 *
83 * @retval true if modem was released by this function
84 * @retval false otherwise
85 */
modem_release(struct sx12xx_data * data)86 static bool modem_release(struct sx12xx_data *data)
87 {
88 /* Increment atomic so both acquire and release will fail */
89 if (!atomic_cas(&data->modem_usage, STATE_BUSY, STATE_CLEANUP)) {
90 return false;
91 }
92 /* Put radio back into sleep mode */
93 Radio.Sleep();
94 /* Completely release modem */
95 data->operation_done = NULL;
96 atomic_clear(&data->modem_usage);
97 return true;
98 }
99
sx12xx_ev_rx_done(uint8_t * payload,uint16_t size,int16_t rssi,int8_t snr)100 static void sx12xx_ev_rx_done(uint8_t *payload, uint16_t size, int16_t rssi,
101 int8_t snr)
102 {
103 struct k_poll_signal *sig = dev_data.operation_done;
104
105 /* Receiving in asynchronous mode */
106 if (dev_data.async_rx_cb) {
107 /* Start receiving again */
108 Radio.Rx(0);
109 /* Run the callback */
110 dev_data.async_rx_cb(dev_data.dev, payload, size, rssi, snr,
111 dev_data.async_user_data);
112 /* Don't run the synchronous code */
113 return;
114 }
115
116 /* Manually release the modem instead of just calling modem_release
117 * as we need to perform cleanup operations while still ensuring
118 * others can't use the modem.
119 */
120 if (!atomic_cas(&dev_data.modem_usage, STATE_BUSY, STATE_CLEANUP)) {
121 return;
122 }
123 /* We can make two observations here:
124 * 1. lora_recv hasn't already exited due to a timeout.
125 * (modem_release would have been successfully called)
126 * 2. If the k_poll in lora_recv times out before we raise the signal,
127 * but while this code is running, it will block on the
128 * signal again.
129 * This lets us guarantee that the operation_done signal and pointers
130 * in rx_params are always valid in this function.
131 */
132
133 /* Store actual size */
134 if (size < *dev_data.rx_params.size) {
135 *dev_data.rx_params.size = size;
136 }
137 /* Copy received data to output buffer */
138 memcpy(dev_data.rx_params.buf, payload,
139 *dev_data.rx_params.size);
140 /* Output RSSI and SNR */
141 if (dev_data.rx_params.rssi) {
142 *dev_data.rx_params.rssi = rssi;
143 }
144 if (dev_data.rx_params.snr) {
145 *dev_data.rx_params.snr = snr;
146 }
147 /* Put radio back into sleep mode */
148 Radio.Sleep();
149 /* Completely release modem */
150 dev_data.operation_done = NULL;
151 atomic_clear(&dev_data.modem_usage);
152 /* Notify caller RX is complete */
153 k_poll_signal_raise(sig, 0);
154 }
155
sx12xx_ev_tx_done(void)156 static void sx12xx_ev_tx_done(void)
157 {
158 struct k_poll_signal *sig = dev_data.operation_done;
159
160 if (modem_release(&dev_data)) {
161 /* Raise signal if provided */
162 if (sig) {
163 k_poll_signal_raise(sig, 0);
164 }
165 }
166 }
167
sx12xx_ev_tx_timed_out(void)168 static void sx12xx_ev_tx_timed_out(void)
169 {
170 /* Just release the modem */
171 modem_release(&dev_data);
172 }
173
sx12xx_ev_rx_error(void)174 static void sx12xx_ev_rx_error(void)
175 {
176 struct k_poll_signal *sig = dev_data.operation_done;
177
178 /* Receiving in asynchronous mode */
179 if (dev_data.async_rx_cb) {
180 /* Start receiving again */
181 Radio.Rx(0);
182 /* Don't run the synchronous code */
183 return;
184 }
185
186 /* Finish synchronous receive with error */
187 if (modem_release(&dev_data)) {
188 /* Raise signal if provided */
189 if (sig) {
190 k_poll_signal_raise(sig, -EIO);
191 }
192 }
193 }
194
sx12xx_lora_send(const struct device * dev,uint8_t * data,uint32_t data_len)195 int sx12xx_lora_send(const struct device *dev, uint8_t *data,
196 uint32_t data_len)
197 {
198 struct k_poll_signal done = K_POLL_SIGNAL_INITIALIZER(done);
199 struct k_poll_event evt = K_POLL_EVENT_INITIALIZER(
200 K_POLL_TYPE_SIGNAL,
201 K_POLL_MODE_NOTIFY_ONLY,
202 &done);
203 uint32_t air_time;
204 int ret;
205
206 /* Validate that we have a TX configuration */
207 if (!dev_data.tx_cfg.frequency) {
208 return -EINVAL;
209 }
210
211 ret = sx12xx_lora_send_async(dev, data, data_len, &done);
212 if (ret < 0) {
213 return ret;
214 }
215
216 /* Calculate expected airtime of the packet */
217 air_time = Radio.TimeOnAir(MODEM_LORA,
218 dev_data.tx_cfg.bandwidth,
219 dev_data.tx_cfg.datarate,
220 dev_data.tx_cfg.coding_rate,
221 dev_data.tx_cfg.preamble_len,
222 0, data_len, true);
223 LOG_DBG("Expected air time of %d bytes = %dms", data_len, air_time);
224
225 /* Wait for the packet to finish transmitting.
226 * Use twice the tx duration to ensure that we are actually detecting
227 * a failed transmission, and not some minor timing variation between
228 * modem and driver.
229 */
230 ret = k_poll(&evt, 1, K_MSEC(2 * air_time));
231 if (ret < 0) {
232 LOG_ERR("Packet transmission failed!");
233 if (!modem_release(&dev_data)) {
234 /* TX done interrupt is currently running */
235 k_poll(&evt, 1, K_FOREVER);
236 }
237 }
238 return ret;
239 }
240
sx12xx_lora_send_async(const struct device * dev,uint8_t * data,uint32_t data_len,struct k_poll_signal * async)241 int sx12xx_lora_send_async(const struct device *dev, uint8_t *data,
242 uint32_t data_len, struct k_poll_signal *async)
243 {
244 /* Ensure available, freed by sx12xx_ev_tx_done */
245 if (!modem_acquire(&dev_data)) {
246 return -EBUSY;
247 }
248
249 /* Store signal */
250 dev_data.operation_done = async;
251
252 Radio.SetMaxPayloadLength(MODEM_LORA, data_len);
253
254 Radio.Send(data, data_len);
255
256 return 0;
257 }
258
sx12xx_lora_recv(const struct device * dev,uint8_t * data,uint8_t size,k_timeout_t timeout,int16_t * rssi,int8_t * snr)259 int sx12xx_lora_recv(const struct device *dev, uint8_t *data, uint8_t size,
260 k_timeout_t timeout, int16_t *rssi, int8_t *snr)
261 {
262 struct k_poll_signal done = K_POLL_SIGNAL_INITIALIZER(done);
263 struct k_poll_event evt = K_POLL_EVENT_INITIALIZER(
264 K_POLL_TYPE_SIGNAL,
265 K_POLL_MODE_NOTIFY_ONLY,
266 &done);
267 int ret;
268
269 /* Ensure available, decremented by sx12xx_ev_rx_done or on timeout */
270 if (!modem_acquire(&dev_data)) {
271 return -EBUSY;
272 }
273
274 dev_data.async_rx_cb = NULL;
275 /* Store operation signal */
276 dev_data.operation_done = &done;
277 /* Set data output location */
278 dev_data.rx_params.buf = data;
279 dev_data.rx_params.size = &size;
280 dev_data.rx_params.rssi = rssi;
281 dev_data.rx_params.snr = snr;
282
283 Radio.SetMaxPayloadLength(MODEM_LORA, 255);
284 Radio.Rx(0);
285
286 ret = k_poll(&evt, 1, timeout);
287 if (ret < 0) {
288 if (!modem_release(&dev_data)) {
289 /* Releasing the modem failed, which means that
290 * the RX callback is currently running. Wait until
291 * the RX callback finishes and we get our packet.
292 */
293 k_poll(&evt, 1, K_FOREVER);
294
295 /* We did receive a packet */
296 return size;
297 }
298 LOG_INF("Receive timeout");
299 return ret;
300 }
301
302 if (done.result < 0) {
303 LOG_ERR("Receive error");
304 return done.result;
305 }
306
307 return size;
308 }
309
sx12xx_lora_recv_async(const struct device * dev,lora_recv_cb cb,void * user_data)310 int sx12xx_lora_recv_async(const struct device *dev, lora_recv_cb cb, void *user_data)
311 {
312 /* Cancel ongoing reception */
313 if (cb == NULL) {
314 if (!modem_release(&dev_data)) {
315 /* Not receiving or already being stopped */
316 return -EINVAL;
317 }
318 return 0;
319 }
320
321 /* Ensure available */
322 if (!modem_acquire(&dev_data)) {
323 return -EBUSY;
324 }
325
326 /* Store parameters */
327 dev_data.async_rx_cb = cb;
328 dev_data.async_user_data = user_data;
329
330 /* Start reception */
331 Radio.SetMaxPayloadLength(MODEM_LORA, 255);
332 Radio.Rx(0);
333
334 return 0;
335 }
336
sx12xx_lora_config(const struct device * dev,struct lora_modem_config * config)337 int sx12xx_lora_config(const struct device *dev,
338 struct lora_modem_config *config)
339 {
340 /* Ensure available, decremented after configuration */
341 if (!modem_acquire(&dev_data)) {
342 return -EBUSY;
343 }
344
345 Radio.SetChannel(config->frequency);
346
347 if (config->tx) {
348 /* Store TX config locally for airtime calculations */
349 memcpy(&dev_data.tx_cfg, config, sizeof(dev_data.tx_cfg));
350 /* Configure radio driver */
351 Radio.SetTxConfig(MODEM_LORA, config->tx_power, 0,
352 config->bandwidth, config->datarate,
353 config->coding_rate, config->preamble_len,
354 false, true, 0, 0, config->iq_inverted, 4000);
355 } else {
356 /* TODO: Get symbol timeout value from config parameters */
357 Radio.SetRxConfig(MODEM_LORA, config->bandwidth,
358 config->datarate, config->coding_rate,
359 0, config->preamble_len, 10, false, 0,
360 false, 0, 0, config->iq_inverted, true);
361 }
362
363 Radio.SetPublicNetwork(config->public_network);
364
365 modem_release(&dev_data);
366 return 0;
367 }
368
sx12xx_lora_test_cw(const struct device * dev,uint32_t frequency,int8_t tx_power,uint16_t duration)369 int sx12xx_lora_test_cw(const struct device *dev, uint32_t frequency,
370 int8_t tx_power,
371 uint16_t duration)
372 {
373 /* Ensure available, freed in sx12xx_ev_tx_done */
374 if (!modem_acquire(&dev_data)) {
375 return -EBUSY;
376 }
377
378 Radio.SetTxContinuousWave(frequency, tx_power, duration);
379 return 0;
380 }
381
sx12xx_init(const struct device * dev)382 int sx12xx_init(const struct device *dev)
383 {
384 atomic_set(&dev_data.modem_usage, 0);
385
386 dev_data.dev = dev;
387 dev_data.events.TxDone = sx12xx_ev_tx_done;
388 dev_data.events.RxDone = sx12xx_ev_rx_done;
389 dev_data.events.RxError = sx12xx_ev_rx_error;
390 /* TX timeout event raises at the end of the test CW transmission */
391 dev_data.events.TxTimeout = sx12xx_ev_tx_timed_out;
392 Radio.Init(&dev_data.events);
393
394 /*
395 * Automatically place the radio into sleep mode upon boot.
396 * The required `lora_config` call before transmission or reception
397 * will bring the radio out of sleep mode before it is used. The radio
398 * is automatically placed back into sleep mode upon TX or RX
399 * completion.
400 */
401 Radio.Sleep();
402
403 return 0;
404 }
405