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