1 /*
2  * Copyright (c) 2020 Laird Connectivity
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #define DT_DRV_COMPAT swir_hl7800
8 
9 #include <zephyr/logging/log.h>
10 #include <zephyr/logging/log_ctrl.h>
11 #define LOG_MODULE_NAME modem_hl7800
12 LOG_MODULE_REGISTER(LOG_MODULE_NAME, CONFIG_MODEM_LOG_LEVEL);
13 
14 #include <zephyr/types.h>
15 #include <stddef.h>
16 #include <stdlib.h>
17 #include <ctype.h>
18 #include <errno.h>
19 #include <zephyr/kernel.h>
20 #include <zephyr/drivers/gpio.h>
21 #include <zephyr/device.h>
22 #include <zephyr/init.h>
23 
24 #include <zephyr/pm/device.h>
25 #include <zephyr/drivers/uart.h>
26 
27 #include <zephyr/net/net_context.h>
28 #include <zephyr/net/net_if.h>
29 #include <zephyr/net/net_offload.h>
30 #include <zephyr/net/net_pkt.h>
31 #include <zephyr/net/dns_resolve.h>
32 #include <zephyr/net/offloaded_netdev.h>
33 #if defined(CONFIG_NET_IPV6)
34 #include "ipv6.h"
35 #endif
36 #if defined(CONFIG_NET_IPV4)
37 #include "ipv4.h"
38 #endif
39 #if defined(CONFIG_NET_UDP)
40 #include "udp_internal.h"
41 #endif
42 
43 #ifdef CONFIG_MODEM_HL7800_FW_UPDATE
44 #include <zephyr/fs/fs.h>
45 #endif
46 
47 #include "modem_receiver.h"
48 #include <zephyr/drivers/modem/hl7800.h>
49 
50 #define PREFIXED_SWITCH_CASE_RETURN_STRING(prefix, val)                        \
51 	case prefix##_##val: {                                                 \
52 		return #val;                                                   \
53 	}
54 
55 /* Uncomment the #define below to enable a hexdump of all incoming
56  * data from the modem receiver
57  */
58 /* #define HL7800_ENABLE_VERBOSE_MODEM_RECV_HEXDUMP 1 */
59 
60 #define HL7800_LOG_UNHANDLED_RX_MSGS 1
61 
62 /* Uncomment the #define(s) below to enable extra debugging */
63 /* #define HL7800_RX_LOCK_LOG 1 */
64 /* #define HL7800_TX_LOCK_LOG 1 */
65 /* #define HL7800_IO_LOG 1 */
66 
67 #define HL7800_RX_LOCK_DBG_LOG(fmt, ...)                                       \
68 	do {                                                                   \
69 		if (IS_ENABLED(HL7800_RX_LOCK_LOG)) {                          \
70 			LOG_DBG(fmt, ##__VA_ARGS__);                           \
71 		}                                                              \
72 	} while (false)
73 
74 #define HL7800_TX_LOCK_DBG_LOG(fmt, ...)                                       \
75 	do {                                                                   \
76 		if (IS_ENABLED(HL7800_TX_LOCK_LOG)) {                          \
77 			LOG_DBG(fmt, ##__VA_ARGS__);                           \
78 		}                                                              \
79 	} while (false)
80 
81 #define HL7800_IO_DBG_LOG(fmt, ...)                                            \
82 	do {                                                                   \
83 		if (IS_ENABLED(HL7800_IO_LOG)) {                               \
84 			LOG_DBG(fmt, ##__VA_ARGS__);                           \
85 		}                                                              \
86 	} while (false)
87 
88 #if ((LOG_LEVEL == LOG_LEVEL_DBG) &&                                           \
89      defined(CONFIG_MODEM_HL7800_LOW_POWER_MODE))
90 #define PRINT_AWAKE_MSG LOG_WRN("awake")
91 #define PRINT_NOT_AWAKE_MSG LOG_WRN("NOT awake")
92 #else
93 #define PRINT_AWAKE_MSG
94 #define PRINT_NOT_AWAKE_MSG
95 #endif
96 
97 enum tcp_notif {
98 	HL7800_TCP_NET_ERR,
99 	HL7800_TCP_NO_SOCKS,
100 	HL7800_TCP_MEM,
101 	HL7800_TCP_DNS,
102 	HL7800_TCP_DISCON,
103 	HL7800_TCP_CONN,
104 	HL7800_TCP_ERR,
105 	HL7800_TCP_CLIENT_REQ,
106 	HL7800_TCP_DATA_SND,
107 	HL7800_TCP_ID,
108 	HL7800_TCP_RUNNING,
109 	HL7800_TCP_ALL_USED,
110 	HL7800_TCP_TIMEOUT,
111 	HL7800_TCP_SSL_CONN,
112 	HL7800_TCP_SSL_INIT
113 };
114 
115 enum udp_notif {
116 	HL7800_UDP_NET_ERR = 0,
117 	HL7800_UDP_NO_SOCKS = 1,
118 	HL7800_UDP_MEM = 2,
119 	HL7800_UDP_DNS = 3,
120 	HL7800_UDP_CONN = 5,
121 	HL7800_UDP_ERR = 6,
122 	HL7800_UDP_DATA_SND = 8, /* this matches TCP_DATA_SND */
123 	HL7800_UDP_ID = 9,
124 	HL7800_UDP_RUNNING = 10,
125 	HL7800_UDP_ALL_USED = 11
126 };
127 
128 enum socket_state {
129 	SOCK_IDLE,
130 	SOCK_RX,
131 	SOCK_TX,
132 	SOCK_CONNECTED,
133 };
134 
135 enum hl7800_lpm {
136 	HL7800_LPM_NONE,
137 	HL7800_LPM_EDRX,
138 	HL7800_LPM_PSM,
139 };
140 
141 /* pin settings */
142 enum mdm_control_pins {
143 	MDM_RESET = 0,
144 	MDM_WAKE,
145 	MDM_PWR_ON,
146 	MDM_FAST_SHUTD,
147 	MDM_VGPIO,
148 	MDM_UART_DSR,
149 	MDM_UART_CTS,
150 	MDM_GPIO6,
151 	MAX_MDM_CONTROL_PINS,
152 };
153 
154 enum net_operator_status { NO_OPERATOR, REGISTERED };
155 
156 enum device_service_indications {
157 	WDSI_PKG_DOWNLOADED = 3,
158 };
159 
160 #ifdef CONFIG_MODEM_HL7800_FW_UPDATE
161 enum XMODEM_CONTROL_CHARACTERS {
162 	XM_SOH = 0x01,
163 	XM_SOH_1K = 0x02,
164 	XM_EOT = 0x04,
165 	XM_ACK = 0x06, /* 'R' */
166 	XM_NACK = 0x15, /* 'N' */
167 	XM_ETB = 0x17,
168 	XM_CAN = 0x18,
169 	XM_C = 0x43
170 };
171 
172 #define XMODEM_DATA_SIZE 1024
173 #define XMODEM_PACKET_SIZE (XMODEM_DATA_SIZE + 4)
174 #define XMODEM_PAD_VALUE 26
175 
176 struct xmodem_packet {
177 	uint8_t preamble;
178 	uint8_t id;
179 	uint8_t id_complement;
180 	uint8_t data[XMODEM_DATA_SIZE];
181 	uint8_t crc;
182 };
183 #endif
184 
185 #define MDM_UART_DEV	DEVICE_DT_GET(DT_INST_BUS(0))
186 
187 #define MDM_SEND_OK_ENABLED 0
188 #define MDM_SEND_OK_DISABLED 1
189 
190 #define MDM_CMD_SEND_TIMEOUT K_SECONDS(6)
191 #define MDM_IP_SEND_RX_TIMEOUT K_SECONDS(62)
192 #define MDM_SOCK_NOTIF_DELAY K_MSEC(150)
193 #define MDM_CMD_CONN_TIMEOUT K_SECONDS(31)
194 
195 #define MDM_MAX_DATA_LENGTH 1500
196 #define MDM_MTU 1500
197 #define MDM_MAX_RESP_SIZE 128
198 #define MDM_IP_INFO_RESP_SIZE 256
199 #define MDM_EID_LENGTH	       33
200 #define MDM_CCID_RESP_MAX_SIZE (MDM_HL7800_ICCID_MAX_SIZE + MDM_EID_LENGTH)
201 
202 #define MDM_HANDLER_MATCH_MAX_LEN 100
203 
204 #define MDM_MAX_SOCKETS 6
205 
206 /* Special value used to indicate that a socket is being created
207  * and that its actual ID hasn't been assigned yet.
208  */
209 #define MDM_CREATE_SOCKET_ID (MDM_MAX_SOCKETS + 1)
210 
211 #define BUF_ALLOC_TIMEOUT K_SECONDS(1)
212 
213 #define SIZE_OF_NUL 1
214 
215 #define SIZE_WITHOUT_NUL(v) (sizeof(v) - SIZE_OF_NUL)
216 
217 #define CMD_HANDLER(cmd_, cb_)                                                 \
218 	{                                                                      \
219 		.cmd = cmd_, .cmd_len = (uint16_t)sizeof(cmd_) - 1,            \
220 		.func = on_cmd_##cb_                                           \
221 	}
222 
223 #define MDM_MANUFACTURER_LENGTH 16
224 #define MDM_MODEL_LENGTH 7
225 #define MDM_SN_RESPONSE_LENGTH (MDM_HL7800_SERIAL_NUMBER_SIZE + 7)
226 #define MDM_NETWORK_STATUS_LENGTH 45
227 
228 #define MDM_TOP_BAND_SIZE 4
229 #define MDM_MIDDLE_BAND_SIZE 8
230 #define MDM_BOTTOM_BAND_SIZE 8
231 #define MDM_TOP_BAND_START_POSITION 2
232 #define MDM_MIDDLE_BAND_START_POSITION 6
233 #define MDM_BOTTOM_BAND_START_POSITION 14
234 #define MDM_BAND_BITMAP_STR_LENGTH_MAX                                                             \
235 	(MDM_TOP_BAND_SIZE + MDM_MIDDLE_BAND_SIZE + MDM_BOTTOM_BAND_SIZE)
236 #define MDM_BAND_BITMAP_STR_LENGTH_MIN 1
237 
238 #define MDM_DEFAULT_AT_CMD_RETRIES 3
239 #define MDM_WAKEUP_TIME K_SECONDS(12)
240 #define MDM_BOOT_TIME K_SECONDS(12)
241 #define MDM_WAKE_TO_CHECK_CTS_DELAY_MS K_MSEC(20)
242 
243 #define MDM_WAIT_FOR_DATA_TIME K_MSEC(50)
244 #define MDM_RESET_LOW_TIME K_MSEC(50)
245 #define MDM_RESET_HIGH_TIME K_MSEC(10)
246 #define MDM_WAIT_FOR_DATA_RETRIES 3
247 
248 #define RSSI_UNKNOWN -999
249 
250 #define DNS_WORK_DELAY_SECS 1
251 #define IFACE_WORK_DELAY K_MSEC(500)
252 #define SOCKET_CLEANUP_WORK_DELAY K_MSEC(100)
253 #define WAIT_FOR_KSUP_RETRIES 5
254 
255 #define CGCONTRDP_RESPONSE_NUM_DELIMS 7
256 #define COPS_RESPONSE_NUM_DELIMS 2
257 #define KCELLMEAS_RESPONSE_NUM_DELIMS 4
258 
259 #define PROFILE_LINE_1                                                         \
260 	"E1 Q0 V1 X4 &C1 &D1 &R1 &S0 +IFC=2,2 &K3 +IPR=115200 +FCLASS0\r\n"
261 #define PROFILE_LINE_2                                                         \
262 	"S00:255 S01:255 S03:255 S04:255 S05:255 S07:255 S08:255 S10:255\r\n"
263 
264 #define ADDRESS_FAMILY_IPV4 "IPV4"
265 #if defined(CONFIG_MODEM_HL7800_ADDRESS_FAMILY_IPV4V6)
266 #define MODEM_HL7800_ADDRESS_FAMILY "IPV4V6"
267 #elif defined(CONFIG_MODEM_HL7800_ADDRESS_FAMILY_IPV4)
268 #define MODEM_HL7800_ADDRESS_FAMILY ADDRESS_FAMILY_IPV4
269 #else
270 #define MODEM_HL7800_ADDRESS_FAMILY "IPV6"
271 #endif
272 #define MDM_HL7800_SOCKET_AF_IPV4 0
273 #define MDM_HL7800_SOCKET_AF_IPV6 1
274 
275 #define SET_RAT_M1_CMD_LEGACY "AT+KSRAT=0"
276 #define SET_RAT_NB1_CMD_LEGACY "AT+KSRAT=1"
277 #define SET_RAT_M1_CMD "AT+KSRAT=0,1"
278 #define SET_RAT_NB1_CMD "AT+KSRAT=1,1"
279 #define NEW_RAT_CMD_MIN_VERSION "HL7800.4.5.4.0"
280 #define HL7800_VERSION_FORMAT "HL7800.%zu.%zu.%zu.%zu"
281 
282 #define MAX_PROFILE_LINE_LENGTH                                                \
283 	MAX(sizeof(PROFILE_LINE_1), sizeof(PROFILE_LINE_2))
284 
285 #define IPV6_ADDR_FORMAT "####:####:####:####:####:####:####:####"
286 #define HL7800_IPV6_ADDR_LEN                                                                       \
287 	sizeof("a01.a02.a03.a04.a05.a06.a07.a08.a09.a10.a11.a12.a13.a14.a15.a16")
288 
289 #define MDM_ADDR_FAM_MAX_LEN sizeof("IPV4V6")
290 
291 /* The ? can be a + or - */
292 static const char TIME_STRING_FORMAT[] = "\"yy/MM/dd,hh:mm:ss?zz\"";
293 #define TIME_STRING_DIGIT_STRLEN 2
294 #define TIME_STRING_SEPARATOR_STRLEN 1
295 #define TIME_STRING_PLUS_MINUS_INDEX (6 * 3)
296 #define TIME_STRING_FIRST_SEPARATOR_INDEX 0
297 #define TIME_STRING_FIRST_DIGIT_INDEX 1
298 #define TIME_STRING_TO_TM_STRUCT_YEAR_OFFSET (2000 - 1900)
299 
300 /* Time structure min, max */
301 #define TM_YEAR_RANGE 0, 99
302 #define TM_MONTH_RANGE_PLUS_1 1, 12
303 #define TM_DAY_RANGE 1, 31
304 #define TM_HOUR_RANGE 0, 23
305 #define TM_MIN_RANGE 0, 59
306 #define TM_SEC_RANGE 0, 60 /* leap second */
307 #define QUARTER_HOUR_RANGE 0, 96
308 #define SECONDS_PER_QUARTER_HOUR (15 * 60)
309 
310 #define SEND_AT_CMD_ONCE_EXPECT_OK(c)                                          \
311 	do {                                                                   \
312 		ret = send_at_cmd(NULL, (c), MDM_CMD_SEND_TIMEOUT, 0, false);  \
313 		if (ret < 0) {                                                 \
314 			LOG_ERR("%s result:%d", (c), ret);                     \
315 			goto error;                                            \
316 		}                                                              \
317 	} while (false)
318 
319 #define SEND_AT_CMD_IGNORE_ERROR(c)                                            \
320 	do {                                                                   \
321 		ret = send_at_cmd(NULL, (c), MDM_CMD_SEND_TIMEOUT, 0, false);  \
322 		if (ret < 0) {                                                 \
323 			LOG_ERR("%s result:%d", (c), ret);                     \
324 		}                                                              \
325 	} while (false)
326 
327 #define SEND_AT_CMD_EXPECT_OK(c)                                               \
328 	do {                                                                   \
329 		ret = send_at_cmd(NULL, (c), MDM_CMD_SEND_TIMEOUT,             \
330 				  MDM_DEFAULT_AT_CMD_RETRIES, false);          \
331 		if (ret < 0) {                                                 \
332 			LOG_ERR("%s result:%d", (c), ret);                     \
333 			goto error;                                            \
334 		}                                                              \
335 	} while (false)
336 
337 /* Complex has "no_id_resp" set to true because the sending command
338  * is the command used to process the response
339  */
340 #define SEND_COMPLEX_AT_CMD(c)                                                 \
341 	do {                                                                   \
342 		ret = send_at_cmd(NULL, (c), MDM_CMD_SEND_TIMEOUT,             \
343 				  MDM_DEFAULT_AT_CMD_RETRIES, true);           \
344 		if (ret < 0) {                                                 \
345 			LOG_ERR("%s result:%d", (c), ret);                     \
346 			goto error;                                            \
347 		}                                                              \
348 	} while (false)
349 
350 NET_BUF_POOL_DEFINE(mdm_recv_pool, CONFIG_MODEM_HL7800_RECV_BUF_CNT,
351 		    CONFIG_MODEM_HL7800_RECV_BUF_SIZE, 0, NULL);
352 
353 static uint8_t mdm_recv_buf[MDM_MAX_DATA_LENGTH];
354 
355 static K_SEM_DEFINE(hl7800_RX_lock_sem, 1, 1);
356 static K_SEM_DEFINE(hl7800_TX_lock_sem, 1, 1);
357 static K_SEM_DEFINE(cb_lock, 1, 1);
358 
359 /* RX thread structures */
360 K_THREAD_STACK_DEFINE(hl7800_rx_stack, CONFIG_MODEM_HL7800_RX_STACK_SIZE);
361 struct k_thread hl7800_rx_thread;
362 #define RX_THREAD_PRIORITY K_PRIO_COOP(7)
363 
364 /* RX thread work queue */
365 K_THREAD_STACK_DEFINE(hl7800_workq_stack,
366 		      CONFIG_MODEM_HL7800_RX_WORKQ_STACK_SIZE);
367 static struct k_work_q hl7800_workq;
368 #define WORKQ_PRIORITY K_PRIO_COOP(7)
369 
370 static const char EOF_PATTERN[] = "--EOF--Pattern--";
371 static const char CONNECT_STRING[] = "CONNECT";
372 static const char OK_STRING[] = "OK";
373 
374 struct hl7800_socket {
375 	struct net_context *context;
376 	sa_family_t family;
377 	enum net_sock_type type;
378 	enum net_ip_protocol ip_proto;
379 	struct sockaddr src;
380 	struct sockaddr dst;
381 
382 	bool created;
383 	bool reconfig;
384 	int socket_id;
385 	int rx_size;
386 	int error;
387 	enum socket_state state;
388 
389 	/** semaphore */
390 	struct k_sem sock_send_sem;
391 
392 	/** socket callbacks */
393 	struct k_work recv_cb_work;
394 	struct k_work rx_data_work;
395 	struct k_work_delayable notif_work;
396 	net_context_recv_cb_t recv_cb;
397 	struct net_pkt *recv_pkt;
398 	void *recv_user_data;
399 };
400 
401 struct stale_socket {
402 	int reserved; /* first word of queue data item reserved for the kernel */
403 	enum net_sock_type type;
404 	uint8_t id;
405 	bool allocated;
406 };
407 
408 #define NO_ID_RESP_CMD_MAX_LENGTH 32
409 
410 struct hl7800_config {
411 	struct gpio_dt_spec gpio[MAX_MDM_CONTROL_PINS];
412 };
413 
414 struct hl7800_iface_ctx {
415 	struct net_if *iface;
416 	uint8_t mac_addr[6];
417 	struct in_addr ipv4Addr, subnet, gateway, dns_v4;
418 #ifdef CONFIG_NET_IPV6
419 	struct in6_addr ipv6Addr, dns_v6;
420 	char dns_v6_string[HL7800_IPV6_ADDR_LEN];
421 #endif
422 	bool restarting;
423 	bool initialized;
424 	bool wait_for_KSUP;
425 	uint32_t wait_for_KSUP_tries;
426 	bool reconfig_IP_connection;
427 	char dns_v4_string[NET_IPV4_ADDR_LEN];
428 	char no_id_resp_cmd[NO_ID_RESP_CMD_MAX_LENGTH];
429 	bool search_no_id_resp;
430 
431 	/* GPIO PORT devices */
432 	struct gpio_callback mdm_vgpio_cb;
433 	struct gpio_callback mdm_uart_dsr_cb;
434 	struct gpio_callback mdm_gpio6_cb;
435 	struct gpio_callback mdm_uart_cts_cb;
436 	int vgpio_state;
437 	int dsr_state;
438 	int gpio6_state;
439 	int cts_state;
440 
441 	/* RX specific attributes */
442 	struct mdm_receiver_context mdm_ctx;
443 
444 	/* socket data */
445 	struct hl7800_socket sockets[MDM_MAX_SOCKETS];
446 	int last_socket_id;
447 	int last_error;
448 	struct stale_socket stale_sockets[MDM_MAX_SOCKETS];
449 	struct k_queue stale_socket_queue;
450 
451 	/* semaphores */
452 	struct k_sem response_sem;
453 	struct k_sem mdm_awake;
454 
455 	/* work */
456 	struct k_work_delayable rssi_query_work;
457 	struct k_work_delayable iface_status_work;
458 	struct k_work_delayable dns_work;
459 	struct k_work mdm_vgpio_work;
460 	struct k_work_delayable mdm_reset_work;
461 	struct k_work_delayable allow_sleep_work;
462 	struct k_work_delayable delete_untracked_socket_work;
463 	struct k_work mdm_pwr_off_work;
464 
465 #ifdef CONFIG_MODEM_HL7800_FW_UPDATE
466 	/* firmware update */
467 	enum mdm_hl7800_fota_state fw_update_state;
468 	struct fs_file_t fw_update_file;
469 	struct xmodem_packet fw_packet;
470 	uint32_t fw_packet_count;
471 	int file_pos;
472 	struct k_work finish_fw_update_work;
473 	bool fw_updated;
474 #endif
475 
476 	/* modem info */
477 	/* NOTE: make sure length is +1 for null char */
478 	char mdm_manufacturer[MDM_MANUFACTURER_LENGTH];
479 	char mdm_model[MDM_MODEL_LENGTH];
480 	char mdm_revision[MDM_HL7800_REVISION_MAX_SIZE];
481 	char mdm_imei[MDM_HL7800_IMEI_SIZE];
482 	char mdm_sn[MDM_HL7800_SERIAL_NUMBER_SIZE];
483 	char mdm_network_status[MDM_NETWORK_STATUS_LENGTH];
484 	char mdm_iccid[MDM_HL7800_ICCID_MAX_SIZE];
485 	enum mdm_hl7800_startup_state mdm_startup_state;
486 	enum mdm_hl7800_radio_mode mdm_rat;
487 	char mdm_active_bands_string[MDM_HL7800_LTE_BAND_STR_SIZE];
488 	char mdm_bands_string[MDM_HL7800_LTE_BAND_STR_SIZE];
489 	char mdm_imsi[MDM_HL7800_IMSI_MAX_STR_SIZE];
490 	int mdm_rssi;
491 	uint16_t mdm_bands_top;
492 	uint32_t mdm_bands_middle;
493 	uint32_t mdm_bands_bottom;
494 	int32_t mdm_sinr;
495 	bool mdm_echo_is_on;
496 	struct mdm_hl7800_apn mdm_apn;
497 	bool mdm_startup_reporting_on;
498 	int device_services_ind;
499 	bool new_rat_cmd_support;
500 	uint8_t operator_index;
501 	enum mdm_hl7800_functionality functionality;
502 	char mdm_pdp_addr_fam[MDM_ADDR_FAM_MAX_LEN];
503 
504 	/* modem state */
505 	bool allow_sleep;
506 	bool uart_on;
507 	enum mdm_hl7800_sleep desired_sleep_level;
508 	enum mdm_hl7800_sleep sleep_state;
509 	enum hl7800_lpm low_power_mode;
510 	enum mdm_hl7800_network_state network_state;
511 	bool network_dropped;
512 	bool dns_ready;
513 	enum net_operator_status operator_status;
514 	struct tm local_time;
515 	int32_t local_time_offset;
516 	bool local_time_valid;
517 	bool configured;
518 	bool off;
519 	void (*wake_up_callback)(int state);
520 	void (*gpio6_callback)(int state);
521 	void (*cts_callback)(int state);
522 
523 #ifdef CONFIG_MODEM_HL7800_GPS
524 	struct k_work_delayable gps_work;
525 	uint32_t gps_query_location_rate_seconds;
526 #endif
527 };
528 
529 struct cmd_handler {
530 	const char *cmd;
531 	uint16_t cmd_len;
532 	bool (*func)(struct net_buf **buf, uint16_t len);
533 };
534 
535 static sys_slist_t hl7800_event_callback_list =
536 	SYS_SLIST_STATIC_INIT(&hl7800_event_callback_list);
537 
538 const static struct hl7800_config hl7800_cfg = {
539 	.gpio = {
540 		GPIO_DT_SPEC_INST_GET(0, mdm_reset_gpios),
541 		GPIO_DT_SPEC_INST_GET(0, mdm_wake_gpios),
542 		GPIO_DT_SPEC_INST_GET(0, mdm_pwr_on_gpios),
543 		GPIO_DT_SPEC_INST_GET(0, mdm_fast_shutd_gpios),
544 		GPIO_DT_SPEC_INST_GET(0, mdm_vgpio_gpios),
545 		GPIO_DT_SPEC_INST_GET(0, mdm_uart_dsr_gpios),
546 		GPIO_DT_SPEC_INST_GET(0, mdm_uart_cts_gpios),
547 		GPIO_DT_SPEC_INST_GET(0, mdm_gpio6_gpios),
548 	},
549 };
550 static struct hl7800_iface_ctx ictx;
551 
552 static size_t hl7800_read_rx(struct net_buf **buf);
553 static char *get_network_state_string(enum mdm_hl7800_network_state state);
554 static char *get_startup_state_string(enum mdm_hl7800_startup_state state);
555 static char *get_sleep_state_string(enum mdm_hl7800_sleep state);
556 static void set_network_state(enum mdm_hl7800_network_state state);
557 static void set_startup_state(enum mdm_hl7800_startup_state state);
558 static void set_sleep_state(enum mdm_hl7800_sleep state);
559 static void generate_network_state_event(void);
560 static void generate_startup_state_event(void);
561 static void generate_sleep_state_event(void);
562 static int modem_boot_handler(char *reason);
563 static void mdm_vgpio_work_cb(struct k_work *item);
564 static void mdm_reset_work_callback(struct k_work *item);
565 static void mdm_power_off_work_callback(struct k_work *item);
566 static int write_apn(char *access_point_name);
567 #ifdef CONFIG_MODEM_HL7800_LOW_POWER_MODE
568 static void mark_sockets_for_reconfig(void);
569 #endif
570 static void hl7800_build_mac(struct hl7800_iface_ctx *ictx);
571 static void rssi_query(void);
572 
573 #ifdef CONFIG_MODEM_HL7800_LOW_POWER_MODE
574 static void initialize_sleep_level(void);
575 static int set_sleep_level(void);
576 #endif
577 
578 #ifdef CONFIG_MODEM_HL7800_FW_UPDATE
579 static char *get_fota_state_string(enum mdm_hl7800_fota_state state);
580 static void set_fota_state(enum mdm_hl7800_fota_state state);
581 static void generate_fota_state_event(void);
582 static void generate_fota_count_event(void);
583 #endif
584 
alloc_stale_socket(void)585 static struct stale_socket *alloc_stale_socket(void)
586 {
587 	struct stale_socket *sock = NULL;
588 
589 	for (int i = 0; i < MDM_MAX_SOCKETS; i++) {
590 		if (!ictx.stale_sockets[i].allocated) {
591 			sock = &ictx.stale_sockets[i];
592 			sock->allocated = true;
593 			break;
594 		}
595 	}
596 
597 	return sock;
598 }
599 
free_stale_socket(struct stale_socket * sock)600 static void free_stale_socket(struct stale_socket *sock)
601 {
602 	if (sock != NULL) {
603 		sock->allocated = false;
604 	}
605 }
606 
queue_stale_socket(enum net_sock_type type,uint8_t id)607 static int queue_stale_socket(enum net_sock_type type, uint8_t id)
608 {
609 	int ret = 0;
610 	struct stale_socket *sock = NULL;
611 
612 	sock = alloc_stale_socket();
613 	if (sock != NULL) {
614 		sock->type = type;
615 		sock->id = id;
616 		k_queue_append(&ictx.stale_socket_queue, (void *)sock);
617 	} else {
618 		LOG_ERR("Could not alloc stale socket");
619 		ret = -ENOMEM;
620 	}
621 
622 	return ret;
623 }
624 
dequeue_stale_socket(void)625 static struct stale_socket *dequeue_stale_socket(void)
626 {
627 	struct stale_socket *sock = NULL;
628 
629 	sock = (struct stale_socket *)k_queue_get(&ictx.stale_socket_queue, K_NO_WAIT);
630 
631 	return sock;
632 }
633 
634 static bool convert_time_string_to_struct(struct tm *tm, int32_t *offset,
635 					  char *time_string);
636 static int modem_reset_and_configure(void);
637 
read_pin(int default_state,const struct gpio_dt_spec * spec)638 static int read_pin(int default_state, const struct gpio_dt_spec *spec)
639 {
640 	int state = gpio_pin_get_raw(spec->port, spec->pin);
641 
642 	if (state < 0) {
643 		LOG_ERR("Unable to read port: %s pin: %d status: %d",
644 			spec->port->name, spec->pin, state);
645 		state = default_state;
646 	}
647 
648 	return state;
649 }
650 
651 #ifdef CONFIG_MODEM_HL7800_LOW_POWER_MODE
is_cmd_ready(void)652 static bool is_cmd_ready(void)
653 {
654 	ictx.vgpio_state = read_pin(0, &hl7800_cfg.gpio[MDM_VGPIO]);
655 
656 	ictx.gpio6_state = read_pin(0, &hl7800_cfg.gpio[MDM_GPIO6]);
657 
658 	ictx.cts_state = read_pin(1, &hl7800_cfg.gpio[MDM_UART_CTS]);
659 
660 	return ictx.vgpio_state && ictx.gpio6_state && !ictx.cts_state;
661 }
662 #endif
663 
664 /**
665  * The definition of awake is that the HL7800
666  * is ready to receive AT commands successfully
667  */
check_hl7800_awake(void)668 static void check_hl7800_awake(void)
669 {
670 #ifdef CONFIG_MODEM_HL7800_LOW_POWER_MODE
671 	bool is_cmd_rdy = is_cmd_ready();
672 
673 	if (is_cmd_rdy && (ictx.sleep_state != HL7800_SLEEP_AWAKE) &&
674 	    !ictx.allow_sleep && !ictx.wait_for_KSUP) {
675 		PRINT_AWAKE_MSG;
676 		set_sleep_state(HL7800_SLEEP_AWAKE);
677 		k_sem_give(&ictx.mdm_awake);
678 	} else if (!is_cmd_rdy && ictx.sleep_state == HL7800_SLEEP_AWAKE &&
679 		   ictx.allow_sleep) {
680 		PRINT_NOT_AWAKE_MSG;
681 
682 		if (ictx.desired_sleep_level == HL7800_SLEEP_HIBERNATE ||
683 		    ictx.desired_sleep_level == HL7800_SLEEP_LITE_HIBERNATE) {
684 			/* If the device is sleeping (not ready to receive commands)
685 			 * then the device may send +KSUP when waking up.
686 			 * We should wait for it.
687 			 */
688 			ictx.wait_for_KSUP = true;
689 			ictx.wait_for_KSUP_tries = 0;
690 
691 			set_sleep_state(ictx.desired_sleep_level);
692 
693 		} else if (ictx.desired_sleep_level == HL7800_SLEEP_SLEEP) {
694 			set_sleep_state(HL7800_SLEEP_SLEEP);
695 		}
696 	}
697 #endif
698 }
699 
hl7800_RX_lock(void)700 static int hl7800_RX_lock(void)
701 {
702 	HL7800_RX_LOCK_DBG_LOG("Locking RX [%p]...", k_current_get());
703 	int rc = k_sem_take(&hl7800_RX_lock_sem, K_FOREVER);
704 
705 	if (rc != 0) {
706 		LOG_ERR("Unable to lock hl7800 (%d)", rc);
707 	} else {
708 		HL7800_RX_LOCK_DBG_LOG("Locked RX [%p]", k_current_get());
709 	}
710 
711 	return rc;
712 }
713 
hl7800_RX_unlock(void)714 static void hl7800_RX_unlock(void)
715 {
716 	HL7800_RX_LOCK_DBG_LOG("UNLocking RX [%p]...", k_current_get());
717 	k_sem_give(&hl7800_RX_lock_sem);
718 	HL7800_RX_LOCK_DBG_LOG("UNLocked RX [%p]", k_current_get());
719 }
720 
hl7800_RX_locked(void)721 static bool hl7800_RX_locked(void)
722 {
723 	if (k_sem_count_get(&hl7800_RX_lock_sem) == 0) {
724 		return true;
725 	} else {
726 		return false;
727 	}
728 }
729 
hl7800_TX_lock(void)730 static int hl7800_TX_lock(void)
731 {
732 	HL7800_TX_LOCK_DBG_LOG("Locking TX [%p]...", k_current_get());
733 	int rc = k_sem_take(&hl7800_TX_lock_sem, K_FOREVER);
734 
735 	if (rc != 0) {
736 		LOG_ERR("Unable to lock hl7800 (%d)", rc);
737 	} else {
738 		HL7800_TX_LOCK_DBG_LOG("Locked TX [%p]", k_current_get());
739 	}
740 
741 	return rc;
742 }
743 
hl7800_TX_unlock(void)744 static void hl7800_TX_unlock(void)
745 {
746 	HL7800_TX_LOCK_DBG_LOG("UNLocking TX [%p]...", k_current_get());
747 	k_sem_give(&hl7800_TX_lock_sem);
748 	HL7800_TX_LOCK_DBG_LOG("UNLocked TX [%p]", k_current_get());
749 }
750 
hl7800_TX_locked(void)751 static bool hl7800_TX_locked(void)
752 {
753 	if (k_sem_count_get(&hl7800_TX_lock_sem) == 0) {
754 		return true;
755 	} else {
756 		return false;
757 	}
758 }
759 
hl7800_lock(void)760 static void hl7800_lock(void)
761 {
762 	hl7800_TX_lock();
763 	hl7800_RX_lock();
764 }
765 
hl7800_unlock(void)766 static void hl7800_unlock(void)
767 {
768 	hl7800_RX_unlock();
769 	hl7800_TX_unlock();
770 }
771 
socket_get(void)772 static struct hl7800_socket *socket_get(void)
773 {
774 	int i;
775 	struct hl7800_socket *sock = NULL;
776 
777 	for (i = 0; i < MDM_MAX_SOCKETS; i++) {
778 		if (!ictx.sockets[i].context) {
779 			sock = &ictx.sockets[i];
780 			break;
781 		}
782 	}
783 
784 	return sock;
785 }
786 
socket_from_id(int socket_id)787 static struct hl7800_socket *socket_from_id(int socket_id)
788 {
789 	int i;
790 	struct hl7800_socket *sock = NULL;
791 
792 	if (socket_id < 1) {
793 		return NULL;
794 	}
795 
796 	for (i = 0; i < MDM_MAX_SOCKETS; i++) {
797 		if (ictx.sockets[i].socket_id == socket_id) {
798 			sock = &ictx.sockets[i];
799 			break;
800 		}
801 	}
802 
803 	return sock;
804 }
805 
socket_put(struct hl7800_socket * sock)806 static void socket_put(struct hl7800_socket *sock)
807 {
808 	if (!sock) {
809 		return;
810 	}
811 
812 	sock->context = NULL;
813 	sock->socket_id = -1;
814 	sock->created = false;
815 	sock->reconfig = false;
816 	sock->error = 0;
817 	sock->rx_size = 0;
818 	sock->state = SOCK_IDLE;
819 	(void)memset(&sock->src, 0, sizeof(struct sockaddr));
820 	(void)memset(&sock->dst, 0, sizeof(struct sockaddr));
821 }
822 
hl7800_sprint_ip_addr(const struct sockaddr * addr)823 char *hl7800_sprint_ip_addr(const struct sockaddr *addr)
824 {
825 	static char buf[NET_IPV6_ADDR_LEN];
826 
827 #if defined(CONFIG_NET_IPV6)
828 	if (addr->sa_family == AF_INET6) {
829 		return net_addr_ntop(AF_INET6, &net_sin6(addr)->sin6_addr, buf,
830 				     sizeof(buf));
831 	} else
832 #endif
833 #if defined(CONFIG_NET_IPV4)
834 		if (addr->sa_family == AF_INET) {
835 		return net_addr_ntop(AF_INET, &net_sin(addr)->sin_addr, buf,
836 				     sizeof(buf));
837 	} else
838 #endif
839 	{
840 		LOG_ERR("Unknown IP address family:%d", addr->sa_family);
841 		return NULL;
842 	}
843 }
844 
mdm_hl7800_register_wake_test_point_callback(void (* func)(int state))845 void mdm_hl7800_register_wake_test_point_callback(void (*func)(int state))
846 {
847 	ictx.wake_up_callback = func;
848 }
849 
mdm_hl7800_register_gpio6_callback(void (* func)(int state))850 void mdm_hl7800_register_gpio6_callback(void (*func)(int state))
851 {
852 	ictx.gpio6_callback = func;
853 }
854 
mdm_hl7800_register_cts_callback(void (* func)(int state))855 void mdm_hl7800_register_cts_callback(void (*func)(int state))
856 {
857 	ictx.cts_callback = func;
858 }
859 
modem_assert_wake(bool assert)860 static void modem_assert_wake(bool assert)
861 {
862 	int state;
863 
864 	if (assert) {
865 		HL7800_IO_DBG_LOG("MDM_WAKE_PIN -> ASSERTED");
866 		state = 1;
867 	} else {
868 		HL7800_IO_DBG_LOG("MDM_WAKE_PIN -> NOT_ASSERTED");
869 		state = 0;
870 	}
871 
872 	gpio_pin_set_dt(&hl7800_cfg.gpio[MDM_WAKE], state);
873 
874 	if (ictx.wake_up_callback != NULL) {
875 		ictx.wake_up_callback(state);
876 	}
877 }
878 
modem_assert_pwr_on(bool assert)879 static void modem_assert_pwr_on(bool assert)
880 {
881 	if (assert) {
882 		HL7800_IO_DBG_LOG("MDM_PWR_ON -> ASSERTED");
883 		gpio_pin_set_dt(&hl7800_cfg.gpio[MDM_PWR_ON], 1);
884 	} else {
885 		HL7800_IO_DBG_LOG("MDM_PWR_ON -> NOT_ASSERTED");
886 		gpio_pin_set_dt(&hl7800_cfg.gpio[MDM_PWR_ON], 0);
887 	}
888 }
889 
modem_assert_fast_shutd(bool assert)890 static void modem_assert_fast_shutd(bool assert)
891 {
892 	if (assert) {
893 		HL7800_IO_DBG_LOG("MDM_FAST_SHUTD -> ASSERTED");
894 		gpio_pin_set_dt(&hl7800_cfg.gpio[MDM_FAST_SHUTD], 1);
895 	} else {
896 		HL7800_IO_DBG_LOG("MDM_FAST_SHUTD -> NOT_ASSERTED");
897 		gpio_pin_set_dt(&hl7800_cfg.gpio[MDM_FAST_SHUTD], 0);
898 	}
899 }
900 
allow_sleep_work_callback(struct k_work * item)901 static void allow_sleep_work_callback(struct k_work *item)
902 {
903 	ARG_UNUSED(item);
904 	LOG_DBG("Allow sleep");
905 	ictx.allow_sleep = true;
906 	set_sleep_state(ictx.desired_sleep_level);
907 	modem_assert_wake(false);
908 }
909 
allow_sleep(bool allow)910 static void allow_sleep(bool allow)
911 {
912 #ifdef CONFIG_MODEM_HL7800_LOW_POWER_MODE
913 	if (allow) {
914 		k_work_reschedule_for_queue(&hl7800_workq,
915 					    &ictx.allow_sleep_work,
916 					    K_MSEC(CONFIG_MODEM_HL7800_ALLOW_SLEEP_DELAY_MS));
917 	} else {
918 		LOG_DBG("Keep awake");
919 		k_work_cancel_delayable(&ictx.allow_sleep_work);
920 		ictx.allow_sleep = false;
921 		modem_assert_wake(true);
922 	}
923 #endif
924 }
925 
event_handler(enum mdm_hl7800_event event,void * event_data)926 static void event_handler(enum mdm_hl7800_event event, void *event_data)
927 {
928 	sys_snode_t *node;
929 	struct mdm_hl7800_callback_agent *agent;
930 
931 	k_sem_take(&cb_lock, K_FOREVER);
932 	SYS_SLIST_FOR_EACH_NODE(&hl7800_event_callback_list, node) {
933 		agent = CONTAINER_OF(node, struct mdm_hl7800_callback_agent, node);
934 		if (agent->event_callback != NULL) {
935 			agent->event_callback(event, event_data);
936 		}
937 	}
938 	k_sem_give(&cb_lock);
939 }
940 
mdm_hl7800_get_signal_quality(int * rsrp,int * sinr)941 void mdm_hl7800_get_signal_quality(int *rsrp, int *sinr)
942 {
943 	if (CONFIG_MODEM_HL7800_RSSI_RATE_SECONDS == 0) {
944 		rssi_query();
945 	}
946 
947 	*rsrp = ictx.mdm_rssi;
948 	*sinr = ictx.mdm_sinr;
949 }
950 
mdm_hl7800_wakeup(bool wakeup)951 void mdm_hl7800_wakeup(bool wakeup)
952 {
953 	allow_sleep(!wakeup);
954 }
955 
956 /* Send an AT command with a series of response handlers */
send_at_cmd(struct hl7800_socket * sock,const uint8_t * data,k_timeout_t timeout,int retries,bool no_id_resp)957 static int send_at_cmd(struct hl7800_socket *sock, const uint8_t *data,
958 		       k_timeout_t timeout, int retries, bool no_id_resp)
959 {
960 	int ret = 0;
961 
962 	ictx.last_error = 0;
963 
964 	do {
965 		if (!sock) {
966 			k_sem_reset(&ictx.response_sem);
967 			ictx.last_socket_id = 0;
968 		} else {
969 			sock->error = 0;
970 			k_sem_reset(&sock->sock_send_sem);
971 			ictx.last_socket_id = sock->socket_id;
972 		}
973 		if (no_id_resp) {
974 			strncpy(ictx.no_id_resp_cmd, data,
975 				sizeof(ictx.no_id_resp_cmd) - 1);
976 			ictx.search_no_id_resp = true;
977 		}
978 
979 		LOG_DBG("OUT: [%s]", (char *)data);
980 		mdm_receiver_send(&ictx.mdm_ctx, data, strlen(data));
981 		mdm_receiver_send(&ictx.mdm_ctx, "\r", 1);
982 
983 		if (K_TIMEOUT_EQ(timeout, K_NO_WAIT)) {
984 			goto done;
985 		}
986 
987 		if (!sock) {
988 			ret = k_sem_take(&ictx.response_sem, timeout);
989 		} else {
990 			ret = k_sem_take(&sock->sock_send_sem, timeout);
991 		}
992 
993 		if (ret == 0) {
994 			if (sock) {
995 				ret = sock->error;
996 			} else {
997 				ret = ictx.last_error;
998 			}
999 		} else if (ret == -EAGAIN) {
1000 			ret = -ETIMEDOUT;
1001 		}
1002 
1003 		retries--;
1004 		if (retries < 0) {
1005 			retries = 0;
1006 		}
1007 	} while (ret != 0 && retries > 0);
1008 done:
1009 	ictx.search_no_id_resp = false;
1010 	return ret;
1011 }
1012 
wakeup_hl7800(void)1013 static int wakeup_hl7800(void)
1014 {
1015 #ifdef CONFIG_MODEM_HL7800_LOW_POWER_MODE
1016 	int ret;
1017 
1018 	allow_sleep(false);
1019 
1020 	/* If modem is in sleep mode (not hibernate),
1021 	 * then it can respond in ~10 ms.
1022 	 */
1023 	if (ictx.desired_sleep_level == HL7800_SLEEP_SLEEP) {
1024 		k_sleep(MDM_WAKE_TO_CHECK_CTS_DELAY_MS);
1025 	}
1026 
1027 	if (!is_cmd_ready()) {
1028 		LOG_DBG("Waiting to wakeup");
1029 		ret = k_sem_take(&ictx.mdm_awake, MDM_WAKEUP_TIME);
1030 		if (ret) {
1031 			LOG_DBG("Err waiting for wakeup: %d", ret);
1032 		}
1033 	}
1034 #endif
1035 	return 0;
1036 }
1037 
mdm_hl7800_send_at_cmd(const uint8_t * data)1038 int32_t mdm_hl7800_send_at_cmd(const uint8_t *data)
1039 {
1040 	int ret;
1041 
1042 	if (!data) {
1043 		return -EINVAL;
1044 	}
1045 
1046 	hl7800_lock();
1047 	wakeup_hl7800();
1048 	ictx.last_socket_id = 0;
1049 	ret = send_at_cmd(NULL, data, MDM_CMD_SEND_TIMEOUT, 0, false);
1050 	allow_sleep(true);
1051 	hl7800_unlock();
1052 	return ret;
1053 }
1054 
1055 /* The access point name (and username and password) are stored in the modem's
1056  * non-volatile memory.
1057  */
mdm_hl7800_update_apn(char * access_point_name)1058 int32_t mdm_hl7800_update_apn(char *access_point_name)
1059 {
1060 	int ret = -EINVAL;
1061 
1062 	hl7800_lock();
1063 	wakeup_hl7800();
1064 	ictx.last_socket_id = 0;
1065 	ret = write_apn(access_point_name);
1066 	allow_sleep(true);
1067 	hl7800_unlock();
1068 
1069 	if (ret >= 0) {
1070 		/* After a reset the APN will be re-read from the modem
1071 		 * and an event will be generated.
1072 		 */
1073 		k_work_reschedule_for_queue(&hl7800_workq, &ictx.mdm_reset_work,
1074 					    K_NO_WAIT);
1075 	}
1076 	return ret;
1077 }
1078 
mdm_hl7800_valid_rat(uint8_t value)1079 bool mdm_hl7800_valid_rat(uint8_t value)
1080 {
1081 	if ((value == MDM_RAT_CAT_M1) || (value == MDM_RAT_CAT_NB1)) {
1082 		return true;
1083 	}
1084 	return false;
1085 }
1086 
mdm_hl7800_update_rat(enum mdm_hl7800_radio_mode value)1087 int32_t mdm_hl7800_update_rat(enum mdm_hl7800_radio_mode value)
1088 {
1089 	int ret = -EINVAL;
1090 
1091 	if (value == ictx.mdm_rat) {
1092 		/* The set command will fail (in the modem)
1093 		 * if the RAT isn't different.
1094 		 */
1095 		return 0;
1096 	} else if (!mdm_hl7800_valid_rat(value)) {
1097 		return ret;
1098 	}
1099 
1100 	hl7800_lock();
1101 	wakeup_hl7800();
1102 	ictx.last_socket_id = 0;
1103 
1104 	if (value == MDM_RAT_CAT_M1) {
1105 		if (ictx.new_rat_cmd_support) {
1106 			SEND_AT_CMD_ONCE_EXPECT_OK(SET_RAT_M1_CMD);
1107 		} else {
1108 			SEND_AT_CMD_ONCE_EXPECT_OK(SET_RAT_M1_CMD_LEGACY);
1109 		}
1110 	} else { /* MDM_RAT_CAT_NB1 */
1111 		if (ictx.new_rat_cmd_support) {
1112 			SEND_AT_CMD_ONCE_EXPECT_OK(SET_RAT_NB1_CMD);
1113 		} else {
1114 			SEND_AT_CMD_ONCE_EXPECT_OK(SET_RAT_NB1_CMD_LEGACY);
1115 		}
1116 	}
1117 
1118 error:
1119 
1120 	allow_sleep(true);
1121 	hl7800_unlock();
1122 
1123 	/* Changing the RAT causes the modem to reset.
1124 	 * A reset and reconfigure ensures the modem configuration and
1125 	 * state are valid.
1126 	 */
1127 	if (ret >= 0) {
1128 		k_work_reschedule_for_queue(&hl7800_workq, &ictx.mdm_reset_work, K_NO_WAIT);
1129 	}
1130 
1131 	return ret;
1132 }
1133 
mdm_hl7800_get_local_time(struct tm * tm,int32_t * offset)1134 int32_t mdm_hl7800_get_local_time(struct tm *tm, int32_t *offset)
1135 {
1136 	int ret;
1137 
1138 	ictx.local_time_valid = false;
1139 
1140 	hl7800_lock();
1141 	wakeup_hl7800();
1142 	ictx.last_socket_id = 0;
1143 	ret = send_at_cmd(NULL, "AT+CCLK?", MDM_CMD_SEND_TIMEOUT, 0, false);
1144 	allow_sleep(true);
1145 	if (ictx.local_time_valid) {
1146 		memcpy(tm, &ictx.local_time, sizeof(struct tm));
1147 		memcpy(offset, &ictx.local_time_offset, sizeof(*offset));
1148 	} else {
1149 		ret = -EIO;
1150 	}
1151 	hl7800_unlock();
1152 	return ret;
1153 }
1154 
mdm_hl7800_get_operator_index(void)1155 int32_t mdm_hl7800_get_operator_index(void)
1156 {
1157 	int ret;
1158 
1159 	hl7800_lock();
1160 	wakeup_hl7800();
1161 	ictx.last_socket_id = 0;
1162 	ret = send_at_cmd(NULL, "AT+KCARRIERCFG?", MDM_CMD_SEND_TIMEOUT, 0,
1163 			  false);
1164 	allow_sleep(true);
1165 	hl7800_unlock();
1166 	if (ret < 0) {
1167 		return ret;
1168 	} else {
1169 		return ictx.operator_index;
1170 	}
1171 }
1172 
mdm_hl7800_get_functionality(void)1173 int32_t mdm_hl7800_get_functionality(void)
1174 {
1175 	int ret;
1176 
1177 	hl7800_lock();
1178 	wakeup_hl7800();
1179 	ictx.last_socket_id = 0;
1180 	ret = send_at_cmd(NULL, "AT+CFUN?", MDM_CMD_SEND_TIMEOUT, 0, false);
1181 	allow_sleep(true);
1182 	hl7800_unlock();
1183 
1184 	if (ret < 0) {
1185 		return ret;
1186 	} else {
1187 		return ictx.functionality;
1188 	}
1189 }
1190 
mdm_hl7800_set_functionality(enum mdm_hl7800_functionality mode)1191 int32_t mdm_hl7800_set_functionality(enum mdm_hl7800_functionality mode)
1192 {
1193 	int ret;
1194 	char buf[sizeof("AT+CFUN=###,0")] = { 0 };
1195 
1196 	hl7800_lock();
1197 	wakeup_hl7800();
1198 	snprintk(buf, sizeof(buf), "AT+CFUN=%u,0", mode);
1199 	ictx.last_socket_id = 0;
1200 	ret = send_at_cmd(NULL, buf, MDM_CMD_SEND_TIMEOUT,
1201 			  MDM_DEFAULT_AT_CMD_RETRIES, false);
1202 	allow_sleep(true);
1203 	hl7800_unlock();
1204 
1205 	return ret;
1206 }
1207 
1208 #ifdef CONFIG_MODEM_HL7800_GPS
mdm_hl7800_set_gps_rate(uint32_t rate)1209 int32_t mdm_hl7800_set_gps_rate(uint32_t rate)
1210 {
1211 	int ret = -1;
1212 
1213 	hl7800_lock();
1214 	wakeup_hl7800();
1215 	ictx.gps_query_location_rate_seconds = rate;
1216 
1217 	/* Stopping first allows changing the rate between two non-zero values.
1218 	 * Ignore error if GNSS isn't running.
1219 	 */
1220 	SEND_AT_CMD_IGNORE_ERROR("AT+GNSSSTOP");
1221 
1222 	if (rate == 0) {
1223 		SEND_AT_CMD_EXPECT_OK("AT+CFUN=1,0");
1224 	} else {
1225 		/* Navigation doesn't work when LTE is on. */
1226 		SEND_AT_CMD_EXPECT_OK("AT+CFUN=4,0");
1227 
1228 		SEND_AT_CMD_EXPECT_OK("AT+GNSSCONF=1,1");
1229 
1230 		if (IS_ENABLED(CONFIG_MODEM_HL7800_USE_GLONASS)) {
1231 			SEND_AT_CMD_EXPECT_OK("AT+GNSSCONF=10,1");
1232 		}
1233 		/* Enable all NMEA sentences */
1234 		SEND_AT_CMD_EXPECT_OK("AT+GNSSNMEA=0,1000,0,1FF");
1235 		/* Enable GPS */
1236 		SEND_AT_CMD_EXPECT_OK("AT+GNSSSTART=0");
1237 	}
1238 
1239 error:
1240 	if (rate && ret == 0) {
1241 		k_work_reschedule_for_queue(&hl7800_workq, &ictx.gps_work,
1242 					    K_SECONDS(ictx.gps_query_location_rate_seconds));
1243 	} else {
1244 		k_work_cancel_delayable(&ictx.gps_work);
1245 	}
1246 	LOG_DBG("GPS status: %d rate: %u", ret, rate);
1247 
1248 	allow_sleep(true);
1249 	hl7800_unlock();
1250 	return ret;
1251 }
1252 #endif /* CONFIG_MODEM_HL7800_GPS */
1253 
1254 #ifdef CONFIG_MODEM_HL7800_POLTE
mdm_hl7800_polte_register(void)1255 int32_t mdm_hl7800_polte_register(void)
1256 {
1257 	int ret = -1;
1258 
1259 	hl7800_lock();
1260 	wakeup_hl7800();
1261 	/* register for events */
1262 	SEND_AT_CMD_EXPECT_OK("AT%POLTEEV=\"REGISTER\",1");
1263 	SEND_AT_CMD_EXPECT_OK("AT%POLTEEV=\"LOCATION\",1");
1264 	/* register with polte.io */
1265 	SEND_AT_CMD_EXPECT_OK("AT%POLTECMD=\"REGISTER\"");
1266 error:
1267 	LOG_DBG("PoLTE register status: %d", ret);
1268 	allow_sleep(true);
1269 	hl7800_unlock();
1270 	return ret;
1271 }
1272 
mdm_hl7800_polte_enable(char * user,char * password)1273 int32_t mdm_hl7800_polte_enable(char *user, char *password)
1274 {
1275 	int ret = -1;
1276 	char buf[sizeof(MDM_HL7800_SET_POLTE_USER_AND_PASSWORD_FMT_STR) +
1277 		 MDM_HL7800_MAX_POLTE_USER_ID_SIZE + MDM_HL7800_MAX_POLTE_PASSWORD_SIZE] = { 0 };
1278 
1279 	hl7800_lock();
1280 	wakeup_hl7800();
1281 
1282 	/* register for events */
1283 	SEND_AT_CMD_EXPECT_OK("AT%POLTEEV=\"REGISTER\",1");
1284 	SEND_AT_CMD_EXPECT_OK("AT%POLTEEV=\"LOCATION\",1");
1285 	/*  restore user and password (not saved in NV by modem) */
1286 	snprintk(buf, sizeof(buf), MDM_HL7800_SET_POLTE_USER_AND_PASSWORD_FMT_STR, user, password);
1287 	ret = send_at_cmd(NULL, buf, MDM_CMD_SEND_TIMEOUT, MDM_DEFAULT_AT_CMD_RETRIES, false);
1288 
1289 error:
1290 	LOG_DBG("PoLTE register status: %d", ret);
1291 	allow_sleep(true);
1292 	hl7800_unlock();
1293 	return ret;
1294 }
1295 
mdm_hl7800_polte_locate(void)1296 int32_t mdm_hl7800_polte_locate(void)
1297 {
1298 	int ret = -1;
1299 
1300 	hl7800_lock();
1301 	wakeup_hl7800();
1302 	SEND_AT_CMD_EXPECT_OK("AT%POLTECMD=\"LOCATE\",2,1");
1303 error:
1304 	LOG_DBG("PoLTE locate status: %d", ret);
1305 	allow_sleep(true);
1306 	hl7800_unlock();
1307 	return ret;
1308 }
1309 
1310 #endif /* CONFIG_MODEM_HL7800_POLTE */
1311 
1312 /**
1313  * @brief Perform a site survey.
1314  *
1315  */
mdm_hl7800_perform_site_survey(void)1316 int32_t mdm_hl7800_perform_site_survey(void)
1317 {
1318 	int ret;
1319 
1320 	hl7800_lock();
1321 	wakeup_hl7800();
1322 	ret = send_at_cmd(NULL, "at%meas=\"97\"", MDM_CMD_SEND_TIMEOUT, 0, false);
1323 	allow_sleep(true);
1324 	hl7800_unlock();
1325 	return ret;
1326 }
1327 
mdm_hl7800_generate_status_events(void)1328 void mdm_hl7800_generate_status_events(void)
1329 {
1330 	hl7800_lock();
1331 	generate_startup_state_event();
1332 	generate_network_state_event();
1333 	generate_sleep_state_event();
1334 #ifdef CONFIG_MODEM_HL7800_FW_UPDATE
1335 	generate_fota_state_event();
1336 #endif
1337 	event_handler(HL7800_EVENT_RSSI, &ictx.mdm_rssi);
1338 	event_handler(HL7800_EVENT_SINR, &ictx.mdm_sinr);
1339 	event_handler(HL7800_EVENT_APN_UPDATE, &ictx.mdm_apn);
1340 	event_handler(HL7800_EVENT_RAT, &ictx.mdm_rat);
1341 	event_handler(HL7800_EVENT_BANDS, ictx.mdm_bands_string);
1342 	event_handler(HL7800_EVENT_ACTIVE_BANDS, ictx.mdm_active_bands_string);
1343 	event_handler(HL7800_EVENT_REVISION, ictx.mdm_revision);
1344 	hl7800_unlock();
1345 }
1346 
mdm_hl7800_log_filter_set(uint32_t level)1347 uint32_t mdm_hl7800_log_filter_set(uint32_t level)
1348 {
1349 	uint32_t new_log_level = 0;
1350 
1351 #ifdef CONFIG_LOG_RUNTIME_FILTERING
1352 	new_log_level =
1353 		log_filter_set(NULL, Z_LOG_LOCAL_DOMAIN_ID,
1354 			       log_source_id_get(STRINGIFY(LOG_MODULE_NAME)),
1355 			       level);
1356 #endif
1357 
1358 	return new_log_level;
1359 }
1360 
send_data(struct hl7800_socket * sock,struct net_pkt * pkt)1361 static int send_data(struct hl7800_socket *sock, struct net_pkt *pkt)
1362 {
1363 	int ret;
1364 	struct net_buf *frag;
1365 	char dst_addr[NET_IPV6_ADDR_LEN];
1366 	char buf[sizeof("AT+KUDPSND=##,\"" IPV6_ADDR_FORMAT "\",#####,####")];
1367 	size_t send_len, actual_send_len;
1368 
1369 	send_len = 0, actual_send_len = 0;
1370 
1371 	if (!sock) {
1372 		return -EINVAL;
1373 	}
1374 
1375 	sock->error = 0;
1376 	sock->state = SOCK_TX;
1377 
1378 	frag = pkt->frags;
1379 	send_len = net_buf_frags_len(frag);
1380 	/* start sending data */
1381 	k_sem_reset(&sock->sock_send_sem);
1382 	if (sock->type == SOCK_STREAM) {
1383 		snprintk(buf, sizeof(buf), "AT+KTCPSND=%d,%zu", sock->socket_id,
1384 			 send_len);
1385 	} else {
1386 		if (!net_addr_ntop(sock->family, &net_sin(&sock->dst)->sin_addr,
1387 				   dst_addr, sizeof(dst_addr))) {
1388 			LOG_ERR("Invalid dst addr");
1389 			return -EINVAL;
1390 		}
1391 		snprintk(buf, sizeof(buf), "AT+KUDPSND=%d,\"%s\",%u,%zu",
1392 			 sock->socket_id, dst_addr,
1393 			 net_sin(&sock->dst)->sin_port, send_len);
1394 	}
1395 	send_at_cmd(sock, buf, K_NO_WAIT, 0, false);
1396 
1397 	/* wait for CONNECT  or error */
1398 	ret = k_sem_take(&sock->sock_send_sem, MDM_IP_SEND_RX_TIMEOUT);
1399 	if (ret) {
1400 		LOG_ERR("Err waiting for CONNECT (%d)", ret);
1401 		goto done;
1402 	}
1403 	/* check for error */
1404 	if (sock->error != 0) {
1405 		ret = sock->error;
1406 		LOG_ERR("AT+K**PSND (%d)", ret);
1407 		goto done;
1408 	}
1409 
1410 	/* Loop through packet data and send */
1411 	while (frag) {
1412 		actual_send_len += frag->len;
1413 		mdm_receiver_send(&ictx.mdm_ctx, frag->data, frag->len);
1414 		frag = frag->frags;
1415 	}
1416 	if (actual_send_len != send_len) {
1417 		LOG_WRN("AT+K**PSND act: %zd exp: %zd", actual_send_len,
1418 			send_len);
1419 	}
1420 	LOG_DBG("Sent %zu bytes", actual_send_len);
1421 
1422 	/* Send EOF pattern to terminate data */
1423 	k_sem_reset(&sock->sock_send_sem);
1424 	mdm_receiver_send(&ictx.mdm_ctx, EOF_PATTERN, strlen(EOF_PATTERN));
1425 	ret = k_sem_take(&sock->sock_send_sem, MDM_IP_SEND_RX_TIMEOUT);
1426 	if (ret == 0) {
1427 		ret = sock->error;
1428 	} else if (ret == -EAGAIN) {
1429 		ret = -ETIMEDOUT;
1430 	}
1431 done:
1432 	if (sock->type == SOCK_STREAM) {
1433 		if (sock->error == 0) {
1434 			sock->state = SOCK_CONNECTED;
1435 		}
1436 	} else {
1437 		sock->state = SOCK_IDLE;
1438 	}
1439 
1440 	return ret;
1441 }
1442 
1443 /*** NET_BUF HELPERS ***/
1444 
is_crlf(uint8_t c)1445 static bool is_crlf(uint8_t c)
1446 {
1447 	if (c == '\n' || c == '\r') {
1448 		return true;
1449 	} else {
1450 		return false;
1451 	}
1452 }
1453 
net_buf_skipcrlf(struct net_buf ** buf)1454 static void net_buf_skipcrlf(struct net_buf **buf)
1455 {
1456 	/* chop off any /n or /r */
1457 	while (*buf && is_crlf(*(*buf)->data)) {
1458 		net_buf_pull_u8(*buf);
1459 		if (!(*buf)->len) {
1460 			*buf = net_buf_frag_del(NULL, *buf);
1461 		}
1462 	}
1463 }
1464 
net_buf_findcrlf(struct net_buf * buf,struct net_buf ** frag)1465 static uint16_t net_buf_findcrlf(struct net_buf *buf, struct net_buf **frag)
1466 {
1467 	uint16_t len = 0U, pos = 0U;
1468 
1469 	while (buf && !is_crlf(*(buf->data + pos))) {
1470 		if (pos + 1 >= buf->len) {
1471 			len += buf->len;
1472 			buf = buf->frags;
1473 			pos = 0U;
1474 		} else {
1475 			pos++;
1476 		}
1477 	}
1478 
1479 	if (buf && is_crlf(*(buf->data + pos))) {
1480 		len += pos;
1481 		*frag = buf;
1482 		return len;
1483 	}
1484 
1485 	return 0;
1486 }
1487 
net_buf_get_u8(struct net_buf ** buf)1488 static uint8_t net_buf_get_u8(struct net_buf **buf)
1489 {
1490 	uint8_t val = net_buf_pull_u8(*buf);
1491 
1492 	if (!(*buf)->len) {
1493 		*buf = net_buf_frag_del(NULL, *buf);
1494 	}
1495 	return val;
1496 }
1497 
net_buf_remove(struct net_buf ** buf,uint32_t len)1498 static uint32_t net_buf_remove(struct net_buf **buf, uint32_t len)
1499 {
1500 	uint32_t to_remove;
1501 	uint32_t removed = 0;
1502 
1503 	while (*buf && len > 0) {
1504 		to_remove = (*buf)->len;
1505 		if (to_remove > len) {
1506 			to_remove = len;
1507 		}
1508 		net_buf_pull(*buf, to_remove);
1509 		removed += to_remove;
1510 		len -= to_remove;
1511 		if (!(*buf)->len) {
1512 			*buf = net_buf_frag_del(NULL, *buf);
1513 		}
1514 	}
1515 	return removed;
1516 }
1517 
1518 /*** UDP / TCP Helper Function ***/
1519 
1520 /* Setup IP header data to be used by some network applications.
1521  * While much is dummy data, some fields such as dst, port and family are
1522  * important.
1523  * Return the IP + protocol header length.
1524  */
pkt_setup_ip_data(struct net_pkt * pkt,struct hl7800_socket * sock)1525 static int pkt_setup_ip_data(struct net_pkt *pkt, struct hl7800_socket *sock)
1526 {
1527 	int hdr_len = 0;
1528 	uint16_t src_port = 0U, dst_port = 0U;
1529 #if defined(CONFIG_NET_TCP)
1530 	struct net_tcp_hdr *tcp;
1531 #endif
1532 
1533 #if defined(CONFIG_NET_IPV6)
1534 	if (net_pkt_family(pkt) == AF_INET6) {
1535 		if (net_ipv6_create(
1536 			    pkt,
1537 			    &((struct sockaddr_in6 *)&sock->dst)->sin6_addr,
1538 			    &((struct sockaddr_in6 *)&sock->src)->sin6_addr)) {
1539 			return -1;
1540 		}
1541 		src_port = ntohs(net_sin6(&sock->src)->sin6_port);
1542 		dst_port = ntohs(net_sin6(&sock->dst)->sin6_port);
1543 
1544 		hdr_len = sizeof(struct net_ipv6_hdr);
1545 	}
1546 #endif
1547 #if defined(CONFIG_NET_IPV4)
1548 	if (net_pkt_family(pkt) == AF_INET) {
1549 		if (net_ipv4_create(
1550 			    pkt, &((struct sockaddr_in *)&sock->dst)->sin_addr,
1551 			    &((struct sockaddr_in *)&sock->src)->sin_addr)) {
1552 			return -1;
1553 		}
1554 		src_port = ntohs(net_sin(&sock->src)->sin_port);
1555 		dst_port = ntohs(net_sin(&sock->dst)->sin_port);
1556 
1557 		hdr_len = sizeof(struct net_ipv4_hdr);
1558 	}
1559 #endif
1560 
1561 #if defined(CONFIG_NET_UDP)
1562 	if (sock->ip_proto == IPPROTO_UDP) {
1563 		if (net_udp_create(pkt, dst_port, src_port)) {
1564 			return -1;
1565 		}
1566 
1567 		hdr_len += NET_UDPH_LEN;
1568 	}
1569 #endif
1570 #if defined(CONFIG_NET_TCP)
1571 	if (sock->ip_proto == IPPROTO_TCP) {
1572 		NET_PKT_DATA_ACCESS_DEFINE(tcp_access, struct net_tcp_hdr);
1573 
1574 		tcp = (struct net_tcp_hdr *)net_pkt_get_data(pkt, &tcp_access);
1575 		if (!tcp) {
1576 			return -1;
1577 		}
1578 
1579 		(void)memset(tcp, 0, NET_TCPH_LEN);
1580 
1581 		/* Setup TCP header */
1582 		tcp->src_port = dst_port;
1583 		tcp->dst_port = src_port;
1584 
1585 		if (net_pkt_set_data(pkt, &tcp_access)) {
1586 			return -1;
1587 		}
1588 
1589 		hdr_len += NET_TCPH_LEN;
1590 	}
1591 #endif /* CONFIG_NET_TCP */
1592 
1593 	return hdr_len;
1594 }
1595 
1596 /*** MODEM RESPONSE HANDLERS ***/
1597 
wait_for_modem_data(struct net_buf ** buf,uint32_t current_len,uint32_t expected_len)1598 static uint32_t wait_for_modem_data(struct net_buf **buf, uint32_t current_len,
1599 				    uint32_t expected_len)
1600 {
1601 	uint32_t waitForDataTries = 0;
1602 
1603 	while ((current_len < expected_len) &&
1604 	       (waitForDataTries < MDM_WAIT_FOR_DATA_RETRIES)) {
1605 		LOG_DBG("cur:%d, exp:%d", current_len, expected_len);
1606 		k_sleep(MDM_WAIT_FOR_DATA_TIME);
1607 		current_len += hl7800_read_rx(buf);
1608 		waitForDataTries++;
1609 	}
1610 
1611 	return current_len;
1612 }
1613 
wait_for_modem_data_and_newline(struct net_buf ** buf,uint32_t current_len,uint32_t expected_len)1614 static uint32_t wait_for_modem_data_and_newline(struct net_buf **buf,
1615 						uint32_t current_len,
1616 						uint32_t expected_len)
1617 {
1618 	return wait_for_modem_data(buf, current_len,
1619 				   (expected_len + strlen("\r\n")));
1620 }
1621 
1622 /* Handler: AT+CGMI */
on_cmd_atcmdinfo_manufacturer(struct net_buf ** buf,uint16_t len)1623 static bool on_cmd_atcmdinfo_manufacturer(struct net_buf **buf, uint16_t len)
1624 {
1625 	struct net_buf *frag = NULL;
1626 	size_t out_len;
1627 	int len_no_null = MDM_MANUFACTURER_LENGTH - 1;
1628 
1629 	/* make sure revision data is received
1630 	 *  waiting for: Sierra Wireless\r\n
1631 	 */
1632 	wait_for_modem_data_and_newline(buf, net_buf_frags_len(*buf),
1633 					MDM_MANUFACTURER_LENGTH);
1634 
1635 	frag = NULL;
1636 	len = net_buf_findcrlf(*buf, &frag);
1637 	if (!frag) {
1638 		LOG_ERR("Unable to find mfg end");
1639 		goto done;
1640 	}
1641 	if (len < len_no_null) {
1642 		LOG_WRN("mfg too short (len:%d)", len);
1643 	} else if (len > len_no_null) {
1644 		LOG_WRN("mfg too long (len:%d)", len);
1645 		len = MDM_MANUFACTURER_LENGTH;
1646 	}
1647 
1648 	out_len = net_buf_linearize(ictx.mdm_manufacturer,
1649 				    sizeof(ictx.mdm_manufacturer) - 1, *buf, 0,
1650 				    len);
1651 	ictx.mdm_manufacturer[out_len] = 0;
1652 	LOG_INF("Manufacturer: %s", ictx.mdm_manufacturer);
1653 done:
1654 	return true;
1655 }
1656 
1657 /* Handler: AT+CGMM */
on_cmd_atcmdinfo_model(struct net_buf ** buf,uint16_t len)1658 static bool on_cmd_atcmdinfo_model(struct net_buf **buf, uint16_t len)
1659 {
1660 	struct net_buf *frag = NULL;
1661 	size_t out_len;
1662 	int len_no_null = MDM_MODEL_LENGTH - 1;
1663 
1664 	/* make sure model data is received
1665 	 *  waiting for: HL7800\r\n
1666 	 */
1667 	wait_for_modem_data_and_newline(buf, net_buf_frags_len(*buf),
1668 					MDM_MODEL_LENGTH);
1669 
1670 	frag = NULL;
1671 	len = net_buf_findcrlf(*buf, &frag);
1672 	if (!frag) {
1673 		LOG_ERR("Unable to find model end");
1674 		goto done;
1675 	}
1676 	if (len < len_no_null) {
1677 		LOG_WRN("model too short (len:%d)", len);
1678 	} else if (len > len_no_null) {
1679 		LOG_WRN("model too long (len:%d)", len);
1680 		len = MDM_MODEL_LENGTH;
1681 	}
1682 
1683 	out_len = net_buf_linearize(ictx.mdm_model, sizeof(ictx.mdm_model) - 1,
1684 				    *buf, 0, len);
1685 	ictx.mdm_model[out_len] = 0;
1686 	LOG_INF("Model: %s", ictx.mdm_model);
1687 done:
1688 	return true;
1689 }
1690 
1691 /* Handler: AT+CGMR */
on_cmd_atcmdinfo_revision(struct net_buf ** buf,uint16_t len)1692 static bool on_cmd_atcmdinfo_revision(struct net_buf **buf, uint16_t len)
1693 {
1694 	struct net_buf *frag = NULL;
1695 	size_t out_len;
1696 
1697 	/* make sure revision data is received
1698 	 *  waiting for something like: AHL7800.1.2.3.1.20171211\r\n
1699 	 */
1700 	wait_for_modem_data_and_newline(buf, net_buf_frags_len(*buf),
1701 					MDM_HL7800_REVISION_MAX_SIZE);
1702 
1703 	frag = NULL;
1704 	len = net_buf_findcrlf(*buf, &frag);
1705 	if (!frag) {
1706 		LOG_ERR("Unable to find rev end");
1707 		goto done;
1708 	}
1709 	if (len == 0) {
1710 		LOG_WRN("revision not found");
1711 	} else if (len > MDM_HL7800_REVISION_MAX_STRLEN) {
1712 		LOG_WRN("revision too long (len:%d)", len);
1713 		len = MDM_HL7800_REVISION_MAX_STRLEN;
1714 	}
1715 
1716 	out_len = net_buf_linearize(
1717 		ictx.mdm_revision, sizeof(ictx.mdm_revision) - 1, *buf, 0, len);
1718 	ictx.mdm_revision[out_len] = 0;
1719 	LOG_INF("Revision: %s", ictx.mdm_revision);
1720 	event_handler(HL7800_EVENT_REVISION, ictx.mdm_revision);
1721 done:
1722 	return true;
1723 }
1724 
1725 /* Handler: AT+CGSN */
on_cmd_atcmdinfo_imei(struct net_buf ** buf,uint16_t len)1726 static bool on_cmd_atcmdinfo_imei(struct net_buf **buf, uint16_t len)
1727 {
1728 	struct net_buf *frag = NULL;
1729 	size_t out_len;
1730 
1731 	/* make sure IMEI data is received
1732 	 *  waiting for: ###############\r\n
1733 	 */
1734 	wait_for_modem_data_and_newline(buf, net_buf_frags_len(*buf),
1735 					MDM_HL7800_IMEI_SIZE);
1736 
1737 	frag = NULL;
1738 	len = net_buf_findcrlf(*buf, &frag);
1739 	if (!frag) {
1740 		LOG_ERR("Unable to find IMEI end");
1741 		goto done;
1742 	}
1743 	if (len < MDM_HL7800_IMEI_STRLEN) {
1744 		LOG_WRN("IMEI too short (len:%d)", len);
1745 	} else if (len > MDM_HL7800_IMEI_STRLEN) {
1746 		LOG_WRN("IMEI too long (len:%d)", len);
1747 		len = MDM_HL7800_IMEI_STRLEN;
1748 	}
1749 
1750 	out_len = net_buf_linearize(ictx.mdm_imei, sizeof(ictx.mdm_imei) - 1,
1751 				    *buf, 0, len);
1752 	ictx.mdm_imei[out_len] = 0;
1753 
1754 	LOG_INF("IMEI: %s", ictx.mdm_imei);
1755 done:
1756 	return true;
1757 }
1758 
1759 /* Handler: +CCID: <ICCID>,<EID>
1760  * NOTE: EID will only be present for eSIM
1761  */
on_cmd_atcmdinfo_iccid(struct net_buf ** buf,uint16_t len)1762 static bool on_cmd_atcmdinfo_iccid(struct net_buf **buf, uint16_t len)
1763 {
1764 	int ret;
1765 	char value[MDM_CCID_RESP_MAX_SIZE];
1766 	char *delim;
1767 	size_t out_len;
1768 
1769 	out_len = net_buf_linearize(value, sizeof(value), *buf, 0, len);
1770 	value[out_len] = 0;
1771 
1772 	LOG_DBG("+CCID: %s", value);
1773 
1774 	if (len > MDM_HL7800_ICCID_MAX_STRLEN) {
1775 		delim = strchr(value, ',');
1776 		if (!delim) {
1777 			LOG_ERR("Could not process +CCID");
1778 			return true;
1779 		}
1780 		/* Replace ',' with null so value contains two null terminated strings */
1781 		*delim = 0;
1782 		LOG_INF("EID: %s", delim + 1);
1783 	}
1784 
1785 	ret = snprintk(ictx.mdm_iccid, sizeof(ictx.mdm_iccid), "%s", value);
1786 	if (ret > MDM_HL7800_ICCID_MAX_STRLEN) {
1787 		LOG_WRN("ICCID too long: %d", ret);
1788 	}
1789 
1790 	LOG_INF("ICCID: %s", ictx.mdm_iccid);
1791 
1792 	return true;
1793 }
1794 
on_cmd_atcmdinfo_imsi(struct net_buf ** buf,uint16_t len)1795 static bool on_cmd_atcmdinfo_imsi(struct net_buf **buf, uint16_t len)
1796 {
1797 	struct net_buf *frag = NULL;
1798 	size_t out_len;
1799 
1800 	/* The handler for the IMSI is based on the command.
1801 	 *  waiting for: <IMSI>\r\n
1802 	 */
1803 	wait_for_modem_data_and_newline(buf, net_buf_frags_len(*buf),
1804 					MDM_HL7800_IMSI_MIN_STR_SIZE);
1805 
1806 	frag = NULL;
1807 	len = net_buf_findcrlf(*buf, &frag);
1808 	if (!frag) {
1809 		LOG_ERR("Unable to find IMSI end");
1810 		goto done;
1811 	}
1812 	if (len > MDM_HL7800_IMSI_MAX_STRLEN) {
1813 		LOG_WRN("IMSI too long (len:%d)", len);
1814 		len = MDM_HL7800_IMSI_MAX_STRLEN;
1815 	}
1816 
1817 	out_len = net_buf_linearize(ictx.mdm_imsi, MDM_HL7800_IMSI_MAX_STR_SIZE,
1818 				    *buf, 0, len);
1819 	ictx.mdm_imsi[out_len] = 0;
1820 
1821 	if (strstr(ictx.mdm_imsi, "ERROR") != NULL) {
1822 		LOG_ERR("Unable to read IMSI");
1823 		memset(ictx.mdm_imsi, 0, sizeof(ictx.mdm_imsi));
1824 	}
1825 
1826 	LOG_INF("IMSI: %s", ictx.mdm_imsi);
1827 done:
1828 	return true;
1829 }
1830 
dns_work_cb(struct k_work * work)1831 static void dns_work_cb(struct k_work *work)
1832 {
1833 #if defined(CONFIG_DNS_RESOLVER) && !defined(CONFIG_DNS_SERVER_IP_ADDRESSES)
1834 	int ret;
1835 	struct dns_resolve_context *dnsCtx;
1836 	struct sockaddr temp_addr;
1837 	bool valid_address = false;
1838 	static const char *const dns_servers_str[] = {
1839 #ifdef CONFIG_NET_IPV6
1840 		ictx.dns_v6_string,
1841 #endif
1842 #ifdef CONFIG_NET_IPV4
1843 		ictx.dns_v4_string,
1844 #endif
1845 		NULL};
1846 
1847 #ifdef CONFIG_NET_IPV6
1848 	valid_address =
1849 		net_ipaddr_parse(ictx.dns_v6_string, strlen(ictx.dns_v6_string), &temp_addr);
1850 	if (!valid_address && IS_ENABLED(CONFIG_NET_IPV4)) {
1851 		/* IPv6 DNS string is not valid, replace it with IPv4 address and recheck */
1852 		strncpy(ictx.dns_v6_string, ictx.dns_v4_string, strlen(ictx.dns_v4_string));
1853 		valid_address = net_ipaddr_parse(ictx.dns_v6_string, strlen(ictx.dns_v6_string),
1854 						 &temp_addr);
1855 	}
1856 #else
1857 	valid_address =
1858 		net_ipaddr_parse(ictx.dns_v4_string, strlen(ictx.dns_v4_string), &temp_addr);
1859 #endif
1860 
1861 	if (!valid_address) {
1862 		LOG_WRN("No valid DNS address!");
1863 	} else if (ictx.iface && net_if_is_up(ictx.iface) && !ictx.dns_ready) {
1864 		/* set new DNS addr in DNS resolver */
1865 		LOG_DBG("Refresh DNS resolver");
1866 		dnsCtx = dns_resolve_get_default();
1867 		ret = dns_resolve_reconfigure(dnsCtx, (const char **)dns_servers_str, NULL);
1868 		if (ret < 0) {
1869 			LOG_ERR("dns_resolve_init fail (%d)", ret);
1870 			return;
1871 		}
1872 		ictx.dns_ready = true;
1873 	}
1874 #endif
1875 }
1876 
mdm_hl7800_get_iccid(void)1877 char *mdm_hl7800_get_iccid(void)
1878 {
1879 	return ictx.mdm_iccid;
1880 }
1881 
mdm_hl7800_get_sn(void)1882 char *mdm_hl7800_get_sn(void)
1883 {
1884 	return ictx.mdm_sn;
1885 }
1886 
mdm_hl7800_get_imei(void)1887 char *mdm_hl7800_get_imei(void)
1888 {
1889 	return ictx.mdm_imei;
1890 }
1891 
mdm_hl7800_get_fw_version(void)1892 char *mdm_hl7800_get_fw_version(void)
1893 {
1894 	return ictx.mdm_revision;
1895 }
1896 
mdm_hl7800_get_imsi(void)1897 char *mdm_hl7800_get_imsi(void)
1898 {
1899 	return ictx.mdm_imsi;
1900 }
1901 
1902 /* Convert HL7800 IPv6 address string in format
1903  * a01.a02.a03.a04.a05.a06.a07.a08.a09.a10.a11.a12.a13.a14.a15.a16 to
1904  * an IPv6 address.
1905  */
hl7800_net_addr6_pton(const char * src,struct in6_addr * dst)1906 static int hl7800_net_addr6_pton(const char *src, struct in6_addr *dst)
1907 {
1908 	int num_sections = 8;
1909 	int i, len;
1910 	uint16_t ipv6_section;
1911 
1912 	len = strlen(src);
1913 	for (i = 0; i < len; i++) {
1914 		if (!(src[i] >= '0' && src[i] <= '9') && src[i] != '.') {
1915 			return -EINVAL;
1916 		}
1917 	}
1918 
1919 	for (i = 0; i < num_sections; i++) {
1920 		if (!src || *src == '\0') {
1921 			return -EINVAL;
1922 		}
1923 
1924 		ipv6_section = (uint16_t)strtol(src, NULL, 10);
1925 		src = strchr(src, '.');
1926 		src++;
1927 		if (!src || *src == '\0') {
1928 			return -EINVAL;
1929 		}
1930 		ipv6_section = (ipv6_section << 8) | (uint16_t)strtol(src, NULL, 10);
1931 		UNALIGNED_PUT(htons(ipv6_section), &dst->s6_addr16[i]);
1932 
1933 		src = strchr(src, '.');
1934 		if (src) {
1935 			src++;
1936 		} else {
1937 			if (i < num_sections - 1) {
1938 				return -EINVAL;
1939 			}
1940 		}
1941 	}
1942 
1943 	return 0;
1944 }
1945 
1946 /* Handler: +CGCONTRDP: <cid>,<bearer_id>,<apn>,<local_addr and subnet_mask>,
1947  *			<gw_addr>,<DNS_prim_addr>,<DNS_sec_addr>
1948  */
on_cmd_atcmdinfo_ipaddr(struct net_buf ** buf,uint16_t len)1949 static bool on_cmd_atcmdinfo_ipaddr(struct net_buf **buf, uint16_t len)
1950 {
1951 	int ret;
1952 	int num_delims = CGCONTRDP_RESPONSE_NUM_DELIMS;
1953 	char *delims[CGCONTRDP_RESPONSE_NUM_DELIMS];
1954 	size_t out_len;
1955 	char value[MDM_IP_INFO_RESP_SIZE];
1956 	char *search_start, *addr_start, *sm_start;
1957 	struct in_addr new_ipv4_addr;
1958 	struct in6_addr new_ipv6_addr;
1959 	bool is_ipv4;
1960 	int addr_len;
1961 	char temp_addr_str[HL7800_IPV6_ADDR_LEN];
1962 	k_timeout_t delay;
1963 
1964 	out_len = net_buf_linearize(value, sizeof(value), *buf, 0, len);
1965 	value[out_len] = 0;
1966 	search_start = value;
1967 	LOG_DBG("IP info: %s", value);
1968 
1969 	/* find all delimiters (,) */
1970 	for (int i = 0; i < num_delims; i++) {
1971 		delims[i] = strchr(search_start, ',');
1972 		if (!delims[i]) {
1973 			LOG_ERR("Could not find delim %d, val: %s", i,
1974 				value);
1975 			return true;
1976 		}
1977 		/* Start next search after current delim location */
1978 		search_start = delims[i] + 1;
1979 	}
1980 
1981 	/* determine if IPv4 or IPv6 by checking length of ip address plus
1982 	 * gateway string.
1983 	 */
1984 	is_ipv4 = false;
1985 	addr_len = delims[3] - delims[2];
1986 	LOG_DBG("IP string len: %d", addr_len);
1987 	if (addr_len <= (NET_IPV4_ADDR_LEN * 2)) {
1988 		is_ipv4 = true;
1989 	}
1990 
1991 	/* Find start of subnet mask */
1992 	addr_start = delims[2] + 1;
1993 	if (is_ipv4) {
1994 		num_delims = 4;
1995 	} else {
1996 		num_delims = 16;
1997 	}
1998 	search_start = addr_start;
1999 	sm_start = addr_start;
2000 	for (int i = 0; i < num_delims; i++) {
2001 		sm_start = strchr(search_start, '.');
2002 		if (!sm_start) {
2003 			LOG_ERR("Could not find submask start");
2004 			return true;
2005 		}
2006 		/* Start next search after current delim location */
2007 		search_start = sm_start + 1;
2008 	}
2009 
2010 	/* get new IP addr */
2011 	addr_len = sm_start - addr_start;
2012 	strncpy(temp_addr_str, addr_start, addr_len);
2013 	temp_addr_str[addr_len] = 0;
2014 	LOG_DBG("IP addr: %s", temp_addr_str);
2015 	if (is_ipv4) {
2016 		ret = net_addr_pton(AF_INET, temp_addr_str, &new_ipv4_addr);
2017 	} else {
2018 		ret = hl7800_net_addr6_pton(temp_addr_str, &new_ipv6_addr);
2019 	}
2020 	if (ret < 0) {
2021 		LOG_ERR("Invalid IP addr");
2022 		return true;
2023 	}
2024 
2025 	if (is_ipv4) {
2026 		/* move past the '.' */
2027 		sm_start += 1;
2028 		/* store new subnet mask */
2029 		addr_len = delims[3] - sm_start;
2030 		strncpy(temp_addr_str, sm_start, addr_len);
2031 		temp_addr_str[addr_len] = 0;
2032 		ret = net_addr_pton(AF_INET, temp_addr_str, &ictx.subnet);
2033 		if (ret < 0) {
2034 			LOG_ERR("Invalid subnet");
2035 			return true;
2036 		}
2037 
2038 		/* store new gateway */
2039 		addr_start = delims[3] + 1;
2040 		addr_len = delims[4] - addr_start;
2041 		strncpy(temp_addr_str, addr_start, addr_len);
2042 		temp_addr_str[addr_len] = 0;
2043 		ret = net_addr_pton(AF_INET, temp_addr_str, &ictx.gateway);
2044 		if (ret < 0) {
2045 			LOG_ERR("Invalid gateway");
2046 			return true;
2047 		}
2048 	}
2049 
2050 	/* store new dns */
2051 	addr_start = delims[4] + 1;
2052 	addr_len = delims[5] - addr_start;
2053 	strncpy(temp_addr_str, addr_start, addr_len);
2054 	temp_addr_str[addr_len] = 0;
2055 	if (is_ipv4) {
2056 		ret = strncmp(temp_addr_str, ictx.dns_v4_string, addr_len);
2057 		if (ret != 0) {
2058 			ictx.dns_ready = false;
2059 		}
2060 		strncpy(ictx.dns_v4_string, addr_start, addr_len);
2061 		ictx.dns_v4_string[addr_len] = 0;
2062 		ret = net_addr_pton(AF_INET, ictx.dns_v4_string, &ictx.dns_v4);
2063 		LOG_DBG("IPv4 DNS addr: %s", ictx.dns_v4_string);
2064 	}
2065 #ifdef CONFIG_NET_IPV6
2066 	else {
2067 		ret = strncmp(temp_addr_str, ictx.dns_v6_string, addr_len);
2068 		if (ret != 0) {
2069 			ictx.dns_ready = false;
2070 		}
2071 		/* store HL7800 formatted IPv6 DNS string temporarily */
2072 		strncpy(ictx.dns_v6_string, addr_start, addr_len);
2073 
2074 		ret = hl7800_net_addr6_pton(ictx.dns_v6_string, &ictx.dns_v6);
2075 		net_addr_ntop(AF_INET6, &ictx.dns_v6, ictx.dns_v6_string,
2076 			      sizeof(ictx.dns_v6_string));
2077 		LOG_DBG("IPv6 DNS addr: %s", ictx.dns_v6_string);
2078 	}
2079 #endif
2080 	if (ret < 0) {
2081 		LOG_ERR("Invalid dns");
2082 		return true;
2083 	}
2084 
2085 	if (ictx.iface) {
2086 		if (is_ipv4) {
2087 #ifdef CONFIG_NET_IPV4
2088 			/* remove the current IPv4 addr before adding a new one.
2089 			 * We dont care if it is successful or not.
2090 			 */
2091 			net_if_ipv4_addr_rm(ictx.iface, &ictx.ipv4Addr);
2092 
2093 			if (!net_if_ipv4_addr_add(ictx.iface, &new_ipv4_addr, NET_ADDR_DHCP, 0)) {
2094 				LOG_ERR("Cannot set iface IPv4 addr");
2095 			}
2096 
2097 			net_if_ipv4_set_netmask(ictx.iface, &ictx.subnet);
2098 			net_if_ipv4_set_gw(ictx.iface, &ictx.gateway);
2099 #endif
2100 			/* store the new IP addr */
2101 			net_ipaddr_copy(&ictx.ipv4Addr, &new_ipv4_addr);
2102 		} else {
2103 #if CONFIG_NET_IPV6
2104 			net_if_ipv6_addr_rm(ictx.iface, &ictx.ipv6Addr);
2105 			if (!net_if_ipv6_addr_add(ictx.iface, &new_ipv6_addr, NET_ADDR_AUTOCONF,
2106 						  0)) {
2107 				LOG_ERR("Cannot set iface IPv6 addr");
2108 			}
2109 #endif
2110 		}
2111 
2112 		/* start DNS update work */
2113 		delay = K_NO_WAIT;
2114 		if (!ictx.initialized) {
2115 			/* Delay this in case the network
2116 			 * stack is still starting up
2117 			 */
2118 			delay = K_SECONDS(DNS_WORK_DELAY_SECS);
2119 		}
2120 		k_work_reschedule_for_queue(&hl7800_workq, &ictx.dns_work,
2121 					    delay);
2122 	} else {
2123 		LOG_ERR("iface NULL");
2124 	}
2125 
2126 	return true;
2127 }
2128 
2129 /* Handler1: +COPS: <mode>[,<format>,<oper>[,<AcT>]]
2130  *
2131  * Handler2:
2132  * +COPS: [list of supported (<stat>, long alphanumeric <oper>, short
2133  * alphanumeric <oper>, numeric <oper>[,< AcT>])s][,,
2134  * (list of supported <mode>s),(list of supported <format>s)]
2135  */
on_cmd_atcmdinfo_operator_status(struct net_buf ** buf,uint16_t len)2136 static bool on_cmd_atcmdinfo_operator_status(struct net_buf **buf, uint16_t len)
2137 {
2138 	size_t out_len;
2139 	char value[MDM_MAX_RESP_SIZE];
2140 	int num_delims = COPS_RESPONSE_NUM_DELIMS;
2141 	char *delims[COPS_RESPONSE_NUM_DELIMS];
2142 	char *search_start;
2143 	int i;
2144 
2145 	out_len = net_buf_linearize(value, sizeof(value), *buf, 0, len);
2146 	value[out_len] = 0;
2147 
2148 	/* For AT+COPS=?, result is most likely longer than size of log string */
2149 	if (strchr(value, '(') != NULL) {
2150 		LOG_HEXDUMP_DBG(value, out_len, "Operator: ");
2151 		goto done;
2152 	} else {
2153 		LOG_INF("Operator: %s", value);
2154 	}
2155 
2156 	/* Process AT+COPS? */
2157 	if (len == 1) {
2158 		/* only mode was returned, there is no operator info */
2159 		ictx.operator_status = NO_OPERATOR;
2160 		goto done;
2161 	}
2162 
2163 	search_start = value;
2164 
2165 	/* find all delimiters (,) */
2166 	for (i = 0; i < num_delims; i++) {
2167 		delims[i] = strchr(search_start, ',');
2168 		if (!delims[i]) {
2169 			LOG_ERR("Could not find delim %d, val: %s", i, value);
2170 			goto done;
2171 		}
2172 		/* Start next search after current delim location */
2173 		search_start = delims[i] + 1;
2174 	}
2175 
2176 	/* we found both delimiters, that means we have an operator */
2177 	ictx.operator_status = REGISTERED;
2178 done:
2179 	return true;
2180 }
2181 
2182 /* Handler: +KGSN: T5640400011101 */
on_cmd_atcmdinfo_serial_number(struct net_buf ** buf,uint16_t len)2183 static bool on_cmd_atcmdinfo_serial_number(struct net_buf **buf, uint16_t len)
2184 {
2185 	struct net_buf *frag = NULL;
2186 	char value[MDM_SN_RESPONSE_LENGTH];
2187 	size_t out_len;
2188 	int sn_len;
2189 	char *val_start;
2190 
2191 	/* make sure SN# data is received.
2192 	 *  we are waiting for: +KGSN: ##############\r\n
2193 	 */
2194 	wait_for_modem_data(buf, net_buf_frags_len(*buf),
2195 			    MDM_SN_RESPONSE_LENGTH);
2196 
2197 	frag = NULL;
2198 	len = net_buf_findcrlf(*buf, &frag);
2199 	if (!frag) {
2200 		LOG_ERR("Unable to find sn end");
2201 		goto done;
2202 	}
2203 
2204 	/* get msg data */
2205 	out_len = net_buf_linearize(value, sizeof(value), *buf, 0, len);
2206 	value[out_len] = 0;
2207 
2208 	/* find ':' */
2209 	val_start = strchr(value, ':');
2210 	if (!val_start) {
2211 		LOG_ERR("Unable to find sn ':'");
2212 		goto done;
2213 	}
2214 	/* Remove ": " chars */
2215 	val_start += 2;
2216 
2217 	sn_len = len - (val_start - value);
2218 	if (sn_len < MDM_HL7800_SERIAL_NUMBER_STRLEN) {
2219 		LOG_WRN("sn too short (len:%d)", sn_len);
2220 	} else if (sn_len > MDM_HL7800_SERIAL_NUMBER_STRLEN) {
2221 		LOG_WRN("sn too long (len:%d)", sn_len);
2222 		sn_len = MDM_HL7800_SERIAL_NUMBER_STRLEN;
2223 	}
2224 
2225 	strncpy(ictx.mdm_sn, val_start, sn_len);
2226 	ictx.mdm_sn[sn_len] = 0;
2227 	LOG_INF("Serial #: %s", ictx.mdm_sn);
2228 done:
2229 	return true;
2230 }
2231 
2232 /* Handler: +KSRAT: # */
on_cmd_radio_tech_status(struct net_buf ** buf,uint16_t len)2233 static bool on_cmd_radio_tech_status(struct net_buf **buf, uint16_t len)
2234 {
2235 	size_t out_len;
2236 	char value[MDM_MAX_RESP_SIZE];
2237 
2238 	out_len = net_buf_linearize(value, sizeof(value), *buf, 0, len);
2239 	value[out_len] = 0;
2240 	ictx.mdm_rat = strtol(value, NULL, 10);
2241 	LOG_INF("+KSRAT: %d", ictx.mdm_rat);
2242 	event_handler(HL7800_EVENT_RAT, &ictx.mdm_rat);
2243 
2244 	return true;
2245 }
2246 
2247 /* Handler: +KBNDCFG: #,####################### */
on_cmd_radio_band_configuration(struct net_buf ** buf,uint16_t len)2248 static bool on_cmd_radio_band_configuration(struct net_buf **buf, uint16_t len)
2249 {
2250 	size_t out_len;
2251 	char value[MDM_MAX_RESP_SIZE];
2252 	char n_tmp[sizeof("#########")];
2253 
2254 	out_len = net_buf_linearize(value, sizeof(value), *buf, 0, len);
2255 	value[out_len] = 0;
2256 
2257 	if (value[0] != (ictx.mdm_rat == MDM_RAT_CAT_M1 ? '0' : '1')) {
2258 		/* Invalid RAT */
2259 		return true;
2260 	} else if (strlen(value) < sizeof("#,###################")) {
2261 		/* String size too short */
2262 		return true;
2263 	}
2264 
2265 	memcpy(ictx.mdm_bands_string, &value[MDM_TOP_BAND_START_POSITION],
2266 	       MDM_HL7800_LTE_BAND_STRLEN);
2267 
2268 	memcpy(n_tmp, &value[MDM_TOP_BAND_START_POSITION], MDM_TOP_BAND_SIZE);
2269 	n_tmp[MDM_TOP_BAND_SIZE] = 0;
2270 	ictx.mdm_bands_top = strtoul(n_tmp, NULL, 16);
2271 
2272 	memcpy(n_tmp, &value[MDM_MIDDLE_BAND_START_POSITION],
2273 	       MDM_MIDDLE_BAND_SIZE);
2274 	n_tmp[MDM_MIDDLE_BAND_SIZE] = 0;
2275 	ictx.mdm_bands_middle = strtoul(n_tmp, NULL, 16);
2276 
2277 	memcpy(n_tmp, &value[MDM_BOTTOM_BAND_START_POSITION],
2278 	       MDM_BOTTOM_BAND_SIZE);
2279 	n_tmp[MDM_BOTTOM_BAND_SIZE] = 0;
2280 	ictx.mdm_bands_bottom = strtoul(n_tmp, NULL, 16);
2281 
2282 	LOG_INF("Current band configuration: %04x %08x %08x",
2283 		ictx.mdm_bands_top, ictx.mdm_bands_middle,
2284 		ictx.mdm_bands_bottom);
2285 
2286 	event_handler(HL7800_EVENT_BANDS, ictx.mdm_bands_string);
2287 
2288 	return true;
2289 }
2290 
2291 /* Handler: +KBND: #,####################### */
on_cmd_radio_active_bands(struct net_buf ** buf,uint16_t len)2292 static bool on_cmd_radio_active_bands(struct net_buf **buf, uint16_t len)
2293 {
2294 	size_t out_len;
2295 	char value[MDM_MAX_RESP_SIZE];
2296 
2297 	out_len = net_buf_linearize(value, sizeof(value), *buf, 0, len);
2298 	value[out_len] = 0;
2299 
2300 	if (strlen(value) < sizeof("#,###################")) {
2301 		/* String size too short */
2302 		return true;
2303 	}
2304 
2305 	memcpy(ictx.mdm_active_bands_string,
2306 	       &value[MDM_TOP_BAND_START_POSITION], MDM_HL7800_LTE_BAND_STRLEN);
2307 	event_handler(HL7800_EVENT_ACTIVE_BANDS, ictx.mdm_active_bands_string);
2308 
2309 	return true;
2310 }
2311 
get_startup_state_string(enum mdm_hl7800_startup_state state)2312 static char *get_startup_state_string(enum mdm_hl7800_startup_state state)
2313 {
2314 	/* clang-format off */
2315 	switch (state) {
2316 		PREFIXED_SWITCH_CASE_RETURN_STRING(HL7800_STARTUP_STATE, READY);
2317 		PREFIXED_SWITCH_CASE_RETURN_STRING(HL7800_STARTUP_STATE, WAITING_FOR_ACCESS_CODE);
2318 		PREFIXED_SWITCH_CASE_RETURN_STRING(HL7800_STARTUP_STATE, SIM_NOT_PRESENT);
2319 		PREFIXED_SWITCH_CASE_RETURN_STRING(HL7800_STARTUP_STATE, SIMLOCK);
2320 		PREFIXED_SWITCH_CASE_RETURN_STRING(HL7800_STARTUP_STATE, UNRECOVERABLE_ERROR);
2321 		PREFIXED_SWITCH_CASE_RETURN_STRING(HL7800_STARTUP_STATE, UNKNOWN);
2322 		PREFIXED_SWITCH_CASE_RETURN_STRING(HL7800_STARTUP_STATE, INACTIVE_SIM);
2323 	default:
2324 		return "UNKNOWN";
2325 	}
2326 	/* clang-format on */
2327 }
2328 
set_startup_state(enum mdm_hl7800_startup_state state)2329 static void set_startup_state(enum mdm_hl7800_startup_state state)
2330 {
2331 	ictx.mdm_startup_state = state;
2332 	generate_startup_state_event();
2333 }
2334 
generate_startup_state_event(void)2335 static void generate_startup_state_event(void)
2336 {
2337 	struct mdm_hl7800_compound_event event;
2338 
2339 	event.code = ictx.mdm_startup_state;
2340 	event.string = get_startup_state_string(ictx.mdm_startup_state);
2341 	LOG_INF("Startup State: %s", event.string);
2342 	event_handler(HL7800_EVENT_STARTUP_STATE_CHANGE, &event);
2343 }
2344 
mdm_hl7800_set_desired_sleep_level(enum mdm_hl7800_sleep level)2345 int mdm_hl7800_set_desired_sleep_level(enum mdm_hl7800_sleep level)
2346 {
2347 	int r = -EPERM;
2348 
2349 #if CONFIG_MODEM_HL7800_LOW_POWER_MODE
2350 	switch (level) {
2351 	case HL7800_SLEEP_AWAKE:
2352 	case HL7800_SLEEP_HIBERNATE:
2353 	case HL7800_SLEEP_LITE_HIBERNATE:
2354 	case HL7800_SLEEP_SLEEP:
2355 		ictx.desired_sleep_level = level;
2356 		r = 0;
2357 		break;
2358 	default:
2359 		r = -EINVAL;
2360 	}
2361 
2362 	if (r == 0) {
2363 		hl7800_lock();
2364 		wakeup_hl7800();
2365 		r = set_sleep_level();
2366 		allow_sleep(true);
2367 		hl7800_unlock();
2368 	}
2369 #endif
2370 
2371 	return r;
2372 }
2373 
2374 #ifdef CONFIG_MODEM_HL7800_LOW_POWER_MODE
2375 
initialize_sleep_level(void)2376 static void initialize_sleep_level(void)
2377 {
2378 	if (ictx.desired_sleep_level == HL7800_SLEEP_UNINITIALIZED) {
2379 		if (IS_ENABLED(CONFIG_MODEM_HL7800_SLEEP_LEVEL_HIBERNATE)) {
2380 			ictx.desired_sleep_level = HL7800_SLEEP_HIBERNATE;
2381 		} else if (IS_ENABLED(CONFIG_MODEM_HL7800_SLEEP_LEVEL_LITE_HIBERNATE)) {
2382 			ictx.desired_sleep_level = HL7800_SLEEP_LITE_HIBERNATE;
2383 		} else if (IS_ENABLED(CONFIG_MODEM_HL7800_SLEEP_LEVEL_SLEEP)) {
2384 			ictx.desired_sleep_level = HL7800_SLEEP_SLEEP;
2385 		} else {
2386 			ictx.desired_sleep_level = HL7800_SLEEP_AWAKE;
2387 		}
2388 	}
2389 }
2390 
set_sleep_level(void)2391 static int set_sleep_level(void)
2392 {
2393 	char cmd[sizeof("AT+KSLEEP=#,#,##")];
2394 	static const char SLEEP_CMD_FMT[] = "AT+KSLEEP=%d,%d,%d";
2395 	int delay = CONFIG_MODEM_HL7800_SLEEP_DELAY_AFTER_REBOOT;
2396 	int ret = 0;
2397 
2398 	/* AT+KSLEEP= <management>[,<level>[,<delay to sleep after reboot>]]
2399 	 * management 1 means the HL7800 decides when it enters sleep mode
2400 	 */
2401 	switch (ictx.desired_sleep_level) {
2402 	case HL7800_SLEEP_HIBERNATE:
2403 		snprintk(cmd, sizeof(cmd), SLEEP_CMD_FMT, 1, 2, delay);
2404 		break;
2405 	case HL7800_SLEEP_LITE_HIBERNATE:
2406 		snprintk(cmd, sizeof(cmd), SLEEP_CMD_FMT, 1, 1, delay);
2407 		break;
2408 	case HL7800_SLEEP_SLEEP:
2409 		snprintk(cmd, sizeof(cmd), SLEEP_CMD_FMT, 1, 0, delay);
2410 		break;
2411 	default:
2412 		/* don't sleep */
2413 		snprintk(cmd, sizeof(cmd), SLEEP_CMD_FMT, 2, 0, delay);
2414 		break;
2415 	}
2416 
2417 	SEND_AT_CMD_EXPECT_OK(cmd);
2418 
2419 error:
2420 	return ret;
2421 }
2422 
2423 #endif /* CONFIG_MODEM_HL7800_LOW_POWER_MODE */
2424 
get_sleep_state_string(enum mdm_hl7800_sleep state)2425 static char *get_sleep_state_string(enum mdm_hl7800_sleep state)
2426 {
2427 	/* clang-format off */
2428 	switch (state) {
2429 		PREFIXED_SWITCH_CASE_RETURN_STRING(HL7800_SLEEP, UNINITIALIZED);
2430 		PREFIXED_SWITCH_CASE_RETURN_STRING(HL7800_SLEEP, HIBERNATE);
2431 		PREFIXED_SWITCH_CASE_RETURN_STRING(HL7800_SLEEP, LITE_HIBERNATE);
2432 		PREFIXED_SWITCH_CASE_RETURN_STRING(HL7800_SLEEP, SLEEP);
2433 		PREFIXED_SWITCH_CASE_RETURN_STRING(HL7800_SLEEP, AWAKE);
2434 	default:
2435 		return "UNKNOWN";
2436 	}
2437 	/* clang-format on */
2438 }
2439 
set_sleep_state(enum mdm_hl7800_sleep state)2440 static void set_sleep_state(enum mdm_hl7800_sleep state)
2441 {
2442 	ictx.sleep_state = state;
2443 	if (ictx.sleep_state != HL7800_SLEEP_AWAKE) {
2444 		k_sem_reset(&ictx.mdm_awake);
2445 	}
2446 	generate_sleep_state_event();
2447 }
2448 
generate_sleep_state_event(void)2449 static void generate_sleep_state_event(void)
2450 {
2451 	struct mdm_hl7800_compound_event event;
2452 
2453 	event.code = ictx.sleep_state;
2454 	event.string = get_sleep_state_string(ictx.sleep_state);
2455 	LOG_INF("Sleep State: %s", event.string);
2456 	event_handler(HL7800_EVENT_SLEEP_STATE_CHANGE, &event);
2457 }
2458 
2459 #ifdef CONFIG_MODEM_HL7800_FW_UPDATE
get_fota_state_string(enum mdm_hl7800_fota_state state)2460 static char *get_fota_state_string(enum mdm_hl7800_fota_state state)
2461 {
2462 	/* clang-format off */
2463 	switch (state) {
2464 		PREFIXED_SWITCH_CASE_RETURN_STRING(HL7800_FOTA, IDLE);
2465 		PREFIXED_SWITCH_CASE_RETURN_STRING(HL7800_FOTA, START);
2466 		PREFIXED_SWITCH_CASE_RETURN_STRING(HL7800_FOTA, WIP);
2467 		PREFIXED_SWITCH_CASE_RETURN_STRING(HL7800_FOTA, PAD);
2468 		PREFIXED_SWITCH_CASE_RETURN_STRING(HL7800_FOTA, SEND_EOT);
2469 		PREFIXED_SWITCH_CASE_RETURN_STRING(HL7800_FOTA, FILE_ERROR);
2470 		PREFIXED_SWITCH_CASE_RETURN_STRING(HL7800_FOTA, INSTALL);
2471 		PREFIXED_SWITCH_CASE_RETURN_STRING(HL7800_FOTA, REBOOT_AND_RECONFIGURE);
2472 		PREFIXED_SWITCH_CASE_RETURN_STRING(HL7800_FOTA, COMPLETE);
2473 	default:
2474 		return "UNKNOWN";
2475 	}
2476 	/* clang-format on */
2477 }
2478 
set_fota_state(enum mdm_hl7800_fota_state state)2479 static void set_fota_state(enum mdm_hl7800_fota_state state)
2480 {
2481 	LOG_INF("FOTA state: %s->%s",
2482 		get_fota_state_string(ictx.fw_update_state),
2483 		get_fota_state_string(state));
2484 	ictx.fw_update_state = state;
2485 	generate_fota_state_event();
2486 }
2487 
generate_fota_state_event(void)2488 static void generate_fota_state_event(void)
2489 {
2490 	struct mdm_hl7800_compound_event event;
2491 
2492 	event.code = ictx.fw_update_state;
2493 	event.string = get_fota_state_string(ictx.fw_update_state);
2494 	event_handler(HL7800_EVENT_FOTA_STATE, &event);
2495 }
2496 
generate_fota_count_event(void)2497 static void generate_fota_count_event(void)
2498 {
2499 	uint32_t count = ictx.fw_packet_count * XMODEM_DATA_SIZE;
2500 
2501 	event_handler(HL7800_EVENT_FOTA_COUNT, &count);
2502 }
2503 #endif
2504 
2505 /* Handler: +KSUP: # */
on_cmd_startup_report(struct net_buf ** buf,uint16_t len)2506 static bool on_cmd_startup_report(struct net_buf **buf, uint16_t len)
2507 {
2508 	size_t out_len;
2509 	char value[MDM_MAX_RESP_SIZE];
2510 
2511 	memset(value, 0, sizeof(value));
2512 	out_len = net_buf_linearize(value, sizeof(value), *buf, 0, len);
2513 	if (out_len > 0) {
2514 		set_startup_state(strtol(value, NULL, 10));
2515 	} else {
2516 		set_startup_state(HL7800_STARTUP_STATE_UNKNOWN);
2517 	}
2518 
2519 #ifdef CONFIG_MODEM_HL7800_FW_UPDATE
2520 	if (ictx.fw_updated) {
2521 		ictx.fw_updated = false;
2522 		set_fota_state(HL7800_FOTA_REBOOT_AND_RECONFIGURE);
2523 		/* issue reset after a firmware update to reconfigure modem state */
2524 		k_work_reschedule_for_queue(&hl7800_workq, &ictx.mdm_reset_work,
2525 					    K_NO_WAIT);
2526 	} else
2527 #endif
2528 	{
2529 		PRINT_AWAKE_MSG;
2530 		ictx.wait_for_KSUP = false;
2531 		ictx.mdm_startup_reporting_on = true;
2532 		ictx.reconfig_IP_connection = true;
2533 #ifdef CONFIG_MODEM_HL7800_LOW_POWER_MODE
2534 		mark_sockets_for_reconfig();
2535 #endif
2536 		set_sleep_state(HL7800_SLEEP_AWAKE);
2537 		k_sem_give(&ictx.mdm_awake);
2538 	}
2539 
2540 	return true;
2541 }
2542 
profile_handler(struct net_buf ** buf,uint16_t len,bool active_profile)2543 static bool profile_handler(struct net_buf **buf, uint16_t len,
2544 			    bool active_profile)
2545 {
2546 	uint32_t size;
2547 	int echo_state = -1;
2548 	struct net_buf *frag = NULL;
2549 	uint16_t line_length;
2550 	char line[MAX_PROFILE_LINE_LENGTH];
2551 	size_t output_length;
2552 
2553 	/* Prepare net buffer for this parser. */
2554 	net_buf_remove(buf, len);
2555 	net_buf_skipcrlf(buf);
2556 
2557 	size = wait_for_modem_data(buf, net_buf_frags_len(*buf),
2558 				   sizeof(PROFILE_LINE_1));
2559 	net_buf_skipcrlf(buf); /* remove any \r\n that are in the front */
2560 
2561 	/* Parse configuration data to determine if echo is on/off. */
2562 	line_length = net_buf_findcrlf(*buf, &frag);
2563 	if (line_length) {
2564 		memset(line, 0, sizeof(line));
2565 		output_length = net_buf_linearize(line, SIZE_WITHOUT_NUL(line),
2566 						  *buf, 0, line_length);
2567 		LOG_DBG("length: %u: %s", line_length, line);
2568 
2569 		/* Echo on off is the first thing on the line: E0, E1 */
2570 		if (output_length >= SIZE_WITHOUT_NUL("E?")) {
2571 			echo_state = (line[1] == '1') ? 1 : 0;
2572 		}
2573 	}
2574 	LOG_DBG("echo: %d", echo_state);
2575 	net_buf_remove(buf, line_length);
2576 	net_buf_skipcrlf(buf);
2577 
2578 	if (active_profile) {
2579 		ictx.mdm_echo_is_on = (echo_state != 0);
2580 	}
2581 
2582 	/* Discard next line.  This waits for the longest possible response even
2583 	 * though most registers won't have the value 0xFF. */
2584 	size = wait_for_modem_data(buf, net_buf_frags_len(*buf),
2585 				   sizeof(PROFILE_LINE_2));
2586 	net_buf_skipcrlf(buf);
2587 	len = net_buf_findcrlf(*buf, &frag);
2588 	net_buf_remove(buf, len);
2589 	net_buf_skipcrlf(buf);
2590 
2591 	return false;
2592 }
2593 
on_cmd_atcmdinfo_active_profile(struct net_buf ** buf,uint16_t len)2594 static bool on_cmd_atcmdinfo_active_profile(struct net_buf **buf, uint16_t len)
2595 {
2596 	return profile_handler(buf, len, true);
2597 }
2598 
on_cmd_atcmdinfo_stored_profile0(struct net_buf ** buf,uint16_t len)2599 static bool on_cmd_atcmdinfo_stored_profile0(struct net_buf **buf, uint16_t len)
2600 {
2601 	return profile_handler(buf, len, false);
2602 }
2603 
on_cmd_atcmdinfo_stored_profile1(struct net_buf ** buf,uint16_t len)2604 static bool on_cmd_atcmdinfo_stored_profile1(struct net_buf **buf, uint16_t len)
2605 {
2606 	return profile_handler(buf, len, false);
2607 }
2608 
2609 /* +WPPP: 1,1,"username","password" */
on_cmd_atcmdinfo_pdp_authentication_cfg(struct net_buf ** buf,uint16_t len)2610 static bool on_cmd_atcmdinfo_pdp_authentication_cfg(struct net_buf **buf,
2611 						    uint16_t len)
2612 {
2613 	struct net_buf *frag = NULL;
2614 	uint16_t line_length;
2615 	char line[MDM_HL7800_APN_CMD_MAX_SIZE];
2616 	size_t output_length;
2617 	size_t i;
2618 	char *p;
2619 
2620 	wait_for_modem_data_and_newline(buf, net_buf_frags_len(*buf),
2621 					MDM_HL7800_APN_CMD_MAX_SIZE);
2622 
2623 	line_length = net_buf_findcrlf(*buf, &frag);
2624 	if (line_length) {
2625 		memset(line, 0, sizeof(line));
2626 		output_length = net_buf_linearize(line, SIZE_WITHOUT_NUL(line),
2627 						  *buf, 0, line_length);
2628 		LOG_DBG("length: %u: %s", line_length, line);
2629 		if (output_length > 0) {
2630 			memset(ictx.mdm_apn.username, 0,
2631 			       sizeof(ictx.mdm_apn.username));
2632 			memset(ictx.mdm_apn.password, 0,
2633 			       sizeof(ictx.mdm_apn.password));
2634 
2635 			i = 0;
2636 			p = strchr(line, '"');
2637 			if (p != NULL) {
2638 				p += 1;
2639 				i = 0;
2640 				while ((p != NULL) && (*p != '"') &&
2641 				       (i <
2642 					MDM_HL7800_APN_USERNAME_MAX_STRLEN)) {
2643 					ictx.mdm_apn.username[i++] = *p++;
2644 				}
2645 			}
2646 			LOG_INF("APN Username: %s",
2647 				ictx.mdm_apn.username);
2648 
2649 			p = strchr(p + 1, '"');
2650 			if (p != NULL) {
2651 				p += 1;
2652 				i = 0;
2653 				while ((p != NULL) && (*p != '"') &&
2654 				       (i <
2655 					MDM_HL7800_APN_PASSWORD_MAX_STRLEN)) {
2656 					ictx.mdm_apn.password[i++] = *p++;
2657 				}
2658 			}
2659 			LOG_INF("APN Password: %s",
2660 				ictx.mdm_apn.password);
2661 		}
2662 	}
2663 	net_buf_remove(buf, line_length);
2664 	net_buf_skipcrlf(buf);
2665 
2666 	return false;
2667 }
2668 
2669 /* Only context 1 is used. Other contexts are unhandled.
2670  *
2671  * +CGDCONT: 1,"IP","access point name",,0,0,0,0,0,,0,,,,,
2672  */
on_cmd_atcmdinfo_pdp_context(struct net_buf ** buf,uint16_t len)2673 static bool on_cmd_atcmdinfo_pdp_context(struct net_buf **buf, uint16_t len)
2674 {
2675 	struct net_buf *frag = NULL;
2676 	uint16_t line_length;
2677 	char line[MDM_HL7800_APN_CMD_MAX_SIZE];
2678 	size_t output_length;
2679 	char *p;
2680 	size_t i;
2681 
2682 	wait_for_modem_data_and_newline(buf, net_buf_frags_len(*buf),
2683 					MDM_HL7800_APN_CMD_MAX_SIZE);
2684 
2685 	line_length = net_buf_findcrlf(*buf, &frag);
2686 	if (line_length) {
2687 		memset(line, 0, sizeof(line));
2688 		output_length = net_buf_linearize(line, SIZE_WITHOUT_NUL(line),
2689 						  *buf, 0, line_length);
2690 		LOG_DBG("length: %u: %s", line_length, line);
2691 		if (output_length > 0) {
2692 			memset(ictx.mdm_apn.value, 0, sizeof(ictx.mdm_apn.value));
2693 			memset(ictx.mdm_pdp_addr_fam, 0, MDM_ADDR_FAM_MAX_LEN);
2694 
2695 			/* Address family after first , */
2696 			p = strchr(line, ',');
2697 			if (p == NULL) {
2698 				LOG_WRN("Issue parsing APN response");
2699 				goto done;
2700 			}
2701 			p += 2;
2702 			i = 0;
2703 			while ((p != NULL) && (*p != '"') && (i < MDM_ADDR_FAM_MAX_LEN)) {
2704 				ictx.mdm_pdp_addr_fam[i++] = *p++;
2705 			}
2706 			LOG_DBG("PDP address family: %s", ictx.mdm_pdp_addr_fam);
2707 
2708 			/* APN after second , " */
2709 			p = strchr(p, ',');
2710 			if (p == NULL) {
2711 				LOG_WRN("Issue parsing APN response");
2712 				goto done;
2713 			}
2714 			p++;
2715 			if (*p == ',') {
2716 				/* APN is blank */
2717 				goto done;
2718 			}
2719 			if (*p == '"') {
2720 				p++;
2721 				i = 0;
2722 				while ((p != NULL) && (*p != '"') &&
2723 				       (i < MDM_HL7800_APN_MAX_STRLEN)) {
2724 					ictx.mdm_apn.value[i++] = *p++;
2725 				}
2726 			}
2727 
2728 			LOG_INF("APN: %s", ictx.mdm_apn.value);
2729 		}
2730 	}
2731 done:
2732 	net_buf_remove(buf, line_length);
2733 	net_buf_skipcrlf(buf);
2734 
2735 	return false;
2736 }
2737 
hl7800_query_rssi(void)2738 static int hl7800_query_rssi(void)
2739 {
2740 	int ret;
2741 
2742 	ret = send_at_cmd(NULL, "AT+KCELLMEAS=0", MDM_CMD_SEND_TIMEOUT, 1,
2743 			  false);
2744 	if (ret < 0) {
2745 		LOG_ERR("AT+KCELLMEAS ret:%d", ret);
2746 	}
2747 	return ret;
2748 }
2749 
hl7800_start_rssi_work(void)2750 static void hl7800_start_rssi_work(void)
2751 {
2752 	/* Rate is not checked here to allow one reading
2753 	 * when going from network down->up
2754 	 */
2755 	k_work_reschedule_for_queue(&hl7800_workq, &ictx.rssi_query_work,
2756 				    K_NO_WAIT);
2757 }
2758 
hl7800_stop_rssi_work(void)2759 static void hl7800_stop_rssi_work(void)
2760 {
2761 	int rc;
2762 
2763 	rc = k_work_cancel_delayable(&ictx.rssi_query_work);
2764 	if (rc != 0) {
2765 		LOG_ERR("Could not cancel RSSI work [%d]", rc);
2766 	}
2767 }
2768 
rssi_query(void)2769 static void rssi_query(void)
2770 {
2771 	hl7800_lock();
2772 	wakeup_hl7800();
2773 	hl7800_query_rssi();
2774 	allow_sleep(true);
2775 	hl7800_unlock();
2776 }
2777 
hl7800_rssi_query_work(struct k_work * work)2778 static void hl7800_rssi_query_work(struct k_work *work)
2779 {
2780 	rssi_query();
2781 
2782 	/* re-start RSSI query work */
2783 	if (CONFIG_MODEM_HL7800_RSSI_RATE_SECONDS > 0) {
2784 		k_work_reschedule_for_queue(&hl7800_workq, &ictx.rssi_query_work,
2785 					    K_SECONDS(CONFIG_MODEM_HL7800_RSSI_RATE_SECONDS));
2786 	}
2787 }
2788 
2789 #ifdef CONFIG_MODEM_HL7800_GPS
2790 /* Unsolicited notification
2791  * Handler: +GNSSEV: <eventType>,<eventStatus>
2792  */
on_cmd_gps_event(struct net_buf ** buf,uint16_t len)2793 static bool on_cmd_gps_event(struct net_buf **buf, uint16_t len)
2794 {
2795 	size_t out_len;
2796 	char value[MDM_MAX_RESP_SIZE];
2797 	char *start = NULL;
2798 	char *end = NULL;
2799 	int8_t event = -1;
2800 	int8_t status = -1;
2801 
2802 	memset(value, 0, sizeof(value));
2803 	out_len = net_buf_linearize(value, sizeof(value), *buf, 0, len);
2804 	if (out_len > 0) {
2805 		start = value;
2806 		event = strtol(start, &end, 10);
2807 		if (end == strchr(value, ',')) {
2808 			start = end + 1;
2809 			status = strtol(start, &end, 10);
2810 		}
2811 	}
2812 
2813 	LOG_INF("GPS event: %d status: %d", event, status);
2814 
2815 	if (event == HL7800_GNSS_EVENT_POSITION) {
2816 		event_handler(HL7800_EVENT_GPS_POSITION_STATUS, &status);
2817 	}
2818 
2819 	return true;
2820 }
2821 
gps_work_callback(struct k_work * work)2822 static void gps_work_callback(struct k_work *work)
2823 {
2824 	ARG_UNUSED(work);
2825 	int r;
2826 
2827 	hl7800_lock();
2828 	wakeup_hl7800();
2829 	r = send_at_cmd(NULL, "AT+GNSSLOC?", MDM_CMD_SEND_TIMEOUT, 1, false);
2830 	allow_sleep(true);
2831 	hl7800_unlock();
2832 
2833 	LOG_DBG("GPS location request status: %d", r);
2834 
2835 	if (ictx.gps_query_location_rate_seconds) {
2836 		k_work_reschedule_for_queue(&hl7800_workq, &ictx.gps_work,
2837 					    K_SECONDS(ictx.gps_query_location_rate_seconds));
2838 	}
2839 }
2840 
2841 /* The AT+GNSSLOC? command returns 1 of 2 things:
2842  *
2843  * +GNSSLOC:
2844  * Latitude: "49 Deg 10 Min 21.49 Sec N"
2845  * Longitude:  "123 Deg 4 Min 14.76 Sec W"
2846  * GpsTime: "yyyy mm dd hh:mm:ss"
2847  * FixType: "2D" or "3D"
2848  * HEPE: "8.485 m" (Horizontal Estimated Position Error)
2849  * Altitude: "-1 m"
2850  * AltUnc: "3.0 m"
2851  * Direction: "0.0 deg"
2852  * HorSpeed: "0.0 m/s"
2853  * VerSpeed: "0.0 m/s"
2854  * OK
2855  *
2856  * OR
2857  *
2858  * +GNSSLOC:
2859  * FIX NOT AVAILABLE
2860  * OK
2861  *
2862  * Since each response is on its own line, the command handler is used
2863  * to handle each one as an individual response.
2864  */
gps_handler(struct net_buf ** buf,uint16_t len,enum mdm_hl7800_gps_string_types str_type)2865 static bool gps_handler(struct net_buf **buf, uint16_t len,
2866 			enum mdm_hl7800_gps_string_types str_type)
2867 {
2868 	struct mdm_hl7800_compound_event event;
2869 	char gps_str[MDM_HL7800_MAX_GPS_STR_SIZE];
2870 	size_t gps_len = sizeof(gps_str) - 1;
2871 	struct net_buf *frag = NULL;
2872 	size_t out_len;
2873 
2874 	wait_for_modem_data_and_newline(buf, net_buf_frags_len(*buf), sizeof(gps_str));
2875 
2876 	frag = NULL;
2877 	len = net_buf_findcrlf(*buf, &frag);
2878 	if (!frag) {
2879 		LOG_ERR("Unable to find end");
2880 		goto done;
2881 	}
2882 
2883 	if (len > gps_len) {
2884 		LOG_WRN("GPS string too long (len:%d)", len);
2885 		len = gps_len;
2886 	}
2887 
2888 	out_len = net_buf_linearize(gps_str, gps_len, *buf, 0, len);
2889 	gps_str[out_len] = 0;
2890 
2891 	event.code = str_type;
2892 	event.string = gps_str;
2893 	event_handler(HL7800_EVENT_GPS, &event);
2894 done:
2895 	return true;
2896 }
2897 
on_cmd_latitude(struct net_buf ** buf,uint16_t len)2898 static bool on_cmd_latitude(struct net_buf **buf, uint16_t len)
2899 {
2900 	return gps_handler(buf, len, HL7800_GPS_STR_LATITUDE);
2901 }
2902 
on_cmd_longitude(struct net_buf ** buf,uint16_t len)2903 static bool on_cmd_longitude(struct net_buf **buf, uint16_t len)
2904 {
2905 	return gps_handler(buf, len, HL7800_GPS_STR_LONGITUDE);
2906 }
2907 
on_cmd_gps_time(struct net_buf ** buf,uint16_t len)2908 static bool on_cmd_gps_time(struct net_buf **buf, uint16_t len)
2909 {
2910 	return gps_handler(buf, len, HL7800_GPS_STR_GPS_TIME);
2911 }
2912 
on_cmd_fix_type(struct net_buf ** buf,uint16_t len)2913 static bool on_cmd_fix_type(struct net_buf **buf, uint16_t len)
2914 {
2915 	return gps_handler(buf, len, HL7800_GPS_STR_FIX_TYPE);
2916 }
2917 
on_cmd_hepe(struct net_buf ** buf,uint16_t len)2918 static bool on_cmd_hepe(struct net_buf **buf, uint16_t len)
2919 {
2920 	return gps_handler(buf, len, HL7800_GPS_STR_HEPE);
2921 }
2922 
on_cmd_altitude(struct net_buf ** buf,uint16_t len)2923 static bool on_cmd_altitude(struct net_buf **buf, uint16_t len)
2924 {
2925 	return gps_handler(buf, len, HL7800_GPS_STR_ALTITUDE);
2926 }
2927 
on_cmd_alt_unc(struct net_buf ** buf,uint16_t len)2928 static bool on_cmd_alt_unc(struct net_buf **buf, uint16_t len)
2929 {
2930 	return gps_handler(buf, len, HL7800_GPS_STR_ALT_UNC);
2931 }
2932 
on_cmd_direction(struct net_buf ** buf,uint16_t len)2933 static bool on_cmd_direction(struct net_buf **buf, uint16_t len)
2934 {
2935 	return gps_handler(buf, len, HL7800_GPS_STR_DIRECTION);
2936 }
2937 
on_cmd_hor_speed(struct net_buf ** buf,uint16_t len)2938 static bool on_cmd_hor_speed(struct net_buf **buf, uint16_t len)
2939 {
2940 	return gps_handler(buf, len, HL7800_GPS_STR_HOR_SPEED);
2941 }
2942 
on_cmd_ver_speed(struct net_buf ** buf,uint16_t len)2943 static bool on_cmd_ver_speed(struct net_buf **buf, uint16_t len)
2944 {
2945 	return gps_handler(buf, len, HL7800_GPS_STR_VER_SPEED);
2946 }
2947 #endif /* CONFIG_MODEM_HL7800_GPS */
2948 
2949 #ifdef CONFIG_MODEM_HL7800_POLTE
2950 /* Handler: %POLTEEVU: "REGISTER",0, <mqttAuthUser>, <mqttAuthPassword> */
on_cmd_polte_registration(struct net_buf ** buf,uint16_t len)2951 static bool on_cmd_polte_registration(struct net_buf **buf, uint16_t len)
2952 {
2953 	char rsp[MDM_MAX_RESP_SIZE] = { 0 };
2954 	size_t rsp_len = sizeof(rsp) - 1;
2955 	char *rsp_end = rsp + rsp_len;
2956 	struct mdm_hl7800_polte_registration_event_data data;
2957 	struct net_buf *frag = NULL;
2958 	size_t out_len;
2959 	char *location;
2960 	bool parsed;
2961 
2962 	memset(&data, 0, sizeof(data));
2963 
2964 	wait_for_modem_data_and_newline(buf, net_buf_frags_len(*buf), sizeof(rsp));
2965 
2966 	location = rsp;
2967 	parsed = false;
2968 	frag = NULL;
2969 	len = net_buf_findcrlf(*buf, &frag);
2970 	do {
2971 		if (!frag) {
2972 			LOG_ERR("Unable to find end");
2973 			break;
2974 		}
2975 
2976 		if (len > rsp_len) {
2977 			LOG_WRN("string too long (len:%d)", len);
2978 			len = rsp_len;
2979 		}
2980 
2981 		out_len = net_buf_linearize(rsp, rsp_len, *buf, 0, len);
2982 		rsp[out_len] = 0;
2983 
2984 		/* Command handler looks for string up to the user field */
2985 		location = strstr(location, "\"");
2986 		if (location != NULL && location < rsp_end) {
2987 			location += 1;
2988 			if (location >= rsp_end) {
2989 				break;
2990 			}
2991 			data.user = location;
2992 		} else {
2993 			break;
2994 		}
2995 
2996 		/* Find end of user field and null terminate string */
2997 		location = strstr(location, "\"");
2998 		if (location != NULL && location < rsp_end) {
2999 			*location = 0;
3000 			location += 1;
3001 			if (location >= rsp_end) {
3002 				break;
3003 			}
3004 		} else {
3005 			break;
3006 		}
3007 
3008 		location = strstr(location, ",\"");
3009 		if (location != NULL && location < rsp_end) {
3010 			location += 2;
3011 			if (location >= rsp_end) {
3012 				break;
3013 			}
3014 			data.password = location;
3015 
3016 		} else {
3017 			break;
3018 		}
3019 
3020 		location = strstr(location, "\"");
3021 		if (location != NULL && location < rsp_end) {
3022 			*location = 0;
3023 		} else {
3024 			break;
3025 		}
3026 		parsed = true;
3027 	} while (false);
3028 
3029 	if (parsed && data.user && data.password) {
3030 		data.status = 0;
3031 	} else {
3032 		data.status = -1;
3033 		LOG_ERR("Unable to parse PoLTE registration");
3034 	}
3035 
3036 	event_handler(HL7800_EVENT_POLTE_REGISTRATION, &data);
3037 
3038 	return true;
3039 }
3040 
3041 /* Handler: %POLTECMD: "LOCATE",<res> */
on_cmd_polte_locate_cmd_rsp(struct net_buf ** buf,uint16_t len)3042 static bool on_cmd_polte_locate_cmd_rsp(struct net_buf **buf, uint16_t len)
3043 {
3044 	char rsp[sizeof("99")] = { 0 };
3045 	size_t rsp_len = sizeof(rsp) - 1;
3046 	size_t out_len;
3047 	struct net_buf *frag = NULL;
3048 	struct mdm_hl7800_polte_location_data data;
3049 
3050 	memset(&data, 0, sizeof(data));
3051 
3052 	wait_for_modem_data_and_newline(buf, net_buf_frags_len(*buf), sizeof(rsp));
3053 
3054 	data.status = -1;
3055 	frag = NULL;
3056 	len = net_buf_findcrlf(*buf, &frag);
3057 	do {
3058 		if (!frag) {
3059 			LOG_ERR("Unable to find end");
3060 			break;
3061 		}
3062 
3063 		if (len > rsp_len) {
3064 			LOG_WRN("string too long (len:%d)", len);
3065 			len = rsp_len;
3066 		}
3067 
3068 		out_len = net_buf_linearize(rsp, rsp_len, *buf, 0, len);
3069 		rsp[out_len] = 0;
3070 
3071 		data.status = (uint32_t)strtoul(rsp, NULL, 10);
3072 	} while (false);
3073 
3074 	event_handler(HL7800_EVENT_POLTE_LOCATE_STATUS, &data);
3075 
3076 	return true;
3077 }
3078 
3079 /* Handler:
3080  * %POLTEEVU: "LOCATION",<stat>[,<latitude>,<longitude>,<time>,<confidence>]
3081  */
on_cmd_polte_location(struct net_buf ** buf,uint16_t len)3082 static bool on_cmd_polte_location(struct net_buf **buf, uint16_t len)
3083 {
3084 	char rsp[MDM_MAX_RESP_SIZE] = { 0 };
3085 	size_t rsp_len = sizeof(rsp) - 1;
3086 	char *rsp_end = rsp + rsp_len;
3087 	struct net_buf *frag = NULL;
3088 	size_t out_len = 0;
3089 	char *start;
3090 	char *end;
3091 	bool parsed;
3092 	struct mdm_hl7800_polte_location_data data;
3093 	static const char POLTE_LOC_DELIMITER[] = "\",\"";
3094 
3095 	memset(&data, 0, sizeof(data));
3096 
3097 	wait_for_modem_data_and_newline(buf, net_buf_frags_len(*buf), sizeof(rsp));
3098 
3099 	parsed = false;
3100 	frag = NULL;
3101 	len = net_buf_findcrlf(*buf, &frag);
3102 	do {
3103 		if (!frag) {
3104 			LOG_ERR("Unable to find end");
3105 			break;
3106 		}
3107 
3108 		if (len > rsp_len) {
3109 			LOG_WRN("string too long (len:%d)", len);
3110 			len = rsp_len;
3111 		}
3112 
3113 		out_len = net_buf_linearize(rsp, rsp_len, *buf, 0, len);
3114 		rsp[out_len] = 0;
3115 
3116 		data.status = -1;
3117 		start = rsp;
3118 		end = "";
3119 		/* Comma isn't present when there is an error. */
3120 		start = strstr(start, ",");
3121 		if (start != NULL && start < rsp_end) {
3122 			*start = ' ';
3123 			start += 1;
3124 		}
3125 		data.status = (uint32_t)strtoul(rsp, &end, 10);
3126 		if (data.status != 0) {
3127 			LOG_WRN("Response not received from PoLTE server: %d", data.status);
3128 			data.status = MDM_HL7800_POLTE_SERVER_ERROR;
3129 			parsed = true;
3130 			break;
3131 		} else if (start >= rsp_end) {
3132 			break;
3133 		}
3134 
3135 		start = strstr(start, "\"") + 1;
3136 		end = strstr(start, POLTE_LOC_DELIMITER);
3137 		if (start > rsp && start < rsp_end && end < rsp_end && end > start) {
3138 			memcpy(data.latitude, start, MIN(end - start, sizeof(data.latitude) - 1));
3139 		} else {
3140 			break;
3141 		}
3142 
3143 		start = end + strlen(POLTE_LOC_DELIMITER);
3144 		end = strstr(start, POLTE_LOC_DELIMITER);
3145 		if (start > rsp && start < rsp_end && end < rsp_end && end > start) {
3146 			memcpy(data.longitude, start, MIN(end - start, sizeof(data.longitude) - 1));
3147 		} else {
3148 			break;
3149 		}
3150 
3151 		start = end + strlen(POLTE_LOC_DELIMITER);
3152 		end = strstr(start, POLTE_LOC_DELIMITER);
3153 		if (start > rsp && start < rsp_end && end < rsp_end && end > start) {
3154 			data.timestamp = (uint32_t)strtoul(start, NULL, 10);
3155 		} else {
3156 			break;
3157 		}
3158 
3159 		start = end + strlen(POLTE_LOC_DELIMITER);
3160 		end = strstr(start, "\"");
3161 		if (start > rsp && start < rsp_end && end < rsp_end && end > start) {
3162 			memcpy(data.confidence_in_meters, start,
3163 			       MIN(end - start, sizeof(data.confidence_in_meters) - 1));
3164 		} else {
3165 			break;
3166 		}
3167 
3168 		parsed = true;
3169 	} while (false);
3170 
3171 	if (!parsed) {
3172 		LOG_HEXDUMP_ERR(rsp, out_len, "Unable to parse PoLTE location");
3173 	} else {
3174 		LOG_HEXDUMP_DBG(rsp, out_len, "PoLTE Location");
3175 	}
3176 
3177 	event_handler(HL7800_EVENT_POLTE, &data);
3178 
3179 	return true;
3180 }
3181 #endif /* CONFIG_MODEM_HL7800_POLTE */
3182 
notify_all_tcp_sockets_closed(void)3183 static void notify_all_tcp_sockets_closed(void)
3184 {
3185 	int i;
3186 	struct hl7800_socket *sock = NULL;
3187 
3188 	for (i = 0; i < MDM_MAX_SOCKETS; i++) {
3189 		sock = &ictx.sockets[i];
3190 		if ((sock->context != NULL) && (sock->type == SOCK_STREAM)) {
3191 			LOG_DBG("Sock %d closed", sock->socket_id);
3192 			/* signal RX callback with null packet */
3193 			if (sock->recv_cb) {
3194 				sock->recv_cb(sock->context, sock->recv_pkt,
3195 					      NULL, NULL, 0,
3196 					      sock->recv_user_data);
3197 			}
3198 		}
3199 	}
3200 }
3201 
iface_status_work_cb(struct k_work * work)3202 static void iface_status_work_cb(struct k_work *work)
3203 {
3204 	int ret;
3205 	hl7800_lock();
3206 	enum mdm_hl7800_network_state state;
3207 
3208 	if (ictx.off) {
3209 		goto done;
3210 	} else if (!ictx.initialized && ictx.restarting) {
3211 		LOG_DBG("Wait for driver init, process network state later");
3212 		/* we are not ready to process this yet, try again later */
3213 		k_work_reschedule_for_queue(&hl7800_workq,
3214 					    &ictx.iface_status_work,
3215 					    IFACE_WORK_DELAY);
3216 		goto done;
3217 	} else if (ictx.wait_for_KSUP && ictx.wait_for_KSUP_tries < WAIT_FOR_KSUP_RETRIES) {
3218 		LOG_DBG("Wait for +KSUP before updating network state");
3219 		ictx.wait_for_KSUP_tries++;
3220 		/* we have not received +KSUP yet, lets wait more time to receive +KSUP */
3221 		k_work_reschedule_for_queue(&hl7800_workq,
3222 					    &ictx.iface_status_work,
3223 					    IFACE_WORK_DELAY);
3224 		goto done;
3225 	} else if (ictx.wait_for_KSUP && ictx.wait_for_KSUP_tries >= WAIT_FOR_KSUP_RETRIES) {
3226 		/* give up waiting for KSUP */
3227 		LOG_DBG("Give up waiting for");
3228 		ictx.wait_for_KSUP = false;
3229 		check_hl7800_awake();
3230 	}
3231 
3232 	wakeup_hl7800();
3233 
3234 	LOG_DBG("Updating network state...");
3235 
3236 	state = ictx.network_state;
3237 	/* Ensure we bring the network interface down and then re-check the current state */
3238 	if (ictx.network_dropped) {
3239 		ictx.network_dropped = false;
3240 		state = HL7800_OUT_OF_COVERAGE;
3241 		k_work_reschedule_for_queue(&hl7800_workq, &ictx.iface_status_work,
3242 					    IFACE_WORK_DELAY);
3243 	}
3244 
3245 	/* Query operator selection */
3246 	ret = send_at_cmd(NULL, "AT+COPS?", MDM_CMD_SEND_TIMEOUT, 0, false);
3247 	if (ret < 0) {
3248 		LOG_ERR("AT+COPS ret:%d", ret);
3249 	}
3250 
3251 	/* bring iface up/down */
3252 	switch (state) {
3253 	case HL7800_HOME_NETWORK:
3254 	case HL7800_ROAMING:
3255 		if (ictx.iface) {
3256 			LOG_DBG("HL7800 iface UP");
3257 			net_if_carrier_on(ictx.iface);
3258 		}
3259 		break;
3260 	case HL7800_OUT_OF_COVERAGE:
3261 	default:
3262 		if (ictx.iface && (ictx.low_power_mode != HL7800_LPM_PSM)) {
3263 			LOG_DBG("HL7800 iface DOWN");
3264 			ictx.dns_ready = false;
3265 			net_if_carrier_off(ictx.iface);
3266 		}
3267 		break;
3268 	}
3269 
3270 	if ((ictx.iface && !net_if_is_up(ictx.iface)) ||
3271 	    (ictx.low_power_mode == HL7800_LPM_PSM && state == HL7800_OUT_OF_COVERAGE)) {
3272 		hl7800_stop_rssi_work();
3273 		notify_all_tcp_sockets_closed();
3274 	} else if (ictx.iface && net_if_is_up(ictx.iface)) {
3275 		hl7800_start_rssi_work();
3276 		/* get IP address info */
3277 		(void)send_at_cmd(NULL, "AT+CGCONTRDP=1", MDM_CMD_SEND_TIMEOUT,
3278 				  CONFIG_MODEM_HL7800_GET_IP_ADDR_INFO_ATTEMPTS, false);
3279 		/* get active bands */
3280 		SEND_AT_CMD_IGNORE_ERROR("AT+KBND?");
3281 	}
3282 	LOG_DBG("Network state updated");
3283 	allow_sleep(true);
3284 done:
3285 	hl7800_unlock();
3286 }
3287 
get_network_state_string(enum mdm_hl7800_network_state state)3288 static char *get_network_state_string(enum mdm_hl7800_network_state state)
3289 {
3290 	switch (state) {
3291 		PREFIXED_SWITCH_CASE_RETURN_STRING(HL7800, NOT_REGISTERED);
3292 		PREFIXED_SWITCH_CASE_RETURN_STRING(HL7800, HOME_NETWORK);
3293 		PREFIXED_SWITCH_CASE_RETURN_STRING(HL7800, SEARCHING);
3294 		PREFIXED_SWITCH_CASE_RETURN_STRING(HL7800, REGISTRATION_DENIED);
3295 		PREFIXED_SWITCH_CASE_RETURN_STRING(HL7800, OUT_OF_COVERAGE);
3296 		PREFIXED_SWITCH_CASE_RETURN_STRING(HL7800, ROAMING);
3297 		PREFIXED_SWITCH_CASE_RETURN_STRING(HL7800, EMERGENCY);
3298 		PREFIXED_SWITCH_CASE_RETURN_STRING(HL7800, UNABLE_TO_CONFIGURE);
3299 	default:
3300 		return "UNKNOWN";
3301 	}
3302 }
3303 
set_network_state(enum mdm_hl7800_network_state state)3304 static void set_network_state(enum mdm_hl7800_network_state state)
3305 {
3306 	ictx.network_state = state;
3307 	generate_network_state_event();
3308 }
3309 
generate_network_state_event(void)3310 static void generate_network_state_event(void)
3311 {
3312 	struct mdm_hl7800_compound_event event;
3313 
3314 	event.code = ictx.network_state;
3315 	event.string = get_network_state_string(ictx.network_state);
3316 	LOG_INF("Network State: %d %s", ictx.network_state, event.string);
3317 	event_handler(HL7800_EVENT_NETWORK_STATE_CHANGE, &event);
3318 }
3319 
3320 /* Handler: +CEREG: <n>,<stat>[,[<lac>],[<ci>],[<AcT>]
3321  *  [,[<cause_type>],[<reject_cause>] [,[<Active-Time>],[<Periodic-TAU>]]]]
3322  */
on_cmd_network_report_query(struct net_buf ** buf,uint16_t len)3323 static bool on_cmd_network_report_query(struct net_buf **buf, uint16_t len)
3324 {
3325 	size_t out_len;
3326 	char value[MDM_MAX_RESP_SIZE];
3327 	char *pos;
3328 	int l;
3329 	char val[MDM_MAX_RESP_SIZE];
3330 
3331 	out_len = net_buf_linearize(value, sizeof(value), *buf, 0, len);
3332 	pos = strchr(value, ',');
3333 	if (pos) {
3334 		l = (value + out_len) - pos;
3335 		strncpy(val, pos + 1, l);
3336 		val[l] = 0;
3337 		set_network_state(strtol(val, NULL, 0));
3338 
3339 		/* start work to adjust iface */
3340 		k_work_reschedule_for_queue(&hl7800_workq,
3341 					    &ictx.iface_status_work,
3342 					    IFACE_WORK_DELAY);
3343 	}
3344 
3345 	return true;
3346 }
3347 
on_cmd_operator_index_query(struct net_buf ** buf,uint16_t len)3348 static bool on_cmd_operator_index_query(struct net_buf **buf, uint16_t len)
3349 {
3350 	struct net_buf *frag = NULL;
3351 	char carrier[MDM_HL7800_OPERATOR_INDEX_SIZE];
3352 	size_t out_len;
3353 
3354 	wait_for_modem_data_and_newline(buf, net_buf_frags_len(*buf),
3355 					MDM_HL7800_OPERATOR_INDEX_SIZE);
3356 
3357 	frag = NULL;
3358 	len = net_buf_findcrlf(*buf, &frag);
3359 	if (!frag) {
3360 		LOG_ERR("Unable to find end of operator index response");
3361 		goto done;
3362 	}
3363 
3364 	out_len = net_buf_linearize(carrier, MDM_HL7800_OPERATOR_INDEX_STRLEN,
3365 				    *buf, 0, len);
3366 	carrier[out_len] = 0;
3367 	ictx.operator_index = (uint8_t)strtol(carrier, NULL, 10);
3368 
3369 	LOG_INF("Operator Index: %u", ictx.operator_index);
3370 done:
3371 	return true;
3372 }
3373 
on_cmd_modem_functionality(struct net_buf ** buf,uint16_t len)3374 static bool on_cmd_modem_functionality(struct net_buf **buf, uint16_t len)
3375 {
3376 	struct net_buf *frag;
3377 	size_t out_len;
3378 	char rsp[MDM_HL7800_MODEM_FUNCTIONALITY_SIZE];
3379 
3380 	wait_for_modem_data_and_newline(buf, net_buf_frags_len(*buf),
3381 					MDM_HL7800_MODEM_FUNCTIONALITY_SIZE);
3382 
3383 	frag = NULL;
3384 	len = net_buf_findcrlf(*buf, &frag);
3385 	if (!frag) {
3386 		LOG_ERR("Unable to find end of response");
3387 		goto done;
3388 	}
3389 
3390 	out_len = net_buf_linearize(rsp, MDM_HL7800_MODEM_FUNCTIONALITY_STRLEN,
3391 				    *buf, 0, len);
3392 	rsp[out_len] = 0;
3393 	ictx.functionality = strtol(rsp, NULL, 10);
3394 
3395 	LOG_INF("Modem Functionality: %u", ictx.functionality);
3396 done:
3397 	return true;
3398 }
3399 
3400 /* There can be multiple responses from a single command.
3401  * %MEAS: EARFCN=5826, CellID=420, RSRP=-99, RSRQ=-15
3402  * %MEAS: EARFCN=6400, CellID=201, RSRP=-93, RSRQ=-21
3403  */
on_cmd_survey_status(struct net_buf ** buf,uint16_t len)3404 static bool on_cmd_survey_status(struct net_buf **buf, uint16_t len)
3405 {
3406 	struct net_buf *frag = NULL;
3407 	char response[sizeof("EARFCN=XXXXXXXXXXX, CellID=XXXXXXXXXXX, RSRP=-XXX, RSRQ=-XXX")];
3408 	char *key;
3409 	size_t out_len;
3410 	char *value;
3411 	struct mdm_hl7800_site_survey site_survey;
3412 
3413 	wait_for_modem_data_and_newline(buf, net_buf_frags_len(*buf),
3414 					sizeof(response));
3415 
3416 	frag = NULL;
3417 	len = net_buf_findcrlf(*buf, &frag);
3418 	if (!frag) {
3419 		LOG_ERR("Unable to find end");
3420 		goto done;
3421 	}
3422 
3423 	out_len = net_buf_linearize(response, sizeof(response), *buf, 0, len);
3424 	LOG_HEXDUMP_DBG(response, out_len, "Site Survey");
3425 
3426 	key = "EARFCN=";
3427 	value = strstr(response, key);
3428 	if (value == NULL) {
3429 		goto done;
3430 	} else {
3431 		value += strlen(key);
3432 		site_survey.earfcn = strtoul(value, NULL, 10);
3433 	}
3434 
3435 	key = "CellID=";
3436 	value = strstr(response, key);
3437 	if (value == NULL) {
3438 		goto done;
3439 	} else {
3440 		value += strlen(key);
3441 		site_survey.cell_id = strtoul(value, NULL, 10);
3442 	}
3443 
3444 	key = "RSRP=";
3445 	value = strstr(response, key);
3446 	if (value == NULL) {
3447 		goto done;
3448 	} else {
3449 		value += strlen(key);
3450 		site_survey.rsrp = strtol(value, NULL, 10);
3451 	}
3452 
3453 	key = "RSRQ=";
3454 	value = strstr(response, key);
3455 	if (value == NULL) {
3456 		goto done;
3457 	} else {
3458 		value += strlen(key);
3459 		site_survey.rsrq = strtol(value, NULL, 10);
3460 	}
3461 
3462 	event_handler(HL7800_EVENT_SITE_SURVEY, &site_survey);
3463 
3464 done:
3465 	return true;
3466 }
3467 
3468 /* Handler: +CCLK: "yy/MM/dd,hh:mm:ss±zz" */
on_cmd_rtc_query(struct net_buf ** buf,uint16_t len)3469 static bool on_cmd_rtc_query(struct net_buf **buf, uint16_t len)
3470 {
3471 	struct net_buf *frag = NULL;
3472 	size_t str_len = sizeof(TIME_STRING_FORMAT) - 1;
3473 	char rtc_string[sizeof(TIME_STRING_FORMAT)];
3474 
3475 	memset(rtc_string, 0, sizeof(rtc_string));
3476 	ictx.local_time_valid = false;
3477 
3478 	wait_for_modem_data_and_newline(buf, net_buf_frags_len(*buf),
3479 					sizeof(TIME_STRING_FORMAT));
3480 
3481 	frag = NULL;
3482 	len = net_buf_findcrlf(*buf, &frag);
3483 	if (!frag) {
3484 		goto done;
3485 	}
3486 	if (len != str_len) {
3487 		LOG_WRN("Unexpected length for RTC string %d (expected:%zu)",
3488 			len, str_len);
3489 	} else {
3490 		net_buf_linearize(rtc_string, str_len, *buf, 0, str_len);
3491 		LOG_INF("RTC string: '%s'", rtc_string);
3492 		ictx.local_time_valid = convert_time_string_to_struct(
3493 			&ictx.local_time, &ictx.local_time_offset, rtc_string);
3494 	}
3495 done:
3496 	return true;
3497 }
3498 
valid_time_string(const char * time_string)3499 static bool valid_time_string(const char *time_string)
3500 {
3501 	size_t offset, i;
3502 
3503 	/* Ensure the all the expected delimiters are present */
3504 	offset = TIME_STRING_DIGIT_STRLEN + TIME_STRING_SEPARATOR_STRLEN;
3505 	i = TIME_STRING_FIRST_SEPARATOR_INDEX;
3506 
3507 	for (; i < TIME_STRING_PLUS_MINUS_INDEX; i += offset) {
3508 		if (time_string[i] != TIME_STRING_FORMAT[i]) {
3509 			return false;
3510 		}
3511 	}
3512 	/* The last character is the offset from UTC and can be either
3513 	 * positive or negative.  The last " is also handled here.
3514 	 */
3515 	if ((time_string[i] == '+' || time_string[i] == '-') &&
3516 	    (time_string[i + offset] == '"')) {
3517 		return true;
3518 	}
3519 	return false;
3520 }
3521 
get_next_time_string_digit(int * failure_cnt,char ** pp,int min,int max)3522 int get_next_time_string_digit(int *failure_cnt, char **pp, int min, int max)
3523 {
3524 	char digits[TIME_STRING_DIGIT_STRLEN + SIZE_OF_NUL];
3525 	int result;
3526 
3527 	memset(digits, 0, sizeof(digits));
3528 	memcpy(digits, *pp, TIME_STRING_DIGIT_STRLEN);
3529 	*pp += TIME_STRING_DIGIT_STRLEN + TIME_STRING_SEPARATOR_STRLEN;
3530 	result = strtol(digits, NULL, 10);
3531 	if (result > max) {
3532 		*failure_cnt += 1;
3533 		return max;
3534 	} else if (result < min) {
3535 		*failure_cnt += 1;
3536 		return min;
3537 	} else {
3538 		return result;
3539 	}
3540 }
3541 
convert_time_string_to_struct(struct tm * tm,int32_t * offset,char * time_string)3542 static bool convert_time_string_to_struct(struct tm *tm, int32_t *offset,
3543 					  char *time_string)
3544 {
3545 	int fc = 0;
3546 	char *ptr = time_string;
3547 
3548 	if (!valid_time_string(ptr)) {
3549 		return false;
3550 	}
3551 	ptr = &ptr[TIME_STRING_FIRST_DIGIT_INDEX];
3552 	tm->tm_year = TIME_STRING_TO_TM_STRUCT_YEAR_OFFSET +
3553 		      get_next_time_string_digit(&fc, &ptr, TM_YEAR_RANGE);
3554 	tm->tm_mon =
3555 		get_next_time_string_digit(&fc, &ptr, TM_MONTH_RANGE_PLUS_1) -
3556 		1;
3557 	tm->tm_mday = get_next_time_string_digit(&fc, &ptr, TM_DAY_RANGE);
3558 	tm->tm_hour = get_next_time_string_digit(&fc, &ptr, TM_HOUR_RANGE);
3559 	tm->tm_min = get_next_time_string_digit(&fc, &ptr, TM_MIN_RANGE);
3560 	tm->tm_sec = get_next_time_string_digit(&fc, &ptr, TM_SEC_RANGE);
3561 	tm->tm_isdst = 0;
3562 	*offset = (int32_t)get_next_time_string_digit(&fc, &ptr,
3563 						      QUARTER_HOUR_RANGE) *
3564 		  SECONDS_PER_QUARTER_HOUR;
3565 	if (time_string[TIME_STRING_PLUS_MINUS_INDEX] == '-') {
3566 		*offset *= -1;
3567 	}
3568 	return (fc == 0);
3569 }
3570 
3571 /* Handler: +CEREG: <stat>[,[<lac>],[<ci>],[<AcT>]
3572  *  [,[<cause_type>],[<reject_cause>] [,[<Active-Time>],[<Periodic-TAU>]]]]
3573  */
on_cmd_network_report(struct net_buf ** buf,uint16_t len)3574 static bool on_cmd_network_report(struct net_buf **buf, uint16_t len)
3575 {
3576 	size_t out_len;
3577 	char *pos;
3578 	int l;
3579 	char val[MDM_MAX_RESP_SIZE];
3580 
3581 	out_len = net_buf_linearize(ictx.mdm_network_status,
3582 				    sizeof(ictx.mdm_network_status) - 1, *buf,
3583 				    0, len);
3584 	ictx.mdm_network_status[out_len] = 0;
3585 	LOG_DBG("Network status: %s", ictx.mdm_network_status);
3586 	pos = strchr(ictx.mdm_network_status, ',');
3587 	if (pos) {
3588 		l = pos - ictx.mdm_network_status;
3589 		strncpy(val, ictx.mdm_network_status, l);
3590 		val[l] = 0;
3591 		set_network_state(strtol(val, NULL, 0));
3592 	} else {
3593 		set_network_state(strtol(ictx.mdm_network_status, NULL, 0));
3594 	}
3595 
3596 	/* keep HL7800 awake because we want to process the network state soon */
3597 	allow_sleep(false);
3598 	/* start work to adjust iface */
3599 	k_work_reschedule_for_queue(&hl7800_workq, &ictx.iface_status_work,
3600 				    IFACE_WORK_DELAY);
3601 
3602 	return true;
3603 }
3604 
3605 /* Handler: +KCELLMEAS: <RSRP>,<Downlink Path Loss>,<PUSCH Tx Power>,
3606  *                       <PUCCH Tx Power>,<SiNR>
3607  */
on_cmd_atcmdinfo_rssi(struct net_buf ** buf,uint16_t len)3608 static bool on_cmd_atcmdinfo_rssi(struct net_buf **buf, uint16_t len)
3609 {
3610 	/* number of ',' delimiters in this response */
3611 	int num_delims = KCELLMEAS_RESPONSE_NUM_DELIMS;
3612 	char *delims[KCELLMEAS_RESPONSE_NUM_DELIMS];
3613 	size_t out_len;
3614 	char value[MDM_MAX_RESP_SIZE];
3615 	char *search_start;
3616 	int i;
3617 
3618 	out_len = net_buf_linearize(value, len, *buf, 0, len);
3619 	value[out_len] = 0;
3620 	search_start = value;
3621 
3622 	/* find all delimiters */
3623 	for (i = 0; i < num_delims; i++) {
3624 		delims[i] = strchr(search_start, ',');
3625 		if (!delims[i]) {
3626 			LOG_ERR("Could not find delim %d, val: %s", i,
3627 				value);
3628 			goto done;
3629 		}
3630 		/* Start next search after current delim location */
3631 		search_start = delims[i] + 1;
3632 	}
3633 	/* the first value in the message is the RSRP */
3634 	ictx.mdm_rssi = strtol(value, NULL, 10);
3635 	/* the 4th ',' (last in the msg) is the start of the SINR */
3636 	ictx.mdm_sinr = strtol(delims[3] + 1, NULL, 10);
3637 	if ((delims[1] - delims[0]) == 1) {
3638 		/* there is no value between the first and second
3639 		 *  delimiter, signal is unknown
3640 		 */
3641 		LOG_INF("RSSI (RSRP): UNKNOWN");
3642 	} else {
3643 		LOG_INF("RSSI (RSRP): %d SINR: %d", ictx.mdm_rssi,
3644 			ictx.mdm_sinr);
3645 		event_handler(HL7800_EVENT_RSSI, &ictx.mdm_rssi);
3646 		event_handler(HL7800_EVENT_SINR, &ictx.mdm_sinr);
3647 	}
3648 done:
3649 	return true;
3650 }
3651 
3652 /* Handle the "OK" response from an AT command or a socket call */
on_cmd_sockok(struct net_buf ** buf,uint16_t len)3653 static bool on_cmd_sockok(struct net_buf **buf, uint16_t len)
3654 {
3655 	struct hl7800_socket *sock = NULL;
3656 
3657 	sock = socket_from_id(ictx.last_socket_id);
3658 	if (!sock) {
3659 		ictx.last_error = 0;
3660 		k_sem_give(&ictx.response_sem);
3661 	} else {
3662 		sock->error = 0;
3663 		k_sem_give(&sock->sock_send_sem);
3664 	}
3665 	return true;
3666 }
3667 
3668 /* Handler: +KTCP_IND/+KUDP_IND */
on_cmd_sock_ind(struct net_buf ** buf,uint16_t len,const char * const type)3669 static bool on_cmd_sock_ind(struct net_buf **buf, uint16_t len, const char *const type)
3670 {
3671 	struct hl7800_socket *sock = NULL;
3672 	char *delim;
3673 	char value[MDM_MAX_RESP_SIZE];
3674 	size_t out_len;
3675 	int id;
3676 
3677 	ictx.last_error = 0;
3678 
3679 	out_len = net_buf_linearize(value, sizeof(value), *buf, 0, len);
3680 	value[out_len] = 0;
3681 
3682 	/* find ',' because this is the format we expect */
3683 	delim = strchr(value, ',');
3684 	if (!delim) {
3685 		LOG_ERR("%s could not find ','", type);
3686 		goto done;
3687 	}
3688 
3689 	id = strtol(value, NULL, 10);
3690 	LOG_DBG("%s ID: %d", type, id);
3691 	sock = socket_from_id(id);
3692 	if (sock) {
3693 		sock->error = 0;
3694 		k_sem_give(&sock->sock_send_sem);
3695 	}
3696 
3697 done:
3698 	return true;
3699 }
3700 
on_cmd_ktcp_ind(struct net_buf ** buf,uint16_t len)3701 static bool on_cmd_ktcp_ind(struct net_buf **buf, uint16_t len)
3702 {
3703 	return on_cmd_sock_ind(buf, len, "+KTCP_IND");
3704 }
3705 
on_cmd_kudp_ind(struct net_buf ** buf,uint16_t len)3706 static bool on_cmd_kudp_ind(struct net_buf **buf, uint16_t len)
3707 {
3708 	return on_cmd_sock_ind(buf, len, "+KUDP_IND");
3709 }
3710 
3711 
3712 /* Handler: ERROR */
on_cmd_sockerror(struct net_buf ** buf,uint16_t len)3713 static bool on_cmd_sockerror(struct net_buf **buf, uint16_t len)
3714 {
3715 	struct hl7800_socket *sock = NULL;
3716 	char string[MDM_MAX_RESP_SIZE];
3717 
3718 	if (len > 0) {
3719 		memset(string, 0, sizeof(string));
3720 		net_buf_linearize(string, sizeof(string), *buf, 0, len);
3721 		LOG_ERR("'%s'", string);
3722 	}
3723 
3724 	sock = socket_from_id(ictx.last_socket_id);
3725 	if (!sock) {
3726 		ictx.last_error = -EIO;
3727 		k_sem_give(&ictx.response_sem);
3728 	} else {
3729 		sock->error = -EIO;
3730 		k_sem_give(&sock->sock_send_sem);
3731 	}
3732 
3733 	return true;
3734 }
3735 
3736 /* Handler: CME/CMS Error */
on_cmd_sock_error_code(struct net_buf ** buf,uint16_t len)3737 static bool on_cmd_sock_error_code(struct net_buf **buf, uint16_t len)
3738 {
3739 	struct hl7800_socket *sock = NULL;
3740 	char value[MDM_MAX_RESP_SIZE];
3741 	size_t out_len;
3742 
3743 	out_len = net_buf_linearize(value, sizeof(value), *buf, 0, len);
3744 	value[out_len] = 0;
3745 
3746 	LOG_ERR("Error code: %s", value);
3747 
3748 	sock = socket_from_id(ictx.last_socket_id);
3749 	if (!sock) {
3750 		ictx.last_error = -EIO;
3751 		k_sem_give(&ictx.response_sem);
3752 	} else {
3753 		sock->error = -EIO;
3754 		k_sem_give(&sock->sock_send_sem);
3755 	}
3756 
3757 	return true;
3758 }
3759 
sock_notif_cb_work(struct k_work * work)3760 static void sock_notif_cb_work(struct k_work *work)
3761 {
3762 	struct hl7800_socket *sock = NULL;
3763 	struct k_work_delayable *dwork;
3764 
3765 	dwork = k_work_delayable_from_work(work);
3766 	sock = CONTAINER_OF(dwork, struct hl7800_socket, notif_work);
3767 
3768 	hl7800_lock();
3769 	/* send null packet */
3770 	if (sock->recv_pkt != NULL) {
3771 		/* we are in the middle of RX,
3772 		 * requeue this and try again
3773 		 */
3774 		k_work_reschedule_for_queue(&hl7800_workq, &sock->notif_work,
3775 					    MDM_SOCK_NOTIF_DELAY);
3776 	} else {
3777 		if (sock->type == SOCK_STREAM) {
3778 			LOG_DBG("Sock %d trigger NULL packet", sock->socket_id);
3779 			k_work_submit_to_queue(&hl7800_workq, &sock->recv_cb_work);
3780 		}
3781 	}
3782 	hl7800_unlock();
3783 }
3784 
3785 /* Handler: +KTCP_NOTIF/+KUDP_NOTIF */
on_cmd_sock_notif(struct net_buf ** buf,uint16_t len)3786 static bool on_cmd_sock_notif(struct net_buf **buf, uint16_t len)
3787 {
3788 	struct hl7800_socket *sock = NULL;
3789 	char *delim;
3790 	char value[MDM_MAX_RESP_SIZE];
3791 	size_t out_len;
3792 	uint8_t notif_val;
3793 	bool err = false;
3794 	bool trigger_sem = true;
3795 	int id;
3796 
3797 	out_len = net_buf_linearize(value, sizeof(value), *buf, 0, len);
3798 	value[out_len] = 0;
3799 
3800 	/* find ',' because this is the format we expect */
3801 	delim = strchr(value, ',');
3802 	if (!delim) {
3803 		LOG_ERR("+K**P_NOTIF could not find ','");
3804 		goto done;
3805 	}
3806 
3807 	id = strtol(value, NULL, 10);
3808 	notif_val = strtol(delim + 1, NULL, 10);
3809 	if (notif_val == HL7800_TCP_DISCON) {
3810 		LOG_DBG("+K**P_NOTIF: %d,%d", id, notif_val);
3811 	} else {
3812 		LOG_WRN("+K**P_NOTIF: %d,%d", id, notif_val);
3813 	}
3814 	sock = socket_from_id(id);
3815 	if (!sock) {
3816 		goto done;
3817 	}
3818 
3819 	switch (notif_val) {
3820 	case HL7800_TCP_DATA_SND:
3821 		err = false;
3822 		sock->error = 0;
3823 		break;
3824 	case HL7800_TCP_DISCON:
3825 		trigger_sem = false;
3826 		err = true;
3827 		sock->error = -ENOTCONN;
3828 		break;
3829 	default:
3830 		ictx.network_dropped = true;
3831 		err = true;
3832 		sock->error = -EIO;
3833 		break;
3834 	}
3835 
3836 	if (err) {
3837 		/* Send NULL packet to callback to notify upper stack layers
3838 		 * that the peer closed the connection or there was an error.
3839 		 * This is so an app will not get stuck in recv() forever.
3840 		 * Let's do the callback processing in a different work queue
3841 		 * so RX is not delayed.
3842 		 */
3843 		k_work_reschedule_for_queue(&hl7800_workq, &sock->notif_work, MDM_SOCK_NOTIF_DELAY);
3844 		if (trigger_sem) {
3845 			k_sem_give(&sock->sock_send_sem);
3846 		}
3847 
3848 		if (ictx.network_dropped) {
3849 			k_work_reschedule_for_queue(&hl7800_workq, &ictx.iface_status_work,
3850 						    IFACE_WORK_DELAY);
3851 		}
3852 	}
3853 done:
3854 	return true;
3855 }
3856 
delete_socket(struct hl7800_socket * sock,enum net_sock_type type,uint8_t id)3857 static int delete_socket(struct hl7800_socket *sock, enum net_sock_type type, uint8_t id)
3858 {
3859 	char cmd[sizeof("AT+KUDPCLOSE=###")];
3860 
3861 	if (type == SOCK_STREAM) {
3862 		snprintk(cmd, sizeof(cmd), "AT+KTCPDEL=%d", id);
3863 	} else if (type == SOCK_DGRAM) {
3864 		snprintk(cmd, sizeof(cmd), "AT+KUDPCLOSE=%d", id);
3865 	}
3866 
3867 	return send_at_cmd(sock, cmd, MDM_CMD_SEND_TIMEOUT, 0, false);
3868 }
3869 
delete_untracked_socket_work_cb(struct k_work * item)3870 static void delete_untracked_socket_work_cb(struct k_work *item)
3871 {
3872 	struct stale_socket *sock = NULL;
3873 
3874 	do {
3875 		sock = dequeue_stale_socket();
3876 		if (sock != NULL) {
3877 			LOG_DBG("Delete untracked socket [%d]", sock->id);
3878 			delete_socket(NULL, sock->type, sock->id);
3879 			free_stale_socket(sock);
3880 		}
3881 	} while (sock != NULL);
3882 }
3883 
on_cmd_sockcreate(enum net_sock_type type,struct net_buf ** buf,uint16_t len)3884 static bool on_cmd_sockcreate(enum net_sock_type type, struct net_buf **buf, uint16_t len)
3885 {
3886 	size_t out_len;
3887 	char value[MDM_MAX_RESP_SIZE];
3888 	struct hl7800_socket *sock = NULL;
3889 
3890 	out_len = net_buf_linearize(value, sizeof(value), *buf, 0, len);
3891 	value[out_len] = 0;
3892 	ictx.last_socket_id = strtol(value, NULL, 10);
3893 	if (type == SOCK_STREAM) {
3894 		LOG_DBG("+KTCPCFG: %d", ictx.last_socket_id);
3895 	} else if (type == SOCK_DGRAM) {
3896 		LOG_DBG("+KUDPCFG: %d", ictx.last_socket_id);
3897 	}
3898 
3899 	/* check if the socket has been created already */
3900 	sock = socket_from_id(ictx.last_socket_id);
3901 	if (!sock) {
3902 		LOG_DBG("look up new socket by creation id");
3903 		sock = socket_from_id(MDM_CREATE_SOCKET_ID);
3904 		if (!sock) {
3905 			if (queue_stale_socket(type, ictx.last_socket_id) == 0) {
3906 				/* delay some time before socket cleanup in case there
3907 				 * are multiple sockets to cleanup
3908 				 */
3909 				k_work_reschedule_for_queue(&hl7800_workq,
3910 							    &ictx.delete_untracked_socket_work,
3911 							    SOCKET_CLEANUP_WORK_DELAY);
3912 			}
3913 			goto done;
3914 		}
3915 	}
3916 
3917 	sock->socket_id = ictx.last_socket_id;
3918 	sock->created = true;
3919 	sock->reconfig = false;
3920 	/* don't give back semaphore -- OK to follow */
3921 done:
3922 	return true;
3923 }
3924 
3925 /* Handler: +KTCPCFG: <session_id> */
on_cmd_sock_tcp_create(struct net_buf ** buf,uint16_t len)3926 static bool on_cmd_sock_tcp_create(struct net_buf **buf, uint16_t len)
3927 {
3928 	return on_cmd_sockcreate(SOCK_STREAM, buf, len);
3929 }
3930 
3931 /* Handler: +KUDPCFG: <session_id> */
on_cmd_sock_udp_create(struct net_buf ** buf,uint16_t len)3932 static bool on_cmd_sock_udp_create(struct net_buf **buf, uint16_t len)
3933 {
3934 	return on_cmd_sockcreate(SOCK_DGRAM, buf, len);
3935 }
3936 
sockreadrecv_cb_work(struct k_work * work)3937 static void sockreadrecv_cb_work(struct k_work *work)
3938 {
3939 	struct hl7800_socket *sock = NULL;
3940 	struct net_pkt *pkt;
3941 
3942 	sock = CONTAINER_OF(work, struct hl7800_socket, recv_cb_work);
3943 
3944 	LOG_DBG("Sock %d RX CB (size: %zd)", sock->socket_id,
3945 		(sock->recv_pkt != NULL) ? net_pkt_get_len(sock->recv_pkt) : 0);
3946 	/* return data */
3947 	pkt = sock->recv_pkt;
3948 	sock->recv_pkt = NULL;
3949 	if (sock->recv_cb) {
3950 		sock->recv_cb(sock->context, pkt, NULL, NULL, 0,
3951 			      sock->recv_user_data);
3952 	} else {
3953 		net_pkt_unref(pkt);
3954 	}
3955 }
3956 
sock_read(struct net_buf ** buf,uint16_t len)3957 static void sock_read(struct net_buf **buf, uint16_t len)
3958 {
3959 	struct hl7800_socket *sock = NULL;
3960 	struct net_buf *frag;
3961 	uint8_t c = 0U;
3962 	int i, hdr_len;
3963 	char ok_resp[sizeof(OK_STRING)];
3964 	char eof[sizeof(EOF_PATTERN)];
3965 	size_t out_len;
3966 
3967 	sock = socket_from_id(ictx.last_socket_id);
3968 	if (!sock) {
3969 		LOG_ERR("Socket not found! (%d)", ictx.last_socket_id);
3970 		goto exit;
3971 	}
3972 
3973 	if (sock->error != 0) {
3974 		/* cancel notif work and restart */
3975 		k_work_reschedule_for_queue(&hl7800_workq, &sock->notif_work,
3976 					    MDM_SOCK_NOTIF_DELAY);
3977 	}
3978 
3979 	LOG_DBG("Socket %d RX %u bytes", sock->socket_id, sock->rx_size);
3980 
3981 	/* remove ending \r\n from last CONNECT */
3982 	if (net_buf_frags_len(*buf) < 2) {
3983 		/* wait for \n to be RXd.  \r was already RXd. */
3984 		wait_for_modem_data(buf, 0, 1);
3985 	}
3986 	/* remove \r\n */
3987 	net_buf_remove(buf, 2);
3988 	if (!*buf) {
3989 		wait_for_modem_data(buf, 0, sock->rx_size);
3990 	}
3991 
3992 	LOG_DBG("Processing RX, buf len: %zd", net_buf_frags_len(*buf));
3993 
3994 	/* allocate an RX pkt */
3995 	sock->recv_pkt = net_pkt_rx_alloc_with_buffer(
3996 		net_context_get_iface(sock->context), sock->rx_size,
3997 		sock->family, sock->ip_proto, BUF_ALLOC_TIMEOUT);
3998 	if (!sock->recv_pkt) {
3999 		LOG_ERR("Failed net_pkt_get_reserve_rx!");
4000 		goto done;
4001 	}
4002 
4003 	/* set pkt data */
4004 	net_pkt_set_context(sock->recv_pkt, sock->context);
4005 
4006 	/* add IP / protocol headers */
4007 	hdr_len = pkt_setup_ip_data(sock->recv_pkt, sock);
4008 
4009 	/* receive data */
4010 	for (i = 0; i < sock->rx_size; i++) {
4011 		/* pull data from buf and advance to the next frag if needed */
4012 		c = net_buf_get_u8(buf);
4013 		/* write data to packet */
4014 		if (net_pkt_write_u8(sock->recv_pkt, c)) {
4015 			LOG_ERR("Unable to add data! Aborting! Bytes RXd:%d",
4016 				i);
4017 			goto rx_err;
4018 		}
4019 
4020 		if (!*buf && i < sock->rx_size) {
4021 			LOG_DBG("RX more data, bytes RXd:%d", i + 1);
4022 			/* wait for at least one more byte */
4023 			wait_for_modem_data(buf, 0, 1);
4024 			if (!*buf) {
4025 				LOG_ERR("No data in buf!");
4026 				break;
4027 			}
4028 		}
4029 	}
4030 
4031 	LOG_DBG("Got all data, get EOF and OK (buf len:%zd)",
4032 		net_buf_frags_len(*buf));
4033 
4034 	if (!*buf || (net_buf_frags_len(*buf) < strlen(EOF_PATTERN))) {
4035 		wait_for_modem_data(buf, net_buf_frags_len(*buf),
4036 				    strlen(EOF_PATTERN));
4037 		if (!*buf) {
4038 			LOG_WRN("No EOF present");
4039 			goto all_rx_data;
4040 		}
4041 	}
4042 
4043 	out_len = net_buf_linearize(eof, sizeof(eof), *buf, 0,
4044 				    strlen(EOF_PATTERN));
4045 	eof[out_len] = 0;
4046 	/* remove EOF pattern from buffer */
4047 	net_buf_remove(buf, strlen(EOF_PATTERN));
4048 	if (strcmp(eof, EOF_PATTERN)) {
4049 		LOG_WRN("Could not find EOF [%s]", eof);
4050 	}
4051 
4052 	/* Make sure we have \r\nOK\r\n length in the buffer */
4053 	if (!*buf || (net_buf_frags_len(*buf) < strlen(OK_STRING) + 4)) {
4054 		wait_for_modem_data(buf, net_buf_frags_len(*buf),
4055 				    strlen(OK_STRING) + 4);
4056 		if (!*buf) {
4057 			LOG_WRN("No OK present");
4058 			goto all_rx_data;
4059 		}
4060 	}
4061 
4062 	frag = NULL;
4063 	len = net_buf_findcrlf(*buf, &frag);
4064 	if (!frag) {
4065 		LOG_WRN("Unable to find OK start");
4066 		goto all_rx_data;
4067 	}
4068 	/* remove \r\n before OK */
4069 	net_buf_skipcrlf(buf);
4070 
4071 	out_len = net_buf_linearize(ok_resp, sizeof(ok_resp), *buf, 0,
4072 				    strlen(OK_STRING));
4073 	ok_resp[out_len] = 0;
4074 	/* remove the message from the buffer */
4075 	net_buf_remove(buf, strlen(OK_STRING));
4076 	if (strcmp(ok_resp, OK_STRING)) {
4077 		LOG_WRN("Could not find OK [%s]", ok_resp);
4078 	}
4079 
4080 	/* remove \r\n after OK */
4081 	net_buf_skipcrlf(buf);
4082 
4083 all_rx_data:
4084 	net_pkt_cursor_init(sock->recv_pkt);
4085 	net_pkt_set_overwrite(sock->recv_pkt, true);
4086 
4087 	if (hdr_len > 0) {
4088 		net_pkt_skip(sock->recv_pkt, hdr_len);
4089 	}
4090 
4091 	/* Let's do the callback processing in a different work queue in
4092 	 * case the app takes a long time.
4093 	 */
4094 	k_work_submit_to_queue(&hl7800_workq, &sock->recv_cb_work);
4095 	LOG_DBG("Sock %d RX done", sock->socket_id);
4096 	goto done;
4097 rx_err:
4098 	net_pkt_unref(sock->recv_pkt);
4099 	sock->recv_pkt = NULL;
4100 done:
4101 	if (sock->type == SOCK_STREAM) {
4102 		if (sock->error == 0) {
4103 			sock->state = SOCK_CONNECTED;
4104 		}
4105 	} else {
4106 		sock->state = SOCK_IDLE;
4107 	}
4108 exit:
4109 	allow_sleep(true);
4110 	hl7800_TX_unlock();
4111 }
4112 
on_cmd_connect(struct net_buf ** buf,uint16_t len)4113 static bool on_cmd_connect(struct net_buf **buf, uint16_t len)
4114 {
4115 	bool remove_data_from_buffer = true;
4116 	struct hl7800_socket *sock = NULL;
4117 
4118 	sock = socket_from_id(ictx.last_socket_id);
4119 	if (!sock) {
4120 		LOG_ERR("Sock (%d) not found", ictx.last_socket_id);
4121 		goto done;
4122 	}
4123 
4124 	if (sock->state == SOCK_RX) {
4125 		remove_data_from_buffer = false;
4126 		sock_read(buf, len);
4127 	} else {
4128 		k_sem_give(&sock->sock_send_sem);
4129 	}
4130 
4131 done:
4132 	return remove_data_from_buffer;
4133 }
4134 
start_socket_rx(struct hl7800_socket * sock,uint16_t rx_size)4135 static int start_socket_rx(struct hl7800_socket *sock, uint16_t rx_size)
4136 {
4137 	char sendbuf[sizeof("AT+KTCPRCV=+#########,#####")];
4138 
4139 	if ((sock->socket_id <= 0) || (sock->rx_size <= 0)) {
4140 		LOG_WRN("Cannot start socket RX, ID: %d rx size: %d",
4141 			sock->socket_id, sock->rx_size);
4142 		return -1;
4143 	}
4144 
4145 	LOG_DBG("Start socket RX ID:%d size:%d", sock->socket_id, rx_size);
4146 	sock->state = SOCK_RX;
4147 	if (sock->type == SOCK_DGRAM) {
4148 #if defined(CONFIG_NET_IPV4)
4149 		if (rx_size > (net_if_get_mtu(ictx.iface) - NET_IPV4UDPH_LEN)) {
4150 			sock->rx_size =
4151 				net_if_get_mtu(ictx.iface) - NET_IPV4UDPH_LEN;
4152 		}
4153 #endif
4154 #if defined(CONFIG_NET_IPV6)
4155 		if (rx_size > (net_if_get_mtu(ictx.iface) - NET_IPV6UDPH_LEN)) {
4156 			sock->rx_size =
4157 				net_if_get_mtu(ictx.iface) - NET_IPV6UDPH_LEN;
4158 		}
4159 #endif
4160 		snprintk(sendbuf, sizeof(sendbuf), "AT+KUDPRCV=%d,%u",
4161 			 sock->socket_id, rx_size);
4162 	} else {
4163 #if defined(CONFIG_NET_IPV4)
4164 		if (rx_size > (net_if_get_mtu(ictx.iface) - NET_IPV4TCPH_LEN)) {
4165 			sock->rx_size =
4166 				net_if_get_mtu(ictx.iface) - NET_IPV4TCPH_LEN;
4167 		}
4168 #endif
4169 #if defined(CONFIG_NET_IPV6)
4170 		if (rx_size > (net_if_get_mtu(ictx.iface) - NET_IPV6TCPH_LEN)) {
4171 			sock->rx_size =
4172 				net_if_get_mtu(ictx.iface) - NET_IPV6TCPH_LEN;
4173 		}
4174 #endif
4175 		snprintk(sendbuf, sizeof(sendbuf), "AT+KTCPRCV=%d,%u",
4176 			 sock->socket_id, sock->rx_size);
4177 	}
4178 
4179 	/* Send AT+K**PRCV, The modem
4180 	 * will respond with "CONNECT" and the data requested
4181 	 * and then "OK" or "ERROR".
4182 	 * The rest of the data processing will be handled
4183 	 * once CONNECT is RXd.
4184 	 */
4185 	send_at_cmd(sock, sendbuf, K_NO_WAIT, 0, false);
4186 	return 0;
4187 }
4188 
sock_rx_data_cb_work(struct k_work * work)4189 static void sock_rx_data_cb_work(struct k_work *work)
4190 {
4191 	struct hl7800_socket *sock = NULL;
4192 	int rc;
4193 
4194 	sock = CONTAINER_OF(work, struct hl7800_socket, rx_data_work);
4195 
4196 	hl7800_lock();
4197 	wakeup_hl7800();
4198 
4199 	/* start RX */
4200 	rc = start_socket_rx(sock, sock->rx_size);
4201 
4202 	/* Only unlock the RX because we just locked it above.
4203 	 *  At the end of socket RX, the TX will be unlocked.
4204 	 */
4205 	hl7800_RX_unlock();
4206 	if (rc < 0) {
4207 		/* we didn't start socket RX so unlock TX now. */
4208 		hl7800_TX_unlock();
4209 	}
4210 }
4211 
4212 /* Handler: +KTCP_DATA/+KUDP_DATA: <socket_id>,<left_bytes> */
on_cmd_sockdataind(struct net_buf ** buf,uint16_t len)4213 static bool on_cmd_sockdataind(struct net_buf **buf, uint16_t len)
4214 {
4215 	int socket_id, left_bytes, rc;
4216 	size_t out_len;
4217 	char *delim;
4218 	char value[sizeof("##,####")];
4219 	struct hl7800_socket *sock = NULL;
4220 	bool unlock = false;
4221 	bool defer_rx = false;
4222 
4223 	if (!hl7800_TX_locked()) {
4224 		hl7800_TX_lock();
4225 		unlock = true;
4226 	} else {
4227 		defer_rx = true;
4228 	}
4229 
4230 	out_len = net_buf_linearize(value, sizeof(value) - 1, *buf, 0, len);
4231 	value[out_len] = 0;
4232 
4233 	/* First comma separator marks the end of socket_id */
4234 	delim = strchr(value, ',');
4235 	if (!delim) {
4236 		LOG_ERR("Missing comma");
4237 		goto error;
4238 	}
4239 
4240 	/* replace comma with null */
4241 	*delim++ = '\0';
4242 	socket_id = strtol(value, NULL, 0);
4243 
4244 	/* second param is for left_bytes */
4245 	left_bytes = strtol(delim, NULL, 0);
4246 
4247 	sock = socket_from_id(socket_id);
4248 	if (!sock) {
4249 		LOG_ERR("Unable to find socket_id:%d", socket_id);
4250 		goto error;
4251 	}
4252 
4253 	sock->rx_size = left_bytes;
4254 	if (defer_rx) {
4255 		LOG_DBG("Defer socket RX -> ID: %d bytes: %u", socket_id,
4256 			left_bytes);
4257 		k_work_submit_to_queue(&hl7800_workq, &sock->rx_data_work);
4258 	} else {
4259 		if (left_bytes > 0) {
4260 			rc = start_socket_rx(sock, left_bytes);
4261 			if (rc < 0) {
4262 				goto error;
4263 			}
4264 			goto done;
4265 		}
4266 	}
4267 error:
4268 	if (unlock) {
4269 		hl7800_TX_unlock();
4270 	}
4271 done:
4272 	return true;
4273 }
4274 
4275 /* Handler: +WDSI: ## */
on_cmd_device_service_ind(struct net_buf ** buf,uint16_t len)4276 static bool on_cmd_device_service_ind(struct net_buf **buf, uint16_t len)
4277 {
4278 	char value[MDM_MAX_RESP_SIZE];
4279 	size_t out_len;
4280 
4281 	memset(value, 0, sizeof(value));
4282 	out_len = net_buf_linearize(value, sizeof(value), *buf, 0, len);
4283 	if (out_len > 0) {
4284 		ictx.device_services_ind = strtol(value, NULL, 10);
4285 	}
4286 	LOG_INF("+WDSI: %d", ictx.device_services_ind);
4287 
4288 #ifdef CONFIG_MODEM_HL7800_FW_UPDATE
4289 	if (ictx.device_services_ind == WDSI_PKG_DOWNLOADED) {
4290 		k_work_submit_to_queue(&hl7800_workq,
4291 				       &ictx.finish_fw_update_work);
4292 	}
4293 #endif
4294 
4295 	return true;
4296 }
4297 
read_rx_allocator(k_timeout_t timeout,void * user_data)4298 static inline struct net_buf *read_rx_allocator(k_timeout_t timeout,
4299 						void *user_data)
4300 {
4301 	return net_buf_alloc((struct net_buf_pool *)user_data, timeout);
4302 }
4303 
hl7800_read_rx(struct net_buf ** buf)4304 static size_t hl7800_read_rx(struct net_buf **buf)
4305 {
4306 	uint8_t uart_buffer[CONFIG_MODEM_HL7800_RECV_BUF_SIZE];
4307 	size_t bytes_read, total_read;
4308 	int ret;
4309 	uint16_t rx_len;
4310 
4311 	bytes_read = 0, total_read = 0;
4312 
4313 	/* read all of the data from mdm_receiver */
4314 	while (true) {
4315 		ret = mdm_receiver_recv(&ictx.mdm_ctx, uart_buffer,
4316 					sizeof(uart_buffer), &bytes_read);
4317 		if (ret < 0 || bytes_read == 0) {
4318 			/* mdm_receiver buffer is empty */
4319 			break;
4320 		}
4321 
4322 		if (IS_ENABLED(HL7800_ENABLE_VERBOSE_MODEM_RECV_HEXDUMP)) {
4323 			LOG_HEXDUMP_DBG((const uint8_t *)&uart_buffer,
4324 					bytes_read, "HL7800 RX");
4325 		}
4326 		/* make sure we have storage */
4327 		if (!*buf) {
4328 			*buf = net_buf_alloc(&mdm_recv_pool, BUF_ALLOC_TIMEOUT);
4329 			if (!*buf) {
4330 				LOG_ERR("Can't allocate RX data! "
4331 					"Skipping data!");
4332 				break;
4333 			}
4334 		}
4335 
4336 		rx_len =
4337 			net_buf_append_bytes(*buf, bytes_read, uart_buffer,
4338 					     BUF_ALLOC_TIMEOUT,
4339 					     read_rx_allocator, &mdm_recv_pool);
4340 		if (rx_len < bytes_read) {
4341 			LOG_ERR("Data was lost! read %u of %zu!", rx_len,
4342 				bytes_read);
4343 		}
4344 		total_read += bytes_read;
4345 	}
4346 
4347 	return total_read;
4348 }
4349 
4350 #ifdef CONFIG_MODEM_HL7800_FW_UPDATE
finish_fw_update_work_callback(struct k_work * item)4351 static void finish_fw_update_work_callback(struct k_work *item)
4352 {
4353 	ARG_UNUSED(item);
4354 
4355 	send_at_cmd(NULL, "AT+WDSR=4", MDM_CMD_SEND_TIMEOUT, 0, false);
4356 	ictx.fw_updated = true;
4357 	set_fota_state(HL7800_FOTA_INSTALL);
4358 	hl7800_unlock();
4359 }
4360 
calc_fw_update_crc(uint8_t * ptr,int count)4361 static uint8_t calc_fw_update_crc(uint8_t *ptr, int count)
4362 {
4363 	uint8_t crc = 0;
4364 	unsigned char l;
4365 	uint16_t i = 0;
4366 
4367 	while (i < count) {
4368 		l = *ptr;
4369 		crc += l;
4370 		++ptr;
4371 		++i;
4372 	}
4373 
4374 	return crc;
4375 }
4376 
send_fw_update_packet(struct xmodem_packet * pkt)4377 static int send_fw_update_packet(struct xmodem_packet *pkt)
4378 {
4379 	generate_fota_count_event();
4380 	LOG_DBG("Send FW update packet %d,%d", pkt->id, ictx.fw_packet_count);
4381 	return mdm_receiver_send(&ictx.mdm_ctx, (const uint8_t *)pkt,
4382 				 XMODEM_PACKET_SIZE);
4383 }
4384 
prepare_and_send_fw_packet(void)4385 static int prepare_and_send_fw_packet(void)
4386 {
4387 	int ret = 0;
4388 	int read_res;
4389 
4390 	ictx.fw_packet.id_complement = 0xFF - ictx.fw_packet.id;
4391 
4392 	ret = fs_seek(&ictx.fw_update_file, ictx.file_pos, FS_SEEK_SET);
4393 	if (ret < 0) {
4394 		set_fota_state(HL7800_FOTA_FILE_ERROR);
4395 		LOG_ERR("Could not seek to offset %d of file", ictx.file_pos);
4396 		return ret;
4397 	}
4398 
4399 	read_res = fs_read(&ictx.fw_update_file, ictx.fw_packet.data,
4400 			   XMODEM_DATA_SIZE);
4401 	if (read_res < 0) {
4402 		set_fota_state(HL7800_FOTA_FILE_ERROR);
4403 		LOG_ERR("Failed to read fw update file [%d]", read_res);
4404 		return ret;
4405 	} else if (read_res < XMODEM_DATA_SIZE) {
4406 		set_fota_state(HL7800_FOTA_PAD);
4407 		fs_close(&ictx.fw_update_file);
4408 		/* pad rest of data */
4409 		for (int i = read_res; i < XMODEM_DATA_SIZE; i++) {
4410 			ictx.fw_packet.data[i] = XMODEM_PAD_VALUE;
4411 		}
4412 	}
4413 
4414 	ictx.fw_packet.crc =
4415 		calc_fw_update_crc(ictx.fw_packet.data, XMODEM_DATA_SIZE);
4416 
4417 	send_fw_update_packet(&ictx.fw_packet);
4418 
4419 	ictx.file_pos += read_res;
4420 	ictx.fw_packet_count++;
4421 	ictx.fw_packet.id++;
4422 
4423 	return ret;
4424 }
4425 
process_fw_update_rx(struct net_buf ** rx_buf)4426 static void process_fw_update_rx(struct net_buf **rx_buf)
4427 {
4428 	static uint8_t xm_msg;
4429 	uint8_t eot = XM_EOT;
4430 
4431 	xm_msg = net_buf_get_u8(rx_buf);
4432 
4433 	if (xm_msg == XM_NACK) {
4434 		if (ictx.fw_update_state == HL7800_FOTA_START) {
4435 			/* send first FW update packet */
4436 			set_fota_state(HL7800_FOTA_WIP);
4437 			ictx.file_pos = 0;
4438 			ictx.fw_packet_count = 1;
4439 			ictx.fw_packet.id = 1;
4440 			ictx.fw_packet.preamble = XM_SOH_1K;
4441 
4442 			prepare_and_send_fw_packet();
4443 		} else if (ictx.fw_update_state == HL7800_FOTA_WIP) {
4444 			LOG_DBG("RX FW update NACK");
4445 			/* resend last packet */
4446 			send_fw_update_packet(&ictx.fw_packet);
4447 		}
4448 	} else if (xm_msg == XM_ACK) {
4449 		LOG_DBG("RX FW update ACK");
4450 		if (ictx.fw_update_state == HL7800_FOTA_WIP) {
4451 			/* send next FW update packet */
4452 			prepare_and_send_fw_packet();
4453 		} else if (ictx.fw_update_state == HL7800_FOTA_PAD) {
4454 			set_fota_state(HL7800_FOTA_SEND_EOT);
4455 			mdm_receiver_send(&ictx.mdm_ctx, &eot, sizeof(eot));
4456 		}
4457 	} else {
4458 		LOG_WRN("RX unhandled FW update value: %02x", xm_msg);
4459 	}
4460 }
4461 
4462 #endif /* CONFIG_MODEM_HL7800_FW_UPDATE */
4463 
4464 /* RX thread */
hl7800_rx(void)4465 static void hl7800_rx(void)
4466 {
4467 	struct net_buf *rx_buf = NULL;
4468 	struct net_buf *frag = NULL;
4469 	int i, cmp_res;
4470 	uint16_t len;
4471 	size_t out_len;
4472 	bool cmd_handled = false;
4473 	static char rx_msg[MDM_HANDLER_MATCH_MAX_LEN];
4474 	bool unlock = false;
4475 	bool remove_line_from_buf = true;
4476 #ifdef HL7800_LOG_UNHANDLED_RX_MSGS
4477 	char msg[MDM_MAX_RESP_SIZE];
4478 #endif
4479 
4480 	static const struct cmd_handler handlers[] = {
4481 		/* MODEM Information */
4482 		CMD_HANDLER("AT+CGMI", atcmdinfo_manufacturer),
4483 		CMD_HANDLER("AT+CGMM", atcmdinfo_model),
4484 		CMD_HANDLER("AT+CGMR", atcmdinfo_revision),
4485 		CMD_HANDLER("AT+CGSN", atcmdinfo_imei),
4486 		CMD_HANDLER("AT+KGSN=3", atcmdinfo_serial_number),
4487 		CMD_HANDLER("+KCELLMEAS: ", atcmdinfo_rssi),
4488 		CMD_HANDLER("+CGCONTRDP: ", atcmdinfo_ipaddr),
4489 		CMD_HANDLER("+COPS: ", atcmdinfo_operator_status),
4490 		CMD_HANDLER("+KSRAT: ", radio_tech_status),
4491 		CMD_HANDLER("+KBNDCFG: ", radio_band_configuration),
4492 		CMD_HANDLER("+KBND: ", radio_active_bands),
4493 		CMD_HANDLER("+CCID: ", atcmdinfo_iccid),
4494 		CMD_HANDLER("ACTIVE PROFILE:", atcmdinfo_active_profile),
4495 		CMD_HANDLER("STORED PROFILE 0:", atcmdinfo_stored_profile0),
4496 		CMD_HANDLER("STORED PROFILE 1:", atcmdinfo_stored_profile1),
4497 		CMD_HANDLER("+WPPP: 1,1,", atcmdinfo_pdp_authentication_cfg),
4498 		CMD_HANDLER("+CGDCONT: 1", atcmdinfo_pdp_context),
4499 		CMD_HANDLER("AT+CEREG?", network_report_query),
4500 		CMD_HANDLER("+KCARRIERCFG: ", operator_index_query),
4501 		CMD_HANDLER("AT+CIMI", atcmdinfo_imsi),
4502 		CMD_HANDLER("+CFUN: ", modem_functionality),
4503 		CMD_HANDLER("%MEAS: ", survey_status),
4504 		CMD_HANDLER("+CCLK: ", rtc_query),
4505 
4506 		/* UNSOLICITED modem information */
4507 		/* mobile startup report */
4508 		CMD_HANDLER("+KSUP: ", startup_report),
4509 		/* network status */
4510 		CMD_HANDLER("+CEREG: ", network_report),
4511 
4512 		/* SOLICITED CMD AND SOCKET RESPONSES */
4513 		CMD_HANDLER("OK", sockok),
4514 		CMD_HANDLER("ERROR", sockerror),
4515 
4516 		/* SOLICITED SOCKET RESPONSES */
4517 		CMD_HANDLER("+CME ERROR: ", sock_error_code),
4518 		CMD_HANDLER("+CMS ERROR: ", sock_error_code),
4519 		CMD_HANDLER("+CEER: ", sockerror),
4520 		CMD_HANDLER("+KTCPCFG: ", sock_tcp_create),
4521 		CMD_HANDLER("+KUDPCFG: ", sock_udp_create),
4522 		CMD_HANDLER(CONNECT_STRING, connect),
4523 		CMD_HANDLER("NO CARRIER", sockerror),
4524 
4525 		/* UNSOLICITED SOCKET RESPONSES */
4526 		CMD_HANDLER("+KTCP_IND: ", ktcp_ind),
4527 		CMD_HANDLER("+KUDP_IND: ", kudp_ind),
4528 		CMD_HANDLER("+KTCP_NOTIF: ", sock_notif),
4529 		CMD_HANDLER("+KUDP_NOTIF: ", sock_notif),
4530 		CMD_HANDLER("+KTCP_DATA: ", sockdataind),
4531 		CMD_HANDLER("+KUDP_DATA: ", sockdataind),
4532 
4533 		/* FIRMWARE UPDATE RESPONSES */
4534 		CMD_HANDLER("+WDSI: ", device_service_ind),
4535 
4536 #ifdef CONFIG_MODEM_HL7800_GPS
4537 		CMD_HANDLER("+GNSSEV: ", gps_event),
4538 		CMD_HANDLER("Latitude: ", latitude),
4539 		CMD_HANDLER("Longitude: ", longitude),
4540 		CMD_HANDLER("GpsTime: ", gps_time),
4541 		CMD_HANDLER("FixType: ", fix_type),
4542 		CMD_HANDLER("HEPE: ", hepe),
4543 		CMD_HANDLER("Altitude: ", altitude),
4544 		CMD_HANDLER("AltUnc: ", alt_unc),
4545 		CMD_HANDLER("Direction: ", direction),
4546 		CMD_HANDLER("HorSpeed: ", hor_speed),
4547 		CMD_HANDLER("VerSpeed: ", ver_speed),
4548 #endif
4549 
4550 #ifdef CONFIG_MODEM_HL7800_POLTE
4551 		CMD_HANDLER("%POLTEEVU: \"REGISTER\",0,", polte_registration),
4552 		CMD_HANDLER("%POLTECMD: \"LOCATE\",", polte_locate_cmd_rsp),
4553 		CMD_HANDLER("%POLTEEVU: \"LOCATION\",", polte_location),
4554 #endif
4555 	};
4556 
4557 	while (true) {
4558 		/* wait for incoming data */
4559 		(void)k_sem_take(&ictx.mdm_ctx.rx_sem, K_FOREVER);
4560 
4561 		hl7800_read_rx(&rx_buf);
4562 		/* If an external module hasn't locked the command processor,
4563 		 * then do so now.
4564 		 */
4565 		if (!hl7800_RX_locked()) {
4566 			hl7800_RX_lock();
4567 			unlock = true;
4568 		} else {
4569 			unlock = false;
4570 		}
4571 
4572 		while (rx_buf) {
4573 			remove_line_from_buf = true;
4574 			cmd_handled = false;
4575 
4576 #ifdef CONFIG_MODEM_HL7800_FW_UPDATE
4577 			if ((ictx.fw_update_state == HL7800_FOTA_START) ||
4578 			    (ictx.fw_update_state == HL7800_FOTA_WIP) ||
4579 			    (ictx.fw_update_state == HL7800_FOTA_PAD)) {
4580 				process_fw_update_rx(&rx_buf);
4581 				if (!rx_buf) {
4582 					break;
4583 				}
4584 			}
4585 #endif
4586 
4587 			net_buf_skipcrlf(&rx_buf);
4588 			if (!rx_buf) {
4589 				break;
4590 			}
4591 
4592 			frag = NULL;
4593 			len = net_buf_findcrlf(rx_buf, &frag);
4594 			if (!frag) {
4595 				break;
4596 			}
4597 
4598 			out_len = net_buf_linearize(rx_msg, sizeof(rx_msg),
4599 						    rx_buf, 0, len);
4600 
4601 			/* look for matching data handlers */
4602 			i = -1;
4603 			for (i = 0; i < ARRAY_SIZE(handlers); i++) {
4604 				if (ictx.search_no_id_resp) {
4605 					cmp_res = strncmp(ictx.no_id_resp_cmd,
4606 							  handlers[i].cmd,
4607 							  handlers[i].cmd_len);
4608 				} else {
4609 					cmp_res =
4610 						strncmp(rx_msg, handlers[i].cmd,
4611 							handlers[i].cmd_len);
4612 				}
4613 
4614 				if (cmp_res == 0) {
4615 					/* found a matching handler */
4616 
4617 					/* skip cmd_len */
4618 					if (!ictx.search_no_id_resp) {
4619 						rx_buf = net_buf_skip(
4620 							rx_buf,
4621 							handlers[i].cmd_len);
4622 					}
4623 
4624 					/* locate next cr/lf */
4625 					frag = NULL;
4626 					len = net_buf_findcrlf(rx_buf, &frag);
4627 					if (!frag) {
4628 						break;
4629 					}
4630 
4631 					LOG_DBG("HANDLE %s (len:%u)",
4632 						handlers[i].cmd, len);
4633 					/* call handler */
4634 					if (handlers[i].func) {
4635 						remove_line_from_buf =
4636 							handlers[i].func(
4637 								&rx_buf, len);
4638 					}
4639 					cmd_handled = true;
4640 					ictx.search_no_id_resp = false;
4641 					frag = NULL;
4642 					/* make sure buf still has data */
4643 					if (!rx_buf) {
4644 						break;
4645 					}
4646 
4647 					/* We've handled the current line
4648 					 * and need to exit the "search for
4649 					 * handler loop".  Let's skip any
4650 					 * "extra" data and look for the next
4651 					 * CR/LF, leaving us ready for the
4652 					 * next handler search.
4653 					 */
4654 					len = net_buf_findcrlf(rx_buf, &frag);
4655 					break;
4656 				}
4657 			}
4658 
4659 			/* Handle unhandled commands */
4660 			if (IS_ENABLED(HL7800_LOG_UNHANDLED_RX_MSGS) &&
4661 			    !cmd_handled && frag && len > 1) {
4662 				out_len = net_buf_linearize(msg, sizeof(msg),
4663 							    rx_buf, 0, len);
4664 				msg[out_len] = 0;
4665 				LOG_HEXDUMP_DBG((const uint8_t *)&msg, len,
4666 						"UNHANDLED RX");
4667 			}
4668 			if (remove_line_from_buf && frag && rx_buf) {
4669 				/* clear out processed line (buffers) */
4670 				net_buf_remove(&rx_buf, len);
4671 			}
4672 		}
4673 
4674 		if (unlock) {
4675 			hl7800_RX_unlock();
4676 		}
4677 
4678 		/* give up time if we have a solid stream of data */
4679 		k_yield();
4680 	}
4681 }
4682 
shutdown_uart(void)4683 static void shutdown_uart(void)
4684 {
4685 #ifdef CONFIG_PM_DEVICE
4686 	int rc;
4687 
4688 	if (ictx.uart_on) {
4689 		HL7800_IO_DBG_LOG("Power OFF the UART");
4690 		uart_irq_rx_disable(ictx.mdm_ctx.uart_dev);
4691 		rc = pm_device_action_run(ictx.mdm_ctx.uart_dev, PM_DEVICE_ACTION_SUSPEND);
4692 		if (rc) {
4693 			LOG_ERR("Error disabling UART peripheral (%d)", rc);
4694 			uart_irq_rx_enable(ictx.mdm_ctx.uart_dev);
4695 		} else {
4696 			ictx.uart_on = false;
4697 		}
4698 	}
4699 #endif
4700 }
4701 
power_on_uart(void)4702 static void power_on_uart(void)
4703 {
4704 #ifdef CONFIG_PM_DEVICE
4705 	int rc;
4706 
4707 	if (!ictx.uart_on) {
4708 		HL7800_IO_DBG_LOG("Power ON the UART");
4709 		rc = pm_device_action_run(ictx.mdm_ctx.uart_dev, PM_DEVICE_ACTION_RESUME);
4710 		if (rc) {
4711 			LOG_ERR("Error enabling UART peripheral (%d)", rc);
4712 			uart_irq_rx_disable(ictx.mdm_ctx.uart_dev);
4713 		} else {
4714 			uart_irq_rx_enable(ictx.mdm_ctx.uart_dev);
4715 			ictx.uart_on = true;
4716 		}
4717 	}
4718 #endif
4719 }
4720 
4721 /* Make sure all IO voltages are removed for proper reset. */
prepare_io_for_reset(void)4722 static void prepare_io_for_reset(void)
4723 {
4724 	HL7800_IO_DBG_LOG("Preparing IO for reset/sleep");
4725 	shutdown_uart();
4726 	modem_assert_wake(false);
4727 	modem_assert_pwr_on(false);
4728 	modem_assert_fast_shutd(false);
4729 	ictx.wait_for_KSUP = true;
4730 	ictx.wait_for_KSUP_tries = 0;
4731 }
4732 
mdm_vgpio_work_cb(struct k_work * item)4733 static void mdm_vgpio_work_cb(struct k_work *item)
4734 {
4735 	ARG_UNUSED(item);
4736 
4737 	hl7800_lock();
4738 	if (!ictx.vgpio_state) {
4739 		if (ictx.desired_sleep_level == HL7800_SLEEP_HIBERNATE ||
4740 		    ictx.desired_sleep_level == HL7800_SLEEP_LITE_HIBERNATE) {
4741 			if (ictx.sleep_state != ictx.desired_sleep_level) {
4742 				set_sleep_state(ictx.desired_sleep_level);
4743 			}
4744 		}
4745 		if (ictx.iface && ictx.initialized &&
4746 		    ictx.low_power_mode != HL7800_LPM_PSM) {
4747 			net_if_carrier_off(ictx.iface);
4748 		}
4749 	}
4750 	hl7800_unlock();
4751 }
4752 
mdm_vgpio_callback_isr(const struct device * port,struct gpio_callback * cb,uint32_t pins)4753 void mdm_vgpio_callback_isr(const struct device *port, struct gpio_callback *cb,
4754 			    uint32_t pins)
4755 {
4756 	ictx.vgpio_state = read_pin(1, &hl7800_cfg.gpio[MDM_VGPIO]);
4757 	HL7800_IO_DBG_LOG("VGPIO:%d", ictx.vgpio_state);
4758 	if (!ictx.vgpio_state) {
4759 		prepare_io_for_reset();
4760 		if (!ictx.restarting && ictx.initialized) {
4761 			ictx.reconfig_IP_connection = true;
4762 		}
4763 		check_hl7800_awake();
4764 	} else {
4765 		if (ictx.off) {
4766 			return;
4767 		}
4768 		/* The peripheral must be enabled in ISR context
4769 		 * because the driver may be
4770 		 * waiting for +KSUP or waiting to send commands.
4771 		 * This can occur, for example, during a modem reset.
4772 		 */
4773 		power_on_uart();
4774 		/* Keep the modem awake to see if it has anything to send to us. */
4775 		allow_sleep(false);
4776 		/* Allow the modem to go back to sleep if it was the one who
4777 		 * sourced the CTS transition.
4778 		 */
4779 		allow_sleep(true);
4780 	}
4781 
4782 	/* When the network state changes a semaphore must be taken.
4783 	 * This can't be done in interrupt context because the wait time != 0.
4784 	 */
4785 	k_work_submit_to_queue(&hl7800_workq, &ictx.mdm_vgpio_work);
4786 }
4787 
mdm_uart_dsr_callback_isr(const struct device * port,struct gpio_callback * cb,uint32_t pins)4788 void mdm_uart_dsr_callback_isr(const struct device *port,
4789 			       struct gpio_callback *cb, uint32_t pins)
4790 {
4791 	ictx.dsr_state = read_pin(1, &hl7800_cfg.gpio[MDM_UART_DSR]);
4792 	HL7800_IO_DBG_LOG("MDM_UART_DSR:%d", ictx.dsr_state);
4793 }
4794 
4795 #ifdef CONFIG_MODEM_HL7800_LOW_POWER_MODE
mark_sockets_for_reconfig(void)4796 static void mark_sockets_for_reconfig(void)
4797 {
4798 	int i;
4799 	struct hl7800_socket *sock = NULL;
4800 
4801 	for (i = 0; i < MDM_MAX_SOCKETS; i++) {
4802 		sock = &ictx.sockets[i];
4803 		if ((sock->context != NULL) && (sock->created)) {
4804 			/* mark socket as possibly needing re-configuration */
4805 			sock->reconfig = true;
4806 		}
4807 	}
4808 }
4809 #endif
4810 
mdm_gpio6_callback_isr(const struct device * port,struct gpio_callback * cb,uint32_t pins)4811 void mdm_gpio6_callback_isr(const struct device *port, struct gpio_callback *cb,
4812 			    uint32_t pins)
4813 {
4814 #ifdef CONFIG_MODEM_HL7800_LOW_POWER_MODE
4815 	ictx.gpio6_state = read_pin(1, &hl7800_cfg.gpio[MDM_GPIO6]);
4816 	HL7800_IO_DBG_LOG("MDM_GPIO6:%d", ictx.gpio6_state);
4817 	if (!ictx.gpio6_state) {
4818 		/* HL7800 is not awake, shut down UART to save power */
4819 		shutdown_uart();
4820 		ictx.wait_for_KSUP = true;
4821 		ictx.wait_for_KSUP_tries = 0;
4822 		ictx.reconfig_IP_connection = true;
4823 		mark_sockets_for_reconfig();
4824 		/* TODO: may need to indicate all TCP connections lost here */
4825 	} else {
4826 		if (ictx.off) {
4827 			return;
4828 		}
4829 		power_on_uart();
4830 	}
4831 
4832 	if ((ictx.gpio6_callback != NULL) &&
4833 	    ((ictx.desired_sleep_level == HL7800_SLEEP_HIBERNATE) ||
4834 	     (ictx.desired_sleep_level == HL7800_SLEEP_LITE_HIBERNATE))) {
4835 		ictx.gpio6_callback(ictx.gpio6_state);
4836 	}
4837 
4838 	check_hl7800_awake();
4839 #else
4840 	HL7800_IO_DBG_LOG("Spurious gpio6 interrupt from the modem");
4841 #endif
4842 }
4843 
4844 /**
4845  * @brief Short spikes in CTS can be removed in the signal used by the application
4846  */
glitch_filter(int default_state,const struct gpio_dt_spec * spec,uint32_t usec_to_wait,uint32_t max_iterations)4847 static int glitch_filter(int default_state, const struct gpio_dt_spec *spec,
4848 			 uint32_t usec_to_wait, uint32_t max_iterations)
4849 {
4850 	int i = 0;
4851 	int state1;
4852 	int state2;
4853 
4854 	do {
4855 		state1 = read_pin(-1, spec);
4856 		k_busy_wait(usec_to_wait);
4857 		state2 = read_pin(-1, spec);
4858 		i += 1;
4859 	} while (((state1 != state2) || (state1 < 0) || (state2 < 0)) && (i < max_iterations));
4860 
4861 	if (i >= max_iterations) {
4862 		LOG_WRN("glitch filter max iterations exceeded %d", i);
4863 		if (state1 < 0) {
4864 			if (state2 < 0) {
4865 				state1 = read_pin(default_state, spec);
4866 			} else {
4867 				state1 = state2;
4868 			}
4869 		}
4870 	}
4871 
4872 	return state1;
4873 }
4874 
mdm_uart_cts_callback(const struct device * port,struct gpio_callback * cb,uint32_t pins)4875 void mdm_uart_cts_callback(const struct device *port, struct gpio_callback *cb, uint32_t pins)
4876 {
4877 	ARG_UNUSED(port);
4878 	ARG_UNUSED(cb);
4879 	ARG_UNUSED(pins);
4880 
4881 	ictx.cts_state =
4882 		glitch_filter(0, &hl7800_cfg.gpio[MDM_UART_CTS],
4883 			      CONFIG_MODEM_HL7800_CTS_FILTER_US,
4884 			      CONFIG_MODEM_HL7800_CTS_FILTER_MAX_ITERATIONS);
4885 
4886 	/* CTS toggles A LOT,
4887 	 * comment out the debug print unless we really need it.
4888 	 */
4889 	/* HL7800_IO_DBG_LOG("MDM_UART_CTS:%d", ictx.cts_state); */
4890 
4891 	if ((ictx.cts_callback != NULL) && (ictx.desired_sleep_level == HL7800_SLEEP_SLEEP)) {
4892 		ictx.cts_callback(ictx.cts_state);
4893 	}
4894 
4895 #ifdef CONFIG_MODEM_HL7800_LOW_POWER_MODE
4896 	if (ictx.cts_state) {
4897 		/* HL7800 is not awake, shut down UART to save power */
4898 		if (ictx.allow_sleep) {
4899 			shutdown_uart();
4900 		}
4901 	} else {
4902 		if (ictx.off) {
4903 			return;
4904 		}
4905 		if (ictx.desired_sleep_level != HL7800_SLEEP_HIBERNATE) {
4906 			power_on_uart();
4907 			if (ictx.sleep_state == HL7800_SLEEP_SLEEP) {
4908 				/* Wake up the modem to see if it has anything to send to us. */
4909 				allow_sleep(false);
4910 				/* Allow the modem to go back to sleep if it was the one who
4911 				 * sourced the CTS transition.
4912 				 */
4913 				allow_sleep(true);
4914 			}
4915 		}
4916 	}
4917 #endif
4918 
4919 	check_hl7800_awake();
4920 }
4921 
modem_reset(void)4922 static void modem_reset(void)
4923 {
4924 	prepare_io_for_reset();
4925 
4926 	LOG_INF("Modem Reset");
4927 	/* Hard reset the modem */
4928 	gpio_pin_set_dt(&hl7800_cfg.gpio[MDM_RESET], 1);
4929 	/* >20 milliseconds required for reset low */
4930 	k_sleep(MDM_RESET_LOW_TIME);
4931 
4932 	ictx.mdm_startup_reporting_on = false;
4933 	set_sleep_state(HL7800_SLEEP_UNINITIALIZED);
4934 	check_hl7800_awake();
4935 	set_network_state(HL7800_NOT_REGISTERED);
4936 	set_startup_state(HL7800_STARTUP_STATE_UNKNOWN);
4937 #ifdef CONFIG_MODEM_HL7800_FW_UPDATE
4938 	if (ictx.fw_update_state == HL7800_FOTA_REBOOT_AND_RECONFIGURE) {
4939 		set_fota_state(HL7800_FOTA_COMPLETE);
4940 	} else {
4941 		set_fota_state(HL7800_FOTA_IDLE);
4942 	}
4943 #endif
4944 	k_sem_reset(&ictx.mdm_awake);
4945 	ictx.off = true;
4946 }
4947 
modem_run(void)4948 static void modem_run(void)
4949 {
4950 	LOG_INF("Modem Run");
4951 	gpio_pin_set_dt(&hl7800_cfg.gpio[MDM_RESET], 0);
4952 	k_sleep(MDM_RESET_HIGH_TIME);
4953 	ictx.off = false;
4954 	allow_sleep(false);
4955 }
4956 
modem_boot_handler(char * reason)4957 static int modem_boot_handler(char *reason)
4958 {
4959 	int ret;
4960 
4961 	LOG_DBG("%s", reason);
4962 	ret = k_sem_take(&ictx.mdm_awake, MDM_BOOT_TIME);
4963 	if (ret) {
4964 		LOG_ERR("Err waiting for boot: %d, DSR: %u", ret,
4965 			ictx.dsr_state);
4966 		return -1;
4967 	} else {
4968 		LOG_INF("Modem booted!");
4969 	}
4970 
4971 	/* Turn OFF EPS network registration status reporting because
4972 	 * it isn't needed until after initialization is complete.
4973 	 */
4974 	SEND_AT_CMD_EXPECT_OK("AT+CEREG=0");
4975 
4976 	/* Determine if echo is on/off by reading the profile
4977 	 * note: It wasn't clear how to read the
4978 	 * active profile so all 3 are read.
4979 	 */
4980 	ictx.mdm_echo_is_on = true;
4981 	SEND_AT_CMD_EXPECT_OK("AT&V");
4982 
4983 	if (ictx.mdm_echo_is_on) {
4984 		/* Turn OFF echo (after boot/reset) because a profile
4985 		 * hasn't been saved yet
4986 		 */
4987 		SEND_AT_CMD_EXPECT_OK("ATE0");
4988 
4989 		/* Save profile 0 */
4990 		SEND_AT_CMD_EXPECT_OK("AT&W");
4991 
4992 		/* Reread profiles so echo state can be checked again. */
4993 		SEND_AT_CMD_EXPECT_OK("AT&V");
4994 	}
4995 
4996 	__ASSERT(!ictx.mdm_echo_is_on, "Echo should be off");
4997 
4998 	return 0;
4999 
5000 error:
5001 	return ret;
5002 }
5003 
5004 /**
5005  * @brief  compares two version strings with any delimiter
5006  *
5007  * @param  *v1: version string 1
5008  * @param  *v2: version string 2
5009  *
5010  * @retval 0 if equal, < 0 if v1 < v2, > 0 if v1 > v2.
5011  */
compare_versions(char * v1,const char * v2)5012 static int compare_versions(char *v1, const char *v2)
5013 {
5014 	int result = 0;
5015 	char *tail1;
5016 	char *tail2;
5017 	unsigned long ver1, ver2;
5018 
5019 	/* loop through each level of the version string */
5020 	while (result == 0) {
5021 		/* extract leading version numbers */
5022 		ver1 = strtoul(v1, &tail1, 10);
5023 		ver2 = strtoul(v2, &tail2, 10);
5024 
5025 		/* if numbers differ, then set the result */
5026 		if (ver1 < ver2) {
5027 			result = -1;
5028 		} else if (ver1 > ver2) {
5029 			result = 1;
5030 		} else {
5031 			/* if numbers are the same, go to next level */
5032 			v1 = tail1;
5033 			v2 = tail2;
5034 			/* if we reach the end of both, then they are identical */
5035 			if (*v1 == '\0' && *v2 == '\0') {
5036 				break;
5037 			/* if we reach the end of one only, it is the smaller */
5038 			} else if (*v1 == '\0') {
5039 				result = -1;
5040 			} else if (*v2 == '\0') {
5041 				result = 1;
5042 			/*  not at end ... so far they match so keep going */
5043 			} else {
5044 				v1++;
5045 				v2++;
5046 			}
5047 		}
5048 	}
5049 	return result;
5050 }
5051 
setup_gprs_connection(char * access_point_name)5052 static int setup_gprs_connection(char *access_point_name)
5053 {
5054 	char cmd_string[sizeof("AT+KCNXCFG=1,\"GPRS\",\"\",,,"
5055 			       "\"IPV4V6\"") +
5056 			MDM_HL7800_APN_MAX_SIZE];
5057 	int cmd_max_len = sizeof(cmd_string) - 1;
5058 
5059 	memset(cmd_string, 0, cmd_max_len);
5060 	strncat(cmd_string, "AT+KCNXCFG=1,\"GPRS\",\"", cmd_max_len);
5061 	strncat(cmd_string, access_point_name, cmd_max_len);
5062 	strncat(cmd_string, "\",,,\"", cmd_max_len);
5063 	strncat(cmd_string, MODEM_HL7800_ADDRESS_FAMILY "\"", cmd_max_len);
5064 	return send_at_cmd(NULL, cmd_string, MDM_CMD_SEND_TIMEOUT, 0, false);
5065 }
5066 
set_bands(const char * bands,bool full_reboot)5067 static int set_bands(const char *bands, bool full_reboot)
5068 {
5069 	int ret;
5070 	char cmd[sizeof("AT+KBNDCFG=#,####################")];
5071 
5072 	snprintk(cmd, sizeof(cmd), "AT+KBNDCFG=%d,%s", ictx.mdm_rat, bands);
5073 	ret = send_at_cmd(NULL, cmd, MDM_CMD_SEND_TIMEOUT, MDM_DEFAULT_AT_CMD_RETRIES, false);
5074 	if (ret < 0) {
5075 		return ret;
5076 	}
5077 
5078 	if (!full_reboot) {
5079 		ret = send_at_cmd(NULL, "AT+CFUN=1,1", MDM_CMD_SEND_TIMEOUT,
5080 				  MDM_DEFAULT_AT_CMD_RETRIES, false);
5081 		if (ret < 0) {
5082 			return ret;
5083 		}
5084 
5085 		ret = modem_boot_handler("LTE bands were just set");
5086 	} else {
5087 		k_work_reschedule_for_queue(&hl7800_workq, &ictx.mdm_reset_work, K_NO_WAIT);
5088 	}
5089 	return ret;
5090 }
5091 
mdm_hl7800_set_bands(const char * bands)5092 int32_t mdm_hl7800_set_bands(const char *bands)
5093 {
5094 	int ret, i;
5095 	char temp_bands[MDM_BAND_BITMAP_STR_LENGTH_MAX + 1];
5096 	int num_leading_zeros;
5097 
5098 	if ((bands == NULL) || (strlen(bands) > MDM_BAND_BITMAP_STR_LENGTH_MAX) ||
5099 	    (strlen(bands) < MDM_BAND_BITMAP_STR_LENGTH_MIN)) {
5100 		return -EINVAL;
5101 	}
5102 
5103 	if (strlen(bands) < MDM_BAND_BITMAP_STR_LENGTH_MAX) {
5104 		num_leading_zeros = MDM_BAND_BITMAP_STR_LENGTH_MAX - strlen(bands);
5105 		for (i = 0; i < num_leading_zeros; i++) {
5106 			temp_bands[i] = '0';
5107 			if (i == (num_leading_zeros - 1)) {
5108 				strncpy(temp_bands + (i + 1), bands, sizeof(temp_bands) - (i + 1));
5109 			}
5110 		}
5111 	} else {
5112 		memcpy(temp_bands, bands, sizeof(temp_bands));
5113 	}
5114 
5115 	/* no need to set bands if settings match */
5116 	if (strncmp(temp_bands, ictx.mdm_bands_string, sizeof(temp_bands)) == 0) {
5117 		return 0;
5118 	}
5119 
5120 	hl7800_lock();
5121 
5122 	ret = set_bands(temp_bands, true);
5123 
5124 	hl7800_unlock();
5125 
5126 	return ret;
5127 }
5128 
modem_reset_and_configure(void)5129 static int modem_reset_and_configure(void)
5130 {
5131 	int ret = 0;
5132 	bool sleep = false;
5133 #ifdef CONFIG_MODEM_HL7800_EDRX
5134 	int edrx_act_type;
5135 	char set_edrx_msg[sizeof("AT+CEDRXS=2,4,\"0000\"")];
5136 #endif
5137 #if CONFIG_MODEM_HL7800_CONFIGURE_BANDS
5138 	uint16_t bands_top = 0;
5139 	uint32_t bands_middle = 0, bands_bottom = 0;
5140 	char new_bands[MDM_BAND_BITMAP_STR_LENGTH_MAX + 1];
5141 #endif
5142 #if CONFIG_MODEM_HL7800_PSM
5143 	const char TURN_ON_PSM[] =
5144 		"AT+CPSMS=1,,,\"" CONFIG_MODEM_HL7800_PSM_PERIODIC_TAU
5145 		"\",\"" CONFIG_MODEM_HL7800_PSM_ACTIVE_TIME "\"";
5146 #endif
5147 
5148 	ictx.restarting = true;
5149 	ictx.dns_ready = false;
5150 	if (ictx.iface) {
5151 		net_if_carrier_off(ictx.iface);
5152 	}
5153 
5154 	hl7800_stop_rssi_work();
5155 
5156 reboot:
5157 	modem_reset();
5158 	modem_run();
5159 	ret = modem_boot_handler("Initialization");
5160 	if (!ictx.mdm_startup_reporting_on) {
5161 		/* Turn on mobile start-up reporting for next reset.
5162 		 * It will indicate if SIM is present.
5163 		 * Its value is saved in non-volatile memory on the HL7800.
5164 		 */
5165 		SEND_AT_CMD_EXPECT_OK("AT+KSREP=1");
5166 		goto reboot;
5167 	} else if (ret < 0) {
5168 		goto error;
5169 	}
5170 
5171 	/* turn on numeric error codes */
5172 	SEND_AT_CMD_EXPECT_OK("AT+CMEE=1");
5173 
5174 	/* modem revision */
5175 	SEND_COMPLEX_AT_CMD("AT+CGMR");
5176 
5177 	/* determine RAT command support */
5178 	ret = compare_versions(ictx.mdm_revision, NEW_RAT_CMD_MIN_VERSION);
5179 	if (ret < 0) {
5180 		ictx.new_rat_cmd_support = false;
5181 	} else {
5182 		ictx.new_rat_cmd_support = true;
5183 	}
5184 
5185 	/* Query current Radio Access Technology (RAT) */
5186 	SEND_AT_CMD_EXPECT_OK("AT+KSRAT?");
5187 
5188 	/* If CONFIG_MODEM_HL7800_RAT_M1 or CONFIG_MODEM_HL7800_RAT_NB1, then
5189 	 * set the radio mode. This is only done here if the driver has not been
5190 	 * initialized (!ictx.configured) yet because the public API also
5191 	 * allows the RAT to be changed (and will reset the modem).
5192 	 */
5193 #ifndef CONFIG_MODEM_HL7800_RAT_NO_CHANGE
5194 	if (!ictx.configured) {
5195 #if CONFIG_MODEM_HL7800_RAT_M1
5196 		if (ictx.mdm_rat != MDM_RAT_CAT_M1) {
5197 			if (ictx.new_rat_cmd_support) {
5198 				SEND_AT_CMD_ONCE_EXPECT_OK(SET_RAT_M1_CMD);
5199 			} else {
5200 				SEND_AT_CMD_ONCE_EXPECT_OK(
5201 					SET_RAT_M1_CMD_LEGACY);
5202 			}
5203 			if (ret >= 0) {
5204 				goto reboot;
5205 			}
5206 		}
5207 #elif CONFIG_MODEM_HL7800_RAT_NB1
5208 		if (ictx.mdm_rat != MDM_RAT_CAT_NB1) {
5209 			if (ictx.new_rat_cmd_support) {
5210 				SEND_AT_CMD_ONCE_EXPECT_OK(SET_RAT_NB1_CMD);
5211 			} else {
5212 				SEND_AT_CMD_ONCE_EXPECT_OK(
5213 					SET_RAT_NB1_CMD_LEGACY);
5214 			}
5215 
5216 			if (ret >= 0) {
5217 				goto reboot;
5218 			}
5219 		}
5220 #endif
5221 	}
5222 #endif
5223 
5224 	/* If this isn't defined, then keep the current state.
5225 	 * If the bands are being reconfigured, this is overridden.
5226 	 */
5227 #ifdef CONFIG_MODEM_HL7800_BOOT_IN_AIRPLANE_MODE
5228 	SEND_AT_CMD_EXPECT_OK("AT+CFUN=4,0");
5229 #endif
5230 
5231 	SEND_AT_CMD_EXPECT_OK("AT+KBNDCFG?");
5232 
5233 	/* Configure LTE bands */
5234 #if CONFIG_MODEM_HL7800_CONFIGURE_BANDS
5235 #if CONFIG_MODEM_HL7800_BAND_1
5236 	bands_bottom |= 1 << 0;
5237 #endif
5238 #if CONFIG_MODEM_HL7800_BAND_2
5239 	bands_bottom |= 1 << 1;
5240 #endif
5241 #if CONFIG_MODEM_HL7800_BAND_3
5242 	bands_bottom |= 1 << 2;
5243 #endif
5244 #if CONFIG_MODEM_HL7800_BAND_4
5245 	bands_bottom |= 1 << 3;
5246 #endif
5247 #if CONFIG_MODEM_HL7800_BAND_5
5248 	bands_bottom |= 1 << 4;
5249 #endif
5250 #if CONFIG_MODEM_HL7800_BAND_8
5251 	bands_bottom |= 1 << 7;
5252 #endif
5253 #if CONFIG_MODEM_HL7800_BAND_9
5254 	bands_bottom |= 1 << 8;
5255 #endif
5256 #if CONFIG_MODEM_HL7800_BAND_10
5257 	bands_bottom |= 1 << 9;
5258 #endif
5259 #if CONFIG_MODEM_HL7800_BAND_12
5260 	bands_bottom |= 1 << 11;
5261 #endif
5262 #if CONFIG_MODEM_HL7800_BAND_13
5263 	bands_bottom |= 1 << 12;
5264 #endif
5265 #if CONFIG_MODEM_HL7800_BAND_14
5266 	bands_bottom |= 1 << 13;
5267 #endif
5268 #if CONFIG_MODEM_HL7800_BAND_17
5269 	bands_bottom |= 1 << 16;
5270 #endif
5271 #if CONFIG_MODEM_HL7800_BAND_18
5272 	bands_bottom |= 1 << 17;
5273 #endif
5274 #if CONFIG_MODEM_HL7800_BAND_19
5275 	bands_bottom |= 1 << 18;
5276 #endif
5277 #if CONFIG_MODEM_HL7800_BAND_20
5278 	bands_bottom |= 1 << 19;
5279 #endif
5280 #if CONFIG_MODEM_HL7800_BAND_25
5281 	bands_bottom |= 1 << 24;
5282 #endif
5283 #if CONFIG_MODEM_HL7800_BAND_26
5284 	bands_bottom |= 1 << 25;
5285 #endif
5286 #if CONFIG_MODEM_HL7800_BAND_27
5287 	bands_bottom |= 1 << 26;
5288 #endif
5289 #if CONFIG_MODEM_HL7800_BAND_28
5290 	bands_bottom |= 1 << 27;
5291 #endif
5292 #if CONFIG_MODEM_HL7800_BAND_66
5293 	bands_top |= 1 << 1;
5294 #endif
5295 
5296 	/* Check if bands are configured correctly */
5297 	if (ictx.mdm_bands_top != bands_top ||
5298 	    ictx.mdm_bands_middle != bands_middle ||
5299 	    ictx.mdm_bands_bottom != bands_bottom) {
5300 		if (ictx.mdm_bands_top != bands_top) {
5301 			LOG_INF("Top band mismatch, want %04x got %04x",
5302 				bands_top, ictx.mdm_bands_top);
5303 		}
5304 		if (ictx.mdm_bands_middle != bands_middle) {
5305 			LOG_INF("Middle band mismatch, want %08x got %08x",
5306 				bands_middle, ictx.mdm_bands_middle);
5307 		}
5308 		if (ictx.mdm_bands_bottom != bands_bottom) {
5309 			LOG_INF("Bottom band mismatch, want %08x got %08x",
5310 				bands_bottom, ictx.mdm_bands_bottom);
5311 		}
5312 
5313 		snprintk(new_bands, sizeof(new_bands),
5314 			 "%0" STRINGIFY(MDM_TOP_BAND_SIZE) "x%0" STRINGIFY(
5315 				 MDM_MIDDLE_BAND_SIZE) "x%0" STRINGIFY(MDM_BOTTOM_BAND_SIZE) "x",
5316 			 bands_top, bands_middle, bands_bottom);
5317 
5318 		ret = set_bands(new_bands, false);
5319 		if (ret < 0) {
5320 			goto error;
5321 		}
5322 	}
5323 #endif
5324 
5325 	ictx.low_power_mode = HL7800_LPM_NONE;
5326 #ifdef CONFIG_MODEM_HL7800_LOW_POWER_MODE
5327 	/* enable GPIO6 low power monitoring */
5328 	SEND_AT_CMD_EXPECT_OK("AT+KHWIOCFG=3,1,6");
5329 
5330 	initialize_sleep_level();
5331 	ret = set_sleep_level();
5332 	if (ret < 0) {
5333 		goto error;
5334 	}
5335 
5336 #if CONFIG_MODEM_HL7800_PSM
5337 	ictx.low_power_mode = HL7800_LPM_PSM;
5338 	/* Turn off eDRX */
5339 	SEND_AT_CMD_EXPECT_OK("AT+CEDRXS=0");
5340 
5341 	SEND_AT_CMD_EXPECT_OK(TURN_ON_PSM);
5342 #elif CONFIG_MODEM_HL7800_EDRX
5343 	ictx.low_power_mode = HL7800_LPM_EDRX;
5344 	/* Turn off PSM */
5345 	SEND_AT_CMD_EXPECT_OK("AT+CPSMS=0");
5346 
5347 	/* turn on eDRX */
5348 	if (ictx.mdm_rat == MDM_RAT_CAT_NB1) {
5349 		edrx_act_type = 5;
5350 	} else {
5351 		edrx_act_type = 4;
5352 	}
5353 	snprintk(set_edrx_msg, sizeof(set_edrx_msg), "AT+CEDRXS=1,%d,\"%s\"",
5354 		 edrx_act_type, CONFIG_MODEM_HL7800_EDRX_VALUE);
5355 	SEND_AT_CMD_EXPECT_OK(set_edrx_msg);
5356 #endif
5357 	sleep = true;
5358 #else
5359 	/* Turn off sleep mode */
5360 	SEND_AT_CMD_EXPECT_OK("AT+KSLEEP=2");
5361 
5362 	/* Turn off PSM */
5363 	SEND_AT_CMD_EXPECT_OK("AT+CPSMS=0");
5364 
5365 	/* Turn off eDRX */
5366 	SEND_AT_CMD_EXPECT_OK("AT+CEDRXS=0");
5367 #endif
5368 
5369 	/* modem manufacturer */
5370 	SEND_COMPLEX_AT_CMD("AT+CGMI");
5371 
5372 	/* modem model */
5373 	SEND_COMPLEX_AT_CMD("AT+CGMM");
5374 
5375 	/* query modem IMEI */
5376 	SEND_COMPLEX_AT_CMD("AT+CGSN");
5377 
5378 	/* query modem serial number */
5379 	SEND_COMPLEX_AT_CMD("AT+KGSN=3");
5380 
5381 	if (ictx.mdm_startup_state != HL7800_STARTUP_STATE_SIM_NOT_PRESENT) {
5382 		/* query SIM ICCID */
5383 		SEND_AT_CMD_IGNORE_ERROR("AT+CCID?");
5384 
5385 		/* query SIM IMSI */
5386 		(void)send_at_cmd(NULL, "AT+CIMI", MDM_CMD_SEND_TIMEOUT, MDM_DEFAULT_AT_CMD_RETRIES,
5387 				  true);
5388 	}
5389 
5390 	/* Query PDP context to get APN */
5391 	SEND_AT_CMD_EXPECT_OK("AT+CGDCONT?");
5392 	if (strcmp(ictx.mdm_pdp_addr_fam, MODEM_HL7800_ADDRESS_FAMILY)) {
5393 		/* set PDP context address family along with current APN */
5394 		ret = write_apn(ictx.mdm_apn.value);
5395 		if (ret < 0) {
5396 			goto error;
5397 		}
5398 	}
5399 
5400 	ret = setup_gprs_connection(ictx.mdm_apn.value);
5401 	if (ret < 0) {
5402 		goto error;
5403 	}
5404 
5405 	/* Query PDP authentication context to get APN username/password.
5406 	 * Temporary Workaround - Ignore error
5407 	 * On some modules this is returning an error and the response data.
5408 	 */
5409 	SEND_AT_CMD_IGNORE_ERROR("AT+WPPP?");
5410 
5411 #if CONFIG_MODEM_HL7800_SET_APN_NAME_ON_STARTUP
5412 	if (!ictx.configured) {
5413 		if (strncmp(ictx.mdm_apn.value, CONFIG_MODEM_HL7800_APN_NAME,
5414 			    MDM_HL7800_APN_MAX_STRLEN) != 0) {
5415 			ret = write_apn(CONFIG_MODEM_HL7800_APN_NAME);
5416 			if (ret < 0) {
5417 				goto error;
5418 			} else {
5419 				goto reboot;
5420 			}
5421 		}
5422 	}
5423 #endif
5424 
5425 	/* query the network status in case we already registered */
5426 	SEND_COMPLEX_AT_CMD("AT+CEREG?");
5427 
5428 	/* Turn on EPS network registration status reporting */
5429 	SEND_AT_CMD_EXPECT_OK("AT+CEREG=4");
5430 
5431 	/* query all socket configs to cleanup any sockets that are not
5432 	 * tracked by the driver
5433 	 */
5434 	SEND_AT_CMD_EXPECT_OK("AT+KTCPCFG?");
5435 	SEND_AT_CMD_EXPECT_OK("AT+KUDPCFG?");
5436 
5437 	/* The modem has been initialized and now the network interface can be
5438 	 * started in the CEREG message handler.
5439 	 */
5440 	LOG_INF("Modem ready!");
5441 	ictx.restarting = false;
5442 	ictx.configured = true;
5443 	allow_sleep(sleep);
5444 	/* trigger APN update event */
5445 	event_handler(HL7800_EVENT_APN_UPDATE, &ictx.mdm_apn);
5446 
5447 #ifdef CONFIG_MODEM_HL7800_BOOT_DELAY
5448 	if (!ictx.initialized) {
5449 		if (ictx.iface != NULL) {
5450 			hl7800_build_mac(&ictx);
5451 			net_if_set_link_addr(ictx.iface, ictx.mac_addr,
5452 					     sizeof(ictx.mac_addr),
5453 					     NET_LINK_ETHERNET);
5454 			ictx.initialized = true;
5455 		}
5456 	}
5457 #endif
5458 
5459 	return 0;
5460 
5461 error:
5462 	LOG_ERR("Unable to configure modem");
5463 	ictx.configured = false;
5464 	set_network_state(HL7800_UNABLE_TO_CONFIGURE);
5465 	/* Kernel will fault with non-zero return value.
5466 	 * Allow other parts of application to run when modem cannot be configured.
5467 	 */
5468 	return 0;
5469 }
5470 
write_apn(char * access_point_name)5471 static int write_apn(char *access_point_name)
5472 {
5473 	char cmd_string[MDM_HL7800_APN_CMD_MAX_SIZE];
5474 
5475 	/* PDP Context */
5476 	memset(cmd_string, 0, MDM_HL7800_APN_CMD_MAX_SIZE);
5477 	if (strcmp(MODEM_HL7800_ADDRESS_FAMILY, ADDRESS_FAMILY_IPV4)) {
5478 		strncat(cmd_string, "AT+CGDCONT=1,\"" MODEM_HL7800_ADDRESS_FAMILY "\",\"",
5479 			MDM_HL7800_APN_CMD_MAX_STRLEN);
5480 	} else {
5481 		strncat(cmd_string, "AT+CGDCONT=1,\"IP\",\"", MDM_HL7800_APN_CMD_MAX_STRLEN);
5482 	}
5483 	strncat(cmd_string, access_point_name, MDM_HL7800_APN_CMD_MAX_STRLEN);
5484 	strncat(cmd_string, "\"", MDM_HL7800_APN_CMD_MAX_STRLEN);
5485 	return send_at_cmd(NULL, cmd_string, MDM_CMD_SEND_TIMEOUT, 0, false);
5486 }
5487 
mdm_reset_work_callback(struct k_work * item)5488 static void mdm_reset_work_callback(struct k_work *item)
5489 {
5490 	ARG_UNUSED(item);
5491 
5492 	mdm_hl7800_reset();
5493 }
5494 
mdm_hl7800_reset(void)5495 int32_t mdm_hl7800_reset(void)
5496 {
5497 	int ret;
5498 
5499 	hl7800_lock();
5500 
5501 	ret = modem_reset_and_configure();
5502 
5503 	hl7800_unlock();
5504 
5505 	return ret;
5506 }
5507 
mdm_power_off_work_callback(struct k_work * item)5508 static void mdm_power_off_work_callback(struct k_work *item)
5509 {
5510 	ARG_UNUSED(item);
5511 	int ret;
5512 #if defined(CONFIG_DNS_RESOLVER)
5513 	struct dns_resolve_context *dns_ctx;
5514 
5515 	LOG_DBG("Shutdown DNS resolver");
5516 	dns_ctx = dns_resolve_get_default();
5517 	(void)dns_resolve_close(dns_ctx);
5518 #endif
5519 
5520 	hl7800_lock();
5521 
5522 	notify_all_tcp_sockets_closed();
5523 
5524 	ret = send_at_cmd(NULL, "AT+CPOF", MDM_CMD_SEND_TIMEOUT, 1, false);
5525 	if (ret) {
5526 		LOG_ERR("AT+CPOF ret:%d", ret);
5527 		return;
5528 	}
5529 	prepare_io_for_reset();
5530 	ictx.dns_ready = false;
5531 	ictx.configured = false;
5532 	ictx.off = true;
5533 	/* bring the iface down */
5534 	if (ictx.iface) {
5535 		net_if_carrier_off(ictx.iface);
5536 	}
5537 	LOG_INF("Modem powered off");
5538 
5539 	hl7800_unlock();
5540 }
5541 
hl7800_power_off(void)5542 static int hl7800_power_off(void)
5543 {
5544 	LOG_INF("Powering off modem");
5545 	wakeup_hl7800();
5546 	hl7800_stop_rssi_work();
5547 	k_work_cancel_delayable(&ictx.iface_status_work);
5548 	k_work_cancel_delayable(&ictx.dns_work);
5549 	k_work_cancel_delayable(&ictx.mdm_reset_work);
5550 	k_work_cancel_delayable(&ictx.allow_sleep_work);
5551 	k_work_cancel_delayable(&ictx.delete_untracked_socket_work);
5552 	(void)k_work_submit_to_queue(&hl7800_workq, &ictx.mdm_pwr_off_work);
5553 
5554 	return 0;
5555 }
5556 
mdm_hl7800_power_off(void)5557 int32_t mdm_hl7800_power_off(void)
5558 {
5559 	int rc;
5560 
5561 	hl7800_lock();
5562 	rc = hl7800_power_off();
5563 	hl7800_unlock();
5564 
5565 	return rc;
5566 }
5567 
mdm_hl7800_register_event_callback(struct mdm_hl7800_callback_agent * agent)5568 int mdm_hl7800_register_event_callback(struct mdm_hl7800_callback_agent *agent)
5569 {
5570 	int ret;
5571 
5572 	ret = k_sem_take(&cb_lock, K_NO_WAIT);
5573 	if (ret < 0) {
5574 		return ret;
5575 	}
5576 	if (!agent->event_callback) {
5577 		LOG_WRN("event_callback is NULL");
5578 	}
5579 	sys_slist_append(&hl7800_event_callback_list, &agent->node);
5580 	k_sem_give(&cb_lock);
5581 
5582 	return ret;
5583 }
5584 
mdm_hl7800_unregister_event_callback(struct mdm_hl7800_callback_agent * agent)5585 int mdm_hl7800_unregister_event_callback(struct mdm_hl7800_callback_agent *agent)
5586 {
5587 	int ret;
5588 
5589 	ret = k_sem_take(&cb_lock, K_NO_WAIT);
5590 	if (ret < 0) {
5591 		return ret;
5592 	}
5593 	ret = (int)sys_slist_find_and_remove(&hl7800_event_callback_list, &agent->node);
5594 	if (ret) {
5595 		ret = 0;
5596 	} else {
5597 		ret = -ENOENT;
5598 	}
5599 	k_sem_give(&cb_lock);
5600 
5601 	return ret;
5602 }
5603 
5604 /*** OFFLOAD FUNCTIONS ***/
5605 
connect_TCP_socket(struct hl7800_socket * sock)5606 static int connect_TCP_socket(struct hl7800_socket *sock)
5607 {
5608 	int ret;
5609 	char cmd_con[sizeof("AT+KTCPCNX=##")];
5610 
5611 	snprintk(cmd_con, sizeof(cmd_con), "AT+KTCPCNX=%d", sock->socket_id);
5612 	ret = send_at_cmd(sock, cmd_con, MDM_CMD_SEND_TIMEOUT, 0, false);
5613 	if (ret < 0) {
5614 		LOG_ERR("AT+KTCPCNX ret:%d", ret);
5615 		ret = -EIO;
5616 		goto done;
5617 	}
5618 	/* Now wait for +KTCP_IND or +KTCP_NOTIF to ensure
5619 	 * the connection succeeded or failed.
5620 	 */
5621 	ret = k_sem_take(&sock->sock_send_sem, MDM_CMD_CONN_TIMEOUT);
5622 	if (ret == 0) {
5623 		ret = sock->error;
5624 	} else if (ret == -EAGAIN) {
5625 		ret = -ETIMEDOUT;
5626 	}
5627 	if (ret < 0) {
5628 		LOG_ERR("+KTCP_IND/NOTIF ret:%d", ret);
5629 		goto done;
5630 	} else {
5631 		sock->state = SOCK_CONNECTED;
5632 		net_context_set_state(sock->context, NET_CONTEXT_CONNECTED);
5633 	}
5634 done:
5635 	return ret;
5636 }
5637 
configure_TCP_socket(struct hl7800_socket * sock)5638 static int configure_TCP_socket(struct hl7800_socket *sock)
5639 {
5640 	int ret;
5641 	char cmd_cfg[sizeof("AT+KTCPCFG=#,#,\"" IPV6_ADDR_FORMAT "\",#####,,,,#,,#")];
5642 	int dst_port = -1;
5643 	int af;
5644 	bool restore_on_boot = false;
5645 
5646 #ifdef CONFIG_MODEM_HL7800_LOW_POWER_MODE
5647 	restore_on_boot = true;
5648 #endif
5649 
5650 	if (sock->dst.sa_family == AF_INET6) {
5651 		af = MDM_HL7800_SOCKET_AF_IPV6;
5652 		dst_port = net_sin6(&sock->dst)->sin6_port;
5653 	} else if (sock->dst.sa_family == AF_INET) {
5654 		af = MDM_HL7800_SOCKET_AF_IPV4;
5655 		dst_port = net_sin(&sock->dst)->sin_port;
5656 	} else {
5657 		return -EINVAL;
5658 	}
5659 
5660 	sock->socket_id = MDM_CREATE_SOCKET_ID;
5661 
5662 	snprintk(cmd_cfg, sizeof(cmd_cfg), "AT+KTCPCFG=%d,%d,\"%s\",%u,,,,%d,,%d", 1, 0,
5663 		 hl7800_sprint_ip_addr(&sock->dst), dst_port, af, restore_on_boot);
5664 	ret = send_at_cmd(sock, cmd_cfg, MDM_CMD_SEND_TIMEOUT, 0, false);
5665 	if (ret < 0) {
5666 		LOG_ERR("AT+KTCPCFG ret:%d", ret);
5667 		ret = -EIO;
5668 		goto done;
5669 	}
5670 
5671 done:
5672 	return ret;
5673 }
5674 
configure_UDP_socket(struct hl7800_socket * sock)5675 static int configure_UDP_socket(struct hl7800_socket *sock)
5676 {
5677 	int ret = 0;
5678 	char cmd[sizeof("AT+KUDPCFG=1,0,,,,,0,#")];
5679 	int af;
5680 	bool restore_on_boot = false;
5681 
5682 #ifdef CONFIG_MODEM_HL7800_LOW_POWER_MODE
5683 	restore_on_boot = true;
5684 #endif
5685 
5686 	sock->socket_id = MDM_CREATE_SOCKET_ID;
5687 
5688 	if (sock->family == AF_INET) {
5689 		af = MDM_HL7800_SOCKET_AF_IPV4;
5690 	} else if (sock->family == AF_INET6) {
5691 		af = MDM_HL7800_SOCKET_AF_IPV6;
5692 	} else {
5693 		return -EINVAL;
5694 	}
5695 
5696 	snprintk(cmd, sizeof(cmd), "AT+KUDPCFG=1,0,,,,,%d,%d", af, restore_on_boot);
5697 	ret = send_at_cmd(sock, cmd, MDM_CMD_SEND_TIMEOUT, 0, false);
5698 	if (ret < 0) {
5699 		LOG_ERR("AT+KUDPCFG ret:%d", ret);
5700 		goto done;
5701 	}
5702 
5703 	/* Now wait for +KUDP_IND or +KUDP_NOTIF to ensure
5704 	 * the socket was created.
5705 	 */
5706 	ret = k_sem_take(&sock->sock_send_sem, MDM_CMD_CONN_TIMEOUT);
5707 	if (ret == 0) {
5708 		ret = sock->error;
5709 	} else if (ret == -EAGAIN) {
5710 		ret = -ETIMEDOUT;
5711 	}
5712 	if (ret < 0) {
5713 		LOG_ERR("+KUDP_IND/NOTIF ret:%d", ret);
5714 		goto done;
5715 	}
5716 done:
5717 	return ret;
5718 }
5719 
reconfigure_IP_connection(void)5720 static int reconfigure_IP_connection(void)
5721 {
5722 	int ret = 0;
5723 
5724 	if (ictx.reconfig_IP_connection) {
5725 		ictx.reconfig_IP_connection = false;
5726 
5727 		/* reconfigure GPRS connection so sockets can be used */
5728 		ret = setup_gprs_connection(ictx.mdm_apn.value);
5729 		if (ret < 0) {
5730 			LOG_ERR("AT+KCNXCFG= ret:%d", ret);
5731 			goto done;
5732 		}
5733 
5734 		/* query all TCP socket configs */
5735 		ret = send_at_cmd(NULL, "AT+KTCPCFG?", MDM_CMD_SEND_TIMEOUT, 0,
5736 				  false);
5737 
5738 		/* query all UDP socket configs */
5739 		ret = send_at_cmd(NULL, "AT+KUDPCFG?", MDM_CMD_SEND_TIMEOUT, 0,
5740 				  false);
5741 	}
5742 
5743 done:
5744 	return ret;
5745 }
5746 
offload_get(sa_family_t family,enum net_sock_type type,enum net_ip_protocol ip_proto,struct net_context ** context)5747 static int offload_get(sa_family_t family, enum net_sock_type type,
5748 		       enum net_ip_protocol ip_proto,
5749 		       struct net_context **context)
5750 {
5751 	int ret = 0;
5752 	struct hl7800_socket *sock = NULL;
5753 
5754 	hl7800_lock();
5755 	/* new socket */
5756 	sock = socket_get();
5757 	if (!sock) {
5758 		ret = -ENOMEM;
5759 		goto done;
5760 	}
5761 
5762 	(*context)->offload_context = sock;
5763 	/* set the context iface index to our iface */
5764 	(*context)->iface = net_if_get_by_iface(ictx.iface);
5765 	sock->family = family;
5766 	sock->type = type;
5767 	sock->ip_proto = ip_proto;
5768 	sock->context = *context;
5769 	sock->reconfig = false;
5770 	sock->created = false;
5771 	sock->socket_id = MDM_CREATE_SOCKET_ID;
5772 
5773 	/* If UDP, create UDP socket now.
5774 	 * TCP socket needs to be created later once the
5775 	 * connection IP address is known.
5776 	 */
5777 	if (type == SOCK_DGRAM) {
5778 		wakeup_hl7800();
5779 
5780 		/* reconfig IP connection if necessary */
5781 		if (reconfigure_IP_connection() < 0) {
5782 			socket_put(sock);
5783 			goto done;
5784 		}
5785 
5786 		ret = configure_UDP_socket(sock);
5787 		if (ret < 0) {
5788 			socket_put(sock);
5789 			goto done;
5790 		}
5791 	}
5792 done:
5793 	allow_sleep(true);
5794 	hl7800_unlock();
5795 	return ret;
5796 }
5797 
offload_bind(struct net_context * context,const struct sockaddr * addr,socklen_t addr_len)5798 static int offload_bind(struct net_context *context,
5799 			const struct sockaddr *addr, socklen_t addr_len)
5800 {
5801 	struct hl7800_socket *sock = NULL;
5802 
5803 	if (!context) {
5804 		return -EINVAL;
5805 	}
5806 
5807 	sock = (struct hl7800_socket *)context->offload_context;
5808 	if (!sock) {
5809 		LOG_ERR("Can't locate socket for net_ctx:%p!", context);
5810 		return -EINVAL;
5811 	}
5812 
5813 	/* save bind address information */
5814 	sock->src.sa_family = addr->sa_family;
5815 #if defined(CONFIG_NET_IPV6)
5816 	if (addr->sa_family == AF_INET6) {
5817 		net_ipaddr_copy(&net_sin6(&sock->src)->sin6_addr,
5818 				&net_sin6(addr)->sin6_addr);
5819 		net_sin6(&sock->src)->sin6_port = net_sin6(addr)->sin6_port;
5820 	} else
5821 #endif
5822 #if defined(CONFIG_NET_IPV4)
5823 		if (addr->sa_family == AF_INET) {
5824 		net_ipaddr_copy(&net_sin(&sock->src)->sin_addr,
5825 				&net_sin(addr)->sin_addr);
5826 		net_sin(&sock->src)->sin_port = net_sin(addr)->sin_port;
5827 	} else
5828 #endif
5829 	{
5830 		return -EPFNOSUPPORT;
5831 	}
5832 
5833 	return 0;
5834 }
5835 
offload_listen(struct net_context * context,int backlog)5836 static int offload_listen(struct net_context *context, int backlog)
5837 {
5838 	/* NOT IMPLEMENTED */
5839 	return -ENOTSUP;
5840 }
5841 
offload_connect(struct net_context * context,const struct sockaddr * addr,socklen_t addr_len,net_context_connect_cb_t cb,int32_t timeout,void * user_data)5842 static int offload_connect(struct net_context *context,
5843 			   const struct sockaddr *addr, socklen_t addr_len,
5844 			   net_context_connect_cb_t cb, int32_t timeout,
5845 			   void *user_data)
5846 {
5847 	int ret = 0;
5848 	int dst_port = -1;
5849 	struct hl7800_socket *sock;
5850 
5851 	if (!context || !addr) {
5852 		return -EINVAL;
5853 	}
5854 
5855 	sock = (struct hl7800_socket *)context->offload_context;
5856 	if (!sock) {
5857 		LOG_ERR("Can't locate socket for net_ctx:%p!", context);
5858 		return -EINVAL;
5859 	}
5860 
5861 	if (sock->socket_id < 1) {
5862 		LOG_ERR("Invalid socket_id(%d) for net_ctx:%p!",
5863 			sock->socket_id, context);
5864 		return -EINVAL;
5865 	}
5866 
5867 	sock->dst.sa_family = addr->sa_family;
5868 
5869 #if defined(CONFIG_NET_IPV6)
5870 	if (addr->sa_family == AF_INET6) {
5871 		net_ipaddr_copy(&net_sin6(&sock->dst)->sin6_addr,
5872 				&net_sin6(addr)->sin6_addr);
5873 		dst_port = ntohs(net_sin6(addr)->sin6_port);
5874 		net_sin6(&sock->dst)->sin6_port = dst_port;
5875 	} else
5876 #endif
5877 #if defined(CONFIG_NET_IPV4)
5878 		if (addr->sa_family == AF_INET) {
5879 		net_ipaddr_copy(&net_sin(&sock->dst)->sin_addr,
5880 				&net_sin(addr)->sin_addr);
5881 		dst_port = ntohs(net_sin(addr)->sin_port);
5882 		net_sin(&sock->dst)->sin_port = dst_port;
5883 	} else
5884 #endif
5885 	{
5886 		return -EINVAL;
5887 	}
5888 
5889 	if (dst_port < 0) {
5890 		LOG_ERR("Invalid port: %d", dst_port);
5891 		return -EINVAL;
5892 	}
5893 
5894 	hl7800_lock();
5895 
5896 	if (sock->type == SOCK_STREAM) {
5897 		wakeup_hl7800();
5898 
5899 		reconfigure_IP_connection();
5900 
5901 		/* Configure/create TCP connection */
5902 		if (!sock->created) {
5903 			ret = configure_TCP_socket(sock);
5904 			if (ret < 0) {
5905 				goto done;
5906 			}
5907 		}
5908 
5909 		/* Connect to TCP */
5910 		ret = connect_TCP_socket(sock);
5911 		if (ret < 0) {
5912 			goto done;
5913 		}
5914 	}
5915 
5916 done:
5917 	allow_sleep(true);
5918 	hl7800_unlock();
5919 
5920 	if (cb) {
5921 		cb(context, ret, user_data);
5922 	}
5923 
5924 	return ret;
5925 }
5926 
offload_accept(struct net_context * context,net_tcp_accept_cb_t cb,int32_t timeout,void * user_data)5927 static int offload_accept(struct net_context *context, net_tcp_accept_cb_t cb,
5928 			  int32_t timeout, void *user_data)
5929 {
5930 	/* NOT IMPLEMENTED */
5931 	return -ENOTSUP;
5932 }
5933 
offload_sendto(struct net_pkt * pkt,const struct sockaddr * dst_addr,socklen_t addr_len,net_context_send_cb_t cb,int32_t timeout,void * user_data)5934 static int offload_sendto(struct net_pkt *pkt, const struct sockaddr *dst_addr,
5935 			  socklen_t addr_len, net_context_send_cb_t cb,
5936 			  int32_t timeout, void *user_data)
5937 {
5938 	struct net_context *context = net_pkt_context(pkt);
5939 	struct hl7800_socket *sock;
5940 	int ret, dst_port = 0;
5941 
5942 	if (!context) {
5943 		return -EINVAL;
5944 	}
5945 
5946 	sock = (struct hl7800_socket *)context->offload_context;
5947 	if (!sock) {
5948 		LOG_ERR("Can't locate socket for net_ctx:%p!", context);
5949 		return -EINVAL;
5950 	}
5951 
5952 #if defined(CONFIG_NET_IPV6)
5953 	if (dst_addr->sa_family == AF_INET6) {
5954 		net_ipaddr_copy(&net_sin6(&sock->dst)->sin6_addr,
5955 				&net_sin6(dst_addr)->sin6_addr);
5956 		dst_port = ntohs(net_sin6(dst_addr)->sin6_port);
5957 		net_sin6(&sock->dst)->sin6_port = dst_port;
5958 	} else
5959 #endif
5960 #if defined(CONFIG_NET_IPV4)
5961 		if (dst_addr->sa_family == AF_INET) {
5962 		net_ipaddr_copy(&net_sin(&sock->dst)->sin_addr,
5963 				&net_sin(dst_addr)->sin_addr);
5964 		dst_port = ntohs(net_sin(dst_addr)->sin_port);
5965 		net_sin(&sock->dst)->sin_port = dst_port;
5966 	} else
5967 #endif
5968 	{
5969 		return -EINVAL;
5970 	}
5971 
5972 	hl7800_lock();
5973 
5974 	wakeup_hl7800();
5975 
5976 	reconfigure_IP_connection();
5977 
5978 	ret = send_data(sock, pkt);
5979 
5980 	allow_sleep(true);
5981 	hl7800_unlock();
5982 
5983 	if (ret >= 0) {
5984 		net_pkt_unref(pkt);
5985 	}
5986 
5987 	if (cb) {
5988 		cb(context, ret, user_data);
5989 	}
5990 
5991 	return ret;
5992 }
5993 
offload_send(struct net_pkt * pkt,net_context_send_cb_t cb,int32_t timeout,void * user_data)5994 static int offload_send(struct net_pkt *pkt, net_context_send_cb_t cb,
5995 			int32_t timeout, void *user_data)
5996 {
5997 	struct net_context *context = net_pkt_context(pkt);
5998 	socklen_t addr_len;
5999 
6000 	addr_len = 0;
6001 #if defined(CONFIG_NET_IPV6)
6002 	if (net_pkt_family(pkt) == AF_INET6) {
6003 		addr_len = sizeof(struct sockaddr_in6);
6004 	} else
6005 #endif /* CONFIG_NET_IPV6 */
6006 #if defined(CONFIG_NET_IPV4)
6007 		if (net_pkt_family(pkt) == AF_INET) {
6008 		addr_len = sizeof(struct sockaddr_in);
6009 	} else
6010 #endif /* CONFIG_NET_IPV4 */
6011 	{
6012 		return -EPFNOSUPPORT;
6013 	}
6014 
6015 	return offload_sendto(pkt, &context->remote, addr_len, cb, timeout,
6016 			      user_data);
6017 }
6018 
offload_recv(struct net_context * context,net_context_recv_cb_t cb,int32_t timeout,void * user_data)6019 static int offload_recv(struct net_context *context, net_context_recv_cb_t cb,
6020 			int32_t timeout, void *user_data)
6021 {
6022 	struct hl7800_socket *sock;
6023 
6024 	if (!context) {
6025 		return -EINVAL;
6026 	}
6027 
6028 	sock = (struct hl7800_socket *)context->offload_context;
6029 	if (!sock) {
6030 		LOG_ERR("Can't locate socket for net_ctx:%p!", context);
6031 		return -EINVAL;
6032 	}
6033 
6034 	sock->recv_cb = cb;
6035 	sock->recv_user_data = user_data;
6036 
6037 	return 0;
6038 }
6039 
offload_put(struct net_context * context)6040 static int offload_put(struct net_context *context)
6041 {
6042 	struct hl7800_socket *sock;
6043 	char cmd[sizeof("AT+KTCPCLOSE=##")];
6044 
6045 	if (!context) {
6046 		return -EINVAL;
6047 	}
6048 
6049 	sock = (struct hl7800_socket *)context->offload_context;
6050 	if (!sock) {
6051 		/* socket was already closed?  Exit quietly here. */
6052 		return 0;
6053 	}
6054 
6055 	/* cancel notif work if queued */
6056 	k_work_cancel_delayable(&sock->notif_work);
6057 
6058 	hl7800_lock();
6059 
6060 	/* close connection */
6061 	if (sock->type == SOCK_STREAM) {
6062 		snprintk(cmd, sizeof(cmd), "AT+KTCPCLOSE=%d",
6063 			 sock->socket_id);
6064 	} else {
6065 		snprintk(cmd, sizeof(cmd), "AT+KUDPCLOSE=%d",
6066 			 sock->socket_id);
6067 	}
6068 
6069 	wakeup_hl7800();
6070 
6071 	if ((sock->type == SOCK_DGRAM) || (sock->error != -ENOTCONN)) {
6072 		send_at_cmd(sock, cmd, MDM_CMD_SEND_TIMEOUT, 0, false);
6073 	}
6074 
6075 	if (sock->type == SOCK_STREAM) {
6076 		/* delete session */
6077 		delete_socket(sock, sock->type, sock->socket_id);
6078 	}
6079 	allow_sleep(true);
6080 
6081 	socket_put(sock);
6082 	net_context_unref(context);
6083 	if (sock->type == SOCK_STREAM) {
6084 		/* TCP contexts are referenced twice,
6085 		 * once for the app and once for the stack.
6086 		 * Since TCP stack is not used for offload,
6087 		 * unref a second time.
6088 		 */
6089 		net_context_unref(context);
6090 	}
6091 
6092 	hl7800_unlock();
6093 
6094 	return 0;
6095 }
6096 
6097 static struct net_offload offload_funcs = {
6098 	.get = offload_get,
6099 	.bind = offload_bind,
6100 	.listen = offload_listen,
6101 	.connect = offload_connect,
6102 	.accept = offload_accept,
6103 	.send = offload_send,
6104 	.sendto = offload_sendto,
6105 	.recv = offload_recv,
6106 	.put = offload_put,
6107 };
6108 
6109 /* Use the last 6 digits of the IMEI as the mac address */
hl7800_build_mac(struct hl7800_iface_ctx * ictx)6110 static void hl7800_build_mac(struct hl7800_iface_ctx *ictx)
6111 {
6112 	ictx->mac_addr[0] = ictx->mdm_imei[MDM_HL7800_IMEI_STRLEN - 6];
6113 	ictx->mac_addr[1] = ictx->mdm_imei[MDM_HL7800_IMEI_STRLEN - 5];
6114 	ictx->mac_addr[2] = ictx->mdm_imei[MDM_HL7800_IMEI_STRLEN - 4];
6115 	ictx->mac_addr[3] = ictx->mdm_imei[MDM_HL7800_IMEI_STRLEN - 3];
6116 	ictx->mac_addr[4] = ictx->mdm_imei[MDM_HL7800_IMEI_STRLEN - 2];
6117 	ictx->mac_addr[5] = ictx->mdm_imei[MDM_HL7800_IMEI_STRLEN - 1];
6118 }
6119 
6120 #ifdef CONFIG_MODEM_HL7800_FW_UPDATE
mdm_hl7800_update_fw(char * file_path)6121 int32_t mdm_hl7800_update_fw(char *file_path)
6122 {
6123 	int ret = 0;
6124 	struct fs_dirent file_info;
6125 	char cmd1[sizeof("AT+WDSD=24643584")];
6126 
6127 	/* get file info */
6128 	ret = fs_stat(file_path, &file_info);
6129 	if (ret >= 0) {
6130 		LOG_DBG("file '%s' size %zu", file_info.name, file_info.size);
6131 	} else {
6132 		LOG_ERR("Failed to get file [%s] info: %d", file_path, ret);
6133 		goto err;
6134 	}
6135 
6136 	ret = fs_open(&ictx.fw_update_file, file_path, FS_O_READ);
6137 	if (ret < 0) {
6138 		LOG_ERR("%s open err: %d", file_path, ret);
6139 		goto err;
6140 	}
6141 
6142 	/* turn on device service indications */
6143 	ret = send_at_cmd(NULL, "AT+WDSI=2", MDM_CMD_SEND_TIMEOUT, 0, false);
6144 	if (ret < 0) {
6145 		goto err;
6146 	}
6147 
6148 	notify_all_tcp_sockets_closed();
6149 	hl7800_stop_rssi_work();
6150 	k_work_cancel_delayable(&ictx.iface_status_work);
6151 	k_work_cancel_delayable(&ictx.dns_work);
6152 	k_work_cancel_delayable(&ictx.mdm_reset_work);
6153 	k_work_cancel_delayable(&ictx.allow_sleep_work);
6154 	k_work_cancel_delayable(&ictx.delete_untracked_socket_work);
6155 	ictx.dns_ready = false;
6156 	if (ictx.iface) {
6157 		LOG_DBG("HL7800 iface DOWN");
6158 		net_if_carrier_off(ictx.iface);
6159 	}
6160 
6161 	/* HL7800 will stay locked for the duration of the FW update */
6162 	hl7800_lock();
6163 
6164 	/* start firmware update process */
6165 	LOG_INF("Initiate FW update, total packets: %zd",
6166 		((file_info.size / XMODEM_DATA_SIZE) + 1));
6167 	set_fota_state(HL7800_FOTA_START);
6168 	(void)snprintk(cmd1, sizeof(cmd1), "AT+WDSD=%zd", file_info.size);
6169 	(void)send_at_cmd(NULL, cmd1, K_NO_WAIT, 0, false);
6170 
6171 err:
6172 	return ret;
6173 }
6174 #endif
6175 
hl7800_init(const struct device * dev)6176 static int hl7800_init(const struct device *dev)
6177 {
6178 	int i, ret = 0;
6179 	struct k_work_queue_config cfg = {
6180 		.name = "hl7800_workq",
6181 	};
6182 	ARG_UNUSED(dev);
6183 
6184 	LOG_DBG("HL7800 Init");
6185 
6186 	/* Prevent the network interface from starting until
6187 	 * the modem has been initialized
6188 	 * because the modem may not have a valid SIM card.
6189 	 */
6190 	ictx.iface = net_if_get_default();
6191 	if (ictx.iface == NULL) {
6192 		return -EIO;
6193 	}
6194 
6195 	net_if_carrier_off(ictx.iface);
6196 
6197 	/* init sockets */
6198 	for (i = 0; i < MDM_MAX_SOCKETS; i++) {
6199 		ictx.sockets[i].socket_id = -1;
6200 		k_work_init(&ictx.sockets[i].recv_cb_work,
6201 			    sockreadrecv_cb_work);
6202 		k_work_init(&ictx.sockets[i].rx_data_work,
6203 			    sock_rx_data_cb_work);
6204 		k_work_init_delayable(&ictx.sockets[i].notif_work,
6205 				      sock_notif_cb_work);
6206 		k_sem_init(&ictx.sockets[i].sock_send_sem, 0, 1);
6207 	}
6208 	ictx.last_socket_id = 0;
6209 	k_sem_init(&ictx.response_sem, 0, 1);
6210 	k_sem_init(&ictx.mdm_awake, 0, 1);
6211 
6212 	/* initialize the work queue */
6213 	k_work_queue_start(&hl7800_workq, hl7800_workq_stack,
6214 			   K_THREAD_STACK_SIZEOF(hl7800_workq_stack),
6215 			   WORKQ_PRIORITY, &cfg);
6216 
6217 	/* init work tasks */
6218 	k_work_init_delayable(&ictx.rssi_query_work, hl7800_rssi_query_work);
6219 	k_work_init_delayable(&ictx.iface_status_work, iface_status_work_cb);
6220 	k_work_init_delayable(&ictx.dns_work, dns_work_cb);
6221 	k_work_init(&ictx.mdm_vgpio_work, mdm_vgpio_work_cb);
6222 	k_work_init_delayable(&ictx.mdm_reset_work, mdm_reset_work_callback);
6223 	k_work_init_delayable(&ictx.allow_sleep_work,
6224 			      allow_sleep_work_callback);
6225 	k_work_init_delayable(&ictx.delete_untracked_socket_work, delete_untracked_socket_work_cb);
6226 	k_work_init(&ictx.mdm_pwr_off_work, mdm_power_off_work_callback);
6227 
6228 #ifdef CONFIG_MODEM_HL7800_GPS
6229 	k_work_init_delayable(&ictx.gps_work, gps_work_callback);
6230 #endif
6231 
6232 #ifdef CONFIG_MODEM_HL7800_FW_UPDATE
6233 	k_work_init(&ictx.finish_fw_update_work,
6234 		    finish_fw_update_work_callback);
6235 	ictx.fw_updated = false;
6236 #endif
6237 
6238 	/* setup port devices and pin directions */
6239 	for (i = 0; i < MAX_MDM_CONTROL_PINS; i++) {
6240 		if (!device_is_ready(hl7800_cfg.gpio[i].port)) {
6241 			LOG_ERR("gpio port (%s) not ready!",
6242 				hl7800_cfg.gpio[i].port->name);
6243 			return -ENODEV;
6244 		}
6245 	}
6246 
6247 	ret = gpio_pin_configure_dt(&hl7800_cfg.gpio[MDM_RESET], GPIO_OUTPUT);
6248 	if (ret) {
6249 		LOG_ERR("Error configuring IO MDM_RESET %d err: %d!",
6250 			hl7800_cfg.gpio[MDM_RESET].pin, ret);
6251 		return ret;
6252 	}
6253 
6254 	ret = gpio_pin_configure_dt(&hl7800_cfg.gpio[MDM_WAKE], GPIO_OUTPUT);
6255 	if (ret) {
6256 		LOG_ERR("Error configuring IO MDM_WAKE %d err: %d!",
6257 			hl7800_cfg.gpio[MDM_WAKE].pin, ret);
6258 		return ret;
6259 	}
6260 
6261 	ret = gpio_pin_configure_dt(&hl7800_cfg.gpio[MDM_PWR_ON], GPIO_OUTPUT);
6262 	if (ret) {
6263 		LOG_ERR("Error configuring IO MDM_PWR_ON %d err: %d!",
6264 			hl7800_cfg.gpio[MDM_PWR_ON].pin, ret);
6265 		return ret;
6266 	}
6267 
6268 	ret = gpio_pin_configure_dt(&hl7800_cfg.gpio[MDM_FAST_SHUTD], GPIO_OUTPUT);
6269 	if (ret) {
6270 		LOG_ERR("Error configuring IO MDM_FAST_SHUTD %d err: %d!",
6271 			hl7800_cfg.gpio[MDM_FAST_SHUTD].pin, ret);
6272 		return ret;
6273 	}
6274 
6275 	ret = gpio_pin_configure_dt(&hl7800_cfg.gpio[MDM_VGPIO], GPIO_INPUT);
6276 	if (ret) {
6277 		LOG_ERR("Error configuring IO MDM_VGPIO %d err: %d!",
6278 			hl7800_cfg.gpio[MDM_VGPIO].pin, ret);
6279 		return ret;
6280 	}
6281 
6282 	ret = gpio_pin_configure_dt(&hl7800_cfg.gpio[MDM_UART_DSR], GPIO_INPUT);
6283 	if (ret) {
6284 		LOG_ERR("Error configuring IO MDM_UART_DSR %d err: %d!",
6285 			hl7800_cfg.gpio[MDM_UART_DSR].pin, ret);
6286 		return ret;
6287 	}
6288 
6289 	ret = gpio_pin_configure_dt(&hl7800_cfg.gpio[MDM_UART_CTS], GPIO_INPUT);
6290 	if (ret) {
6291 		LOG_ERR("Error configuring IO MDM_UART_CTS %d err: %d!",
6292 			hl7800_cfg.gpio[MDM_UART_CTS].pin, ret);
6293 		return ret;
6294 	}
6295 
6296 	ret = gpio_pin_configure_dt(&hl7800_cfg.gpio[MDM_GPIO6], GPIO_INPUT);
6297 	if (ret) {
6298 		LOG_ERR("Error configuring IO MDM_GPIO6 %d err: %d!",
6299 			hl7800_cfg.gpio[MDM_GPIO6].pin, ret);
6300 		return ret;
6301 	}
6302 
6303 	/* when this driver starts, the UART peripheral is already enabled */
6304 	ictx.uart_on = true;
6305 
6306 	modem_assert_wake(false);
6307 	modem_assert_pwr_on(false);
6308 	modem_assert_fast_shutd(false);
6309 
6310 	/* Allow modem to run so we are in a known state.
6311 	 * This allows HL7800 VGPIO to be high, which is good because the UART
6312 	 * IO are already configured.
6313 	 */
6314 	modem_run();
6315 
6316 	/* setup input pin callbacks */
6317 	/* VGPIO */
6318 	gpio_init_callback(&ictx.mdm_vgpio_cb, mdm_vgpio_callback_isr,
6319 			   BIT(hl7800_cfg.gpio[MDM_VGPIO].pin));
6320 	ret = gpio_add_callback(hl7800_cfg.gpio[MDM_VGPIO].port,
6321 				&ictx.mdm_vgpio_cb);
6322 	if (ret) {
6323 		LOG_ERR("Cannot setup vgpio callback! (%d)", ret);
6324 		return ret;
6325 	}
6326 	ret = gpio_pin_interrupt_configure_dt(&hl7800_cfg.gpio[MDM_VGPIO], GPIO_INT_EDGE_BOTH);
6327 	if (ret) {
6328 		LOG_ERR("Error config vgpio interrupt! (%d)", ret);
6329 		return ret;
6330 	}
6331 
6332 	/* UART DSR */
6333 	gpio_init_callback(&ictx.mdm_uart_dsr_cb, mdm_uart_dsr_callback_isr,
6334 			   BIT(hl7800_cfg.gpio[MDM_UART_DSR].pin));
6335 	ret = gpio_add_callback(hl7800_cfg.gpio[MDM_UART_DSR].port,
6336 				&ictx.mdm_uart_dsr_cb);
6337 	if (ret) {
6338 		LOG_ERR("Cannot setup uart dsr callback! (%d)", ret);
6339 		return ret;
6340 	}
6341 	ret = gpio_pin_interrupt_configure_dt(&hl7800_cfg.gpio[MDM_UART_DSR], GPIO_INT_EDGE_BOTH);
6342 	if (ret) {
6343 		LOG_ERR("Error config uart dsr interrupt! (%d)", ret);
6344 		return ret;
6345 	}
6346 
6347 	/* GPIO6 */
6348 	gpio_init_callback(&ictx.mdm_gpio6_cb, mdm_gpio6_callback_isr,
6349 			   BIT(hl7800_cfg.gpio[MDM_GPIO6].pin));
6350 	ret = gpio_add_callback(hl7800_cfg.gpio[MDM_GPIO6].port,
6351 				&ictx.mdm_gpio6_cb);
6352 	if (ret) {
6353 		LOG_ERR("Cannot setup gpio6 callback! (%d)", ret);
6354 		return ret;
6355 	}
6356 	ret = gpio_pin_interrupt_configure_dt(&hl7800_cfg.gpio[MDM_GPIO6], GPIO_INT_EDGE_BOTH);
6357 	if (ret) {
6358 		LOG_ERR("Error config gpio6 interrupt! (%d)", ret);
6359 		return ret;
6360 	}
6361 
6362 	/* UART CTS */
6363 	gpio_init_callback(&ictx.mdm_uart_cts_cb, mdm_uart_cts_callback,
6364 			   BIT(hl7800_cfg.gpio[MDM_UART_CTS].pin));
6365 	ret = gpio_add_callback(hl7800_cfg.gpio[MDM_UART_CTS].port,
6366 				&ictx.mdm_uart_cts_cb);
6367 	if (ret) {
6368 		LOG_ERR("Cannot setup uart cts callback! (%d)", ret);
6369 		return ret;
6370 	}
6371 	ret = gpio_pin_interrupt_configure_dt(&hl7800_cfg.gpio[MDM_UART_CTS], GPIO_INT_EDGE_BOTH);
6372 	if (ret) {
6373 		LOG_ERR("Error config uart cts interrupt! (%d)", ret);
6374 		return ret;
6375 	}
6376 
6377 	/* Set modem data storage */
6378 	ictx.mdm_ctx.data_manufacturer = ictx.mdm_manufacturer;
6379 	ictx.mdm_ctx.data_model = ictx.mdm_model;
6380 	ictx.mdm_ctx.data_revision = ictx.mdm_revision;
6381 #ifdef CONFIG_MODEM_SIM_NUMBERS
6382 	ictx.mdm_ctx.data_imei = ictx.mdm_imei;
6383 #endif
6384 	ictx.mdm_ctx.data_rssi = &ictx.mdm_rssi;
6385 
6386 	ret = mdm_receiver_register(&ictx.mdm_ctx, MDM_UART_DEV,
6387 				    mdm_recv_buf, sizeof(mdm_recv_buf));
6388 	if (ret < 0) {
6389 		LOG_ERR("Error registering modem receiver (%d)!", ret);
6390 		return ret;
6391 	}
6392 
6393 	k_queue_init(&ictx.stale_socket_queue);
6394 
6395 	/* start RX thread */
6396 	k_thread_name_set(
6397 		k_thread_create(&hl7800_rx_thread, hl7800_rx_stack,
6398 				K_THREAD_STACK_SIZEOF(hl7800_rx_stack),
6399 				(k_thread_entry_t)hl7800_rx, NULL, NULL, NULL,
6400 				RX_THREAD_PRIORITY, 0, K_NO_WAIT),
6401 		"hl7800 rx");
6402 
6403 #ifdef CONFIG_MODEM_HL7800_BOOT_DELAY
6404 	modem_reset();
6405 #else
6406 	ret = modem_reset_and_configure();
6407 #endif
6408 
6409 	return ret;
6410 }
6411 
offload_iface_init(struct net_if * iface)6412 static void offload_iface_init(struct net_if *iface)
6413 {
6414 	const struct device *dev = net_if_get_device(iface);
6415 	struct hl7800_iface_ctx *ctx = dev->data;
6416 
6417 	iface->if_dev->offload = &offload_funcs;
6418 	ctx->iface = iface;
6419 
6420 	if (!IS_ENABLED(CONFIG_MODEM_HL7800_BOOT_DELAY)) {
6421 		hl7800_build_mac(&ictx);
6422 		net_if_set_link_addr(iface, ictx.mac_addr, sizeof(ictx.mac_addr),
6423 				     NET_LINK_ETHERNET);
6424 		ictx.initialized = true;
6425 	}
6426 }
6427 
6428 static struct offloaded_if_api api_funcs = {
6429 	.iface_api.init = offload_iface_init,
6430 };
6431 
6432 NET_DEVICE_DT_INST_OFFLOAD_DEFINE(0, hl7800_init, NULL, &ictx,
6433 				  &hl7800_cfg, CONFIG_MODEM_HL7800_INIT_PRIORITY,
6434 				  &api_funcs, MDM_MTU);
6435