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 ARG_UNUSED(res);
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 * p1,void * p2,void * p3)805 static void modem_rx(void *p1, void *p2, void *p3)
806 {
807 ARG_UNUSED(p1);
808 ARG_UNUSED(p2);
809 ARG_UNUSED(p3);
810
811 while (true) {
812 /* Wait for incoming data */
813 modem_iface_uart_rx_wait(&mctx.iface, K_FOREVER);
814
815 modem_cmd_handler_process(&mctx.cmd_handler, &mctx.iface);
816 }
817 }
818
MODEM_CMD_DEFINE(on_cmd_ok)819 MODEM_CMD_DEFINE(on_cmd_ok)
820 {
821 modem_cmd_handler_set_error(data, 0);
822 k_sem_give(&mdata.sem_response);
823 return 0;
824 }
825
MODEM_CMD_DEFINE(on_cmd_error)826 MODEM_CMD_DEFINE(on_cmd_error)
827 {
828 modem_cmd_handler_set_error(data, -EIO);
829 k_sem_give(&mdata.sem_response);
830 return 0;
831 }
832
MODEM_CMD_DEFINE(on_cmd_exterror)833 MODEM_CMD_DEFINE(on_cmd_exterror)
834 {
835 modem_cmd_handler_set_error(data, -EIO);
836 k_sem_give(&mdata.sem_response);
837 return 0;
838 }
839
840 /*
841 * Handles pdp context urc.
842 *
843 * The urc has the form +APP PDP: <index>,<state>.
844 * State can either be ACTIVE for activation or
845 * DEACTIVE if disabled.
846 */
MODEM_CMD_DEFINE(on_urc_app_pdp)847 MODEM_CMD_DEFINE(on_urc_app_pdp)
848 {
849 mdata.pdp_active = strcmp(argv[1], "ACTIVE") == 0;
850 LOG_INF("PDP context: %u", mdata.pdp_active);
851 k_sem_give(&mdata.sem_response);
852 return 0;
853 }
854
MODEM_CMD_DEFINE(on_urc_sms)855 MODEM_CMD_DEFINE(on_urc_sms)
856 {
857 LOG_INF("SMS: %s", argv[0]);
858 return 0;
859 }
860
861 /*
862 * Handles socket data notification.
863 *
864 * The sim modem sends and unsolicited +CADATAIND: <cid>
865 * if data can be read from a socket.
866 */
MODEM_CMD_DEFINE(on_urc_cadataind)867 MODEM_CMD_DEFINE(on_urc_cadataind)
868 {
869 struct modem_socket *sock;
870 int sock_fd;
871
872 sock_fd = atoi(argv[0]);
873
874 sock = modem_socket_from_fd(&mdata.socket_config, sock_fd);
875 if (!sock) {
876 return 0;
877 }
878
879 /* Modem does not tell packet size. Set dummy for receive. */
880 modem_socket_packet_size_update(&mdata.socket_config, sock, 1);
881
882 LOG_INF("Data available on socket: %d", sock_fd);
883 modem_socket_data_ready(&mdata.socket_config, sock);
884
885 return 0;
886 }
887
888 /*
889 * Handles the castate response.
890 *
891 * +CASTATE: <cid>,<state>
892 *
893 * Cid is the connection id (socket fd) and
894 * state can be:
895 * 0 - Closed by remote server or error
896 * 1 - Connected to remote server
897 * 2 - Listening
898 */
MODEM_CMD_DEFINE(on_urc_castate)899 MODEM_CMD_DEFINE(on_urc_castate)
900 {
901 struct modem_socket *sock;
902 int sockfd, state;
903
904 sockfd = atoi(argv[0]);
905 state = atoi(argv[1]);
906
907 sock = modem_socket_from_fd(&mdata.socket_config, sockfd);
908 if (!sock) {
909 return 0;
910 }
911
912 /* Only continue if socket was closed. */
913 if (state != 0) {
914 return 0;
915 }
916
917 LOG_INF("Socket close indication for socket: %d", sockfd);
918
919 sock->is_connected = false;
920 LOG_INF("Socket closed: %d", sockfd);
921
922 return 0;
923 }
924
925 /**
926 * Handles the ftpget urc.
927 *
928 * +FTPGET: <mode>,<error>
929 *
930 * Mode can be 1 for opening a session and
931 * reporting that data is available or 2 for
932 * reading data. This urc handler will only handle
933 * mode 1 because 2 will not occur as urc.
934 *
935 * Error can be either:
936 * - 1 for data available/opened session.
937 * - 0 If transfer is finished.
938 * - >0 for some error.
939 */
MODEM_CMD_DEFINE(on_urc_ftpget)940 MODEM_CMD_DEFINE(on_urc_ftpget)
941 {
942 int error = atoi(argv[0]);
943
944 LOG_INF("+FTPGET: 1,%d", error);
945
946 /* Transfer finished. */
947 if (error == 0) {
948 mdata.ftp.state = SIM7080_FTP_CONNECTION_STATE_FINISHED;
949 } else if (error == 1) {
950 mdata.ftp.state = SIM7080_FTP_CONNECTION_STATE_CONNECTED;
951 } else {
952 mdata.ftp.state = SIM7080_FTP_CONNECTION_STATE_ERROR;
953 }
954
955 k_sem_give(&mdata.sem_ftp);
956
957 return 0;
958 }
959
960 /*
961 * Read manufacturer identification.
962 */
MODEM_CMD_DEFINE(on_cmd_cgmi)963 MODEM_CMD_DEFINE(on_cmd_cgmi)
964 {
965 size_t out_len = net_buf_linearize(
966 mdata.mdm_manufacturer, sizeof(mdata.mdm_manufacturer) - 1, data->rx_buf, 0, len);
967 mdata.mdm_manufacturer[out_len] = '\0';
968 LOG_INF("Manufacturer: %s", mdata.mdm_manufacturer);
969 return 0;
970 }
971
972 /*
973 * Read model identification.
974 */
MODEM_CMD_DEFINE(on_cmd_cgmm)975 MODEM_CMD_DEFINE(on_cmd_cgmm)
976 {
977 size_t out_len = net_buf_linearize(mdata.mdm_model, sizeof(mdata.mdm_model) - 1,
978 data->rx_buf, 0, len);
979 mdata.mdm_model[out_len] = '\0';
980 LOG_INF("Model: %s", mdata.mdm_model);
981 return 0;
982 }
983
984 /*
985 * Read software release.
986 *
987 * Response will be in format RESPONSE: <revision>.
988 */
MODEM_CMD_DEFINE(on_cmd_cgmr)989 MODEM_CMD_DEFINE(on_cmd_cgmr)
990 {
991 size_t out_len;
992 char *p;
993
994 out_len = net_buf_linearize(mdata.mdm_revision, sizeof(mdata.mdm_revision) - 1,
995 data->rx_buf, 0, len);
996 mdata.mdm_revision[out_len] = '\0';
997
998 /* The module prepends a Revision: */
999 p = strchr(mdata.mdm_revision, ':');
1000 if (p) {
1001 out_len = strlen(p + 1);
1002 memmove(mdata.mdm_revision, p + 1, out_len + 1);
1003 }
1004
1005 LOG_INF("Revision: %s", mdata.mdm_revision);
1006 return 0;
1007 }
1008
1009 /*
1010 * Read serial number identification.
1011 */
MODEM_CMD_DEFINE(on_cmd_cgsn)1012 MODEM_CMD_DEFINE(on_cmd_cgsn)
1013 {
1014 size_t out_len =
1015 net_buf_linearize(mdata.mdm_imei, sizeof(mdata.mdm_imei) - 1, data->rx_buf, 0, len);
1016 mdata.mdm_imei[out_len] = '\0';
1017 LOG_INF("IMEI: %s", mdata.mdm_imei);
1018 return 0;
1019 }
1020
1021 #if defined(CONFIG_MODEM_SIM_NUMBERS)
1022 /*
1023 * Read international mobile subscriber identity.
1024 */
MODEM_CMD_DEFINE(on_cmd_cimi)1025 MODEM_CMD_DEFINE(on_cmd_cimi)
1026 {
1027 size_t out_len =
1028 net_buf_linearize(mdata.mdm_imsi, sizeof(mdata.mdm_imsi) - 1, data->rx_buf, 0, len);
1029 mdata.mdm_imsi[out_len] = '\0';
1030
1031 /* Log the received information. */
1032 LOG_INF("IMSI: %s", mdata.mdm_imsi);
1033 return 0;
1034 }
1035
1036 /*
1037 * Read iccid.
1038 */
MODEM_CMD_DEFINE(on_cmd_ccid)1039 MODEM_CMD_DEFINE(on_cmd_ccid)
1040 {
1041 size_t out_len = net_buf_linearize(mdata.mdm_iccid, sizeof(mdata.mdm_iccid) - 1,
1042 data->rx_buf, 0, len);
1043 mdata.mdm_iccid[out_len] = '\0';
1044
1045 /* Log the received information. */
1046 LOG_INF("ICCID: %s", mdata.mdm_iccid);
1047 return 0;
1048 }
1049 #endif /* defined(CONFIG_MODEM_SIM_NUMBERS) */
1050
1051 /*
1052 * Parses the non urc C(E)REG and updates registration status.
1053 */
MODEM_CMD_DEFINE(on_cmd_cereg)1054 MODEM_CMD_DEFINE(on_cmd_cereg)
1055 {
1056 mdata.mdm_registration = atoi(argv[1]);
1057 LOG_INF("CREG: %u", mdata.mdm_registration);
1058 return 0;
1059 }
1060
MODEM_CMD_DEFINE(on_cmd_cpin)1061 MODEM_CMD_DEFINE(on_cmd_cpin)
1062 {
1063 mdata.cpin_ready = strcmp(argv[0], "READY") == 0;
1064 LOG_INF("CPIN: %d", mdata.cpin_ready);
1065 return 0;
1066 }
1067
MODEM_CMD_DEFINE(on_cmd_cgatt)1068 MODEM_CMD_DEFINE(on_cmd_cgatt)
1069 {
1070 mdata.mdm_cgatt = atoi(argv[0]);
1071 LOG_INF("CGATT: %d", mdata.mdm_cgatt);
1072 return 0;
1073 }
1074
1075 /*
1076 * Handler for RSSI query.
1077 *
1078 * +CSQ: <rssi>,<ber>
1079 * rssi: 0,-115dBm; 1,-111dBm; 2...30,-110...-54dBm; 31,-52dBm or greater.
1080 * 99, ukn
1081 * ber: Not used.
1082 */
MODEM_CMD_DEFINE(on_cmd_csq)1083 MODEM_CMD_DEFINE(on_cmd_csq)
1084 {
1085 int rssi = atoi(argv[0]);
1086
1087 if (rssi == 0) {
1088 mdata.mdm_rssi = -115;
1089 } else if (rssi == 1) {
1090 mdata.mdm_rssi = -111;
1091 } else if (rssi > 1 && rssi < 31) {
1092 mdata.mdm_rssi = -114 + 2 * rssi;
1093 } else if (rssi == 31) {
1094 mdata.mdm_rssi = -52;
1095 } else {
1096 mdata.mdm_rssi = -1000;
1097 }
1098
1099 LOG_INF("RSSI: %d", mdata.mdm_rssi);
1100 return 0;
1101 }
1102
1103 /*
1104 * Queries modem RSSI.
1105 *
1106 * If a work queue parameter is provided query work will
1107 * be scheduled. Otherwise rssi is queried once.
1108 */
modem_rssi_query_work(struct k_work * work)1109 static void modem_rssi_query_work(struct k_work *work)
1110 {
1111 struct modem_cmd cmd[] = { MODEM_CMD("+CSQ: ", on_cmd_csq, 2U, ",") };
1112 static char *send_cmd = "AT+CSQ";
1113 int ret;
1114
1115 ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, cmd, ARRAY_SIZE(cmd), send_cmd,
1116 &mdata.sem_response, MDM_CMD_TIMEOUT);
1117 if (ret < 0) {
1118 LOG_ERR("AT+CSQ ret:%d", ret);
1119 }
1120
1121 if (work) {
1122 k_work_reschedule_for_queue(&modem_workq, &mdata.rssi_query_work,
1123 K_SECONDS(RSSI_TIMEOUT_SECS));
1124 }
1125 }
1126
1127 /*
1128 * Possible responses by the sim7080.
1129 */
1130 static const struct modem_cmd response_cmds[] = {
1131 MODEM_CMD("OK", on_cmd_ok, 0U, ""),
1132 MODEM_CMD("ERROR", on_cmd_error, 0U, ""),
1133 MODEM_CMD("+CME ERROR: ", on_cmd_exterror, 1U, ""),
1134 MODEM_CMD_DIRECT(">", on_cmd_tx_ready),
1135 };
1136
1137 /*
1138 * Possible unsolicited commands.
1139 */
1140 static const struct modem_cmd unsolicited_cmds[] = {
1141 MODEM_CMD("+APP PDP: ", on_urc_app_pdp, 2U, ","),
1142 MODEM_CMD("SMS ", on_urc_sms, 1U, ""),
1143 MODEM_CMD("+CADATAIND: ", on_urc_cadataind, 1U, ""),
1144 MODEM_CMD("+CASTATE: ", on_urc_castate, 2U, ","),
1145 MODEM_CMD("+FTPGET: 1,", on_urc_ftpget, 1U, ""),
1146 };
1147
1148 /*
1149 * Activates the pdp context
1150 */
modem_pdp_activate(void)1151 static int modem_pdp_activate(void)
1152 {
1153 int counter;
1154 int ret = 0;
1155 #if defined(CONFIG_MODEM_SIMCOM_SIM7080_RAT_GSM)
1156 const char *buf = "AT+CREG?";
1157 struct modem_cmd cmds[] = { MODEM_CMD("+CREG: ", on_cmd_cereg, 2U, ",") };
1158 #else
1159 const char *buf = "AT+CEREG?";
1160 struct modem_cmd cmds[] = { MODEM_CMD("+CEREG: ", on_cmd_cereg, 2U, ",") };
1161 #endif /* defined(CONFIG_MODEM_SIMCOM_SIM7080_RAT_GSM) */
1162
1163 struct modem_cmd cgatt_cmd[] = { MODEM_CMD("+CGATT: ", on_cmd_cgatt, 1U, "") };
1164
1165 counter = 0;
1166 while (counter++ < MDM_MAX_CGATT_WAITS && mdata.mdm_cgatt != 1) {
1167 ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, cgatt_cmd,
1168 ARRAY_SIZE(cgatt_cmd), "AT+CGATT?", &mdata.sem_response,
1169 MDM_CMD_TIMEOUT);
1170 if (ret < 0) {
1171 LOG_ERR("Failed to query cgatt!!");
1172 return -1;
1173 }
1174
1175 k_sleep(K_SECONDS(1));
1176 }
1177
1178 if (counter >= MDM_MAX_CGATT_WAITS) {
1179 LOG_WRN("Network attach failed!!");
1180 return -1;
1181 }
1182
1183 if (!mdata.cpin_ready || mdata.mdm_cgatt != 1) {
1184 LOG_ERR("Fatal: Modem is not attached to GPRS network!!");
1185 return -1;
1186 }
1187
1188 LOG_INF("Waiting for network");
1189
1190 /* Wait until the module is registered to the network.
1191 * Registration will be set by urc.
1192 */
1193 counter = 0;
1194 while (counter++ < MDM_MAX_CEREG_WAITS && mdata.mdm_registration != 1 &&
1195 mdata.mdm_registration != 5) {
1196 ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, cmds, ARRAY_SIZE(cmds), buf,
1197 &mdata.sem_response, MDM_CMD_TIMEOUT);
1198 if (ret < 0) {
1199 LOG_ERR("Failed to query registration!!");
1200 return -1;
1201 }
1202
1203 k_sleep(K_SECONDS(1));
1204 }
1205
1206 if (counter >= MDM_MAX_CEREG_WAITS) {
1207 LOG_WRN("Network registration failed!");
1208 ret = -1;
1209 goto error;
1210 }
1211
1212 /* Set dual stack mode (IPv4/IPv6) */
1213 ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, NULL, 0, "AT+CNCFG=0,0",
1214 &mdata.sem_response, MDM_CMD_TIMEOUT);
1215 if (ret < 0) {
1216 LOG_ERR("Could not configure pdp context!");
1217 goto error;
1218 }
1219
1220 /*
1221 * Now activate the pdp context and wait for confirmation.
1222 */
1223 ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, NULL, 0, "AT+CNACT=0,1",
1224 &mdata.sem_response, MDM_CMD_TIMEOUT);
1225 if (ret < 0) {
1226 LOG_ERR("Could not activate PDP context.");
1227 goto error;
1228 }
1229
1230 ret = k_sem_take(&mdata.sem_response, MDM_PDP_TIMEOUT);
1231 if (ret < 0 || mdata.pdp_active == false) {
1232 LOG_ERR("Failed to activate PDP context.");
1233 ret = -1;
1234 goto error;
1235 }
1236
1237 LOG_INF("Network active.");
1238
1239 error:
1240 return ret;
1241 }
1242
1243 /*
1244 * Toggles the modems power pin.
1245 */
modem_pwrkey(void)1246 static void modem_pwrkey(void)
1247 {
1248 /* Power pin should be high for 1.5 seconds. */
1249 gpio_pin_set_dt(&power_gpio, 1);
1250 k_sleep(K_MSEC(1500));
1251 gpio_pin_set_dt(&power_gpio, 0);
1252 k_sleep(K_SECONDS(5));
1253 }
1254
1255 /*
1256 * Commands to be sent at setup.
1257 */
1258 static const struct setup_cmd setup_cmds[] = {
1259 SETUP_CMD_NOHANDLE("ATH"),
1260 SETUP_CMD("AT+CGMI", "", on_cmd_cgmi, 0U, ""),
1261 SETUP_CMD("AT+CGMM", "", on_cmd_cgmm, 0U, ""),
1262 SETUP_CMD("AT+CGMR", "", on_cmd_cgmr, 0U, ""),
1263 SETUP_CMD("AT+CGSN", "", on_cmd_cgsn, 0U, ""),
1264 #if defined(CONFIG_MODEM_SIM_NUMBERS)
1265 SETUP_CMD("AT+CIMI", "", on_cmd_cimi, 0U, ""),
1266 SETUP_CMD("AT+CCID", "", on_cmd_ccid, 0U, ""),
1267 #endif /* defined(CONFIG_MODEM_SIM_NUMBERS) */
1268 #if defined(CONFIG_MODEM_SIMCOM_SIM7080_RAT_NB1)
1269 SETUP_CMD_NOHANDLE("AT+CNMP=38"),
1270 SETUP_CMD_NOHANDLE("AT+CMNB=2"),
1271 SETUP_CMD_NOHANDLE("AT+CBANDCFG=\"NB-IOT\"," MDM_LTE_BANDS),
1272 #endif /* defined(CONFIG_MODEM_SIMCOM_SIM7080_RAT_NB1) */
1273 #if defined(CONFIG_MODEM_SIMCOM_SIM7080_RAT_M1)
1274 SETUP_CMD_NOHANDLE("AT+CNMP=38"),
1275 SETUP_CMD_NOHANDLE("AT+CMNB=1"),
1276 SETUP_CMD_NOHANDLE("AT+CBANDCFG=\"CAT-M\"," MDM_LTE_BANDS),
1277 #endif /* defined(CONFIG_MODEM_SIMCOM_SIM7080_RAT_M1) */
1278 #if defined(CONFIG_MODEM_SIMCOM_SIM7080_RAT_GSM)
1279 SETUP_CMD_NOHANDLE("AT+CNMP=13"),
1280 #endif /* defined(CONFIG_MODEM_SIMCOM_SIM7080_RAT_GSM) */
1281 SETUP_CMD("AT+CPIN?", "+CPIN: ", on_cmd_cpin, 1U, ""),
1282 };
1283
1284 /**
1285 * Performs the autobaud sequence until modem answers or limit is reached.
1286 *
1287 * @return On successful boot 0 is returned. Otherwise <0 is returned.
1288 */
modem_autobaud(void)1289 static int modem_autobaud(void)
1290 {
1291 int boot_tries = 0;
1292 int counter = 0;
1293 int ret;
1294
1295 while (boot_tries++ <= MDM_BOOT_TRIES) {
1296 modem_pwrkey();
1297
1298 /*
1299 * The sim7080 has a autobaud function.
1300 * On startup multiple AT's are sent until
1301 * a OK is received.
1302 */
1303 counter = 0;
1304 while (counter < MDM_MAX_AUTOBAUD) {
1305 ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, NULL, 0U, "AT",
1306 &mdata.sem_response, K_MSEC(500));
1307
1308 /* OK was received. */
1309 if (ret == 0) {
1310 /* Disable echo */
1311 return modem_cmd_send(&mctx.iface, &mctx.cmd_handler, NULL, 0U,
1312 "ATE0", &mdata.sem_response, K_SECONDS(2));
1313 }
1314
1315 counter++;
1316 }
1317 }
1318
1319 return -1;
1320 }
1321
1322 /**
1323 * Get the next parameter from the gnss phrase.
1324 *
1325 * @param src The source string supported on first call.
1326 * @param delim The delimiter of the parameter list.
1327 * @param saveptr Pointer for subsequent parses.
1328 * @return On success a pointer to the parameter. On failure
1329 * or end of string NULL is returned.
1330 *
1331 * This function is used instead of strtok because strtok would
1332 * skip empty parameters, which is not desired. The modem may
1333 * omit parameters which could lead to a incorrect parse.
1334 */
gnss_get_next_param(char * src,const char * delim,char ** saveptr)1335 static char *gnss_get_next_param(char *src, const char *delim, char **saveptr)
1336 {
1337 char *start, *del;
1338
1339 if (src) {
1340 start = src;
1341 } else {
1342 start = *saveptr;
1343 }
1344
1345 /* Illegal start string. */
1346 if (!start) {
1347 return NULL;
1348 }
1349
1350 /* End of string reached. */
1351 if (*start == '\0' || *start == '\r') {
1352 return NULL;
1353 }
1354
1355 del = strstr(start, delim);
1356 if (!del) {
1357 return NULL;
1358 }
1359
1360 *del = '\0';
1361 *saveptr = del + 1;
1362
1363 if (del == start) {
1364 return NULL;
1365 }
1366
1367 return start;
1368 }
1369
gnss_skip_param(char ** saveptr)1370 static void gnss_skip_param(char **saveptr)
1371 {
1372 gnss_get_next_param(NULL, ",", saveptr);
1373 }
1374
1375 /**
1376 * Splits float parameters of the CGNSINF response on '.'
1377 *
1378 * @param src Null terminated string containing the float.
1379 * @param f1 Resulting number part of the float.
1380 * @param f2 Resulting fraction part of the float.
1381 * @return 0 if parsing was successful. Otherwise <0 is returned.
1382 *
1383 * If the number part of the float is negative f1 and f2 will be
1384 * negative too.
1385 */
gnss_split_on_dot(const char * src,int32_t * f1,int32_t * f2)1386 static int gnss_split_on_dot(const char *src, int32_t *f1, int32_t *f2)
1387 {
1388 char *dot = strchr(src, '.');
1389
1390 if (!dot) {
1391 return -1;
1392 }
1393
1394 *dot = '\0';
1395
1396 *f1 = (int32_t)strtol(src, NULL, 10);
1397 *f2 = (int32_t)strtol(dot + 1, NULL, 10);
1398
1399 if (*f1 < 0) {
1400 *f2 = -*f2;
1401 }
1402
1403 return 0;
1404 }
1405
1406 /**
1407 * Parses cgnsinf response into the gnss_data structure.
1408 *
1409 * @param gps_buf Null terminated buffer containing the response.
1410 * @return 0 on successful parse. Otherwise <0 is returned.
1411 */
parse_cgnsinf(char * gps_buf)1412 static int parse_cgnsinf(char *gps_buf)
1413 {
1414 char *saveptr;
1415 int ret;
1416 int32_t number, fraction;
1417
1418 char *run_status = gnss_get_next_param(gps_buf, ",", &saveptr);
1419
1420 if (run_status == NULL) {
1421 goto error;
1422 } else if (*run_status != '1') {
1423 goto error;
1424 }
1425
1426 char *fix_status = gnss_get_next_param(NULL, ",", &saveptr);
1427
1428 if (fix_status == NULL) {
1429 goto error;
1430 } else if (*fix_status != '1') {
1431 goto error;
1432 }
1433
1434 char *utc = gnss_get_next_param(NULL, ",", &saveptr);
1435
1436 if (utc == NULL) {
1437 goto error;
1438 }
1439
1440 char *lat = gnss_get_next_param(NULL, ",", &saveptr);
1441
1442 if (lat == NULL) {
1443 goto error;
1444 }
1445
1446 char *lon = gnss_get_next_param(NULL, ",", &saveptr);
1447
1448 if (lon == NULL) {
1449 goto error;
1450 }
1451
1452 char *alt = gnss_get_next_param(NULL, ",", &saveptr);
1453 char *speed = gnss_get_next_param(NULL, ",", &saveptr);
1454 char *course = gnss_get_next_param(NULL, ",", &saveptr);
1455
1456 /* discard fix mode and reserved*/
1457 gnss_skip_param(&saveptr);
1458 gnss_skip_param(&saveptr);
1459
1460 char *hdop = gnss_get_next_param(NULL, ",", &saveptr);
1461
1462 if (hdop == NULL) {
1463 goto error;
1464 }
1465
1466 gnss_data.run_status = 1;
1467 gnss_data.fix_status = 1;
1468
1469 strncpy(gnss_data.utc, utc, sizeof(gnss_data.utc) - 1);
1470
1471 ret = gnss_split_on_dot(lat, &number, &fraction);
1472 if (ret != 0) {
1473 goto error;
1474 }
1475 gnss_data.lat = number * 10000000 + fraction * 10;
1476
1477 ret = gnss_split_on_dot(lon, &number, &fraction);
1478 if (ret != 0) {
1479 goto error;
1480 }
1481 gnss_data.lon = number * 10000000 + fraction * 10;
1482
1483 if (alt) {
1484 ret = gnss_split_on_dot(alt, &number, &fraction);
1485 if (ret != 0) {
1486 goto error;
1487 }
1488 gnss_data.alt = number * 1000 + fraction;
1489 } else {
1490 gnss_data.alt = 0;
1491 }
1492
1493 ret = gnss_split_on_dot(hdop, &number, &fraction);
1494 if (ret != 0) {
1495 goto error;
1496 }
1497 gnss_data.hdop = number * 100 + fraction * 10;
1498
1499 if (course) {
1500 ret = gnss_split_on_dot(course, &number, &fraction);
1501 if (ret != 0) {
1502 goto error;
1503 }
1504 gnss_data.cog = number * 100 + fraction * 10;
1505 } else {
1506 gnss_data.cog = 0;
1507 }
1508
1509 if (speed) {
1510 ret = gnss_split_on_dot(speed, &number, &fraction);
1511 if (ret != 0) {
1512 goto error;
1513 }
1514 gnss_data.kmh = number * 10 + fraction / 10;
1515 } else {
1516 gnss_data.kmh = 0;
1517 }
1518
1519 return 0;
1520 error:
1521 memset(&gnss_data, 0, sizeof(gnss_data));
1522 return -1;
1523 }
1524
1525 /*
1526 * Parses the +CGNSINF Gnss response.
1527 *
1528 * The CGNSINF command has the following parameters but
1529 * not all parameters are set by the module:
1530 *
1531 * +CGNSINF: <GNSS run status>,<Fix status>,<UTC date & Time>,
1532 * <Latitude>,<Longitude>,<MSL Altitude>,<Speed Over Ground>,
1533 * <Course Over Ground>,<Fix Mode>,<Reserved1>,<HDOP>,<PDOP>,
1534 * <VDOP>,<Reserved2>,<GNSS Satellites in View>,<Reserved3>,
1535 * <HPA>,<VPA>
1536 *
1537 */
MODEM_CMD_DEFINE(on_cmd_cgnsinf)1538 MODEM_CMD_DEFINE(on_cmd_cgnsinf)
1539 {
1540 char gps_buf[MDM_GNSS_PARSER_MAX_LEN];
1541 size_t out_len = net_buf_linearize(gps_buf, sizeof(gps_buf) - 1, data->rx_buf, 0, len);
1542
1543 gps_buf[out_len] = '\0';
1544 return parse_cgnsinf(gps_buf);
1545 }
1546
mdm_sim7080_query_gnss(struct sim7080_gnss_data * data)1547 int mdm_sim7080_query_gnss(struct sim7080_gnss_data *data)
1548 {
1549 int ret;
1550 struct modem_cmd cmds[] = { MODEM_CMD("+CGNSINF: ", on_cmd_cgnsinf, 0U, NULL) };
1551
1552 if (get_state() != SIM7080_STATE_GNSS) {
1553 LOG_ERR("GNSS functionality is not enabled!!");
1554 return -1;
1555 }
1556
1557 ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, cmds, ARRAY_SIZE(cmds), "AT+CGNSINF",
1558 &mdata.sem_response, K_SECONDS(2));
1559 if (ret < 0) {
1560 return ret;
1561 }
1562
1563 if (!gnss_data.run_status || !gnss_data.fix_status) {
1564 return -EAGAIN;
1565 }
1566
1567 if (data) {
1568 memcpy(data, &gnss_data, sizeof(gnss_data));
1569 }
1570
1571 memset(&gnss_data, 0, sizeof(gnss_data));
1572
1573 return ret;
1574 }
1575
mdm_sim7080_start_gnss(void)1576 int mdm_sim7080_start_gnss(void)
1577 {
1578 int ret;
1579
1580 change_state(SIM7080_STATE_INIT);
1581 k_work_cancel_delayable(&mdata.rssi_query_work);
1582
1583 ret = modem_autobaud();
1584 if (ret < 0) {
1585 LOG_ERR("Failed to start modem!!");
1586 return -1;
1587 }
1588
1589 ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, NULL, 0U, "AT+CGNSCOLD",
1590 &mdata.sem_response, K_SECONDS(2));
1591 if (ret < 0) {
1592 return -1;
1593 }
1594
1595 change_state(SIM7080_STATE_GNSS);
1596 return 0;
1597 }
1598
1599 /**
1600 * Parse the +FTPGET response.
1601 *
1602 * +FTPGET: <mode>,<len>
1603 *
1604 * Mode is hard set to 2.
1605 *
1606 * Length is the number of bytes following (the ftp data).
1607 */
MODEM_CMD_DEFINE(on_cmd_ftpget)1608 MODEM_CMD_DEFINE(on_cmd_ftpget)
1609 {
1610 int nbytes = atoi(argv[0]);
1611 int bytes_to_skip;
1612 size_t out_len;
1613
1614 if (nbytes == 0) {
1615 mdata.ftp.nread = 0;
1616 return 0;
1617 }
1618
1619 /* Skip length parameter and trailing \r\n */
1620 bytes_to_skip = strlen(argv[0]) + 2;
1621
1622 /* Wait until data is ready.
1623 * >= to ensure buffer is not empty after skip.
1624 */
1625 if (net_buf_frags_len(data->rx_buf) <= nbytes + bytes_to_skip) {
1626 return -EAGAIN;
1627 }
1628
1629 out_len = net_buf_linearize(mdata.ftp.read_buffer, mdata.ftp.nread, data->rx_buf,
1630 bytes_to_skip, nbytes);
1631 if (out_len != nbytes) {
1632 LOG_WRN("FTP read size differs!");
1633 }
1634 data->rx_buf = net_buf_skip(data->rx_buf, nbytes + bytes_to_skip);
1635
1636 mdata.ftp.nread = nbytes;
1637
1638 return 0;
1639 }
1640
mdm_sim7080_ftp_get_read(char * dst,size_t * size)1641 int mdm_sim7080_ftp_get_read(char *dst, size_t *size)
1642 {
1643 int ret;
1644 char buffer[sizeof("AT+FTPGET=#,######")];
1645 struct modem_cmd cmds[] = { MODEM_CMD("+FTPGET: 2,", on_cmd_ftpget, 1U, "") };
1646
1647 /* Some error occurred. */
1648 if (mdata.ftp.state == SIM7080_FTP_CONNECTION_STATE_ERROR ||
1649 mdata.ftp.state == SIM7080_FTP_CONNECTION_STATE_INITIAL) {
1650 return SIM7080_FTP_RC_ERROR;
1651 }
1652
1653 /* Setup buffer. */
1654 mdata.ftp.read_buffer = dst;
1655 mdata.ftp.nread = *size;
1656
1657 /* Read ftp data. */
1658 ret = snprintk(buffer, sizeof(buffer), "AT+FTPGET=2,%zu", *size);
1659 if (ret < 0) {
1660 *size = 0;
1661 return SIM7080_FTP_RC_ERROR;
1662 }
1663
1664 /* Wait for data from the server. */
1665 k_sem_take(&mdata.sem_ftp, K_MSEC(200));
1666
1667 if (mdata.ftp.state == SIM7080_FTP_CONNECTION_STATE_FINISHED) {
1668 *size = 0;
1669 return SIM7080_FTP_RC_FINISHED;
1670 } else if (mdata.ftp.state == SIM7080_FTP_CONNECTION_STATE_ERROR) {
1671 *size = 0;
1672 return SIM7080_FTP_RC_ERROR;
1673 }
1674
1675 ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, cmds, ARRAY_SIZE(cmds), buffer,
1676 &mdata.sem_response, MDM_CMD_TIMEOUT);
1677 if (ret < 0) {
1678 *size = 0;
1679 return SIM7080_FTP_RC_ERROR;
1680 }
1681
1682 /* Set read size. */
1683 *size = mdata.ftp.nread;
1684
1685 return SIM7080_FTP_RC_OK;
1686 }
1687
mdm_sim7080_ftp_get_start(const char * server,const char * user,const char * passwd,const char * file,const char * path)1688 int mdm_sim7080_ftp_get_start(const char *server, const char *user, const char *passwd,
1689 const char *file, const char *path)
1690 {
1691 int ret;
1692 char buffer[256];
1693
1694 /* Start network. */
1695 ret = mdm_sim7080_start_network();
1696 if (ret < 0) {
1697 LOG_ERR("Failed to start network for FTP!");
1698 return -1;
1699 }
1700
1701 /* Set connection id for ftp. */
1702 ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, NULL, 0U, "AT+FTPCID=0",
1703 &mdata.sem_response, MDM_CMD_TIMEOUT);
1704 if (ret < 0) {
1705 LOG_WRN("Failed to set FTP Cid!");
1706 return -1;
1707 }
1708
1709 /* Set ftp server. */
1710 ret = snprintk(buffer, sizeof(buffer), "AT+FTPSERV=\"%s\"", server);
1711 if (ret < 0) {
1712 LOG_WRN("Failed to build command!");
1713 return -1;
1714 }
1715
1716 ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, NULL, 0U, buffer, &mdata.sem_response,
1717 MDM_CMD_TIMEOUT);
1718 if (ret < 0) {
1719 LOG_WRN("Failed to set FTP Cid!");
1720 return -1;
1721 }
1722
1723 /* Set ftp user. */
1724 ret = snprintk(buffer, sizeof(buffer), "AT+FTPUN=\"%s\"", user);
1725 if (ret < 0) {
1726 LOG_WRN("Failed to build command!");
1727 return -1;
1728 }
1729
1730 ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, NULL, 0U, buffer, &mdata.sem_response,
1731 MDM_CMD_TIMEOUT);
1732 if (ret < 0) {
1733 LOG_WRN("Failed to set ftp user!");
1734 return -1;
1735 }
1736
1737 /* Set ftp password. */
1738 ret = snprintk(buffer, sizeof(buffer), "AT+FTPPW=\"%s\"", passwd);
1739 if (ret < 0) {
1740 LOG_WRN("Failed to build command!");
1741 return -1;
1742 }
1743
1744 ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, NULL, 0U, buffer, &mdata.sem_response,
1745 MDM_CMD_TIMEOUT);
1746 if (ret < 0) {
1747 LOG_WRN("Failed to set ftp password!");
1748 return -1;
1749 }
1750
1751 /* Set ftp filename. */
1752 ret = snprintk(buffer, sizeof(buffer), "AT+FTPGETNAME=\"%s\"", file);
1753 if (ret < 0) {
1754 LOG_WRN("Failed to build command!");
1755 return -1;
1756 }
1757
1758 ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, NULL, 0U, buffer, &mdata.sem_response,
1759 MDM_CMD_TIMEOUT);
1760 if (ret < 0) {
1761 LOG_WRN("Failed to set ftp filename!");
1762 return -1;
1763 }
1764
1765 /* Set ftp filename. */
1766 ret = snprintk(buffer, sizeof(buffer), "AT+FTPGETNAME=\"%s\"", file);
1767 if (ret < 0) {
1768 LOG_WRN("Failed to build command!");
1769 return -1;
1770 }
1771
1772 ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, NULL, 0U, buffer, &mdata.sem_response,
1773 MDM_CMD_TIMEOUT);
1774 if (ret < 0) {
1775 LOG_WRN("Failed to set ftp filename!");
1776 return -1;
1777 }
1778
1779 /* Set ftp path. */
1780 ret = snprintk(buffer, sizeof(buffer), "AT+FTPGETPATH=\"%s\"", path);
1781 if (ret < 0) {
1782 LOG_WRN("Failed to build command!");
1783 return -1;
1784 }
1785
1786 ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, NULL, 0U, buffer, &mdata.sem_response,
1787 MDM_CMD_TIMEOUT);
1788 if (ret < 0) {
1789 LOG_WRN("Failed to set ftp path!");
1790 return -1;
1791 }
1792
1793 /* Initialize ftp variables. */
1794 mdata.ftp.read_buffer = NULL;
1795 mdata.ftp.nread = 0;
1796 mdata.ftp.state = SIM7080_FTP_CONNECTION_STATE_INITIAL;
1797
1798 /* Start the ftp session. */
1799 ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, NULL, 0U, "AT+FTPGET=1",
1800 &mdata.sem_ftp, MDM_CMD_TIMEOUT);
1801 if (ret < 0) {
1802 LOG_WRN("Failed to start session!");
1803 return -1;
1804 }
1805
1806 if (mdata.ftp.state != SIM7080_FTP_CONNECTION_STATE_CONNECTED) {
1807 LOG_WRN("Session state is not connected!");
1808 return -1;
1809 }
1810
1811 return 0;
1812 }
1813
1814 /**
1815 * Decode readable hex to "real" hex.
1816 */
mdm_pdu_decode_ascii(char byte)1817 static uint8_t mdm_pdu_decode_ascii(char byte)
1818 {
1819 if ((byte >= '0') && (byte <= '9')) {
1820 return byte - '0';
1821 } else if ((byte >= 'A') && (byte <= 'F')) {
1822 return byte - 'A' + 10;
1823 } else if ((byte >= 'a') && (byte <= 'f')) {
1824 return byte - 'a' + 10;
1825 } else {
1826 return 255;
1827 }
1828 }
1829
1830 /**
1831 * Reads "byte" from pdu.
1832 *
1833 * @param pdu pdu to read from.
1834 * @param index index of "byte".
1835 *
1836 * Sim module "encodes" one pdu byte as two human readable bytes
1837 * this functions squashes these two bytes into one.
1838 */
mdm_pdu_read_byte(const char * pdu,size_t index)1839 static uint8_t mdm_pdu_read_byte(const char *pdu, size_t index)
1840 {
1841 return (mdm_pdu_decode_ascii(pdu[index * 2]) << 4 |
1842 mdm_pdu_decode_ascii(pdu[index * 2 + 1]));
1843 }
1844
1845 /**
1846 * Decodes time from pdu.
1847 *
1848 * @param pdu pdu to read from.
1849 * @param index index of "byte".
1850 */
mdm_pdu_read_time(const char * pdu,size_t index)1851 static uint8_t mdm_pdu_read_time(const char *pdu, size_t index)
1852 {
1853 return (mdm_pdu_decode_ascii(pdu[index * 2]) +
1854 mdm_pdu_decode_ascii(pdu[index * 2 + 1]) * 10);
1855 }
1856
1857 /**
1858 * Decode a sms from pdu mode.
1859 */
mdm_decode_pdu(const char * pdu,size_t pdu_len,struct sim7080_sms * target_buf)1860 static int mdm_decode_pdu(const char *pdu, size_t pdu_len, struct sim7080_sms *target_buf)
1861 {
1862 size_t index;
1863
1864 /*
1865 * GSM_03.38 to Unicode conversion table
1866 */
1867 const short enc7_basic[128] = {
1868 '@', 0xA3, '$', 0xA5, 0xE8, 0xE9, 0xF9, 0xEC, 0xF2, 0xE7,
1869 '\n', 0xD8, 0xF8, '\r', 0xC5, 0xF8, 0x0394, '_', 0x03A6, 0x0393,
1870 0x039B, 0x03A9, 0x03A0, 0x03A8, 0x03A3, 0x0398, 0x039E, '\x1b', 0xC6, 0xE6,
1871 0xDF, 0xC9, ' ', '!', '\"', '#', 0xA4, '%', '&', '\'',
1872 '(', ')', '*', '+', ',', '-', '.', '/', '0', '1',
1873 '2', '3', '4', '5', '6', '7', '8', '9', ':', ';',
1874 '<', '=', '>', '?', 0xA1, 'A', 'B', 'C', 'D', 'E',
1875 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
1876 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y',
1877 'Z', 0xC4, 0xD6, 0xD1, 0xDC, 0xA7, 0xBF, 'a', 'b', 'c',
1878 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
1879 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
1880 'x', 'y', 'z', 0xE4, 0xF6, 0xF1, 0xFC, 0xE0
1881 };
1882
1883 /* two bytes in pdu are on real byte */
1884 pdu_len = (pdu_len / 2);
1885
1886 /* first byte of pdu is length of trailing SMSC information
1887 * skip it by setting index to SMSC length + 1.
1888 */
1889 index = mdm_pdu_read_byte(pdu, 0) + 1;
1890
1891 if (index >= pdu_len) {
1892 return -1;
1893 }
1894
1895 /* read first octet */
1896 target_buf->first_octet = mdm_pdu_read_byte(pdu, index++);
1897
1898 if (index >= pdu_len) {
1899 return -1;
1900 }
1901
1902 /* pdu_index now points to the address field.
1903 * first byte of addr field is the addr length -> skip it.
1904 * address type is not included in addr len -> add +1.
1905 * address is coded in semi octets
1906 * + addr_len/2 if even
1907 * + addr_len/2 + 1 if odd
1908 */
1909 uint8_t addr_len = mdm_pdu_read_byte(pdu, index);
1910
1911 index += ((addr_len % 2) == 0) ? (addr_len / 2) + 2 : (addr_len / 2) + 3;
1912
1913 if (index >= pdu_len) {
1914 return -1;
1915 }
1916
1917 /* read protocol identifier */
1918 target_buf->tp_pid = mdm_pdu_read_byte(pdu, index++);
1919
1920 if (index >= pdu_len) {
1921 return -1;
1922 }
1923
1924 /* read coding scheme */
1925 uint8_t tp_dcs = mdm_pdu_read_byte(pdu, index++);
1926
1927 /* parse date and time */
1928 if ((index + 7) >= pdu_len) {
1929 return -1;
1930 }
1931
1932 target_buf->time.year = mdm_pdu_read_time(pdu, index++);
1933 target_buf->time.month = mdm_pdu_read_time(pdu, index++);
1934 target_buf->time.day = mdm_pdu_read_time(pdu, index++);
1935 target_buf->time.hour = mdm_pdu_read_time(pdu, index++);
1936 target_buf->time.minute = mdm_pdu_read_time(pdu, index++);
1937 target_buf->time.second = mdm_pdu_read_time(pdu, index++);
1938 target_buf->time.timezone = mdm_pdu_read_time(pdu, index++);
1939
1940 /* Read user data length */
1941 uint8_t tp_udl = mdm_pdu_read_byte(pdu, index++);
1942
1943 /* Discard header */
1944 uint8_t header_skip = 0;
1945
1946 if (target_buf->first_octet & SMS_TP_UDHI_HEADER) {
1947 uint8_t tp_udhl = mdm_pdu_read_byte(pdu, index);
1948
1949 index += tp_udhl + 1;
1950 header_skip = tp_udhl + 1;
1951
1952 if (index >= pdu_len) {
1953 return -1;
1954 }
1955 }
1956
1957 /* Read data according to type set in TP-DCS */
1958 if (tp_dcs == 0x00) {
1959 /* 7 bit GSM coding */
1960 uint8_t fill_level = 0;
1961 uint16_t buf = 0;
1962
1963 if (target_buf->first_octet & SMS_TP_UDHI_HEADER) {
1964 /* Initial fill because septets are aligned to
1965 * septet boundary after header
1966 */
1967 uint8_t fill_bits = 7 - ((header_skip * 8) % 7);
1968
1969 if (fill_bits == 7) {
1970 fill_bits = 0;
1971 }
1972
1973 buf = mdm_pdu_read_byte(pdu, index++);
1974
1975 fill_level = 8 - fill_bits;
1976 }
1977
1978 uint16_t data_index = 0;
1979
1980 for (unsigned int idx = 0; idx < tp_udl; idx++) {
1981 if (fill_level < 7) {
1982 uint8_t octet = mdm_pdu_read_byte(pdu, index++);
1983
1984 buf &= ((1 << fill_level) - 1);
1985 buf |= (octet << fill_level);
1986 fill_level += 8;
1987 }
1988
1989 /*
1990 * Convert 7-bit encoded data to Unicode and
1991 * then to UTF-8
1992 */
1993 short letter = enc7_basic[buf & 0x007f];
1994
1995 if (letter < 0x0080) {
1996 target_buf->data[data_index++] = letter & 0x007f;
1997 } else if (letter < 0x0800) {
1998 target_buf->data[data_index++] = 0xc0 | ((letter & 0x07c0) >> 6);
1999 target_buf->data[data_index++] = 0x80 | ((letter & 0x003f) >> 0);
2000 }
2001 buf >>= 7;
2002 fill_level -= 7;
2003 }
2004 target_buf->data_len = data_index;
2005 } else if (tp_dcs == 0x04) {
2006 /* 8 bit binary coding */
2007 for (int idx = 0; idx < tp_udl - header_skip; idx++) {
2008 target_buf->data[idx] = mdm_pdu_read_byte(pdu, index++);
2009 }
2010 target_buf->data_len = tp_udl;
2011 } else if (tp_dcs == 0x08) {
2012 /* Unicode (16 bit per character) */
2013 for (int idx = 0; idx < tp_udl - header_skip; idx++) {
2014 target_buf->data[idx] = mdm_pdu_read_byte(pdu, index++);
2015 }
2016 target_buf->data_len = tp_udl;
2017 } else {
2018 return -1;
2019 }
2020
2021 return 0;
2022 }
2023
2024 /**
2025 * Check if given char sequence is crlf.
2026 *
2027 * @param c The char sequence.
2028 * @param len Total length of the fragment.
2029 * @return @c true if char sequence is crlf.
2030 * Otherwise @c false is returned.
2031 */
is_crlf(uint8_t * c,uint8_t len)2032 static bool is_crlf(uint8_t *c, uint8_t len)
2033 {
2034 /* crlf does not fit. */
2035 if (len < 2) {
2036 return false;
2037 }
2038
2039 return c[0] == '\r' && c[1] == '\n';
2040 }
2041
2042 /**
2043 * Find terminating crlf in a netbuffer.
2044 *
2045 * @param buf The netbuffer.
2046 * @param skip Bytes to skip before search.
2047 * @return Length of the returned fragment or 0 if not found.
2048 */
net_buf_find_crlf(struct net_buf * buf,size_t skip)2049 static size_t net_buf_find_crlf(struct net_buf *buf, size_t skip)
2050 {
2051 size_t len = 0, pos = 0;
2052 struct net_buf *frag = buf;
2053
2054 /* Skip to the start. */
2055 while (frag && skip >= frag->len) {
2056 skip -= frag->len;
2057 frag = frag->frags;
2058 }
2059
2060 /* Need to wait for more data. */
2061 if (!frag) {
2062 return 0;
2063 }
2064
2065 pos = skip;
2066
2067 while (frag && !is_crlf(frag->data + pos, frag->len - pos)) {
2068 if (pos + 1 >= frag->len) {
2069 len += frag->len;
2070 frag = frag->frags;
2071 pos = 0U;
2072 } else {
2073 pos++;
2074 }
2075 }
2076
2077 if (frag && is_crlf(frag->data + pos, frag->len - pos)) {
2078 len += pos;
2079 return len - skip;
2080 }
2081
2082 return 0;
2083 }
2084
2085 /**
2086 * Parses list sms and add them to buffer.
2087 * Format is:
2088 *
2089 * +CMGL: <index>,<stat>,,<length><CR><LF><pdu><CR><LF>
2090 * +CMGL: <index>,<stat>,,<length><CR><LF><pdu><CR><LF>
2091 * ...
2092 * OK
2093 */
MODEM_CMD_DEFINE(on_cmd_cmgl)2094 MODEM_CMD_DEFINE(on_cmd_cmgl)
2095 {
2096 int sms_index, sms_stat, ret;
2097 char pdu_buffer[256];
2098 size_t out_len, sms_len, param_len;
2099 struct sim7080_sms *sms;
2100
2101 sms_index = atoi(argv[0]);
2102 sms_stat = atoi(argv[1]);
2103
2104 /* Get the length of the "length" parameter.
2105 * The last parameter will be stuck in the netbuffer.
2106 * It is not the actual length of the trailing pdu so
2107 * we have to search the next crlf.
2108 */
2109 param_len = net_buf_find_crlf(data->rx_buf, 0);
2110 if (param_len == 0) {
2111 LOG_INF("No <CR><LF>");
2112 return -EAGAIN;
2113 }
2114
2115 /* Get actual trailing pdu len. +2 to skip crlf. */
2116 sms_len = net_buf_find_crlf(data->rx_buf, param_len + 2);
2117 if (sms_len == 0) {
2118 return -EAGAIN;
2119 }
2120
2121 /* Skip to start of pdu. */
2122 data->rx_buf = net_buf_skip(data->rx_buf, param_len + 2);
2123
2124 out_len = net_buf_linearize(pdu_buffer, sizeof(pdu_buffer) - 1, data->rx_buf, 0, sms_len);
2125 pdu_buffer[out_len] = '\0';
2126
2127 data->rx_buf = net_buf_skip(data->rx_buf, sms_len);
2128
2129 /* No buffer specified. */
2130 if (!mdata.sms_buffer) {
2131 return 0;
2132 }
2133
2134 /* No space left in buffer. */
2135 if (mdata.sms_buffer_pos >= mdata.sms_buffer->nsms) {
2136 return 0;
2137 }
2138
2139 sms = &mdata.sms_buffer->sms[mdata.sms_buffer_pos];
2140
2141 ret = mdm_decode_pdu(pdu_buffer, out_len, sms);
2142 if (ret < 0) {
2143 return 0;
2144 }
2145
2146 sms->stat = sms_stat;
2147 sms->index = sms_index;
2148 sms->data[sms->data_len] = '\0';
2149
2150 mdata.sms_buffer_pos++;
2151
2152 return 0;
2153 }
2154
mdm_sim7080_read_sms(struct sim7080_sms_buffer * buffer)2155 int mdm_sim7080_read_sms(struct sim7080_sms_buffer *buffer)
2156 {
2157 int ret;
2158 struct modem_cmd cmds[] = { MODEM_CMD("+CMGL: ", on_cmd_cmgl, 4U, ",\r") };
2159
2160 mdata.sms_buffer = buffer;
2161 mdata.sms_buffer_pos = 0;
2162
2163 ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, cmds, ARRAY_SIZE(cmds), "AT+CMGL=4",
2164 &mdata.sem_response, K_SECONDS(20));
2165 if (ret < 0) {
2166 return -1;
2167 }
2168
2169 return mdata.sms_buffer_pos;
2170 }
2171
mdm_sim7080_delete_sms(uint16_t index)2172 int mdm_sim7080_delete_sms(uint16_t index)
2173 {
2174 int ret;
2175 char buf[sizeof("AT+CMGD=#####")] = { 0 };
2176
2177 ret = snprintk(buf, sizeof(buf), "AT+CMGD=%u", index);
2178 if (ret < 0) {
2179 return -1;
2180 }
2181
2182 ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, NULL, 0, buf, &mdata.sem_response,
2183 K_SECONDS(5));
2184 if (ret < 0) {
2185 return -1;
2186 }
2187
2188 return 0;
2189 }
2190
2191 /*
2192 * Does the modem setup by starting it and
2193 * bringing the modem to a PDP active state.
2194 */
modem_setup(void)2195 static int modem_setup(void)
2196 {
2197 int ret = 0;
2198 int counter = 0;
2199
2200 k_work_cancel_delayable(&mdata.rssi_query_work);
2201
2202 ret = modem_autobaud();
2203 if (ret < 0) {
2204 LOG_ERR("Booting modem failed!!");
2205 goto error;
2206 }
2207
2208 ret = modem_cmd_handler_setup_cmds(&mctx.iface, &mctx.cmd_handler, setup_cmds,
2209 ARRAY_SIZE(setup_cmds), &mdata.sem_response,
2210 MDM_REGISTRATION_TIMEOUT);
2211 if (ret < 0) {
2212 LOG_ERR("Failed to send init commands!");
2213 goto error;
2214 }
2215
2216 k_sleep(K_SECONDS(3));
2217
2218 /* Wait for acceptable rssi values. */
2219 modem_rssi_query_work(NULL);
2220 k_sleep(MDM_WAIT_FOR_RSSI_DELAY);
2221
2222 counter = 0;
2223 while (counter++ < MDM_WAIT_FOR_RSSI_COUNT &&
2224 (mdata.mdm_rssi >= 0 || mdata.mdm_rssi <= -1000)) {
2225 modem_rssi_query_work(NULL);
2226 k_sleep(MDM_WAIT_FOR_RSSI_DELAY);
2227 }
2228
2229 if (mdata.mdm_rssi >= 0 || mdata.mdm_rssi <= -1000) {
2230 LOG_ERR("Network not reachable!!");
2231 ret = -ENETUNREACH;
2232 goto error;
2233 }
2234
2235 ret = modem_pdp_activate();
2236 if (ret < 0) {
2237 goto error;
2238 }
2239
2240 k_work_reschedule_for_queue(&modem_workq, &mdata.rssi_query_work,
2241 K_SECONDS(RSSI_TIMEOUT_SECS));
2242
2243 change_state(SIM7080_STATE_NETWORKING);
2244
2245 error:
2246 return ret;
2247 }
2248
mdm_sim7080_start_network(void)2249 int mdm_sim7080_start_network(void)
2250 {
2251 change_state(SIM7080_STATE_INIT);
2252 return modem_setup();
2253 }
2254
mdm_sim7080_power_on(void)2255 int mdm_sim7080_power_on(void)
2256 {
2257 return modem_autobaud();
2258 }
2259
mdm_sim7080_power_off(void)2260 int mdm_sim7080_power_off(void)
2261 {
2262 int tries = 5;
2263 int autobaud_tries;
2264 int ret = 0;
2265
2266 k_work_cancel_delayable(&mdata.rssi_query_work);
2267
2268 /* Check if module is already off. */
2269 ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, NULL, 0U, "AT", &mdata.sem_response,
2270 K_MSEC(1000));
2271 if (ret < 0) {
2272 change_state(SIM7080_STATE_OFF);
2273 return 0;
2274 }
2275
2276 while (tries--) {
2277 modem_pwrkey();
2278
2279 autobaud_tries = 5;
2280
2281 while (autobaud_tries--) {
2282 ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, NULL, 0U, "AT",
2283 &mdata.sem_response, K_MSEC(500));
2284 if (ret == 0) {
2285 break;
2286 }
2287 }
2288
2289 if (ret < 0) {
2290 change_state(SIM7080_STATE_OFF);
2291 return 0;
2292 }
2293 }
2294
2295 return -1;
2296 }
2297
mdm_sim7080_get_manufacturer(void)2298 const char *mdm_sim7080_get_manufacturer(void)
2299 {
2300 return mdata.mdm_manufacturer;
2301 }
2302
mdm_sim7080_get_model(void)2303 const char *mdm_sim7080_get_model(void)
2304 {
2305 return mdata.mdm_model;
2306 }
2307
mdm_sim7080_get_revision(void)2308 const char *mdm_sim7080_get_revision(void)
2309 {
2310 return mdata.mdm_revision;
2311 }
2312
mdm_sim7080_get_imei(void)2313 const char *mdm_sim7080_get_imei(void)
2314 {
2315 return mdata.mdm_imei;
2316 }
2317
2318 /*
2319 * Initializes modem handlers and context.
2320 * After successful init this function calls
2321 * modem_setup.
2322 */
modem_init(const struct device * dev)2323 static int modem_init(const struct device *dev)
2324 {
2325 int ret;
2326
2327 ARG_UNUSED(dev);
2328
2329 k_sem_init(&mdata.sem_response, 0, 1);
2330 k_sem_init(&mdata.sem_tx_ready, 0, 1);
2331 k_sem_init(&mdata.sem_dns, 0, 1);
2332 k_sem_init(&mdata.sem_ftp, 0, 1);
2333 k_work_queue_start(&modem_workq, modem_workq_stack,
2334 K_KERNEL_STACK_SIZEOF(modem_workq_stack), K_PRIO_COOP(7), NULL);
2335
2336 /* Assume the modem is not registered to the network. */
2337 mdata.mdm_registration = 0;
2338 mdata.cpin_ready = false;
2339 mdata.pdp_active = false;
2340
2341 mdata.sms_buffer = NULL;
2342 mdata.sms_buffer_pos = 0;
2343
2344 /* Socket config. */
2345 ret = modem_socket_init(&mdata.socket_config, &mdata.sockets[0], ARRAY_SIZE(mdata.sockets),
2346 MDM_BASE_SOCKET_NUM, true, &offload_socket_fd_op_vtable);
2347 if (ret < 0) {
2348 goto error;
2349 }
2350
2351 change_state(SIM7080_STATE_INIT);
2352
2353 /* Command handler. */
2354 const struct modem_cmd_handler_config cmd_handler_config = {
2355 .match_buf = &mdata.cmd_match_buf[0],
2356 .match_buf_len = sizeof(mdata.cmd_match_buf),
2357 .buf_pool = &mdm_recv_pool,
2358 .alloc_timeout = BUF_ALLOC_TIMEOUT,
2359 .eol = "\r\n",
2360 .user_data = NULL,
2361 .response_cmds = response_cmds,
2362 .response_cmds_len = ARRAY_SIZE(response_cmds),
2363 .unsol_cmds = unsolicited_cmds,
2364 .unsol_cmds_len = ARRAY_SIZE(unsolicited_cmds),
2365 };
2366
2367 ret = modem_cmd_handler_init(&mctx.cmd_handler, &mdata.cmd_handler_data,
2368 &cmd_handler_config);
2369 if (ret < 0) {
2370 goto error;
2371 }
2372
2373 /* Uart handler. */
2374 const struct modem_iface_uart_config uart_config = {
2375 .rx_rb_buf = &mdata.iface_rb_buf[0],
2376 .rx_rb_buf_len = sizeof(mdata.iface_rb_buf),
2377 .dev = MDM_UART_DEV,
2378 .hw_flow_control = DT_PROP(MDM_UART_NODE, hw_flow_control),
2379 };
2380
2381 ret = modem_iface_uart_init(&mctx.iface, &mdata.iface_data, &uart_config);
2382 if (ret < 0) {
2383 goto error;
2384 }
2385
2386 mdata.current_sock_fd = -1;
2387 mdata.current_sock_written = 0;
2388
2389 mdata.ftp.read_buffer = NULL;
2390 mdata.ftp.nread = 0;
2391 mdata.ftp.state = SIM7080_FTP_CONNECTION_STATE_INITIAL;
2392
2393 /* Modem data storage. */
2394 mctx.data_manufacturer = mdata.mdm_manufacturer;
2395 mctx.data_model = mdata.mdm_model;
2396 mctx.data_revision = mdata.mdm_revision;
2397 mctx.data_imei = mdata.mdm_imei;
2398 #if defined(CONFIG_MODEM_SIM_NUMBERS)
2399 mctx.data_imsi = mdata.mdm_imsi;
2400 mctx.data_iccid = mdata.mdm_iccid;
2401 #endif /* #if defined(CONFIG_MODEM_SIM_NUMBERS) */
2402 mctx.data_rssi = &mdata.mdm_rssi;
2403
2404 ret = gpio_pin_configure_dt(&power_gpio, GPIO_OUTPUT_LOW);
2405 if (ret < 0) {
2406 LOG_ERR("Failed to configure %s pin", "power");
2407 goto error;
2408 }
2409
2410 mctx.driver_data = &mdata;
2411
2412 memset(&gnss_data, 0, sizeof(gnss_data));
2413
2414 ret = modem_context_register(&mctx);
2415 if (ret < 0) {
2416 LOG_ERR("Error registering modem context: %d", ret);
2417 goto error;
2418 }
2419
2420 k_thread_create(&modem_rx_thread, modem_rx_stack, K_KERNEL_STACK_SIZEOF(modem_rx_stack),
2421 modem_rx, NULL, NULL, NULL, K_PRIO_COOP(7), 0, K_NO_WAIT);
2422
2423 /* Init RSSI query */
2424 k_work_init_delayable(&mdata.rssi_query_work, modem_rssi_query_work);
2425
2426 return modem_setup();
2427 error:
2428 return ret;
2429 }
2430
2431 /* Register device with the networking stack. */
2432 NET_DEVICE_DT_INST_OFFLOAD_DEFINE(0, modem_init, NULL, &mdata, NULL,
2433 CONFIG_MODEM_SIMCOM_SIM7080_INIT_PRIORITY, &api_funcs,
2434 MDM_MAX_DATA_LENGTH);
2435
2436 NET_SOCKET_OFFLOAD_REGISTER(simcom_sim7080, CONFIG_NET_SOCKETS_OFFLOAD_PRIORITY,
2437 AF_UNSPEC, offload_is_supported, offload_socket);
2438