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