1 /*
2 * Copyright (C) 2024 David Ullmann
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <stdint.h>
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #define DT_DRV_COMPAT reyax_rylrxxx
12
13 #include <zephyr/logging/log.h>
14 #include <zephyr/drivers/uart.h>
15 #include <zephyr/drivers/gpio.h>
16 #include <zephyr/kernel.h>
17 #include <zephyr/drivers/lora.h>
18 #include <zephyr/modem/pipe.h>
19 #include <zephyr/modem/backend/uart.h>
20 #include <zephyr/modem/chat.h>
21 #include <zephyr/sys/atomic.h>
22 #include <errno.h>
23
24 LOG_MODULE_REGISTER(rylr, CONFIG_LORA_LOG_LEVEL);
25
26 #define RYLR_CMD_BAND_FORMAT "AT+BAND=%u\r\n"
27 #define RYLR_CMD_BAND_PARM_CHARS 9U
28 #define RYLR_CMD_BAND_FORMAT_NUM_WILDCARDS 1U
29 #define RYLR_CMD_BAND_FORMAT_WILDCARD_CHARS (RYLR_CMD_BAND_FORMAT_NUM_WILDCARDS * 2)
30 #define RYLR_CMD_BAND_FORMAT_LEN_WITHOUT_WILDCARDS \
31 (sizeof(RYLR_CMD_BAND_FORMAT) - RYLR_CMD_BAND_FORMAT_WILDCARD_CHARS - 1)
32 #define RYLR_CMD_BAND_LENGTH (RYLR_CMD_BAND_FORMAT_LEN_WITHOUT_WILDCARDS + RYLR_CMD_BAND_PARM_CHARS)
33
34 #define RYLR_CMD_SEND_FORMAT "AT+SEND=0,%u,%s\r\n"
35 #define RYLR_CMD_SEND_FORMAT_NUM_WILDCARDS 2U
36 #define RYLR_CMD_SEND_FORMAT_WILDCARD_CHARS (RYLR_CMD_SEND_FORMAT_NUM_WILDCARDS * 2)
37 #define RYLR_CMD_SEND_FORMAT_LEN_WITHOUT_WILDCARDS \
38 (sizeof(RYLR_CMD_SEND_FORMAT) - RYLR_CMD_SEND_FORMAT_WILDCARD_CHARS - 1)
39 #define RYLR_PAYLOAD_LENGTH_FIELD_CHARS(payload_len) \
40 (payload_len >= 100 ? 3 : (payload_len >= 10 ? 2 : 1))
41 #define RYLR_CMD_SEND_LENGTH(payload_len) \
42 (RYLR_CMD_SEND_FORMAT_LEN_WITHOUT_WILDCARDS + \
43 RYLR_PAYLOAD_LENGTH_FIELD_CHARS(payload_len) + payload_len)
44
45 #define RYLR_CMD_RF_SETTINGS_FORMAT "AT+PARAMETER=%u,%u,%u,%u\r\n"
46 #define RYLR_CMD_RF_SETTINGS_FORMAT_NUM_WILDCARDS 4U
47 #define RYLR_CMD_RF_SETTINGS_FORMAT_WILDCARD_CHARS (RYLR_CMD_RF_SETTINGS_FORMAT_NUM_WILDCARDS * 2U)
48 #define RYLR_CMD_RF_SETTINGS_FORMAT_LEN_WITHOUT_WILDCARDS \
49 (sizeof(RYLR_CMD_RF_SETTINGS_FORMAT) - RYLR_CMD_RF_SETTINGS_FORMAT_WILDCARD_CHARS - 1)
50 #define RYLR_CMD_RF_SETTINGS_FORMAT_PARAM_CHARS(spread_factor) \
51 (RYLR_CMD_RF_SETTINGS_FORMAT_NUM_WILDCARDS - 1) + (spread_factor >= 10U ? 2U : 1U)
52 #define RYLR_CMD_RF_SETTINGS_LEN(spread_factor) \
53 (RYLR_CMD_RF_SETTINGS_FORMAT_LEN_WITHOUT_WILDCARDS + \
54 RYLR_CMD_RF_SETTINGS_FORMAT_PARAM_CHARS(spread_factor))
55
56 #define RYLR_CMD_POWER_FORMAT "AT+CRFOP=%u\r\n"
57 #define RYLR_CMD_POWER_FORMAT_NUM_WILDCARDS 1U
58 #define RYLR_CMD_POWER_FORMAT_WILDCARD_CHARS (RYLR_CMD_POWER_FORMAT_NUM_WILDCARDS * 2U)
59 #define RYLR_CMD_POWER_FORMAT_LEN_WITHOUT_WILDCARDS \
60 (sizeof(RYLR_CMD_POWER_FORMAT) - RYLR_CMD_POWER_FORMAT_WILDCARD_CHARS - 1)
61 #define RYLR_CMD_POWER_FORMAT_PARAM_CHARS(power) (power >= 10U ? 2U : 1U)
62 #define RYLR_CMD_POWER_LEN(power) \
63 (RYLR_CMD_POWER_FORMAT_LEN_WITHOUT_WILDCARDS + RYLR_CMD_POWER_FORMAT_PARAM_CHARS(power))
64
65 #define RYLR_MAX_RESPONSE 256
66 #define RYLR_MAX_MSG_BYTES 256
67
68 #define RYLR_ALLOC_TIMEOUT K_SECONDS(1)
69
70 #define RYLR_TX_PENDING_FLAG_POS (0U)
71 #define RYLR_RX_PENDING_FLAG_POS (1U)
72
73 #define RYLR_IS_TX_PENDING(flags) (flags & (0x01 << RYLR_TX_PENDING_FLAG_POS))
74 #define RYLR_IS_RX_PENDING(flags) (flags & (0x01 << RYLR_RX_PENDING_FLAG_POS))
75
76 #define RYLR_SET_TX_PENDING(flags) (flags |= (0x01 << RYLR_TX_PENDING_FLAG_POS))
77 #define RYLR_SET_RX_PENDING(flags) (flags |= (0x01 << RYLR_RX_PENDING_FLAG_POS))
78
79 #define RYLR_CLEAR_TX_PENDING(flags) (flags &= ~(0x01 << RYLR_TX_PENDING_FLAG_POS))
80 #define RYLR_CLEAR_RX_PENDING(flags) (flags &= ~(0x01 << RYLR_RX_PENDING_FLAG_POS))
81
82 #define RYLR_IS_ASYNC_OP_PENDING(flags) (RYLR_IS_RX_PENDING(flags) || RYLR_IS_TX_PENDING(flags))
83
84 #define RYLR_MAX_RESPONSE_ARGS 6U
85
86 #define RYLR_MIN_RESET_MSECS (100U)
87 #define RYLR_RESET_WAIT_MSECS (RYLR_MIN_RESET_MSECS + 10U)
88
89 struct rylr_config {
90 const struct device *uart;
91 const struct gpio_dt_spec reset;
92 };
93
94 struct rylr_data {
95 uint8_t cmd_buffer[CONFIG_LORA_RYLRXX_CMD_BUF_SIZE];
96 size_t curr_cmd_len;
97 bool is_tx;
98 int handler_error;
99 struct k_msgq rx_msgq;
100 struct k_sem script_sem;
101 struct k_sem operation_sem;
102 uint8_t pending_async_flags;
103 struct k_poll_signal *async_tx_signal;
104 lora_recv_cb async_rx_cb;
105 void *async_user_data;
106 const struct device *dev;
107 uint8_t msgq_buffer[CONFIG_RYLRXXX_UNSOLICITED_RX_MSGQ_SIZE];
108 struct modem_pipe *modem_pipe;
109 uint8_t uart_backend_rx_buff[CONFIG_RYLRXXX_MODEM_BUFFERS_SIZE];
110 uint8_t uart_backend_tx_buff[CONFIG_RYLRXXX_MODEM_BUFFERS_SIZE];
111 struct modem_pipe *uart_pipe;
112 struct modem_backend_uart uart_backend;
113 uint8_t chat_rx_buf[CONFIG_RYLRXXX_MODEM_BUFFERS_SIZE];
114 uint8_t chat_tx_buf[CONFIG_RYLRXXX_MODEM_BUFFERS_SIZE];
115 uint8_t *chat_argv[RYLR_MAX_RESPONSE_ARGS];
116 struct modem_chat chat;
117 struct modem_chat_script dynamic_script;
118 struct modem_chat_script_chat dynamic_chat;
119 };
120
121 struct rylr_recv_msg {
122 uint16_t addr;
123 uint8_t length;
124 uint8_t *data;
125 uint8_t rssi;
126 uint8_t snr;
127 };
128
on_ok(struct modem_chat * chat,char ** argv,uint16_t argc,void * user_data)129 static void on_ok(struct modem_chat *chat, char **argv, uint16_t argc, void *user_data)
130 {
131 int err = 0;
132 struct rylr_data *driver_data = user_data;
133
134 driver_data->handler_error = err;
135 }
136
on_err(struct modem_chat * chat,char ** argv,uint16_t argc,void * user_data)137 static void on_err(struct modem_chat *chat, char **argv, uint16_t argc, void *user_data)
138 {
139 int radio_err = 0;
140 struct rylr_data *driver_data = user_data;
141
142 driver_data->handler_error = -EIO;
143
144 if (argc != 2) {
145 driver_data->handler_error = -EBADMSG;
146 LOG_ERR("malformed error message from radio");
147 return;
148 }
149
150 radio_err = atoi(argv[1]);
151 LOG_ERR("error from rylr: %d", radio_err);
152 }
153
on_rx(struct modem_chat * chat,char ** argv,uint16_t argc,void * user_data)154 static void on_rx(struct modem_chat *chat, char **argv, uint16_t argc, void *user_data)
155 {
156 struct rylr_data *driver_data = user_data;
157 struct rylr_recv_msg msg;
158 int err = 0;
159
160 driver_data->handler_error = 0;
161
162 if (argc != 6) {
163 driver_data->handler_error = -EBADMSG;
164 return;
165 }
166
167 msg.addr = atoi(argv[1]);
168 msg.length = atoi(argv[2]);
169 msg.data = argv[3];
170 msg.rssi = atoi(argv[4]);
171 msg.snr = atoi(argv[5]);
172
173 if (RYLR_IS_RX_PENDING(driver_data->pending_async_flags)) {
174 driver_data->async_rx_cb(driver_data->dev, msg.data, msg.length, msg.rssi, msg.snr,
175 driver_data->async_user_data);
176 } else {
177 err = k_msgq_put(&driver_data->rx_msgq, &msg, K_NO_WAIT);
178 if (err != 0) {
179 LOG_ERR("error adding messgae to queue: %d", err);
180 driver_data->handler_error = err;
181 }
182 }
183 }
184
on_script_finished(struct modem_chat * chat,enum modem_chat_script_result result,void * user_data)185 static void on_script_finished(struct modem_chat *chat, enum modem_chat_script_result result,
186 void *user_data)
187 {
188 struct rylr_data *driver_data = user_data;
189
190 if (RYLR_IS_TX_PENDING(driver_data->pending_async_flags)) {
191 RYLR_CLEAR_TX_PENDING(driver_data->pending_async_flags);
192 k_poll_signal_raise(driver_data->async_tx_signal, driver_data->handler_error);
193 k_sem_give(&driver_data->operation_sem);
194 }
195
196 k_sem_give(&driver_data->script_sem);
197 }
198
199 MODEM_CHAT_MATCH_DEFINE(ok_match, "+OK", "", on_ok);
200
201 MODEM_CHAT_MATCHES_DEFINE(abort_matches, MODEM_CHAT_MATCH("+ERR=", "", on_err));
202
203 MODEM_CHAT_MATCHES_DEFINE(unsol_matches, MODEM_CHAT_MATCH("+RCV=", ",", on_rx));
204
205 MODEM_CHAT_SCRIPT_CMDS_DEFINE(ping_cmd, MODEM_CHAT_SCRIPT_CMD_RESP("AT\r\n", ok_match));
206
207 MODEM_CHAT_SCRIPT_DEFINE(ping_script, ping_cmd, abort_matches, on_script_finished,
208 CONFIG_RYLRXXX_RADIO_CMD_RESPONSE_TIMEOUT_MS);
209
rylr_reset_dynamic_script(struct rylr_data * data)210 static void rylr_reset_dynamic_script(struct rylr_data *data)
211 {
212 data->dynamic_chat.response_matches = &ok_match;
213 data->dynamic_chat.response_matches_size = 1;
214 data->dynamic_chat.timeout = 0;
215
216 data->dynamic_script.script_chats = &data->dynamic_chat;
217 data->dynamic_script.script_chats_size = 1;
218 data->dynamic_script.abort_matches = abort_matches;
219 data->dynamic_script.abort_matches_size = 1;
220 data->dynamic_script.callback = on_script_finished;
221 data->dynamic_script.timeout = CONFIG_RYLRXXX_RADIO_CMD_RESPONSE_TIMEOUT_MS;
222 }
223
rylr_get_bandwidth_index(enum lora_signal_bandwidth bw)224 static uint32_t rylr_get_bandwidth_index(enum lora_signal_bandwidth bw)
225 {
226 switch (bw) {
227 case BW_125_KHZ:
228 return 7;
229 case BW_250_KHZ:
230 return 8;
231 case BW_500_KHZ:
232 return 9;
233 default:
234 return 7;
235 }
236 }
237
rylr_send_cmd_buffer(const struct device * dev)238 static int rylr_send_cmd_buffer(const struct device *dev)
239 {
240 int err = 0;
241 struct rylr_data *data = dev->data;
242
243 rylr_reset_dynamic_script(data);
244
245 data->dynamic_chat.request = data->cmd_buffer;
246 data->dynamic_chat.request_size = data->curr_cmd_len;
247
248 err = modem_chat_run_script(&data->chat, &data->dynamic_script);
249 if (err != 0) {
250 LOG_ERR("could not send cmd: %s. err: %d", data->cmd_buffer, err);
251 return err;
252 }
253 err = k_sem_take(&data->script_sem, K_MSEC(CONFIG_RYLRXXX_RADIO_CMD_RESPONSE_TIMEOUT_MS));
254 if (err) {
255 LOG_ERR("error waiting for response: %d", err);
256 return err;
257 }
258 return data->handler_error;
259 }
260
rylr_set_rf_band(const struct device * dev,uint32_t frequency)261 static int rylr_set_rf_band(const struct device *dev, uint32_t frequency)
262 {
263 struct rylr_data *data = dev->data;
264
265 if (sprintf(data->cmd_buffer, RYLR_CMD_BAND_FORMAT, frequency) != RYLR_CMD_BAND_LENGTH) {
266 LOG_ERR("could not create frequency string");
267 return -EINVAL;
268 }
269
270 data->curr_cmd_len = RYLR_CMD_BAND_LENGTH;
271 return rylr_send_cmd_buffer(dev);
272 }
273
rylr_set_rf_parameters(const struct device * dev,uint32_t datarate,uint32_t bandwidth,uint32_t coding_rate,uint32_t preamble_length)274 static int rylr_set_rf_parameters(const struct device *dev, uint32_t datarate, uint32_t bandwidth,
275 uint32_t coding_rate, uint32_t preamble_length)
276 {
277 struct rylr_data *data = dev->data;
278 size_t cmd_len;
279
280 if (datarate < 7 || datarate > 12) {
281 LOG_ERR("datarate/spread factor must be between 7 and 12 inclusive");
282 return -EINVAL;
283 }
284
285 if (coding_rate < 1 || coding_rate > 4) {
286 LOG_ERR("coding rate must be between 1 and 4 inclusive");
287 return -EINVAL;
288 }
289
290 if (preamble_length < 4 || preamble_length > 7) {
291 LOG_ERR("preamble length must be between 4 and 7 inclusive");
292 return -EINVAL;
293 }
294
295 cmd_len = sprintf(data->cmd_buffer, RYLR_CMD_RF_SETTINGS_FORMAT, datarate,
296 rylr_get_bandwidth_index(bandwidth), coding_rate, preamble_length);
297 if (cmd_len != RYLR_CMD_RF_SETTINGS_LEN(datarate)) {
298 LOG_ERR("could not create rf settings string");
299 return -EINVAL;
300 }
301
302 data->curr_cmd_len = cmd_len;
303 return rylr_send_cmd_buffer(dev);
304 }
305
rylr_set_power(const struct device * dev,uint32_t power)306 static int rylr_set_power(const struct device *dev, uint32_t power)
307 {
308 struct rylr_data *data = dev->data;
309 size_t cmd_len;
310
311 if (power > 15) {
312 LOG_ERR("power cannot be greater than 15");
313 return -EINVAL;
314 }
315
316 cmd_len = RYLR_CMD_POWER_LEN(power);
317 if (sprintf(data->cmd_buffer, RYLR_CMD_POWER_FORMAT, power) != cmd_len) {
318 LOG_ERR("could not create power string");
319 return -EINVAL;
320 }
321
322 data->curr_cmd_len = cmd_len;
323 return rylr_send_cmd_buffer(dev);
324 }
325
rylr_config(const struct device * dev,struct lora_modem_config * config)326 static int rylr_config(const struct device *dev, struct lora_modem_config *config)
327 {
328 int err = 0;
329 struct rylr_data *data = dev->data;
330
331 err = k_sem_take(&data->operation_sem, K_NO_WAIT);
332 if (err != 0) {
333 LOG_ERR("error taking operation semaphore: %d", err);
334 return err;
335 }
336
337 if (RYLR_IS_ASYNC_OP_PENDING(data->pending_async_flags)) {
338 LOG_ERR("pending async opperation");
339 err = -EBUSY;
340 goto exit;
341 }
342
343 err = rylr_set_rf_band(dev, config->frequency);
344 if (err != 0) {
345 LOG_ERR("could not send frequency cmd: %d", err);
346 goto exit;
347 }
348
349 err = rylr_set_rf_parameters(dev, config->datarate, config->bandwidth, config->coding_rate,
350 config->preamble_len);
351 if (err != 0) {
352 LOG_ERR("could not send rf params cmd: %d", err);
353 goto exit;
354 }
355
356 err = rylr_set_power(dev, config->tx_power);
357 if (err != 0) {
358 LOG_ERR("could not send power cmd: %d", err);
359 goto exit;
360 }
361
362 data->is_tx = config->tx;
363
364 exit:
365 k_sem_give(&data->operation_sem);
366 return err;
367 }
368
rylr_send(const struct device * dev,uint8_t * payload,uint32_t payload_len)369 int rylr_send(const struct device *dev, uint8_t *payload, uint32_t payload_len)
370 {
371 int err = 0;
372 struct rylr_data *data = dev->data;
373 int cmd_len = RYLR_CMD_SEND_LENGTH(payload_len);
374
375 err = k_sem_take(&data->operation_sem, K_NO_WAIT);
376 if (err != 0) {
377 LOG_ERR("error taking operation semaphore: %d", err);
378 return err;
379 }
380
381 if (RYLR_IS_ASYNC_OP_PENDING(data->pending_async_flags)) {
382 LOG_ERR("pending async opperation");
383 err = -EBUSY;
384 goto exit;
385 }
386
387 if (!data->is_tx) {
388 LOG_ERR("radio not configured in tx mode");
389 err = -EOPNOTSUPP;
390 goto exit;
391 }
392
393 if (cmd_len > CONFIG_LORA_RYLRXX_CMD_BUF_SIZE) {
394 LOG_ERR("payload too long");
395 err = -EINVAL;
396 goto exit;
397 }
398
399 snprintf(data->cmd_buffer, cmd_len + 1, RYLR_CMD_SEND_FORMAT, payload_len, payload);
400 data->curr_cmd_len = cmd_len;
401 err = rylr_send_cmd_buffer(dev);
402 if (err != 0) {
403 LOG_ERR("error sending data: %d", err);
404 goto exit;
405 }
406
407 exit:
408 k_sem_give(&data->operation_sem);
409 return err;
410 }
411
rylr_send_async(const struct device * dev,uint8_t * payload,uint32_t payload_len,struct k_poll_signal * async)412 int rylr_send_async(const struct device *dev, uint8_t *payload, uint32_t payload_len,
413 struct k_poll_signal *async)
414 {
415 int err = 0;
416 struct rylr_data *data = dev->data;
417 int cmd_len;
418
419 err = k_sem_take(&data->operation_sem, K_NO_WAIT);
420 if (err != 0) {
421 LOG_ERR("error taking operation sem: %d", err);
422 return err;
423 }
424
425 if (RYLR_IS_ASYNC_OP_PENDING(data->pending_async_flags)) {
426 LOG_ERR("pending async opperation");
427 err = -EBUSY;
428 goto bail;
429 }
430
431 RYLR_SET_TX_PENDING(data->pending_async_flags);
432
433 if (!data->is_tx) {
434 LOG_ERR("radio not configured in tx mode");
435 err = -EOPNOTSUPP;
436 goto bail;
437 }
438
439 cmd_len = RYLR_CMD_SEND_LENGTH(payload_len);
440 if (cmd_len > CONFIG_LORA_RYLRXX_CMD_BUF_SIZE) {
441 LOG_ERR("payload too long");
442 err = -EINVAL;
443 goto bail;
444 }
445
446 if (async == NULL) {
447 LOG_ERR("async signal cannot be null");
448 err = -EINVAL;
449 goto bail;
450 }
451
452 data->async_tx_signal = async;
453 data->curr_cmd_len =
454 snprintf(data->cmd_buffer, cmd_len + 1, RYLR_CMD_SEND_FORMAT, payload_len, payload);
455 rylr_reset_dynamic_script(data);
456 data->dynamic_chat.request = data->cmd_buffer;
457 data->dynamic_chat.request_size = data->curr_cmd_len;
458
459 return modem_chat_run_script_async(&data->chat, &data->dynamic_script);
460 bail:
461 RYLR_CLEAR_TX_PENDING(data->pending_async_flags);
462 k_sem_give(&data->operation_sem);
463 return err;
464 }
465
rylr_recv(const struct device * dev,uint8_t * ret_msg,uint8_t size,k_timeout_t timeout,int16_t * rssi,int8_t * snr)466 int rylr_recv(const struct device *dev, uint8_t *ret_msg, uint8_t size, k_timeout_t timeout,
467 int16_t *rssi, int8_t *snr)
468 {
469
470 int ret = 0;
471 struct rylr_data *data = dev->data;
472 struct rylr_recv_msg msg;
473
474 ret = k_sem_take(&data->operation_sem, K_NO_WAIT);
475 if (ret != 0) {
476 LOG_ERR("error taking operation semaphore: %d", ret);
477 return ret;
478 }
479
480 if (data->is_tx) {
481 LOG_ERR("radio is configured for tx");
482 ret = -EOPNOTSUPP;
483 goto exit;
484 }
485
486 if (RYLR_IS_ASYNC_OP_PENDING(data->pending_async_flags)) {
487 LOG_ERR("pending async opperation");
488 ret = -EBUSY;
489 goto exit;
490 }
491
492 ret = k_msgq_get(&data->rx_msgq, &msg, timeout);
493 if (ret != 0) {
494 LOG_ERR("error getting msg from queue: %d", ret);
495 goto exit;
496 }
497
498 ret = data->handler_error;
499 if (ret != 0) {
500 LOG_ERR("error in recv cb: %d", ret);
501 goto exit;
502 }
503
504 if (msg.length > size) {
505 LOG_ERR("buf len of %u too small for message len of %u", size, msg.length);
506 ret = -ENOBUFS;
507 goto exit;
508 }
509
510 *rssi = msg.rssi;
511 *snr = msg.snr;
512 memcpy(ret_msg, msg.data, msg.length);
513 ret = msg.length;
514
515 exit:
516 k_sem_give(&data->operation_sem);
517 return ret;
518 }
519
rylr_recv_async(const struct device * dev,lora_recv_cb cb,void * user_data)520 int rylr_recv_async(const struct device *dev, lora_recv_cb cb, void *user_data)
521 {
522 int err = 0;
523 struct rylr_data *data = dev->data;
524
525 err = k_sem_take(&data->operation_sem, K_NO_WAIT);
526 if (err != 0) {
527 LOG_ERR("error taking operation semaphore: %d", err);
528 return err;
529 }
530
531 /* This is not a user error but the documeted way to cancel async reception in lora api*/
532 if (cb == NULL) {
533 goto bail;
534 }
535
536 if (data->is_tx) {
537 LOG_ERR("radio is configured for tx");
538 err = -EOPNOTSUPP;
539 goto bail;
540 }
541
542 data->async_rx_cb = cb;
543 data->async_user_data = user_data;
544 if (RYLR_IS_ASYNC_OP_PENDING(data->pending_async_flags)) {
545 LOG_ERR("pending async opperation");
546 err = -EBUSY;
547 goto bail;
548 }
549 RYLR_SET_RX_PENDING(data->pending_async_flags);
550
551 return err;
552 bail:
553 RYLR_CLEAR_RX_PENDING(data->pending_async_flags);
554 k_sem_give(&data->operation_sem);
555 return err;
556 }
557
rylr_test_cw(const struct device * dev,uint32_t frequency,int8_t tx_power,uint16_t duration)558 int rylr_test_cw(const struct device *dev, uint32_t frequency, int8_t tx_power, uint16_t duration)
559 {
560 return -ENOSYS;
561 }
562
rylr_init(const struct device * dev)563 static int rylr_init(const struct device *dev)
564 {
565 int err = 0;
566 struct rylr_data *data = dev->data;
567 const struct rylr_config *config = dev->config;
568
569 if (!gpio_is_ready_dt(&config->reset)) {
570 return -ENODEV;
571 }
572
573 if (!device_is_ready(config->uart)) {
574 return -ENODEV;
575 }
576
577 err = gpio_pin_configure_dt(&config->reset, config->reset.dt_flags);
578 if (err != 0) {
579 LOG_ERR("error configuring reset gpio: %d", err);
580 return err;
581 }
582
583 k_msgq_init(&data->rx_msgq, data->msgq_buffer, sizeof(struct rylr_recv_msg),
584 ARRAY_SIZE(data->msgq_buffer));
585
586 err = k_sem_init(&data->script_sem, 0, 1);
587 if (err != 0) {
588 LOG_ERR("error initializing response semaphore. err=%d", err);
589 }
590
591 err = k_sem_init(&data->operation_sem, 1, 1);
592 if (err != 0) {
593 LOG_ERR("error initializing operation semaphore. err=%d", err);
594 }
595
596 const struct modem_backend_uart_config uart_backend_config = {
597 .uart = config->uart,
598 .receive_buf = data->uart_backend_rx_buff,
599 .receive_buf_size = ARRAY_SIZE(data->uart_backend_rx_buff),
600 .transmit_buf = data->uart_backend_tx_buff,
601 .transmit_buf_size = ARRAY_SIZE(data->uart_backend_tx_buff),
602 };
603
604 data->uart_pipe = modem_backend_uart_init(&data->uart_backend, &uart_backend_config);
605
606 const struct modem_chat_config chat_config = {
607 .user_data = data,
608 .receive_buf = data->chat_rx_buf,
609 .receive_buf_size = ARRAY_SIZE(data->chat_rx_buf),
610 .delimiter = "\r\n",
611 .delimiter_size = sizeof("\r\n") - 1,
612 .filter = NULL,
613 .filter_size = 0,
614 .argv = data->chat_argv,
615 .argv_size = ARRAY_SIZE(data->chat_argv),
616 .unsol_matches = unsol_matches,
617 .unsol_matches_size = ARRAY_SIZE(unsol_matches),
618 };
619
620 err = modem_chat_init(&data->chat, &chat_config);
621 if (err != 0) {
622 LOG_ERR("error initializing chat %d", err);
623 return err;
624 }
625
626 err = modem_chat_attach(&data->chat, data->uart_pipe);
627 if (err != 0) {
628 LOG_ERR("error attaching chat %d", err);
629 return err;
630 }
631
632 err = modem_pipe_open(data->uart_pipe, K_SECONDS(10));
633 if (err != 0) {
634 LOG_ERR("error opening uart pipe %d", err);
635 return err;
636 }
637
638 err = gpio_pin_set_dt(&config->reset, 1);
639 if (err != 0) {
640 LOG_ERR("error setting reset line: %d", err);
641 return err;
642 }
643
644 k_sleep(K_MSEC(RYLR_RESET_WAIT_MSECS));
645
646 err = gpio_pin_set_dt(&config->reset, 0);
647 if (err != 0) {
648 LOG_ERR("error unsetting reset line: %d", err);
649 return err;
650 }
651
652 k_sleep(K_MSEC(RYLR_RESET_WAIT_MSECS)); /* wait a bit more for module to boot up*/
653
654 err = modem_chat_run_script(&data->chat, &ping_script);
655 if (err != 0) {
656 LOG_ERR("error pinging radio: %d", err);
657 return err;
658 }
659
660 err = k_sem_take(&data->script_sem, K_MSEC(CONFIG_RYLRXXX_RADIO_CMD_RESPONSE_TIMEOUT_MS));
661 if (err != 0) {
662 LOG_ERR("error waiting for ping response from radio %d", err);
663 return err;
664 }
665
666 LOG_INF("successfully initialized rylr");
667 return err;
668 }
669
670 static DEVICE_API(lora, rylr_lora_api) = {
671 .config = rylr_config,
672 .send = rylr_send,
673 .send_async = rylr_send_async,
674 .recv = rylr_recv,
675 .recv_async = rylr_recv_async,
676 .test_cw = rylr_test_cw,
677 };
678
679 #define RYLR_DEVICE_INIT(n) \
680 static struct rylr_data dev_data_##n; \
681 static const struct rylr_config dev_config_##n = { \
682 .uart = DEVICE_DT_GET(DT_INST_BUS(n)), \
683 .reset = GPIO_DT_SPEC_INST_GET(n, reset_gpios), \
684 }; \
685 DEVICE_DT_INST_DEFINE(n, &rylr_init, NULL, &dev_data_##n, &dev_config_##n, POST_KERNEL, \
686 CONFIG_LORA_INIT_PRIORITY, &rylr_lora_api);
687
688 DT_INST_FOREACH_STATUS_OKAY(RYLR_DEVICE_INIT)
689