1 /*
2 * Copyright (C) 2021 metraTec GmbH
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #define DT_DRV_COMPAT simcom_sim7080
8
9 #include <zephyr/logging/log.h>
10 #include <zephyr/net/offloaded_netdev.h>
11 LOG_MODULE_REGISTER(modem_simcom_sim7080, CONFIG_MODEM_LOG_LEVEL);
12
13 #include <zephyr/drivers/modem/simcom-sim7080.h>
14 #include "simcom-sim7080.h"
15
16 #define SMS_TP_UDHI_HEADER 0x40
17
18 static struct k_thread modem_rx_thread;
19 static struct k_work_q modem_workq;
20 static struct sim7080_data mdata;
21 static struct modem_context mctx;
22 static const struct socket_op_vtable offload_socket_fd_op_vtable;
23
24 static struct zsock_addrinfo dns_result;
25 static struct sockaddr dns_result_addr;
26 static char dns_result_canonname[DNS_MAX_NAME_SIZE + 1];
27
28 static struct sim7080_gnss_data gnss_data;
29
30 static K_KERNEL_STACK_DEFINE(modem_rx_stack, CONFIG_MODEM_SIMCOM_SIM7080_RX_STACK_SIZE);
31 static K_KERNEL_STACK_DEFINE(modem_workq_stack, CONFIG_MODEM_SIMCOM_SIM7080_RX_WORKQ_STACK_SIZE);
32 NET_BUF_POOL_DEFINE(mdm_recv_pool, MDM_RECV_MAX_BUF, MDM_RECV_BUF_SIZE, 0, NULL);
33
34 /* pin settings */
35 static const struct gpio_dt_spec power_gpio = GPIO_DT_SPEC_INST_GET(0, mdm_power_gpios);
36
37 static void socket_close(struct modem_socket *sock);
38 static const struct socket_dns_offload offload_dns_ops;
39
hash32(char * str,int len)40 static inline uint32_t hash32(char *str, int len)
41 {
42 #define HASH_MULTIPLIER 37
43 uint32_t h = 0;
44 int i;
45
46 for (i = 0; i < len; ++i) {
47 h = (h * HASH_MULTIPLIER) + str[i];
48 }
49
50 return h;
51 }
52
modem_get_mac(const struct device * dev)53 static inline uint8_t *modem_get_mac(const struct device *dev)
54 {
55 struct sim7080_data *data = dev->data;
56 uint32_t hash_value;
57
58 data->mac_addr[0] = 0x00;
59 data->mac_addr[1] = 0x10;
60
61 /* use IMEI for mac_addr */
62 hash_value = hash32(mdata.mdm_imei, strlen(mdata.mdm_imei));
63
64 UNALIGNED_PUT(hash_value, (uint32_t *)(data->mac_addr + 2));
65
66 return data->mac_addr;
67 }
68
69 static int offload_socket(int family, int type, int proto);
70
71 /* Setup the Modem NET Interface. */
modem_net_iface_init(struct net_if * iface)72 static void modem_net_iface_init(struct net_if *iface)
73 {
74 const struct device *dev = net_if_get_device(iface);
75 struct sim7080_data *data = dev->data;
76
77 net_if_set_link_addr(iface, modem_get_mac(dev), sizeof(data->mac_addr), NET_LINK_ETHERNET);
78
79 data->netif = iface;
80
81 socket_offload_dns_register(&offload_dns_ops);
82
83 net_if_socket_offload_set(iface, offload_socket);
84 }
85
86 /**
87 * Changes the operating state of the sim7080.
88 *
89 * @param state The new state.
90 */
change_state(enum sim7080_state state)91 static void change_state(enum sim7080_state state)
92 {
93 LOG_DBG("Changing state to (%d)", state);
94 mdata.state = state;
95 }
96
97 /**
98 * Get the current operating state of the sim7080.
99 *
100 * @return The current state.
101 */
get_state(void)102 static enum sim7080_state get_state(void)
103 {
104 return mdata.state;
105 }
106
107 /*
108 * Parses the +CAOPEN command and gives back the
109 * connect semaphore.
110 */
MODEM_CMD_DEFINE(on_cmd_caopen)111 MODEM_CMD_DEFINE(on_cmd_caopen)
112 {
113 int result = atoi(argv[1]);
114
115 LOG_INF("+CAOPEN: %d", result);
116 modem_cmd_handler_set_error(data, result);
117 return 0;
118 }
119
120 /*
121 * Unlock the tx ready semaphore if '> ' is received.
122 */
MODEM_CMD_DIRECT_DEFINE(on_cmd_tx_ready)123 MODEM_CMD_DIRECT_DEFINE(on_cmd_tx_ready)
124 {
125 k_sem_give(&mdata.sem_tx_ready);
126 return len;
127 }
128
129 /*
130 * Connects an modem socket. Protocol can either be TCP or UDP.
131 */
offload_connect(void * obj,const struct sockaddr * addr,socklen_t addrlen)132 static int offload_connect(void *obj, const struct sockaddr *addr, socklen_t addrlen)
133 {
134 struct modem_socket *sock = (struct modem_socket *)obj;
135 uint16_t dst_port = 0;
136 char *protocol;
137 struct modem_cmd cmd[] = { MODEM_CMD("+CAOPEN: ", on_cmd_caopen, 2U, ",") };
138 char buf[sizeof("AT+CAOPEN: #,#,#####,#xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx#,####")];
139 char ip_str[NET_IPV6_ADDR_LEN];
140 int ret;
141
142 /* Modem is not attached to the network. */
143 if (get_state() != SIM7080_STATE_NETWORKING) {
144 return -EAGAIN;
145 }
146
147 if (modem_socket_is_allocated(&mdata.socket_config, sock) == false) {
148 LOG_ERR("Invalid socket id %d from fd %d", sock->id, sock->sock_fd);
149 errno = EINVAL;
150 return -1;
151 }
152
153 if (sock->is_connected == true) {
154 LOG_ERR("Socket is already connected! id: %d, fd: %d", sock->id, sock->sock_fd);
155 errno = EISCONN;
156 return -1;
157 }
158
159 /* get the destination port */
160 if (addr->sa_family == AF_INET6) {
161 dst_port = ntohs(net_sin6(addr)->sin6_port);
162 } else if (addr->sa_family == AF_INET) {
163 dst_port = ntohs(net_sin(addr)->sin_port);
164 }
165
166 /* Get protocol */
167 protocol = (sock->type == SOCK_STREAM) ? "TCP" : "UDP";
168
169 ret = modem_context_sprint_ip_addr(addr, ip_str, sizeof(ip_str));
170 if (ret != 0) {
171 LOG_ERR("Failed to format IP!");
172 errno = ENOMEM;
173 return -1;
174 }
175
176 ret = snprintk(buf, sizeof(buf), "AT+CAOPEN=%d,%d,\"%s\",\"%s\",%d", 0, sock->id,
177 protocol, ip_str, dst_port);
178 if (ret < 0) {
179 LOG_ERR("Failed to build connect command. ID: %d, FD: %d", sock->id, sock->sock_fd);
180 errno = ENOMEM;
181 return -1;
182 }
183
184 ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, cmd, ARRAY_SIZE(cmd), buf,
185 &mdata.sem_response, MDM_CONNECT_TIMEOUT);
186 if (ret < 0) {
187 LOG_ERR("%s ret: %d", buf, ret);
188 socket_close(sock);
189 goto error;
190 }
191
192 ret = modem_cmd_handler_get_error(&mdata.cmd_handler_data);
193 if (ret != 0) {
194 LOG_ERR("Closing the socket!");
195 socket_close(sock);
196 goto error;
197 }
198
199 sock->is_connected = true;
200 errno = 0;
201 return 0;
202 error:
203 errno = -ret;
204 return -1;
205 }
206
207 /*
208 * Send data over a given socket.
209 *
210 * First we signal the module that we want to send data over a socket.
211 * This is done by sending AT+CASEND=<sockfd>,<nbytes>\r\n.
212 * If The module is ready to send data it will send back
213 * an UNTERMINATED prompt '> '. After that data can be sent to the modem.
214 * As terminating byte a STRG+Z (0x1A) is sent. The module will
215 * then send a OK or ERROR.
216 */
offload_sendto(void * obj,const void * buf,size_t len,int flags,const struct sockaddr * dest_addr,socklen_t addrlen)217 static ssize_t offload_sendto(void *obj, const void *buf, size_t len, int flags,
218 const struct sockaddr *dest_addr, socklen_t addrlen)
219 {
220 int ret;
221 struct modem_socket *sock = (struct modem_socket *)obj;
222 char send_buf[sizeof("AT+CASEND=#,####")] = { 0 };
223 char ctrlz = 0x1A;
224
225 /* Modem is not attached to the network. */
226 if (get_state() != SIM7080_STATE_NETWORKING) {
227 LOG_ERR("Modem currently not attached to the network!");
228 return -EAGAIN;
229 }
230
231 /* Do some sanity checks. */
232 if (!buf || len == 0) {
233 errno = EINVAL;
234 return -1;
235 }
236
237 /* Socket has to be connected. */
238 if (!sock->is_connected) {
239 errno = ENOTCONN;
240 return -1;
241 }
242
243 /* Only send up to MTU bytes. */
244 if (len > MDM_MAX_DATA_LENGTH) {
245 len = MDM_MAX_DATA_LENGTH;
246 }
247
248 ret = snprintk(send_buf, sizeof(send_buf), "AT+CASEND=%d,%ld", sock->id, (long)len);
249 if (ret < 0) {
250 LOG_ERR("Failed to build send command!!");
251 errno = ENOMEM;
252 return -1;
253 }
254
255 /* Make sure only one send can be done at a time. */
256 k_sem_take(&mdata.cmd_handler_data.sem_tx_lock, K_FOREVER);
257 k_sem_reset(&mdata.sem_tx_ready);
258
259 /* Send CASEND */
260 mdata.current_sock_written = len;
261 ret = modem_cmd_send_nolock(&mctx.iface, &mctx.cmd_handler, NULL, 0U, send_buf, NULL,
262 K_NO_WAIT);
263 if (ret < 0) {
264 LOG_ERR("Failed to send CASEND!!");
265 goto exit;
266 }
267
268 /* Wait for '> ' */
269 ret = k_sem_take(&mdata.sem_tx_ready, K_SECONDS(2));
270 if (ret < 0) {
271 LOG_ERR("Timeout while waiting for tx");
272 goto exit;
273 }
274
275 /* Send data */
276 mctx.iface.write(&mctx.iface, buf, len);
277 mctx.iface.write(&mctx.iface, &ctrlz, 1);
278
279 /* Wait for the OK */
280 k_sem_reset(&mdata.sem_response);
281 ret = k_sem_take(&mdata.sem_response, MDM_CMD_TIMEOUT);
282 if (ret < 0) {
283 LOG_ERR("Timeout waiting for OK");
284 }
285
286 exit:
287 k_sem_give(&mdata.cmd_handler_data.sem_tx_lock);
288 /* Data was successfully sent */
289
290 if (ret < 0) {
291 errno = -ret;
292 return -1;
293 }
294
295 errno = 0;
296 return mdata.current_sock_written;
297 }
298
299 /*
300 * Read data from a given socket.
301 *
302 * The response has the form +CARECV: <length>,data\r\nOK\r\n
303 */
sockread_common(int sockfd,struct modem_cmd_handler_data * data,int socket_data_length,uint16_t len)304 static int sockread_common(int sockfd, struct modem_cmd_handler_data *data, int socket_data_length,
305 uint16_t len)
306 {
307 struct modem_socket *sock;
308 struct socket_read_data *sock_data;
309 int ret, packet_size;
310
311 if (!len) {
312 LOG_ERR("Invalid length, aborting");
313 return -EAGAIN;
314 }
315
316 if (!data->rx_buf) {
317 LOG_ERR("Incorrect format! Ignoring data!");
318 return -EINVAL;
319 }
320
321 if (socket_data_length <= 0) {
322 LOG_ERR("Length error (%d)", socket_data_length);
323 return -EAGAIN;
324 }
325
326 if (net_buf_frags_len(data->rx_buf) < socket_data_length) {
327 LOG_DBG("Not enough data -- wait!");
328 return -EAGAIN;
329 }
330
331 sock = modem_socket_from_fd(&mdata.socket_config, sockfd);
332 if (!sock) {
333 LOG_ERR("Socket not found! (%d)", sockfd);
334 ret = -EINVAL;
335 goto exit;
336 }
337
338 sock_data = (struct socket_read_data *)sock->data;
339 if (!sock_data) {
340 LOG_ERR("Socket data not found! (%d)", sockfd);
341 ret = -EINVAL;
342 goto exit;
343 }
344
345 ret = net_buf_linearize(sock_data->recv_buf, sock_data->recv_buf_len, data->rx_buf, 0,
346 (uint16_t)socket_data_length);
347 data->rx_buf = net_buf_skip(data->rx_buf, ret);
348 sock_data->recv_read_len = ret;
349 if (ret != socket_data_length) {
350 LOG_ERR("Total copied data is different then received data!"
351 " copied:%d vs. received:%d",
352 ret, socket_data_length);
353 ret = -EINVAL;
354 goto exit;
355 }
356
357 exit:
358 /* Indication only sets length to a dummy value. */
359 packet_size = modem_socket_next_packet_size(&mdata.socket_config, sock);
360 modem_socket_packet_size_update(&mdata.socket_config, sock, -packet_size);
361 return ret;
362 }
363
364 /*
365 * Handler for carecv response.
366 */
MODEM_CMD_DEFINE(on_cmd_carecv)367 MODEM_CMD_DEFINE(on_cmd_carecv)
368 {
369 return sockread_common(mdata.current_sock_fd, data, atoi(argv[0]), len);
370 }
371
372 /*
373 * Read data from a given socket.
374 */
offload_recvfrom(void * obj,void * buf,size_t max_len,int flags,struct sockaddr * src_addr,socklen_t * addrlen)375 static ssize_t offload_recvfrom(void *obj, void *buf, size_t max_len, int flags,
376 struct sockaddr *src_addr, socklen_t *addrlen)
377 {
378 struct modem_socket *sock = (struct modem_socket *)obj;
379 char sendbuf[sizeof("AT+CARECV=##,####")];
380 int ret, packet_size;
381 struct socket_read_data sock_data;
382
383 struct modem_cmd data_cmd[] = { MODEM_CMD("+CARECV: ", on_cmd_carecv, 1U, ",") };
384
385 /* Modem is not attached to the network. */
386 if (get_state() != SIM7080_STATE_NETWORKING) {
387 LOG_ERR("Modem currently not attached to the network!");
388 return -EAGAIN;
389 }
390
391 if (!buf || max_len == 0) {
392 errno = EINVAL;
393 return -1;
394 }
395
396 if (flags & ZSOCK_MSG_PEEK) {
397 errno = ENOTSUP;
398 return -1;
399 }
400
401 packet_size = modem_socket_next_packet_size(&mdata.socket_config, sock);
402 if (!packet_size) {
403 if (flags & ZSOCK_MSG_DONTWAIT) {
404 errno = EAGAIN;
405 return -1;
406 }
407
408 modem_socket_wait_data(&mdata.socket_config, sock);
409 packet_size = modem_socket_next_packet_size(&mdata.socket_config, sock);
410 }
411
412 max_len = (max_len > MDM_MAX_DATA_LENGTH) ? MDM_MAX_DATA_LENGTH : max_len;
413 snprintk(sendbuf, sizeof(sendbuf), "AT+CARECV=%d,%zd", sock->id, max_len);
414
415 memset(&sock_data, 0, sizeof(sock_data));
416 sock_data.recv_buf = buf;
417 sock_data.recv_buf_len = max_len;
418 sock_data.recv_addr = src_addr;
419 sock->data = &sock_data;
420 mdata.current_sock_fd = sock->sock_fd;
421
422 ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, data_cmd, ARRAY_SIZE(data_cmd),
423 sendbuf, &mdata.sem_response, MDM_CMD_TIMEOUT);
424 if (ret < 0) {
425 errno = -ret;
426 ret = -1;
427 goto exit;
428 }
429
430 /* HACK: use dst address as src */
431 if (src_addr && addrlen) {
432 *addrlen = sizeof(sock->dst);
433 memcpy(src_addr, &sock->dst, *addrlen);
434 }
435
436 errno = 0;
437 ret = sock_data.recv_read_len;
438
439 exit:
440 /* clear socket data */
441 mdata.current_sock_fd = -1;
442 sock->data = NULL;
443 return ret;
444 }
445
446 /*
447 * Sends messages to the modem.
448 */
offload_sendmsg(void * obj,const struct msghdr * msg,int flags)449 static ssize_t offload_sendmsg(void *obj, const struct msghdr *msg, int flags)
450 {
451 struct modem_socket *sock = obj;
452 ssize_t sent = 0;
453 const char *buf;
454 size_t len;
455 int ret;
456
457 /* Modem is not attached to the network. */
458 if (get_state() != SIM7080_STATE_NETWORKING) {
459 LOG_ERR("Modem currently not attached to the network!");
460 return -EAGAIN;
461 }
462
463 if (sock->type == SOCK_DGRAM) {
464 /*
465 * Current implementation only handles single contiguous fragment at a time, so
466 * prevent sending multiple datagrams.
467 */
468 if (msghdr_non_empty_iov_count(msg) > 1) {
469 errno = EMSGSIZE;
470 return -1;
471 }
472 }
473
474 for (int i = 0; i < msg->msg_iovlen; i++) {
475 buf = msg->msg_iov[i].iov_base;
476 len = msg->msg_iov[i].iov_len;
477
478 while (len > 0) {
479 ret = offload_sendto(obj, buf, len, flags, msg->msg_name, msg->msg_namelen);
480 if (ret < 0) {
481 if (ret == -EAGAIN) {
482 k_sleep(K_SECONDS(1));
483 } else {
484 return ret;
485 }
486 } else {
487 sent += ret;
488 buf += ret;
489 len -= ret;
490 }
491 }
492 }
493
494 return sent;
495 }
496
497 /*
498 * Closes a given socket.
499 */
socket_close(struct modem_socket * sock)500 static void socket_close(struct modem_socket *sock)
501 {
502 char buf[sizeof("AT+CACLOSE=##")];
503 int ret;
504
505 snprintk(buf, sizeof(buf), "AT+CACLOSE=%d", sock->id);
506
507 ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, NULL, 0U, buf, &mdata.sem_response,
508 MDM_CMD_TIMEOUT);
509 if (ret < 0) {
510 LOG_ERR("%s ret: %d", buf, ret);
511 }
512
513 modem_socket_put(&mdata.socket_config, sock->sock_fd);
514 }
515
516 /*
517 * Offloads read by reading from a given socket.
518 */
offload_read(void * obj,void * buffer,size_t count)519 static ssize_t offload_read(void *obj, void *buffer, size_t count)
520 {
521 return offload_recvfrom(obj, buffer, count, 0, NULL, 0);
522 }
523
524 /*
525 * Offloads write by writing to a given socket.
526 */
offload_write(void * obj,const void * buffer,size_t count)527 static ssize_t offload_write(void *obj, const void *buffer, size_t count)
528 {
529 return offload_sendto(obj, buffer, count, 0, NULL, 0);
530 }
531
532 /*
533 * Offloads close by terminating the connection and freeing the socket.
534 */
offload_close(void * obj)535 static int offload_close(void *obj)
536 {
537 struct modem_socket *sock = (struct modem_socket *)obj;
538
539 /* Modem is not attached to the network. */
540 if (get_state() != SIM7080_STATE_NETWORKING) {
541 LOG_ERR("Modem currently not attached to the network!");
542 return -EAGAIN;
543 }
544
545 /* Make sure socket is allocated */
546 if (modem_socket_is_allocated(&mdata.socket_config, sock) == false) {
547 return 0;
548 }
549
550 /* Close the socket only if it is connected. */
551 if (sock->is_connected) {
552 socket_close(sock);
553 }
554
555 return 0;
556 }
557
558 /*
559 * Polls a given socket.
560 */
offload_poll(struct zsock_pollfd * fds,int nfds,int msecs)561 static int offload_poll(struct zsock_pollfd *fds, int nfds, int msecs)
562 {
563 int i;
564 void *obj;
565
566 /* Modem is not attached to the network. */
567 if (get_state() != SIM7080_STATE_NETWORKING) {
568 LOG_ERR("Modem currently not attached to the network!");
569 return -EAGAIN;
570 }
571
572 /* Only accept modem sockets. */
573 for (i = 0; i < nfds; i++) {
574 if (fds[i].fd < 0) {
575 continue;
576 }
577
578 /* If vtable matches, then it's modem socket. */
579 obj = z_get_fd_obj(fds[i].fd,
580 (const struct fd_op_vtable *)&offload_socket_fd_op_vtable,
581 EINVAL);
582 if (obj == NULL) {
583 return -1;
584 }
585 }
586
587 return modem_socket_poll(&mdata.socket_config, fds, nfds, msecs);
588 }
589
590 /*
591 * Offloads ioctl. Only supported ioctl is poll_offload.
592 */
offload_ioctl(void * obj,unsigned int request,va_list args)593 static int offload_ioctl(void *obj, unsigned int request, va_list args)
594 {
595 switch (request) {
596 case ZFD_IOCTL_POLL_PREPARE:
597 return -EXDEV;
598
599 case ZFD_IOCTL_POLL_UPDATE:
600 return -EOPNOTSUPP;
601
602 case ZFD_IOCTL_POLL_OFFLOAD: {
603 /* Poll on the given socket. */
604 struct zsock_pollfd *fds;
605 int nfds, timeout;
606
607 fds = va_arg(args, struct zsock_pollfd *);
608 nfds = va_arg(args, int);
609 timeout = va_arg(args, int);
610
611 return offload_poll(fds, nfds, timeout);
612 }
613
614 default:
615 errno = EINVAL;
616 return -1;
617 }
618 }
619
620 static const struct socket_op_vtable offload_socket_fd_op_vtable = {
621 .fd_vtable = {
622 .read = offload_read,
623 .write = offload_write,
624 .close = offload_close,
625 .ioctl = offload_ioctl,
626 },
627 .bind = NULL,
628 .connect = offload_connect,
629 .sendto = offload_sendto,
630 .recvfrom = offload_recvfrom,
631 .listen = NULL,
632 .accept = NULL,
633 .sendmsg = offload_sendmsg,
634 .getsockopt = NULL,
635 .setsockopt = NULL,
636 };
637
638 /*
639 * Parses the dns response from the modem.
640 *
641 * Response on success:
642 * +CDNSGIP: 1,<domain name>,<IPv4>[,<IPv6>]
643 *
644 * Response on failure:
645 * +CDNSGIP: 0,<err>
646 */
MODEM_CMD_DEFINE(on_cmd_cdnsgip)647 MODEM_CMD_DEFINE(on_cmd_cdnsgip)
648 {
649 int state;
650 char ips[256];
651 size_t out_len;
652 int ret = -1;
653
654 state = atoi(argv[0]);
655 if (state == 0) {
656 LOG_ERR("DNS lookup failed with error %s", argv[1]);
657 goto exit;
658 }
659
660 /* Offset to skip the leading " */
661 out_len = net_buf_linearize(ips, sizeof(ips) - 1, data->rx_buf, 1, len);
662 ips[out_len] = '\0';
663
664 /* find trailing " */
665 char *ipv4 = strstr(ips, "\"");
666
667 if (!ipv4) {
668 LOG_ERR("Malformed DNS response!!");
669 goto exit;
670 }
671
672 *ipv4 = '\0';
673 net_addr_pton(dns_result.ai_family, ips,
674 &((struct sockaddr_in *)&dns_result_addr)->sin_addr);
675 ret = 0;
676
677 exit:
678 k_sem_give(&mdata.sem_dns);
679 return ret;
680 }
681
682 /*
683 * Perform a dns lookup.
684 */
offload_getaddrinfo(const char * node,const char * service,const struct zsock_addrinfo * hints,struct zsock_addrinfo ** res)685 static int offload_getaddrinfo(const char *node, const char *service,
686 const struct zsock_addrinfo *hints, struct zsock_addrinfo **res)
687 {
688 struct modem_cmd cmd[] = { MODEM_CMD("+CDNSGIP: ", on_cmd_cdnsgip, 2U, ",") };
689 char sendbuf[sizeof("AT+CDNSGIP=\"\",##,#####") + 128];
690 uint32_t port = 0;
691 int ret;
692
693 /* Modem is not attached to the network. */
694 if (get_state() != SIM7080_STATE_NETWORKING) {
695 LOG_ERR("Modem currently not attached to the network!");
696 return DNS_EAI_AGAIN;
697 }
698
699 /* init result */
700 (void)memset(&dns_result, 0, sizeof(dns_result));
701 (void)memset(&dns_result_addr, 0, sizeof(dns_result_addr));
702
703 /* Currently only support IPv4. */
704 dns_result.ai_family = AF_INET;
705 dns_result_addr.sa_family = AF_INET;
706 dns_result.ai_addr = &dns_result_addr;
707 dns_result.ai_addrlen = sizeof(dns_result_addr);
708 dns_result.ai_canonname = dns_result_canonname;
709 dns_result_canonname[0] = '\0';
710
711 if (service) {
712 port = atoi(service);
713 if (port < 1 || port > USHRT_MAX) {
714 return DNS_EAI_SERVICE;
715 }
716 }
717
718 if (port > 0U) {
719 if (dns_result.ai_family == AF_INET) {
720 net_sin(&dns_result_addr)->sin_port = htons(port);
721 }
722 }
723
724 /* Check if node is an IP address */
725 if (net_addr_pton(dns_result.ai_family, node,
726 &((struct sockaddr_in *)&dns_result_addr)->sin_addr) == 0) {
727 *res = &dns_result;
728 return 0;
729 }
730
731 /* user flagged node as numeric host, but we failed net_addr_pton */
732 if (hints && hints->ai_flags & AI_NUMERICHOST) {
733 return DNS_EAI_NONAME;
734 }
735
736 snprintk(sendbuf, sizeof(sendbuf), "AT+CDNSGIP=\"%s\",10,20000", node);
737 ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, cmd, ARRAY_SIZE(cmd), sendbuf,
738 &mdata.sem_dns, MDM_DNS_TIMEOUT);
739 if (ret < 0) {
740 return ret;
741 }
742
743 *res = (struct zsock_addrinfo *)&dns_result;
744 return 0;
745 }
746
747 /*
748 * Free addrinfo structure.
749 */
offload_freeaddrinfo(struct zsock_addrinfo * res)750 static void offload_freeaddrinfo(struct zsock_addrinfo *res)
751 {
752 /* No need to free static memory. */
753 res = NULL;
754 }
755
756 /*
757 * DNS vtable.
758 */
759 static const struct socket_dns_offload offload_dns_ops = {
760 .getaddrinfo = offload_getaddrinfo,
761 .freeaddrinfo = offload_freeaddrinfo,
762 };
763
764 static struct offloaded_if_api api_funcs = {
765 .iface_api.init = modem_net_iface_init,
766 };
767
offload_is_supported(int family,int type,int proto)768 static bool offload_is_supported(int family, int type, int proto)
769 {
770 if (family != AF_INET &&
771 family != AF_INET6) {
772 return false;
773 }
774
775 if (type != SOCK_DGRAM &&
776 type != SOCK_STREAM) {
777 return false;
778 }
779
780 if (proto != IPPROTO_TCP &&
781 proto != IPPROTO_UDP) {
782 return false;
783 }
784
785 return true;
786 }
787
offload_socket(int family,int type,int proto)788 static int offload_socket(int family, int type, int proto)
789 {
790 int ret;
791
792 ret = modem_socket_get(&mdata.socket_config, family, type, proto);
793 if (ret < 0) {
794 errno = -ret;
795 return -1;
796 }
797
798 errno = 0;
799 return ret;
800 }
801
802 /*
803 * Process all messages received from the modem.
804 */
modem_rx(void)805 static void modem_rx(void)
806 {
807 while (true) {
808 /* Wait for incoming data */
809 modem_iface_uart_rx_wait(&mctx.iface, K_FOREVER);
810
811 modem_cmd_handler_process(&mctx.cmd_handler, &mctx.iface);
812 }
813 }
814
MODEM_CMD_DEFINE(on_cmd_ok)815 MODEM_CMD_DEFINE(on_cmd_ok)
816 {
817 modem_cmd_handler_set_error(data, 0);
818 k_sem_give(&mdata.sem_response);
819 return 0;
820 }
821
MODEM_CMD_DEFINE(on_cmd_error)822 MODEM_CMD_DEFINE(on_cmd_error)
823 {
824 modem_cmd_handler_set_error(data, -EIO);
825 k_sem_give(&mdata.sem_response);
826 return 0;
827 }
828
MODEM_CMD_DEFINE(on_cmd_exterror)829 MODEM_CMD_DEFINE(on_cmd_exterror)
830 {
831 modem_cmd_handler_set_error(data, -EIO);
832 k_sem_give(&mdata.sem_response);
833 return 0;
834 }
835
836 /*
837 * Handles pdp context urc.
838 *
839 * The urc has the form +APP PDP: <index>,<state>.
840 * State can either be ACTIVE for activation or
841 * DEACTIVE if disabled.
842 */
MODEM_CMD_DEFINE(on_urc_app_pdp)843 MODEM_CMD_DEFINE(on_urc_app_pdp)
844 {
845 mdata.pdp_active = strcmp(argv[1], "ACTIVE") == 0;
846 LOG_INF("PDP context: %u", mdata.pdp_active);
847 k_sem_give(&mdata.sem_response);
848 return 0;
849 }
850
MODEM_CMD_DEFINE(on_urc_sms)851 MODEM_CMD_DEFINE(on_urc_sms)
852 {
853 LOG_INF("SMS: %s", argv[0]);
854 return 0;
855 }
856
857 /*
858 * Handles socket data notification.
859 *
860 * The sim modem sends and unsolicited +CADATAIND: <cid>
861 * if data can be read from a socket.
862 */
MODEM_CMD_DEFINE(on_urc_cadataind)863 MODEM_CMD_DEFINE(on_urc_cadataind)
864 {
865 struct modem_socket *sock;
866 int sock_fd;
867
868 sock_fd = atoi(argv[0]);
869
870 sock = modem_socket_from_fd(&mdata.socket_config, sock_fd);
871 if (!sock) {
872 return 0;
873 }
874
875 /* Modem does not tell packet size. Set dummy for receive. */
876 modem_socket_packet_size_update(&mdata.socket_config, sock, 1);
877
878 LOG_INF("Data available on socket: %d", sock_fd);
879 modem_socket_data_ready(&mdata.socket_config, sock);
880
881 return 0;
882 }
883
884 /*
885 * Handles the castate response.
886 *
887 * +CASTATE: <cid>,<state>
888 *
889 * Cid is the connection id (socket fd) and
890 * state can be:
891 * 0 - Closed by remote server or error
892 * 1 - Connected to remote server
893 * 2 - Listening
894 */
MODEM_CMD_DEFINE(on_urc_castate)895 MODEM_CMD_DEFINE(on_urc_castate)
896 {
897 struct modem_socket *sock;
898 int sockfd, state;
899
900 sockfd = atoi(argv[0]);
901 state = atoi(argv[1]);
902
903 sock = modem_socket_from_fd(&mdata.socket_config, sockfd);
904 if (!sock) {
905 return 0;
906 }
907
908 /* Only continue if socket was closed. */
909 if (state != 0) {
910 return 0;
911 }
912
913 LOG_INF("Socket close indication for socket: %d", sockfd);
914
915 sock->is_connected = false;
916 LOG_INF("Socket closed: %d", sockfd);
917
918 return 0;
919 }
920
921 /**
922 * Handles the ftpget urc.
923 *
924 * +FTPGET: <mode>,<error>
925 *
926 * Mode can be 1 for opening a session and
927 * reporting that data is available or 2 for
928 * reading data. This urc handler will only handle
929 * mode 1 because 2 will not occur as urc.
930 *
931 * Error can be either:
932 * - 1 for data available/opened session.
933 * - 0 If transfer is finished.
934 * - >0 for some error.
935 */
MODEM_CMD_DEFINE(on_urc_ftpget)936 MODEM_CMD_DEFINE(on_urc_ftpget)
937 {
938 int error = atoi(argv[0]);
939
940 LOG_INF("+FTPGET: 1,%d", error);
941
942 /* Transfer finished. */
943 if (error == 0) {
944 mdata.ftp.state = SIM7080_FTP_CONNECTION_STATE_FINISHED;
945 } else if (error == 1) {
946 mdata.ftp.state = SIM7080_FTP_CONNECTION_STATE_CONNECTED;
947 } else {
948 mdata.ftp.state = SIM7080_FTP_CONNECTION_STATE_ERROR;
949 }
950
951 k_sem_give(&mdata.sem_ftp);
952
953 return 0;
954 }
955
956 /*
957 * Read manufacturer identification.
958 */
MODEM_CMD_DEFINE(on_cmd_cgmi)959 MODEM_CMD_DEFINE(on_cmd_cgmi)
960 {
961 size_t out_len = net_buf_linearize(
962 mdata.mdm_manufacturer, sizeof(mdata.mdm_manufacturer) - 1, data->rx_buf, 0, len);
963 mdata.mdm_manufacturer[out_len] = '\0';
964 LOG_INF("Manufacturer: %s", mdata.mdm_manufacturer);
965 return 0;
966 }
967
968 /*
969 * Read model identification.
970 */
MODEM_CMD_DEFINE(on_cmd_cgmm)971 MODEM_CMD_DEFINE(on_cmd_cgmm)
972 {
973 size_t out_len = net_buf_linearize(mdata.mdm_model, sizeof(mdata.mdm_model) - 1,
974 data->rx_buf, 0, len);
975 mdata.mdm_model[out_len] = '\0';
976 LOG_INF("Model: %s", mdata.mdm_model);
977 return 0;
978 }
979
980 /*
981 * Read software release.
982 *
983 * Response will be in format RESPONSE: <revision>.
984 */
MODEM_CMD_DEFINE(on_cmd_cgmr)985 MODEM_CMD_DEFINE(on_cmd_cgmr)
986 {
987 size_t out_len;
988 char *p;
989
990 out_len = net_buf_linearize(mdata.mdm_revision, sizeof(mdata.mdm_revision) - 1,
991 data->rx_buf, 0, len);
992 mdata.mdm_revision[out_len] = '\0';
993
994 /* The module prepends a Revision: */
995 p = strchr(mdata.mdm_revision, ':');
996 if (p) {
997 out_len = strlen(p + 1);
998 memmove(mdata.mdm_revision, p + 1, out_len + 1);
999 }
1000
1001 LOG_INF("Revision: %s", mdata.mdm_revision);
1002 return 0;
1003 }
1004
1005 /*
1006 * Read serial number identification.
1007 */
MODEM_CMD_DEFINE(on_cmd_cgsn)1008 MODEM_CMD_DEFINE(on_cmd_cgsn)
1009 {
1010 size_t out_len =
1011 net_buf_linearize(mdata.mdm_imei, sizeof(mdata.mdm_imei) - 1, data->rx_buf, 0, len);
1012 mdata.mdm_imei[out_len] = '\0';
1013 LOG_INF("IMEI: %s", mdata.mdm_imei);
1014 return 0;
1015 }
1016
1017 #if defined(CONFIG_MODEM_SIM_NUMBERS)
1018 /*
1019 * Read international mobile subscriber identity.
1020 */
MODEM_CMD_DEFINE(on_cmd_cimi)1021 MODEM_CMD_DEFINE(on_cmd_cimi)
1022 {
1023 size_t out_len =
1024 net_buf_linearize(mdata.mdm_imsi, sizeof(mdata.mdm_imsi) - 1, data->rx_buf, 0, len);
1025 mdata.mdm_imsi[out_len] = '\0';
1026
1027 /* Log the received information. */
1028 LOG_INF("IMSI: %s", mdata.mdm_imsi);
1029 return 0;
1030 }
1031
1032 /*
1033 * Read iccid.
1034 */
MODEM_CMD_DEFINE(on_cmd_ccid)1035 MODEM_CMD_DEFINE(on_cmd_ccid)
1036 {
1037 size_t out_len = net_buf_linearize(mdata.mdm_iccid, sizeof(mdata.mdm_iccid) - 1,
1038 data->rx_buf, 0, len);
1039 mdata.mdm_iccid[out_len] = '\0';
1040
1041 /* Log the received information. */
1042 LOG_INF("ICCID: %s", mdata.mdm_iccid);
1043 return 0;
1044 }
1045 #endif /* defined(CONFIG_MODEM_SIM_NUMBERS) */
1046
1047 /*
1048 * Parses the non urc C(E)REG and updates registration status.
1049 */
MODEM_CMD_DEFINE(on_cmd_cereg)1050 MODEM_CMD_DEFINE(on_cmd_cereg)
1051 {
1052 mdata.mdm_registration = atoi(argv[1]);
1053 LOG_INF("CREG: %u", mdata.mdm_registration);
1054 return 0;
1055 }
1056
MODEM_CMD_DEFINE(on_cmd_cpin)1057 MODEM_CMD_DEFINE(on_cmd_cpin)
1058 {
1059 mdata.cpin_ready = strcmp(argv[0], "READY") == 0;
1060 LOG_INF("CPIN: %d", mdata.cpin_ready);
1061 return 0;
1062 }
1063
MODEM_CMD_DEFINE(on_cmd_cgatt)1064 MODEM_CMD_DEFINE(on_cmd_cgatt)
1065 {
1066 mdata.mdm_cgatt = atoi(argv[0]);
1067 LOG_INF("CGATT: %d", mdata.mdm_cgatt);
1068 return 0;
1069 }
1070
1071 /*
1072 * Handler for RSSI query.
1073 *
1074 * +CSQ: <rssi>,<ber>
1075 * rssi: 0,-115dBm; 1,-111dBm; 2...30,-110...-54dBm; 31,-52dBm or greater.
1076 * 99, ukn
1077 * ber: Not used.
1078 */
MODEM_CMD_DEFINE(on_cmd_csq)1079 MODEM_CMD_DEFINE(on_cmd_csq)
1080 {
1081 int rssi = atoi(argv[0]);
1082
1083 if (rssi == 0) {
1084 mdata.mdm_rssi = -115;
1085 } else if (rssi == 1) {
1086 mdata.mdm_rssi = -111;
1087 } else if (rssi > 1 && rssi < 31) {
1088 mdata.mdm_rssi = -114 + 2 * rssi;
1089 } else if (rssi == 31) {
1090 mdata.mdm_rssi = -52;
1091 } else {
1092 mdata.mdm_rssi = -1000;
1093 }
1094
1095 LOG_INF("RSSI: %d", mdata.mdm_rssi);
1096 return 0;
1097 }
1098
1099 /*
1100 * Queries modem RSSI.
1101 *
1102 * If a work queue parameter is provided query work will
1103 * be scheduled. Otherwise rssi is queried once.
1104 */
modem_rssi_query_work(struct k_work * work)1105 static void modem_rssi_query_work(struct k_work *work)
1106 {
1107 struct modem_cmd cmd[] = { MODEM_CMD("+CSQ: ", on_cmd_csq, 2U, ",") };
1108 static char *send_cmd = "AT+CSQ";
1109 int ret;
1110
1111 ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, cmd, ARRAY_SIZE(cmd), send_cmd,
1112 &mdata.sem_response, MDM_CMD_TIMEOUT);
1113 if (ret < 0) {
1114 LOG_ERR("AT+CSQ ret:%d", ret);
1115 }
1116
1117 if (work) {
1118 k_work_reschedule_for_queue(&modem_workq, &mdata.rssi_query_work,
1119 K_SECONDS(RSSI_TIMEOUT_SECS));
1120 }
1121 }
1122
1123 /*
1124 * Possible responses by the sim7080.
1125 */
1126 static const struct modem_cmd response_cmds[] = {
1127 MODEM_CMD("OK", on_cmd_ok, 0U, ""),
1128 MODEM_CMD("ERROR", on_cmd_error, 0U, ""),
1129 MODEM_CMD("+CME ERROR: ", on_cmd_exterror, 1U, ""),
1130 MODEM_CMD_DIRECT(">", on_cmd_tx_ready),
1131 };
1132
1133 /*
1134 * Possible unsolicited commands.
1135 */
1136 static const struct modem_cmd unsolicited_cmds[] = {
1137 MODEM_CMD("+APP PDP: ", on_urc_app_pdp, 2U, ","),
1138 MODEM_CMD("SMS ", on_urc_sms, 1U, ""),
1139 MODEM_CMD("+CADATAIND: ", on_urc_cadataind, 1U, ""),
1140 MODEM_CMD("+CASTATE: ", on_urc_castate, 2U, ","),
1141 MODEM_CMD("+FTPGET: 1,", on_urc_ftpget, 1U, ""),
1142 };
1143
1144 /*
1145 * Activates the pdp context
1146 */
modem_pdp_activate(void)1147 static int modem_pdp_activate(void)
1148 {
1149 int counter;
1150 int ret = 0;
1151 #if defined(CONFIG_MODEM_SIMCOM_SIM7080_RAT_GSM)
1152 const char *buf = "AT+CREG?";
1153 struct modem_cmd cmds[] = { MODEM_CMD("+CREG: ", on_cmd_cereg, 2U, ",") };
1154 #else
1155 const char *buf = "AT+CEREG?";
1156 struct modem_cmd cmds[] = { MODEM_CMD("+CEREG: ", on_cmd_cereg, 2U, ",") };
1157 #endif /* defined(CONFIG_MODEM_SIMCOM_SIM7080_RAT_GSM) */
1158
1159 struct modem_cmd cgatt_cmd[] = { MODEM_CMD("+CGATT: ", on_cmd_cgatt, 1U, "") };
1160
1161 counter = 0;
1162 while (counter++ < MDM_MAX_CGATT_WAITS && mdata.mdm_cgatt != 1) {
1163 ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, cgatt_cmd,
1164 ARRAY_SIZE(cgatt_cmd), "AT+CGATT?", &mdata.sem_response,
1165 MDM_CMD_TIMEOUT);
1166 if (ret < 0) {
1167 LOG_ERR("Failed to query cgatt!!");
1168 return -1;
1169 }
1170
1171 k_sleep(K_SECONDS(1));
1172 }
1173
1174 if (counter >= MDM_MAX_CGATT_WAITS) {
1175 LOG_WRN("Network attach failed!!");
1176 return -1;
1177 }
1178
1179 if (!mdata.cpin_ready || mdata.mdm_cgatt != 1) {
1180 LOG_ERR("Fatal: Modem is not attached to GPRS network!!");
1181 return -1;
1182 }
1183
1184 LOG_INF("Waiting for network");
1185
1186 /* Wait until the module is registered to the network.
1187 * Registration will be set by urc.
1188 */
1189 counter = 0;
1190 while (counter++ < MDM_MAX_CEREG_WAITS && mdata.mdm_registration != 1 &&
1191 mdata.mdm_registration != 5) {
1192 ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, cmds, ARRAY_SIZE(cmds), buf,
1193 &mdata.sem_response, MDM_CMD_TIMEOUT);
1194 if (ret < 0) {
1195 LOG_ERR("Failed to query registration!!");
1196 return -1;
1197 }
1198
1199 k_sleep(K_SECONDS(1));
1200 }
1201
1202 if (counter >= MDM_MAX_CEREG_WAITS) {
1203 LOG_WRN("Network registration failed!");
1204 ret = -1;
1205 goto error;
1206 }
1207
1208 /* Set dual stack mode (IPv4/IPv6) */
1209 ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, NULL, 0, "AT+CNCFG=0,0",
1210 &mdata.sem_response, MDM_CMD_TIMEOUT);
1211 if (ret < 0) {
1212 LOG_ERR("Could not configure pdp context!");
1213 goto error;
1214 }
1215
1216 /*
1217 * Now activate the pdp context and wait for confirmation.
1218 */
1219 ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, NULL, 0, "AT+CNACT=0,1",
1220 &mdata.sem_response, MDM_CMD_TIMEOUT);
1221 if (ret < 0) {
1222 LOG_ERR("Could not activate PDP context.");
1223 goto error;
1224 }
1225
1226 ret = k_sem_take(&mdata.sem_response, MDM_PDP_TIMEOUT);
1227 if (ret < 0 || mdata.pdp_active == false) {
1228 LOG_ERR("Failed to activate PDP context.");
1229 ret = -1;
1230 goto error;
1231 }
1232
1233 LOG_INF("Network active.");
1234
1235 error:
1236 return ret;
1237 }
1238
1239 /*
1240 * Toggles the modems power pin.
1241 */
modem_pwrkey(void)1242 static void modem_pwrkey(void)
1243 {
1244 /* Power pin should be high for 1.5 seconds. */
1245 gpio_pin_set_dt(&power_gpio, 1);
1246 k_sleep(K_MSEC(1500));
1247 gpio_pin_set_dt(&power_gpio, 0);
1248 k_sleep(K_SECONDS(5));
1249 }
1250
1251 /*
1252 * Commands to be sent at setup.
1253 */
1254 static const struct setup_cmd setup_cmds[] = {
1255 SETUP_CMD_NOHANDLE("ATH"),
1256 SETUP_CMD("AT+CGMI", "", on_cmd_cgmi, 0U, ""),
1257 SETUP_CMD("AT+CGMM", "", on_cmd_cgmm, 0U, ""),
1258 SETUP_CMD("AT+CGMR", "", on_cmd_cgmr, 0U, ""),
1259 SETUP_CMD("AT+CGSN", "", on_cmd_cgsn, 0U, ""),
1260 #if defined(CONFIG_MODEM_SIM_NUMBERS)
1261 SETUP_CMD("AT+CIMI", "", on_cmd_cimi, 0U, ""),
1262 SETUP_CMD("AT+CCID", "", on_cmd_ccid, 0U, ""),
1263 #endif /* defined(CONFIG_MODEM_SIM_NUMBERS) */
1264 #if defined(CONFIG_MODEM_SIMCOM_SIM7080_RAT_NB1)
1265 SETUP_CMD_NOHANDLE("AT+CNMP=38"),
1266 SETUP_CMD_NOHANDLE("AT+CMNB=2"),
1267 SETUP_CMD_NOHANDLE("AT+CBANDCFG=\"NB-IOT\"," MDM_LTE_BANDS),
1268 #endif /* defined(CONFIG_MODEM_SIMCOM_SIM7080_RAT_NB1) */
1269 #if defined(CONFIG_MODEM_SIMCOM_SIM7080_RAT_M1)
1270 SETUP_CMD_NOHANDLE("AT+CNMP=38"),
1271 SETUP_CMD_NOHANDLE("AT+CMNB=1"),
1272 SETUP_CMD_NOHANDLE("AT+CBANDCFG=\"CAT-M\"," MDM_LTE_BANDS),
1273 #endif /* defined(CONFIG_MODEM_SIMCOM_SIM7080_RAT_M1) */
1274 #if defined(CONFIG_MODEM_SIMCOM_SIM7080_RAT_GSM)
1275 SETUP_CMD_NOHANDLE("AT+CNMP=13"),
1276 #endif /* defined(CONFIG_MODEM_SIMCOM_SIM7080_RAT_GSM) */
1277 SETUP_CMD("AT+CPIN?", "+CPIN: ", on_cmd_cpin, 1U, ""),
1278 };
1279
1280 /**
1281 * Performs the autobaud sequence until modem answers or limit is reached.
1282 *
1283 * @return On successful boot 0 is returned. Otherwise <0 is returned.
1284 */
modem_autobaud(void)1285 static int modem_autobaud(void)
1286 {
1287 int boot_tries = 0;
1288 int counter = 0;
1289 int ret;
1290
1291 while (boot_tries++ <= MDM_BOOT_TRIES) {
1292 modem_pwrkey();
1293
1294 /*
1295 * The sim7080 has a autobaud function.
1296 * On startup multiple AT's are sent until
1297 * a OK is received.
1298 */
1299 counter = 0;
1300 while (counter < MDM_MAX_AUTOBAUD) {
1301 ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, NULL, 0U, "AT",
1302 &mdata.sem_response, K_MSEC(500));
1303
1304 /* OK was received. */
1305 if (ret == 0) {
1306 /* Disable echo */
1307 return modem_cmd_send(&mctx.iface, &mctx.cmd_handler, NULL, 0U,
1308 "ATE0", &mdata.sem_response, K_SECONDS(2));
1309 }
1310
1311 counter++;
1312 }
1313 }
1314
1315 return -1;
1316 }
1317
1318 /**
1319 * Get the next parameter from the gnss phrase.
1320 *
1321 * @param src The source string supported on first call.
1322 * @param delim The delimiter of the parameter list.
1323 * @param saveptr Pointer for subsequent parses.
1324 * @return On success a pointer to the parameter. On failure
1325 * or end of string NULL is returned.
1326 *
1327 * This function is used instead of strtok because strtok would
1328 * skip empty parameters, which is not desired. The modem may
1329 * omit parameters which could lead to a incorrect parse.
1330 */
gnss_get_next_param(char * src,const char * delim,char ** saveptr)1331 static char *gnss_get_next_param(char *src, const char *delim, char **saveptr)
1332 {
1333 char *start, *del;
1334
1335 if (src) {
1336 start = src;
1337 } else {
1338 start = *saveptr;
1339 }
1340
1341 /* Illegal start string. */
1342 if (!start) {
1343 return NULL;
1344 }
1345
1346 /* End of string reached. */
1347 if (*start == '\0' || *start == '\r') {
1348 return NULL;
1349 }
1350
1351 del = strstr(start, delim);
1352 if (!del) {
1353 return NULL;
1354 }
1355
1356 *del = '\0';
1357 *saveptr = del + 1;
1358
1359 if (del == start) {
1360 return NULL;
1361 }
1362
1363 return start;
1364 }
1365
gnss_skip_param(char ** saveptr)1366 static void gnss_skip_param(char **saveptr)
1367 {
1368 gnss_get_next_param(NULL, ",", saveptr);
1369 }
1370
1371 /**
1372 * Splits float parameters of the CGNSINF response on '.'
1373 *
1374 * @param src Null terminated string containing the float.
1375 * @param f1 Resulting number part of the float.
1376 * @param f2 Resulting fraction part of the float.
1377 * @return 0 if parsing was successful. Otherwise <0 is returned.
1378 *
1379 * If the number part of the float is negative f1 and f2 will be
1380 * negative too.
1381 */
gnss_split_on_dot(const char * src,int32_t * f1,int32_t * f2)1382 static int gnss_split_on_dot(const char *src, int32_t *f1, int32_t *f2)
1383 {
1384 char *dot = strchr(src, '.');
1385
1386 if (!dot) {
1387 return -1;
1388 }
1389
1390 *dot = '\0';
1391
1392 *f1 = (int32_t)strtol(src, NULL, 10);
1393 *f2 = (int32_t)strtol(dot + 1, NULL, 10);
1394
1395 if (*f1 < 0) {
1396 *f2 = -*f2;
1397 }
1398
1399 return 0;
1400 }
1401
1402 /**
1403 * Parses cgnsinf response into the gnss_data structure.
1404 *
1405 * @param gps_buf Null terminated buffer containing the response.
1406 * @return 0 on successful parse. Otherwise <0 is returned.
1407 */
parse_cgnsinf(char * gps_buf)1408 static int parse_cgnsinf(char *gps_buf)
1409 {
1410 char *saveptr;
1411 int ret;
1412 int32_t number, fraction;
1413
1414 char *run_status = gnss_get_next_param(gps_buf, ",", &saveptr);
1415
1416 if (run_status == NULL) {
1417 goto error;
1418 } else if (*run_status != '1') {
1419 goto error;
1420 }
1421
1422 char *fix_status = gnss_get_next_param(NULL, ",", &saveptr);
1423
1424 if (fix_status == NULL) {
1425 goto error;
1426 } else if (*fix_status != '1') {
1427 goto error;
1428 }
1429
1430 char *utc = gnss_get_next_param(NULL, ",", &saveptr);
1431
1432 if (utc == NULL) {
1433 goto error;
1434 }
1435
1436 char *lat = gnss_get_next_param(NULL, ",", &saveptr);
1437
1438 if (lat == NULL) {
1439 goto error;
1440 }
1441
1442 char *lon = gnss_get_next_param(NULL, ",", &saveptr);
1443
1444 if (lon == NULL) {
1445 goto error;
1446 }
1447
1448 char *alt = gnss_get_next_param(NULL, ",", &saveptr);
1449 char *speed = gnss_get_next_param(NULL, ",", &saveptr);
1450 char *course = gnss_get_next_param(NULL, ",", &saveptr);
1451
1452 /* discard fix mode and reserved*/
1453 gnss_skip_param(&saveptr);
1454 gnss_skip_param(&saveptr);
1455
1456 char *hdop = gnss_get_next_param(NULL, ",", &saveptr);
1457
1458 if (hdop == NULL) {
1459 goto error;
1460 }
1461
1462 gnss_data.run_status = 1;
1463 gnss_data.fix_status = 1;
1464
1465 strncpy(gnss_data.utc, utc, sizeof(gnss_data.utc));
1466
1467 ret = gnss_split_on_dot(lat, &number, &fraction);
1468 if (ret != 0) {
1469 goto error;
1470 }
1471 gnss_data.lat = number * 10000000 + fraction * 10;
1472
1473 ret = gnss_split_on_dot(lon, &number, &fraction);
1474 if (ret != 0) {
1475 goto error;
1476 }
1477 gnss_data.lon = number * 10000000 + fraction * 10;
1478
1479 if (alt) {
1480 ret = gnss_split_on_dot(alt, &number, &fraction);
1481 if (ret != 0) {
1482 goto error;
1483 }
1484 gnss_data.alt = number * 1000 + fraction;
1485 } else {
1486 gnss_data.alt = 0;
1487 }
1488
1489 ret = gnss_split_on_dot(hdop, &number, &fraction);
1490 if (ret != 0) {
1491 goto error;
1492 }
1493 gnss_data.hdop = number * 100 + fraction * 10;
1494
1495 if (course) {
1496 ret = gnss_split_on_dot(course, &number, &fraction);
1497 if (ret != 0) {
1498 goto error;
1499 }
1500 gnss_data.cog = number * 100 + fraction * 10;
1501 } else {
1502 gnss_data.cog = 0;
1503 }
1504
1505 if (speed) {
1506 ret = gnss_split_on_dot(speed, &number, &fraction);
1507 if (ret != 0) {
1508 goto error;
1509 }
1510 gnss_data.kmh = number * 10 + fraction / 10;
1511 } else {
1512 gnss_data.kmh = 0;
1513 }
1514
1515 return 0;
1516 error:
1517 memset(&gnss_data, 0, sizeof(gnss_data));
1518 return -1;
1519 }
1520
1521 /*
1522 * Parses the +CGNSINF Gnss response.
1523 *
1524 * The CGNSINF command has the following parameters but
1525 * not all parameters are set by the module:
1526 *
1527 * +CGNSINF: <GNSS run status>,<Fix status>,<UTC date & Time>,
1528 * <Latitude>,<Longitude>,<MSL Altitude>,<Speed Over Ground>,
1529 * <Course Over Ground>,<Fix Mode>,<Reserved1>,<HDOP>,<PDOP>,
1530 * <VDOP>,<Reserved2>,<GNSS Satellites in View>,<Reserved3>,
1531 * <HPA>,<VPA>
1532 *
1533 */
MODEM_CMD_DEFINE(on_cmd_cgnsinf)1534 MODEM_CMD_DEFINE(on_cmd_cgnsinf)
1535 {
1536 char gps_buf[MDM_GNSS_PARSER_MAX_LEN];
1537 size_t out_len = net_buf_linearize(gps_buf, sizeof(gps_buf) - 1, data->rx_buf, 0, len);
1538
1539 gps_buf[out_len] = '\0';
1540 return parse_cgnsinf(gps_buf);
1541 }
1542
mdm_sim7080_query_gnss(struct sim7080_gnss_data * data)1543 int mdm_sim7080_query_gnss(struct sim7080_gnss_data *data)
1544 {
1545 int ret;
1546 struct modem_cmd cmds[] = { MODEM_CMD("+CGNSINF: ", on_cmd_cgnsinf, 0U, NULL) };
1547
1548 if (get_state() != SIM7080_STATE_GNSS) {
1549 LOG_ERR("GNSS functionality is not enabled!!");
1550 return -1;
1551 }
1552
1553 ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, cmds, ARRAY_SIZE(cmds), "AT+CGNSINF",
1554 &mdata.sem_response, K_SECONDS(2));
1555 if (ret < 0) {
1556 return ret;
1557 }
1558
1559 if (!gnss_data.run_status || !gnss_data.fix_status) {
1560 return -EAGAIN;
1561 }
1562
1563 if (data) {
1564 memcpy(data, &gnss_data, sizeof(gnss_data));
1565 }
1566
1567 memset(&gnss_data, 0, sizeof(gnss_data));
1568
1569 return ret;
1570 }
1571
mdm_sim7080_start_gnss(void)1572 int mdm_sim7080_start_gnss(void)
1573 {
1574 int ret;
1575
1576 change_state(SIM7080_STATE_INIT);
1577 k_work_cancel_delayable(&mdata.rssi_query_work);
1578
1579 ret = modem_autobaud();
1580 if (ret < 0) {
1581 LOG_ERR("Failed to start modem!!");
1582 return -1;
1583 }
1584
1585 ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, NULL, 0U, "AT+CGNSCOLD",
1586 &mdata.sem_response, K_SECONDS(2));
1587 if (ret < 0) {
1588 return -1;
1589 }
1590
1591 change_state(SIM7080_STATE_GNSS);
1592 return 0;
1593 }
1594
1595 /**
1596 * Parse the +FTPGET response.
1597 *
1598 * +FTPGET: <mode>,<len>
1599 *
1600 * Mode is hard set to 2.
1601 *
1602 * Length is the number of bytes following (the ftp data).
1603 */
MODEM_CMD_DEFINE(on_cmd_ftpget)1604 MODEM_CMD_DEFINE(on_cmd_ftpget)
1605 {
1606 int nbytes = atoi(argv[0]);
1607 int bytes_to_skip;
1608 size_t out_len;
1609
1610 if (nbytes == 0) {
1611 mdata.ftp.nread = 0;
1612 return 0;
1613 }
1614
1615 /* Skip length parameter and trailing \r\n */
1616 bytes_to_skip = strlen(argv[0]) + 2;
1617
1618 /* Wait until data is ready.
1619 * >= to ensure buffer is not empty after skip.
1620 */
1621 if (net_buf_frags_len(data->rx_buf) <= nbytes + bytes_to_skip) {
1622 return -EAGAIN;
1623 }
1624
1625 out_len = net_buf_linearize(mdata.ftp.read_buffer, mdata.ftp.nread, data->rx_buf,
1626 bytes_to_skip, nbytes);
1627 if (out_len != nbytes) {
1628 LOG_WRN("FTP read size differs!");
1629 }
1630 data->rx_buf = net_buf_skip(data->rx_buf, nbytes + bytes_to_skip);
1631
1632 mdata.ftp.nread = nbytes;
1633
1634 return 0;
1635 }
1636
mdm_sim7080_ftp_get_read(char * dst,size_t * size)1637 int mdm_sim7080_ftp_get_read(char *dst, size_t *size)
1638 {
1639 int ret;
1640 char buffer[sizeof("AT+FTPGET=#,######")];
1641 struct modem_cmd cmds[] = { MODEM_CMD("+FTPGET: 2,", on_cmd_ftpget, 1U, "") };
1642
1643 /* Some error occurred. */
1644 if (mdata.ftp.state == SIM7080_FTP_CONNECTION_STATE_ERROR ||
1645 mdata.ftp.state == SIM7080_FTP_CONNECTION_STATE_INITIAL) {
1646 return SIM7080_FTP_RC_ERROR;
1647 }
1648
1649 /* Setup buffer. */
1650 mdata.ftp.read_buffer = dst;
1651 mdata.ftp.nread = *size;
1652
1653 /* Read ftp data. */
1654 ret = snprintk(buffer, sizeof(buffer), "AT+FTPGET=2,%zu", *size);
1655 if (ret < 0) {
1656 *size = 0;
1657 return SIM7080_FTP_RC_ERROR;
1658 }
1659
1660 /* Wait for data from the server. */
1661 k_sem_take(&mdata.sem_ftp, K_MSEC(200));
1662
1663 if (mdata.ftp.state == SIM7080_FTP_CONNECTION_STATE_FINISHED) {
1664 *size = 0;
1665 return SIM7080_FTP_RC_FINISHED;
1666 } else if (mdata.ftp.state == SIM7080_FTP_CONNECTION_STATE_ERROR) {
1667 *size = 0;
1668 return SIM7080_FTP_RC_ERROR;
1669 }
1670
1671 ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, cmds, ARRAY_SIZE(cmds), buffer,
1672 &mdata.sem_response, MDM_CMD_TIMEOUT);
1673 if (ret < 0) {
1674 *size = 0;
1675 return SIM7080_FTP_RC_ERROR;
1676 }
1677
1678 /* Set read size. */
1679 *size = mdata.ftp.nread;
1680
1681 return SIM7080_FTP_RC_OK;
1682 }
1683
mdm_sim7080_ftp_get_start(const char * server,const char * user,const char * passwd,const char * file,const char * path)1684 int mdm_sim7080_ftp_get_start(const char *server, const char *user, const char *passwd,
1685 const char *file, const char *path)
1686 {
1687 int ret;
1688 char buffer[256];
1689
1690 /* Start network. */
1691 ret = mdm_sim7080_start_network();
1692 if (ret < 0) {
1693 LOG_ERR("Failed to start network for FTP!");
1694 return -1;
1695 }
1696
1697 /* Set connection id for ftp. */
1698 ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, NULL, 0U, "AT+FTPCID=0",
1699 &mdata.sem_response, MDM_CMD_TIMEOUT);
1700 if (ret < 0) {
1701 LOG_WRN("Failed to set FTP Cid!");
1702 return -1;
1703 }
1704
1705 /* Set ftp server. */
1706 ret = snprintk(buffer, sizeof(buffer), "AT+FTPSERV=\"%s\"", server);
1707 if (ret < 0) {
1708 LOG_WRN("Failed to build command!");
1709 return -1;
1710 }
1711
1712 ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, NULL, 0U, buffer, &mdata.sem_response,
1713 MDM_CMD_TIMEOUT);
1714 if (ret < 0) {
1715 LOG_WRN("Failed to set FTP Cid!");
1716 return -1;
1717 }
1718
1719 /* Set ftp user. */
1720 ret = snprintk(buffer, sizeof(buffer), "AT+FTPUN=\"%s\"", user);
1721 if (ret < 0) {
1722 LOG_WRN("Failed to build command!");
1723 return -1;
1724 }
1725
1726 ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, NULL, 0U, buffer, &mdata.sem_response,
1727 MDM_CMD_TIMEOUT);
1728 if (ret < 0) {
1729 LOG_WRN("Failed to set ftp user!");
1730 return -1;
1731 }
1732
1733 /* Set ftp password. */
1734 ret = snprintk(buffer, sizeof(buffer), "AT+FTPPW=\"%s\"", passwd);
1735 if (ret < 0) {
1736 LOG_WRN("Failed to build command!");
1737 return -1;
1738 }
1739
1740 ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, NULL, 0U, buffer, &mdata.sem_response,
1741 MDM_CMD_TIMEOUT);
1742 if (ret < 0) {
1743 LOG_WRN("Failed to set ftp password!");
1744 return -1;
1745 }
1746
1747 /* Set ftp filename. */
1748 ret = snprintk(buffer, sizeof(buffer), "AT+FTPGETNAME=\"%s\"", file);
1749 if (ret < 0) {
1750 LOG_WRN("Failed to build command!");
1751 return -1;
1752 }
1753
1754 ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, NULL, 0U, buffer, &mdata.sem_response,
1755 MDM_CMD_TIMEOUT);
1756 if (ret < 0) {
1757 LOG_WRN("Failed to set ftp filename!");
1758 return -1;
1759 }
1760
1761 /* Set ftp filename. */
1762 ret = snprintk(buffer, sizeof(buffer), "AT+FTPGETNAME=\"%s\"", file);
1763 if (ret < 0) {
1764 LOG_WRN("Failed to build command!");
1765 return -1;
1766 }
1767
1768 ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, NULL, 0U, buffer, &mdata.sem_response,
1769 MDM_CMD_TIMEOUT);
1770 if (ret < 0) {
1771 LOG_WRN("Failed to set ftp filename!");
1772 return -1;
1773 }
1774
1775 /* Set ftp path. */
1776 ret = snprintk(buffer, sizeof(buffer), "AT+FTPGETPATH=\"%s\"", path);
1777 if (ret < 0) {
1778 LOG_WRN("Failed to build command!");
1779 return -1;
1780 }
1781
1782 ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, NULL, 0U, buffer, &mdata.sem_response,
1783 MDM_CMD_TIMEOUT);
1784 if (ret < 0) {
1785 LOG_WRN("Failed to set ftp path!");
1786 return -1;
1787 }
1788
1789 /* Initialize ftp variables. */
1790 mdata.ftp.read_buffer = NULL;
1791 mdata.ftp.nread = 0;
1792 mdata.ftp.state = SIM7080_FTP_CONNECTION_STATE_INITIAL;
1793
1794 /* Start the ftp session. */
1795 ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, NULL, 0U, "AT+FTPGET=1",
1796 &mdata.sem_ftp, MDM_CMD_TIMEOUT);
1797 if (ret < 0) {
1798 LOG_WRN("Failed to start session!");
1799 return -1;
1800 }
1801
1802 if (mdata.ftp.state != SIM7080_FTP_CONNECTION_STATE_CONNECTED) {
1803 LOG_WRN("Session state is not connected!");
1804 return -1;
1805 }
1806
1807 return 0;
1808 }
1809
1810 /**
1811 * Decode readable hex to "real" hex.
1812 */
mdm_pdu_decode_ascii(char byte)1813 static uint8_t mdm_pdu_decode_ascii(char byte)
1814 {
1815 if ((byte >= '0') && (byte <= '9')) {
1816 return byte - '0';
1817 } else if ((byte >= 'A') && (byte <= 'F')) {
1818 return byte - 'A' + 10;
1819 } else if ((byte >= 'a') && (byte <= 'f')) {
1820 return byte - 'a' + 10;
1821 } else {
1822 return 255;
1823 }
1824 }
1825
1826 /**
1827 * Reads "byte" from pdu.
1828 *
1829 * @param pdu pdu to read from.
1830 * @param index index of "byte".
1831 *
1832 * Sim module "encodes" one pdu byte as two human readable bytes
1833 * this functions squashes these two bytes into one.
1834 */
mdm_pdu_read_byte(const char * pdu,size_t index)1835 static uint8_t mdm_pdu_read_byte(const char *pdu, size_t index)
1836 {
1837 return (mdm_pdu_decode_ascii(pdu[index * 2]) << 4 |
1838 mdm_pdu_decode_ascii(pdu[index * 2 + 1]));
1839 }
1840
1841 /**
1842 * Decodes time from pdu.
1843 *
1844 * @param pdu pdu to read from.
1845 * @param index index of "byte".
1846 */
mdm_pdu_read_time(const char * pdu,size_t index)1847 static uint8_t mdm_pdu_read_time(const char *pdu, size_t index)
1848 {
1849 return (mdm_pdu_decode_ascii(pdu[index * 2]) +
1850 mdm_pdu_decode_ascii(pdu[index * 2 + 1]) * 10);
1851 }
1852
1853 /**
1854 * Decode a sms from pdu mode.
1855 */
mdm_decode_pdu(const char * pdu,size_t pdu_len,struct sim7080_sms * target_buf)1856 static int mdm_decode_pdu(const char *pdu, size_t pdu_len, struct sim7080_sms *target_buf)
1857 {
1858 size_t index;
1859
1860 /*
1861 * GSM_03.38 to Unicode conversion table
1862 */
1863 const short enc7_basic[128] = {
1864 '@', 0xA3, '$', 0xA5, 0xE8, 0xE9, 0xF9, 0xEC, 0xF2, 0xE7,
1865 '\n', 0xD8, 0xF8, '\r', 0xC5, 0xF8, 0x0394, '_', 0x03A6, 0x0393,
1866 0x039B, 0x03A9, 0x03A0, 0x03A8, 0x03A3, 0x0398, 0x039E, '\x1b', 0xC6, 0xE6,
1867 0xDF, 0xC9, ' ', '!', '\"', '#', 0xA4, '%', '&', '\'',
1868 '(', ')', '*', '+', ',', '-', '.', '/', '0', '1',
1869 '2', '3', '4', '5', '6', '7', '8', '9', ':', ';',
1870 '<', '=', '>', '?', 0xA1, 'A', 'B', 'C', 'D', 'E',
1871 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
1872 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y',
1873 'Z', 0xC4, 0xD6, 0xD1, 0xDC, 0xA7, 0xBF, 'a', 'b', 'c',
1874 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
1875 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
1876 'x', 'y', 'z', 0xE4, 0xF6, 0xF1, 0xFC, 0xE0
1877 };
1878
1879 /* two bytes in pdu are on real byte */
1880 pdu_len = (pdu_len / 2);
1881
1882 /* first byte of pdu is length of trailing SMSC information
1883 * skip it by setting index to SMSC length + 1.
1884 */
1885 index = mdm_pdu_read_byte(pdu, 0) + 1;
1886
1887 if (index >= pdu_len) {
1888 return -1;
1889 }
1890
1891 /* read first octet */
1892 target_buf->first_octet = mdm_pdu_read_byte(pdu, index++);
1893
1894 if (index >= pdu_len) {
1895 return -1;
1896 }
1897
1898 /* pdu_index now points to the address field.
1899 * first byte of addr field is the addr length -> skip it.
1900 * address type is not included in addr len -> add +1.
1901 * address is coded in semi octets
1902 * + addr_len/2 if even
1903 * + addr_len/2 + 1 if odd
1904 */
1905 uint8_t addr_len = mdm_pdu_read_byte(pdu, index);
1906
1907 index += ((addr_len % 2) == 0) ? (addr_len / 2) + 2 : (addr_len / 2) + 3;
1908
1909 if (index >= pdu_len) {
1910 return -1;
1911 }
1912
1913 /* read protocol identifier */
1914 target_buf->tp_pid = mdm_pdu_read_byte(pdu, index++);
1915
1916 if (index >= pdu_len) {
1917 return -1;
1918 }
1919
1920 /* read coding scheme */
1921 uint8_t tp_dcs = mdm_pdu_read_byte(pdu, index++);
1922
1923 /* parse date and time */
1924 if ((index + 7) >= pdu_len) {
1925 return -1;
1926 }
1927
1928 target_buf->time.year = mdm_pdu_read_time(pdu, index++);
1929 target_buf->time.month = mdm_pdu_read_time(pdu, index++);
1930 target_buf->time.day = mdm_pdu_read_time(pdu, index++);
1931 target_buf->time.hour = mdm_pdu_read_time(pdu, index++);
1932 target_buf->time.minute = mdm_pdu_read_time(pdu, index++);
1933 target_buf->time.second = mdm_pdu_read_time(pdu, index++);
1934 target_buf->time.timezone = mdm_pdu_read_time(pdu, index++);
1935
1936 /* Read user data length */
1937 uint8_t tp_udl = mdm_pdu_read_byte(pdu, index++);
1938
1939 /* Discard header */
1940 uint8_t header_skip = 0;
1941
1942 if (target_buf->first_octet & SMS_TP_UDHI_HEADER) {
1943 uint8_t tp_udhl = mdm_pdu_read_byte(pdu, index);
1944
1945 index += tp_udhl + 1;
1946 header_skip = tp_udhl + 1;
1947
1948 if (index >= pdu_len) {
1949 return -1;
1950 }
1951 }
1952
1953 /* Read data according to type set in TP-DCS */
1954 if (tp_dcs == 0x00) {
1955 /* 7 bit GSM coding */
1956 uint8_t fill_level = 0;
1957 uint16_t buf = 0;
1958
1959 if (target_buf->first_octet & SMS_TP_UDHI_HEADER) {
1960 /* Initial fill because septets are aligned to
1961 * septet boundary after header
1962 */
1963 uint8_t fill_bits = 7 - ((header_skip * 8) % 7);
1964
1965 if (fill_bits == 7) {
1966 fill_bits = 0;
1967 }
1968
1969 buf = mdm_pdu_read_byte(pdu, index++);
1970
1971 fill_level = 8 - fill_bits;
1972 }
1973
1974 uint16_t data_index = 0;
1975
1976 for (unsigned int idx = 0; idx < tp_udl; idx++) {
1977 if (fill_level < 7) {
1978 uint8_t octet = mdm_pdu_read_byte(pdu, index++);
1979
1980 buf &= ((1 << fill_level) - 1);
1981 buf |= (octet << fill_level);
1982 fill_level += 8;
1983 }
1984
1985 /*
1986 * Convert 7-bit encoded data to Unicode and
1987 * then to UTF-8
1988 */
1989 short letter = enc7_basic[buf & 0x007f];
1990
1991 if (letter < 0x0080) {
1992 target_buf->data[data_index++] = letter & 0x007f;
1993 } else if (letter < 0x0800) {
1994 target_buf->data[data_index++] = 0xc0 | ((letter & 0x07c0) >> 6);
1995 target_buf->data[data_index++] = 0x80 | ((letter & 0x003f) >> 0);
1996 }
1997 buf >>= 7;
1998 fill_level -= 7;
1999 }
2000 target_buf->data_len = data_index;
2001 } else if (tp_dcs == 0x04) {
2002 /* 8 bit binary coding */
2003 for (int idx = 0; idx < tp_udl - header_skip; idx++) {
2004 target_buf->data[idx] = mdm_pdu_read_byte(pdu, index++);
2005 }
2006 target_buf->data_len = tp_udl;
2007 } else if (tp_dcs == 0x08) {
2008 /* Unicode (16 bit per character) */
2009 for (int idx = 0; idx < tp_udl - header_skip; idx++) {
2010 target_buf->data[idx] = mdm_pdu_read_byte(pdu, index++);
2011 }
2012 target_buf->data_len = tp_udl;
2013 } else {
2014 return -1;
2015 }
2016
2017 return 0;
2018 }
2019
2020 /**
2021 * Check if given char sequence is crlf.
2022 *
2023 * @param c The char sequence.
2024 * @param len Total length of the fragment.
2025 * @return @c true if char sequence is crlf.
2026 * Otherwise @c false is returned.
2027 */
is_crlf(uint8_t * c,uint8_t len)2028 static bool is_crlf(uint8_t *c, uint8_t len)
2029 {
2030 /* crlf does not fit. */
2031 if (len < 2) {
2032 return false;
2033 }
2034
2035 return c[0] == '\r' && c[1] == '\n';
2036 }
2037
2038 /**
2039 * Find terminating crlf in a netbuffer.
2040 *
2041 * @param buf The netbuffer.
2042 * @param skip Bytes to skip before search.
2043 * @return Length of the returned fragment or 0 if not found.
2044 */
net_buf_find_crlf(struct net_buf * buf,size_t skip)2045 static size_t net_buf_find_crlf(struct net_buf *buf, size_t skip)
2046 {
2047 size_t len = 0, pos = 0;
2048 struct net_buf *frag = buf;
2049
2050 /* Skip to the start. */
2051 while (frag && skip >= frag->len) {
2052 skip -= frag->len;
2053 frag = frag->frags;
2054 }
2055
2056 /* Need to wait for more data. */
2057 if (!frag) {
2058 return 0;
2059 }
2060
2061 pos = skip;
2062
2063 while (frag && !is_crlf(frag->data + pos, frag->len - pos)) {
2064 if (pos + 1 >= frag->len) {
2065 len += frag->len;
2066 frag = frag->frags;
2067 pos = 0U;
2068 } else {
2069 pos++;
2070 }
2071 }
2072
2073 if (frag && is_crlf(frag->data + pos, frag->len - pos)) {
2074 len += pos;
2075 return len - skip;
2076 }
2077
2078 return 0;
2079 }
2080
2081 /**
2082 * Parses list sms and add them to buffer.
2083 * Format is:
2084 *
2085 * +CMGL: <index>,<stat>,,<length><CR><LF><pdu><CR><LF>
2086 * +CMGL: <index>,<stat>,,<length><CR><LF><pdu><CR><LF>
2087 * ...
2088 * OK
2089 */
MODEM_CMD_DEFINE(on_cmd_cmgl)2090 MODEM_CMD_DEFINE(on_cmd_cmgl)
2091 {
2092 int sms_index, sms_stat, ret;
2093 char pdu_buffer[256];
2094 size_t out_len, sms_len, param_len;
2095 struct sim7080_sms *sms;
2096
2097 sms_index = atoi(argv[0]);
2098 sms_stat = atoi(argv[1]);
2099
2100 /* Get the length of the "length" parameter.
2101 * The last parameter will be stuck in the netbuffer.
2102 * It is not the actual length of the trailing pdu so
2103 * we have to search the next crlf.
2104 */
2105 param_len = net_buf_find_crlf(data->rx_buf, 0);
2106 if (param_len == 0) {
2107 LOG_INF("No <CR><LF>");
2108 return -EAGAIN;
2109 }
2110
2111 /* Get actual trailing pdu len. +2 to skip crlf. */
2112 sms_len = net_buf_find_crlf(data->rx_buf, param_len + 2);
2113 if (sms_len == 0) {
2114 return -EAGAIN;
2115 }
2116
2117 /* Skip to start of pdu. */
2118 data->rx_buf = net_buf_skip(data->rx_buf, param_len + 2);
2119
2120 out_len = net_buf_linearize(pdu_buffer, sizeof(pdu_buffer) - 1, data->rx_buf, 0, sms_len);
2121 pdu_buffer[out_len] = '\0';
2122
2123 data->rx_buf = net_buf_skip(data->rx_buf, sms_len);
2124
2125 /* No buffer specified. */
2126 if (!mdata.sms_buffer) {
2127 return 0;
2128 }
2129
2130 /* No space left in buffer. */
2131 if (mdata.sms_buffer_pos >= mdata.sms_buffer->nsms) {
2132 return 0;
2133 }
2134
2135 sms = &mdata.sms_buffer->sms[mdata.sms_buffer_pos];
2136
2137 ret = mdm_decode_pdu(pdu_buffer, out_len, sms);
2138 if (ret < 0) {
2139 return 0;
2140 }
2141
2142 sms->stat = sms_stat;
2143 sms->index = sms_index;
2144 sms->data[sms->data_len] = '\0';
2145
2146 mdata.sms_buffer_pos++;
2147
2148 return 0;
2149 }
2150
mdm_sim7080_read_sms(struct sim7080_sms_buffer * buffer)2151 int mdm_sim7080_read_sms(struct sim7080_sms_buffer *buffer)
2152 {
2153 int ret;
2154 struct modem_cmd cmds[] = { MODEM_CMD("+CMGL: ", on_cmd_cmgl, 4U, ",\r") };
2155
2156 mdata.sms_buffer = buffer;
2157 mdata.sms_buffer_pos = 0;
2158
2159 ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, cmds, ARRAY_SIZE(cmds), "AT+CMGL=4",
2160 &mdata.sem_response, K_SECONDS(20));
2161 if (ret < 0) {
2162 return -1;
2163 }
2164
2165 return mdata.sms_buffer_pos;
2166 }
2167
mdm_sim7080_delete_sms(uint16_t index)2168 int mdm_sim7080_delete_sms(uint16_t index)
2169 {
2170 int ret;
2171 char buf[sizeof("AT+CMGD=#####")] = { 0 };
2172
2173 ret = snprintk(buf, sizeof(buf), "AT+CMGD=%u", index);
2174 if (ret < 0) {
2175 return -1;
2176 }
2177
2178 ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, NULL, 0, buf, &mdata.sem_response,
2179 K_SECONDS(5));
2180 if (ret < 0) {
2181 return -1;
2182 }
2183
2184 return 0;
2185 }
2186
2187 /*
2188 * Does the modem setup by starting it and
2189 * bringing the modem to a PDP active state.
2190 */
modem_setup(void)2191 static int modem_setup(void)
2192 {
2193 int ret = 0;
2194 int counter = 0;
2195
2196 k_work_cancel_delayable(&mdata.rssi_query_work);
2197
2198 ret = modem_autobaud();
2199 if (ret < 0) {
2200 LOG_ERR("Booting modem failed!!");
2201 goto error;
2202 }
2203
2204 ret = modem_cmd_handler_setup_cmds(&mctx.iface, &mctx.cmd_handler, setup_cmds,
2205 ARRAY_SIZE(setup_cmds), &mdata.sem_response,
2206 MDM_REGISTRATION_TIMEOUT);
2207 if (ret < 0) {
2208 LOG_ERR("Failed to send init commands!");
2209 goto error;
2210 }
2211
2212 k_sleep(K_SECONDS(3));
2213
2214 /* Wait for acceptable rssi values. */
2215 modem_rssi_query_work(NULL);
2216 k_sleep(MDM_WAIT_FOR_RSSI_DELAY);
2217
2218 counter = 0;
2219 while (counter++ < MDM_WAIT_FOR_RSSI_COUNT &&
2220 (mdata.mdm_rssi >= 0 || mdata.mdm_rssi <= -1000)) {
2221 modem_rssi_query_work(NULL);
2222 k_sleep(MDM_WAIT_FOR_RSSI_DELAY);
2223 }
2224
2225 if (mdata.mdm_rssi >= 0 || mdata.mdm_rssi <= -1000) {
2226 LOG_ERR("Network not reachable!!");
2227 ret = -ENETUNREACH;
2228 goto error;
2229 }
2230
2231 ret = modem_pdp_activate();
2232 if (ret < 0) {
2233 goto error;
2234 }
2235
2236 k_work_reschedule_for_queue(&modem_workq, &mdata.rssi_query_work,
2237 K_SECONDS(RSSI_TIMEOUT_SECS));
2238
2239 change_state(SIM7080_STATE_NETWORKING);
2240
2241 error:
2242 return ret;
2243 }
2244
mdm_sim7080_start_network(void)2245 int mdm_sim7080_start_network(void)
2246 {
2247 change_state(SIM7080_STATE_INIT);
2248 return modem_setup();
2249 }
2250
mdm_sim7080_power_on(void)2251 int mdm_sim7080_power_on(void)
2252 {
2253 return modem_autobaud();
2254 }
2255
mdm_sim7080_power_off(void)2256 int mdm_sim7080_power_off(void)
2257 {
2258 int tries = 5;
2259 int autobaud_tries;
2260 int ret = 0;
2261
2262 k_work_cancel_delayable(&mdata.rssi_query_work);
2263
2264 /* Check if module is already off. */
2265 ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, NULL, 0U, "AT", &mdata.sem_response,
2266 K_MSEC(1000));
2267 if (ret < 0) {
2268 change_state(SIM7080_STATE_OFF);
2269 return 0;
2270 }
2271
2272 while (tries--) {
2273 modem_pwrkey();
2274
2275 autobaud_tries = 5;
2276
2277 while (autobaud_tries--) {
2278 ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, NULL, 0U, "AT",
2279 &mdata.sem_response, K_MSEC(500));
2280 if (ret == 0) {
2281 break;
2282 }
2283 }
2284
2285 if (ret < 0) {
2286 change_state(SIM7080_STATE_OFF);
2287 return 0;
2288 }
2289 }
2290
2291 return -1;
2292 }
2293
mdm_sim7080_get_manufacturer(void)2294 const char *mdm_sim7080_get_manufacturer(void)
2295 {
2296 return mdata.mdm_manufacturer;
2297 }
2298
mdm_sim7080_get_model(void)2299 const char *mdm_sim7080_get_model(void)
2300 {
2301 return mdata.mdm_model;
2302 }
2303
mdm_sim7080_get_revision(void)2304 const char *mdm_sim7080_get_revision(void)
2305 {
2306 return mdata.mdm_revision;
2307 }
2308
mdm_sim7080_get_imei(void)2309 const char *mdm_sim7080_get_imei(void)
2310 {
2311 return mdata.mdm_imei;
2312 }
2313
2314 /*
2315 * Initializes modem handlers and context.
2316 * After successful init this function calls
2317 * modem_setup.
2318 */
modem_init(const struct device * dev)2319 static int modem_init(const struct device *dev)
2320 {
2321 int ret;
2322
2323 ARG_UNUSED(dev);
2324
2325 k_sem_init(&mdata.sem_response, 0, 1);
2326 k_sem_init(&mdata.sem_tx_ready, 0, 1);
2327 k_sem_init(&mdata.sem_dns, 0, 1);
2328 k_sem_init(&mdata.sem_ftp, 0, 1);
2329 k_work_queue_start(&modem_workq, modem_workq_stack,
2330 K_KERNEL_STACK_SIZEOF(modem_workq_stack), K_PRIO_COOP(7), NULL);
2331
2332 /* Assume the modem is not registered to the network. */
2333 mdata.mdm_registration = 0;
2334 mdata.cpin_ready = false;
2335 mdata.pdp_active = false;
2336
2337 mdata.sms_buffer = NULL;
2338 mdata.sms_buffer_pos = 0;
2339
2340 /* Socket config. */
2341 ret = modem_socket_init(&mdata.socket_config, &mdata.sockets[0], ARRAY_SIZE(mdata.sockets),
2342 MDM_BASE_SOCKET_NUM, true, &offload_socket_fd_op_vtable);
2343 if (ret < 0) {
2344 goto error;
2345 }
2346
2347 change_state(SIM7080_STATE_INIT);
2348
2349 /* Command handler. */
2350 const struct modem_cmd_handler_config cmd_handler_config = {
2351 .match_buf = &mdata.cmd_match_buf[0],
2352 .match_buf_len = sizeof(mdata.cmd_match_buf),
2353 .buf_pool = &mdm_recv_pool,
2354 .alloc_timeout = BUF_ALLOC_TIMEOUT,
2355 .eol = "\r\n",
2356 .user_data = NULL,
2357 .response_cmds = response_cmds,
2358 .response_cmds_len = ARRAY_SIZE(response_cmds),
2359 .unsol_cmds = unsolicited_cmds,
2360 .unsol_cmds_len = ARRAY_SIZE(unsolicited_cmds),
2361 };
2362
2363 ret = modem_cmd_handler_init(&mctx.cmd_handler, &mdata.cmd_handler_data,
2364 &cmd_handler_config);
2365 if (ret < 0) {
2366 goto error;
2367 }
2368
2369 /* Uart handler. */
2370 const struct modem_iface_uart_config uart_config = {
2371 .rx_rb_buf = &mdata.iface_rb_buf[0],
2372 .rx_rb_buf_len = sizeof(mdata.iface_rb_buf),
2373 .dev = MDM_UART_DEV,
2374 .hw_flow_control = DT_PROP(MDM_UART_NODE, hw_flow_control),
2375 };
2376
2377 ret = modem_iface_uart_init(&mctx.iface, &mdata.iface_data, &uart_config);
2378 if (ret < 0) {
2379 goto error;
2380 }
2381
2382 mdata.current_sock_fd = -1;
2383 mdata.current_sock_written = 0;
2384
2385 mdata.ftp.read_buffer = NULL;
2386 mdata.ftp.nread = 0;
2387 mdata.ftp.state = SIM7080_FTP_CONNECTION_STATE_INITIAL;
2388
2389 /* Modem data storage. */
2390 mctx.data_manufacturer = mdata.mdm_manufacturer;
2391 mctx.data_model = mdata.mdm_model;
2392 mctx.data_revision = mdata.mdm_revision;
2393 mctx.data_imei = mdata.mdm_imei;
2394 #if defined(CONFIG_MODEM_SIM_NUMBERS)
2395 mctx.data_imsi = mdata.mdm_imsi;
2396 mctx.data_iccid = mdata.mdm_iccid;
2397 #endif /* #if defined(CONFIG_MODEM_SIM_NUMBERS) */
2398 mctx.data_rssi = &mdata.mdm_rssi;
2399
2400 ret = gpio_pin_configure_dt(&power_gpio, GPIO_OUTPUT_LOW);
2401 if (ret < 0) {
2402 LOG_ERR("Failed to configure %s pin", "power");
2403 goto error;
2404 }
2405
2406 mctx.driver_data = &mdata;
2407
2408 memset(&gnss_data, 0, sizeof(gnss_data));
2409
2410 ret = modem_context_register(&mctx);
2411 if (ret < 0) {
2412 LOG_ERR("Error registering modem context: %d", ret);
2413 goto error;
2414 }
2415
2416 k_thread_create(&modem_rx_thread, modem_rx_stack, K_KERNEL_STACK_SIZEOF(modem_rx_stack),
2417 (k_thread_entry_t)modem_rx, NULL, NULL, NULL, K_PRIO_COOP(7), 0, K_NO_WAIT);
2418
2419 /* Init RSSI query */
2420 k_work_init_delayable(&mdata.rssi_query_work, modem_rssi_query_work);
2421
2422 return modem_setup();
2423 error:
2424 return ret;
2425 }
2426
2427 /* Register device with the networking stack. */
2428 NET_DEVICE_DT_INST_OFFLOAD_DEFINE(0, modem_init, NULL, &mdata, NULL,
2429 CONFIG_MODEM_SIMCOM_SIM7080_INIT_PRIORITY, &api_funcs,
2430 MDM_MAX_DATA_LENGTH);
2431
2432 NET_SOCKET_OFFLOAD_REGISTER(simcom_sim7080, CONFIG_NET_SOCKETS_OFFLOAD_PRIORITY,
2433 AF_UNSPEC, offload_is_supported, offload_socket);
2434