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 = zvfs_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