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