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