1 /*
2 * Copyright (c) 2018 Foundries.io
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #define DT_DRV_COMPAT wnc_m14a2a
8
9 #define LOG_DOMAIN modem_wncm14a2a
10 #define LOG_LEVEL CONFIG_MODEM_LOG_LEVEL
11 #include <zephyr/logging/log.h>
12 LOG_MODULE_REGISTER(LOG_DOMAIN);
13
14 #include <zephyr/types.h>
15 #include <stddef.h>
16 #include <stdlib.h>
17 #include <ctype.h>
18 #include <errno.h>
19 #include <zephyr/kernel.h>
20 #include <zephyr/drivers/gpio.h>
21 #include <zephyr/device.h>
22 #include <zephyr/init.h>
23 #include <zephyr/random/random.h>
24
25 #include <zephyr/net/net_context.h>
26 #include <zephyr/net/net_if.h>
27 #include <zephyr/net/net_offload.h>
28 #include <zephyr/net/offloaded_netdev.h>
29 #include <zephyr/net/net_pkt.h>
30 #if defined(CONFIG_NET_IPV6)
31 #include "ipv6.h"
32 #endif
33 #if defined(CONFIG_NET_IPV4)
34 #include "ipv4.h"
35 #endif
36 #if defined(CONFIG_NET_UDP)
37 #include "udp_internal.h"
38 #endif
39
40 #include "modem_receiver.h"
41
42 /* Uncomment the #define below to enable a hexdump of all incoming
43 * data from the modem receiver
44 */
45 /* #define ENABLE_VERBOSE_MODEM_RECV_HEXDUMP 1 */
46
47 /* pin settings */
48 enum mdm_control_pins {
49 MDM_BOOT_MODE_SEL = 0,
50 MDM_POWER,
51 MDM_KEEP_AWAKE,
52 MDM_RESET,
53 SHLD_3V3_1V8_SIG_TRANS_ENA,
54 #if DT_INST_NODE_HAS_PROP(0, mdm_send_ok_gpios)
55 MDM_SEND_OK,
56 #endif
57 MAX_MDM_CONTROL_PINS,
58 };
59
60 #define MDM_UART_DEV DEVICE_DT_GET(DT_INST_BUS(0))
61
62 #define MDM_BOOT_MODE_SPECIAL 0
63 #define MDM_BOOT_MODE_NORMAL 1
64
65 #define MDM_CMD_TIMEOUT (5 * MSEC_PER_SEC)
66 #define MDM_CMD_SEND_TIMEOUT (10 * MSEC_PER_SEC)
67 #define MDM_CMD_CONN_TIMEOUT (31 * MSEC_PER_SEC)
68
69 #define MDM_MAX_DATA_LENGTH 1500
70
71 #define MDM_RECV_MAX_BUF 30
72 #define MDM_RECV_BUF_SIZE 128
73
74 #define MDM_MAX_SOCKETS 6
75
76 #define BUF_ALLOC_TIMEOUT K_SECONDS(1)
77
78 #define CMD_HANDLER(cmd_, cb_) { \
79 .cmd = cmd_, \
80 .cmd_len = (uint16_t)sizeof(cmd_)-1, \
81 .func = on_cmd_ ## cb_ \
82 }
83
84 #define MDM_MANUFACTURER_LENGTH 10
85 #define MDM_MODEL_LENGTH 16
86 #define MDM_REVISION_LENGTH 64
87 #define MDM_IMEI_LENGTH 16
88
89 #define RSSI_TIMEOUT_SECS 30
90
91 NET_BUF_POOL_DEFINE(mdm_recv_pool, MDM_RECV_MAX_BUF, MDM_RECV_BUF_SIZE,
92 0, NULL);
93
94 static uint8_t mdm_recv_buf[MDM_MAX_DATA_LENGTH];
95
96 /* RX thread structures */
97 K_KERNEL_STACK_DEFINE(wncm14a2a_rx_stack,
98 CONFIG_MODEM_WNCM14A2A_RX_STACK_SIZE);
99 struct k_thread wncm14a2a_rx_thread;
100
101 /* RX thread work queue */
102 K_KERNEL_STACK_DEFINE(wncm14a2a_workq_stack,
103 CONFIG_MODEM_WNCM14A2A_RX_WORKQ_STACK_SIZE);
104 static struct k_work_q wncm14a2a_workq;
105
106 struct wncm14a2a_socket {
107 struct net_context *context;
108 sa_family_t family;
109 enum net_sock_type type;
110 enum net_ip_protocol ip_proto;
111 struct sockaddr src;
112 struct sockaddr dst;
113
114 int socket_id;
115
116 /** semaphore */
117 struct k_sem sock_send_sem;
118
119 /** socket callbacks */
120 struct k_work recv_cb_work;
121 net_context_recv_cb_t recv_cb;
122 struct net_pkt *recv_pkt;
123 void *recv_user_data;
124 };
125
126 struct wncm14a2a_config {
127 struct gpio_dt_spec gpio[MAX_MDM_CONTROL_PINS];
128 };
129
130 struct wncm14a2a_iface_ctx {
131 struct net_if *iface;
132 uint8_t mac_addr[6];
133
134 /* RX specific attributes */
135 struct mdm_receiver_context mdm_ctx;
136
137 /* socket data */
138 struct wncm14a2a_socket sockets[MDM_MAX_SOCKETS];
139 int last_socket_id;
140 int last_error;
141
142 /* semaphores */
143 struct k_sem response_sem;
144
145 /* RSSI work */
146 struct k_work_delayable rssi_query_work;
147
148 /* modem data */
149 char mdm_manufacturer[MDM_MANUFACTURER_LENGTH];
150 char mdm_model[MDM_MODEL_LENGTH];
151 char mdm_revision[MDM_REVISION_LENGTH];
152 char mdm_imei[MDM_IMEI_LENGTH];
153 int mdm_rssi;
154
155 /* modem state */
156 int ev_csps;
157 int ev_rrcstate;
158 };
159
160 struct cmd_handler {
161 const char *cmd;
162 uint16_t cmd_len;
163 void (*func)(struct net_buf **buf, uint16_t len);
164 };
165
166 const static struct wncm14a2a_config wncm14a2a_cfg = {
167 .gpio = {
168 GPIO_DT_SPEC_INST_GET(0, mdm_boot_mode_sel_gpios),
169 GPIO_DT_SPEC_INST_GET(0, mdm_power_gpios),
170 GPIO_DT_SPEC_INST_GET(0, mdm_keep_awake_gpios),
171 GPIO_DT_SPEC_INST_GET(0, mdm_reset_gpios),
172 GPIO_DT_SPEC_INST_GET(0, mdm_shld_trans_ena_gpios),
173 #if DT_INST_NODE_HAS_PROP(0, mdm_send_ok_gpios)
174 GPIO_DT_SPEC_INST_GET(0, mdm_send_ok_gpios),
175 #endif
176 },
177 };
178
179 static struct wncm14a2a_iface_ctx ictx;
180
181 static void wncm14a2a_read_rx(struct net_buf **buf);
182
183 /*** Verbose Debugging Functions ***/
184 #if defined(ENABLE_VERBOSE_MODEM_RECV_HEXDUMP)
hexdump(const uint8_t * packet,size_t length)185 static inline void hexdump(const uint8_t *packet, size_t length)
186 {
187 char output[sizeof("xxxxyyyy xxxxyyyy")];
188 int n = 0, k = 0;
189 uint8_t byte;
190
191 while (length--) {
192 if (n % 16 == 0) {
193 printk(" %08X ", n);
194 }
195
196 byte = *packet++;
197
198 printk("%02X ", byte);
199
200 if (byte < 0x20 || byte > 0x7f) {
201 output[k++] = '.';
202 } else {
203 output[k++] = byte;
204 }
205
206 n++;
207 if (n % 8 == 0) {
208 if (n % 16 == 0) {
209 output[k] = '\0';
210 printk(" [%s]\n", output);
211 k = 0;
212 } else {
213 printk(" ");
214 }
215 }
216 }
217
218 if (n % 16) {
219 int i;
220
221 output[k] = '\0';
222
223 for (i = 0; i < (16 - (n % 16)); i++) {
224 printk(" ");
225 }
226
227 if ((n % 16) < 8) {
228 printk(" "); /* one extra delimiter after 8 chars */
229 }
230
231 printk(" [%s]\n", output);
232 }
233 }
234 #else
235 #define hexdump(...)
236 #endif
237
socket_get(void)238 static struct wncm14a2a_socket *socket_get(void)
239 {
240 int i;
241 struct wncm14a2a_socket *sock = NULL;
242
243 for (i = 0; i < MDM_MAX_SOCKETS; i++) {
244 if (!ictx.sockets[i].context) {
245 sock = &ictx.sockets[i];
246 break;
247 }
248 }
249
250 return sock;
251 }
252
socket_from_id(int socket_id)253 static struct wncm14a2a_socket *socket_from_id(int socket_id)
254 {
255 int i;
256 struct wncm14a2a_socket *sock = NULL;
257
258 if (socket_id < 1) {
259 return NULL;
260 }
261
262 for (i = 0; i < MDM_MAX_SOCKETS; i++) {
263 if (ictx.sockets[i].socket_id == socket_id) {
264 sock = &ictx.sockets[i];
265 break;
266 }
267 }
268
269 return sock;
270 }
271
socket_put(struct wncm14a2a_socket * sock)272 static void socket_put(struct wncm14a2a_socket *sock)
273 {
274 if (!sock) {
275 return;
276 }
277
278 sock->context = NULL;
279 sock->socket_id = 0;
280 (void)memset(&sock->src, 0, sizeof(struct sockaddr));
281 (void)memset(&sock->dst, 0, sizeof(struct sockaddr));
282 }
283
wncm14a2a_sprint_ip_addr(const struct sockaddr * addr)284 char *wncm14a2a_sprint_ip_addr(const struct sockaddr *addr)
285 {
286 static char buf[NET_IPV6_ADDR_LEN];
287
288 #if defined(CONFIG_NET_IPV6)
289 if (addr->sa_family == AF_INET6) {
290 return net_addr_ntop(AF_INET6, &net_sin6(addr)->sin6_addr,
291 buf, sizeof(buf));
292 } else
293 #endif
294 #if defined(CONFIG_NET_IPV4)
295 if (addr->sa_family == AF_INET) {
296 return net_addr_ntop(AF_INET, &net_sin(addr)->sin_addr,
297 buf, sizeof(buf));
298 } else
299 #endif
300 {
301 LOG_ERR("Unknown IP address family:%d", addr->sa_family);
302 return NULL;
303 }
304 }
305
306 /* Send an AT command with a series of response handlers */
send_at_cmd(struct wncm14a2a_socket * sock,const uint8_t * data,int timeout)307 static int send_at_cmd(struct wncm14a2a_socket *sock,
308 const uint8_t *data, int timeout)
309 {
310 int ret;
311
312 ictx.last_error = 0;
313
314 LOG_DBG("OUT: [%s]", data);
315 mdm_receiver_send(&ictx.mdm_ctx, data, strlen(data));
316 mdm_receiver_send(&ictx.mdm_ctx, "\r\n", 2);
317
318 if (timeout == 0) {
319 return 0;
320 }
321
322 if (!sock) {
323 k_sem_reset(&ictx.response_sem);
324 ret = k_sem_take(&ictx.response_sem, K_MSEC(timeout));
325 } else {
326 k_sem_reset(&sock->sock_send_sem);
327 ret = k_sem_take(&sock->sock_send_sem, K_MSEC(timeout));
328 }
329
330 if (ret == 0) {
331 ret = ictx.last_error;
332 } else if (ret == -EAGAIN) {
333 ret = -ETIMEDOUT;
334 }
335
336 return ret;
337 }
338
send_data(struct wncm14a2a_socket * sock,struct net_pkt * pkt)339 static int send_data(struct wncm14a2a_socket *sock, struct net_pkt *pkt)
340 {
341 int ret;
342 struct net_buf *frag;
343 char buf[sizeof("AT@SOCKWRITE=#,####,1\r")];
344
345 if (!sock) {
346 return -EINVAL;
347 }
348
349 ictx.last_error = 0;
350
351 frag = pkt->frags;
352 /* use SOCKWRITE with binary mode formatting */
353 snprintk(buf, sizeof(buf), "AT@SOCKWRITE=%d,%zu,1\r",
354 sock->socket_id, net_buf_frags_len(frag));
355 mdm_receiver_send(&ictx.mdm_ctx, buf, strlen(buf));
356
357 /* Loop through packet data and send */
358 while (frag) {
359 mdm_receiver_send(&ictx.mdm_ctx,
360 frag->data, frag->len);
361 frag = frag->frags;
362 }
363
364 mdm_receiver_send(&ictx.mdm_ctx, "\r\n", 2);
365 k_sem_reset(&sock->sock_send_sem);
366 ret = k_sem_take(&sock->sock_send_sem, K_MSEC(MDM_CMD_SEND_TIMEOUT));
367 if (ret == 0) {
368 ret = ictx.last_error;
369 } else if (ret == -EAGAIN) {
370 ret = -ETIMEDOUT;
371 }
372
373 return ret;
374 }
375
376 /*** NET_BUF HELPERS ***/
377
is_crlf(uint8_t c)378 static bool is_crlf(uint8_t c)
379 {
380 if (c == '\n' || c == '\r') {
381 return true;
382 } else {
383 return false;
384 }
385 }
386
net_buf_skipcrlf(struct net_buf ** buf)387 static void net_buf_skipcrlf(struct net_buf **buf)
388 {
389 /* chop off any /n or /r */
390 while (*buf && is_crlf(*(*buf)->data)) {
391 net_buf_pull_u8(*buf);
392 if (!(*buf)->len) {
393 *buf = net_buf_frag_del(NULL, *buf);
394 }
395 }
396 }
397
net_buf_findcrlf(struct net_buf * buf,struct net_buf ** frag,uint16_t * offset)398 static uint16_t net_buf_findcrlf(struct net_buf *buf, struct net_buf **frag,
399 uint16_t *offset)
400 {
401 uint16_t len = 0U, pos = 0U;
402
403 while (buf && !is_crlf(*(buf->data + pos))) {
404 if (pos + 1 >= buf->len) {
405 len += buf->len;
406 buf = buf->frags;
407 pos = 0U;
408 } else {
409 pos++;
410 }
411 }
412
413 if (buf && is_crlf(*(buf->data + pos))) {
414 len += pos;
415 *offset = pos;
416 *frag = buf;
417 return len;
418 }
419
420 return 0;
421 }
422
423 /*** UDP / TCP Helper Function ***/
424
425 /* Setup IP header data to be used by some network applications.
426 * While much is dummy data, some fields such as dst, port and family are
427 * important.
428 * Return the IP + protocol header length.
429 */
pkt_setup_ip_data(struct net_pkt * pkt,struct wncm14a2a_socket * sock)430 static int pkt_setup_ip_data(struct net_pkt *pkt,
431 struct wncm14a2a_socket *sock)
432 {
433 int hdr_len = 0;
434 uint16_t src_port = 0U, dst_port = 0U;
435
436 #if defined(CONFIG_NET_IPV6)
437 if (net_pkt_family(pkt) == AF_INET6) {
438 if (net_ipv6_create(
439 pkt,
440 &((struct sockaddr_in6 *)&sock->dst)->sin6_addr,
441 &((struct sockaddr_in6 *)&sock->src)->sin6_addr)) {
442 return -1;
443 }
444 src_port = ntohs(net_sin6(&sock->src)->sin6_port);
445 dst_port = ntohs(net_sin6(&sock->dst)->sin6_port);
446
447 hdr_len = sizeof(struct net_ipv6_hdr);
448 } else
449 #endif
450 #if defined(CONFIG_NET_IPV4)
451 if (net_pkt_family(pkt) == AF_INET) {
452 if (net_ipv4_create(
453 pkt,
454 &((struct sockaddr_in *)&sock->dst)->sin_addr,
455 &((struct sockaddr_in *)&sock->src)->sin_addr)) {
456 return -1;
457 }
458 src_port = ntohs(net_sin(&sock->src)->sin_port);
459 dst_port = ntohs(net_sin(&sock->dst)->sin_port);
460
461 hdr_len = sizeof(struct net_ipv4_hdr);
462 } else
463 #endif
464 {
465 /* no error here as hdr_len is checked later for 0 value */
466 }
467
468 #if defined(CONFIG_NET_UDP)
469 if (sock->ip_proto == IPPROTO_UDP) {
470 if (net_udp_create(pkt, dst_port, src_port)) {
471 return -1;
472 }
473
474 hdr_len += NET_UDPH_LEN;
475 } else
476 #endif
477 #if defined(CONFIG_NET_TCP)
478 if (sock->ip_proto == IPPROTO_TCP) {
479 NET_PKT_DATA_ACCESS_DEFINE(tcp_access, struct net_tcp_hdr);
480 struct net_tcp_hdr *tcp;
481
482 tcp = (struct net_tcp_hdr *)net_pkt_get_data(pkt, &tcp_access);
483 if (!tcp) {
484 return -1;
485 }
486
487 (void)memset(tcp, 0, NET_TCPH_LEN);
488
489 /* Setup TCP header */
490 tcp->src_port = dst_port;
491 tcp->dst_port = src_port;
492
493 if (net_pkt_set_data(pkt, &tcp_access)) {
494 return -1;
495 }
496
497 hdr_len += NET_TCPH_LEN;
498 } else
499 #endif /* CONFIG_NET_TCP */
500 {
501 /* no error here as hdr_len is checked later for 0 value */
502 }
503
504 return hdr_len;
505 }
506
507 /*** MODEM RESPONSE HANDLERS ***/
508
509 /* Last Socket ID Handler */
on_cmd_atcmdecho(struct net_buf ** buf,uint16_t len)510 static void on_cmd_atcmdecho(struct net_buf **buf, uint16_t len)
511 {
512 char value[2];
513 /* make sure only a single digit is picked up for socket_id */
514 value[0] = net_buf_pull_u8(*buf);
515 ictx.last_socket_id = atoi(value);
516 }
517
518 /* Echo Handler for commands without related sockets */
on_cmd_atcmdecho_nosock(struct net_buf ** buf,uint16_t len)519 static void on_cmd_atcmdecho_nosock(struct net_buf **buf, uint16_t len)
520 {
521 /* clear last_socket_id */
522 ictx.last_socket_id = 0;
523 }
524
on_cmd_atcmdinfo_manufacturer(struct net_buf ** buf,uint16_t len)525 static void on_cmd_atcmdinfo_manufacturer(struct net_buf **buf, uint16_t len)
526 {
527 size_t out_len;
528
529 out_len = net_buf_linearize(ictx.mdm_manufacturer,
530 sizeof(ictx.mdm_manufacturer) - 1,
531 *buf, 0, len);
532 ictx.mdm_manufacturer[out_len] = 0;
533 LOG_INF("Manufacturer: %s", ictx.mdm_manufacturer);
534 }
535
on_cmd_atcmdinfo_model(struct net_buf ** buf,uint16_t len)536 static void on_cmd_atcmdinfo_model(struct net_buf **buf, uint16_t len)
537 {
538 size_t out_len;
539
540 out_len = net_buf_linearize(ictx.mdm_model,
541 sizeof(ictx.mdm_model) - 1,
542 *buf, 0, len);
543 ictx.mdm_model[out_len] = 0;
544 LOG_INF("Model: %s", ictx.mdm_model);
545 }
546
on_cmd_atcmdinfo_revision(struct net_buf ** buf,uint16_t len)547 static void on_cmd_atcmdinfo_revision(struct net_buf **buf, uint16_t len)
548 {
549 size_t out_len;
550
551 out_len = net_buf_linearize(ictx.mdm_revision,
552 sizeof(ictx.mdm_revision) - 1,
553 *buf, 0, len);
554 ictx.mdm_revision[out_len] = 0;
555 LOG_INF("Revision: %s", ictx.mdm_revision);
556 }
557
on_cmd_atcmdecho_nosock_imei(struct net_buf ** buf,uint16_t len)558 static void on_cmd_atcmdecho_nosock_imei(struct net_buf **buf, uint16_t len)
559 {
560 struct net_buf *frag = NULL;
561 uint16_t offset;
562 size_t out_len;
563
564 /* make sure IMEI data is received */
565 if (len < MDM_IMEI_LENGTH) {
566 LOG_DBG("Waiting for data");
567 /* wait for more data */
568 k_sleep(K_MSEC(500));
569 wncm14a2a_read_rx(buf);
570 }
571
572 net_buf_skipcrlf(buf);
573 if (!*buf) {
574 LOG_DBG("Unable to find IMEI (net_buf_skipcrlf)");
575 return;
576 }
577
578 frag = NULL;
579 len = net_buf_findcrlf(*buf, &frag, &offset);
580 if (!frag) {
581 LOG_DBG("Unable to find IMEI (net_buf_findcrlf)");
582 return;
583 }
584
585 out_len = net_buf_linearize(ictx.mdm_imei, sizeof(ictx.mdm_imei) - 1,
586 *buf, 0, len);
587 ictx.mdm_imei[out_len] = 0;
588
589 LOG_INF("IMEI: %s", ictx.mdm_imei);
590 }
591
592 /* Handler: %MEAS: RSSI:Reported= -68, Ant0= -63, Ant1= -251 */
on_cmd_atcmdinfo_rssi(struct net_buf ** buf,uint16_t len)593 static void on_cmd_atcmdinfo_rssi(struct net_buf **buf, uint16_t len)
594 {
595 int start = 0, i = 0;
596 size_t value_size;
597 char value[64];
598
599 value_size = sizeof(value);
600 (void)memset(value, 0, value_size);
601 while (*buf && len > 0 && i < value_size) {
602 value[i] = net_buf_pull_u8(*buf);
603 if (!(*buf)->len) {
604 *buf = net_buf_frag_del(NULL, *buf);
605 }
606
607 /* 2nd "=" marks the beginning of the RSSI value */
608 if (start < 2) {
609 if (value[i] == '=') {
610 start++;
611 }
612
613 continue;
614 }
615
616 /* "," marks the end of the RSSI value */
617 if (value[i] == ',') {
618 value[i] = '\0';
619 break;
620 }
621
622 i++;
623 }
624
625 if (i > 0) {
626 ictx.mdm_rssi = atoi(value);
627 LOG_INF("RSSI: %d", ictx.mdm_rssi);
628 } else {
629 LOG_WRN("Bad format found for RSSI");
630 }
631 }
632
633 /* Handler: OK */
on_cmd_sockok(struct net_buf ** buf,uint16_t len)634 static void on_cmd_sockok(struct net_buf **buf, uint16_t len)
635 {
636 struct wncm14a2a_socket *sock = NULL;
637
638 ictx.last_error = 0;
639 sock = socket_from_id(ictx.last_socket_id);
640 if (!sock) {
641 k_sem_give(&ictx.response_sem);
642 } else {
643 k_sem_give(&sock->sock_send_sem);
644 }
645 }
646
647 /* Handler: ERROR */
on_cmd_sockerror(struct net_buf ** buf,uint16_t len)648 static void on_cmd_sockerror(struct net_buf **buf, uint16_t len)
649 {
650 struct wncm14a2a_socket *sock = NULL;
651
652 ictx.last_error = -EIO;
653 sock = socket_from_id(ictx.last_socket_id);
654 if (!sock) {
655 k_sem_give(&ictx.response_sem);
656 } else {
657 k_sem_give(&sock->sock_send_sem);
658 }
659 }
660
661 /* Handler: @EXTERR:<exterror_id> */
on_cmd_sockexterror(struct net_buf ** buf,uint16_t len)662 static void on_cmd_sockexterror(struct net_buf **buf, uint16_t len)
663 {
664 char value[8];
665 size_t out_len;
666
667 struct wncm14a2a_socket *sock = NULL;
668
669 out_len = net_buf_linearize(value, sizeof(value) - 1, *buf, 0, len);
670 value[out_len] = 0;
671 ictx.last_error = -atoi(value);
672 LOG_ERR("@EXTERR:%d", ictx.last_error);
673 sock = socket_from_id(ictx.last_socket_id);
674 if (!sock) {
675 k_sem_give(&ictx.response_sem);
676 } else {
677 k_sem_give(&sock->sock_send_sem);
678 }
679 }
680
681 /* Handler: @SOCKDIAL:<status> */
on_cmd_sockdial(struct net_buf ** buf,uint16_t len)682 static void on_cmd_sockdial(struct net_buf **buf, uint16_t len)
683 {
684 char value[8];
685 size_t out_len;
686
687 out_len = net_buf_linearize(value, sizeof(value) - 1, *buf, 0, len);
688 value[out_len] = 0;
689 ictx.last_error = atoi(value);
690 k_sem_give(&ictx.response_sem);
691 }
692
693 /* Handler: @SOCKCREAT:<socket_id> */
on_cmd_sockcreat(struct net_buf ** buf,uint16_t len)694 static void on_cmd_sockcreat(struct net_buf **buf, uint16_t len)
695 {
696 char value[2];
697 struct wncm14a2a_socket *sock = NULL;
698
699 /* look up new socket by special id */
700 sock = socket_from_id(MDM_MAX_SOCKETS + 1);
701 if (sock) {
702 /* make sure only a single digit is picked up for socket_id */
703 value[0] = net_buf_pull_u8(*buf);
704 sock->socket_id = atoi(value);
705 }
706 /* don't give back semaphore -- OK to follow */
707 }
708
709 /* Handler: @SOCKWRITE:<actual_length> */
on_cmd_sockwrite(struct net_buf ** buf,uint16_t len)710 static void on_cmd_sockwrite(struct net_buf **buf, uint16_t len)
711 {
712 char value[8];
713 size_t out_len;
714 int write_len;
715 struct wncm14a2a_socket *sock = NULL;
716
717 /* TODO: check against what we wanted to send */
718 out_len = net_buf_linearize(value, sizeof(value) - 1, *buf, 0, len);
719 value[out_len] = 0;
720 write_len = atoi(value);
721 if (write_len <= 0) {
722 return;
723 }
724
725 sock = socket_from_id(ictx.last_socket_id);
726 if (sock) {
727 k_sem_give(&sock->sock_send_sem);
728 }
729 }
730
sockreadrecv_cb_work(struct k_work * work)731 static void sockreadrecv_cb_work(struct k_work *work)
732 {
733 struct wncm14a2a_socket *sock = NULL;
734 struct net_pkt *pkt;
735
736 sock = CONTAINER_OF(work, struct wncm14a2a_socket, recv_cb_work);
737
738 /* return data */
739 pkt = sock->recv_pkt;
740 sock->recv_pkt = NULL;
741 if (sock->recv_cb) {
742 sock->recv_cb(sock->context, pkt, NULL, NULL,
743 0, sock->recv_user_data);
744 } else {
745 net_pkt_unref(pkt);
746 }
747 }
748
749 /* Handler: @SOCKREAD:<actual_length>,"<hex encoded binary>" */
on_cmd_sockread(struct net_buf ** buf,uint16_t len)750 static void on_cmd_sockread(struct net_buf **buf, uint16_t len)
751 {
752 struct wncm14a2a_socket *sock = NULL;
753 uint8_t c = 0U;
754 int i, actual_length, hdr_len = 0;
755 size_t value_size;
756 char value[10];
757
758 /* first comma marks the end of actual_length */
759 i = 0;
760 value_size = sizeof(value);
761 (void)memset(value, 0, value_size);
762 while (*buf && i < value_size - 1) {
763 value[i++] = net_buf_pull_u8(*buf);
764 len--;
765 if (!(*buf)->len) {
766 *buf = net_buf_frag_del(NULL, *buf);
767 }
768
769 if (value[i-1] == ',') {
770 i--;
771 break;
772 }
773 }
774
775 /* make sure we still have buf data, the last pulled character was
776 * a comma and that the next char in the buffer is a quote.
777 */
778 if (!*buf || value[i] != ',' || *(*buf)->data != '\"') {
779 LOG_ERR("Incorrect format! Ignoring data!");
780 return;
781 }
782
783 /* clear the comma */
784 value[i] = '\0';
785 actual_length = atoi(value);
786
787 /* skip quote */
788 len--;
789 net_buf_pull_u8(*buf);
790 if (!(*buf)->len) {
791 *buf = net_buf_frag_del(NULL, *buf);
792 }
793
794 /* check that we have enough data */
795 if (!*buf || len > (actual_length * 2) + 1) {
796 LOG_ERR("Incorrect format! Ignoring data!");
797 return;
798 }
799
800 sock = socket_from_id(ictx.last_socket_id);
801 if (!sock) {
802 LOG_ERR("Socket not found! (%d)", ictx.last_socket_id);
803 return;
804 }
805
806 /* allocate an RX pkt */
807 sock->recv_pkt = net_pkt_rx_alloc_with_buffer(
808 net_context_get_iface(sock->context),
809 actual_length, sock->family, sock->ip_proto,
810 BUF_ALLOC_TIMEOUT);
811 if (!sock->recv_pkt) {
812 LOG_ERR("Failed net_pkt_get_reserve_rx!");
813 return;
814 }
815
816 /* set pkt data */
817 net_pkt_set_context(sock->recv_pkt, sock->context);
818
819 /* add IP / protocol headers */
820 hdr_len = pkt_setup_ip_data(sock->recv_pkt, sock);
821
822 /* move hex encoded data from the buffer to the recv_pkt */
823 for (i = 0; i < actual_length * 2; i++) {
824 char c2 = *(*buf)->data;
825
826 if (isdigit((int)c2) != 0) {
827 c += c2 - '0';
828 } else if (isalpha((int)c2) != 0) {
829 c += c2 - (isupper((int)c2) != 0 ? 'A' - 10 : 'a' - 10);
830 } else {
831 /* TODO: unexpected input! skip? */
832 }
833
834 if (i % 2) {
835 if (net_pkt_write_u8(sock->recv_pkt, c)) {
836 LOG_ERR("Unable to add data! Aborting!");
837 net_pkt_unref(sock->recv_pkt);
838 sock->recv_pkt = NULL;
839 return;
840 }
841
842 c = 0U;
843 } else {
844 c = c << 4;
845 }
846
847 /* pull data from buf and advance to the next frag if needed */
848 net_buf_pull_u8(*buf);
849 if (!(*buf)->len) {
850 *buf = net_buf_frag_del(NULL, *buf);
851 }
852 }
853
854 net_pkt_cursor_init(sock->recv_pkt);
855 net_pkt_set_overwrite(sock->recv_pkt, true);
856
857 if (hdr_len > 0) {
858 net_pkt_skip(sock->recv_pkt, hdr_len);
859 }
860
861 /* Let's do the callback processing in a different work queue in
862 * case the app takes a long time.
863 */
864 k_work_submit_to_queue(&wncm14a2a_workq, &sock->recv_cb_work);
865 }
866
867 /* Handler: @SOCKDATAIND: <socket_id>,<session_status>,<left_bytes> */
on_cmd_sockdataind(struct net_buf ** buf,uint16_t len)868 static void on_cmd_sockdataind(struct net_buf **buf, uint16_t len)
869 {
870 int socket_id, left_bytes;
871 size_t out_len;
872 char *delim1, *delim2;
873 char value[sizeof("#,#,#####\r")];
874 char sendbuf[sizeof("AT@SOCKREAD=-#####,-#####\r")];
875 struct wncm14a2a_socket *sock = NULL;
876
877 out_len = net_buf_linearize(value, sizeof(value) - 1, *buf, 0, len);
878 value[out_len] = 0;
879
880 /* First comma separator marks the end of socket_id */
881 delim1 = strchr(value, ',');
882 if (!delim1) {
883 LOG_ERR("Missing 1st comma");
884 return;
885 }
886
887 *delim1++ = '\0';
888 socket_id = atoi(value);
889
890 /* Second comma separator marks the end of session_status */
891 /* TODO: ignore for now, but maybe this is useful? */
892 delim2 = strchr(delim1, ',');
893 if (!delim2) {
894 LOG_ERR("Missing 2nd comma");
895 return;
896 }
897
898 *delim2++ = '\0';
899
900 /* Third param is for left_bytes */
901 /* TODO: ignore for now because we ask for max data len
902 * but maybe this is useful in the future?
903 */
904 left_bytes = atoi(delim2);
905
906 sock = socket_from_id(socket_id);
907 if (!sock) {
908 LOG_ERR("Unable to find socket_id:%d", socket_id);
909 return;
910 }
911
912 if (left_bytes > 0) {
913 LOG_DBG("socket_id:%d left_bytes:%d", socket_id, left_bytes);
914 snprintk(sendbuf, sizeof(sendbuf), "AT@SOCKREAD=%d,%d",
915 sock->socket_id, left_bytes);
916
917 /* We entered this trigger due to an unsolicited modem response.
918 * When we send the AT@SOCKREAD command it won't generate an
919 * "OK" response directly. The modem will respond with
920 * "@SOCKREAD ..." and the data requested and then "OK" or
921 * "ERROR". Let's not wait here by passing in a timeout to
922 * send_at_cmd(). Instead, when the resulting response is
923 * received, we trigger on_cmd_sockread() to handle it.
924 */
925 send_at_cmd(sock, sendbuf, 0);
926 }
927 }
928
on_cmd_socknotifyev(struct net_buf ** buf,uint16_t len)929 static void on_cmd_socknotifyev(struct net_buf **buf, uint16_t len)
930 {
931 char value[40];
932 size_t out_len;
933 int p1 = 0, p2 = 0;
934
935 out_len = net_buf_linearize(value, sizeof(value) - 1, *buf, 0, len);
936 value[out_len] = 0;
937
938 /* walk value till 1st quote */
939 while (p1 < len && value[p1] != '\"') {
940 p1++;
941 }
942
943 if (value[p1] != '\"') {
944 /* 1st quote not found */
945 return;
946 }
947
948 p1++;
949 p2 = p1;
950 while (p2 < len && value[p2] != '\"') {
951 p2++;
952 }
953
954 if (value[p2] != '\"') {
955 /* 2nd quote not found */
956 return;
957 }
958
959 /* clear quote */
960 value[p2] = '\0';
961 p2++;
962
963 /* skip comma if present */
964 if (value[p2] == ',') {
965 p2++;
966 }
967
968 /* CSPS: 0: Moved to PS mode, 1: Moved to CS/PS mode */
969 if (!strncmp(&value[p1], "CSPS", 4)) {
970 ictx.ev_csps = atoi(&value[p2]);
971 /* This also signifies that RRCSTATE = 1 */
972 ictx.ev_rrcstate = 1;
973 LOG_DBG("CSPS:%d", ictx.ev_csps);
974 /* RRCSTATE: 0: RRC Idle, 1: RRC Connected, 2: RRC Unknown */
975 } else if (!strncmp(&value[p1], "RRCSTATE", 8)) {
976 ictx.ev_rrcstate = atoi(&value[p2]);
977 LOG_DBG("RRCSTATE:%d", ictx.ev_rrcstate);
978 } else if (!strncmp(&value[p1], "LTIME", 5)) {
979 /* local time from network */
980 LOG_INF("LTIME:%s", &value[p2]);
981 } else if (!strncmp(&value[p1], "SIB1", 4)) {
982 /* do nothing? */
983 LOG_DBG("SIB1");
984 } else {
985 LOG_DBG("UNHANDLED: [%s:%s]", &value[p1], &value[p2]);
986 }
987 }
988
net_buf_ncmp(struct net_buf * buf,const uint8_t * s2,size_t n)989 static int net_buf_ncmp(struct net_buf *buf, const uint8_t *s2, size_t n)
990 {
991 struct net_buf *frag = buf;
992 uint16_t offset = 0U;
993
994 while ((n > 0) && (*(frag->data + offset) == *s2) && (*s2 != '\0')) {
995 if (offset == frag->len) {
996 if (!frag->frags) {
997 break;
998 }
999 frag = frag->frags;
1000 offset = 0U;
1001 } else {
1002 offset++;
1003 }
1004
1005 s2++;
1006 n--;
1007 }
1008
1009 return (n == 0) ? 0 : (*(frag->data + offset) - *s2);
1010 }
1011
read_rx_allocator(k_timeout_t timeout,void * user_data)1012 static inline struct net_buf *read_rx_allocator(k_timeout_t timeout,
1013 void *user_data)
1014 {
1015 return net_buf_alloc((struct net_buf_pool *)user_data, timeout);
1016 }
1017
wncm14a2a_read_rx(struct net_buf ** buf)1018 static void wncm14a2a_read_rx(struct net_buf **buf)
1019 {
1020 uint8_t uart_buffer[MDM_RECV_BUF_SIZE];
1021 size_t bytes_read = 0;
1022 int ret;
1023 uint16_t rx_len;
1024
1025 /* read all of the data from mdm_receiver */
1026 while (true) {
1027 ret = mdm_receiver_recv(&ictx.mdm_ctx,
1028 uart_buffer,
1029 sizeof(uart_buffer),
1030 &bytes_read);
1031 if (ret < 0 || bytes_read == 0) {
1032 /* mdm_receiver buffer is empty */
1033 break;
1034 }
1035
1036 hexdump(uart_buffer, bytes_read);
1037
1038 /* make sure we have storage */
1039 if (!*buf) {
1040 *buf = net_buf_alloc(&mdm_recv_pool, BUF_ALLOC_TIMEOUT);
1041 if (!*buf) {
1042 LOG_ERR("Can't allocate RX data! "
1043 "Skipping data!");
1044 break;
1045 }
1046 }
1047
1048 rx_len = net_buf_append_bytes(*buf, bytes_read, uart_buffer,
1049 BUF_ALLOC_TIMEOUT,
1050 read_rx_allocator,
1051 &mdm_recv_pool);
1052 if (rx_len < bytes_read) {
1053 LOG_ERR("Data was lost! read %u of %zu!",
1054 rx_len, bytes_read);
1055 }
1056 }
1057 }
1058
1059 /* RX thread */
wncm14a2a_rx(void * p1,void * p2,void * p3)1060 static void wncm14a2a_rx(void *p1, void *p2, void *p3)
1061 {
1062 ARG_UNUSED(p1);
1063 ARG_UNUSED(p2);
1064 ARG_UNUSED(p3);
1065
1066 struct net_buf *rx_buf = NULL;
1067 struct net_buf *frag = NULL;
1068 int i;
1069 uint16_t offset, len;
1070
1071 static const struct cmd_handler handlers[] = {
1072 /* NON-SOCKET COMMAND ECHOES to clear last_socket_id */
1073 CMD_HANDLER("ATE1", atcmdecho_nosock),
1074 CMD_HANDLER("AT%PDNSET=", atcmdecho_nosock),
1075 CMD_HANDLER("ATI", atcmdecho_nosock),
1076 CMD_HANDLER("AT+CGSN", atcmdecho_nosock_imei),
1077 CMD_HANDLER("AT%MEAS=", atcmdecho_nosock),
1078 CMD_HANDLER("AT@INTERNET=", atcmdecho_nosock),
1079 CMD_HANDLER("AT@SOCKDIAL=", atcmdecho_nosock),
1080 CMD_HANDLER("AT@SOCKCREAT=", atcmdecho_nosock),
1081
1082 /* SOCKET COMMAND ECHOES for last_socket_id processing */
1083 CMD_HANDLER("AT@SOCKCONN=", atcmdecho),
1084 CMD_HANDLER("AT@SOCKWRITE=", atcmdecho),
1085 CMD_HANDLER("AT@SOCKREAD=", atcmdecho),
1086 CMD_HANDLER("AT@SOCKCLOSE=", atcmdecho),
1087
1088 /* MODEM Information */
1089 CMD_HANDLER("Manufacturer: ", atcmdinfo_manufacturer),
1090 CMD_HANDLER("Model: ", atcmdinfo_model),
1091 CMD_HANDLER("Revision: ", atcmdinfo_revision),
1092 CMD_HANDLER("%MEAS: RSSI:", atcmdinfo_rssi),
1093
1094 /* SOLICITED SOCKET RESPONSES */
1095 CMD_HANDLER("OK", sockok),
1096 CMD_HANDLER("ERROR", sockerror),
1097 CMD_HANDLER("@EXTERR:", sockexterror),
1098 CMD_HANDLER("@SOCKDIAL:", sockdial),
1099 CMD_HANDLER("@SOCKCREAT:", sockcreat),
1100 CMD_HANDLER("@OCKCREAT:", sockcreat), /* seeing this a lot */
1101 CMD_HANDLER("@SOCKWRITE:", sockwrite),
1102 CMD_HANDLER("@SOCKREAD:", sockread),
1103
1104 /* UNSOLICITED SOCKET RESPONSES */
1105 CMD_HANDLER("@SOCKDATAIND:", sockdataind),
1106 CMD_HANDLER("%NOTIFYEV:", socknotifyev),
1107 };
1108
1109 while (true) {
1110 /* wait for incoming data */
1111 (void)k_sem_take(&ictx.mdm_ctx.rx_sem, K_FOREVER);
1112
1113 wncm14a2a_read_rx(&rx_buf);
1114
1115 while (rx_buf) {
1116 net_buf_skipcrlf(&rx_buf);
1117 if (!rx_buf) {
1118 break;
1119 }
1120
1121 frag = NULL;
1122 len = net_buf_findcrlf(rx_buf, &frag, &offset);
1123 if (!frag) {
1124 break;
1125 }
1126
1127 /* look for matching data handlers */
1128 i = -1;
1129 for (i = 0; i < ARRAY_SIZE(handlers); i++) {
1130 if (net_buf_ncmp(rx_buf, handlers[i].cmd,
1131 handlers[i].cmd_len) == 0) {
1132 /* found a matching handler */
1133 LOG_DBG("MATCH %s (len:%u)",
1134 handlers[i].cmd, len);
1135
1136 /* skip cmd_len */
1137 rx_buf = net_buf_skip(rx_buf,
1138 handlers[i].cmd_len);
1139
1140 /* locate next cr/lf */
1141 frag = NULL;
1142 len = net_buf_findcrlf(rx_buf,
1143 &frag, &offset);
1144 if (!frag) {
1145 break;
1146 }
1147
1148 /* call handler */
1149 if (handlers[i].func) {
1150 handlers[i].func(&rx_buf, len);
1151 }
1152
1153 frag = NULL;
1154 /* make sure buf still has data */
1155 if (!rx_buf) {
1156 break;
1157 }
1158
1159 /*
1160 * We've handled the current line
1161 * and need to exit the "search for
1162 * handler loop". Let's skip any
1163 * "extra" data and look for the next
1164 * CR/LF, leaving us ready for the
1165 * next handler search. Ignore the
1166 * length returned.
1167 */
1168 (void)net_buf_findcrlf(rx_buf,
1169 &frag, &offset);
1170 break;
1171 }
1172 }
1173
1174 if (frag && rx_buf) {
1175 /* clear out processed line (buffers) */
1176 while (frag && rx_buf != frag) {
1177 rx_buf = net_buf_frag_del(NULL, rx_buf);
1178 }
1179
1180 net_buf_pull(rx_buf, offset);
1181 }
1182 }
1183
1184 /* give up time if we have a solid stream of data */
1185 k_yield();
1186 }
1187 }
1188
modem_pin_init(void)1189 static int modem_pin_init(void)
1190 {
1191 LOG_INF("Setting Modem Pins");
1192
1193 /* Hard reset the modem (>5 seconds required)
1194 * (doesn't go through the signal level translator)
1195 */
1196 LOG_DBG("MDM_RESET_PIN -> ASSERTED");
1197 gpio_pin_set_dt(&wncm14a2a_cfg.gpio[MDM_RESET], 1);
1198 k_sleep(K_SECONDS(7));
1199 LOG_DBG("MDM_RESET_PIN -> NOT_ASSERTED");
1200 gpio_pin_set_dt(&wncm14a2a_cfg.gpio[MDM_RESET], 0);
1201
1202 /* disable signal level translator (necessary
1203 * for the modem to boot properly). All signals
1204 * except mdm_reset go through the level translator
1205 * and have internal pull-up/down in the module. While
1206 * the level translator is disabled, these pins will
1207 * be in the correct state.
1208 */
1209 LOG_DBG("SIG_TRANS_ENA_PIN -> DISABLED");
1210 gpio_pin_set_dt(&wncm14a2a_cfg.gpio[SHLD_3V3_1V8_SIG_TRANS_ENA], 0);
1211
1212 /* While the level translator is disabled and output pins
1213 * are tristated, make sure the inputs are in the same state
1214 * as the WNC Module pins so that when the level translator is
1215 * enabled, there are no differences.
1216 */
1217 LOG_DBG("MDM_BOOT_MODE_SEL_PIN -> NORMAL");
1218 gpio_pin_set_dt(&wncm14a2a_cfg.gpio[MDM_BOOT_MODE_SEL], MDM_BOOT_MODE_NORMAL);
1219 LOG_DBG("MDM_POWER_PIN -> ENABLE");
1220 gpio_pin_set_dt(&wncm14a2a_cfg.gpio[MDM_POWER], 1);
1221 LOG_DBG("MDM_KEEP_AWAKE_PIN -> ENABLED");
1222 gpio_pin_set_dt(&wncm14a2a_cfg.gpio[MDM_KEEP_AWAKE], 1);
1223 #if DT_INST_NODE_HAS_PROP(0, mdm_send_ok_gpios)
1224 LOG_DBG("MDM_SEND_OK_PIN -> ENABLED");
1225 gpio_pin_set_dt(&wncm14a2a_cfg.gpio[MDM_SEND_OK], 1);
1226 #endif
1227
1228 /* wait for the WNC Module to perform its initial boot correctly */
1229 k_sleep(K_SECONDS(1));
1230
1231 /* Enable the level translator.
1232 * The input pins should now be the same as how the M14A module is
1233 * driving them with internal pull ups/downs.
1234 * When enabled, there will be no changes in the above 4 pins...
1235 */
1236 LOG_DBG("SIG_TRANS_ENA_PIN -> ENABLED");
1237 gpio_pin_set_dt(&wncm14a2a_cfg.gpio[SHLD_3V3_1V8_SIG_TRANS_ENA], 1);
1238
1239 LOG_INF("... Done!");
1240
1241 return 0;
1242 }
1243
modem_wakeup_pin_fix(void)1244 static void modem_wakeup_pin_fix(void)
1245 {
1246 /* AT&T recommend toggling the KEEP_AWAKE signal to reduce missed
1247 * UART characters.
1248 */
1249 LOG_DBG("Toggling MDM_KEEP_AWAKE_PIN to avoid missed characters");
1250 k_sleep(K_MSEC(20));
1251 LOG_DBG("MDM_KEEP_AWAKE_PIN -> DISABLED");
1252 gpio_pin_set_dt(&wncm14a2a_cfg.gpio[MDM_KEEP_AWAKE], 0);
1253 k_sleep(K_SECONDS(2));
1254 LOG_DBG("MDM_KEEP_AWAKE_PIN -> ENABLED");
1255 gpio_pin_set_dt(&wncm14a2a_cfg.gpio[MDM_KEEP_AWAKE], 1);
1256 k_sleep(K_MSEC(20));
1257 }
1258
wncm14a2a_rssi_query_work(struct k_work * work)1259 static void wncm14a2a_rssi_query_work(struct k_work *work)
1260 {
1261 int ret;
1262
1263 /* query modem RSSI */
1264 ret = send_at_cmd(NULL, "AT%MEAS=\"23\"", MDM_CMD_TIMEOUT);
1265 if (ret < 0) {
1266 LOG_ERR("AT%%MEAS ret:%d", ret);
1267 }
1268
1269 /* re-start RSSI query work */
1270 k_work_reschedule_for_queue(&wncm14a2a_workq, &ictx.rssi_query_work,
1271 K_SECONDS(RSSI_TIMEOUT_SECS));
1272 }
1273
wncm14a2a_modem_reset(void)1274 static void wncm14a2a_modem_reset(void)
1275 {
1276 int ret = 0, retry_count = 0, counter = 0;
1277
1278 /* bring down network interface */
1279 net_if_carrier_off(ictx.iface);
1280
1281 restart:
1282 /* stop RSSI delay work */
1283 k_work_cancel_delayable(&ictx.rssi_query_work);
1284
1285 modem_pin_init();
1286
1287 LOG_INF("Waiting for modem to respond");
1288
1289 /* Give the modem a while to start responding to simple 'AT' commands.
1290 * Also wait for CSPS=1 or RRCSTATE=1 notification
1291 */
1292 ret = -1;
1293 while (counter++ < 50 && ret < 0) {
1294 k_sleep(K_SECONDS(2));
1295 ret = send_at_cmd(NULL, "AT", MDM_CMD_TIMEOUT);
1296 if (ret < 0 && ret != -ETIMEDOUT) {
1297 break;
1298 }
1299 }
1300
1301 if (ret < 0) {
1302 LOG_ERR("MODEM WAIT LOOP ERROR: %d", ret);
1303 goto error;
1304 }
1305
1306 LOG_INF("Setting modem to always stay awake");
1307 modem_wakeup_pin_fix();
1308
1309 ret = send_at_cmd(NULL, "ATE1", MDM_CMD_TIMEOUT);
1310 if (ret < 0) {
1311 LOG_ERR("ATE1 ret:%d", ret);
1312 goto error;
1313 }
1314
1315 ret = send_at_cmd(NULL, "AT%PDNSET=1,\"" CONFIG_MODEM_WNCM14A2A_APN_NAME
1316 "\",\"IPV4V6\"", MDM_CMD_TIMEOUT);
1317 if (ret < 0) {
1318 LOG_ERR("AT%%PDNSET ret:%d", ret);
1319 goto error;
1320 }
1321
1322 /* query modem info */
1323 LOG_INF("Querying modem information");
1324 ret = send_at_cmd(NULL, "ATI", MDM_CMD_TIMEOUT);
1325 if (ret < 0) {
1326 LOG_ERR("ATI ret:%d", ret);
1327 goto error;
1328 }
1329
1330 /* query modem IMEI */
1331 ret = send_at_cmd(NULL, "AT+CGSN", MDM_CMD_TIMEOUT);
1332 if (ret < 0) {
1333 LOG_ERR("AT+CGSN ret:%d", ret);
1334 goto error;
1335 }
1336
1337 LOG_INF("Waiting for network");
1338
1339 /* query modem RSSI */
1340 wncm14a2a_rssi_query_work(NULL);
1341 k_sleep(K_SECONDS(2));
1342
1343 counter = 0;
1344 /* wait for RSSI > -1000 and != 0 */
1345 while (counter++ < 15 &&
1346 (ictx.mdm_rssi <= -1000 ||
1347 ictx.mdm_rssi == 0)) {
1348 /* stop RSSI delay work */
1349 k_work_cancel_delayable(&ictx.rssi_query_work);
1350 wncm14a2a_rssi_query_work(NULL);
1351 k_sleep(K_SECONDS(2));
1352 }
1353
1354 if (ictx.mdm_rssi <= -1000 || ictx.mdm_rssi == 0) {
1355 retry_count++;
1356 if (retry_count > 3) {
1357 LOG_ERR("Failed network init. Too many attempts!");
1358 goto error;
1359 }
1360
1361 LOG_ERR("Failed network init. Restarting process.");
1362 goto restart;
1363 }
1364
1365 LOG_INF("Network is ready.");
1366
1367 ret = send_at_cmd(NULL, "AT@INTERNET=1", MDM_CMD_TIMEOUT);
1368 if (ret < 0) {
1369 LOG_ERR("AT@INTERNET ret:%d", ret);
1370 goto error;
1371 }
1372
1373 ret = send_at_cmd(NULL, "AT@SOCKDIAL=1", MDM_CMD_TIMEOUT);
1374 if (ret < 0) {
1375 LOG_ERR("SOCKDIAL=1 CHECK ret:%d", ret);
1376 /* don't report this as an error, we retry later */
1377 }
1378
1379 /* Set iface up */
1380 net_if_carrier_on(ictx.iface);
1381
1382 error:
1383 return;
1384 }
1385
wncm14a2a_init(const struct device * dev)1386 static int wncm14a2a_init(const struct device *dev)
1387 {
1388 int i, ret = 0;
1389
1390 ARG_UNUSED(dev);
1391
1392 (void)memset(&ictx, 0, sizeof(ictx));
1393 for (i = 0; i < MDM_MAX_SOCKETS; i++) {
1394 k_work_init(&ictx.sockets[i].recv_cb_work,
1395 sockreadrecv_cb_work);
1396 k_sem_init(&ictx.sockets[i].sock_send_sem, 0, 1);
1397 }
1398 k_sem_init(&ictx.response_sem, 0, 1);
1399
1400 /* initialize the work queue */
1401 k_work_queue_start(&wncm14a2a_workq, wncm14a2a_workq_stack,
1402 K_KERNEL_STACK_SIZEOF(wncm14a2a_workq_stack),
1403 K_PRIO_COOP(7), NULL);
1404
1405 ictx.last_socket_id = 0;
1406
1407 /* setup port devices and pin directions */
1408 for (i = 0; i < MAX_MDM_CONTROL_PINS; i++) {
1409 if (!gpio_is_ready_dt(&wncm14a2a_cfg.gpio[i])) {
1410 LOG_ERR("gpio port (%s) not ready!",
1411 wncm14a2a_cfg.gpio[i].port->name);
1412 return -ENODEV;
1413 }
1414
1415 gpio_pin_configure_dt(&wncm14a2a_cfg.gpio[i], GPIO_OUTPUT);
1416 }
1417
1418 /* Set modem data storage */
1419 ictx.mdm_ctx.data_manufacturer = ictx.mdm_manufacturer;
1420 ictx.mdm_ctx.data_model = ictx.mdm_model;
1421 ictx.mdm_ctx.data_revision = ictx.mdm_revision;
1422 #ifdef CONFIG_MODEM_SIM_NUMBERS
1423 ictx.mdm_ctx.data_imei = ictx.mdm_imei;
1424 #endif
1425 ictx.mdm_ctx.data_rssi = &ictx.mdm_rssi;
1426
1427 ret = mdm_receiver_register(&ictx.mdm_ctx, MDM_UART_DEV,
1428 mdm_recv_buf, sizeof(mdm_recv_buf));
1429 if (ret < 0) {
1430 LOG_ERR("Error registering modem receiver (%d)!", ret);
1431 goto error;
1432 }
1433
1434 /* start RX thread */
1435 k_thread_create(&wncm14a2a_rx_thread, wncm14a2a_rx_stack,
1436 K_KERNEL_STACK_SIZEOF(wncm14a2a_rx_stack),
1437 wncm14a2a_rx,
1438 NULL, NULL, NULL, K_PRIO_COOP(7), 0, K_NO_WAIT);
1439
1440 /* init RSSI query */
1441 k_work_init_delayable(&ictx.rssi_query_work, wncm14a2a_rssi_query_work);
1442
1443 wncm14a2a_modem_reset();
1444
1445 error:
1446 return ret;
1447 }
1448
1449 /*** OFFLOAD FUNCTIONS ***/
1450
offload_get(sa_family_t family,enum net_sock_type type,enum net_ip_protocol ip_proto,struct net_context ** context)1451 static int offload_get(sa_family_t family,
1452 enum net_sock_type type,
1453 enum net_ip_protocol ip_proto,
1454 struct net_context **context)
1455 {
1456 int ret;
1457 char buf[sizeof("AT@SOCKCREAT=###,#\r")];
1458 struct wncm14a2a_socket *sock = NULL;
1459
1460 /* new socket */
1461 sock = socket_get();
1462 if (!sock) {
1463 return -ENOMEM;
1464 }
1465
1466 (*context)->offload_context = sock;
1467 sock->family = family;
1468 sock->type = type;
1469 sock->ip_proto = ip_proto;
1470 sock->context = *context;
1471 sock->socket_id = MDM_MAX_SOCKETS + 1; /* socket # needs assigning */
1472
1473 snprintk(buf, sizeof(buf), "AT@SOCKCREAT=%d,%d", type,
1474 family == AF_INET ? 0 : 1);
1475 ret = send_at_cmd(NULL, buf, MDM_CMD_TIMEOUT);
1476 if (ret < 0) {
1477 LOG_ERR("AT@SOCKCREAT ret:%d", ret);
1478 socket_put(sock);
1479 }
1480
1481 return ret;
1482 }
1483
offload_bind(struct net_context * context,const struct sockaddr * addr,socklen_t addrlen)1484 static int offload_bind(struct net_context *context,
1485 const struct sockaddr *addr,
1486 socklen_t addrlen)
1487 {
1488 struct wncm14a2a_socket *sock = NULL;
1489
1490 if (!context) {
1491 return -EINVAL;
1492 }
1493
1494 sock = (struct wncm14a2a_socket *)context->offload_context;
1495 if (!sock) {
1496 LOG_ERR("Can't locate socket for net_ctx:%p!", context);
1497 return -EINVAL;
1498 }
1499
1500 /* save bind address information */
1501 sock->src.sa_family = addr->sa_family;
1502 #if defined(CONFIG_NET_IPV6)
1503 if (addr->sa_family == AF_INET6) {
1504 net_ipaddr_copy(&net_sin6(&sock->src)->sin6_addr,
1505 &net_sin6(addr)->sin6_addr);
1506 net_sin6(&sock->src)->sin6_port = net_sin6(addr)->sin6_port;
1507 } else
1508 #endif
1509 #if defined(CONFIG_NET_IPV4)
1510 if (addr->sa_family == AF_INET) {
1511 net_ipaddr_copy(&net_sin(&sock->src)->sin_addr,
1512 &net_sin(addr)->sin_addr);
1513 net_sin(&sock->src)->sin_port = net_sin(addr)->sin_port;
1514 } else
1515 #endif
1516 {
1517 return -EPFNOSUPPORT;
1518 }
1519
1520 return 0;
1521 }
1522
offload_listen(struct net_context * context,int backlog)1523 static int offload_listen(struct net_context *context, int backlog)
1524 {
1525 /* NOT IMPLEMENTED */
1526 return -ENOTSUP;
1527 }
1528
offload_connect(struct net_context * context,const struct sockaddr * addr,socklen_t addrlen,net_context_connect_cb_t cb,int32_t timeout,void * user_data)1529 static int offload_connect(struct net_context *context,
1530 const struct sockaddr *addr,
1531 socklen_t addrlen,
1532 net_context_connect_cb_t cb,
1533 int32_t timeout,
1534 void *user_data)
1535 {
1536 int ret, dst_port = -1;
1537 int32_t timeout_sec = -1; /* if not changed, this will be min timeout */
1538 char buf[sizeof("AT@SOCKCONN=#,###.###.###.###,#####,#####\r")];
1539 struct wncm14a2a_socket *sock;
1540
1541 if (timeout > 0) {
1542 timeout_sec = timeout / MSEC_PER_SEC;
1543 }
1544
1545 if (!context || !addr) {
1546 return -EINVAL;
1547 }
1548
1549 sock = (struct wncm14a2a_socket *)context->offload_context;
1550 if (!sock) {
1551 LOG_ERR("Can't locate socket for net_ctx:%p!", context);
1552 return -EINVAL;
1553 }
1554
1555 if (sock->socket_id < 1) {
1556 LOG_ERR("Invalid socket_id(%d) for net_ctx:%p!",
1557 sock->socket_id, context);
1558 return -EINVAL;
1559 }
1560
1561 sock->dst.sa_family = addr->sa_family;
1562
1563 #if defined(CONFIG_NET_IPV6)
1564 if (addr->sa_family == AF_INET6) {
1565 net_ipaddr_copy(&net_sin6(&sock->dst)->sin6_addr,
1566 &net_sin6(addr)->sin6_addr);
1567 dst_port = ntohs(net_sin6(addr)->sin6_port);
1568 net_sin6(&sock->dst)->sin6_port = dst_port;
1569 } else
1570 #endif
1571 #if defined(CONFIG_NET_IPV4)
1572 if (addr->sa_family == AF_INET) {
1573 net_ipaddr_copy(&net_sin(&sock->dst)->sin_addr,
1574 &net_sin(addr)->sin_addr);
1575 dst_port = ntohs(net_sin(addr)->sin_port);
1576 net_sin(&sock->dst)->sin_port = dst_port;
1577 } else
1578 #endif
1579 {
1580 return -EINVAL;
1581 }
1582
1583 if (dst_port < 0) {
1584 LOG_ERR("Invalid port: %d", dst_port);
1585 return -EINVAL;
1586 }
1587
1588 /*
1589 * AT@SOCKCONN timeout param has minimum value of 30 seconds and
1590 * maximum value of 360 seconds, otherwise an error is generated
1591 */
1592 timeout_sec = CLAMP(timeout_sec, 30, 360);
1593
1594 snprintk(buf, sizeof(buf), "AT@SOCKCONN=%d,\"%s\",%d,%d",
1595 sock->socket_id, wncm14a2a_sprint_ip_addr(addr),
1596 dst_port, timeout_sec);
1597 ret = send_at_cmd(sock, buf, MDM_CMD_CONN_TIMEOUT);
1598 if (!ret) {
1599 net_context_set_state(sock->context, NET_CONTEXT_CONNECTED);
1600 } else {
1601 LOG_ERR("AT@SOCKCONN ret:%d", ret);
1602 }
1603
1604 if (cb) {
1605 cb(context, ret, user_data);
1606 }
1607
1608 return ret;
1609 }
1610
offload_accept(struct net_context * context,net_tcp_accept_cb_t cb,int32_t timeout,void * user_data)1611 static int offload_accept(struct net_context *context,
1612 net_tcp_accept_cb_t cb,
1613 int32_t timeout,
1614 void *user_data)
1615 {
1616 /* NOT IMPLEMENTED */
1617 return -ENOTSUP;
1618 }
1619
offload_sendto(struct net_pkt * pkt,const struct sockaddr * dst_addr,socklen_t addrlen,net_context_send_cb_t cb,int32_t timeout,void * user_data)1620 static int offload_sendto(struct net_pkt *pkt,
1621 const struct sockaddr *dst_addr,
1622 socklen_t addrlen,
1623 net_context_send_cb_t cb,
1624 int32_t timeout,
1625 void *user_data)
1626 {
1627 struct net_context *context = net_pkt_context(pkt);
1628 struct wncm14a2a_socket *sock;
1629 int ret = 0;
1630
1631 if (!context) {
1632 return -EINVAL;
1633 }
1634
1635 sock = (struct wncm14a2a_socket *)context->offload_context;
1636 if (!sock) {
1637 LOG_ERR("Can't locate socket for net_ctx:%p!", context);
1638 return -EINVAL;
1639 }
1640
1641 ret = send_data(sock, pkt);
1642 if (ret < 0) {
1643 LOG_ERR("send_data error: %d", ret);
1644 } else {
1645 net_pkt_unref(pkt);
1646 }
1647
1648 if (cb) {
1649 cb(context, ret, user_data);
1650 }
1651
1652 return ret;
1653 }
1654
offload_send(struct net_pkt * pkt,net_context_send_cb_t cb,int32_t timeout,void * user_data)1655 static int offload_send(struct net_pkt *pkt,
1656 net_context_send_cb_t cb,
1657 int32_t timeout,
1658 void *user_data)
1659 {
1660 struct net_context *context = net_pkt_context(pkt);
1661 socklen_t addrlen;
1662
1663 #if defined(CONFIG_NET_IPV6)
1664 if (net_pkt_family(pkt) == AF_INET6) {
1665 addrlen = sizeof(struct sockaddr_in6);
1666 } else
1667 #endif /* CONFIG_NET_IPV6 */
1668 #if defined(CONFIG_NET_IPV4)
1669 if (net_pkt_family(pkt) == AF_INET) {
1670 addrlen = sizeof(struct sockaddr_in);
1671 } else
1672 #endif /* CONFIG_NET_IPV4 */
1673 {
1674 return -EPFNOSUPPORT;
1675 }
1676
1677 return offload_sendto(pkt, &context->remote, addrlen, cb,
1678 timeout, user_data);
1679 }
1680
offload_recv(struct net_context * context,net_context_recv_cb_t cb,int32_t timeout,void * user_data)1681 static int offload_recv(struct net_context *context,
1682 net_context_recv_cb_t cb,
1683 int32_t timeout,
1684 void *user_data)
1685 {
1686 struct wncm14a2a_socket *sock;
1687
1688 if (!context) {
1689 return -EINVAL;
1690 }
1691
1692 sock = (struct wncm14a2a_socket *)context->offload_context;
1693 if (!sock) {
1694 LOG_ERR("Can't locate socket for net_ctx:%p!", context);
1695 return -EINVAL;
1696 }
1697
1698 sock->recv_cb = cb;
1699 sock->recv_user_data = user_data;
1700
1701 return 0;
1702 }
1703
offload_put(struct net_context * context)1704 static int offload_put(struct net_context *context)
1705 {
1706 struct wncm14a2a_socket *sock;
1707 char buf[sizeof("AT@SOCKCLOSE=#\r")];
1708 int ret;
1709
1710 if (!context) {
1711 return -EINVAL;
1712 }
1713
1714 sock = (struct wncm14a2a_socket *)context->offload_context;
1715 if (!sock) {
1716 /* socket was already closed? Exit quietly here. */
1717 return 0;
1718 }
1719
1720 snprintk(buf, sizeof(buf), "AT@SOCKCLOSE=%d", sock->socket_id);
1721
1722 ret = send_at_cmd(sock, buf, MDM_CMD_TIMEOUT);
1723 if (ret < 0) {
1724 LOG_ERR("AT@SOCKCLOSE ret:%d", ret);
1725 }
1726
1727 /* clear last_socket_id */
1728 ictx.last_socket_id = 0;
1729
1730 socket_put(sock);
1731 net_context_unref(context);
1732 if (sock->type == SOCK_STREAM) {
1733 /* TCP contexts are referenced twice,
1734 * once for the app and once for the stack.
1735 * Since TCP stack is not used for offload,
1736 * unref a second time.
1737 */
1738 net_context_unref(context);
1739 }
1740
1741 return 0;
1742 }
1743
1744 static struct net_offload offload_funcs = {
1745 .get = offload_get,
1746 .bind = offload_bind,
1747 .listen = offload_listen, /* TODO */
1748 .connect = offload_connect,
1749 .accept = offload_accept, /* TODO */
1750 .send = offload_send,
1751 .sendto = offload_sendto,
1752 .recv = offload_recv,
1753 .put = offload_put,
1754 };
1755
wncm14a2a_get_mac(const struct device * dev)1756 static inline uint8_t *wncm14a2a_get_mac(const struct device *dev)
1757 {
1758 struct wncm14a2a_iface_ctx *ctx = dev->data;
1759
1760 ctx->mac_addr[0] = 0x00;
1761 ctx->mac_addr[1] = 0x10;
1762
1763 UNALIGNED_PUT(sys_cpu_to_be32(sys_rand32_get()),
1764 (uint32_t *)(ctx->mac_addr + 2));
1765
1766 return ctx->mac_addr;
1767 }
1768
offload_iface_init(struct net_if * iface)1769 static void offload_iface_init(struct net_if *iface)
1770 {
1771 const struct device *dev = net_if_get_device(iface);
1772 struct wncm14a2a_iface_ctx *ctx = dev->data;
1773
1774 iface->if_dev->offload = &offload_funcs;
1775 net_if_set_link_addr(iface, wncm14a2a_get_mac(dev),
1776 sizeof(ctx->mac_addr),
1777 NET_LINK_ETHERNET);
1778 ctx->iface = iface;
1779 }
1780
1781 static struct offloaded_if_api api_funcs = {
1782 .iface_api.init = offload_iface_init,
1783 };
1784
1785 NET_DEVICE_DT_INST_OFFLOAD_DEFINE(0, wncm14a2a_init, NULL,
1786 &ictx, &wncm14a2a_cfg,
1787 CONFIG_MODEM_WNCM14A2A_INIT_PRIORITY,
1788 &api_funcs,
1789 MDM_MAX_DATA_LENGTH);
1790