diff --git a/drivers/modem/hl78xx/CMakeLists.txt b/drivers/modem/hl78xx/CMakeLists.txt index 1320925476238..2897f935bb24d 100644 --- a/drivers/modem/hl78xx/CMakeLists.txt +++ b/drivers/modem/hl78xx/CMakeLists.txt @@ -13,6 +13,11 @@ zephyr_library_sources( hl78xx_apis.c ) +zephyr_library_sources_ifdef( + CONFIG_MODEM_HL78XX_AT_SHELL + hl78xx_at_shell.c +) + add_subdirectory_ifdef(CONFIG_HL78XX_EVT_MONITOR hl78xx_evt_monitor) zephyr_library_include_directories( diff --git a/drivers/modem/hl78xx/Kconfig.hl78xx b/drivers/modem/hl78xx/Kconfig.hl78xx index bed24a07276fa..08ae3a7f792c5 100644 --- a/drivers/modem/hl78xx/Kconfig.hl78xx +++ b/drivers/modem/hl78xx/Kconfig.hl78xx @@ -57,33 +57,21 @@ config MODEM_HL78XX_12_FW_R6 endif # MODEM_HL78XX_12 -config MODEM_HL78XX_UART_BUFFER_SIZES - int "The UART receive and transmit buffer sizes in bytes." - default 512 - -config MODEM_HL78XX_CHAT_BUFFER_SIZES - int "The size of the buffers used for the chat scripts in bytes." - default 512 - -config MODEM_HL78XX_USER_PIPE_BUFFER_SIZES - int "The size of the buffers used for each user pipe in bytes." - default 512 - -config MODEM_HL78XX_RECV_BUF_CNT - int "The number of allocated network buffers" - default 30 - -config MODEM_HL78XX_RECV_BUF_SIZE - int "The size of the network buffers in bytes" - default 128 - -config MODEM_HL78XX_RX_WORKQ_STACK_SIZE - int "Stack size for the Sierra Wireless HL78XX driver modem driver work queue" - default 2048 - help - This stack is used by the work queue to pass off net_pkt data - to the rest of the network stack, letting the rx thread continue - processing data. +config MODEM_HL78XX_AT_SHELL + bool "AT command shell" + help + Enable AT command shell for the modem. +if MODEM_HL78XX_AT_SHELL +config MODEM_AT_SHELL_RESPONSE_TIMEOUT_MS + int "Timeout waiting for response to AT command in milliseconds" + default 500 +config MODEM_AT_SHELL_COMMAND_MAX_SIZE + int "Maximum size of AT command" + default 32 +config MODEM_AT_SHELL_RESPONSE_MAX_SIZE + int "Maximum size of AT response" + default 64 +endif # MODEM_HL78XX_AT_SHELL choice MODEM_HL78XX_ADDRESS_FAMILY prompt "IP Address family" @@ -719,6 +707,55 @@ config MODEM_MIN_ALLOWED_SIGNAL_STRENGTH default -140 range - 140 0 +config MODEM_HL78XX_AIRVANTAGE + bool "AirVantage" + help + Enable HL78xx modules connect to the AirVantage DM Server over OMA + +if MODEM_HL78XX_AIRVANTAGE + +choice MODEM_HL78XX_AIRVANTAGE_SESSION_INITIATION + prompt "AirVantage Initialization" + default MODEM_HL78XX_AIRVANTAGE_HOST_INITIATED + help + Choose this setting to enable HL78xx modules to connect to the AirVantage DM Server. +config MODEM_HL78XX_AIRVANTAGE_HOST_INITIATED + bool "Host Initiated" + help + The host application is responsible for initiating the connection to the AirVantage server. + +config MODEM_HL78XX_AIRVANTAGE_MODULE_INITIATED + bool "Module Initiated" + help + The HL78xx module is responsible for initiating the connection to the AirVantage server. +endchoice + +menuconfig MODEM_HL78XX_AIRVANTAGE_USER_AGREEMENT + bool "User Agreement Activation" + help + Activating User Agreements enables the host processor application to control the FOTA flow. For instance, the host + processor application, busy fulfilling a service (e.g. car is operating, ongoing payment transaction), can decide to + postpone firmware download or install operations, as accepting a firmware installation will lead the embedded + module to reboot upon FOTA completion. + +if MODEM_HL78XX_AIRVANTAGE_USER_AGREEMENT +config MODEM_HL78XX_AIRVANTAGE_UA_CONNECT_AIRVANTAGE + bool "Connect to AirVantage" + help + Module requests the user/application to connect to AirVantage + +config MODEM_HL78XX_AIRVANTAGE_UA_DOWNLOAD_FIRMWARE + bool "Download Firmware" + help + AirVantage requests the device to download a firmware package + +config MODEM_HL78XX_AIRVANTAGE_UA_INSTALL_FIRMWARE + bool "Install Firmware" + help + AirVantage requests the device to install the downloaded firmware package +endif # MODEM_HL78XX_AIRVANTAGE_USER_AGREEMENT +endif # MODEM_HL78XX_AIRVANTAGE + config MODEM_HL78XX_ADVANCED_SOCKET_CONFIG bool "Advanced socket configuration" help @@ -759,6 +796,14 @@ config MODEM_HL78XX_NUM_SOCKETS help Maximum number of sockets that can be opened at the same time +config MODEM_HL78XX_MAX_PDP_CONTEXTS + int "Maximum number of PDP contexts" + default 1 + range 1 1 if !MODEM_HL78XX_ADVANCED_SOCKET_CONFIG + range 1 2 if MODEM_HL78XX_ADVANCED_SOCKET_CONFIG + help + Maximum number of PDP contexts that can be defined at the same time + config MODEM_HL78XX_SOCKETS_SOCKOPT_TLS bool "TLS for sockets" depends on NET_SOCKETS_SOCKOPT_TLS @@ -766,38 +811,58 @@ config MODEM_HL78XX_SOCKETS_SOCKOPT_TLS This option enables TLS (Transport Layer Security) for sockets on the HL78xx modem. -config MODEM_HL78XX_LOG_CONTEXT_VERBOSE_DEBUG - bool "Verbose debug output in the HL78xx" - depends on MODEM_MODULES_LOG_LEVEL_DBG +config MODEM_HL78XX_UART_BUFFER_SIZES + int "The UART receive and transmit buffer sizes in bytes." + default 512 + +config MODEM_HL78XX_CHAT_BUFFER_SIZES + int "The size of the buffers used for the chat scripts in bytes." + default 512 + +config MODEM_HL78XX_USER_PIPE_BUFFER_SIZES + int "The size of the buffers used for each user pipe in bytes." + default 512 + +config MODEM_HL78XX_RECV_BUF_CNT + int "The number of allocated network buffers" + default 30 + +config MODEM_HL78XX_RECV_BUF_SIZE + int "The size of the network buffers in bytes" + default 128 + +config MODEM_HL78XX_RX_WORKQ_STACK_SIZE + int "Stack size for the Sierra Wireless HL78XX driver modem driver work queue" + default 2048 help - Enabling this setting will turn on VERY heavy debugging from the - modem. Do NOT leave on for production. - This setting is depends on global log level debug. + This stack is used by the work queue to pass off net_pkt data + to the rest of the network stack, letting the rx thread continue + processing data. -config MODEM_HL78XX_DEV_POWER_PULSE_DURATION +config MODEM_HL78XX_DEV_POWER_PULSE_DURATION_MS int "Duration of the power-on pulse in milliseconds." default 1500 help Trigger a power-on sequence by setting a power on GPIO pin high for a specific amount of time. -config MODEM_HL78XX_DEV_RESET_PULSE_DURATION +config MODEM_HL78XX_DEV_RESET_PULSE_DURATION_MS int "Duration of the power-reset pulse in milliseconds." default 100 help Trigger a power-reset sequence by setting a reset GPIO pin high for a specific amount of time. -config MODEM_HL78XX_DEV_STARTUP_TIME +config MODEM_HL78XX_DEV_STARTUP_TIME_MS int "Wait before assuming the device is ready." - default 1000 + default 120 help The expected time (in milliseconds) the modem needs to fully power on and become operational. -config MODEM_HL78XX_DEV_SHUTDOWN_TIME +config MODEM_HL78XX_DEV_SHUTDOWN_TIME_MS int "Wait before assuming the device is completely off." - default 1000 + default 120 help The amount of time (in milliseconds) the system should wait for the modem to fully shut down @@ -817,6 +882,14 @@ config MODEM_HL78XX_OFFLOAD_INIT_PRIORITY Do not mess with it unless you know what you are doing. Make sure offload init priority higher than dev init priority +config MODEM_HL78XX_LOG_CONTEXT_VERBOSE_DEBUG + bool "Verbose debug output in the HL78xx" + depends on MODEM_MODULES_LOG_LEVEL_DBG + help + Enabling this setting will turn on VERY heavy debugging from the + modem. Do NOT leave on for production. + This setting is depends on global log level debug. + rsource "hl78xx_evt_monitor/Kconfig.hl78xx_evt_monitor" endif # MODEM_HL78XX diff --git a/drivers/modem/hl78xx/hl78xx.c b/drivers/modem/hl78xx/hl78xx.c index 92542a447abf2..a6cbd65771c15 100644 --- a/drivers/modem/hl78xx/hl78xx.c +++ b/drivers/modem/hl78xx/hl78xx.c @@ -109,6 +109,8 @@ static const char *hl78xx_state_str(enum hl78xx_state state) return "await registered"; case MODEM_HL78XX_STATE_CARRIER_ON: return "carrier on"; + case MODEM_HL78XX_STATE_FOTA: + return "fota"; case MODEM_HL78XX_STATE_CARRIER_OFF: return "carrier off"; case MODEM_HL78XX_STATE_SIM_POWER_OFF: @@ -153,6 +155,28 @@ static const char *hl78xx_event_str(enum hl78xx_event event) return "bus closed"; case MODEM_HL78XX_EVENT_SOCKET_READY: return "socket ready"; +#ifdef CONFIG_MODEM_HL78XX_AIRVANTAGE + case MODEM_HL78XX_EVENT_WDSI_UPDATE: + return "wdsi update"; + case MODEM_HL78XX_EVENT_WDSI_RESTART: + return "wdsi restart"; + case MODEM_HL78XX_EVENT_WDSI_DOWNLOAD_REQUEST: + return "wdsi download request"; + case MODEM_HL78XX_EVENT_WDSI_DOWNLOAD_PROGRESS: + return "wdsi download progress"; + case MODEM_HL78XX_EVENT_WDSI_DOWNLOAD_COMPLETE: + return "wdsi download complete"; + case MODEM_HL78XX_EVENT_WDSI_INSTALL_REQUEST: + return "wdsi install request"; + case MODEM_HL78XX_EVENT_WDSI_INSTALLING_FIRMWARE: + return "wdsi installing firmware"; + case MODEM_HL78XX_EVENT_WDSI_FIRMWARE_INSTALL_SUCCEEDED: + return "wdsi firmware install succeeded"; + case MODEM_HL78XX_EVENT_WDSI_FIRMWARE_INSTALL_FAILED: + return "wdsi firmware install failed"; +#endif /* CONFIG_MODEM_HL78XX_AIRVANTAGE */ + case MODEM_HL78XX_EVENT_MDM_RESTART: + return "modem unexpected restart"; default: return "unknown event"; } @@ -355,12 +379,28 @@ void hl78xx_on_cxreg(struct modem_chat *chat, char **argv, uint16_t argc, void * void hl78xx_on_ksup(struct modem_chat *chat, char **argv, uint16_t argc, void *user_data) { int module_status; + struct hl78xx_data *data = (struct hl78xx_data *)user_data; struct hl78xx_evt event = {.type = HL78XX_LTE_MODEM_STARTUP}; if (argc != 2) { return; } module_status = ATOI(argv[1], 0, "module_status"); + data->status.boot.status = module_status; + /* Check for unexpected restart */ + if (data->status.boot.is_booted_previously == true && + module_status == (int)HL78XX_MODULE_READY) { + LOG_DBG("Modem unexpected restart detected %d", module_status); + hl78xx_delegate_event(data, MODEM_HL78XX_EVENT_MDM_RESTART); + } else if (data->status.boot.is_booted_previously == true && + module_status != (int)HL78XX_MODULE_READY) { + LOG_DBG("Modem failed to start %d", module_status); + hl78xx_delegate_event(data, MODEM_HL78XX_EVENT_SUSPEND); + } else { + data->status.boot.is_booted_previously = true; + LOG_DBG("Modem started successfully %d %d", module_status, + data->status.boot.is_booted_previously); + } event.content.value = module_status; event_dispatcher_dispatch(&event); HL78XX_LOG_DBG("Module status: %d", module_status); @@ -436,6 +476,20 @@ void hl78xx_on_cgmr(struct modem_chat *chat, char **argv, uint16_t argc, void *u k_mutex_unlock(&data->api_lock); } +void hl78xx_on_serial_number(struct modem_chat *chat, char **argv, uint16_t argc, void *user_data) +{ + struct hl78xx_data *data = (struct hl78xx_data *)user_data; + + if (argc != 2) { + return; + } + HL78XX_LOG_DBG("Serial Number: %s %s", argv[0], argv[1]); + k_mutex_lock(&data->api_lock, K_FOREVER); + safe_strncpy((char *)data->identity.serial_number, argv[1], + sizeof(data->identity.serial_number)); + k_mutex_unlock(&data->api_lock); +} + void hl78xx_on_iccid(struct modem_chat *chat, char **argv, uint16_t argc, void *user_data) { struct hl78xx_data *data = (struct hl78xx_data *)user_data; @@ -475,6 +529,27 @@ void hl78xx_on_kstatev(struct modem_chat *chat, char **argv, uint16_t argc, void event_dispatcher_dispatch(&event); } } + +void hl78xx_on_cgact(struct modem_chat *chat, char **argv, uint16_t argc, void *user_data) +{ + struct hl78xx_data *data = (struct hl78xx_data *)user_data; + int act_status = -1; + int cid = -1; + + if (argc != 3) { + return; + } + cid = ATOI(argv[1], -1, "cid"); + act_status = ATOI(argv[2], -1, "act_status"); + if (cid == -1 || act_status == -1 || cid > CONFIG_MODEM_HL78XX_MAX_PDP_CONTEXTS) { + /* Invalid parameters */ + return; + } + + data->status.gprs[cid - 1].is_active = (act_status == 1) ? true : false; + data->status.gprs[cid - 1].cid = cid; + HL78XX_LOG_DBG("CGACT: %s %s", argv[0], argv[2]); +} #endif void hl78xx_on_ksrep(struct modem_chat *chat, char **argv, uint16_t argc, void *user_data) @@ -590,7 +665,58 @@ void hl78xx_on_cops(struct modem_chat *chat, char **argv, uint16_t argc, void *u sizeof(data->status.network_operator.operator)); data->status.network_operator.format = ATOI(argv[2], 0, "network_operator_format"); } +#ifdef CONFIG_MODEM_HL78XX_AIRVANTAGE +void hl78xx_on_wdsi(struct modem_chat *chat, char **argv, uint16_t argc, void *user_data) +{ + struct hl78xx_data *data = (struct hl78xx_data *)user_data; + struct hl78xx_evt event = {.type = HL78XX_LTE_FOTA_UPDATE_STATUS}; + int wsi_status = -1; + uint32_t wsi_data = 0; + if (argc < 2) { + return; + } + wsi_status = ATOI(argv[1], -1, "wdsi"); + if (wsi_status == -1) { + return; + } + data->status.wdsi.level = wsi_status; + if (argc == 3) { + wsi_data = ATOI(argv[2], 0, "data"); + data->status.wdsi.data = wsi_data; + } + if (data->status.wdsi.level == WDSI_FIRMWARE_AVAILABLE) { + data->status.wdsi.fota_size = wsi_data; + hl78xx_delegate_event(data, MODEM_HL78XX_EVENT_WDSI_UPDATE); + } else if (data->status.wdsi.level == WDSI_BOOTSTRAP_CREDENTIALS_PRESENT) { + hl78xx_delegate_event(data, MODEM_HL78XX_EVENT_WDSI_RESTART); + } else if (data->status.wdsi.level == WDSI_FIRMWARE_DOWNLOAD_REQUEST) { + hl78xx_delegate_event(data, MODEM_HL78XX_EVENT_WDSI_DOWNLOAD_REQUEST); + } else if (data->status.wdsi.level == WDSI_DOWNLOAD_IN_PROGRESS) { + hl78xx_delegate_event(data, MODEM_HL78XX_EVENT_WDSI_DOWNLOAD_PROGRESS); + data->status.wdsi.progress = wsi_data; + } else if (data->status.wdsi.level == WDSI_FIRMWARE_DOWNLOADED) { + hl78xx_delegate_event(data, MODEM_HL78XX_EVENT_WDSI_DOWNLOAD_COMPLETE); + } else if (data->status.wdsi.level == WDSI_FIRMWARE_INSTALL_REQUEST) { + hl78xx_delegate_event(data, MODEM_HL78XX_EVENT_WDSI_INSTALL_REQUEST); + } else if (data->status.wdsi.level == WDSI_FIRMWARE_UPDATE_START) { + hl78xx_delegate_event(data, MODEM_HL78XX_EVENT_WDSI_INSTALLING_FIRMWARE); + } else if (data->status.wdsi.level == WDSI_FIRMWARE_UPDATE_SUCCESS) { + hl78xx_delegate_event(data, MODEM_HL78XX_EVENT_WDSI_FIRMWARE_INSTALL_SUCCEEDED); + } else if (data->status.wdsi.level == WDSI_FIRMWARE_UPDATE_FAILED) { + hl78xx_delegate_event(data, MODEM_HL78XX_EVENT_WDSI_FIRMWARE_INSTALL_FAILED); + } else { + /* other WDSI levels during FOTA can be handled here if needed */ + } + if ((data->status.wdsi.level == WDSI_DOWNLOAD_IN_PROGRESS && + (data->status.wdsi.progress == 0 || data->status.wdsi.progress == 100)) || + data->status.wdsi.level != WDSI_DOWNLOAD_IN_PROGRESS) { + event.content.wdsi_indication = data->status.wdsi.level; + event_dispatcher_dispatch(&event); + } + HL78XX_LOG_DBG("WDSI: %d %d", wsi_status, wsi_data); +} +#endif /* CONFIG_MODEM_HL78XX_AIRVANTAGE */ /* ------------------------------------------------------------------------- * Pipe & chat initialization * - modem backend pipe setup and chat initialisation helpers @@ -877,32 +1003,36 @@ static void hl78xx_await_power_on_event_handler(struct hl78xx_data *data, enum h { switch (evt) { case MODEM_HL78XX_EVENT_TIMEOUT: - hl78xx_enter_state(data, MODEM_HL78XX_STATE_RUN_INIT_SCRIPT); + modem_pipe_attach(data->uart_pipe, hl78xx_bus_pipe_handler, data); + modem_pipe_open_async(data->uart_pipe); break; case MODEM_HL78XX_EVENT_SUSPEND: hl78xx_enter_state(data, MODEM_HL78XX_STATE_IDLE); break; + case MODEM_HL78XX_EVENT_BUS_OPENED: + modem_chat_attach(&data->chat, data->uart_pipe); + hl78xx_run_post_restart_script_async(data); + break; + + case MODEM_HL78XX_EVENT_SCRIPT_SUCCESS: + hl78xx_enter_state(data, MODEM_HL78XX_STATE_RUN_INIT_SCRIPT); + break; + default: break; } } static int hl78xx_on_run_init_script_state_enter(struct hl78xx_data *data) { - modem_pipe_attach(data->uart_pipe, hl78xx_bus_pipe_handler, data); - return modem_pipe_open_async(data->uart_pipe); + hl78xx_run_init_script_async(data); + return 0; } static void hl78xx_run_init_script_event_handler(struct hl78xx_data *data, enum hl78xx_event evt) { switch (evt) { - case MODEM_HL78XX_EVENT_BUS_OPENED: - modem_chat_attach(&data->chat, data->uart_pipe); - /* Run init script via chat TU wrapper (script symbols live in hl78xx_chat.c) */ - hl78xx_run_init_script_async(data); - break; - case MODEM_HL78XX_EVENT_SCRIPT_SUCCESS: hl78xx_enter_state(data, MODEM_HL78XX_STATE_RUN_RAT_CONFIG_SCRIPT); break; @@ -967,11 +1097,10 @@ static void hl78xx_run_init_fail_script_event_handler(struct hl78xx_data *data, case MODEM_HL78XX_EVENT_SCRIPT_FAILED: if (!hl78xx_gpio_is_enabled(&config->mdm_gpio_wake)) { - LOG_ERR("modem wake pin is not enabled, make sure modem low power is " - "disabled, if you are not sure enable wake up pin by adding it " - "dts!!"); + LOG_ERR("The modem wake pin is not enabled. Make sure that modem low-power " + "mode is disabled. If you’re unsure, enable it by adding the " + "corresponding DTS configuration entry."); } - if (data->status.script_fail_counter++ < MAX_SCRIPT_AT_CMD_RETRY) { if (hl78xx_gpio_is_enabled(&config->mdm_gpio_pwr_on)) { hl78xx_enter_state(data, MODEM_HL78XX_STATE_POWER_ON_PULSE); @@ -1008,6 +1137,7 @@ static int hl78xx_on_rat_cfg_script_state_enter(struct hl78xx_data *data) } if (modem_require_restart) { + HL78XX_LOG_DBG("Modem restart required to apply new RAT/Band settings"); ret = modem_dynamic_cmd_send(data, NULL, cmd_restart, strlen(cmd_restart), hl78xx_get_ok_match(), 1, false); if (ret < 0) { @@ -1027,17 +1157,13 @@ static int hl78xx_on_rat_cfg_script_state_enter(struct hl78xx_data *data) static void hl78xx_run_rat_cfg_script_event_handler(struct hl78xx_data *data, enum hl78xx_event evt) { - int ret = 0; - switch (evt) { case MODEM_HL78XX_EVENT_TIMEOUT: LOG_DBG("Rebooting modem to apply new RAT settings"); - ret = hl78xx_run_post_restart_script_async(data); - if (ret < 0) { - hl78xx_delegate_event(data, MODEM_HL78XX_EVENT_SUSPEND); - } break; - + case MODEM_HL78XX_EVENT_MDM_RESTART: + hl78xx_enter_state(data, MODEM_HL78XX_STATE_RUN_INIT_SCRIPT); + break; case MODEM_HL78XX_EVENT_SCRIPT_SUCCESS: hl78xx_enter_state(data, MODEM_HL78XX_STATE_RUN_ENABLE_GPRS_SCRIPT); break; @@ -1116,7 +1242,7 @@ static void hl78xx_enable_gprs_event_handler(struct hl78xx_data *data, enum hl78 switch (evt) { case MODEM_HL78XX_EVENT_SCRIPT_SUCCESS: case MODEM_HL78XX_EVENT_SCRIPT_FAILED: - hl78xx_start_timer(data, MODEM_HL78XX_PERIODIC_SCRIPT_TIMEOUT); + hl78xx_enter_state(data, MODEM_HL78XX_STATE_AWAIT_REGISTERED); break; case MODEM_HL78XX_EVENT_TIMEOUT: @@ -1169,6 +1295,11 @@ static void hl78xx_await_registered_event_handler(struct hl78xx_data *data, enum break; + case MODEM_HL78XX_EVENT_MDM_RESTART: + LOG_DBG("Modem restart detected %d", __LINE__); + hl78xx_enter_state(data, MODEM_HL78XX_STATE_RUN_INIT_SCRIPT); + break; + case MODEM_HL78XX_EVENT_REGISTERED: hl78xx_enter_state(data, MODEM_HL78XX_STATE_CARRIER_ON); break; @@ -1190,6 +1321,16 @@ static int hl78xx_on_await_registered_state_leave(struct hl78xx_data *data) static int hl78xx_on_carrier_on_state_enter(struct hl78xx_data *data) { +#ifdef CONFIG_MODEM_HL78XX_RAT_GSM + int ret = 0; + /* Activate the PDP context */ + ret = hl78xx_gsm_pdp_activate(data); + if (ret) { + LOG_ERR("Failed to activate PDP context: %d", ret); + hl78xx_delegate_event(data, MODEM_HL78XX_EVENT_SCRIPT_FAILED); + return ret; + } +#endif /* CONFIG_MODEM_HL78XX_RAT_GSM */ notif_carrier_on(data->dev); iface_status_work_cb(data, hl78xx_chat_callback_handler); return 0; @@ -1203,6 +1344,7 @@ static void hl78xx_carrier_on_event_handler(struct hl78xx_data *data, enum hl78x break; case MODEM_HL78XX_EVENT_SCRIPT_FAILED: + /* TODO: Handle script failure */ break; case MODEM_HL78XX_EVENT_TIMEOUT: @@ -1217,6 +1359,19 @@ static void hl78xx_carrier_on_event_handler(struct hl78xx_data *data, enum hl78x hl78xx_enter_state(data, MODEM_HL78XX_STATE_INIT_POWER_OFF); break; + case MODEM_HL78XX_EVENT_MDM_RESTART: + LOG_DBG("Modem restart detected %d", __LINE__); + hl78xx_enter_state(data, MODEM_HL78XX_STATE_RUN_INIT_SCRIPT); + break; +#ifdef CONFIG_MODEM_HL78XX_AIRVANTAGE + case MODEM_HL78XX_EVENT_WDSI_UPDATE: + case MODEM_HL78XX_EVENT_WDSI_DOWNLOAD_REQUEST: + case MODEM_HL78XX_EVENT_WDSI_DOWNLOAD_PROGRESS: + case MODEM_HL78XX_EVENT_WDSI_INSTALL_REQUEST: + hl78xx_enter_state(data, MODEM_HL78XX_STATE_FOTA); + data->status.wdsi.in_progress = true; + break; +#endif /* CONFIG_MODEM_HL78XX_AIRVANTAGE */ default: break; } @@ -1227,7 +1382,118 @@ static int hl78xx_on_carrier_on_state_leave(struct hl78xx_data *data) hl78xx_stop_timer(data); return 0; } +#ifdef CONFIG_MODEM_HL78XX_AIRVANTAGE +static int hl78xx_on_fota_state_enter(struct hl78xx_data *data) +{ + HL78XX_LOG_DBG("Entering FOTA state"); + hl78xx_start_timer(data, K_MSEC(100)); + /* Decide best time to start FOTA */ + return 0; +} +static void hl78xx_fota_event_handler(struct hl78xx_data *data, enum hl78xx_event evt) +{ + switch (evt) { + case MODEM_HL78XX_EVENT_TIMEOUT: + /* Start FOTA process */ + if (data->status.wdsi.in_progress == true) { + if (data->status.wdsi.level == WDSI_FIRMWARE_DOWNLOAD_REQUEST && + data->status.wdsi.fota_state != HL78XX_WDSI_FOTA_DOWNLOADING) { + LOG_INF("FOTA available, notifying modem..."); + hl78xx_delegate_event(data, + MODEM_HL78XX_EVENT_WDSI_DOWNLOAD_REQUEST); + } else if (data->status.wdsi.level == WDSI_FIRMWARE_INSTALL_REQUEST && + data->status.wdsi.fota_state != HL78XX_WDSI_FOTA_INSTALLING) { + LOG_INF("FOTA downloaded, notifying modem..."); + hl78xx_delegate_event(data, + MODEM_HL78XX_EVENT_WDSI_INSTALL_REQUEST); + } else { + HL78XX_LOG_DBG("FOTA in progress, notifying modem..."); + hl78xx_delegate_event(data, MODEM_HL78XX_EVENT_WDSI_UPDATE); + } + } + break; + case MODEM_HL78XX_EVENT_SCRIPT_SUCCESS: + HL78XX_LOG_DBG("FOTA script completed successfully."); + break; + case MODEM_HL78XX_EVENT_WDSI_UPDATE: + if (data->status.wdsi.level == WDSI_DM_SESSION_CLOSED) { + LOG_INF("FOTA DM session closed."); + if (data->status.wdsi.in_progress == true) { + LOG_INF("FOTA update process completed, rebooting modem..."); + } else { + LOG_INF("FOTA update process not started, returning to " + "carrier on state..."); + } + break; + } + break; + case MODEM_HL78XX_EVENT_WDSI_RESTART: + LOG_INF("FOTA modem restart occurred...%d", data->status.boot.is_booted_previously); + break; + case MODEM_HL78XX_EVENT_WDSI_DOWNLOAD_REQUEST: + if (data->status.wdsi.fota_state == HL78XX_WDSI_FOTA_DOWNLOADING) { + return; + } + LOG_INF("FOTA download requested File size %d bytes, starting download...", + data->status.wdsi.fota_size); + data->status.wdsi.fota_state = HL78XX_WDSI_FOTA_DOWNLOADING; + hl78xx_run_fota_script_download_accept_async(data); + break; + case MODEM_HL78XX_EVENT_WDSI_DOWNLOAD_PROGRESS: + LOG_INF("FOTA update in progress, completion... %d%%", data->status.wdsi.progress); + break; + case MODEM_HL78XX_EVENT_WDSI_DOWNLOAD_COMPLETE: + LOG_INF("FOTA download completed..."); + data->status.wdsi.fota_state = HL78XX_WDSI_FOTA_DOWNLOAD_COMPLETED; + break; + case MODEM_HL78XX_EVENT_WDSI_INSTALL_REQUEST: + LOG_INF("FOTA install request received..."); + data->status.wdsi.fota_state = HL78XX_WDSI_FOTA_INSTALLING; + hl78xx_run_fota_script_install_accept_async(data); + break; + case MODEM_HL78XX_EVENT_WDSI_INSTALLING_FIRMWARE: + LOG_INF("Install accepted, FOTA update installing..."); + LOG_INF("This may take several minutes, please wait..."); + LOG_INF("Do not power off the modem!!!"); + break; + case MODEM_HL78XX_EVENT_WDSI_FIRMWARE_INSTALL_SUCCEEDED: + LOG_INF("FOTA firmware install succeeded...Waiting for modem +KSUP"); + data->status.wdsi.fota_state = HL78XX_WDSI_FOTA_INSTALL_COMPLETED; + data->status.wdsi.in_progress = false; + data->status.wdsi.progress = 0; + break; + case MODEM_HL78XX_EVENT_WDSI_FIRMWARE_INSTALL_FAILED: + LOG_INF("FOTA firmware install failed..."); + data->status.wdsi.in_progress = false; + data->status.wdsi.progress = 0; + /* TODO: fail, do something */ + break; + case MODEM_HL78XX_EVENT_MDM_RESTART: + if (data->status.wdsi.in_progress == true) { + /* FOTA update in progress, waiting for it to complete */ + data->status.wdsi.fota_state = HL78XX_WDSI_FOTA_IDLE; + } else { + LOG_INF("Exiting FOTA state, re-initializing modem..."); + hl78xx_enter_state(data, MODEM_HL78XX_STATE_RUN_INIT_SCRIPT); + } + break; + case MODEM_HL78XX_EVENT_REGISTERED: + /* stay in FOTA state */ + hl78xx_start_timer(data, K_MSEC(100)); + break; + default: + break; + } +} + +static int hl78xx_on_fota_state_leave(struct hl78xx_data *data) +{ + HL78XX_LOG_DBG("Exiting FOTA state"); + hl78xx_stop_timer(data); + return 0; +} +#endif /* CONFIG_MODEM_HL78XX_AIRVANTAGE */ static int hl78xx_on_carrier_off_state_enter(struct hl78xx_data *data) { notif_carrier_off(data->dev); @@ -1465,7 +1731,7 @@ static void hl78xx_event_handler(struct hl78xx_data *data, enum hl78xx_event evt if ((int)s <= MODEM_HL78XX_STATE_AWAIT_POWER_OFF && hl78xx_state_table[s].on_event) { hl78xx_state_table[s].on_event(data, evt); } else { - LOG_ERR("%d %s unknown event", __LINE__, __func__); + LOG_ERR("%d unknown event %d", __LINE__, evt); } if (state != s) { hl78xx_log_state_changed(state, s); @@ -1682,7 +1948,6 @@ static int hl78xx_init(const struct device *dev) if (ret < 0) { goto error; } - #ifndef CONFIG_PM_DEVICE hl78xx_delegate_event(data, MODEM_HL78XX_EVENT_RESUME); #else @@ -1692,6 +1957,7 @@ static int hl78xx_init(const struct device *dev) #ifdef CONFIG_MODEM_HL78XX_STAY_IN_BOOT_MODE_FOR_ROAMING k_sem_take(&data->stay_in_boot_mode_sem, K_FOREVER); #endif + LOG_INF("Modem HL78xx initialized"); return 0; error: return ret; @@ -1766,6 +2032,13 @@ const static struct hl78xx_state_handlers hl78xx_state_table[] = { hl78xx_on_carrier_on_state_leave, hl78xx_carrier_on_event_handler }, +#ifdef CONFIG_MODEM_HL78XX_AIRVANTAGE + [MODEM_HL78XX_STATE_FOTA] = { + hl78xx_on_fota_state_enter, + hl78xx_on_fota_state_leave, + hl78xx_fota_event_handler + }, +#endif /* CONFIG_MODEM_HL78XX_AIRVANTAGE */ [MODEM_HL78XX_STATE_CARRIER_OFF] = { hl78xx_on_carrier_off_state_enter, hl78xx_on_carrier_off_state_leave, @@ -1846,10 +2119,10 @@ static DEVICE_API(cellular, hl78xx_api) = { CONFIG_MODEM_HL78XX_DEV_INIT_PRIORITY, &hl78xx_api); #define MODEM_DEVICE_SWIR_HL78XX(inst) \ - MODEM_HL78XX_DEFINE_INSTANCE(inst, CONFIG_MODEM_HL78XX_DEV_POWER_PULSE_DURATION, \ - CONFIG_MODEM_HL78XX_DEV_RESET_PULSE_DURATION, \ - CONFIG_MODEM_HL78XX_DEV_STARTUP_TIME, \ - CONFIG_MODEM_HL78XX_DEV_SHUTDOWN_TIME, false, NULL, NULL) + MODEM_HL78XX_DEFINE_INSTANCE(inst, CONFIG_MODEM_HL78XX_DEV_POWER_PULSE_DURATION_MS, \ + CONFIG_MODEM_HL78XX_DEV_RESET_PULSE_DURATION_MS, \ + CONFIG_MODEM_HL78XX_DEV_STARTUP_TIME_MS, \ + CONFIG_MODEM_HL78XX_DEV_SHUTDOWN_TIME_MS, false, NULL, NULL) #define DT_DRV_COMPAT swir_hl7812 DT_INST_FOREACH_STATUS_OKAY(MODEM_DEVICE_SWIR_HL78XX) diff --git a/drivers/modem/hl78xx/hl78xx.h b/drivers/modem/hl78xx/hl78xx.h index d48f5b2d88743..62857db7944eb 100644 --- a/drivers/modem/hl78xx/hl78xx.h +++ b/drivers/modem/hl78xx/hl78xx.h @@ -41,6 +41,7 @@ #define MDM_MAX_DATA_LENGTH CONFIG_MODEM_HL78XX_UART_BUFFER_SIZES #define MDM_MAX_SOCKETS CONFIG_MODEM_HL78XX_NUM_SOCKETS +#define MDM_MAX_PDP_CONTEXTS CONFIG_MODEM_HL78XX_MAX_PDP_CONTEXTS #define MDM_BASE_SOCKET_NUM 1 #define MDM_BAND_BITMAP_LEN_BYTES 32 #define MDM_BAND_HEX_STR_LEN (MDM_BAND_BITMAP_LEN_BYTES * 2 + 1) @@ -68,38 +69,43 @@ #endif /* Modem Communication Patterns */ -#define EOF_PATTERN "--EOF--Pattern--" -#define TERMINATION_PATTERN "+++" -#define CONNECT_STRING "CONNECT" -#define CME_ERROR_STRING "+CME ERROR: " -#define OK_STRING "OK" - +#define EOF_PATTERN "--EOF--Pattern--" +#define TERMINATION_PATTERN "+++" +#define CONNECT_STRING "CONNECT" +#define CME_ERROR_STRING "+CME ERROR: " +#define OK_STRING "OK" /* RAT (Radio Access Technology) commands */ -#define SET_RAT_M1_CMD_LEGACY "AT+KSRAT=0" -#define SET_RAT_NB1_CMD_LEGACY "AT+KSRAT=1" -#define SET_RAT_GSM_CMD_LEGACY "AT+KSRAT=2" -#define SET_RAT_NBNTN_CMD_LEGACY "AT+KSRAT=3" - -#define KSRAT_QUERY "AT+KSRAT?" -#define DISABLE_RAT_AUTO "AT+KSELACQ=0,0" - -#define SET_RAT_M1_CMD "AT+KSRAT=0,1" -#define SET_RAT_NB1_CMD "AT+KSRAT=1,1" -#define SET_RAT_GMS_CMD "AT+KSRAT=2,1" -#define SET_RAT_NBNTN_CMD "AT+KSRAT=3,1" - +#define SET_RAT_M1_CMD_LEGACY "AT+KSRAT=0" +#define SET_RAT_NB1_CMD_LEGACY "AT+KSRAT=1" +#define SET_RAT_GSM_CMD_LEGACY "AT+KSRAT=2" +#define SET_RAT_NBNTN_CMD_LEGACY "AT+KSRAT=3" +#define SET_RAT_M1_CMD "AT+KSRAT=0,1" +#define SET_RAT_NB1_CMD "AT+KSRAT=1,1" +#define SET_RAT_GMS_CMD "AT+KSRAT=2,1" +#define SET_RAT_NBNTN_CMD "AT+KSRAT=3,1" +#define KSRAT_QUERY "AT+KSRAT?" +#define DISABLE_RAT_AUTO "AT+KSELACQ=0,0" +/* Enable/Disable RAT registration status */ +#define ENABLE_LTE_REG_STATUS_CMD "AT+CEREG=5" +#define ENABLE_GSM_REG_STATUS_CMD "AT+CREG=3" +#define DISABLE_LTE_REG_STATUS_CMD "AT+CEREG=0" +#define DISABLE_GSM_REG_STATUS_CMD "AT+CREG=0" /* Power mode commands */ -#define SET_AIRPLANE_MODE_CMD_LEGACY "AT+CFUN=4,0" -#define SET_AIRPLANE_MODE_CMD "AT+CFUN=4,1" -#define SET_FULLFUNCTIONAL_MODE_CMD_LEGACY "AT+CFUN=1,0" -#define SET_FULLFUNCTIONAL_MODE_CMD "AT+CFUN=1,1" -#define SET_SIM_PWR_OFF_MODE_CMD "AT+CFUN=0" -#define GET_FULLFUNCTIONAL_MODE_CMD "AT+CFUN?" -#define MDM_POWER_OFF_CMD_LEGACY "AT+CPWROFF" -#define MDM_POWER_FAST_OFF_CMD_LEGACY "AT+CPWROFF=1" +#define SET_AIRPLANE_MODE_CMD_LEGACY "AT+CFUN=4,0" +#define SET_AIRPLANE_MODE_CMD "AT+CFUN=4,1" +#define SET_FULLFUNCTIONAL_MODE_CMD_LEGACY "AT+CFUN=1,0" +#define SET_FULLFUNCTIONAL_MODE_CMD "AT+CFUN=1,1" +#define SET_SIM_PWR_OFF_MODE_CMD "AT+CFUN=0" +#define GET_FULLFUNCTIONAL_MODE_CMD "AT+CFUN?" +#define MDM_POWER_OFF_CMD_LEGACY "AT+CPWROFF" +#define MDM_POWER_FAST_OFF_CMD_LEGACY "AT+CPWROFF=1" /* PDP Context commands */ -#define DEACTIVATE_PDP_CONTEXT "AT+CGACT=0" -#define ACTIVATE_PDP_CONTEXT "AT+CGACT=1" +#define DEACTIVATE_PDP_CONTEXT "AT+CGACT=0" +#define ACTIVATE_PDP_CONTEXT "AT+CGACT=1" +/* Airvantage commands */ +/* User initiated connection */ +#define WDSI_USER_INITIATED_CONNECTION_START_CMD "AT+WDSS=1,1" +#define WDSI_USER_INITIATED_CONNECTION_STOP_CMD "AT+WDSS=1,0" /* Helper macros */ #define ATOI(s_, value_, desc_) modem_atoi(s_, value_, desc_, __func__) @@ -110,7 +116,7 @@ (LOG_DBG(str, ##__VA_ARGS__)), \ ((void)0)) -/* Enums */ +/* States */ enum hl78xx_state { MODEM_HL78XX_STATE_IDLE = 0, MODEM_HL78XX_STATE_RESET_PULSE, @@ -126,6 +132,7 @@ enum hl78xx_state { */ MODEM_HL78XX_STATE_AWAIT_REGISTERED, MODEM_HL78XX_STATE_CARRIER_ON, + MODEM_HL78XX_STATE_FOTA, /* Minimum functionality, SIM powered off, Modem Power down * CFUN=0 */ @@ -152,7 +159,24 @@ enum hl78xx_event { MODEM_HL78XX_EVENT_DEREGISTERED, MODEM_HL78XX_EVENT_BUS_OPENED, MODEM_HL78XX_EVENT_BUS_CLOSED, + /* Modem unexpected restart event */ + MODEM_HL78XX_EVENT_MDM_RESTART, MODEM_HL78XX_EVENT_SOCKET_READY, + MODEM_HL78XX_EVENT_NTN_POSREQ, +#ifdef CONFIG_MODEM_HL78XX_AIRVANTAGE + + /* WDSI FOTA events */ + MODEM_HL78XX_EVENT_WDSI_UPDATE, + MODEM_HL78XX_EVENT_WDSI_RESTART, + MODEM_HL78XX_EVENT_WDSI_DOWNLOAD_REQUEST, + MODEM_HL78XX_EVENT_WDSI_DOWNLOAD_PROGRESS, + MODEM_HL78XX_EVENT_WDSI_DOWNLOAD_COMPLETE, + MODEM_HL78XX_EVENT_WDSI_INSTALL_REQUEST, + MODEM_HL78XX_EVENT_WDSI_INSTALLING_FIRMWARE, + MODEM_HL78XX_EVENT_WDSI_FIRMWARE_INSTALL_SUCCEEDED, + MODEM_HL78XX_EVENT_WDSI_FIRMWARE_INSTALL_FAILED, +#endif /* CONFIG_MODEM_HL78XX_AIRVANTAGE */ + MODEM_HL78XX_EVENT_COUNT }; enum hl78xx_tcp_notif { @@ -243,6 +267,7 @@ struct modem_identity { uint8_t iccid[MDM_ICCID_LENGTH]; uint8_t manufacturer[MDM_MANUFACTURER_LENGTH]; uint8_t fw_version[MDM_REVISION_LENGTH]; + uint8_t serial_number[MDM_SERIAL_NUMBER_LENGTH]; char apn[MDM_APN_MAX_LENGTH]; }; struct hl78xx_phone_functionality_work { @@ -254,7 +279,34 @@ struct hl78xx_network_operator { char operator[MDM_MODEL_LENGTH]; uint8_t format; }; - +struct hl78xx_modem_boot_status { + bool is_booted_previously; + enum hl78xx_module_status status; +}; +struct hl78xx_gprs_status { + bool is_active; + int8_t cid; +}; +#ifdef CONFIG_MODEM_HL78XX_AIRVANTAGE +/* WDSI FOTA states */ +enum hl78xx_wdsi_fota_states { + HL78XX_WDSI_FOTA_IDLE = 0, + HL78XX_WDSI_FOTA_DOWNLOADING, + HL78XX_WDSI_FOTA_DOWNLOAD_COMPLETED, + HL78XX_WDSI_FOTA_INSTALLING, + HL78XX_WDSI_FOTA_INSTALL_COMPLETED, + HL78XX_WDSI_FOTA_INSTALL_FAILED +}; +struct hl78xx_wdsi_status { + enum wdsi_indication level; + uint32_t data; + size_t fota_size; + bool in_progress; + enum hl78xx_wdsi_fota_states fota_state; + bool completed; + int progress; +}; +#endif /* CONFIG_MODEM_HL78XX_AIRVANTAGE */ struct modem_status { struct registration_status registration; int16_t rssi; @@ -265,18 +317,21 @@ struct modem_status { int variant; enum hl78xx_state state; struct kband_syntax kbndcfg[HL78XX_RAT_COUNT]; + struct hl78xx_gprs_status gprs[MDM_MAX_PDP_CONTEXTS]; + struct hl78xx_modem_boot_status boot; struct hl78xx_phone_functionality_work phone_functionality; struct apn_state apn; struct hl78xx_network_operator network_operator; +#ifdef CONFIG_MODEM_HL78XX_AIRVANTAGE + struct hl78xx_wdsi_status wdsi; +#endif /* CONFIG_MODEM_HL78XX_AIRVANTAGE */ }; - struct modem_gpio_callbacks { struct gpio_callback vgpio_cb; struct gpio_callback uart_dsr_cb; struct gpio_callback gpio6_cb; struct gpio_callback uart_cts_cb; }; - struct modem_event_system { struct k_work event_dispatch_work; uint8_t event_buf[8]; diff --git a/drivers/modem/hl78xx/hl78xx_apis.c b/drivers/modem/hl78xx/hl78xx_apis.c index e1af412b1730c..760696a6f9402 100644 --- a/drivers/modem/hl78xx/hl78xx_apis.c +++ b/drivers/modem/hl78xx/hl78xx_apis.c @@ -175,7 +175,10 @@ int hl78xx_api_func_get_modem_info_vendor(const struct device *dev, safe_strncpy(info, (const char *)data->status.network_operator.operator, MIN(size, sizeof(data->status.network_operator.operator))); break; - + case HL78XX_MODEM_INFO_SERIAL_NUMBER: + safe_strncpy(info, (const char *)data->identity.serial_number, + MIN(size, sizeof(data->identity.serial_number))); + break; default: break; } @@ -289,3 +292,34 @@ int hl78xx_api_func_modem_dynamic_cmd_send(const struct device *dev, const char return modem_dynamic_cmd_send(data, NULL, cmd, cmd_size, response_matches, matches_size, true); } +#ifdef CONFIG_MODEM_HL78XX_AIRVANTAGE +int hl78xx_start_airvantage_dm_session(const struct device *dev) +{ + int ret = 0; + struct hl78xx_data *data = (struct hl78xx_data *)dev->data; + + ret = modem_dynamic_cmd_send(data, NULL, WDSI_USER_INITIATED_CONNECTION_START_CMD, + strlen(WDSI_USER_INITIATED_CONNECTION_START_CMD), + hl78xx_get_ok_match(), 1, false); + if (ret < 0) { + LOG_ERR("Start DM session error %d", ret); + return ret; + } + return 0; +} + +int hl78xx_stop_airvantage_dm_session(const struct device *dev) +{ + int ret = 0; + struct hl78xx_data *data = (struct hl78xx_data *)dev->data; + + ret = modem_dynamic_cmd_send(data, NULL, WDSI_USER_INITIATED_CONNECTION_STOP_CMD, + strlen(WDSI_USER_INITIATED_CONNECTION_STOP_CMD), + hl78xx_get_ok_match(), 1, false); + if (ret < 0) { + LOG_ERR("Stop DM session error %d", ret); + return ret; + } + return 0; +} +#endif /* CONFIG_MODEM_HL78XX_AIRVANTAGE */ diff --git a/drivers/modem/hl78xx/hl78xx_at_shell.c b/drivers/modem/hl78xx/hl78xx_at_shell.c new file mode 100644 index 0000000000000..695f0aca585e8 --- /dev/null +++ b/drivers/modem/hl78xx/hl78xx_at_shell.c @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2025 Netfeasa Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include + +#include +LOG_MODULE_REGISTER(modem_at_shell, CONFIG_MODEM_LOG_LEVEL); + +#define AT_SHELL_STATE_SCRIPT_RUNNING_BIT 1 + +const static struct device *modem = DEVICE_DT_GET(DT_ALIAS(modem)); +static struct modem_chat *at_shell_chat; +static uint8_t at_shell_request_buf[CONFIG_MODEM_AT_SHELL_COMMAND_MAX_SIZE]; +static struct modem_chat_script_chat at_shell_script_chat[1]; +static struct modem_chat_match at_shell_script_chat_matches[2]; +static uint8_t at_shell_match_buf[CONFIG_MODEM_AT_SHELL_RESPONSE_MAX_SIZE]; +static const struct shell *at_shell_active_shell; +static atomic_t at_shell_state; + +static void at_shell_print_any_match(struct modem_chat *chat, char **argv, uint16_t argc, + void *user_data) +{ + if (at_shell_active_shell == NULL) { + return; + } + + if (argc != 2) { + return; + } + + shell_print(at_shell_active_shell, "%s", argv[1]); +} + +static void at_shell_print_match(struct modem_chat *chat, char **argv, uint16_t argc, + void *user_data) +{ + if (at_shell_active_shell == NULL) { + return; + } + + if (argc != 1) { + return; + } + + shell_print(at_shell_active_shell, "%s", argv[0]); +} + +MODEM_CHAT_MATCHES_DEFINE(at_shell_abort_matches, + MODEM_CHAT_MATCH("+CME ERROR:", "", at_shell_print_match), + MODEM_CHAT_MATCH("ERROR", "", at_shell_print_match)); + +static void at_shell_script_callback(struct modem_chat *chat, enum modem_chat_script_result result, + void *user_data) +{ + atomic_clear_bit(&at_shell_state, AT_SHELL_STATE_SCRIPT_RUNNING_BIT); +} + +MODEM_CHAT_SCRIPT_DEFINE(at_shell_script, at_shell_script_chat, at_shell_abort_matches, + at_shell_script_callback, CONFIG_MODEM_AT_SHELL_RESPONSE_TIMEOUT_MS); + +static void at_shell_init_script_chat(void) +{ + /* Match anything except the expected response without progressing script */ + modem_chat_match_init(&at_shell_script_chat_matches[0]); + modem_chat_match_set_match(&at_shell_script_chat_matches[0], ""); + modem_chat_match_set_separators(&at_shell_script_chat_matches[0], ""); + modem_chat_match_set_callback(&at_shell_script_chat_matches[0], at_shell_print_any_match); + modem_chat_match_set_partial(&at_shell_script_chat_matches[0], true); + modem_chat_match_enable_wildcards(&at_shell_script_chat_matches[0], false); + + /* Match the expected response and terminate script */ + modem_chat_match_init(&at_shell_script_chat_matches[1]); + modem_chat_match_set_match(&at_shell_script_chat_matches[1], ""); + modem_chat_match_set_separators(&at_shell_script_chat_matches[1], ""); + modem_chat_match_set_callback(&at_shell_script_chat_matches[1], at_shell_print_match); + modem_chat_match_set_partial(&at_shell_script_chat_matches[1], false); + modem_chat_match_enable_wildcards(&at_shell_script_chat_matches[1], false); + + modem_chat_script_chat_init(at_shell_script_chat); + modem_chat_script_chat_set_response_matches(at_shell_script_chat, + at_shell_script_chat_matches, + ARRAY_SIZE(at_shell_script_chat_matches)); + modem_chat_script_chat_set_timeout(at_shell_script_chat, + CONFIG_MODEM_AT_SHELL_RESPONSE_TIMEOUT_MS); +} + +static int hl78xx_at_shell_init(void) +{ + struct hl78xx_data *data = NULL; + + if (device_is_ready(modem) == false) { + LOG_ERR("%d, %s Device %s is not ready", __LINE__, __func__, modem->name); + } + data = (struct hl78xx_data *)modem->data; + if (data == NULL) { + LOG_ERR("%d, %s Modem data is NULL", __LINE__, __func__); + return -EINVAL; + } + at_shell_chat = &data->chat; + + at_shell_init_script_chat(); + return 0; +} + +static int at_shell_cmd_handler(const struct shell *sh, size_t argc, char **argv) +{ + int ret; + + if (argc < 2) { + return -EINVAL; + } + if (atomic_test_and_set_bit(&at_shell_state, AT_SHELL_STATE_SCRIPT_RUNNING_BIT)) { + shell_error(sh, "script is already running"); + return -EBUSY; + } + strncpy(at_shell_request_buf, argv[1], sizeof(at_shell_request_buf) - 1); + ret = modem_chat_script_chat_set_request(at_shell_script_chat, at_shell_request_buf); + if (ret < 0) { + return -EINVAL; + } + if (argc == 3) { + strncpy(at_shell_match_buf, argv[2], sizeof(at_shell_match_buf) - 1); + } else { + strncpy(at_shell_match_buf, "OK", sizeof(at_shell_match_buf) - 1); + } + ret = modem_chat_match_set_match(&at_shell_script_chat_matches[1], at_shell_match_buf); + if (ret < 0) { + return -EINVAL; + } + at_shell_active_shell = sh; + ret = modem_chat_run_script_async(at_shell_chat, &at_shell_script); + if (ret < 0) { + shell_error(sh, "failed to start script"); + atomic_clear_bit(&at_shell_state, AT_SHELL_STATE_SCRIPT_RUNNING_BIT); + } + return ret; +} + +SHELL_STATIC_SUBCMD_SET_CREATE(modem_sub_cmds, + SHELL_CMD_ARG(at, NULL, "at ", + at_shell_cmd_handler, 1, 2), + SHELL_SUBCMD_SET_END); + +SHELL_CMD_REGISTER(modem, &modem_sub_cmds, "Modem commands", NULL); + +SYS_INIT(hl78xx_at_shell_init, APPLICATION, CONFIG_APPLICATION_INIT_PRIORITY); diff --git a/drivers/modem/hl78xx/hl78xx_cfg.c b/drivers/modem/hl78xx/hl78xx_cfg.c index 461d066865b78..b62734d442c16 100644 --- a/drivers/modem/hl78xx/hl78xx_cfg.c +++ b/drivers/modem/hl78xx/hl78xx_cfg.c @@ -87,8 +87,8 @@ int hl78xx_rat_cfg(struct hl78xx_data *data, bool *modem_require_restart, cmd_set_rat = (const char *)SET_RAT_NBNTN_CMD_LEGACY; *rat_request = HL78XX_RAT_NBNTN; } -#endif -#endif +#endif /* CONFIG_MODEM_HL78XX_12_FW_R6 */ +#endif /* CONFIG_MODEM_HL78XX_12 */ if (cmd_set_rat == NULL || *rat_request == HL78XX_RAT_MODE_NONE) { ret = -EINVAL; @@ -104,7 +104,25 @@ int hl78xx_rat_cfg(struct hl78xx_data *data, bool *modem_require_restart, *modem_require_restart = true; } } -#endif +#if defined(CONFIG_MODEM_HL78XX_12) && \ + (defined(CONFIG_MODEM_HL78XX_RAT_GSM) || defined(CONFIG_MODEM_HL78XX_AUTORAT)) + if (*rat_request == HL78XX_RAT_GSM) { + /* For GSM RAT, no band configuration is needed */ + ret = hl78xx_run_lte_dis_gsm_en_reg_status_script(data); + if (ret < 0) { + goto error; + } + } else { +#endif /* CONFIG_MODEM_HL78XX_RAT_GSM */ + /* For LTE RATs, enable LTE registration status and disable GSM */ + ret = hl78xx_run_gsm_dis_lte_en_reg_status_script(data); + if (ret < 0) { + goto error; + } +#ifdef CONFIG_MODEM_HL78XX_RAT_GSM + } +#endif /* CONFIG_MODEM_HL78XX_RAT_GSM */ +#endif /* CONFIG_MODEM_HL78XX_AUTORAT */ error: return ret; @@ -121,12 +139,16 @@ int hl78xx_band_cfg(struct hl78xx_data *data, bool *modem_require_restart, if (rat_config_request == HL78XX_RAT_MODE_NONE) { return -EINVAL; } +#ifdef CONFIG_MODEM_HL78XX_RAT_GSM + if (rat_config_request == HL78XX_RAT_GSM) { + return 0; + } +#endif /* CONFIG_MODEM_HL78XX_RAT_GSM */ #ifdef CONFIG_MODEM_HL78XX_AUTORAT for (int rat = HL78XX_RAT_CAT_M1; rat <= HL78XX_RAT_NB1; rat++) { #else int rat = rat_config_request; - -#endif +#endif /* CONFIG_MODEM_HL78XX_AUTORAT */ ret = hl78xx_get_band_default_config_for_rat(rat, bnd_bitmap, ARRAY_SIZE(bnd_bitmap)); if (ret) { @@ -192,13 +214,41 @@ int hl78xx_set_apn_internal(struct hl78xx_data *data, const char *apn, uint16_t if (ret < 0) { goto error; } +#ifdef CONFIG_MODEM_HL78XX_AIRVANTAGE + ret = modem_dynamic_cmd_send(data, NULL, "AT+WDSS=2,1", strlen("AT+WDSS=2,1"), + hl78xx_get_ok_match(), 1, false); + if (ret < 0) { + goto error; + } +#endif /* CONFIG_MODEM_HL78XX_AIRVANTAGE */ data->status.apn.state = APN_STATE_CONFIGURED; return 0; error: LOG_ERR("Set APN to %s, result: %d", apn, ret); return ret; } +#ifdef CONFIG_MODEM_HL78XX_RAT_GSM +int hl78xx_gsm_pdp_activate(struct hl78xx_data *data) +{ + int ret = 0; + /* Activate the PDP context, Today only one pdp context is supported */ + const char *cmd_activate_pdp = "AT+CGACT=1,1"; + /* Check if the current RAT is GSM and if the PDP context is not already active */ + if (data->status.registration.rat_mode == HL78XX_RAT_CAT_M1 || + data->status.registration.rat_mode == HL78XX_RAT_NB1 || + data->status.gprs[0].is_active) { + return 0; + } + ret = modem_dynamic_cmd_send(data, NULL, cmd_activate_pdp, strlen(cmd_activate_pdp), + hl78xx_get_ok_match(), 1, false); + if (ret < 0) { + LOG_ERR("GSM PDP activation failed: %d", ret); + return ret; + } + return 0; +} +#endif /* CONFIG_MODEM_HL78XX_RAT_GSM */ #if defined(CONFIG_MODEM_HL78XX_APN_SOURCE_ICCID) || defined(CONFIG_MODEM_HL78XX_APN_SOURCE_IMSI) int find_apn(const char *profile, const char *associated_number, char *apn_buff, uint8_t prefix_len) { diff --git a/drivers/modem/hl78xx/hl78xx_cfg.h b/drivers/modem/hl78xx/hl78xx_cfg.h index 5d8be2abe58d5..5387128384325 100644 --- a/drivers/modem/hl78xx/hl78xx_cfg.h +++ b/drivers/modem/hl78xx/hl78xx_cfg.h @@ -22,7 +22,9 @@ int hl78xx_rat_cfg(struct hl78xx_data *data, bool *modem_require_restart, int hl78xx_band_cfg(struct hl78xx_data *data, bool *modem_require_restart, enum hl78xx_cell_rat_mode rat_config_request); - +#ifdef CONFIG_MODEM_HL78XX_RAT_GSM +int hl78xx_gsm_pdp_activate(struct hl78xx_data *data); +#endif int hl78xx_set_apn_internal(struct hl78xx_data *data, const char *apn, uint16_t size); /** diff --git a/drivers/modem/hl78xx/hl78xx_chat.c b/drivers/modem/hl78xx/hl78xx_chat.c index 5b94791aa1d2e..0033ad588ca52 100644 --- a/drivers/modem/hl78xx/hl78xx_chat.c +++ b/drivers/modem/hl78xx/hl78xx_chat.c @@ -36,7 +36,10 @@ void hl78xx_on_cxreg(struct modem_chat *chat, char **argv, uint16_t argc, void * void hl78xx_on_cgdcontrdp(struct modem_chat *chat, char **argv, uint16_t argc, void *user_data); #if defined(CONFIG_MODEM_HL78XX_12) void hl78xx_on_kstatev(struct modem_chat *chat, char **argv, uint16_t argc, void *user_data); -#endif +#ifdef CONFIG_MODEM_HL78XX_RAT_GSM +void hl78xx_on_cgact(struct modem_chat *chat, char **argv, uint16_t argc, void *user_data); +#endif /* CONFIG_MODEM_HL78XX_RAT_GSM */ +#endif /* CONFIG_MODEM_HL78XX_12 */ void hl78xx_on_socknotifydata(struct modem_chat *chat, char **argv, uint16_t argc, void *user_data); void hl78xx_on_ktcpnotif(struct modem_chat *chat, char **argv, uint16_t argc, void *user_data); /* Handler implemented to assign modem-provided udp socket ids */ @@ -65,35 +68,47 @@ void hl78xx_on_iccid(struct modem_chat *chat, char **argv, uint16_t argc, void * void hl78xx_on_ksrep(struct modem_chat *chat, char **argv, uint16_t argc, void *user_data); void hl78xx_on_ksrat(struct modem_chat *chat, char **argv, uint16_t argc, void *user_data); void hl78xx_on_kselacq(struct modem_chat *chat, char **argv, uint16_t argc, void *user_data); - +void hl78xx_on_serial_number(struct modem_chat *chat, char **argv, uint16_t argc, void *user_data); +#ifdef CONFIG_MODEM_HL78XX_AIRVANTAGE +void hl78xx_on_wdsi(struct modem_chat *chat, char **argv, uint16_t argc, void *user_data); +#endif /* CONFIG_MODEM_HL78XX_AIRVANTAGE */ MODEM_CHAT_MATCH_DEFINE(hl78xx_ok_match, "OK", "", NULL); MODEM_CHAT_MATCHES_DEFINE(hl78xx_allow_match, MODEM_CHAT_MATCH("OK", "", NULL), MODEM_CHAT_MATCH(CME_ERROR_STRING, "", NULL)); - -MODEM_CHAT_MATCHES_DEFINE(hl78xx_unsol_matches, MODEM_CHAT_MATCH("+CREG: ", ",", hl78xx_on_cxreg), +/* clang-format off */ +MODEM_CHAT_MATCHES_DEFINE(hl78xx_unsol_matches, + MODEM_CHAT_MATCH("+KSUP: ", "", hl78xx_on_ksup), + MODEM_CHAT_MATCH("+CREG: ", ",", hl78xx_on_cxreg), MODEM_CHAT_MATCH("+CEREG: ", ",", hl78xx_on_cxreg), #if defined(CONFIG_MODEM_HL78XX_12) MODEM_CHAT_MATCH("+KSTATEV: ", ",", hl78xx_on_kstatev), -#endif +#ifdef CONFIG_MODEM_HL78XX_RAT_GSM + MODEM_CHAT_MATCH("+CGACT: ", ",", hl78xx_on_cgact), +#endif /* CONFIG_MODEM_HL78XX_RAT_GSM */ +#endif /* CONFIG_MODEM_HL78XX_12 */ MODEM_CHAT_MATCH("+KUDP_DATA: ", ",", hl78xx_on_socknotifydata), MODEM_CHAT_MATCH("+KTCP_DATA: ", ",", hl78xx_on_socknotifydata), MODEM_CHAT_MATCH("+KTCP_NOTIF: ", ",", hl78xx_on_ktcpnotif), #ifdef CONFIG_MODEM_HL78XX_LOG_CONTEXT_VERBOSE_DEBUG MODEM_CHAT_MATCH("+KUDP_RCV: ", ",", hl78xx_on_udprcv), #endif +#ifdef CONFIG_MODEM_HL78XX_AIRVANTAGE + MODEM_CHAT_MATCH("+WDSI: ", ",", hl78xx_on_wdsi), +#endif /* CONFIG_MODEM_HL78XX_AIRVANTAGE */ MODEM_CHAT_MATCH("+KBNDCFG: ", ",", hl78xx_on_kbndcfg), MODEM_CHAT_MATCH("+CSQ: ", ",", hl78xx_on_csq), MODEM_CHAT_MATCH("+CESQ: ", ",", hl78xx_on_cesq), MODEM_CHAT_MATCH("+CFUN: ", "", hl78xx_on_cfun), MODEM_CHAT_MATCH("+COPS: ", ",", hl78xx_on_cops)); - -MODEM_CHAT_MATCHES_DEFINE(hl78xx_abort_matches, MODEM_CHAT_MATCH("+CME ERROR: ", "", NULL)); +/* clang-format on */ +MODEM_CHAT_MATCHES_DEFINE(hl78xx_abort_matches, MODEM_CHAT_MATCH(CME_ERROR_STRING, "", NULL)); MODEM_CHAT_MATCH_DEFINE(hl78xx_at_ready_match, "+KSUP: ", "", hl78xx_on_ksup); MODEM_CHAT_MATCH_DEFINE(hl78xx_imei_match, "", "", hl78xx_on_imei); MODEM_CHAT_MATCH_DEFINE(hl78xx_cgmm_match, "", "", hl78xx_on_cgmm); MODEM_CHAT_MATCH_DEFINE(hl78xx_cimi_match, "", "", hl78xx_on_imsi); MODEM_CHAT_MATCH_DEFINE(hl78xx_cgmi_match, "", "", hl78xx_on_cgmi); MODEM_CHAT_MATCH_DEFINE(hl78xx_cgmr_match, "", "", hl78xx_on_cgmr); +MODEM_CHAT_MATCH_DEFINE(hl78xx_serial_number_match, "+KGSN: ", "", hl78xx_on_serial_number); MODEM_CHAT_MATCH_DEFINE(hl78xx_iccid_match, "+CCID: ", "", hl78xx_on_iccid); MODEM_CHAT_MATCH_DEFINE(hl78xx_ksrep_match, "+KSREP: ", ",", hl78xx_on_ksrep); MODEM_CHAT_MATCH_DEFINE(hl78xx_ksrat_match, "+KSRAT: ", "", hl78xx_on_ksrat); @@ -107,7 +122,6 @@ MODEM_CHAT_SCRIPT_DEFINE(hl78xx_periodic_chat_script, hl78xx_periodic_chat_scrip hl78xx_abort_matches, hl78xx_chat_callback_handler, 4); MODEM_CHAT_SCRIPT_CMDS_DEFINE(hl78xx_init_chat_script_cmds, - MODEM_CHAT_SCRIPT_CMD_RESP("", hl78xx_at_ready_match), MODEM_CHAT_SCRIPT_CMD_RESP("AT+KHWIOCFG=3,1,6", hl78xx_ok_match), MODEM_CHAT_SCRIPT_CMD_RESP("ATE0", hl78xx_ok_match), MODEM_CHAT_SCRIPT_CMD_RESP("AT+CFUN=4,0", hl78xx_ok_match), @@ -116,6 +130,8 @@ MODEM_CHAT_SCRIPT_CMDS_DEFINE(hl78xx_init_chat_script_cmds, MODEM_CHAT_SCRIPT_CMD_RESP("AT+CEDRXS=0", hl78xx_ok_match), MODEM_CHAT_SCRIPT_CMD_RESP("AT+KPATTERN=\"--EOF--Pattern--\"", hl78xx_ok_match), + MODEM_CHAT_SCRIPT_CMD_RESP("AT+KGSN=3", hl78xx_serial_number_match), + MODEM_CHAT_SCRIPT_CMD_RESP("", hl78xx_ok_match), MODEM_CHAT_SCRIPT_CMD_RESP("AT+CCID", hl78xx_iccid_match), MODEM_CHAT_SCRIPT_CMD_RESP("", hl78xx_ok_match), MODEM_CHAT_SCRIPT_CMD_RESP("AT+CMEE=1", hl78xx_ok_match), @@ -136,12 +152,28 @@ MODEM_CHAT_SCRIPT_CMDS_DEFINE(hl78xx_init_chat_script_cmds, MODEM_CHAT_SCRIPT_CMD_RESP("AT+KSELACQ?", hl78xx_kselacq_match), MODEM_CHAT_SCRIPT_CMD_RESP("AT+KSRAT?", hl78xx_ksrat_match), MODEM_CHAT_SCRIPT_CMD_RESP("AT+KBNDCFG?", hl78xx_ok_match), - MODEM_CHAT_SCRIPT_CMD_RESP("AT+CGACT?", hl78xx_ok_match), - MODEM_CHAT_SCRIPT_CMD_RESP("AT+CREG=0", hl78xx_ok_match), - MODEM_CHAT_SCRIPT_CMD_RESP("AT+CEREG=5", hl78xx_ok_match)); +#ifdef CONFIG_MODEM_HL78XX_AIRVANTAGE +#ifdef CONFIG_MODEM_HL78XX_12 + MODEM_CHAT_SCRIPT_CMD_RESP("AT+WDSI=8191", hl78xx_ok_match), +#elif defined(CONFIG_MODEM_HL78XX_00) + MODEM_CHAT_SCRIPT_CMD_RESP("AT+WDSI=4479", hl78xx_ok_match), +#else + MODEM_CHAT_SCRIPT_CMD_RESP("AT+WDSI=?", hl78xx_ok_match), +#endif /* CONFIG_MODEM_HL78XX_12 */ +#ifdef CONFIG_MODEM_HL78XX_AIRVANTAGE_UA_CONNECT_AIRVANTAGE + MODEM_CHAT_SCRIPT_CMD_RESP("AT+WDSC=0,1", hl78xx_ok_match), +#endif /* CONFIG_MODEM_HL78XX_AIRVANTAGE_UA_CONNECT_AIRVANTAGE */ +#ifdef CONFIG_MODEM_HL78XX_AIRVANTAGE_UA_DOWNLOAD_FIRMWARE + MODEM_CHAT_SCRIPT_CMD_RESP("AT+WDSC=1,1", hl78xx_ok_match), +#endif /* CONFIG_MODEM_HL78XX_AIRVANTAGE_UA_DOWNLOAD_FIRMWARE */ +#ifdef CONFIG_MODEM_HL78XX_AIRVANTAGE_UA_INSTALL_FIRMWARE + MODEM_CHAT_SCRIPT_CMD_RESP("AT+WDSC=2,1", hl78xx_ok_match), +#endif /* CONFIG_MODEM_HL78XX_AIRVANTAGE_UA_INSTALL_FIRMWARE */ +#endif /* CONFIG_MODEM_HL78XX_AIRVANTAGE */ + MODEM_CHAT_SCRIPT_CMD_RESP("AT+CGACT?", hl78xx_ok_match)); MODEM_CHAT_SCRIPT_DEFINE(hl78xx_init_chat_script, hl78xx_init_chat_script_cmds, - hl78xx_abort_matches, hl78xx_chat_callback_handler, 10); + hl78xx_abort_matches, hl78xx_chat_callback_handler, 1000); /* Post-restart script (moved from hl78xx.c) */ MODEM_CHAT_SCRIPT_CMDS_DEFINE(hl78xx_post_restart_chat_script_cmds, @@ -177,6 +209,42 @@ MODEM_CHAT_SCRIPT_CMDS_DEFINE(hl78xx_pwroff_cmds, MODEM_CHAT_SCRIPT_DEFINE(hl78xx_pwroff_script, hl78xx_pwroff_cmds, hl78xx_abort_matches, hl78xx_chat_callback_handler, 4); +/* GSM registration status disable / LTE registration status enable script */ +MODEM_CHAT_SCRIPT_CMDS_DEFINE(hl78xx_gsm_dis_lte_en_reg_status_script_cmds, + MODEM_CHAT_SCRIPT_CMD_RESP("AT+CREG=0", hl78xx_ok_match), + MODEM_CHAT_SCRIPT_CMD_RESP("AT+CEREG=5", hl78xx_ok_match)); + +MODEM_CHAT_SCRIPT_DEFINE(hl78xx_gsm_dis_lte_en_reg_status_script, + hl78xx_gsm_dis_lte_en_reg_status_script_cmds, hl78xx_abort_matches, NULL, + 4); + +#if defined(CONFIG_MODEM_HL78XX_12) && \ + (defined(CONFIG_MODEM_HL78XX_RAT_GSM) || defined(CONFIG_MODEM_HL78XX_AUTORAT)) +/* LTE registration status disable / GSM registration status enable script */ +MODEM_CHAT_SCRIPT_CMDS_DEFINE(hl78xx_lte_dis_gsm_en_reg_status_script_cmds, + MODEM_CHAT_SCRIPT_CMD_RESP("AT+CEREG=0", hl78xx_ok_match), + MODEM_CHAT_SCRIPT_CMD_RESP("AT+CREG=3", hl78xx_ok_match)); +MODEM_CHAT_SCRIPT_DEFINE(hl78xx_lte_dis_gsm_en_reg_status_script, + hl78xx_lte_dis_gsm_en_reg_status_script_cmds, hl78xx_abort_matches, NULL, + 4); +#endif /* CONFIG_MODEM_HL78XX_12 */ +#ifdef CONFIG_MODEM_HL78XX_AIRVANTAGE +/* AirVantage script connect accept */ +MODEM_CHAT_SCRIPT_CMDS_DEFINE(hl78xx_av_connect_accept_cmds, + MODEM_CHAT_SCRIPT_CMD_RESP("AT+WDSR=1", hl78xx_ok_match)); +MODEM_CHAT_SCRIPT_DEFINE(hl78xx_av_connect_accept_script, hl78xx_av_connect_accept_cmds, + hl78xx_abort_matches, hl78xx_chat_callback_handler, 10); +/* FOTA script download accept */ +MODEM_CHAT_SCRIPT_CMDS_DEFINE(hl78xx_fota_download_accept_cmds, + MODEM_CHAT_SCRIPT_CMD_RESP("AT+WDSR=3", hl78xx_ok_match)); +MODEM_CHAT_SCRIPT_DEFINE(hl78xx_fota_download_accept_script, hl78xx_fota_download_accept_cmds, + hl78xx_abort_matches, hl78xx_chat_callback_handler, 10); +/* FOTA script install */ +MODEM_CHAT_SCRIPT_CMDS_DEFINE(hl78xx_fota_install_accept_cmds, + MODEM_CHAT_SCRIPT_CMD_RESP("AT+WDSR=4", hl78xx_ok_match)); +MODEM_CHAT_SCRIPT_DEFINE(hl78xx_fota_install_accept_script, hl78xx_fota_install_accept_cmds, + hl78xx_abort_matches, hl78xx_chat_callback_handler, 10); +#endif /* CONFIG_MODEM_HL78XX_AIRVANTAGE */ /* Socket-specific matches and wrappers exposed for the sockets translation * unit. These were extracted from hl78xx_sockets.c to centralize chat * definitions. @@ -374,3 +442,48 @@ int hl78xx_run_pwroff_script_async(struct hl78xx_data *data) } return modem_chat_run_script_async(&data->chat, &hl78xx_pwroff_script); } +#if defined(CONFIG_MODEM_HL78XX_12) && \ + (defined(CONFIG_MODEM_HL78XX_RAT_GSM) || defined(CONFIG_MODEM_HL78XX_AUTORAT)) +/* Run the LTE disable GSM enable registration status script */ +int hl78xx_run_lte_dis_gsm_en_reg_status_script(struct hl78xx_data *data) +{ + if (!data) { + return -EINVAL; + } + return modem_chat_run_script(&data->chat, &hl78xx_lte_dis_gsm_en_reg_status_script); +} +#endif /* CONFIG_MODEM_HL78XX_RAT_GSM */ +/* Run the GSM disable LTE enable registration status script */ +int hl78xx_run_gsm_dis_lte_en_reg_status_script(struct hl78xx_data *data) +{ + if (!data) { + return -EINVAL; + } + return modem_chat_run_script(&data->chat, &hl78xx_gsm_dis_lte_en_reg_status_script); +} +#ifdef CONFIG_MODEM_HL78XX_AIRVANTAGE +/* AirVantage script connect accept */ +int hl78xx_run_av_connect_accept_script_async(struct hl78xx_data *data) +{ + if (!data) { + return -EINVAL; + } + return modem_chat_run_script_async(&data->chat, &hl78xx_av_connect_accept_script); +} +/* FOTA script download accept */ +int hl78xx_run_fota_script_download_accept_async(struct hl78xx_data *data) +{ + if (!data) { + return -EINVAL; + } + return modem_chat_run_script_async(&data->chat, &hl78xx_fota_download_accept_script); +} +/* FOTA script install accept */ +int hl78xx_run_fota_script_install_accept_async(struct hl78xx_data *data) +{ + if (!data) { + return -EINVAL; + } + return modem_chat_run_script_async(&data->chat, &hl78xx_fota_install_accept_script); +} +#endif /* CONFIG_MODEM_HL78XX_AIRVANTAGE */ diff --git a/drivers/modem/hl78xx/hl78xx_chat.h b/drivers/modem/hl78xx/hl78xx_chat.h index eb3a1dec8365b..70cda45888577 100644 --- a/drivers/modem/hl78xx/hl78xx_chat.h +++ b/drivers/modem/hl78xx/hl78xx_chat.h @@ -31,6 +31,7 @@ void hl78xx_chat_callback_handler(struct modem_chat *chat, enum modem_chat_scrip /* Wrapper helpers so other translation units don't need compile-time * visibility of the MODEM_CHAT_* macro-generated symbols. */ +const struct modem_chat_match *hl78xx_get_at_ready_match(void); const struct modem_chat_match *hl78xx_get_ok_match(void); const struct modem_chat_match *hl78xx_get_abort_matches(void); const struct modem_chat_match *hl78xx_get_unsol_matches(void); @@ -47,13 +48,25 @@ int hl78xx_run_init_fail_script_async(struct hl78xx_data *data); int hl78xx_run_enable_ksup_urc_script_async(struct hl78xx_data *data); int hl78xx_run_pwroff_script_async(struct hl78xx_data *data); int hl78xx_run_post_restart_script_async(struct hl78xx_data *data); +#if defined(CONFIG_MODEM_HL78XX_12) && defined(CONFIG_MODEM_HL78XX_RAT_GSM) || \ + defined(CONFIG_MODEM_HL78XX_AUTORAT) +/* Run the LTE disable GSM enable registration status script */ +int hl78xx_run_lte_dis_gsm_en_reg_status_script(struct hl78xx_data *data); +#endif /* CONFIG_MODEM_HL78XX_RAT_GSM */ +/* Run the GSM disable LTE enable registration status script */ +int hl78xx_run_gsm_dis_lte_en_reg_status_script(struct hl78xx_data *data); +#ifdef CONFIG_MODEM_HL78XX_AIRVANTAGE +/* FOTA-related script runners */ +int hl78xx_run_av_connect_accept_script_async(struct hl78xx_data *data); +int hl78xx_run_fota_script_download_accept_async(struct hl78xx_data *data); +int hl78xx_run_fota_script_install_accept_async(struct hl78xx_data *data); +#endif /* CONFIG_MODEM_HL78XX_AIRVANTAGE */ /* Async runners for init/periodic scripts */ int hl78xx_run_init_script_async(struct hl78xx_data *data); int hl78xx_run_periodic_script_async(struct hl78xx_data *data); /* Getter for ksrat match (moved into chat TU) */ const struct modem_chat_match *hl78xx_get_ksrat_match(void); - /* Socket-related chat matches used by the sockets TU */ const struct modem_chat_match *hl78xx_get_sockets_ok_match(void); const struct modem_chat_match *hl78xx_get_connect_matches(void); diff --git a/include/zephyr/drivers/modem/hl78xx_apis.h b/include/zephyr/drivers/modem/hl78xx_apis.h index bffd35d0e0c7c..525a26a30d352 100644 --- a/include/zephyr/drivers/modem/hl78xx_apis.h +++ b/include/zephyr/drivers/modem/hl78xx_apis.h @@ -18,26 +18,27 @@ extern "C" { #endif /* Magic constants */ -#define CSQ_RSSI_UNKNOWN (99) -#define CESQ_RSRP_UNKNOWN (255) -#define CESQ_RSRQ_UNKNOWN (255) +#define CSQ_RSSI_UNKNOWN (99) +#define CESQ_RSRP_UNKNOWN (255) +#define CESQ_RSRQ_UNKNOWN (255) /* Magic numbers to units conversions */ -#define CSQ_RSSI_TO_DB(v) (-113 + (2 * (v))) -#define CESQ_RSRP_TO_DB(v) (-140 + (v)) -#define CESQ_RSRQ_TO_DB(v) (-20 + ((v) / 2)) +#define CSQ_RSSI_TO_DB(v) (-113 + (2 * (v))) +#define CESQ_RSRP_TO_DB(v) (-140 + (v)) +#define CESQ_RSRQ_TO_DB(v) (-20 + ((v) / 2)) /** Monitor is paused. */ -#define PAUSED 1 +#define PAUSED 1 /** Monitor is active, default */ -#define ACTIVE 0 -#define MDM_MANUFACTURER_LENGTH 20 -#define MDM_MODEL_LENGTH 32 -#define MDM_REVISION_LENGTH 64 -#define MDM_IMEI_LENGTH 16 -#define MDM_IMSI_LENGTH 23 -#define MDM_ICCID_LENGTH 22 -#define MDM_APN_MAX_LENGTH 64 -#define MDM_MAX_CERT_LENGTH 4096 -#define MDM_MAX_HOSTNAME_LEN 128 +#define ACTIVE 0 +#define MDM_MANUFACTURER_LENGTH 20 +#define MDM_MODEL_LENGTH 32 +#define MDM_REVISION_LENGTH 64 +#define MDM_IMEI_LENGTH 16 +#define MDM_SERIAL_NUMBER_LENGTH 32 +#define MDM_IMSI_LENGTH 23 +#define MDM_ICCID_LENGTH 22 +#define MDM_APN_MAX_LENGTH 64 +#define MDM_MAX_CERT_LENGTH 4096 +#define MDM_MAX_HOSTNAME_LEN 128 /** * @brief Define an Event monitor to receive notifications in the system workqueue thread. * @@ -78,15 +79,21 @@ enum hl78xx_phone_functionality { }; /** Module status codes */ enum hl78xx_module_status { + /** Module is ready to receive commands for the TE. No access code is required. */ HL78XX_MODULE_READY = 0, + /** Module is waiting for an access code. Use AT+CPIN? to determine it. */ HL78XX_MODULE_WAITING_FOR_ACCESS_CODE, + /** SIM card is not present. */ HL78XX_MODULE_SIM_NOT_PRESENT, + /** Module is in “SIMlock” state. */ HL78XX_MODULE_SIMLOCK, + /** Unrecoverable error. */ HL78XX_MODULE_UNRECOVERABLE_ERROR, + /** Unknown state. */ HL78XX_MODULE_UNKNOWN_STATE, + /** Inactive SIM. */ HL78XX_MODULE_INACTIVE_SIM }; - /** Cellular modem info type */ enum hl78xx_modem_info_type { /* Access Point Name */ @@ -95,8 +102,9 @@ enum hl78xx_modem_info_type { HL78XX_MODEM_INFO_CURRENT_RAT, /* */ HL78XX_MODEM_INFO_NETWORK_OPERATOR, + /* */ + HL78XX_MODEM_INFO_SERIAL_NUMBER, }; - /** Cellular network structure */ struct hl78xx_network { /** Cellular access technology */ @@ -115,7 +123,54 @@ enum hl78xx_evt_type { HL78XX_LTE_REGISTRATION_STAT_UPDATE, HL78XX_LTE_SIM_REGISTRATION, HL78XX_LTE_MODEM_STARTUP, + HL78XX_LTE_FOTA_UPDATE_STATUS, +}; +#ifdef CONFIG_MODEM_HL78XX_AIRVANTAGE +/** + * Enum representing Device Services Indications (+WDSI) + */ +enum wdsi_indication { + /** Raised at startup if credentials for Bootstrap Server are present */ + WDSI_BOOTSTRAP_CREDENTIALS_PRESENT = 0, + /** Device requests user agreement to connect to AirVantage */ + WDSI_USER_AGREEMENT_REQUEST = 1, + /** AirVantage requests device to download firmware package */ + WDSI_FIRMWARE_DOWNLOAD_REQUEST = 2, + /** AirVantage requests device to install firmware package */ + WDSI_FIRMWARE_INSTALL_REQUEST = 3, + /** Starting authentication with Bootstrap or DM Server */ + WDSI_AUTHENTICATION_START = 4, + /** Authentication failed */ + WDSI_AUTHENTICATION_FAILED = 5, + /** Authentication succeeded, starting session */ + WDSI_AUTHENTICATION_SUCCESS = 6, + /** Connection denied by server */ + WDSI_CONNECTION_DENIED = 7, + /** DM session closed */ + WDSI_DM_SESSION_CLOSED = 8, + /** Firmware package available for download */ + WDSI_FIRMWARE_AVAILABLE = 9, + /** Firmware package downloaded and stored */ + WDSI_FIRMWARE_DOWNLOADED = 10, + /** Firmware download issue, reason indicated by subcode */ + WDSI_FIRMWARE_DOWNLOAD_ISSUE = 11, + /** Package verified and certified */ + WDSI_PACKAGE_VERIFIED_CERTIFIED = 12, + /** Package verified but not certified */ + WDSI_PACKAGE_VERIFIED_NOT_CERTIFIED = 13, + /** Starting firmware update */ + WDSI_FIRMWARE_UPDATE_START = 14, + /** Firmware update failed */ + WDSI_FIRMWARE_UPDATE_FAILED = 15, + /** Firmware updated successfully */ + WDSI_FIRMWARE_UPDATE_SUCCESS = 16, + /** Download in progress, percentage indicated */ + WDSI_DOWNLOAD_IN_PROGRESS = 18, + /** Session started with Bootstrap server +WDSI: 23,0*/ + /** Session started with DM server +WDSI: 23,1*/ + WDSI_SESSION_STARTED = 23 }; +#endif /* CONFIG_MODEM_HL78XX_AIRVANTAGE */ struct hl78xx_evt { enum hl78xx_evt_type type; @@ -123,6 +178,9 @@ struct hl78xx_evt { union { enum cellular_registration_status reg_status; enum hl78xx_cell_rat_mode rat_mode; +#ifdef CONFIG_MODEM_HL78XX_AIRVANTAGE + enum wdsi_indication wdsi_indication; +#endif /* CONFIG_MODEM_HL78XX_AIRVANTAGE */ bool status; int value; } content; @@ -450,7 +508,12 @@ int hl78xx_evt_monitor_unregister(struct hl78xx_evt_monitor_entry *mon); * @brief Convert HL78xx RAT mode to standard cellular API. */ enum cellular_access_technology hl78xx_rat_to_access_tech(enum hl78xx_cell_rat_mode rat_mode); - +#ifdef CONFIG_MODEM_HL78XX_AIRVANTAGE +/** Start a AirVantage Device Management (DM) session. */ +int hl78xx_start_airvantage_dm_session(const struct device *dev); +/** Stop a AirVantage Device Management (DM) session. */ +int hl78xx_stop_airvantage_dm_session(const struct device *dev); +#endif /* CONFIG_MODEM_HL78XX_AIRVANTAGE */ #ifdef __cplusplus } #endif diff --git a/samples/drivers/modem/hello_hl78xx/boards/mg100.conf b/samples/drivers/modem/hello_hl78xx/boards/mg100.conf index 8faf74132ae1b..1f89aa111650d 100644 --- a/samples/drivers/modem/hello_hl78xx/boards/mg100.conf +++ b/samples/drivers/modem/hello_hl78xx/boards/mg100.conf @@ -1 +1,2 @@ CONFIG_MODEM_HL7800=n +CONFIG_MODEM_HL78XX_AUTORAT=n diff --git a/samples/drivers/modem/hello_hl78xx/boards/nrf9160dk_nrf9160_ns.conf b/samples/drivers/modem/hello_hl78xx/boards/nrf9160dk_nrf9160_ns.conf index d39bd9151a541..520c07714b047 100644 --- a/samples/drivers/modem/hello_hl78xx/boards/nrf9160dk_nrf9160_ns.conf +++ b/samples/drivers/modem/hello_hl78xx/boards/nrf9160dk_nrf9160_ns.conf @@ -8,7 +8,8 @@ CONFIG_UART_1_NRF_HW_ASYNC_TIMER=1 CONFIG_ENTROPY_GENERATOR=y CONFIG_TEST_RANDOM_GENERATOR=y -CONFIG_MODEM_HL78XX_DEV_STARTUP_TIME=1000 +CONFIG_MODEM_HL78XX_DEV_STARTUP_TIME_MS=120 +CONFIG_MODEM_HL78XX_DEV_SHUTDOWN_TIME_MS=120 # Disable AT shell as SLM application has no AT mode user pipes CONFIG_MODEM_AT_SHELL=n # Increase log buffer size to accommodate large dumps diff --git a/samples/drivers/modem/hello_hl78xx/boards/pinnacle_100_dvk.conf b/samples/drivers/modem/hello_hl78xx/boards/pinnacle_100_dvk.conf index 8faf74132ae1b..1f89aa111650d 100644 --- a/samples/drivers/modem/hello_hl78xx/boards/pinnacle_100_dvk.conf +++ b/samples/drivers/modem/hello_hl78xx/boards/pinnacle_100_dvk.conf @@ -1 +1,2 @@ CONFIG_MODEM_HL7800=n +CONFIG_MODEM_HL78XX_AUTORAT=n diff --git a/samples/drivers/modem/hello_hl78xx/prj.conf b/samples/drivers/modem/hello_hl78xx/prj.conf index dc69dcd52f02b..f1a0e63ad7e52 100644 --- a/samples/drivers/modem/hello_hl78xx/prj.conf +++ b/samples/drivers/modem/hello_hl78xx/prj.conf @@ -53,7 +53,11 @@ CONFIG_MODEM_HL78XX=y # Statistics CONFIG_MODEM_STATS=y + +# shell CONFIG_SHELL=y +CONFIG_MODEM_HL78XX_AT_SHELL=y +CONFIG_MODEM_AT_SHELL_COMMAND_MAX_SIZE=256 #apn source # CONFIG_MODEM_HL78XX_APN_SOURCE_KCONFIG=y @@ -66,10 +70,17 @@ CONFIG_MODEM_HL78XX_AUTORAT=n # CONFIG_MODEM_HL78XX_AUTORAT_PRL_PROFILES="2,1,3" # CONFIG_MODEM_HL78XX_AUTORAT_NB_BAND_CFG="3,8,20,28" # CONFIG_MODEM_HL78XX_RAT_NB1=y +# CONFIG_MODEM_HL78XX_RAT_GSM=y # Stay in boot mode until registered to a network # CONFIG_MODEM_HL78XX_STAY_IN_BOOT_MODE_FOR_ROAMING=y +# Enable AirVantage support +CONFIG_MODEM_HL78XX_AIRVANTAGE=y +CONFIG_MODEM_HL78XX_AIRVANTAGE_USER_AGREEMENT=y +CONFIG_MODEM_HL78XX_AIRVANTAGE_UA_CONNECT_AIRVANTAGE=y +CONFIG_MODEM_HL78XX_AIRVANTAGE_UA_DOWNLOAD_FIRMWARE=y +CONFIG_MODEM_HL78XX_AIRVANTAGE_UA_INSTALL_FIRMWARE=y # Monitor modem events CONFIG_HL78XX_EVT_MONITOR=y # Logging