From 7d90755726b74ef039e803511518ff9475985982 Mon Sep 17 00:00:00 2001 From: Lukas Gehreke Date: Wed, 19 Mar 2025 14:34:38 +0100 Subject: [PATCH 01/28] drivers: sim7080: Own simcom modem driver directory Placed sim7080 driver in separate directory and split it in multiple source files for better readability. Signed-off-by: Lukas Gehreke --- drivers/modem/CMakeLists.txt | 4 +- drivers/modem/Kconfig | 2 +- drivers/modem/simcom/CMakeLists.txt | 6 + drivers/modem/simcom/Kconfig | 6 + drivers/modem/simcom/sim7080/CMakeLists.txt | 15 + .../sim7080/Kconfig} | 0 drivers/modem/simcom/sim7080/sim7080.c | 912 ++++++++++++++++++ .../sim7080/sim7080.h} | 14 + drivers/modem/simcom/sim7080/sim7080_dns.c | 144 +++ drivers/modem/simcom/sim7080/sim7080_ftp.c | 225 +++++ drivers/modem/simcom/sim7080/sim7080_gps.c | 289 ++++++ drivers/modem/simcom/sim7080/sim7080_sms.c | 390 ++++++++ drivers/modem/simcom/sim7080/sim7080_sock.c | 539 +++++++++++ 13 files changed, 2542 insertions(+), 4 deletions(-) create mode 100644 drivers/modem/simcom/CMakeLists.txt create mode 100644 drivers/modem/simcom/Kconfig create mode 100644 drivers/modem/simcom/sim7080/CMakeLists.txt rename drivers/modem/{Kconfig.simcom-sim7080 => simcom/sim7080/Kconfig} (100%) create mode 100644 drivers/modem/simcom/sim7080/sim7080.c rename drivers/modem/{simcom-sim7080.h => simcom/sim7080/sim7080.h} (92%) create mode 100644 drivers/modem/simcom/sim7080/sim7080_dns.c create mode 100644 drivers/modem/simcom/sim7080/sim7080_ftp.c create mode 100644 drivers/modem/simcom/sim7080/sim7080_gps.c create mode 100644 drivers/modem/simcom/sim7080/sim7080_sms.c create mode 100644 drivers/modem/simcom/sim7080/sim7080_sock.c diff --git a/drivers/modem/CMakeLists.txt b/drivers/modem/CMakeLists.txt index adc6614dc7fe5..5553cb2e5467d 100644 --- a/drivers/modem/CMakeLists.txt +++ b/drivers/modem/CMakeLists.txt @@ -31,9 +31,7 @@ if (CONFIG_MODEM_HL7800) zephyr_library_sources(hl7800.c) endif() -if (CONFIG_MODEM_SIM7080) - zephyr_library_sources(simcom-sim7080.c) -endif() +add_subdirectory(simcom) zephyr_library_sources_ifdef(CONFIG_MODEM_CELLULAR modem_cellular.c) zephyr_library_sources_ifdef(CONFIG_MODEM_AT_USER_PIPE modem_at_user_pipe.c) diff --git a/drivers/modem/Kconfig b/drivers/modem/Kconfig index b8e66ef427482..a0c40edd879df 100644 --- a/drivers/modem/Kconfig +++ b/drivers/modem/Kconfig @@ -194,6 +194,6 @@ source "drivers/modem/Kconfig.cellular" source "drivers/modem/Kconfig.at_shell" source "drivers/modem/Kconfig.hl7800" -source "drivers/modem/Kconfig.simcom-sim7080" +source "drivers/modem/simcom/Kconfig" endif # MODEM diff --git a/drivers/modem/simcom/CMakeLists.txt b/drivers/modem/simcom/CMakeLists.txt new file mode 100644 index 0000000000000..49028eb9036d6 --- /dev/null +++ b/drivers/modem/simcom/CMakeLists.txt @@ -0,0 +1,6 @@ +# Copyright (c) 2025 Metratec GmbH. +# SPDX-License-Identifier: Apache-2.0 + +# zephyr-keep-sorted-start +add_subdirectory_ifdef(CONFIG_MODEM_SIM7080 sim7080) +# zephyr-keep-sorted-stop diff --git a/drivers/modem/simcom/Kconfig b/drivers/modem/simcom/Kconfig new file mode 100644 index 0000000000000..c8f37c1a55207 --- /dev/null +++ b/drivers/modem/simcom/Kconfig @@ -0,0 +1,6 @@ +# Copyright (c) 2025 Metratec GmbH. +# SPDX-License-Identifier: Apache-2.0 + +# zephyr-keep-sorted-start +source "drivers/modem/simcom/sim7080/Kconfig" +# zephyr-keep-sorted-stop diff --git a/drivers/modem/simcom/sim7080/CMakeLists.txt b/drivers/modem/simcom/sim7080/CMakeLists.txt new file mode 100644 index 0000000000000..1fbdf49046946 --- /dev/null +++ b/drivers/modem/simcom/sim7080/CMakeLists.txt @@ -0,0 +1,15 @@ +# Copyright (c) 2025 Metratec GmbH. +# SPDX-License-Identifier: Apache-2.0 + +zephyr_library() + +zephyr_library_include_directories(${ZEPHYR_BASE}/drivers/modem) +zephyr_library_include_directories(${ZEPHYR_BASE}/subsys/net/ip) +zephyr_library_include_directories(${ZEPHYR_BASE}/subsys/net/lib/sockets) +zephyr_library_sources( + sim7080.c + sim7080_dns.c + sim7080_sock.c + sim7080_sms.c + sim7080_ftp.c + sim7080_gps.c) diff --git a/drivers/modem/Kconfig.simcom-sim7080 b/drivers/modem/simcom/sim7080/Kconfig similarity index 100% rename from drivers/modem/Kconfig.simcom-sim7080 rename to drivers/modem/simcom/sim7080/Kconfig diff --git a/drivers/modem/simcom/sim7080/sim7080.c b/drivers/modem/simcom/sim7080/sim7080.c new file mode 100644 index 0000000000000..bdcee36a12f4f --- /dev/null +++ b/drivers/modem/simcom/sim7080/sim7080.c @@ -0,0 +1,912 @@ +/* + * Copyright (C) 2021 metraTec GmbH + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT simcom_sim7080 + +#include +#include +LOG_MODULE_REGISTER(modem_simcom_sim7080, CONFIG_MODEM_LOG_LEVEL); + +#include +#include "sim7080.h" + +struct sim7080_data mdata; +struct modem_context mctx; + +static struct k_thread modem_rx_thread; +static struct k_work_q modem_workq; + +static K_KERNEL_STACK_DEFINE(modem_rx_stack, CONFIG_MODEM_SIMCOM_SIM7080_RX_STACK_SIZE); +static K_KERNEL_STACK_DEFINE(modem_workq_stack, CONFIG_MODEM_SIMCOM_SIM7080_RX_WORKQ_STACK_SIZE); +NET_BUF_POOL_DEFINE(mdm_recv_pool, MDM_RECV_MAX_BUF, MDM_RECV_BUF_SIZE, 0, NULL); + +/* pin settings */ +static const struct gpio_dt_spec power_gpio = GPIO_DT_SPEC_INST_GET(0, mdm_power_gpios); + +struct modem_context *sim7080_get_mctx(void) +{ + return &mctx; +} + +static inline uint32_t hash32(char *str, int len) +{ +#define HASH_MULTIPLIER 37 + uint32_t h = 0; + int i; + + for (i = 0; i < len; ++i) { + h = (h * HASH_MULTIPLIER) + str[i]; + } + + return h; +} + +static inline uint8_t *modem_get_mac(const struct device *dev) +{ + struct sim7080_data *data = dev->data; + uint32_t hash_value; + + data->mac_addr[0] = 0x00; + data->mac_addr[1] = 0x10; + + /* use IMEI for mac_addr */ + hash_value = hash32(mdata.mdm_imei, strlen(mdata.mdm_imei)); + + UNALIGNED_PUT(hash_value, (uint32_t *)(data->mac_addr + 2)); + + return data->mac_addr; +} + +static int offload_socket(int family, int type, int proto); + +/* Setup the Modem NET Interface. */ +static void modem_net_iface_init(struct net_if *iface) +{ + const struct device *dev = net_if_get_device(iface); + struct sim7080_data *data = dev->data; + + net_if_set_link_addr(iface, modem_get_mac(dev), sizeof(data->mac_addr), NET_LINK_ETHERNET); + + data->netif = iface; + + socket_offload_dns_register(&offload_dns_ops); + + net_if_socket_offload_set(iface, offload_socket); +} + +/** + * Changes the operating state of the sim7080. + * + * @param state The new state. + */ +void sim7080_change_state(enum sim7080_state state) +{ + LOG_DBG("Changing state to (%d)", state); + mdata.state = state; +} + +/** + * Get the current operating state of the sim7080. + * + * @return The current state. + */ +enum sim7080_state sim7080_get_state(void) +{ + return mdata.state; +} + +static struct offloaded_if_api api_funcs = { + .iface_api.init = modem_net_iface_init, +}; + +static bool offload_is_supported(int family, int type, int proto) +{ + if (family != AF_INET && + family != AF_INET6) { + return false; + } + + if (type != SOCK_DGRAM && + type != SOCK_STREAM) { + return false; + } + + if (proto != IPPROTO_TCP && + proto != IPPROTO_UDP) { + return false; + } + + return true; +} + +static int offload_socket(int family, int type, int proto) +{ + int ret; + + ret = modem_socket_get(&mdata.socket_config, family, type, proto); + if (ret < 0) { + errno = -ret; + return -1; + } + + errno = 0; + return ret; +} + +/* + * Process all messages received from the modem. + */ +static void modem_rx(void *p1, void *p2, void *p3) +{ + ARG_UNUSED(p1); + ARG_UNUSED(p2); + ARG_UNUSED(p3); + + while (true) { + /* Wait for incoming data */ + modem_iface_uart_rx_wait(&mctx.iface, K_FOREVER); + + modem_cmd_handler_process(&mctx.cmd_handler, &mctx.iface); + } +} + +MODEM_CMD_DEFINE(on_cmd_ok) +{ + modem_cmd_handler_set_error(data, 0); + k_sem_give(&mdata.sem_response); + return 0; +} + +MODEM_CMD_DEFINE(on_cmd_error) +{ + modem_cmd_handler_set_error(data, -EIO); + k_sem_give(&mdata.sem_response); + return 0; +} + +MODEM_CMD_DEFINE(on_cmd_exterror) +{ + modem_cmd_handler_set_error(data, -EIO); + k_sem_give(&mdata.sem_response); + return 0; +} + +/* + * Handles pdp context urc. + * + * The urc has the form +APP PDP: ,. + * State can either be ACTIVE for activation or + * DEACTIVE if disabled. + */ +MODEM_CMD_DEFINE(on_urc_app_pdp) +{ + mdata.pdp_active = strcmp(argv[1], "ACTIVE") == 0; + LOG_INF("PDP context: %u", mdata.pdp_active); + k_sem_give(&mdata.sem_response); + return 0; +} + +MODEM_CMD_DEFINE(on_urc_sms) +{ + LOG_INF("SMS: %s", argv[0]); + return 0; +} + +/* + * Handles socket data notification. + * + * The sim modem sends and unsolicited +CADATAIND: + * if data can be read from a socket. + */ +MODEM_CMD_DEFINE(on_urc_cadataind) +{ + struct modem_socket *sock; + int sock_fd; + + sock_fd = atoi(argv[0]); + + sock = modem_socket_from_fd(&mdata.socket_config, sock_fd); + if (!sock) { + return 0; + } + + /* Modem does not tell packet size. Set dummy for receive. */ + modem_socket_packet_size_update(&mdata.socket_config, sock, 1); + + LOG_INF("Data available on socket: %d", sock_fd); + modem_socket_data_ready(&mdata.socket_config, sock); + + return 0; +} + +/* + * Handles the castate response. + * + * +CASTATE: , + * + * Cid is the connection id (socket fd) and + * state can be: + * 0 - Closed by remote server or error + * 1 - Connected to remote server + * 2 - Listening + */ +MODEM_CMD_DEFINE(on_urc_castate) +{ + struct modem_socket *sock; + int sockfd, state; + + sockfd = atoi(argv[0]); + state = atoi(argv[1]); + + sock = modem_socket_from_fd(&mdata.socket_config, sockfd); + if (!sock) { + return 0; + } + + /* Only continue if socket was closed. */ + if (state != 0) { + return 0; + } + + LOG_INF("Socket close indication for socket: %d", sockfd); + + sock->is_connected = false; + LOG_INF("Socket closed: %d", sockfd); + + return 0; +} + +/** + * Handles the ftpget urc. + * + * +FTPGET: , + * + * Mode can be 1 for opening a session and + * reporting that data is available or 2 for + * reading data. This urc handler will only handle + * mode 1 because 2 will not occur as urc. + * + * Error can be either: + * - 1 for data available/opened session. + * - 0 If transfer is finished. + * - >0 for some error. + */ +MODEM_CMD_DEFINE(on_urc_ftpget) +{ + int error = atoi(argv[0]); + + LOG_INF("+FTPGET: 1,%d", error); + + /* Transfer finished. */ + if (error == 0) { + mdata.ftp.state = SIM7080_FTP_CONNECTION_STATE_FINISHED; + } else if (error == 1) { + mdata.ftp.state = SIM7080_FTP_CONNECTION_STATE_CONNECTED; + } else { + mdata.ftp.state = SIM7080_FTP_CONNECTION_STATE_ERROR; + } + + k_sem_give(&mdata.sem_ftp); + + return 0; +} + +/* + * Read manufacturer identification. + */ +MODEM_CMD_DEFINE(on_cmd_cgmi) +{ + size_t out_len = net_buf_linearize( + mdata.mdm_manufacturer, sizeof(mdata.mdm_manufacturer) - 1, data->rx_buf, 0, len); + mdata.mdm_manufacturer[out_len] = '\0'; + LOG_INF("Manufacturer: %s", mdata.mdm_manufacturer); + return 0; +} + +/* + * Read model identification. + */ +MODEM_CMD_DEFINE(on_cmd_cgmm) +{ + size_t out_len = net_buf_linearize(mdata.mdm_model, sizeof(mdata.mdm_model) - 1, + data->rx_buf, 0, len); + mdata.mdm_model[out_len] = '\0'; + LOG_INF("Model: %s", mdata.mdm_model); + return 0; +} + +/* + * Read software release. + * + * Response will be in format RESPONSE: . + */ +MODEM_CMD_DEFINE(on_cmd_cgmr) +{ + size_t out_len; + char *p; + + out_len = net_buf_linearize(mdata.mdm_revision, sizeof(mdata.mdm_revision) - 1, + data->rx_buf, 0, len); + mdata.mdm_revision[out_len] = '\0'; + + /* The module prepends a Revision: */ + p = strchr(mdata.mdm_revision, ':'); + if (p) { + out_len = strlen(p + 1); + memmove(mdata.mdm_revision, p + 1, out_len + 1); + } + + LOG_INF("Revision: %s", mdata.mdm_revision); + return 0; +} + +/* + * Read serial number identification. + */ +MODEM_CMD_DEFINE(on_cmd_cgsn) +{ + size_t out_len = + net_buf_linearize(mdata.mdm_imei, sizeof(mdata.mdm_imei) - 1, data->rx_buf, 0, len); + mdata.mdm_imei[out_len] = '\0'; + LOG_INF("IMEI: %s", mdata.mdm_imei); + return 0; +} + +#if defined(CONFIG_MODEM_SIM_NUMBERS) +/* + * Read international mobile subscriber identity. + */ +MODEM_CMD_DEFINE(on_cmd_cimi) +{ + size_t out_len = + net_buf_linearize(mdata.mdm_imsi, sizeof(mdata.mdm_imsi) - 1, data->rx_buf, 0, len); + mdata.mdm_imsi[out_len] = '\0'; + + /* Log the received information. */ + LOG_INF("IMSI: %s", mdata.mdm_imsi); + return 0; +} + +/* + * Read iccid. + */ +MODEM_CMD_DEFINE(on_cmd_ccid) +{ + size_t out_len = net_buf_linearize(mdata.mdm_iccid, sizeof(mdata.mdm_iccid) - 1, + data->rx_buf, 0, len); + mdata.mdm_iccid[out_len] = '\0'; + + /* Log the received information. */ + LOG_INF("ICCID: %s", mdata.mdm_iccid); + return 0; +} +#endif /* defined(CONFIG_MODEM_SIM_NUMBERS) */ + +/* + * Parses the non urc C(E)REG and updates registration status. + */ +MODEM_CMD_DEFINE(on_cmd_cereg) +{ + mdata.mdm_registration = atoi(argv[1]); + LOG_INF("CREG: %u", mdata.mdm_registration); + return 0; +} + +MODEM_CMD_DEFINE(on_cmd_cpin) +{ + mdata.cpin_ready = strcmp(argv[0], "READY") == 0; + LOG_INF("CPIN: %d", mdata.cpin_ready); + return 0; +} + +MODEM_CMD_DEFINE(on_cmd_cgatt) +{ + mdata.mdm_cgatt = atoi(argv[0]); + LOG_INF("CGATT: %d", mdata.mdm_cgatt); + return 0; +} + +/* + * Handler for RSSI query. + * + * +CSQ: , + * rssi: 0,-115dBm; 1,-111dBm; 2...30,-110...-54dBm; 31,-52dBm or greater. + * 99, ukn + * ber: Not used. + */ +MODEM_CMD_DEFINE(on_cmd_csq) +{ + int rssi = atoi(argv[0]); + + if (rssi == 0) { + mdata.mdm_rssi = -115; + } else if (rssi == 1) { + mdata.mdm_rssi = -111; + } else if (rssi > 1 && rssi < 31) { + mdata.mdm_rssi = -114 + 2 * rssi; + } else if (rssi == 31) { + mdata.mdm_rssi = -52; + } else { + mdata.mdm_rssi = -1000; + } + + LOG_INF("RSSI: %d", mdata.mdm_rssi); + return 0; +} + +/* + * Queries modem RSSI. + * + * If a work queue parameter is provided query work will + * be scheduled. Otherwise rssi is queried once. + */ +static void modem_rssi_query_work(struct k_work *work) +{ + struct modem_cmd cmd[] = { MODEM_CMD("+CSQ: ", on_cmd_csq, 2U, ",") }; + static char *send_cmd = "AT+CSQ"; + int ret; + + ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, cmd, ARRAY_SIZE(cmd), send_cmd, + &mdata.sem_response, MDM_CMD_TIMEOUT); + if (ret < 0) { + LOG_ERR("AT+CSQ ret:%d", ret); + } + + if (work) { + k_work_reschedule_for_queue(&modem_workq, &mdata.rssi_query_work, + K_SECONDS(RSSI_TIMEOUT_SECS)); + } +} + +/* + * Unlock the tx ready semaphore if '> ' is received. + */ +MODEM_CMD_DIRECT_DEFINE(on_cmd_tx_ready) +{ + k_sem_give(&mdata.sem_tx_ready); + return len; +} + +/* + * Possible responses by the sim7080. + */ +static const struct modem_cmd response_cmds[] = { + MODEM_CMD("OK", on_cmd_ok, 0U, ""), + MODEM_CMD("ERROR", on_cmd_error, 0U, ""), + MODEM_CMD("+CME ERROR: ", on_cmd_exterror, 1U, ""), + MODEM_CMD_DIRECT(">", on_cmd_tx_ready), +}; + +/* + * Possible unsolicited commands. + */ +static const struct modem_cmd unsolicited_cmds[] = { + MODEM_CMD("+APP PDP: ", on_urc_app_pdp, 2U, ","), + MODEM_CMD("SMS ", on_urc_sms, 1U, ""), + MODEM_CMD("+CADATAIND: ", on_urc_cadataind, 1U, ""), + MODEM_CMD("+CASTATE: ", on_urc_castate, 2U, ","), + MODEM_CMD("+FTPGET: 1,", on_urc_ftpget, 1U, ""), +}; + +/* + * Activates the pdp context + */ +static int modem_pdp_activate(void) +{ + int counter; + int ret = 0; +#if defined(CONFIG_MODEM_SIMCOM_SIM7080_RAT_GSM) + const char *buf = "AT+CREG?"; + struct modem_cmd cmds[] = { MODEM_CMD("+CREG: ", on_cmd_cereg, 2U, ",") }; +#else + const char *buf = "AT+CEREG?"; + struct modem_cmd cmds[] = { MODEM_CMD("+CEREG: ", on_cmd_cereg, 2U, ",") }; +#endif /* defined(CONFIG_MODEM_SIMCOM_SIM7080_RAT_GSM) */ + + struct modem_cmd cgatt_cmd[] = { MODEM_CMD("+CGATT: ", on_cmd_cgatt, 1U, "") }; + + counter = 0; + while (counter++ < MDM_MAX_CGATT_WAITS && mdata.mdm_cgatt != 1) { + ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, cgatt_cmd, + ARRAY_SIZE(cgatt_cmd), "AT+CGATT?", &mdata.sem_response, + MDM_CMD_TIMEOUT); + if (ret < 0) { + LOG_ERR("Failed to query cgatt!!"); + return -1; + } + + k_sleep(K_SECONDS(1)); + } + + if (counter >= MDM_MAX_CGATT_WAITS) { + LOG_WRN("Network attach failed!!"); + return -1; + } + + if (!mdata.cpin_ready || mdata.mdm_cgatt != 1) { + LOG_ERR("Fatal: Modem is not attached to GPRS network!!"); + return -1; + } + + LOG_INF("Waiting for network"); + + /* Wait until the module is registered to the network. + * Registration will be set by urc. + */ + counter = 0; + while (counter++ < MDM_MAX_CEREG_WAITS && mdata.mdm_registration != 1 && + mdata.mdm_registration != 5) { + ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, cmds, ARRAY_SIZE(cmds), buf, + &mdata.sem_response, MDM_CMD_TIMEOUT); + if (ret < 0) { + LOG_ERR("Failed to query registration!!"); + return -1; + } + + k_sleep(K_SECONDS(1)); + } + + if (counter >= MDM_MAX_CEREG_WAITS) { + LOG_WRN("Network registration failed!"); + ret = -1; + goto error; + } + + /* Set dual stack mode (IPv4/IPv6) */ + ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, NULL, 0, "AT+CNCFG=0,0", + &mdata.sem_response, MDM_CMD_TIMEOUT); + if (ret < 0) { + LOG_ERR("Could not configure pdp context!"); + goto error; + } + + /* + * Now activate the pdp context and wait for confirmation. + */ + ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, NULL, 0, "AT+CNACT=0,1", + &mdata.sem_response, MDM_CMD_TIMEOUT); + if (ret < 0) { + LOG_ERR("Could not activate PDP context."); + goto error; + } + + ret = k_sem_take(&mdata.sem_response, MDM_PDP_TIMEOUT); + if (ret < 0 || mdata.pdp_active == false) { + LOG_ERR("Failed to activate PDP context."); + ret = -1; + goto error; + } + + LOG_INF("Network active."); + +error: + return ret; +} + +/* + * Toggles the modems power pin. + */ +static void modem_pwrkey(void) +{ + /* Power pin should be high for 1.5 seconds. */ + gpio_pin_set_dt(&power_gpio, 1); + k_sleep(K_MSEC(1500)); + gpio_pin_set_dt(&power_gpio, 0); + k_sleep(K_SECONDS(5)); +} + +/* + * Commands to be sent at setup. + */ +static const struct setup_cmd setup_cmds[] = { + SETUP_CMD_NOHANDLE("ATH"), + SETUP_CMD("AT+CGMI", "", on_cmd_cgmi, 0U, ""), + SETUP_CMD("AT+CGMM", "", on_cmd_cgmm, 0U, ""), + SETUP_CMD("AT+CGMR", "", on_cmd_cgmr, 0U, ""), + SETUP_CMD("AT+CGSN", "", on_cmd_cgsn, 0U, ""), +#if defined(CONFIG_MODEM_SIM_NUMBERS) + SETUP_CMD("AT+CIMI", "", on_cmd_cimi, 0U, ""), + SETUP_CMD("AT+CCID", "", on_cmd_ccid, 0U, ""), +#endif /* defined(CONFIG_MODEM_SIM_NUMBERS) */ +#if defined(CONFIG_MODEM_SIMCOM_SIM7080_RAT_NB1) + SETUP_CMD_NOHANDLE("AT+CNMP=38"), + SETUP_CMD_NOHANDLE("AT+CMNB=2"), + SETUP_CMD_NOHANDLE("AT+CBANDCFG=\"NB-IOT\"," MDM_LTE_BANDS), +#endif /* defined(CONFIG_MODEM_SIMCOM_SIM7080_RAT_NB1) */ +#if defined(CONFIG_MODEM_SIMCOM_SIM7080_RAT_M1) + SETUP_CMD_NOHANDLE("AT+CNMP=38"), + SETUP_CMD_NOHANDLE("AT+CMNB=1"), + SETUP_CMD_NOHANDLE("AT+CBANDCFG=\"CAT-M\"," MDM_LTE_BANDS), +#endif /* defined(CONFIG_MODEM_SIMCOM_SIM7080_RAT_M1) */ +#if defined(CONFIG_MODEM_SIMCOM_SIM7080_RAT_GSM) + SETUP_CMD_NOHANDLE("AT+CNMP=13"), +#endif /* defined(CONFIG_MODEM_SIMCOM_SIM7080_RAT_GSM) */ + SETUP_CMD("AT+CPIN?", "+CPIN: ", on_cmd_cpin, 1U, ""), +}; + +/** + * Performs the autobaud sequence until modem answers or limit is reached. + * + * @return On successful boot 0 is returned. Otherwise <0 is returned. + */ +int modem_autobaud(void) +{ + int boot_tries = 0; + int counter = 0; + int ret; + + while (boot_tries++ <= MDM_BOOT_TRIES) { + modem_pwrkey(); + + /* + * The sim7080 has a autobaud function. + * On startup multiple AT's are sent until + * a OK is received. + */ + counter = 0; + while (counter < MDM_MAX_AUTOBAUD) { + ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, NULL, 0U, "AT", + &mdata.sem_response, K_MSEC(500)); + + /* OK was received. */ + if (ret == 0) { + /* Disable echo */ + return modem_cmd_send(&mctx.iface, &mctx.cmd_handler, NULL, 0U, + "ATE0", &mdata.sem_response, K_SECONDS(2)); + } + + counter++; + } + } + + return -1; +} + +/* + * Does the modem setup by starting it and + * bringing the modem to a PDP active state. + */ +static int modem_setup(void) +{ + int ret = 0; + int counter = 0; + + k_work_cancel_delayable(&mdata.rssi_query_work); + + ret = modem_autobaud(); + if (ret < 0) { + LOG_ERR("Booting modem failed!!"); + goto error; + } + + ret = modem_cmd_handler_setup_cmds(&mctx.iface, &mctx.cmd_handler, setup_cmds, + ARRAY_SIZE(setup_cmds), &mdata.sem_response, + MDM_REGISTRATION_TIMEOUT); + if (ret < 0) { + LOG_ERR("Failed to send init commands!"); + goto error; + } + + k_sleep(K_SECONDS(3)); + + /* Wait for acceptable rssi values. */ + modem_rssi_query_work(NULL); + k_sleep(MDM_WAIT_FOR_RSSI_DELAY); + + counter = 0; + while (counter++ < MDM_WAIT_FOR_RSSI_COUNT && + (mdata.mdm_rssi >= 0 || mdata.mdm_rssi <= -1000)) { + modem_rssi_query_work(NULL); + k_sleep(MDM_WAIT_FOR_RSSI_DELAY); + } + + if (mdata.mdm_rssi >= 0 || mdata.mdm_rssi <= -1000) { + LOG_ERR("Network not reachable!!"); + ret = -ENETUNREACH; + goto error; + } + + ret = modem_pdp_activate(); + if (ret < 0) { + goto error; + } + + k_work_reschedule_for_queue(&modem_workq, &mdata.rssi_query_work, + K_SECONDS(RSSI_TIMEOUT_SECS)); + + sim7080_change_state(SIM7080_STATE_NETWORKING); + +error: + return ret; +} + +int mdm_sim7080_start_network(void) +{ + sim7080_change_state(SIM7080_STATE_INIT); + return modem_setup(); +} + +int mdm_sim7080_power_on(void) +{ + return modem_autobaud(); +} + +int mdm_sim7080_power_off(void) +{ + int tries = 5; + int autobaud_tries; + int ret = 0; + + k_work_cancel_delayable(&mdata.rssi_query_work); + + /* Check if module is already off. */ + ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, NULL, 0U, "AT", &mdata.sem_response, + K_MSEC(1000)); + if (ret < 0) { + sim7080_change_state(SIM7080_STATE_OFF); + return 0; + } + + while (tries--) { + modem_pwrkey(); + + autobaud_tries = 5; + + while (autobaud_tries--) { + ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, NULL, 0U, "AT", + &mdata.sem_response, K_MSEC(500)); + if (ret == 0) { + break; + } + } + + if (ret < 0) { + sim7080_change_state(SIM7080_STATE_OFF); + return 0; + } + } + + return -1; +} + +const char *mdm_sim7080_get_manufacturer(void) +{ + return mdata.mdm_manufacturer; +} + +const char *mdm_sim7080_get_model(void) +{ + return mdata.mdm_model; +} + +const char *mdm_sim7080_get_revision(void) +{ + return mdata.mdm_revision; +} + +const char *mdm_sim7080_get_imei(void) +{ + return mdata.mdm_imei; +} + +/* + * Initializes modem handlers and context. + * After successful init this function calls + * modem_setup. + */ +static int modem_init(const struct device *dev) +{ + int ret; + + ARG_UNUSED(dev); + + k_sem_init(&mdata.sem_response, 0, 1); + k_sem_init(&mdata.sem_tx_ready, 0, 1); + k_sem_init(&mdata.sem_dns, 0, 1); + k_sem_init(&mdata.sem_ftp, 0, 1); + k_work_queue_start(&modem_workq, modem_workq_stack, + K_KERNEL_STACK_SIZEOF(modem_workq_stack), K_PRIO_COOP(7), NULL); + + /* Assume the modem is not registered to the network. */ + mdata.mdm_registration = 0; + mdata.cpin_ready = false; + mdata.pdp_active = false; + + mdata.sms_buffer = NULL; + mdata.sms_buffer_pos = 0; + + /* Socket config. */ + ret = modem_socket_init(&mdata.socket_config, &mdata.sockets[0], ARRAY_SIZE(mdata.sockets), + MDM_BASE_SOCKET_NUM, true, &offload_socket_fd_op_vtable); + if (ret < 0) { + goto error; + } + + sim7080_change_state(SIM7080_STATE_INIT); + + /* Command handler. */ + const struct modem_cmd_handler_config cmd_handler_config = { + .match_buf = &mdata.cmd_match_buf[0], + .match_buf_len = sizeof(mdata.cmd_match_buf), + .buf_pool = &mdm_recv_pool, + .alloc_timeout = BUF_ALLOC_TIMEOUT, + .eol = "\r\n", + .user_data = NULL, + .response_cmds = response_cmds, + .response_cmds_len = ARRAY_SIZE(response_cmds), + .unsol_cmds = unsolicited_cmds, + .unsol_cmds_len = ARRAY_SIZE(unsolicited_cmds), + }; + + ret = modem_cmd_handler_init(&mctx.cmd_handler, &mdata.cmd_handler_data, + &cmd_handler_config); + if (ret < 0) { + goto error; + } + + /* Uart handler. */ + const struct modem_iface_uart_config uart_config = { + .rx_rb_buf = &mdata.iface_rb_buf[0], + .rx_rb_buf_len = sizeof(mdata.iface_rb_buf), + .dev = MDM_UART_DEV, + .hw_flow_control = DT_PROP(MDM_UART_NODE, hw_flow_control), + }; + + ret = modem_iface_uart_init(&mctx.iface, &mdata.iface_data, &uart_config); + if (ret < 0) { + goto error; + } + + mdata.current_sock_fd = -1; + mdata.current_sock_written = 0; + + mdata.ftp.read_buffer = NULL; + mdata.ftp.nread = 0; + mdata.ftp.state = SIM7080_FTP_CONNECTION_STATE_INITIAL; + + /* Modem data storage. */ + mctx.data_manufacturer = mdata.mdm_manufacturer; + mctx.data_model = mdata.mdm_model; + mctx.data_revision = mdata.mdm_revision; + mctx.data_imei = mdata.mdm_imei; +#if defined(CONFIG_MODEM_SIM_NUMBERS) + mctx.data_imsi = mdata.mdm_imsi; + mctx.data_iccid = mdata.mdm_iccid; +#endif /* #if defined(CONFIG_MODEM_SIM_NUMBERS) */ + mctx.data_rssi = &mdata.mdm_rssi; + + ret = gpio_pin_configure_dt(&power_gpio, GPIO_OUTPUT_LOW); + if (ret < 0) { + LOG_ERR("Failed to configure %s pin", "power"); + goto error; + } + + mctx.driver_data = &mdata; + + ret = modem_context_register(&mctx); + if (ret < 0) { + LOG_ERR("Error registering modem context: %d", ret); + goto error; + } + + k_thread_create(&modem_rx_thread, modem_rx_stack, K_KERNEL_STACK_SIZEOF(modem_rx_stack), + modem_rx, NULL, NULL, NULL, K_PRIO_COOP(7), 0, K_NO_WAIT); + + /* Init RSSI query */ + k_work_init_delayable(&mdata.rssi_query_work, modem_rssi_query_work); + + return modem_setup(); +error: + return ret; +} + +/* Register device with the networking stack. */ +NET_DEVICE_DT_INST_OFFLOAD_DEFINE(0, modem_init, NULL, &mdata, NULL, + CONFIG_MODEM_SIMCOM_SIM7080_INIT_PRIORITY, &api_funcs, + MDM_MAX_DATA_LENGTH); + +NET_SOCKET_OFFLOAD_REGISTER(simcom_sim7080, CONFIG_NET_SOCKETS_OFFLOAD_PRIORITY, + AF_UNSPEC, offload_is_supported, offload_socket); diff --git a/drivers/modem/simcom-sim7080.h b/drivers/modem/simcom/sim7080/sim7080.h similarity index 92% rename from drivers/modem/simcom-sim7080.h rename to drivers/modem/simcom/sim7080/sim7080.h index cb16100cb5857..383091ec771d4 100644 --- a/drivers/modem/simcom-sim7080.h +++ b/drivers/modem/simcom/sim7080/sim7080.h @@ -177,4 +177,18 @@ struct socket_read_data { uint16_t recv_read_len; }; +/* + * Driver internals + */ +extern struct sim7080_data mdata; +extern struct modem_context mctx; +extern const struct socket_op_vtable offload_socket_fd_op_vtable; +extern const struct socket_dns_offload offload_dns_ops; + +enum sim7080_state sim7080_get_state(void); + +void sim7080_change_state(enum sim7080_state state); + +int modem_autobaud(void); + #endif /* SIMCOM_SIM7080_H */ diff --git a/drivers/modem/simcom/sim7080/sim7080_dns.c b/drivers/modem/simcom/sim7080/sim7080_dns.c new file mode 100644 index 0000000000000..2c57f88be564c --- /dev/null +++ b/drivers/modem/simcom/sim7080/sim7080_dns.c @@ -0,0 +1,144 @@ +/* + * Copyright (C) 2025 metraTec GmbH + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT simcom_sim7080 + +#include +#include +LOG_MODULE_REGISTER(modem_simcom_sim7080_dns, CONFIG_MODEM_LOG_LEVEL); + +#include +#include "sim7080.h" + +static struct zsock_addrinfo dns_result; +static struct sockaddr dns_result_addr; +static char dns_result_canonname[DNS_MAX_NAME_SIZE + 1]; + +/* + * Parses the dns response from the modem. + * + * Response on success: + * +CDNSGIP: 1,,[,] + * + * Response on failure: + * +CDNSGIP: 0, + */ +MODEM_CMD_DEFINE(on_cmd_cdnsgip) +{ + int state; + char ips[256]; + size_t out_len; + int ret = -1; + + state = atoi(argv[0]); + if (state == 0) { + LOG_ERR("DNS lookup failed with error %s", argv[1]); + goto exit; + } + + /* Offset to skip the leading " */ + out_len = net_buf_linearize(ips, sizeof(ips) - 1, data->rx_buf, 1, len); + ips[out_len] = '\0'; + + /* find trailing " */ + char *ipv4 = strstr(ips, "\""); + + if (!ipv4) { + LOG_ERR("Malformed DNS response!!"); + goto exit; + } + + *ipv4 = '\0'; + net_addr_pton(dns_result.ai_family, ips, + &((struct sockaddr_in *)&dns_result_addr)->sin_addr); + ret = 0; + +exit: + k_sem_give(&mdata.sem_dns); + return ret; +} + +/* + * Perform a dns lookup. + */ +static int offload_getaddrinfo(const char *node, const char *service, + const struct zsock_addrinfo *hints, struct zsock_addrinfo **res) +{ + struct modem_cmd cmd[] = { MODEM_CMD("+CDNSGIP: ", on_cmd_cdnsgip, 2U, ",") }; + char sendbuf[sizeof("AT+CDNSGIP=\"\",##,#####") + 128]; + uint32_t port = 0; + int ret; + + /* Modem is not attached to the network. */ + if (sim7080_get_state() != SIM7080_STATE_NETWORKING) { + LOG_ERR("Modem currently not attached to the network!"); + return DNS_EAI_AGAIN; + } + + /* init result */ + (void)memset(&dns_result, 0, sizeof(dns_result)); + (void)memset(&dns_result_addr, 0, sizeof(dns_result_addr)); + + /* Currently only support IPv4. */ + dns_result.ai_family = AF_INET; + dns_result_addr.sa_family = AF_INET; + dns_result.ai_addr = &dns_result_addr; + dns_result.ai_addrlen = sizeof(dns_result_addr); + dns_result.ai_canonname = dns_result_canonname; + dns_result_canonname[0] = '\0'; + + if (service) { + port = atoi(service); + if (port < 1 || port > USHRT_MAX) { + return DNS_EAI_SERVICE; + } + } + + if (port > 0U) { + if (dns_result.ai_family == AF_INET) { + net_sin(&dns_result_addr)->sin_port = htons(port); + } + } + + /* Check if node is an IP address */ + if (net_addr_pton(dns_result.ai_family, node, + &((struct sockaddr_in *)&dns_result_addr)->sin_addr) == 0) { + *res = &dns_result; + return 0; + } + + /* user flagged node as numeric host, but we failed net_addr_pton */ + if (hints && hints->ai_flags & AI_NUMERICHOST) { + return DNS_EAI_NONAME; + } + + snprintk(sendbuf, sizeof(sendbuf), "AT+CDNSGIP=\"%s\",10,20000", node); + ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, cmd, ARRAY_SIZE(cmd), sendbuf, + &mdata.sem_dns, MDM_DNS_TIMEOUT); + if (ret < 0) { + return ret; + } + + *res = (struct zsock_addrinfo *)&dns_result; + return 0; +} + +/* + * Free addrinfo structure. + */ +static void offload_freeaddrinfo(struct zsock_addrinfo *res) +{ + /* No need to free static memory. */ + ARG_UNUSED(res); +} + +/* + * DNS vtable. + */ +const struct socket_dns_offload offload_dns_ops = { + .getaddrinfo = offload_getaddrinfo, + .freeaddrinfo = offload_freeaddrinfo, +}; diff --git a/drivers/modem/simcom/sim7080/sim7080_ftp.c b/drivers/modem/simcom/sim7080/sim7080_ftp.c new file mode 100644 index 0000000000000..c33368ec47a8a --- /dev/null +++ b/drivers/modem/simcom/sim7080/sim7080_ftp.c @@ -0,0 +1,225 @@ +/* + * Copyright (C) 2025 Metratec GmbH + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +LOG_MODULE_REGISTER(modem_sim7080_ftp, CONFIG_MODEM_LOG_LEVEL); + +#include "sim7080.h" + +/** + * Parse the +FTPGET response. + * + * +FTPGET: , + * + * Mode is hard set to 2. + * + * Length is the number of bytes following (the ftp data). + */ +MODEM_CMD_DEFINE(on_cmd_ftpget) +{ + int nbytes = atoi(argv[0]); + int bytes_to_skip; + size_t out_len; + + if (nbytes == 0) { + mdata.ftp.nread = 0; + return 0; + } + + /* Skip length parameter and trailing \r\n */ + bytes_to_skip = strlen(argv[0]) + 2; + + /* Wait until data is ready. + * >= to ensure buffer is not empty after skip. + */ + if (net_buf_frags_len(data->rx_buf) <= nbytes + bytes_to_skip) { + return -EAGAIN; + } + + out_len = net_buf_linearize(mdata.ftp.read_buffer, mdata.ftp.nread, data->rx_buf, + bytes_to_skip, nbytes); + if (out_len != nbytes) { + LOG_WRN("FTP read size differs!"); + } + data->rx_buf = net_buf_skip(data->rx_buf, nbytes + bytes_to_skip); + + mdata.ftp.nread = nbytes; + + return 0; +} + +int mdm_sim7080_ftp_get_read(char *dst, size_t *size) +{ + int ret; + char buffer[sizeof("AT+FTPGET=#,######")]; + struct modem_cmd cmds[] = { MODEM_CMD("+FTPGET: 2,", on_cmd_ftpget, 1U, "") }; + + /* Some error occurred. */ + if (mdata.ftp.state == SIM7080_FTP_CONNECTION_STATE_ERROR || + mdata.ftp.state == SIM7080_FTP_CONNECTION_STATE_INITIAL) { + return SIM7080_FTP_RC_ERROR; + } + + /* Setup buffer. */ + mdata.ftp.read_buffer = dst; + mdata.ftp.nread = *size; + + /* Read ftp data. */ + ret = snprintk(buffer, sizeof(buffer), "AT+FTPGET=2,%zu", *size); + if (ret < 0) { + *size = 0; + return SIM7080_FTP_RC_ERROR; + } + + /* Wait for data from the server. */ + k_sem_take(&mdata.sem_ftp, K_MSEC(200)); + + if (mdata.ftp.state == SIM7080_FTP_CONNECTION_STATE_FINISHED) { + *size = 0; + return SIM7080_FTP_RC_FINISHED; + } else if (mdata.ftp.state == SIM7080_FTP_CONNECTION_STATE_ERROR) { + *size = 0; + return SIM7080_FTP_RC_ERROR; + } + + ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, cmds, ARRAY_SIZE(cmds), buffer, + &mdata.sem_response, MDM_CMD_TIMEOUT); + if (ret < 0) { + *size = 0; + return SIM7080_FTP_RC_ERROR; + } + + /* Set read size. */ + *size = mdata.ftp.nread; + + return SIM7080_FTP_RC_OK; +} + +int mdm_sim7080_ftp_get_start(const char *server, const char *user, const char *passwd, + const char *file, const char *path) +{ + int ret; + char buffer[256]; + + /* Start network. */ + ret = mdm_sim7080_start_network(); + if (ret < 0) { + LOG_ERR("Failed to start network for FTP!"); + return -1; + } + + /* Set connection id for ftp. */ + ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, NULL, 0U, "AT+FTPCID=0", + &mdata.sem_response, MDM_CMD_TIMEOUT); + if (ret < 0) { + LOG_WRN("Failed to set FTP Cid!"); + return -1; + } + + /* Set ftp server. */ + ret = snprintk(buffer, sizeof(buffer), "AT+FTPSERV=\"%s\"", server); + if (ret < 0) { + LOG_WRN("Failed to build command!"); + return -1; + } + + ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, NULL, 0U, buffer, &mdata.sem_response, + MDM_CMD_TIMEOUT); + if (ret < 0) { + LOG_WRN("Failed to set FTP Cid!"); + return -1; + } + + /* Set ftp user. */ + ret = snprintk(buffer, sizeof(buffer), "AT+FTPUN=\"%s\"", user); + if (ret < 0) { + LOG_WRN("Failed to build command!"); + return -1; + } + + ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, NULL, 0U, buffer, &mdata.sem_response, + MDM_CMD_TIMEOUT); + if (ret < 0) { + LOG_WRN("Failed to set ftp user!"); + return -1; + } + + /* Set ftp password. */ + ret = snprintk(buffer, sizeof(buffer), "AT+FTPPW=\"%s\"", passwd); + if (ret < 0) { + LOG_WRN("Failed to build command!"); + return -1; + } + + ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, NULL, 0U, buffer, &mdata.sem_response, + MDM_CMD_TIMEOUT); + if (ret < 0) { + LOG_WRN("Failed to set ftp password!"); + return -1; + } + + /* Set ftp filename. */ + ret = snprintk(buffer, sizeof(buffer), "AT+FTPGETNAME=\"%s\"", file); + if (ret < 0) { + LOG_WRN("Failed to build command!"); + return -1; + } + + ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, NULL, 0U, buffer, &mdata.sem_response, + MDM_CMD_TIMEOUT); + if (ret < 0) { + LOG_WRN("Failed to set ftp filename!"); + return -1; + } + + /* Set ftp filename. */ + ret = snprintk(buffer, sizeof(buffer), "AT+FTPGETNAME=\"%s\"", file); + if (ret < 0) { + LOG_WRN("Failed to build command!"); + return -1; + } + + ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, NULL, 0U, buffer, &mdata.sem_response, + MDM_CMD_TIMEOUT); + if (ret < 0) { + LOG_WRN("Failed to set ftp filename!"); + return -1; + } + + /* Set ftp path. */ + ret = snprintk(buffer, sizeof(buffer), "AT+FTPGETPATH=\"%s\"", path); + if (ret < 0) { + LOG_WRN("Failed to build command!"); + return -1; + } + + ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, NULL, 0U, buffer, &mdata.sem_response, + MDM_CMD_TIMEOUT); + if (ret < 0) { + LOG_WRN("Failed to set ftp path!"); + return -1; + } + + /* Initialize ftp variables. */ + mdata.ftp.read_buffer = NULL; + mdata.ftp.nread = 0; + mdata.ftp.state = SIM7080_FTP_CONNECTION_STATE_INITIAL; + + /* Start the ftp session. */ + ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, NULL, 0U, "AT+FTPGET=1", + &mdata.sem_ftp, MDM_CMD_TIMEOUT); + if (ret < 0) { + LOG_WRN("Failed to start session!"); + return -1; + } + + if (mdata.ftp.state != SIM7080_FTP_CONNECTION_STATE_CONNECTED) { + LOG_WRN("Session state is not connected!"); + return -1; + } + + return 0; +} diff --git a/drivers/modem/simcom/sim7080/sim7080_gps.c b/drivers/modem/simcom/sim7080/sim7080_gps.c new file mode 100644 index 0000000000000..6e83ca7ae817e --- /dev/null +++ b/drivers/modem/simcom/sim7080/sim7080_gps.c @@ -0,0 +1,289 @@ +/* + * Copyright (C) 2025 Metratec GmbH + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +LOG_MODULE_REGISTER(modem_sim7080_gps, CONFIG_MODEM_LOG_LEVEL); + +#include "sim7080.h" + +static struct sim7080_gnss_data gnss_data; + +/** + * Get the next parameter from the gnss phrase. + * + * @param src The source string supported on first call. + * @param delim The delimiter of the parameter list. + * @param saveptr Pointer for subsequent parses. + * @return On success a pointer to the parameter. On failure + * or end of string NULL is returned. + * + * This function is used instead of strtok because strtok would + * skip empty parameters, which is not desired. The modem may + * omit parameters which could lead to a incorrect parse. + */ +static char *gnss_get_next_param(char *src, const char *delim, char **saveptr) +{ + char *start, *del; + + if (src) { + start = src; + } else { + start = *saveptr; + } + + /* Illegal start string. */ + if (!start) { + return NULL; + } + + /* End of string reached. */ + if (*start == '\0' || *start == '\r') { + return NULL; + } + + del = strstr(start, delim); + if (!del) { + return NULL; + } + + *del = '\0'; + *saveptr = del + 1; + + if (del == start) { + return NULL; + } + + return start; +} + +static void gnss_skip_param(char **saveptr) +{ + gnss_get_next_param(NULL, ",", saveptr); +} + +/** + * Splits float parameters of the CGNSINF response on '.' + * + * @param src Null terminated string containing the float. + * @param f1 Resulting number part of the float. + * @param f2 Resulting fraction part of the float. + * @return 0 if parsing was successful. Otherwise <0 is returned. + * + * If the number part of the float is negative f1 and f2 will be + * negative too. + */ +static int gnss_split_on_dot(const char *src, int32_t *f1, int32_t *f2) +{ + char *dot = strchr(src, '.'); + + if (!dot) { + return -1; + } + + *dot = '\0'; + + *f1 = (int32_t)strtol(src, NULL, 10); + *f2 = (int32_t)strtol(dot + 1, NULL, 10); + + if (*f1 < 0) { + *f2 = -*f2; + } + + return 0; +} + +/** + * Parses cgnsinf response into the gnss_data structure. + * + * @param gps_buf Null terminated buffer containing the response. + * @return 0 on successful parse. Otherwise <0 is returned. + */ +static int parse_cgnsinf(char *gps_buf) +{ + char *saveptr; + int ret; + int32_t number, fraction; + + char *run_status = gnss_get_next_param(gps_buf, ",", &saveptr); + + if (run_status == NULL) { + goto error; + } else if (*run_status != '1') { + goto error; + } + + char *fix_status = gnss_get_next_param(NULL, ",", &saveptr); + + if (fix_status == NULL) { + goto error; + } else if (*fix_status != '1') { + goto error; + } + + char *utc = gnss_get_next_param(NULL, ",", &saveptr); + + if (utc == NULL) { + goto error; + } + + char *lat = gnss_get_next_param(NULL, ",", &saveptr); + + if (lat == NULL) { + goto error; + } + + char *lon = gnss_get_next_param(NULL, ",", &saveptr); + + if (lon == NULL) { + goto error; + } + + char *alt = gnss_get_next_param(NULL, ",", &saveptr); + char *speed = gnss_get_next_param(NULL, ",", &saveptr); + char *course = gnss_get_next_param(NULL, ",", &saveptr); + + /* discard fix mode and reserved*/ + gnss_skip_param(&saveptr); + gnss_skip_param(&saveptr); + + char *hdop = gnss_get_next_param(NULL, ",", &saveptr); + + if (hdop == NULL) { + goto error; + } + + gnss_data.run_status = 1; + gnss_data.fix_status = 1; + + strncpy(gnss_data.utc, utc, sizeof(gnss_data.utc) - 1); + + ret = gnss_split_on_dot(lat, &number, &fraction); + if (ret != 0) { + goto error; + } + gnss_data.lat = number * 10000000 + fraction * 10; + + ret = gnss_split_on_dot(lon, &number, &fraction); + if (ret != 0) { + goto error; + } + gnss_data.lon = number * 10000000 + fraction * 10; + + if (alt) { + ret = gnss_split_on_dot(alt, &number, &fraction); + if (ret != 0) { + goto error; + } + gnss_data.alt = number * 1000 + fraction; + } else { + gnss_data.alt = 0; + } + + ret = gnss_split_on_dot(hdop, &number, &fraction); + if (ret != 0) { + goto error; + } + gnss_data.hdop = number * 100 + fraction * 10; + + if (course) { + ret = gnss_split_on_dot(course, &number, &fraction); + if (ret != 0) { + goto error; + } + gnss_data.cog = number * 100 + fraction * 10; + } else { + gnss_data.cog = 0; + } + + if (speed) { + ret = gnss_split_on_dot(speed, &number, &fraction); + if (ret != 0) { + goto error; + } + gnss_data.kmh = number * 10 + fraction / 10; + } else { + gnss_data.kmh = 0; + } + + return 0; +error: + memset(&gnss_data, 0, sizeof(gnss_data)); + return -1; +} + +/* + * Parses the +CGNSINF Gnss response. + * + * The CGNSINF command has the following parameters but + * not all parameters are set by the module: + * + * +CGNSINF: ,,, + * ,,,, + * ,,,,, + * ,,,, + * , + * + */ +MODEM_CMD_DEFINE(on_cmd_cgnsinf) +{ + char gps_buf[MDM_GNSS_PARSER_MAX_LEN]; + size_t out_len = net_buf_linearize(gps_buf, sizeof(gps_buf) - 1, data->rx_buf, 0, len); + + gps_buf[out_len] = '\0'; + return parse_cgnsinf(gps_buf); +} + +int mdm_sim7080_query_gnss(struct sim7080_gnss_data *data) +{ + int ret; + struct modem_cmd cmds[] = { MODEM_CMD("+CGNSINF: ", on_cmd_cgnsinf, 0U, NULL) }; + + if (sim7080_get_state() != SIM7080_STATE_GNSS) { + LOG_ERR("GNSS functionality is not enabled!!"); + return -1; + } + + memset(&gnss_data, 0, sizeof(gnss_data)); + + ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, cmds, ARRAY_SIZE(cmds), "AT+CGNSINF", + &mdata.sem_response, K_SECONDS(2)); + if (ret < 0) { + return ret; + } + + if (!gnss_data.run_status || !gnss_data.fix_status) { + return -EAGAIN; + } + + if (data) { + memcpy(data, &gnss_data, sizeof(gnss_data)); + } + + return ret; +} + +int mdm_sim7080_start_gnss(void) +{ + int ret; + + sim7080_change_state(SIM7080_STATE_INIT); + k_work_cancel_delayable(&mdata.rssi_query_work); + + ret = modem_autobaud(); + if (ret < 0) { + LOG_ERR("Failed to start modem!!"); + return -1; + } + + ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, NULL, 0U, "AT+CGNSCOLD", + &mdata.sem_response, K_SECONDS(2)); + if (ret < 0) { + return -1; + } + + sim7080_change_state(SIM7080_STATE_GNSS); + return 0; +} \ No newline at end of file diff --git a/drivers/modem/simcom/sim7080/sim7080_sms.c b/drivers/modem/simcom/sim7080/sim7080_sms.c new file mode 100644 index 0000000000000..2c4f2b256e611 --- /dev/null +++ b/drivers/modem/simcom/sim7080/sim7080_sms.c @@ -0,0 +1,390 @@ +/* + * Copyright (C) 2025 Metratec GmbH + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +LOG_MODULE_REGISTER(modem_sim7080_sms, CONFIG_MODEM_LOG_LEVEL); + +#include "sim7080.h" + +#define SMS_TP_UDHI_HEADER 0x40 + +/** + * Decode readable hex to "real" hex. + */ +static uint8_t mdm_pdu_decode_ascii(char byte) +{ + if ((byte >= '0') && (byte <= '9')) { + return byte - '0'; + } else if ((byte >= 'A') && (byte <= 'F')) { + return byte - 'A' + 10; + } else if ((byte >= 'a') && (byte <= 'f')) { + return byte - 'a' + 10; + } else { + return 255; + } +} + +/** + * Reads "byte" from pdu. + * + * @param pdu pdu to read from. + * @param index index of "byte". + * + * Sim module "encodes" one pdu byte as two human readable bytes + * this functions squashes these two bytes into one. + */ +static uint8_t mdm_pdu_read_byte(const char *pdu, size_t index) +{ + return (mdm_pdu_decode_ascii(pdu[index * 2]) << 4 | + mdm_pdu_decode_ascii(pdu[index * 2 + 1])); +} + +/** + * Decodes time from pdu. + * + * @param pdu pdu to read from. + * @param index index of "byte". + */ +static uint8_t mdm_pdu_read_time(const char *pdu, size_t index) +{ + return (mdm_pdu_decode_ascii(pdu[index * 2]) + + mdm_pdu_decode_ascii(pdu[index * 2 + 1]) * 10); +} + +/** + * Decode a sms from pdu mode. + */ +static int mdm_decode_pdu(const char *pdu, size_t pdu_len, struct sim7080_sms *target_buf) +{ + size_t index; + + /* + * GSM_03.38 to Unicode conversion table + */ + const short enc7_basic[128] = { + '@', 0xA3, '$', 0xA5, 0xE8, 0xE9, 0xF9, 0xEC, 0xF2, 0xE7, + '\n', 0xD8, 0xF8, '\r', 0xC5, 0xF8, 0x0394, '_', 0x03A6, 0x0393, + 0x039B, 0x03A9, 0x03A0, 0x03A8, 0x03A3, 0x0398, 0x039E, '\x1b', 0xC6, 0xE6, + 0xDF, 0xC9, ' ', '!', '\"', '#', 0xA4, '%', '&', '\'', + '(', ')', '*', '+', ',', '-', '.', '/', '0', '1', + '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', + '<', '=', '>', '?', 0xA1, 'A', 'B', 'C', 'D', 'E', + 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', + 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', + 'Z', 0xC4, 0xD6, 0xD1, 0xDC, 0xA7, 0xBF, 'a', 'b', 'c', + 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', + 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', + 'x', 'y', 'z', 0xE4, 0xF6, 0xF1, 0xFC, 0xE0 + }; + + /* two bytes in pdu are on real byte */ + pdu_len = (pdu_len / 2); + + /* first byte of pdu is length of trailing SMSC information + * skip it by setting index to SMSC length + 1. + */ + index = mdm_pdu_read_byte(pdu, 0) + 1; + + if (index >= pdu_len) { + return -1; + } + + /* read first octet */ + target_buf->first_octet = mdm_pdu_read_byte(pdu, index++); + + if (index >= pdu_len) { + return -1; + } + + /* pdu_index now points to the address field. + * first byte of addr field is the addr length -> skip it. + * address type is not included in addr len -> add +1. + * address is coded in semi octets + * + addr_len/2 if even + * + addr_len/2 + 1 if odd + */ + uint8_t addr_len = mdm_pdu_read_byte(pdu, index); + + index += ((addr_len % 2) == 0) ? (addr_len / 2) + 2 : (addr_len / 2) + 3; + + if (index >= pdu_len) { + return -1; + } + + /* read protocol identifier */ + target_buf->tp_pid = mdm_pdu_read_byte(pdu, index++); + + if (index >= pdu_len) { + return -1; + } + + /* read coding scheme */ + uint8_t tp_dcs = mdm_pdu_read_byte(pdu, index++); + + /* parse date and time */ + if ((index + 7) >= pdu_len) { + return -1; + } + + target_buf->time.year = mdm_pdu_read_time(pdu, index++); + target_buf->time.month = mdm_pdu_read_time(pdu, index++); + target_buf->time.day = mdm_pdu_read_time(pdu, index++); + target_buf->time.hour = mdm_pdu_read_time(pdu, index++); + target_buf->time.minute = mdm_pdu_read_time(pdu, index++); + target_buf->time.second = mdm_pdu_read_time(pdu, index++); + target_buf->time.timezone = mdm_pdu_read_time(pdu, index++); + + /* Read user data length */ + uint8_t tp_udl = mdm_pdu_read_byte(pdu, index++); + + /* Discard header */ + uint8_t header_skip = 0; + + if (target_buf->first_octet & SMS_TP_UDHI_HEADER) { + uint8_t tp_udhl = mdm_pdu_read_byte(pdu, index); + + index += tp_udhl + 1; + header_skip = tp_udhl + 1; + + if (index >= pdu_len) { + return -1; + } + } + + /* Read data according to type set in TP-DCS */ + if (tp_dcs == 0x00) { + /* 7 bit GSM coding */ + uint8_t fill_level = 0; + uint16_t buf = 0; + + if (target_buf->first_octet & SMS_TP_UDHI_HEADER) { + /* Initial fill because septets are aligned to + * septet boundary after header + */ + uint8_t fill_bits = 7 - ((header_skip * 8) % 7); + + if (fill_bits == 7) { + fill_bits = 0; + } + + buf = mdm_pdu_read_byte(pdu, index++); + + fill_level = 8 - fill_bits; + } + + uint16_t data_index = 0; + + for (unsigned int idx = 0; idx < tp_udl; idx++) { + if (fill_level < 7) { + uint8_t octet = mdm_pdu_read_byte(pdu, index++); + + buf &= ((1 << fill_level) - 1); + buf |= (octet << fill_level); + fill_level += 8; + } + + /* + * Convert 7-bit encoded data to Unicode and + * then to UTF-8 + */ + short letter = enc7_basic[buf & 0x007f]; + + if (letter < 0x0080) { + target_buf->data[data_index++] = letter & 0x007f; + } else if (letter < 0x0800) { + target_buf->data[data_index++] = 0xc0 | ((letter & 0x07c0) >> 6); + target_buf->data[data_index++] = 0x80 | ((letter & 0x003f) >> 0); + } + buf >>= 7; + fill_level -= 7; + } + target_buf->data_len = data_index; + } else if (tp_dcs == 0x04) { + /* 8 bit binary coding */ + for (int idx = 0; idx < tp_udl - header_skip; idx++) { + target_buf->data[idx] = mdm_pdu_read_byte(pdu, index++); + } + target_buf->data_len = tp_udl; + } else if (tp_dcs == 0x08) { + /* Unicode (16 bit per character) */ + for (int idx = 0; idx < tp_udl - header_skip; idx++) { + target_buf->data[idx] = mdm_pdu_read_byte(pdu, index++); + } + target_buf->data_len = tp_udl; + } else { + return -1; + } + + return 0; +} + +/** + * Check if given char sequence is crlf. + * + * @param c The char sequence. + * @param len Total length of the fragment. + * @return @c true if char sequence is crlf. + * Otherwise @c false is returned. + */ +static bool is_crlf(uint8_t *c, uint8_t len) +{ + /* crlf does not fit. */ + if (len < 2) { + return false; + } + + return c[0] == '\r' && c[1] == '\n'; +} + +/** + * Find terminating crlf in a netbuffer. + * + * @param buf The netbuffer. + * @param skip Bytes to skip before search. + * @return Length of the returned fragment or 0 if not found. + */ +static size_t net_buf_find_crlf(struct net_buf *buf, size_t skip) +{ + size_t len = 0, pos = 0; + struct net_buf *frag = buf; + + /* Skip to the start. */ + while (frag && skip >= frag->len) { + skip -= frag->len; + frag = frag->frags; + } + + /* Need to wait for more data. */ + if (!frag) { + return 0; + } + + pos = skip; + + while (frag && !is_crlf(frag->data + pos, frag->len - pos)) { + if (pos + 1 >= frag->len) { + len += frag->len; + frag = frag->frags; + pos = 0U; + } else { + pos++; + } + } + + if (frag && is_crlf(frag->data + pos, frag->len - pos)) { + len += pos; + return len - skip; + } + + return 0; +} + +/** + * Parses list sms and add them to buffer. + * Format is: + * + * +CMGL: ,,, + * +CMGL: ,,, + * ... + * OK + */ +MODEM_CMD_DEFINE(on_cmd_cmgl) +{ + int sms_index, sms_stat, ret; + char pdu_buffer[256]; + size_t out_len, sms_len, param_len; + struct sim7080_sms *sms; + + sms_index = atoi(argv[0]); + sms_stat = atoi(argv[1]); + + /* Get the length of the "length" parameter. + * The last parameter will be stuck in the netbuffer. + * It is not the actual length of the trailing pdu so + * we have to search the next crlf. + */ + param_len = net_buf_find_crlf(data->rx_buf, 0); + if (param_len == 0) { + LOG_INF("No "); + return -EAGAIN; + } + + /* Get actual trailing pdu len. +2 to skip crlf. */ + sms_len = net_buf_find_crlf(data->rx_buf, param_len + 2); + if (sms_len == 0) { + return -EAGAIN; + } + + /* Skip to start of pdu. */ + data->rx_buf = net_buf_skip(data->rx_buf, param_len + 2); + + out_len = net_buf_linearize(pdu_buffer, sizeof(pdu_buffer) - 1, data->rx_buf, 0, sms_len); + pdu_buffer[out_len] = '\0'; + + data->rx_buf = net_buf_skip(data->rx_buf, sms_len); + + /* No buffer specified. */ + if (!mdata.sms_buffer) { + return 0; + } + + /* No space left in buffer. */ + if (mdata.sms_buffer_pos >= mdata.sms_buffer->nsms) { + return 0; + } + + sms = &mdata.sms_buffer->sms[mdata.sms_buffer_pos]; + + ret = mdm_decode_pdu(pdu_buffer, out_len, sms); + if (ret < 0) { + return 0; + } + + sms->stat = sms_stat; + sms->index = sms_index; + sms->data[sms->data_len] = '\0'; + + mdata.sms_buffer_pos++; + + return 0; +} + +int mdm_sim7080_read_sms(struct sim7080_sms_buffer *buffer) +{ + int ret; + struct modem_cmd cmds[] = { MODEM_CMD("+CMGL: ", on_cmd_cmgl, 4U, ",\r") }; + + mdata.sms_buffer = buffer; + mdata.sms_buffer_pos = 0; + + ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, cmds, ARRAY_SIZE(cmds), "AT+CMGL=4", + &mdata.sem_response, K_SECONDS(20)); + if (ret < 0) { + return -1; + } + + return mdata.sms_buffer_pos; +} + +int mdm_sim7080_delete_sms(uint16_t index) +{ + int ret; + char buf[sizeof("AT+CMGD=#####")] = { 0 }; + + ret = snprintk(buf, sizeof(buf), "AT+CMGD=%u", index); + if (ret < 0) { + return -1; + } + + ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, NULL, 0, buf, &mdata.sem_response, + K_SECONDS(5)); + if (ret < 0) { + return -1; + } + + return 0; +} diff --git a/drivers/modem/simcom/sim7080/sim7080_sock.c b/drivers/modem/simcom/sim7080/sim7080_sock.c new file mode 100644 index 0000000000000..b358de03d00e5 --- /dev/null +++ b/drivers/modem/simcom/sim7080/sim7080_sock.c @@ -0,0 +1,539 @@ +/* + * Copyright (C) 2025 metraTec GmbH + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT simcom_sim7080 + +#include +#include +LOG_MODULE_REGISTER(modem_simcom_sim7080_sock, CONFIG_MODEM_LOG_LEVEL); + +#include +#include "sim7080.h" + +static void socket_close(struct modem_socket *sock); + +/* + * Parses the +CAOPEN command and gives back the + * connect semaphore. + */ +MODEM_CMD_DEFINE(on_cmd_caopen) +{ + int result = atoi(argv[1]); + + LOG_INF("+CAOPEN: %d", result); + modem_cmd_handler_set_error(data, result); + return 0; +} + +/* + * Connects an modem socket. Protocol can either be TCP or UDP. + */ +static int offload_connect(void *obj, const struct sockaddr *addr, socklen_t addrlen) +{ + struct modem_socket *sock = (struct modem_socket *)obj; + uint16_t dst_port = 0; + char *protocol; + struct modem_cmd cmd[] = { MODEM_CMD("+CAOPEN: ", on_cmd_caopen, 2U, ",") }; + char buf[sizeof("AT+CAOPEN: #,#,#####," + "#xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxx.xxx.xxx.xxx#,####")]; + char ip_str[NET_IPV6_ADDR_LEN]; + int ret; + + /* Modem is not attached to the network. */ + if (sim7080_get_state() != SIM7080_STATE_NETWORKING) { + return -EAGAIN; + } + + if (modem_socket_is_allocated(&mdata.socket_config, sock) == false) { + LOG_ERR("Invalid socket id %d from fd %d", sock->id, sock->sock_fd); + errno = EINVAL; + return -1; + } + + if (sock->is_connected == true) { + LOG_ERR("Socket is already connected! id: %d, fd: %d", sock->id, sock->sock_fd); + errno = EISCONN; + return -1; + } + + /* get the destination port */ + if (addr->sa_family == AF_INET6) { + dst_port = ntohs(net_sin6(addr)->sin6_port); + } else if (addr->sa_family == AF_INET) { + dst_port = ntohs(net_sin(addr)->sin_port); + } + + /* Get protocol */ + protocol = (sock->type == SOCK_STREAM) ? "TCP" : "UDP"; + + ret = modem_context_sprint_ip_addr(addr, ip_str, sizeof(ip_str)); + if (ret != 0) { + LOG_ERR("Failed to format IP!"); + errno = ENOMEM; + return -1; + } + + ret = snprintk(buf, sizeof(buf), "AT+CAOPEN=%d,%d,\"%s\",\"%s\",%d", 0, sock->id, + protocol, ip_str, dst_port); + if (ret < 0) { + LOG_ERR("Failed to build connect command. ID: %d, FD: %d", sock->id, sock->sock_fd); + errno = ENOMEM; + return -1; + } + + ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, cmd, ARRAY_SIZE(cmd), buf, + &mdata.sem_response, MDM_CONNECT_TIMEOUT); + if (ret < 0) { + LOG_ERR("%s ret: %d", buf, ret); + socket_close(sock); + goto error; + } + + ret = modem_cmd_handler_get_error(&mdata.cmd_handler_data); + if (ret != 0) { + LOG_ERR("Closing the socket!"); + socket_close(sock); + goto error; + } + + sock->is_connected = true; + errno = 0; + return 0; +error: + errno = -ret; + return -1; +} + +/* + * Send data over a given socket. + * + * First we signal the module that we want to send data over a socket. + * This is done by sending AT+CASEND=,\r\n. + * If The module is ready to send data it will send back + * an UNTERMINATED prompt '> '. After that data can be sent to the modem. + * As terminating byte a STRG+Z (0x1A) is sent. The module will + * then send a OK or ERROR. + */ +static ssize_t offload_sendto(void *obj, const void *buf, size_t len, int flags, + const struct sockaddr *dest_addr, socklen_t addrlen) +{ + int ret; + struct modem_socket *sock = (struct modem_socket *)obj; + char send_buf[sizeof("AT+CASEND=#,####")] = { 0 }; + char ctrlz = 0x1A; + + /* Modem is not attached to the network. */ + if (sim7080_get_state() != SIM7080_STATE_NETWORKING) { + LOG_ERR("Modem currently not attached to the network!"); + return -EAGAIN; + } + + /* Do some sanity checks. */ + if (!buf || len == 0) { + errno = EINVAL; + return -1; + } + + /* Socket has to be connected. */ + if (!sock->is_connected) { + errno = ENOTCONN; + return -1; + } + + /* Only send up to MTU bytes. */ + if (len > MDM_MAX_DATA_LENGTH) { + len = MDM_MAX_DATA_LENGTH; + } + + ret = snprintk(send_buf, sizeof(send_buf), "AT+CASEND=%d,%ld", sock->id, (long)len); + if (ret < 0) { + LOG_ERR("Failed to build send command!!"); + errno = ENOMEM; + return -1; + } + + /* Make sure only one send can be done at a time. */ + k_sem_take(&mdata.cmd_handler_data.sem_tx_lock, K_FOREVER); + k_sem_reset(&mdata.sem_tx_ready); + + /* Send CASEND */ + mdata.current_sock_written = len; + ret = modem_cmd_send_nolock(&mctx.iface, &mctx.cmd_handler, NULL, 0U, send_buf, NULL, + K_NO_WAIT); + if (ret < 0) { + LOG_ERR("Failed to send CASEND!!"); + goto exit; + } + + /* Wait for '> ' */ + ret = k_sem_take(&mdata.sem_tx_ready, K_SECONDS(2)); + if (ret < 0) { + LOG_ERR("Timeout while waiting for tx"); + goto exit; + } + + /* Send data */ + modem_cmd_send_data_nolock(&mctx.iface, buf, len); + modem_cmd_send_data_nolock(&mctx.iface, &ctrlz, 1); + + /* Wait for the OK */ + k_sem_reset(&mdata.sem_response); + ret = k_sem_take(&mdata.sem_response, MDM_CMD_TIMEOUT); + if (ret < 0) { + LOG_ERR("Timeout waiting for OK"); + } + +exit: + k_sem_give(&mdata.cmd_handler_data.sem_tx_lock); + /* Data was successfully sent */ + + if (ret < 0) { + errno = -ret; + return -1; + } + + errno = 0; + return mdata.current_sock_written; +} + +/* + * Read data from a given socket. + * + * The response has the form +CARECV: ,data\r\nOK\r\n + */ +static int sockread_common(int sockfd, struct modem_cmd_handler_data *data, int socket_data_length, + uint16_t len) +{ + struct modem_socket *sock; + struct socket_read_data *sock_data; + int ret, packet_size; + + if (!len) { + LOG_ERR("Invalid length, aborting"); + return -EAGAIN; + } + + if (!data->rx_buf) { + LOG_ERR("Incorrect format! Ignoring data!"); + return -EINVAL; + } + + if (socket_data_length <= 0) { + LOG_ERR("Length error (%d)", socket_data_length); + return -EAGAIN; + } + + if (net_buf_frags_len(data->rx_buf) < socket_data_length) { + LOG_DBG("Not enough data -- wait!"); + return -EAGAIN; + } + + sock = modem_socket_from_fd(&mdata.socket_config, sockfd); + if (!sock) { + LOG_ERR("Socket not found! (%d)", sockfd); + ret = -EINVAL; + goto exit; + } + + sock_data = (struct socket_read_data *)sock->data; + if (!sock_data) { + LOG_ERR("Socket data not found! (%d)", sockfd); + ret = -EINVAL; + goto exit; + } + + ret = net_buf_linearize(sock_data->recv_buf, sock_data->recv_buf_len, data->rx_buf, 0, + (uint16_t)socket_data_length); + data->rx_buf = net_buf_skip(data->rx_buf, ret); + sock_data->recv_read_len = ret; + if (ret != socket_data_length) { + LOG_ERR("Total copied data is different then received data!" + " copied:%d vs. received:%d", + ret, socket_data_length); + ret = -EINVAL; + goto exit; + } + +exit: + /* Indication only sets length to a dummy value. */ + packet_size = modem_socket_next_packet_size(&mdata.socket_config, sock); + modem_socket_packet_size_update(&mdata.socket_config, sock, -packet_size); + return ret; +} + +/* + * Handler for carecv response. + */ +MODEM_CMD_DEFINE(on_cmd_carecv) +{ + return sockread_common(mdata.current_sock_fd, data, atoi(argv[0]), len); +} + +/* + * Read data from a given socket. + */ +static ssize_t offload_recvfrom(void *obj, void *buf, size_t max_len, int flags, + struct sockaddr *src_addr, socklen_t *addrlen) +{ + struct modem_socket *sock = (struct modem_socket *)obj; + char sendbuf[sizeof("AT+CARECV=##,####")]; + int ret, packet_size; + struct socket_read_data sock_data; + + struct modem_cmd data_cmd[] = { MODEM_CMD("+CARECV: ", on_cmd_carecv, 1U, ",") }; + + /* Modem is not attached to the network. */ + if (sim7080_get_state() != SIM7080_STATE_NETWORKING) { + LOG_ERR("Modem currently not attached to the network!"); + return -EAGAIN; + } + + if (!buf || max_len == 0) { + errno = EINVAL; + return -1; + } + + if (flags & ZSOCK_MSG_PEEK) { + errno = ENOTSUP; + return -1; + } + + packet_size = modem_socket_next_packet_size(&mdata.socket_config, sock); + if (!packet_size) { + if (flags & ZSOCK_MSG_DONTWAIT) { + errno = EAGAIN; + return -1; + } + + modem_socket_wait_data(&mdata.socket_config, sock); + packet_size = modem_socket_next_packet_size(&mdata.socket_config, sock); + } + + max_len = (max_len > MDM_MAX_DATA_LENGTH) ? MDM_MAX_DATA_LENGTH : max_len; + snprintk(sendbuf, sizeof(sendbuf), "AT+CARECV=%d,%zd", sock->id, max_len); + + memset(&sock_data, 0, sizeof(sock_data)); + sock_data.recv_buf = buf; + sock_data.recv_buf_len = max_len; + sock_data.recv_addr = src_addr; + sock->data = &sock_data; + mdata.current_sock_fd = sock->sock_fd; + + ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, data_cmd, ARRAY_SIZE(data_cmd), + sendbuf, &mdata.sem_response, MDM_CMD_TIMEOUT); + if (ret < 0) { + errno = -ret; + ret = -1; + goto exit; + } + + /* HACK: use dst address as src */ + if (src_addr && addrlen) { + *addrlen = sizeof(sock->dst); + memcpy(src_addr, &sock->dst, *addrlen); + } + + errno = 0; + ret = sock_data.recv_read_len; + +exit: + /* clear socket data */ + mdata.current_sock_fd = -1; + sock->data = NULL; + return ret; +} + +/* + * Sends messages to the modem. + */ +static ssize_t offload_sendmsg(void *obj, const struct msghdr *msg, int flags) +{ + struct modem_socket *sock = obj; + ssize_t sent = 0; + const char *buf; + size_t len; + int ret; + + /* Modem is not attached to the network. */ + if (sim7080_get_state() != SIM7080_STATE_NETWORKING) { + LOG_ERR("Modem currently not attached to the network!"); + return -EAGAIN; + } + + if (sock->type == SOCK_DGRAM) { + /* + * Current implementation only handles single contiguous fragment at a time, so + * prevent sending multiple datagrams. + */ + if (msghdr_non_empty_iov_count(msg) > 1) { + errno = EMSGSIZE; + return -1; + } + } + + for (int i = 0; i < msg->msg_iovlen; i++) { + buf = msg->msg_iov[i].iov_base; + len = msg->msg_iov[i].iov_len; + + while (len > 0) { + ret = offload_sendto(obj, buf, len, flags, msg->msg_name, msg->msg_namelen); + if (ret < 0) { + if (ret == -EAGAIN) { + k_sleep(K_SECONDS(1)); + } else { + return ret; + } + } else { + sent += ret; + buf += ret; + len -= ret; + } + } + } + + return sent; +} + +/* + * Closes a given socket. + */ +static void socket_close(struct modem_socket *sock) +{ + char buf[sizeof("AT+CACLOSE=##")]; + int ret; + + snprintk(buf, sizeof(buf), "AT+CACLOSE=%d", sock->id); + + ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, NULL, 0U, buf, &mdata.sem_response, + MDM_CMD_TIMEOUT); + if (ret < 0) { + LOG_ERR("%s ret: %d", buf, ret); + } + + modem_socket_put(&mdata.socket_config, sock->sock_fd); +} + +/* + * Offloads read by reading from a given socket. + */ +static ssize_t offload_read(void *obj, void *buffer, size_t count) +{ + return offload_recvfrom(obj, buffer, count, 0, NULL, 0); +} + +/* + * Offloads write by writing to a given socket. + */ +static ssize_t offload_write(void *obj, const void *buffer, size_t count) +{ + return offload_sendto(obj, buffer, count, 0, NULL, 0); +} + +/* + * Offloads close by terminating the connection and freeing the socket. + */ +static int offload_close(void *obj) +{ + struct modem_socket *sock = (struct modem_socket *)obj; + + /* Modem is not attached to the network. */ + if (sim7080_get_state() != SIM7080_STATE_NETWORKING) { + LOG_ERR("Modem currently not attached to the network!"); + return -EAGAIN; + } + + /* Make sure socket is allocated */ + if (modem_socket_is_allocated(&mdata.socket_config, sock) == false) { + return 0; + } + + /* Close the socket only if it is connected. */ + if (sock->is_connected) { + socket_close(sock); + } + + return 0; +} + +/* + * Polls a given socket. + */ +static int offload_poll(struct zsock_pollfd *fds, int nfds, int msecs) +{ + int i; + void *obj; + + /* Modem is not attached to the network. */ + if (sim7080_get_state() != SIM7080_STATE_NETWORKING) { + LOG_ERR("Modem currently not attached to the network!"); + return -EAGAIN; + } + + /* Only accept modem sockets. */ + for (i = 0; i < nfds; i++) { + if (fds[i].fd < 0) { + continue; + } + + /* If vtable matches, then it's modem socket. */ + obj = zvfs_get_fd_obj(fds[i].fd, + (const struct fd_op_vtable *)&offload_socket_fd_op_vtable, + EINVAL); + if (obj == NULL) { + return -1; + } + } + + return modem_socket_poll(&mdata.socket_config, fds, nfds, msecs); +} + +/* + * Offloads ioctl. Only supported ioctl is poll_offload. + */ +static int offload_ioctl(void *obj, unsigned int request, va_list args) +{ + switch (request) { + case ZFD_IOCTL_POLL_PREPARE: + return -EXDEV; + + case ZFD_IOCTL_POLL_UPDATE: + return -EOPNOTSUPP; + + case ZFD_IOCTL_POLL_OFFLOAD: { + /* Poll on the given socket. */ + struct zsock_pollfd *fds; + int nfds, timeout; + + fds = va_arg(args, struct zsock_pollfd *); + nfds = va_arg(args, int); + timeout = va_arg(args, int); + + return offload_poll(fds, nfds, timeout); + } + + default: + errno = EINVAL; + return -1; + } +} + +const struct socket_op_vtable offload_socket_fd_op_vtable = { + .fd_vtable = { + .read = offload_read, + .write = offload_write, + .close = offload_close, + .ioctl = offload_ioctl, + }, + .bind = NULL, + .connect = offload_connect, + .sendto = offload_sendto, + .recvfrom = offload_recvfrom, + .listen = NULL, + .accept = NULL, + .sendmsg = offload_sendmsg, + .getsockopt = NULL, + .setsockopt = NULL, +}; From 41b9287338c6a0a880b6368eb952ee120f623a30 Mon Sep 17 00:00:00 2001 From: Lukas Gehreke Date: Wed, 9 Apr 2025 12:08:25 +0200 Subject: [PATCH 02/28] drivers: modem: Using fixed baudrate for sim7080 On first boot a fixed baudrate is set for the sim7080. This makes power on detection more reliable. Signed-off-by: Lukas Gehreke --- drivers/modem/simcom/sim7080/Kconfig | 24 ++ drivers/modem/simcom/sim7080/sim7080.c | 316 +++++++++++++++------ drivers/modem/simcom/sim7080/sim7080.h | 21 +- drivers/modem/simcom/sim7080/sim7080_gps.c | 2 +- 4 files changed, 263 insertions(+), 100 deletions(-) diff --git a/drivers/modem/simcom/sim7080/Kconfig b/drivers/modem/simcom/sim7080/Kconfig index e8cee8f5fc12d..3d6d8f4a0fb68 100644 --- a/drivers/modem/simcom/sim7080/Kconfig +++ b/drivers/modem/simcom/sim7080/Kconfig @@ -49,6 +49,14 @@ config MODEM_SIMCOM_SIM7080_APN context. This value is specific to the network provider and may need to be changed. +config MODEM_SIMCOM_SIM7080_BAUDRATE + int "Baudrate for modem UART" + default 115200 + help + Set this to the baudrate the uart is using. On first startup + the modem is configured to use autobaud. The driver will then + configure the modem to use a fixed baudrate for faster startups. + choice MODEM_SIMCOM_SIM7080_RAT bool "Radio Access Technology Mode" default MODEM_SIMCOM_SIM7080_RAT_NB1 @@ -70,4 +78,20 @@ config MODEM_SIMCOM_SIM7080_RAT_GSM endchoice +choice + bool "Modem Boot Type" + default MODEM_SIMCOM_SIM7080_BOOT_TYPE_NORMAL + +config MODEM_SIMCOM_SIM7080_BOOT_TYPE_NORMAL + bool "Normal boot" + help + Boot the modem and attach to network + +config MODEM_SIMCOM_SIM7080_BOOT_TYPE_CONSTRAINED + bool "Constrained boot" + help + Check if the modem is operational and then power off + +endchoice + endif # MODEM_SIM7080 diff --git a/drivers/modem/simcom/sim7080/sim7080.c b/drivers/modem/simcom/sim7080/sim7080.c index bdcee36a12f4f..dc5b252445682 100644 --- a/drivers/modem/simcom/sim7080/sim7080.c +++ b/drivers/modem/simcom/sim7080/sim7080.c @@ -395,17 +395,17 @@ MODEM_CMD_DEFINE(on_cmd_cereg) return 0; } -MODEM_CMD_DEFINE(on_cmd_cpin) -{ - mdata.cpin_ready = strcmp(argv[0], "READY") == 0; - LOG_INF("CPIN: %d", mdata.cpin_ready); - return 0; -} - MODEM_CMD_DEFINE(on_cmd_cgatt) { - mdata.mdm_cgatt = atoi(argv[0]); - LOG_INF("CGATT: %d", mdata.mdm_cgatt); + int cgatt = atoi(argv[0]); + + if (cgatt) { + mdata.status_flags |= SIM7080_STATUS_FLAG_ATTACHED; + } else { + mdata.status_flags &= ~SIM7080_STATUS_FLAG_ATTACHED; + } + + LOG_INF("CGATT: %d", cgatt); return 0; } @@ -470,6 +470,36 @@ MODEM_CMD_DIRECT_DEFINE(on_cmd_tx_ready) return len; } +MODEM_CMD_DIRECT_DEFINE(on_urc_rdy) +{ + LOG_DBG("RDY received"); + mdata.status_flags |= SIM7080_STATUS_FLAG_POWER_ON; + k_sem_give(&mdata.boot_sem); + return 0; +} + +MODEM_CMD_DIRECT_DEFINE(on_urc_pwr_down) +{ + LOG_DBG("POWER DOWN received"); + mdata.status_flags &= ~SIM7080_STATUS_FLAG_POWER_ON; + k_sem_give(&mdata.boot_sem); + return 0; +} + +MODEM_CMD_DEFINE(on_urc_cpin) +{ + if (strcmp(argv[0], "READY") == 0) { + mdata.status_flags |= SIM7080_STATUS_FLAG_CPIN_READY; + } else { + mdata.status_flags &= ~SIM7080_STATUS_FLAG_CPIN_READY; + } + + k_sem_give(&mdata.boot_sem); + + LOG_INF("CPIN: %s", argv[0]); + return 0; +} + /* * Possible responses by the sim7080. */ @@ -489,6 +519,9 @@ static const struct modem_cmd unsolicited_cmds[] = { MODEM_CMD("+CADATAIND: ", on_urc_cadataind, 1U, ""), MODEM_CMD("+CASTATE: ", on_urc_castate, 2U, ","), MODEM_CMD("+FTPGET: 1,", on_urc_ftpget, 1U, ""), + MODEM_CMD("RDY", on_urc_rdy, 0U, ""), + MODEM_CMD("NORMAL POWER DOWN", on_urc_pwr_down, 0U, ""), + MODEM_CMD("+CPIN: ", on_urc_cpin, 1U, ","), }; /* @@ -509,7 +542,7 @@ static int modem_pdp_activate(void) struct modem_cmd cgatt_cmd[] = { MODEM_CMD("+CGATT: ", on_cmd_cgatt, 1U, "") }; counter = 0; - while (counter++ < MDM_MAX_CGATT_WAITS && mdata.mdm_cgatt != 1) { + while (counter++ < MDM_MAX_CGATT_WAITS && (mdata.status_flags & SIM7080_STATUS_FLAG_ATTACHED) == 0) { ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, cgatt_cmd, ARRAY_SIZE(cgatt_cmd), "AT+CGATT?", &mdata.sem_response, MDM_CMD_TIMEOUT); @@ -526,7 +559,8 @@ static int modem_pdp_activate(void) return -1; } - if (!mdata.cpin_ready || mdata.mdm_cgatt != 1) { + if ((mdata.status_flags & SIM7080_STATUS_FLAG_CPIN_READY) == 0 || + (mdata.status_flags & SIM7080_STATUS_FLAG_ATTACHED) == 0) { LOG_ERR("Fatal: Modem is not attached to GPRS network!!"); return -1; } @@ -591,41 +625,31 @@ static int modem_pdp_activate(void) */ static void modem_pwrkey(void) { + LOG_DBG("Pulling PWRKEY"); /* Power pin should be high for 1.5 seconds. */ gpio_pin_set_dt(&power_gpio, 1); k_sleep(K_MSEC(1500)); gpio_pin_set_dt(&power_gpio, 0); - k_sleep(K_SECONDS(5)); } -/* - * Commands to be sent at setup. - */ -static const struct setup_cmd setup_cmds[] = { - SETUP_CMD_NOHANDLE("ATH"), - SETUP_CMD("AT+CGMI", "", on_cmd_cgmi, 0U, ""), - SETUP_CMD("AT+CGMM", "", on_cmd_cgmm, 0U, ""), - SETUP_CMD("AT+CGMR", "", on_cmd_cgmr, 0U, ""), - SETUP_CMD("AT+CGSN", "", on_cmd_cgsn, 0U, ""), -#if defined(CONFIG_MODEM_SIM_NUMBERS) - SETUP_CMD("AT+CIMI", "", on_cmd_cimi, 0U, ""), - SETUP_CMD("AT+CCID", "", on_cmd_ccid, 0U, ""), -#endif /* defined(CONFIG_MODEM_SIM_NUMBERS) */ -#if defined(CONFIG_MODEM_SIMCOM_SIM7080_RAT_NB1) - SETUP_CMD_NOHANDLE("AT+CNMP=38"), - SETUP_CMD_NOHANDLE("AT+CMNB=2"), - SETUP_CMD_NOHANDLE("AT+CBANDCFG=\"NB-IOT\"," MDM_LTE_BANDS), -#endif /* defined(CONFIG_MODEM_SIMCOM_SIM7080_RAT_NB1) */ -#if defined(CONFIG_MODEM_SIMCOM_SIM7080_RAT_M1) - SETUP_CMD_NOHANDLE("AT+CNMP=38"), - SETUP_CMD_NOHANDLE("AT+CMNB=1"), - SETUP_CMD_NOHANDLE("AT+CBANDCFG=\"CAT-M\"," MDM_LTE_BANDS), -#endif /* defined(CONFIG_MODEM_SIMCOM_SIM7080_RAT_M1) */ -#if defined(CONFIG_MODEM_SIMCOM_SIM7080_RAT_GSM) - SETUP_CMD_NOHANDLE("AT+CNMP=13"), -#endif /* defined(CONFIG_MODEM_SIMCOM_SIM7080_RAT_GSM) */ - SETUP_CMD("AT+CPIN?", "+CPIN: ", on_cmd_cpin, 1U, ""), -}; +static int modem_set_baudrate(uint32_t baudrate) +{ + char buf[sizeof("AT+IPR=##########")] = {0}; + + int ret = snprintk(buf, sizeof(buf), "AT+IPR=%u", baudrate); + if (ret < 0) { + LOG_ERR("Failed to build command"); + goto out; + } + + ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, NULL, 0U, buf, &mdata.sem_response, K_SECONDS(2)); + if (ret != 0) { + LOG_ERR("Failed to set baudrate"); + } + +out: + return ret; +} /** * Performs the autobaud sequence until modem answers or limit is reached. @@ -634,37 +658,150 @@ static const struct setup_cmd setup_cmds[] = { */ int modem_autobaud(void) { - int boot_tries = 0; int counter = 0; - int ret; + int ret = -1; + + /* + * The sim7080 has a autobaud function. + * On startup multiple AT's are sent until + * a OK is received. + */ + counter = 0; + while (counter++ <= MDM_MAX_AUTOBAUD) { + ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, NULL, 0U, "AT", + &mdata.sem_response, K_MSEC(500)); + if (ret != 0) { + LOG_DBG("No response to autobaud AT"); + continue; + } + break; + } + return ret; +} + +/** + * Power on the modem and wait for operational sim card. + * + * @param allow_autobaud Allow autobaud functionality. + * @return 0 on success. Otherwise <0. + * + * @note Autobaud is only allowed during driver setup. + * In any other case a fixed baudrate should be used. + */ +static int modem_boot(bool allow_autobaud) +{ + uint8_t boot_tries = 0; + int ret = -1; + + /* Reset the status flags */ + mdata.status_flags = 0; + + /* Try boot multiple times in case modem was already on */ while (boot_tries++ <= MDM_BOOT_TRIES) { + + k_sem_reset(&mdata.boot_sem); + modem_pwrkey(); - /* - * The sim7080 has a autobaud function. - * On startup multiple AT's are sent until - * a OK is received. - */ - counter = 0; - while (counter < MDM_MAX_AUTOBAUD) { - ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, NULL, 0U, "AT", - &mdata.sem_response, K_MSEC(500)); - - /* OK was received. */ - if (ret == 0) { - /* Disable echo */ - return modem_cmd_send(&mctx.iface, &mctx.cmd_handler, NULL, 0U, - "ATE0", &mdata.sem_response, K_SECONDS(2)); + ret = k_sem_take(&mdata.boot_sem, K_SECONDS(5)); + if (ret == 0) { + if (mdata.status_flags & SIM7080_STATUS_FLAG_POWER_ON) { + LOG_INF("Modem booted"); + break; } - counter++; + LOG_INF("Modem turned off"); + k_sleep(K_SECONDS(1)); + continue; + } + + LOG_WRN("No modem response after pwrkey"); + + if (allow_autobaud == false) { + continue; + } + + LOG_INF("Trying autobaud"); + + ret = modem_autobaud(); + if (ret != 0) { + LOG_WRN("Autobaud failed"); + continue; + } + + /* Set baudrate to disable autobaud on next startup */ + ret = modem_set_baudrate(CONFIG_MODEM_SIMCOM_SIM7080_BAUDRATE); + if (ret != 0) { + LOG_ERR("Failed to disable echo"); + continue; + } + + /* Reset modem and wait for ready indication */ + ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, NULL, 0U, "AT+CFUN=1,1", + &mdata.sem_response, K_MSEC(500)); + if (ret != 0) { + LOG_ERR("Reset failed"); + break; } + + ret = k_sem_take(&mdata.boot_sem, K_SECONDS(5)); + if (ret != 0) { + LOG_ERR("No RDY received!"); + break; + } + + if ((mdata.status_flags & SIM7080_STATUS_FLAG_POWER_ON) == 0) { + LOG_ERR("Modem not powered"); + break; + } + + break; + } + + if (ret != 0) { + LOG_ERR("Modem boot failed!"); + goto out; } - return -1; + /* Wait for sim card status */ + ret = k_sem_take(&mdata.boot_sem, K_SECONDS(5)); + if (ret != 0) { + LOG_ERR("Timeout while waiting for sim status"); + goto out; + } + + if ((mdata.status_flags & SIM7080_STATUS_FLAG_CPIN_READY) == 0) { + LOG_ERR("Sim card not ready!"); + goto out; + } + + /* Disable echo on successful boot */ + ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, NULL, 0U, "ATE0", + &mdata.sem_response, K_MSEC(500)); + if (ret != 0) { + LOG_ERR("Disabling echo failed"); + goto out; + } + +out: + return ret; } +/* + * Commands to be sent at setup. + */ +static const struct setup_cmd setup_cmds[] = { + SETUP_CMD("AT+CGMI", "", on_cmd_cgmi, 0U, ""), + SETUP_CMD("AT+CGMM", "", on_cmd_cgmm, 0U, ""), + SETUP_CMD("AT+CGMR", "", on_cmd_cgmr, 0U, ""), + SETUP_CMD("AT+CGSN", "", on_cmd_cgsn, 0U, ""), +#if defined(CONFIG_MODEM_SIM_NUMBERS) + SETUP_CMD("AT+CIMI", "", on_cmd_cimi, 0U, ""), + SETUP_CMD("AT+CCID", "", on_cmd_ccid, 0U, ""), +#endif /* defined(CONFIG_MODEM_SIM_NUMBERS) */ +}; + /* * Does the modem setup by starting it and * bringing the modem to a PDP active state. @@ -672,11 +809,10 @@ int modem_autobaud(void) static int modem_setup(void) { int ret = 0; - int counter = 0; k_work_cancel_delayable(&mdata.rssi_query_work); - ret = modem_autobaud(); + ret = modem_boot(true); if (ret < 0) { LOG_ERR("Booting modem failed!!"); goto error; @@ -690,13 +826,13 @@ static int modem_setup(void) goto error; } - k_sleep(K_SECONDS(3)); + sim7080_change_state(SIM7080_STATE_IDLE); /* Wait for acceptable rssi values. */ modem_rssi_query_work(NULL); k_sleep(MDM_WAIT_FOR_RSSI_DELAY); - counter = 0; + int counter = 0; while (counter++ < MDM_WAIT_FOR_RSSI_COUNT && (mdata.mdm_rssi >= 0 || mdata.mdm_rssi <= -1000)) { modem_rssi_query_work(NULL); @@ -731,45 +867,44 @@ int mdm_sim7080_start_network(void) int mdm_sim7080_power_on(void) { - return modem_autobaud(); + return modem_boot(false); } int mdm_sim7080_power_off(void) { - int tries = 5; - int autobaud_tries; - int ret = 0; + int ret = -EALREADY; k_work_cancel_delayable(&mdata.rssi_query_work); - /* Check if module is already off. */ - ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, NULL, 0U, "AT", &mdata.sem_response, - K_MSEC(1000)); - if (ret < 0) { - sim7080_change_state(SIM7080_STATE_OFF); - return 0; + if ((mdata.status_flags & SIM7080_STATUS_FLAG_POWER_ON) == 0) { + LOG_WRN("Modem already off"); + goto out; } - while (tries--) { - modem_pwrkey(); + k_sem_reset(&mdata.boot_sem); - autobaud_tries = 5; + /* Pull pwrkey to turn off */ + modem_pwrkey(); - while (autobaud_tries--) { - ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, NULL, 0U, "AT", - &mdata.sem_response, K_MSEC(500)); - if (ret == 0) { - break; - } - } + /* Wait for power down indication */ + ret = k_sem_take(&mdata.boot_sem, K_SECONDS(5)); + if (ret != 0) { + LOG_ERR("No power down indication"); + goto out; + } - if (ret < 0) { - sim7080_change_state(SIM7080_STATE_OFF); - return 0; - } + if ((mdata.status_flags & SIM7080_STATUS_FLAG_POWER_ON) != 0) { + LOG_ERR("Modem not powered down!"); + ret = -1; + goto out; } - return -1; + LOG_DBG("Modem turned off"); + mdata.status_flags = 0; + sim7080_change_state(SIM7080_STATE_OFF); + +out: + return ret; } const char *mdm_sim7080_get_manufacturer(void) @@ -807,12 +942,13 @@ static int modem_init(const struct device *dev) k_sem_init(&mdata.sem_tx_ready, 0, 1); k_sem_init(&mdata.sem_dns, 0, 1); k_sem_init(&mdata.sem_ftp, 0, 1); + k_sem_init(&mdata.boot_sem, 0 ,1); k_work_queue_start(&modem_workq, modem_workq_stack, K_KERNEL_STACK_SIZEOF(modem_workq_stack), K_PRIO_COOP(7), NULL); /* Assume the modem is not registered to the network. */ mdata.mdm_registration = 0; - mdata.cpin_ready = false; + mdata.status_flags = 0; mdata.pdp_active = false; mdata.sms_buffer = NULL; @@ -825,7 +961,7 @@ static int modem_init(const struct device *dev) goto error; } - sim7080_change_state(SIM7080_STATE_INIT); + sim7080_change_state(SIM7080_STATE_OFF); /* Command handler. */ const struct modem_cmd_handler_config cmd_handler_config = { diff --git a/drivers/modem/simcom/sim7080/sim7080.h b/drivers/modem/simcom/sim7080/sim7080.h index 383091ec771d4..b08d2e7b5c009 100644 --- a/drivers/modem/simcom/sim7080/sim7080.h +++ b/drivers/modem/simcom/sim7080/sim7080.h @@ -45,7 +45,7 @@ #define MDM_MAX_AUTOBAUD 5 #define MDM_MAX_CEREG_WAITS 40 #define MDM_MAX_CGATT_WAITS 40 -#define MDM_BOOT_TRIES 4 +#define MDM_BOOT_TRIES 2 #define MDM_GNSS_PARSER_MAX_LEN 128 #define MDM_APN CONFIG_MODEM_SIMCOM_SIM7080_APN #define MDM_LTE_BANDS CONFIG_MODEM_SIMCOM_SIM7080_LTE_BANDS @@ -63,6 +63,7 @@ enum sim7080_state { SIM7080_STATE_INIT = 0, + SIM7080_STATE_IDLE, SIM7080_STATE_NETWORKING, SIM7080_STATE_GNSS, SIM7080_STATE_OFF, @@ -80,6 +81,13 @@ enum sim7080_ftp_connection_state { SIM7080_FTP_CONNECTION_STATE_ERROR, }; +enum sim7080_status_flags { + SIM7080_STATUS_FLAG_POWER_ON = 0x01, + SIM7080_STATUS_FLAG_CPIN_READY = 0x02, + SIM7080_STATUS_FLAG_ATTACHED = 0x04, + SIM7080_STATUS_FLAG_PDP_ACTIVE = 0x08, +}; + /* * Driver data. */ @@ -133,14 +141,8 @@ struct sim7080_data { * Network registration of the modem. */ uint8_t mdm_registration; - /* - * Whether gprs is attached or detached. - */ - uint8_t mdm_cgatt; - /* - * If the sim card is ready or not. - */ - bool cpin_ready; + /* Modem status flags */ + uint32_t status_flags; /* * Flag if the PDP context is active. */ @@ -165,6 +167,7 @@ struct sim7080_data { struct k_sem sem_tx_ready; struct k_sem sem_dns; struct k_sem sem_ftp; + struct k_sem boot_sem; }; /* diff --git a/drivers/modem/simcom/sim7080/sim7080_gps.c b/drivers/modem/simcom/sim7080/sim7080_gps.c index 6e83ca7ae817e..61ab3eff6f22d 100644 --- a/drivers/modem/simcom/sim7080/sim7080_gps.c +++ b/drivers/modem/simcom/sim7080/sim7080_gps.c @@ -272,7 +272,7 @@ int mdm_sim7080_start_gnss(void) sim7080_change_state(SIM7080_STATE_INIT); k_work_cancel_delayable(&mdata.rssi_query_work); - ret = modem_autobaud(); + ret = mdm_sim7080_power_on(); if (ret < 0) { LOG_ERR("Failed to start modem!!"); return -1; From 3eb7c2e51913fc89cf6d28a66404d7193e53158f Mon Sep 17 00:00:00 2001 From: Lukas Gehreke Date: Tue, 15 Apr 2025 15:11:24 +0200 Subject: [PATCH 03/28] drivers: modem: Added modem model check to sim7080 driver Check the modem model on boot. Signed-off-by: Lukas Gehreke --- drivers/modem/simcom/sim7080/sim7080.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/modem/simcom/sim7080/sim7080.c b/drivers/modem/simcom/sim7080/sim7080.c index dc5b252445682..782dbe4b8f689 100644 --- a/drivers/modem/simcom/sim7080/sim7080.c +++ b/drivers/modem/simcom/sim7080/sim7080.c @@ -826,6 +826,12 @@ static int modem_setup(void) goto error; } + if (strcmp(mdata.mdm_model, "SIMCOM_SIM7080") != 0) { + LOG_ERR("Wrong modem model: %s", mdata.mdm_model); + ret = -EINVAL; + goto error; + } + sim7080_change_state(SIM7080_STATE_IDLE); /* Wait for acceptable rssi values. */ From aef671bfa88f7c12a82e12675ee390b195b35236 Mon Sep 17 00:00:00 2001 From: Lukas Gehreke Date: Tue, 15 Apr 2025 15:58:46 +0200 Subject: [PATCH 04/28] drivers: modem: sim7080: own file for pdp handling PDP context handling takes place in separate source file for better readability. Signed-off-by: Lukas Gehreke --- drivers/modem/simcom/sim7080/CMakeLists.txt | 1 + drivers/modem/simcom/sim7080/sim7080.c | 222 +--------------- drivers/modem/simcom/sim7080/sim7080.h | 11 +- drivers/modem/simcom/sim7080/sim7080_pdp.c | 266 ++++++++++++++++++++ 4 files changed, 286 insertions(+), 214 deletions(-) create mode 100644 drivers/modem/simcom/sim7080/sim7080_pdp.c diff --git a/drivers/modem/simcom/sim7080/CMakeLists.txt b/drivers/modem/simcom/sim7080/CMakeLists.txt index 1fbdf49046946..bb2ee13050820 100644 --- a/drivers/modem/simcom/sim7080/CMakeLists.txt +++ b/drivers/modem/simcom/sim7080/CMakeLists.txt @@ -8,6 +8,7 @@ zephyr_library_include_directories(${ZEPHYR_BASE}/subsys/net/ip) zephyr_library_include_directories(${ZEPHYR_BASE}/subsys/net/lib/sockets) zephyr_library_sources( sim7080.c + sim7080_pdp.c sim7080_dns.c sim7080_sock.c sim7080_sms.c diff --git a/drivers/modem/simcom/sim7080/sim7080.c b/drivers/modem/simcom/sim7080/sim7080.c index 782dbe4b8f689..26e1fa65c27b4 100644 --- a/drivers/modem/simcom/sim7080/sim7080.c +++ b/drivers/modem/simcom/sim7080/sim7080.c @@ -17,7 +17,7 @@ struct sim7080_data mdata; struct modem_context mctx; static struct k_thread modem_rx_thread; -static struct k_work_q modem_workq; +struct k_work_q modem_workq; static K_KERNEL_STACK_DEFINE(modem_rx_stack, CONFIG_MODEM_SIMCOM_SIM7080_RX_STACK_SIZE); static K_KERNEL_STACK_DEFINE(modem_workq_stack, CONFIG_MODEM_SIMCOM_SIM7080_RX_WORKQ_STACK_SIZE); @@ -26,11 +26,6 @@ NET_BUF_POOL_DEFINE(mdm_recv_pool, MDM_RECV_MAX_BUF, MDM_RECV_BUF_SIZE, 0, NULL) /* pin settings */ static const struct gpio_dt_spec power_gpio = GPIO_DT_SPEC_INST_GET(0, mdm_power_gpios); -struct modem_context *sim7080_get_mctx(void) -{ - return &mctx; -} - static inline uint32_t hash32(char *str, int len) { #define HASH_MULTIPLIER 37 @@ -183,9 +178,15 @@ MODEM_CMD_DEFINE(on_cmd_exterror) */ MODEM_CMD_DEFINE(on_urc_app_pdp) { - mdata.pdp_active = strcmp(argv[1], "ACTIVE") == 0; - LOG_INF("PDP context: %u", mdata.pdp_active); - k_sem_give(&mdata.sem_response); + bool active = strcmp(argv[1], "ACTIVE") == 0; + if (active) { + mdata.status_flags |= SIM7080_STATUS_FLAG_PDP_ACTIVE; + } else { + mdata.status_flags &= ~SIM7080_STATUS_FLAG_PDP_ACTIVE; + } + + LOG_INF("PDP context: %u", active); + k_sem_give(&mdata.pdp_sem); return 0; } @@ -385,82 +386,6 @@ MODEM_CMD_DEFINE(on_cmd_ccid) } #endif /* defined(CONFIG_MODEM_SIM_NUMBERS) */ -/* - * Parses the non urc C(E)REG and updates registration status. - */ -MODEM_CMD_DEFINE(on_cmd_cereg) -{ - mdata.mdm_registration = atoi(argv[1]); - LOG_INF("CREG: %u", mdata.mdm_registration); - return 0; -} - -MODEM_CMD_DEFINE(on_cmd_cgatt) -{ - int cgatt = atoi(argv[0]); - - if (cgatt) { - mdata.status_flags |= SIM7080_STATUS_FLAG_ATTACHED; - } else { - mdata.status_flags &= ~SIM7080_STATUS_FLAG_ATTACHED; - } - - LOG_INF("CGATT: %d", cgatt); - return 0; -} - -/* - * Handler for RSSI query. - * - * +CSQ: , - * rssi: 0,-115dBm; 1,-111dBm; 2...30,-110...-54dBm; 31,-52dBm or greater. - * 99, ukn - * ber: Not used. - */ -MODEM_CMD_DEFINE(on_cmd_csq) -{ - int rssi = atoi(argv[0]); - - if (rssi == 0) { - mdata.mdm_rssi = -115; - } else if (rssi == 1) { - mdata.mdm_rssi = -111; - } else if (rssi > 1 && rssi < 31) { - mdata.mdm_rssi = -114 + 2 * rssi; - } else if (rssi == 31) { - mdata.mdm_rssi = -52; - } else { - mdata.mdm_rssi = -1000; - } - - LOG_INF("RSSI: %d", mdata.mdm_rssi); - return 0; -} - -/* - * Queries modem RSSI. - * - * If a work queue parameter is provided query work will - * be scheduled. Otherwise rssi is queried once. - */ -static void modem_rssi_query_work(struct k_work *work) -{ - struct modem_cmd cmd[] = { MODEM_CMD("+CSQ: ", on_cmd_csq, 2U, ",") }; - static char *send_cmd = "AT+CSQ"; - int ret; - - ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, cmd, ARRAY_SIZE(cmd), send_cmd, - &mdata.sem_response, MDM_CMD_TIMEOUT); - if (ret < 0) { - LOG_ERR("AT+CSQ ret:%d", ret); - } - - if (work) { - k_work_reschedule_for_queue(&modem_workq, &mdata.rssi_query_work, - K_SECONDS(RSSI_TIMEOUT_SECS)); - } -} - /* * Unlock the tx ready semaphore if '> ' is received. */ @@ -524,102 +449,6 @@ static const struct modem_cmd unsolicited_cmds[] = { MODEM_CMD("+CPIN: ", on_urc_cpin, 1U, ","), }; -/* - * Activates the pdp context - */ -static int modem_pdp_activate(void) -{ - int counter; - int ret = 0; -#if defined(CONFIG_MODEM_SIMCOM_SIM7080_RAT_GSM) - const char *buf = "AT+CREG?"; - struct modem_cmd cmds[] = { MODEM_CMD("+CREG: ", on_cmd_cereg, 2U, ",") }; -#else - const char *buf = "AT+CEREG?"; - struct modem_cmd cmds[] = { MODEM_CMD("+CEREG: ", on_cmd_cereg, 2U, ",") }; -#endif /* defined(CONFIG_MODEM_SIMCOM_SIM7080_RAT_GSM) */ - - struct modem_cmd cgatt_cmd[] = { MODEM_CMD("+CGATT: ", on_cmd_cgatt, 1U, "") }; - - counter = 0; - while (counter++ < MDM_MAX_CGATT_WAITS && (mdata.status_flags & SIM7080_STATUS_FLAG_ATTACHED) == 0) { - ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, cgatt_cmd, - ARRAY_SIZE(cgatt_cmd), "AT+CGATT?", &mdata.sem_response, - MDM_CMD_TIMEOUT); - if (ret < 0) { - LOG_ERR("Failed to query cgatt!!"); - return -1; - } - - k_sleep(K_SECONDS(1)); - } - - if (counter >= MDM_MAX_CGATT_WAITS) { - LOG_WRN("Network attach failed!!"); - return -1; - } - - if ((mdata.status_flags & SIM7080_STATUS_FLAG_CPIN_READY) == 0 || - (mdata.status_flags & SIM7080_STATUS_FLAG_ATTACHED) == 0) { - LOG_ERR("Fatal: Modem is not attached to GPRS network!!"); - return -1; - } - - LOG_INF("Waiting for network"); - - /* Wait until the module is registered to the network. - * Registration will be set by urc. - */ - counter = 0; - while (counter++ < MDM_MAX_CEREG_WAITS && mdata.mdm_registration != 1 && - mdata.mdm_registration != 5) { - ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, cmds, ARRAY_SIZE(cmds), buf, - &mdata.sem_response, MDM_CMD_TIMEOUT); - if (ret < 0) { - LOG_ERR("Failed to query registration!!"); - return -1; - } - - k_sleep(K_SECONDS(1)); - } - - if (counter >= MDM_MAX_CEREG_WAITS) { - LOG_WRN("Network registration failed!"); - ret = -1; - goto error; - } - - /* Set dual stack mode (IPv4/IPv6) */ - ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, NULL, 0, "AT+CNCFG=0,0", - &mdata.sem_response, MDM_CMD_TIMEOUT); - if (ret < 0) { - LOG_ERR("Could not configure pdp context!"); - goto error; - } - - /* - * Now activate the pdp context and wait for confirmation. - */ - ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, NULL, 0, "AT+CNACT=0,1", - &mdata.sem_response, MDM_CMD_TIMEOUT); - if (ret < 0) { - LOG_ERR("Could not activate PDP context."); - goto error; - } - - ret = k_sem_take(&mdata.sem_response, MDM_PDP_TIMEOUT); - if (ret < 0 || mdata.pdp_active == false) { - LOG_ERR("Failed to activate PDP context."); - ret = -1; - goto error; - } - - LOG_INF("Network active."); - -error: - return ret; -} - /* * Toggles the modems power pin. */ @@ -834,32 +663,7 @@ static int modem_setup(void) sim7080_change_state(SIM7080_STATE_IDLE); - /* Wait for acceptable rssi values. */ - modem_rssi_query_work(NULL); - k_sleep(MDM_WAIT_FOR_RSSI_DELAY); - - int counter = 0; - while (counter++ < MDM_WAIT_FOR_RSSI_COUNT && - (mdata.mdm_rssi >= 0 || mdata.mdm_rssi <= -1000)) { - modem_rssi_query_work(NULL); - k_sleep(MDM_WAIT_FOR_RSSI_DELAY); - } - - if (mdata.mdm_rssi >= 0 || mdata.mdm_rssi <= -1000) { - LOG_ERR("Network not reachable!!"); - ret = -ENETUNREACH; - goto error; - } - - ret = modem_pdp_activate(); - if (ret < 0) { - goto error; - } - - k_work_reschedule_for_queue(&modem_workq, &mdata.rssi_query_work, - K_SECONDS(RSSI_TIMEOUT_SECS)); - - sim7080_change_state(SIM7080_STATE_NETWORKING); + ret = sim7080_pdp_activate(); error: return ret; @@ -949,13 +753,13 @@ static int modem_init(const struct device *dev) k_sem_init(&mdata.sem_dns, 0, 1); k_sem_init(&mdata.sem_ftp, 0, 1); k_sem_init(&mdata.boot_sem, 0 ,1); + k_sem_init(&mdata.pdp_sem, 0, 1); k_work_queue_start(&modem_workq, modem_workq_stack, K_KERNEL_STACK_SIZEOF(modem_workq_stack), K_PRIO_COOP(7), NULL); /* Assume the modem is not registered to the network. */ mdata.mdm_registration = 0; mdata.status_flags = 0; - mdata.pdp_active = false; mdata.sms_buffer = NULL; mdata.sms_buffer_pos = 0; @@ -1038,7 +842,7 @@ static int modem_init(const struct device *dev) modem_rx, NULL, NULL, NULL, K_PRIO_COOP(7), 0, K_NO_WAIT); /* Init RSSI query */ - k_work_init_delayable(&mdata.rssi_query_work, modem_rssi_query_work); + k_work_init_delayable(&mdata.rssi_query_work, sim7080_rssi_query_work); return modem_setup(); error: diff --git a/drivers/modem/simcom/sim7080/sim7080.h b/drivers/modem/simcom/sim7080/sim7080.h index b08d2e7b5c009..bae1e1c2fd954 100644 --- a/drivers/modem/simcom/sim7080/sim7080.h +++ b/drivers/modem/simcom/sim7080/sim7080.h @@ -143,10 +143,6 @@ struct sim7080_data { uint8_t mdm_registration; /* Modem status flags */ uint32_t status_flags; - /* - * Flag if the PDP context is active. - */ - bool pdp_active; /* SMS buffer structure provided by read. */ struct sim7080_sms_buffer *sms_buffer; /* Position in the sms buffer. */ @@ -168,6 +164,7 @@ struct sim7080_data { struct k_sem sem_dns; struct k_sem sem_ftp; struct k_sem boot_sem; + struct k_sem pdp_sem; }; /* @@ -187,11 +184,15 @@ extern struct sim7080_data mdata; extern struct modem_context mctx; extern const struct socket_op_vtable offload_socket_fd_op_vtable; extern const struct socket_dns_offload offload_dns_ops; +extern struct k_work_q modem_workq; + +extern void sim7080_rssi_query_work(struct k_work *work); enum sim7080_state sim7080_get_state(void); void sim7080_change_state(enum sim7080_state state); -int modem_autobaud(void); +int sim7080_pdp_activate(void); +int sim7080_pdp_deactivate(void); #endif /* SIMCOM_SIM7080_H */ diff --git a/drivers/modem/simcom/sim7080/sim7080_pdp.c b/drivers/modem/simcom/sim7080/sim7080_pdp.c new file mode 100644 index 0000000000000..88f225552e8ed --- /dev/null +++ b/drivers/modem/simcom/sim7080/sim7080_pdp.c @@ -0,0 +1,266 @@ +/* + * Copyright (C) 2025 metraTec GmbH + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +LOG_MODULE_REGISTER(modem_simcom_sim7080_pdp, CONFIG_MODEM_LOG_LEVEL); + +#include "sim7080.h" + +static const struct setup_cmd band_setup_cmds[] = { + #if defined(CONFIG_MODEM_SIMCOM_SIM7080_RAT_NB1) + SETUP_CMD_NOHANDLE("AT+CNMP=38"), + SETUP_CMD_NOHANDLE("AT+CMNB=2"), + SETUP_CMD_NOHANDLE("AT+CBANDCFG=\"NB-IOT\"," MDM_LTE_BANDS), + #endif /* defined(CONFIG_MODEM_SIMCOM_SIM7080_RAT_NB1) */ + #if defined(CONFIG_MODEM_SIMCOM_SIM7080_RAT_M1) + SETUP_CMD_NOHANDLE("AT+CNMP=38"), + SETUP_CMD_NOHANDLE("AT+CMNB=1"), + SETUP_CMD_NOHANDLE("AT+CBANDCFG=\"CAT-M\"," MDM_LTE_BANDS), + #endif /* defined(CONFIG_MODEM_SIMCOM_SIM7080_RAT_M1) */ + #if defined(CONFIG_MODEM_SIMCOM_SIM7080_RAT_GSM) + SETUP_CMD_NOHANDLE("AT+CNMP=13"), + #endif /* defined(CONFIG_MODEM_SIMCOM_SIM7080_RAT_GSM) */ +}; + +/* + * Handler for RSSI query. + * + * +CSQ: , + * rssi: 0,-115dBm; 1,-111dBm; 2...30,-110...-54dBm; 31,-52dBm or greater. + * 99, ukn + * ber: Not used. + */ +MODEM_CMD_DEFINE(on_cmd_csq) +{ + int rssi = atoi(argv[0]); + + if (rssi == 0) { + mdata.mdm_rssi = -115; + } else if (rssi == 1) { + mdata.mdm_rssi = -111; + } else if (rssi > 1 && rssi < 31) { + mdata.mdm_rssi = -114 + 2 * rssi; + } else if (rssi == 31) { + mdata.mdm_rssi = -52; + } else { + mdata.mdm_rssi = -1000; + } + + LOG_INF("RSSI: %d", mdata.mdm_rssi); + return 0; +} + +/* + * Queries modem RSSI. + * + * If a work queue parameter is provided query work will + * be scheduled. Otherwise rssi is queried once. + */ +void sim7080_rssi_query_work(struct k_work *work) +{ + struct modem_cmd cmd[] = { MODEM_CMD("+CSQ: ", on_cmd_csq, 2U, ",") }; + static char *send_cmd = "AT+CSQ"; + int ret; + + ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, cmd, ARRAY_SIZE(cmd), send_cmd, + &mdata.sem_response, MDM_CMD_TIMEOUT); + if (ret < 0) { + LOG_ERR("AT+CSQ ret:%d", ret); + } + + if (work) { + k_work_reschedule_for_queue(&modem_workq, &mdata.rssi_query_work, + K_SECONDS(RSSI_TIMEOUT_SECS)); + } +} + +/* + * Parses the non urc C(E)REG and updates registration status. + */ +MODEM_CMD_DEFINE(on_cmd_cereg) +{ + mdata.mdm_registration = atoi(argv[1]); + LOG_INF("CREG: %u", mdata.mdm_registration); + return 0; +} + +MODEM_CMD_DEFINE(on_cmd_cgatt) +{ + int cgatt = atoi(argv[0]); + + if (cgatt) { + mdata.status_flags |= SIM7080_STATUS_FLAG_ATTACHED; + } else { + mdata.status_flags &= ~SIM7080_STATUS_FLAG_ATTACHED; + } + + LOG_INF("CGATT: %d", cgatt); + return 0; +} + +int sim7080_pdp_activate(void) +{ + int counter; + int ret = 0; +#if defined(CONFIG_MODEM_SIMCOM_SIM7080_RAT_GSM) + const char *buf = "AT+CREG?"; + struct modem_cmd cmds[] = { MODEM_CMD("+CREG: ", on_cmd_cereg, 2U, ",") }; +#else + const char *buf = "AT+CEREG?"; + struct modem_cmd cmds[] = { MODEM_CMD("+CEREG: ", on_cmd_cereg, 2U, ",") }; +#endif /* defined(CONFIG_MODEM_SIMCOM_SIM7080_RAT_GSM) */ + + /* Set the preferred bands */ + ret = modem_cmd_handler_setup_cmds(&mctx.iface, &mctx.cmd_handler, band_setup_cmds, + ARRAY_SIZE(band_setup_cmds), &mdata.sem_response, + MDM_REGISTRATION_TIMEOUT); + if (ret != 0) { + LOG_ERR("Failed to send band setup commands"); + goto error; + } + + /* Wait for acceptable rssi values. */ + sim7080_rssi_query_work(NULL); + + counter = 0; + while (counter++ < MDM_WAIT_FOR_RSSI_COUNT && + (mdata.mdm_rssi >= 0 || mdata.mdm_rssi <= -1000)) { + k_sleep(MDM_WAIT_FOR_RSSI_DELAY); + sim7080_rssi_query_work(NULL); + } + + if (mdata.mdm_rssi >= 0 || mdata.mdm_rssi <= -1000) { + LOG_ERR("No valid RSSI reached"); + ret = -ENETUNREACH; + goto error; + } + + struct modem_cmd cgatt_cmd[] = { MODEM_CMD("+CGATT: ", on_cmd_cgatt, 1U, "") }; + + ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, cgatt_cmd, + ARRAY_SIZE(cgatt_cmd), "AT+CGATT?", &mdata.sem_response, + MDM_CMD_TIMEOUT); + if (ret < 0) { + LOG_ERR("Failed to query cgatt"); + goto error; + } + + counter = 0; + while (counter++ < MDM_MAX_CGATT_WAITS && (mdata.status_flags & SIM7080_STATUS_FLAG_ATTACHED) == 0) { + ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, cgatt_cmd, + ARRAY_SIZE(cgatt_cmd), "AT+CGATT?", &mdata.sem_response, + MDM_CMD_TIMEOUT); + if (ret < 0) { + LOG_ERR("Failed to query cgatt"); + goto error; + } + + k_sleep(K_SECONDS(1)); + } + + if ((mdata.status_flags & SIM7080_STATUS_FLAG_CPIN_READY) == 0 || + (mdata.status_flags & SIM7080_STATUS_FLAG_ATTACHED) == 0) { + LOG_ERR("Fatal: Modem is not attached to GPRS network"); + ret = -ENETUNREACH; + goto error; + } + + LOG_INF("Waiting for network"); + + /* Wait until the module is registered to the network. + * Registration will be set by urc. + */ + ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, cmds, ARRAY_SIZE(cmds), buf, + &mdata.sem_response, MDM_CMD_TIMEOUT); + if (ret < 0) { + LOG_ERR("Failed to query registration"); + goto error; + } + + counter = 0; + while (counter++ < MDM_MAX_CEREG_WAITS && mdata.mdm_registration != 1 && + mdata.mdm_registration != 5) { + k_sleep(K_SECONDS(1)); + + ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, cmds, ARRAY_SIZE(cmds), buf, + &mdata.sem_response, MDM_CMD_TIMEOUT); + if (ret < 0) { + LOG_ERR("Failed to query registration"); + goto error; + } + } + + if (mdata.mdm_registration != 1 && mdata.mdm_registration != 5) { + LOG_WRN("Network registration failed!"); + ret = -ENETUNREACH; + goto error; + } + + /* Set dual stack mode (IPv4/IPv6) */ + ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, NULL, 0, "AT+CNCFG=0,0", + &mdata.sem_response, MDM_CMD_TIMEOUT); + if (ret < 0) { + LOG_ERR("Could not configure pdp context!"); + goto error; + } + + /* + * Now activate the pdp context and wait for confirmation. + */ + ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, NULL, 0, "AT+CNACT=0,1", + &mdata.sem_response, MDM_CMD_TIMEOUT); + if (ret < 0) { + LOG_ERR("Could not activate PDP context."); + goto error; + } + + k_sem_reset(&mdata.pdp_sem); + ret = k_sem_take(&mdata.pdp_sem, MDM_PDP_TIMEOUT); + if (ret < 0 || (mdata.status_flags & SIM7080_STATUS_FLAG_PDP_ACTIVE) == 0) { + LOG_ERR("Failed to activate PDP context."); + ret = -ENETUNREACH; + goto error; + } + + LOG_INF("Network active."); + sim7080_change_state(SIM7080_STATE_NETWORKING); + + k_work_reschedule_for_queue(&modem_workq, &mdata.rssi_query_work, + K_SECONDS(RSSI_TIMEOUT_SECS)); + +error: + return ret; +} + +int sim7080_pdp_deactivate(void) +{ + int ret = -EINVAL; + + if (sim7080_get_state() != SIM7080_STATE_NETWORKING) { + LOG_WRN("Cannot deactivate pdp context in state: %d", sim7080_get_state()); + goto out; + } + + ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, NULL, 0, "AT+CNACT=0,0", + &mdata.sem_response, MDM_CMD_TIMEOUT); + if (ret < 0) { + LOG_ERR("Could not deactivate PDP context."); + goto out; + } + + k_sem_reset(&mdata.pdp_sem); + ret = k_sem_take(&mdata.pdp_sem, MDM_PDP_TIMEOUT); + if (ret < 0 || (mdata.status_flags & SIM7080_STATUS_FLAG_PDP_ACTIVE) != 0) { + LOG_ERR("PDP response timed out"); + ret = -EIO; + } + + LOG_INF("PDP context deactivated"); + sim7080_change_state(SIM7080_STATE_IDLE); + +out: + return ret; +} From b25f1bb210abcaf1b404e661a0e907c6ad586e57 Mon Sep 17 00:00:00 2001 From: Lukas Gehreke Date: Wed, 23 Apr 2025 14:04:49 +0200 Subject: [PATCH 05/28] drivers: modem: Implemented boot modes for sim7080 Modem can either attach to network after initialization or be turned off. Signed-off-by: Lukas Gehreke --- drivers/modem/simcom/sim7080/sim7080.c | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/drivers/modem/simcom/sim7080/sim7080.c b/drivers/modem/simcom/sim7080/sim7080.c index 26e1fa65c27b4..a552e47da24dd 100644 --- a/drivers/modem/simcom/sim7080/sim7080.c +++ b/drivers/modem/simcom/sim7080/sim7080.c @@ -613,6 +613,8 @@ static int modem_boot(bool allow_autobaud) goto out; } + sim7080_change_state(SIM7080_STATE_IDLE); + out: return ret; } @@ -661,9 +663,13 @@ static int modem_setup(void) goto error; } - sim7080_change_state(SIM7080_STATE_IDLE); - +#if IS_ENABLED(CONFIG_MODEM_SIMCOM_SIM7080_BOOT_TYPE_CONSTRAINED) + ret = mdm_sim7080_power_off(); +#elif IS_ENABLED(CONFIG_MODEM_SIMCOM_SIM7080_BOOT_TYPE_NORMAL) ret = sim7080_pdp_activate(); +#else +#error No boot type selected +#endif error: return ret; @@ -671,8 +677,17 @@ static int modem_setup(void) int mdm_sim7080_start_network(void) { - sim7080_change_state(SIM7080_STATE_INIT); - return modem_setup(); + int ret = -EINVAL; + + if (sim7080_get_state() != SIM7080_STATE_IDLE) { + LOG_WRN("Can only activate networking from idle state"); + goto out; + } + + ret = sim7080_pdp_activate(); + +out: + return ret; } int mdm_sim7080_power_on(void) From f9aa90abe558cd8a2d89455025d315f49b06f4c3 Mon Sep 17 00:00:00 2001 From: Lukas Gehreke Date: Thu, 24 Apr 2025 09:54:09 +0200 Subject: [PATCH 06/28] drivers: modem: sim7080: added stop functions for network and gnss Network and gnss can be disabled with stop functions instead of power cycling the modem. The start functions will also not power cycle the modem. In order to call the start functions the modem needs to be booted. Signed-off-by: Lukas Gehreke --- drivers/modem/simcom/sim7080/sim7080.c | 25 +++++++++- drivers/modem/simcom/sim7080/sim7080_gps.c | 50 +++++++++++++++---- drivers/modem/simcom/sim7080/sim7080_pdp.c | 2 + include/zephyr/drivers/modem/simcom-sim7080.h | 20 +++++++- 4 files changed, 84 insertions(+), 13 deletions(-) diff --git a/drivers/modem/simcom/sim7080/sim7080.c b/drivers/modem/simcom/sim7080/sim7080.c index a552e47da24dd..4f8f786e6ae0e 100644 --- a/drivers/modem/simcom/sim7080/sim7080.c +++ b/drivers/modem/simcom/sim7080/sim7080.c @@ -677,10 +677,14 @@ static int modem_setup(void) int mdm_sim7080_start_network(void) { - int ret = -EINVAL; + int ret = -EALREADY; - if (sim7080_get_state() != SIM7080_STATE_IDLE) { + if (sim7080_get_state() == SIM7080_STATE_NETWORKING) { + LOG_WRN("Network already active"); + goto out; + } else if (sim7080_get_state() != SIM7080_STATE_IDLE) { LOG_WRN("Can only activate networking from idle state"); + ret = -EINVAL; goto out; } @@ -690,6 +694,23 @@ int mdm_sim7080_start_network(void) return ret; } +int mdm_sim7080_stop_network(void) +{ + int ret = -EINVAL; + + if (sim7080_get_state() != SIM7080_STATE_NETWORKING) { + LOG_WRN("Modem not in networking state"); + goto out; + } + + //TODO: close sockets + + ret = sim7080_pdp_deactivate(); + +out: + return ret; +} + int mdm_sim7080_power_on(void) { return modem_boot(false); diff --git a/drivers/modem/simcom/sim7080/sim7080_gps.c b/drivers/modem/simcom/sim7080/sim7080_gps.c index 61ab3eff6f22d..03d3c9a9369c2 100644 --- a/drivers/modem/simcom/sim7080/sim7080_gps.c +++ b/drivers/modem/simcom/sim7080/sim7080_gps.c @@ -267,23 +267,53 @@ int mdm_sim7080_query_gnss(struct sim7080_gnss_data *data) int mdm_sim7080_start_gnss(void) { - int ret; - - sim7080_change_state(SIM7080_STATE_INIT); - k_work_cancel_delayable(&mdata.rssi_query_work); + int ret = -EALREADY; + + if (sim7080_get_state() == SIM7080_STATE_GNSS) { + LOG_WRN("Modem already in gnss state"); + goto out; + } else if (sim7080_get_state() != SIM7080_STATE_IDLE) { + LOG_WRN("Can only activate gnss from idle state"); + ret = -EINVAL; + goto out; + } - ret = mdm_sim7080_power_on(); + ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, NULL, 0U, "AT+CGNSPWR=1", + &mdata.sem_response, K_SECONDS(2)); if (ret < 0) { - LOG_ERR("Failed to start modem!!"); - return -1; + LOG_ERR("Failed to power on gnss: %d", ret); + goto out; } ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, NULL, 0U, "AT+CGNSCOLD", &mdata.sem_response, K_SECONDS(2)); if (ret < 0) { - return -1; + LOG_ERR("Failed to start gnss: %d", ret); + goto out; } sim7080_change_state(SIM7080_STATE_GNSS); - return 0; -} \ No newline at end of file +out: + return ret; +} + +int mdm_sim7080_stop_gnss(void) +{ + int ret = -EINVAL; + + if (sim7080_get_state() != SIM7080_STATE_GNSS) { + LOG_WRN("Modem not in gnss state"); + goto out; + } + + ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, NULL, 0U, "AT+CGNSPWR=0", + &mdata.sem_response, K_SECONDS(2)); + if (ret < 0) { + LOG_ERR("Failed to power on gnss: %d", ret); + goto out; + } + + sim7080_change_state(SIM7080_STATE_IDLE); +out: + return ret; +} diff --git a/drivers/modem/simcom/sim7080/sim7080_pdp.c b/drivers/modem/simcom/sim7080/sim7080_pdp.c index 88f225552e8ed..5a92d5d752016 100644 --- a/drivers/modem/simcom/sim7080/sim7080_pdp.c +++ b/drivers/modem/simcom/sim7080/sim7080_pdp.c @@ -258,6 +258,8 @@ int sim7080_pdp_deactivate(void) ret = -EIO; } + k_work_cancel_delayable(&mdata.rssi_query_work); + LOG_INF("PDP context deactivated"); sim7080_change_state(SIM7080_STATE_IDLE); diff --git a/include/zephyr/drivers/modem/simcom-sim7080.h b/include/zephyr/drivers/modem/simcom-sim7080.h index d6560633d4758..3c5612a66c373 100644 --- a/include/zephyr/drivers/modem/simcom-sim7080.h +++ b/include/zephyr/drivers/modem/simcom-sim7080.h @@ -133,19 +133,37 @@ int mdm_sim7080_power_on(void); int mdm_sim7080_power_off(void); /** - * @brief Starts the modem in network operation mode. + * @brief Activates the network operation mode of the modem. * * @return 0 on success. Otherwise <0 is returned. + * @note The modem needs to be booted for this function to work. + * Concurrent use of network and gnss is not possible. */ int mdm_sim7080_start_network(void); +/** + * @brief Stops the networking operation mode of the modem. + * + * @return 0 on success. Otherwise <0 is returned. + */ +int mdm_sim7080_stop_network(void); + /** * @brief Starts the modem in gnss operation mode. * * @return 0 on success. Otherwise <0 is returned. + * @note The modem needs to be booted for this function to work. + * Concurrent use of network and gnss is not possible. */ int mdm_sim7080_start_gnss(void); +/** + * @brief Stops the modem gnss operation mode. + * + * @return 0 on success. Otherwise <0 is returned. + */ +int mdm_sim7080_stop_gnss(void); + /** * @brief Query gnss position form the modem. * From fafa93de685f58f3563cbc0c406a9c3546cee96d Mon Sep 17 00:00:00 2001 From: Lukas Gehreke Date: Thu, 24 Apr 2025 11:43:49 +0200 Subject: [PATCH 07/28] drivers: modem: moved sim7080 socket related urc handling to socket file Moved socket related urc handling to dedicated file. Signed-off-by: Lukas Gehreke --- drivers/modem/simcom/sim7080/sim7080.c | 291 ++++++++------------ drivers/modem/simcom/sim7080/sim7080.h | 6 + drivers/modem/simcom/sim7080/sim7080_sock.c | 83 ++++++ 3 files changed, 200 insertions(+), 180 deletions(-) diff --git a/drivers/modem/simcom/sim7080/sim7080.c b/drivers/modem/simcom/sim7080/sim7080.c index 4f8f786e6ae0e..9359ab1351c74 100644 --- a/drivers/modem/simcom/sim7080/sim7080.c +++ b/drivers/modem/simcom/sim7080/sim7080.c @@ -55,8 +55,6 @@ static inline uint8_t *modem_get_mac(const struct device *dev) return data->mac_addr; } -static int offload_socket(int family, int type, int proto); - /* Setup the Modem NET Interface. */ static void modem_net_iface_init(struct net_if *iface) { @@ -69,7 +67,7 @@ static void modem_net_iface_init(struct net_if *iface) socket_offload_dns_register(&offload_dns_ops); - net_if_socket_offload_set(iface, offload_socket); + net_if_socket_offload_set(iface, sim7080_offload_socket); } /** @@ -117,20 +115,6 @@ static bool offload_is_supported(int family, int type, int proto) return true; } -static int offload_socket(int family, int type, int proto) -{ - int ret; - - ret = modem_socket_get(&mdata.socket_config, family, type, proto); - if (ret < 0) { - errno = -ret; - return -1; - } - - errno = 0; - return ret; -} - /* * Process all messages received from the modem. */ @@ -169,132 +153,6 @@ MODEM_CMD_DEFINE(on_cmd_exterror) return 0; } -/* - * Handles pdp context urc. - * - * The urc has the form +APP PDP: ,. - * State can either be ACTIVE for activation or - * DEACTIVE if disabled. - */ -MODEM_CMD_DEFINE(on_urc_app_pdp) -{ - bool active = strcmp(argv[1], "ACTIVE") == 0; - if (active) { - mdata.status_flags |= SIM7080_STATUS_FLAG_PDP_ACTIVE; - } else { - mdata.status_flags &= ~SIM7080_STATUS_FLAG_PDP_ACTIVE; - } - - LOG_INF("PDP context: %u", active); - k_sem_give(&mdata.pdp_sem); - return 0; -} - -MODEM_CMD_DEFINE(on_urc_sms) -{ - LOG_INF("SMS: %s", argv[0]); - return 0; -} - -/* - * Handles socket data notification. - * - * The sim modem sends and unsolicited +CADATAIND: - * if data can be read from a socket. - */ -MODEM_CMD_DEFINE(on_urc_cadataind) -{ - struct modem_socket *sock; - int sock_fd; - - sock_fd = atoi(argv[0]); - - sock = modem_socket_from_fd(&mdata.socket_config, sock_fd); - if (!sock) { - return 0; - } - - /* Modem does not tell packet size. Set dummy for receive. */ - modem_socket_packet_size_update(&mdata.socket_config, sock, 1); - - LOG_INF("Data available on socket: %d", sock_fd); - modem_socket_data_ready(&mdata.socket_config, sock); - - return 0; -} - -/* - * Handles the castate response. - * - * +CASTATE: , - * - * Cid is the connection id (socket fd) and - * state can be: - * 0 - Closed by remote server or error - * 1 - Connected to remote server - * 2 - Listening - */ -MODEM_CMD_DEFINE(on_urc_castate) -{ - struct modem_socket *sock; - int sockfd, state; - - sockfd = atoi(argv[0]); - state = atoi(argv[1]); - - sock = modem_socket_from_fd(&mdata.socket_config, sockfd); - if (!sock) { - return 0; - } - - /* Only continue if socket was closed. */ - if (state != 0) { - return 0; - } - - LOG_INF("Socket close indication for socket: %d", sockfd); - - sock->is_connected = false; - LOG_INF("Socket closed: %d", sockfd); - - return 0; -} - -/** - * Handles the ftpget urc. - * - * +FTPGET: , - * - * Mode can be 1 for opening a session and - * reporting that data is available or 2 for - * reading data. This urc handler will only handle - * mode 1 because 2 will not occur as urc. - * - * Error can be either: - * - 1 for data available/opened session. - * - 0 If transfer is finished. - * - >0 for some error. - */ -MODEM_CMD_DEFINE(on_urc_ftpget) -{ - int error = atoi(argv[0]); - - LOG_INF("+FTPGET: 1,%d", error); - - /* Transfer finished. */ - if (error == 0) { - mdata.ftp.state = SIM7080_FTP_CONNECTION_STATE_FINISHED; - } else if (error == 1) { - mdata.ftp.state = SIM7080_FTP_CONNECTION_STATE_CONNECTED; - } else { - mdata.ftp.state = SIM7080_FTP_CONNECTION_STATE_ERROR; - } - - k_sem_give(&mdata.sem_ftp); - - return 0; -} - /* * Read manufacturer identification. */ @@ -395,6 +253,114 @@ MODEM_CMD_DIRECT_DEFINE(on_cmd_tx_ready) return len; } +/* + * Handles pdp context urc. + * + * The urc has the form +APP PDP: ,. + * State can either be ACTIVE for activation or + * DEACTIVE if disabled. + */ +MODEM_CMD_DEFINE(on_urc_app_pdp) +{ + bool active = strcmp(argv[1], "ACTIVE") == 0; + if (active) { + mdata.status_flags |= SIM7080_STATUS_FLAG_PDP_ACTIVE; + } else { + mdata.status_flags &= ~SIM7080_STATUS_FLAG_PDP_ACTIVE; + } + + LOG_INF("PDP context: %u", active); + k_sem_give(&mdata.pdp_sem); + return 0; +} + +MODEM_CMD_DEFINE(on_urc_pdp_deact) +{ + LOG_INF("PDP context deactivated by network"); + + mdata.status_flags &= ~SIM7080_STATUS_FLAG_PDP_ACTIVE; + return 0; +} + +MODEM_CMD_DEFINE(on_urc_sms) +{ + LOG_INF("SMS: %s", argv[0]); + return 0; +} + +/* + * Handles socket data notification. + * + * The sim modem sends and unsolicited +CADATAIND: + * if data can be read from a socket. + */ +MODEM_CMD_DEFINE(on_urc_cadataind) +{ + int sock_fd; + + sock_fd = atoi(argv[0]); + + sim7080_handle_sock_data_indication(sock_fd); + return 0; +} + +/* + * Handles the castate response. + * + * +CASTATE: , + * + * Cid is the connection id (socket fd) and + * state can be: + * 0 - Closed by remote server or error + * 1 - Connected to remote server + * 2 - Listening + */ +MODEM_CMD_DEFINE(on_urc_castate) +{ + int sockfd, state; + + sockfd = atoi(argv[0]); + state = atoi(argv[1]); + + sim7080_handle_sock_state(sockfd, state); + return 0; +} + +/** + * Handles the ftpget urc. + * + * +FTPGET: , + * + * Mode can be 1 for opening a session and + * reporting that data is available or 2 for + * reading data. This urc handler will only handle + * mode 1 because 2 will not occur as urc. + * + * Error can be either: + * - 1 for data available/opened session. + * - 0 If transfer is finished. + * - >0 for some error. + */ +MODEM_CMD_DEFINE(on_urc_ftpget) +{ + int error = atoi(argv[0]); + + LOG_INF("+FTPGET: 1,%d", error); + + /* Transfer finished. */ + if (error == 0) { + mdata.ftp.state = SIM7080_FTP_CONNECTION_STATE_FINISHED; + } else if (error == 1) { + mdata.ftp.state = SIM7080_FTP_CONNECTION_STATE_CONNECTED; + } else { + mdata.ftp.state = SIM7080_FTP_CONNECTION_STATE_ERROR; + } + + k_sem_give(&mdata.sem_ftp); + + return 0; +} + MODEM_CMD_DIRECT_DEFINE(on_urc_rdy) { LOG_DBG("RDY received"); @@ -440,6 +406,7 @@ static const struct modem_cmd response_cmds[] = { */ static const struct modem_cmd unsolicited_cmds[] = { MODEM_CMD("+APP PDP: ", on_urc_app_pdp, 2U, ","), + MODEM_CMD("+PDP: DEACT", on_urc_pdp_deact, 0U, ""), MODEM_CMD("SMS ", on_urc_sms, 1U, ""), MODEM_CMD("+CADATAIND: ", on_urc_cadataind, 1U, ""), MODEM_CMD("+CASTATE: ", on_urc_castate, 2U, ","), @@ -675,42 +642,6 @@ static int modem_setup(void) return ret; } -int mdm_sim7080_start_network(void) -{ - int ret = -EALREADY; - - if (sim7080_get_state() == SIM7080_STATE_NETWORKING) { - LOG_WRN("Network already active"); - goto out; - } else if (sim7080_get_state() != SIM7080_STATE_IDLE) { - LOG_WRN("Can only activate networking from idle state"); - ret = -EINVAL; - goto out; - } - - ret = sim7080_pdp_activate(); - -out: - return ret; -} - -int mdm_sim7080_stop_network(void) -{ - int ret = -EINVAL; - - if (sim7080_get_state() != SIM7080_STATE_NETWORKING) { - LOG_WRN("Modem not in networking state"); - goto out; - } - - //TODO: close sockets - - ret = sim7080_pdp_deactivate(); - -out: - return ret; -} - int mdm_sim7080_power_on(void) { return modem_boot(false); @@ -891,4 +822,4 @@ NET_DEVICE_DT_INST_OFFLOAD_DEFINE(0, modem_init, NULL, &mdata, NULL, MDM_MAX_DATA_LENGTH); NET_SOCKET_OFFLOAD_REGISTER(simcom_sim7080, CONFIG_NET_SOCKETS_OFFLOAD_PRIORITY, - AF_UNSPEC, offload_is_supported, offload_socket); + AF_UNSPEC, offload_is_supported, sim7080_offload_socket); diff --git a/drivers/modem/simcom/sim7080/sim7080.h b/drivers/modem/simcom/sim7080/sim7080.h index bae1e1c2fd954..199c7320d6754 100644 --- a/drivers/modem/simcom/sim7080/sim7080.h +++ b/drivers/modem/simcom/sim7080/sim7080.h @@ -195,4 +195,10 @@ void sim7080_change_state(enum sim7080_state state); int sim7080_pdp_activate(void); int sim7080_pdp_deactivate(void); +int sim7080_offload_socket(int family, int type, int proto); + +void sim7080_handle_sock_data_indication(int fd); + +void sim7080_handle_sock_state(int fd, uint8_t state); + #endif /* SIMCOM_SIM7080_H */ diff --git a/drivers/modem/simcom/sim7080/sim7080_sock.c b/drivers/modem/simcom/sim7080/sim7080_sock.c index b358de03d00e5..abb46ed9fd8da 100644 --- a/drivers/modem/simcom/sim7080/sim7080_sock.c +++ b/drivers/modem/simcom/sim7080/sim7080_sock.c @@ -537,3 +537,86 @@ const struct socket_op_vtable offload_socket_fd_op_vtable = { .getsockopt = NULL, .setsockopt = NULL, }; + +void sim7080_handle_sock_data_indication(int fd) +{ + struct modem_socket *sock = modem_socket_from_fd(&mdata.socket_config, fd); + if (!sock) { + LOG_INF("No socket with fd %d", fd); + return; + } + + /* Modem does not tell packet size. Set dummy for receive. */ + modem_socket_packet_size_update(&mdata.socket_config, sock, 1); + + LOG_INF("Data available on socket: %d", fd); + modem_socket_data_ready(&mdata.socket_config, sock); +} + +void sim7080_handle_sock_state(int fd, uint8_t state) +{ + struct modem_socket *sock = modem_socket_from_fd(&mdata.socket_config, fd); + if (!sock) { + LOG_INF("No socket with fd %d", fd); + return; + } + + /* Only continue if socket was closed. */ + if (state != 0) { + return; + } + + LOG_INF("Socket close indication for socket: %d", fd); + + sock->is_connected = false; +} + +int sim7080_offload_socket(int family, int type, int proto) +{ + int ret; + + ret = modem_socket_get(&mdata.socket_config, family, type, proto); + if (ret < 0) { + errno = -ret; + return -1; + } + + errno = 0; + return ret; +} + +int mdm_sim7080_start_network(void) +{ + int ret = -EALREADY; + + if (sim7080_get_state() == SIM7080_STATE_NETWORKING) { + LOG_WRN("Network already active"); + goto out; + } else if (sim7080_get_state() != SIM7080_STATE_IDLE) { + LOG_WRN("Can only activate networking from idle state"); + ret = -EINVAL; + goto out; + } + + ret = sim7080_pdp_activate(); + +out: + return ret; +} + +int mdm_sim7080_stop_network(void) +{ + int ret = -EINVAL; + + if (sim7080_get_state() != SIM7080_STATE_NETWORKING) { + LOG_WRN("Modem not in networking state"); + goto out; + } + + //TODO: close sockets + + ret = sim7080_pdp_deactivate(); + +out: + return ret; +} From 48d02aa3653f50fb6a0efb3e59b1c3604504a870 Mon Sep 17 00:00:00 2001 From: Lukas Gehreke Date: Mon, 28 Apr 2025 14:56:25 +0200 Subject: [PATCH 08/28] drivers: modem: corrected sim7080 socket error codes. Socket functions return EINVAL instead of EAGAIN when modem is not in networking mode. Using EAGAIN could lead to a infinite sleep loop in offload_sendmsg(). Signed-off-by: Lukas Gehreke --- drivers/modem/simcom/sim7080/sim7080_sock.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/modem/simcom/sim7080/sim7080_sock.c b/drivers/modem/simcom/sim7080/sim7080_sock.c index abb46ed9fd8da..e934214eeae32 100644 --- a/drivers/modem/simcom/sim7080/sim7080_sock.c +++ b/drivers/modem/simcom/sim7080/sim7080_sock.c @@ -44,7 +44,7 @@ static int offload_connect(void *obj, const struct sockaddr *addr, socklen_t add /* Modem is not attached to the network. */ if (sim7080_get_state() != SIM7080_STATE_NETWORKING) { - return -EAGAIN; + return -EINVAL; } if (modem_socket_is_allocated(&mdata.socket_config, sock) == false) { @@ -128,7 +128,7 @@ static ssize_t offload_sendto(void *obj, const void *buf, size_t len, int flags, /* Modem is not attached to the network. */ if (sim7080_get_state() != SIM7080_STATE_NETWORKING) { LOG_ERR("Modem currently not attached to the network!"); - return -EAGAIN; + return -EINVAL; } /* Do some sanity checks. */ @@ -288,7 +288,7 @@ static ssize_t offload_recvfrom(void *obj, void *buf, size_t max_len, int flags, /* Modem is not attached to the network. */ if (sim7080_get_state() != SIM7080_STATE_NETWORKING) { LOG_ERR("Modem currently not attached to the network!"); - return -EAGAIN; + return -EINVAL; } if (!buf || max_len == 0) { @@ -360,7 +360,7 @@ static ssize_t offload_sendmsg(void *obj, const struct msghdr *msg, int flags) /* Modem is not attached to the network. */ if (sim7080_get_state() != SIM7080_STATE_NETWORKING) { LOG_ERR("Modem currently not attached to the network!"); - return -EAGAIN; + return -EINVAL; } if (sock->type == SOCK_DGRAM) { @@ -442,7 +442,7 @@ static int offload_close(void *obj) /* Modem is not attached to the network. */ if (sim7080_get_state() != SIM7080_STATE_NETWORKING) { LOG_ERR("Modem currently not attached to the network!"); - return -EAGAIN; + return -EINVAL; } /* Make sure socket is allocated */ @@ -469,7 +469,7 @@ static int offload_poll(struct zsock_pollfd *fds, int nfds, int msecs) /* Modem is not attached to the network. */ if (sim7080_get_state() != SIM7080_STATE_NETWORKING) { LOG_ERR("Modem currently not attached to the network!"); - return -EAGAIN; + return -EINVAL; } /* Only accept modem sockets. */ From 7ffb630fb55992455bebffe7f4a1b1f09d6105dc Mon Sep 17 00:00:00 2001 From: Lukas Gehreke Date: Mon, 28 Apr 2025 15:10:38 +0200 Subject: [PATCH 09/28] drivers: modem: sim7080: removed sleep from offload_sendmsg Removed sleep to prevent infinite loop in sendmsg. Signed-off-by: Lukas Gehreke --- drivers/modem/simcom/sim7080/sim7080_sock.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/drivers/modem/simcom/sim7080/sim7080_sock.c b/drivers/modem/simcom/sim7080/sim7080_sock.c index e934214eeae32..4caafe03d7e04 100644 --- a/drivers/modem/simcom/sim7080/sim7080_sock.c +++ b/drivers/modem/simcom/sim7080/sim7080_sock.c @@ -381,16 +381,12 @@ static ssize_t offload_sendmsg(void *obj, const struct msghdr *msg, int flags) while (len > 0) { ret = offload_sendto(obj, buf, len, flags, msg->msg_name, msg->msg_namelen); if (ret < 0) { - if (ret == -EAGAIN) { - k_sleep(K_SECONDS(1)); - } else { - return ret; - } - } else { - sent += ret; - buf += ret; - len -= ret; + return ret; } + + sent += ret; + buf += ret; + len -= ret; } } From 03e99fcb614502838708eefb0c15bef146f4afd8 Mon Sep 17 00:00:00 2001 From: Lukas Gehreke Date: Mon, 28 Apr 2025 15:26:59 +0200 Subject: [PATCH 10/28] drivers: modem: fixed offload_connect for sim7080 Connection id and pdp index were swapped. Corrected this and hardcoded pdp index since 0 is always used as index. Signed-off-by: Lukas Gehreke --- drivers/modem/simcom/sim7080/sim7080_sock.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/modem/simcom/sim7080/sim7080_sock.c b/drivers/modem/simcom/sim7080/sim7080_sock.c index 4caafe03d7e04..2fdbf9ff6f0db 100644 --- a/drivers/modem/simcom/sim7080/sim7080_sock.c +++ b/drivers/modem/simcom/sim7080/sim7080_sock.c @@ -76,7 +76,7 @@ static int offload_connect(void *obj, const struct sockaddr *addr, socklen_t add return -1; } - ret = snprintk(buf, sizeof(buf), "AT+CAOPEN=%d,%d,\"%s\",\"%s\",%d", 0, sock->id, + ret = snprintk(buf, sizeof(buf), "AT+CAOPEN=%d,0,\"%s\",\"%s\",%d", sock->id, protocol, ip_str, dst_port); if (ret < 0) { LOG_ERR("Failed to build connect command. ID: %d, FD: %d", sock->id, sock->sock_fd); From a674c7940835a072dcee52b95db3b18c014d6395 Mon Sep 17 00:00:00 2001 From: Lukas Gehreke Date: Tue, 29 Apr 2025 11:59:48 +0200 Subject: [PATCH 11/28] drivers: modem: sim7080: Corrected socket send sequence. Query available tx size before sending data instead of using hardcoded number. Removed unnecessary strg+z send after data. Signed-off-by: Lukas Gehreke --- drivers/modem/simcom/sim7080/sim7080.h | 1 + drivers/modem/simcom/sim7080/sim7080_sock.c | 45 +++++++++++++++++---- 2 files changed, 38 insertions(+), 8 deletions(-) diff --git a/drivers/modem/simcom/sim7080/sim7080.h b/drivers/modem/simcom/sim7080/sim7080.h index 199c7320d6754..94859948bff38 100644 --- a/drivers/modem/simcom/sim7080/sim7080.h +++ b/drivers/modem/simcom/sim7080/sim7080.h @@ -137,6 +137,7 @@ struct sim7080_data { */ int current_sock_fd; int current_sock_written; + size_t tx_space_avail; /* * Network registration of the modem. */ diff --git a/drivers/modem/simcom/sim7080/sim7080_sock.c b/drivers/modem/simcom/sim7080/sim7080_sock.c index 2fdbf9ff6f0db..7466ef2acd771 100644 --- a/drivers/modem/simcom/sim7080/sim7080_sock.c +++ b/drivers/modem/simcom/sim7080/sim7080_sock.c @@ -107,6 +107,13 @@ static int offload_connect(void *obj, const struct sockaddr *addr, socklen_t add return -1; } +MODEM_CMD_DEFINE(on_cmd_casend) +{ + mdata.tx_space_avail = strtoul(argv[0], NULL, 10); + LOG_DBG("Available tx space: %zu", mdata.tx_space_avail); + return 0; +} + /* * Send data over a given socket. * @@ -123,7 +130,7 @@ static ssize_t offload_sendto(void *obj, const void *buf, size_t len, int flags, int ret; struct modem_socket *sock = (struct modem_socket *)obj; char send_buf[sizeof("AT+CASEND=#,####")] = { 0 }; - char ctrlz = 0x1A; + struct modem_cmd cmd[] = { MODEM_CMD("+CASEND: ", on_cmd_casend, 1U, "") }; /* Modem is not attached to the network. */ if (sim7080_get_state() != SIM7080_STATE_NETWORKING) { @@ -143,14 +150,37 @@ static ssize_t offload_sendto(void *obj, const void *buf, size_t len, int flags, return -1; } - /* Only send up to MTU bytes. */ - if (len > MDM_MAX_DATA_LENGTH) { - len = MDM_MAX_DATA_LENGTH; + /* Query the available space in send buffer */ + ret = snprintk(send_buf, sizeof(send_buf), "AT+CASEND=%d", sock->id); + if (ret < 0) { + LOG_ERR("Failed to build send query command"); + errno = ENOMEM; + return -1; + } + + mdata.tx_space_avail = 0; + ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, cmd, ARRAY_SIZE(cmd), send_buf, + &mdata.sem_response, K_SECONDS(2)); + if (ret < 0) { + LOG_ERR("Failed to query available tx size: %d", ret); + errno = EIO; + return -1; + } + + if (mdata.tx_space_avail == 0) { + LOG_WRN("No space left in tx buffer"); + errno = ENOMEM; + return -1; + } + + /* Only send up to available tx size bytes. */ + if (len > mdata.tx_space_avail) { + len = mdata.tx_space_avail; } - ret = snprintk(send_buf, sizeof(send_buf), "AT+CASEND=%d,%ld", sock->id, (long)len); + ret = snprintk(send_buf, sizeof(send_buf), "AT+CASEND=%d,%zu", sock->id, len); if (ret < 0) { - LOG_ERR("Failed to build send command!!"); + LOG_ERR("Failed to build send command"); errno = ENOMEM; return -1; } @@ -164,7 +194,7 @@ static ssize_t offload_sendto(void *obj, const void *buf, size_t len, int flags, ret = modem_cmd_send_nolock(&mctx.iface, &mctx.cmd_handler, NULL, 0U, send_buf, NULL, K_NO_WAIT); if (ret < 0) { - LOG_ERR("Failed to send CASEND!!"); + LOG_ERR("Failed to send CASEND"); goto exit; } @@ -177,7 +207,6 @@ static ssize_t offload_sendto(void *obj, const void *buf, size_t len, int flags, /* Send data */ modem_cmd_send_data_nolock(&mctx.iface, buf, len); - modem_cmd_send_data_nolock(&mctx.iface, &ctrlz, 1); /* Wait for the OK */ k_sem_reset(&mdata.sem_response); From 182bf53dd9128bccb5aced775a4ee9670d889f06 Mon Sep 17 00:00:00 2001 From: Lukas Gehreke Date: Tue, 29 Apr 2025 12:50:03 +0200 Subject: [PATCH 12/28] drivers: modem: sim7080: fixed socket connect behavior The modem handler error can not be used to transport the result of CAOPEN since it is overwritten by the trailing OK. Socket does not get closed forcefully when connecting failed. Signed-off-by: Lukas Gehreke --- drivers/modem/simcom/sim7080/sim7080.h | 1 + drivers/modem/simcom/sim7080/sim7080_sock.c | 11 +++++------ 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/modem/simcom/sim7080/sim7080.h b/drivers/modem/simcom/sim7080/sim7080.h index 94859948bff38..9a1ee658c3d80 100644 --- a/drivers/modem/simcom/sim7080/sim7080.h +++ b/drivers/modem/simcom/sim7080/sim7080.h @@ -138,6 +138,7 @@ struct sim7080_data { int current_sock_fd; int current_sock_written; size_t tx_space_avail; + uint8_t socket_open_rc; /* * Network registration of the modem. */ diff --git a/drivers/modem/simcom/sim7080/sim7080_sock.c b/drivers/modem/simcom/sim7080/sim7080_sock.c index 7466ef2acd771..ee9254c356ff1 100644 --- a/drivers/modem/simcom/sim7080/sim7080_sock.c +++ b/drivers/modem/simcom/sim7080/sim7080_sock.c @@ -24,7 +24,7 @@ MODEM_CMD_DEFINE(on_cmd_caopen) int result = atoi(argv[1]); LOG_INF("+CAOPEN: %d", result); - modem_cmd_handler_set_error(data, result); + mdata.socket_open_rc = result; return 0; } @@ -84,18 +84,17 @@ static int offload_connect(void *obj, const struct sockaddr *addr, socklen_t add return -1; } + mdata.socket_open_rc = 1; ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, cmd, ARRAY_SIZE(cmd), buf, &mdata.sem_response, MDM_CONNECT_TIMEOUT); if (ret < 0) { LOG_ERR("%s ret: %d", buf, ret); - socket_close(sock); goto error; } - ret = modem_cmd_handler_get_error(&mdata.cmd_handler_data); - if (ret != 0) { - LOG_ERR("Closing the socket!"); - socket_close(sock); + if (mdata.socket_open_rc != 0) { + LOG_ERR("Failed to open the socket: %u", mdata.socket_open_rc); + ret = -ENOTCONN; goto error; } From b7af2f32687e3ff5924d2d47fc08b457f58c9650 Mon Sep 17 00:00:00 2001 From: Lukas Gehreke Date: Tue, 29 Apr 2025 12:53:02 +0200 Subject: [PATCH 13/28] drivers: modem: sim7080: socket can be closed if not connected Removed connected check from offload_close in order to be able to close non-connected sockets. Signed-off-by: Lukas Gehreke --- drivers/modem/simcom/sim7080/sim7080_sock.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/modem/simcom/sim7080/sim7080_sock.c b/drivers/modem/simcom/sim7080/sim7080_sock.c index ee9254c356ff1..c313dadeb358a 100644 --- a/drivers/modem/simcom/sim7080/sim7080_sock.c +++ b/drivers/modem/simcom/sim7080/sim7080_sock.c @@ -474,10 +474,7 @@ static int offload_close(void *obj) return 0; } - /* Close the socket only if it is connected. */ - if (sock->is_connected) { - socket_close(sock); - } + socket_close(sock); return 0; } From 92be72fbe5b0575951411398c1ab12181acb4965 Mon Sep 17 00:00:00 2001 From: Lukas Gehreke Date: Tue, 29 Apr 2025 13:20:49 +0200 Subject: [PATCH 14/28] drivers: modem: sim7080: preventing recvfrom hangup on closed socket If a socket gets closed by the network while waiting on data in offload_recvfrom this would hangup forever since modem_socket_wait_data does not support timeouts. When the socket gets closed this wait is unblocked. Signed-off-by: Lukas Gehreke --- drivers/modem/simcom/sim7080/sim7080_sock.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/modem/simcom/sim7080/sim7080_sock.c b/drivers/modem/simcom/sim7080/sim7080_sock.c index c313dadeb358a..971476e0210fd 100644 --- a/drivers/modem/simcom/sim7080/sim7080_sock.c +++ b/drivers/modem/simcom/sim7080/sim7080_sock.c @@ -590,6 +590,10 @@ void sim7080_handle_sock_state(int fd, uint8_t state) LOG_INF("Socket close indication for socket: %d", fd); sock->is_connected = false; + + /* Unblock potentially waiting socket */ + modem_socket_packet_size_update(&mdata.socket_config, sock, 0); + modem_socket_data_ready(&mdata.socket_config, sock); } int sim7080_offload_socket(int family, int type, int proto) From 306c286a82c8c8fd18f604f035cb2dc7c20a6bde Mon Sep 17 00:00:00 2001 From: Lukas Gehreke Date: Tue, 6 May 2025 15:27:32 +0200 Subject: [PATCH 15/28] drivers: modem: sim7080: added gpio set function Added functionality to set modem gpio pins. Signed-off-by: Lukas Gehreke --- drivers/modem/simcom/sim7080/sim7080.c | 19 +++++++++++++++++++ include/zephyr/drivers/modem/simcom-sim7080.h | 11 +++++++++++ 2 files changed, 30 insertions(+) diff --git a/drivers/modem/simcom/sim7080/sim7080.c b/drivers/modem/simcom/sim7080/sim7080.c index 9359ab1351c74..277cacf2a195b 100644 --- a/drivers/modem/simcom/sim7080/sim7080.c +++ b/drivers/modem/simcom/sim7080/sim7080.c @@ -132,6 +132,25 @@ static void modem_rx(void *p1, void *p2, void *p3) } } +int mdm_sim7080_set_gpio(int gpio, int level) +{ + int ret; + char buf[sizeof("AT+SGPIO=#,#,#,#")]; + + ret = snprintk(buf, sizeof(buf), "AT+SGPIO=0,%u,1,%u", gpio, !!level); + if (ret < 0) { + return -1; + } + + ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, NULL, 0, buf, &mdata.sem_response, + K_SECONDS(5)); + if (ret < 0) { + return -1; + } + + return ret; +} + MODEM_CMD_DEFINE(on_cmd_ok) { modem_cmd_handler_set_error(data, 0); diff --git a/include/zephyr/drivers/modem/simcom-sim7080.h b/include/zephyr/drivers/modem/simcom-sim7080.h index 3c5612a66c373..bed63d5628b63 100644 --- a/include/zephyr/drivers/modem/simcom-sim7080.h +++ b/include/zephyr/drivers/modem/simcom-sim7080.h @@ -214,6 +214,17 @@ int mdm_sim7080_read_sms(struct sim7080_sms_buffer *buffer); */ int mdm_sim7080_delete_sms(uint16_t index); +/** + * Set the level of one of the module's GPIO pins + * + * @param gpio GPIO pin number + * @param level New logical level of the GPIO + * @return 0 on success. Otherwise -1 is returned. + * + * @note The GPIO will be configured as output implicitly. + */ +int mdm_sim7080_set_gpio(int gpio, int level); + /** * Start a ftp get session. * From 49ff26a21231be25724be8d88514bc4734062f4d Mon Sep 17 00:00:00 2001 From: Lukas Gehreke Date: Tue, 6 May 2025 16:04:23 +0200 Subject: [PATCH 16/28] drivers: modem: sim7080: added function to get iccid Added function to get the iccid number. Signed-off-by: Lukas Gehreke --- drivers/modem/simcom/sim7080/sim7080.c | 12 ++++++++++++ include/zephyr/drivers/modem/simcom-sim7080.h | 5 +++++ 2 files changed, 17 insertions(+) diff --git a/drivers/modem/simcom/sim7080/sim7080.c b/drivers/modem/simcom/sim7080/sim7080.c index 277cacf2a195b..62141764a63d4 100644 --- a/drivers/modem/simcom/sim7080/sim7080.c +++ b/drivers/modem/simcom/sim7080/sim7080.c @@ -723,6 +723,18 @@ const char *mdm_sim7080_get_imei(void) return mdata.mdm_imei; } +#if defined(CONFIG_MODEM_SIM_NUMBERS) +const char *mdm_sim7080_get_iccid(void) +{ + return mdata.mdm_iccid; +} +#else +const char *mdm_sim7080_get_iccid(void) +{ + return NULL; +} +#endif /* #if defined(CONFIG_MODEM_SIM_NUMBERS) */ + /* * Initializes modem handlers and context. * After successful init this function calls diff --git a/include/zephyr/drivers/modem/simcom-sim7080.h b/include/zephyr/drivers/modem/simcom-sim7080.h index bed63d5628b63..57bf419d057a4 100644 --- a/include/zephyr/drivers/modem/simcom-sim7080.h +++ b/include/zephyr/drivers/modem/simcom-sim7080.h @@ -192,6 +192,11 @@ const char *mdm_sim7080_get_revision(void); */ const char *mdm_sim7080_get_imei(void); +/** + * Get the sim7080 iccid number. + */ +const char *mdm_sim7080_get_iccid(void); + /** * Read sms from sim module. * From 76cbd8374e28e9e28f3e9aaf221704bcc140b329 Mon Sep 17 00:00:00 2001 From: Lukas Gehreke Date: Mon, 12 May 2025 10:29:05 +0200 Subject: [PATCH 17/28] drivers: modem: Added battery measurement function for sim7080 Added function to measure battery voltage, battery charge status and battery connection level. Signed-off-by: Lukas Gehreke --- drivers/modem/simcom/sim7080/CMakeLists.txt | 3 +- drivers/modem/simcom/sim7080/sim7080_meas.c | 62 +++++++++++++++++++ include/zephyr/drivers/modem/simcom-sim7080.h | 10 +++ 3 files changed, 74 insertions(+), 1 deletion(-) create mode 100644 drivers/modem/simcom/sim7080/sim7080_meas.c diff --git a/drivers/modem/simcom/sim7080/CMakeLists.txt b/drivers/modem/simcom/sim7080/CMakeLists.txt index bb2ee13050820..2716036aea99c 100644 --- a/drivers/modem/simcom/sim7080/CMakeLists.txt +++ b/drivers/modem/simcom/sim7080/CMakeLists.txt @@ -13,4 +13,5 @@ zephyr_library_sources( sim7080_sock.c sim7080_sms.c sim7080_ftp.c - sim7080_gps.c) + sim7080_gps.c + sim7080_meas.c) diff --git a/drivers/modem/simcom/sim7080/sim7080_meas.c b/drivers/modem/simcom/sim7080/sim7080_meas.c new file mode 100644 index 0000000000000..1573353facb38 --- /dev/null +++ b/drivers/modem/simcom/sim7080/sim7080_meas.c @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2025 Metratec GmbH + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +LOG_MODULE_REGISTER(modem_sim7080_meas, CONFIG_MODEM_LOG_LEVEL); + +#include "sim7080.h" + +static struct { + uint8_t bcs; + uint8_t bcl; + uint16_t volt; +} cbc_data; + +MODEM_CMD_DEFINE(on_cmd_cbc) +{ + long tmp; + + tmp = strtol(argv[0], NULL, 10); + if (errno == -ERANGE) { + return -EBADMSG; + } + cbc_data.bcs = (uint8_t)tmp; + tmp = strtol(argv[1], NULL, 10); + if (errno == -ERANGE) { + return -EBADMSG; + } + cbc_data.bcl = (uint8_t)tmp; + tmp = strtol(argv[2], NULL, 10); + if (errno == -ERANGE) { + return -EBADMSG; + } + cbc_data.volt = (uint16_t)tmp; + + return 0; +} + +int mdm_sim7080_get_battery_charge(uint8_t *bcs, uint8_t *bcl, uint16_t *voltage) +{ + int ret; + struct modem_cmd cmds[] = {MODEM_CMD("+CBC: ", on_cmd_cbc, 3U, ",")}; + + if (sim7080_get_state() == SIM7080_STATE_OFF) { + LOG_ERR("SIM7080 not powered on!"); + return -1; + } + + ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, cmds, ARRAY_SIZE(cmds), "AT+CBC", + &mdata.sem_response, K_SECONDS(2)); + if (ret < 0) { + return ret; + } + + *bcs = cbc_data.bcs; + *bcl = cbc_data.bcl; + *voltage = cbc_data.volt; + + return ret; +} diff --git a/include/zephyr/drivers/modem/simcom-sim7080.h b/include/zephyr/drivers/modem/simcom-sim7080.h index 57bf419d057a4..b06fd46d1423a 100644 --- a/include/zephyr/drivers/modem/simcom-sim7080.h +++ b/include/zephyr/drivers/modem/simcom-sim7080.h @@ -253,6 +253,16 @@ int mdm_sim7080_ftp_get_start(const char *server, const char *user, const char * */ int mdm_sim7080_ftp_get_read(char *dst, size_t *size); +/** + * Read voltage, charge status and battery connection level. + * + * @param bcs [out] Charge status. + * @param bcl [out] Battery connection level. + * @param voltage [out] Battery voltage in mV. + * @return 0 on success. Otherwise a negative error is returned. + */ +int mdm_sim7080_get_battery_charge(uint8_t *bcs, uint8_t *bcl, uint16_t *voltage); + #ifdef __cplusplus } #endif From 2938c5d99d2ccc5b406309387abdf2729e34d9e9 Mon Sep 17 00:00:00 2001 From: Lukas Gehreke Date: Mon, 12 May 2025 10:37:51 +0200 Subject: [PATCH 18/28] drivers: modem: sim7080: added function to query the modem state. Added function to query the modem state from application side. Signed-off-by: Lukas Gehreke --- drivers/modem/simcom/sim7080/sim7080.c | 5 +++++ drivers/modem/simcom/sim7080/sim7080.h | 8 -------- include/zephyr/drivers/modem/simcom-sim7080.h | 15 +++++++++++++++ 3 files changed, 20 insertions(+), 8 deletions(-) diff --git a/drivers/modem/simcom/sim7080/sim7080.c b/drivers/modem/simcom/sim7080/sim7080.c index 62141764a63d4..25960e87b159f 100644 --- a/drivers/modem/simcom/sim7080/sim7080.c +++ b/drivers/modem/simcom/sim7080/sim7080.c @@ -91,6 +91,11 @@ enum sim7080_state sim7080_get_state(void) return mdata.state; } +enum sim7080_state mdm_sim7080_get_state(void) +{ + return sim7080_get_state(); +} + static struct offloaded_if_api api_funcs = { .iface_api.init = modem_net_iface_init, }; diff --git a/drivers/modem/simcom/sim7080/sim7080.h b/drivers/modem/simcom/sim7080/sim7080.h index 9a1ee658c3d80..d97cb0a4a8da9 100644 --- a/drivers/modem/simcom/sim7080/sim7080.h +++ b/drivers/modem/simcom/sim7080/sim7080.h @@ -61,14 +61,6 @@ #define MDM_IMSI_LENGTH 16 #define MDM_ICCID_LENGTH 32 -enum sim7080_state { - SIM7080_STATE_INIT = 0, - SIM7080_STATE_IDLE, - SIM7080_STATE_NETWORKING, - SIM7080_STATE_GNSS, - SIM7080_STATE_OFF, -}; - /* Possible states of the ftp connection. */ enum sim7080_ftp_connection_state { /* Not connected yet. */ diff --git a/include/zephyr/drivers/modem/simcom-sim7080.h b/include/zephyr/drivers/modem/simcom-sim7080.h index b06fd46d1423a..60be752974fbd 100644 --- a/include/zephyr/drivers/modem/simcom-sim7080.h +++ b/include/zephyr/drivers/modem/simcom-sim7080.h @@ -18,6 +18,14 @@ extern "C" { #define SIM7080_GNSS_DATA_UTC_LEN 20 #define SIM7080_SMS_MAX_LEN 160 +enum sim7080_state { + SIM7080_STATE_INIT = 0, + SIM7080_STATE_IDLE, + SIM7080_STATE_NETWORKING, + SIM7080_STATE_GNSS, + SIM7080_STATE_OFF, +}; + struct sim7080_gnss_data { /** * Whether gnss is powered or not. @@ -118,6 +126,13 @@ struct sim7080_sms_buffer { uint8_t nsms; }; +/** + * Get the current state of the modem. + * + * @return The current state. + */ +enum sim7080_state mdm_sim7080_get_state(void); + /** * @brief Power on the Sim7080. * From 50f544b14336dbf87c06f17646b9fccf23e1fcce Mon Sep 17 00:00:00 2001 From: Lukas Gehreke Date: Mon, 12 May 2025 16:27:45 +0200 Subject: [PATCH 19/28] drivers: modem: sim7080: added command to inquire ue system information Added command to query ue system information from the modem. Signed-off-by: Lukas Gehreke --- drivers/modem/Kconfig | 1 + drivers/modem/simcom/sim7080/sim7080_meas.c | 215 ++++++++++++++++++ include/zephyr/drivers/modem/simcom-sim7080.h | 89 ++++++++ 3 files changed, 305 insertions(+) diff --git a/drivers/modem/Kconfig b/drivers/modem/Kconfig index a0c40edd879df..02de18fee7a97 100644 --- a/drivers/modem/Kconfig +++ b/drivers/modem/Kconfig @@ -135,6 +135,7 @@ config MODEM_CMD_HANDLER config MODEM_CMD_HANDLER_MAX_PARAM_COUNT int "Maximum number of params parsed per command" depends on MODEM_CMD_HANDLER + default 14 if MODEM_SIM7080 default 6 help This option sets the maximum number of parameters which may be diff --git a/drivers/modem/simcom/sim7080/sim7080_meas.c b/drivers/modem/simcom/sim7080/sim7080_meas.c index 1573353facb38..1c4b391801f6b 100644 --- a/drivers/modem/simcom/sim7080/sim7080_meas.c +++ b/drivers/modem/simcom/sim7080/sim7080_meas.c @@ -4,11 +4,40 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include +#include #include LOG_MODULE_REGISTER(modem_sim7080_meas, CONFIG_MODEM_LOG_LEVEL); #include "sim7080.h" +/* Common CPSI indices */ +#define CPSI_SYS_MODE_IDX 0U +#define CPSI_OP_MODE_IDX 1U +#define CPSI_MCC_MNC_IDX 2U +/* GSM specific CPSI indices */ +#define CPSI_GSM_LAC_IDX 3U +#define CPSI_GSM_CID_IDX 4U +#define CPSI_GSM_ARFCN_IDX 5U +#define CPSI_GSM_RX_LVL_IDX 6U +#define CPSI_GSM_TLO_ADJ_IDX 7U +#define CPSI_GSM_C1_C2_IDX 8U +/* LTE specific CPSI indices */ +#define CPSI_LTE_TAC_IDX 3U +#define CPSI_LTE_SCI_IDX 4U +#define CPSI_LTE_PCI_IDX 5U +#define CPSI_LTE_BAND_IDX 6U +#define CPSI_LTE_EARFCN_IDX 7U +#define CPSI_LTE_DLBW_IDX 8U +#define CPSI_LTE_ULBW_IDX 9U +#define CPSI_LTE_RSRQ_IDX 10U +#define CPSI_LTE_RSRP_IDX 11U +#define CPSI_LTE_RSSI_IDX 12U +#define CPSI_LTE_RSSNR_IDX 13U + +#define CPSI_GSM_ARG_COUNT 9U +#define CPSI_LTE_ARG_COUNT 14U + static struct { uint8_t bcs; uint8_t bcl; @@ -60,3 +89,189 @@ int mdm_sim7080_get_battery_charge(uint8_t *bcs, uint8_t *bcl, uint16_t *voltage return ret; } + +static const uint8_t *ue_sys_mode_lut[] = { + "NO SERVICE", + "GSM", + "LTE CAT-M1", + "LTE NB-IOT", +}; + +static const uint8_t *ue_op_mode_lut[] = { + "Online", + "Offline", + "Factory Test Mode", + "Reset", + "Low Power Mode", +}; + +/** + * Check lookup table for match. + * @param s 0 terminated source string. + * @param lut The lookup table. + * @param size Size of the lookup table. + * @return Index in the lookup table or -1 on no match. + */ +static int8_t lut_match(const uint8_t *s, const uint8_t **lut, uint8_t size) +{ + for (uint8_t i = 0; i < size; i++) { + if (strcmp(s, lut[i]) == 0) { + return i; + } + } + + return -1; +} + +static int cpsi_parse_minus(uint8_t *s, uint16_t *a, uint16_t *b) +{ + char *saveptr; + char *tmp = strtok_r(s, "-", &saveptr); + if (tmp == NULL) { + return -1; + } + + *a = (uint16_t)strtoul(tmp, NULL, 10); + + tmp = strtok_r(NULL, NULL, &saveptr); + if (tmp == NULL) { + return -1; + } + + *b = (uint16_t)strtoul(tmp, NULL, 10); + + return 0; +} + +static int cpsi_parse_gsm(struct sim7080_ue_sys_info *info, uint8_t **argv, uint16_t argc) +{ + int ret = -EINVAL; + + if (argc != CPSI_GSM_ARG_COUNT) { + LOG_ERR("Unexpected number of arguments: %u", argc); + goto out; + } + + ret = cpsi_parse_minus(argv[CPSI_MCC_MNC_IDX], &info->cell.gsm.mcc, &info->cell.gsm.mcn); + if (ret != 0) { + LOG_ERR("Failed to parse MCC/MCN"); + goto out; + } + + info->cell.gsm.lac = (uint16_t)strtoul(argv[CPSI_GSM_LAC_IDX], NULL, 16); + info->cell.gsm.cid = (uint16_t)strtoul(argv[CPSI_GSM_CID_IDX], NULL, 10); + strncpy(info->cell.gsm.arfcn, argv[CPSI_GSM_ARFCN_IDX], sizeof(info->cell.gsm.arfcn) - 1); + info->cell.gsm.rx_lvl = (int16_t)strtol(argv[CPSI_GSM_CID_IDX], NULL, 10); + info->cell.gsm.track_lo_adjust = (int16_t)strtol(argv[CPSI_GSM_TLO_ADJ_IDX], NULL, 10); + + ret = cpsi_parse_minus(argv[CPSI_GSM_C1_C2_IDX], &info->cell.gsm.c1, &info->cell.gsm.c2); + if (ret != 0) { + LOG_ERR("Failed to parse C1/C2"); + goto out; + } + +out: + return ret; +} + +static int cpsi_parse_lte(struct sim7080_ue_sys_info *info, uint8_t **argv, uint16_t argc) +{ + int ret = -EINVAL; + + if (argc != CPSI_LTE_ARG_COUNT) { + LOG_ERR("Unexpected number of arguments: %u", argc); + goto out; + } + + ret = cpsi_parse_minus(argv[CPSI_MCC_MNC_IDX], &info->cell.lte.mcc, &info->cell.lte.mcn); + if (ret != 0) { + LOG_ERR("Failed to parse MCC/MCN"); + goto out; + } + + info->cell.lte.tac = (uint16_t)strtoul(argv[CPSI_LTE_TAC_IDX], NULL, 16); + info->cell.lte.sci = (uint32_t)strtoul(argv[CPSI_LTE_SCI_IDX], NULL, 10); + info->cell.lte.pci = (uint16_t)strtoul(argv[CPSI_LTE_PCI_IDX], NULL, 10); + strncpy(info->cell.lte.band, argv[CPSI_LTE_BAND_IDX], sizeof(info->cell.lte.band) - 1); + info->cell.lte.earfcn = (uint16_t)strtoul(argv[CPSI_LTE_EARFCN_IDX], NULL, 10); + info->cell.lte.dlbw = (uint16_t)strtoul(argv[CPSI_LTE_DLBW_IDX], NULL, 10); + info->cell.lte.ulbw = (uint16_t)strtoul(argv[CPSI_LTE_ULBW_IDX], NULL, 10); + info->cell.lte.rsrq = (int16_t)strtol(argv[CPSI_LTE_RSRQ_IDX], NULL, 10); + info->cell.lte.rsrp = (int16_t)strtol(argv[CPSI_LTE_RSRP_IDX], NULL, 10); + info->cell.lte.rssi = (int16_t)strtol(argv[CPSI_LTE_RSSI_IDX], NULL, 10); + info->cell.lte.rssnr = (int16_t)strtol(argv[CPSI_LTE_RSSNR_IDX], NULL, 10); + info->cell.lte.sinr = 2 * info->cell.lte.rssnr - 20; + +out: + return ret; +} + +static struct sim7080_ue_sys_info *ue_sys_info; + +MODEM_CMD_DEFINE(on_cmd_cpsi) +{ + int ret = -1; + + memset(ue_sys_info, 0, sizeof(*ue_sys_info)); + + if (argc < 2) { + LOG_ERR("Insufficient number of parameters: %u", argc); + goto out; + } + + ret = lut_match(argv[CPSI_SYS_MODE_IDX], ue_sys_mode_lut, ARRAY_SIZE(ue_sys_mode_lut)); + if (ret < 0) { + LOG_ERR("Illegal sys mode: %s", argv[CPSI_SYS_MODE_IDX]); + goto out; + } + + ue_sys_info->sys_mode = (enum sim7080_ue_sys_mode)ret; + + ret = lut_match(argv[CPSI_OP_MODE_IDX], ue_op_mode_lut, ARRAY_SIZE(ue_op_mode_lut)); + if (ret < 0) { + LOG_ERR("Illegal op mode: %s", argv[CPSI_OP_MODE_IDX]); + goto out; + } + + ue_sys_info->op_mode = (enum sim7080_ue_op_mode)ret; + + if (ue_sys_info->sys_mode == SIM7080_UE_SYS_MODE_NO_SERVICE) { + /* No further information available */ + ret = 0; + } else if (ue_sys_info->sys_mode == SIM7080_UE_SYS_MODE_GSM) { + ret = cpsi_parse_gsm(ue_sys_info, argv, argc); + } else if (ue_sys_info->sys_mode == SIM7080_UE_SYS_MODE_LTE_CAT_M1 || + ue_sys_info->sys_mode == SIM7080_UE_SYS_MODE_LTE_NB_IOT) { + ret = cpsi_parse_lte(ue_sys_info, argv, argc); + } + +out: + return ret; +} + +int mdm_sim7080_get_ue_sys_info(struct sim7080_ue_sys_info *info) +{ + int ret = -1; + struct modem_cmd cmds[] = {MODEM_CMD("+CPSI: ", on_cmd_cpsi, 14U, ",")}; + + if (sim7080_get_state() == SIM7080_STATE_OFF) { + LOG_ERR("SIM7080 not powered on!"); + goto out; + } + + if (info == NULL) { + ret = -EINVAL; + goto out; + } + + ue_sys_info = info; + + ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, cmds, ARRAY_SIZE(cmds), "AT+CPSI?", + &mdata.sem_response, K_SECONDS(2)); + if (ret < 0) { + goto out; + } + +out: + return ret; +} diff --git a/include/zephyr/drivers/modem/simcom-sim7080.h b/include/zephyr/drivers/modem/simcom-sim7080.h index 60be752974fbd..dcbb2247bbc8d 100644 --- a/include/zephyr/drivers/modem/simcom-sim7080.h +++ b/include/zephyr/drivers/modem/simcom-sim7080.h @@ -17,6 +17,7 @@ extern "C" { #define SIM7080_GNSS_DATA_UTC_LEN 20 #define SIM7080_SMS_MAX_LEN 160 +#define SIM7080_UE_SYS_INFO_BAND_SIZE 32 enum sim7080_state { SIM7080_STATE_INIT = 0, @@ -126,6 +127,86 @@ struct sim7080_sms_buffer { uint8_t nsms; }; +enum sim7080_ue_sys_mode { + SIM7080_UE_SYS_MODE_NO_SERVICE, + SIM7080_UE_SYS_MODE_GSM, + SIM7080_UE_SYS_MODE_LTE_CAT_M1, + SIM7080_UE_SYS_MODE_LTE_NB_IOT, +}; + +enum sim7080_ue_op_mode { + SIM7080_UE_OP_MODE_ONLINE, + SIM7080_UE_OP_MODE_OFFLINE, + SIM7080_UE_OP_MODE_FACTORY_TEST_MODE, + SIM7080_UE_OP_MODE_RESET, + SIM7080_UE_OP_MODE_LOW_POWER_MODE, +}; + +struct sim7080_ue_sys_info_gsm { + /* Mobile country code */ + uint16_t mcc; + /* Mobile network code */ + uint16_t mcn; + /* Location area code */ + uint16_t lac; + /* Cell ID */ + uint16_t cid; + /* Absolute radio frequency channel number */ + uint8_t arfcn[SIM7080_UE_SYS_INFO_BAND_SIZE + 1]; + /* RX level in dBm */ + int16_t rx_lvl; + /* Track LO adjust */ + int16_t track_lo_adjust; + /* C1 coefficient */ + uint16_t c1; + /* C2 coefficient */ + uint16_t c2; +}; + +struct sim7080_ue_sys_info_lte { + /* Mobile country code */ + uint16_t mcc; + /* Mobile network code */ + uint16_t mcn; + /* Tracing area code */ + uint16_t tac; + /* Serving Cell ID */ + uint32_t sci; + /* Physical Cell ID */ + uint16_t pci; + /* Frequency band */ + uint8_t band[SIM7080_UE_SYS_INFO_BAND_SIZE + 1]; + /* E-UTRA absolute radio frequency channel number */ + uint16_t earfcn; + /* Downlink bandwidth in MHz */ + uint16_t dlbw; + /* Uplink bandwidth in MHz */ + uint16_t ulbw; + /* Reference signal received quality in dB */ + int16_t rsrq; + /* Reference signal received power in dBm */ + int16_t rsrp; + /* Received signal strength indicator in dBm */ + int16_t rssi; + /* Reference signal signal to noise ratio in dB */ + int16_t rssnr; + /* Signal to interference plus noise ratio in dB */ + int16_t sinr; +}; + +struct sim7080_ue_sys_info { + /* Refer to sim7080_ue_sys_mode */ + enum sim7080_ue_sys_mode sys_mode; + /* Refer to sim7080_ue_op_mode */ + enum sim7080_ue_op_mode op_mode; + union { + /* Only set if sys_mode is GSM */ + struct sim7080_ue_sys_info_gsm gsm; + /* Only set if sys mode is LTE CAT-M1/NB-IOT */ + struct sim7080_ue_sys_info_lte lte; + } cell; +}; + /** * Get the current state of the modem. * @@ -278,6 +359,14 @@ int mdm_sim7080_ftp_get_read(char *dst, size_t *size); */ int mdm_sim7080_get_battery_charge(uint8_t *bcs, uint8_t *bcl, uint16_t *voltage); +/** + * Read the ue system information + * + * @param info Destination buffer for information. + * @return 0 on success. Otherwise a negative error is returned. + */ +int mdm_sim7080_get_ue_sys_info(struct sim7080_ue_sys_info *info); + #ifdef __cplusplus } #endif From 464c4eef4bcd8babad63c1aea358e9aab56f7ad7 Mon Sep 17 00:00:00 2001 From: Lukas Gehreke Date: Wed, 14 May 2025 11:42:55 +0200 Subject: [PATCH 20/28] drivers: sim7080: implemented gnss xtra functionality. Added funtions to download a gnss xtra file, query its validity and use it in gps. Signed-off-by: Lukas Gehreke --- drivers/modem/simcom/sim7080/sim7080.c | 10 ++ drivers/modem/simcom/sim7080/sim7080.h | 3 + drivers/modem/simcom/sim7080/sim7080_gps.c | 132 +++++++++++++++++- include/zephyr/drivers/modem/simcom-sim7080.h | 28 ++++ 4 files changed, 172 insertions(+), 1 deletion(-) diff --git a/drivers/modem/simcom/sim7080/sim7080.c b/drivers/modem/simcom/sim7080/sim7080.c index 25960e87b159f..19dc8fd45f4d9 100644 --- a/drivers/modem/simcom/sim7080/sim7080.c +++ b/drivers/modem/simcom/sim7080/sim7080.c @@ -415,6 +415,14 @@ MODEM_CMD_DEFINE(on_urc_cpin) return 0; } +MODEM_CMD_DEFINE(on_urc_httptofs) +{ + mdata.http_status = (uint16_t)strtoul(argv[0], NULL, 10); + LOG_INF("HTTP status: %u", mdata.http_status); + k_sem_give(&mdata.sem_http); + return 0; +} + /* * Possible responses by the sim7080. */ @@ -438,6 +446,7 @@ static const struct modem_cmd unsolicited_cmds[] = { MODEM_CMD("RDY", on_urc_rdy, 0U, ""), MODEM_CMD("NORMAL POWER DOWN", on_urc_pwr_down, 0U, ""), MODEM_CMD("+CPIN: ", on_urc_cpin, 1U, ","), + MODEM_CMD("+HTTPTOFS: ", on_urc_httptofs, 2U, ","), }; /* @@ -755,6 +764,7 @@ static int modem_init(const struct device *dev) k_sem_init(&mdata.sem_tx_ready, 0, 1); k_sem_init(&mdata.sem_dns, 0, 1); k_sem_init(&mdata.sem_ftp, 0, 1); + k_sem_init(&mdata.sem_http, 0, 1); k_sem_init(&mdata.boot_sem, 0 ,1); k_sem_init(&mdata.pdp_sem, 0, 1); k_work_queue_start(&modem_workq, modem_workq_stack, diff --git a/drivers/modem/simcom/sim7080/sim7080.h b/drivers/modem/simcom/sim7080/sim7080.h index d97cb0a4a8da9..89e6da3c5a627 100644 --- a/drivers/modem/simcom/sim7080/sim7080.h +++ b/drivers/modem/simcom/sim7080/sim7080.h @@ -141,6 +141,8 @@ struct sim7080_data { struct sim7080_sms_buffer *sms_buffer; /* Position in the sms buffer. */ uint8_t sms_buffer_pos; + /* Status of the last http operation */ + uint16_t http_status; /* Ftp related variables. */ struct { /* User buffer for ftp data. */ @@ -157,6 +159,7 @@ struct sim7080_data { struct k_sem sem_tx_ready; struct k_sem sem_dns; struct k_sem sem_ftp; + struct k_sem sem_http; struct k_sem boot_sem; struct k_sem pdp_sem; }; diff --git a/drivers/modem/simcom/sim7080/sim7080_gps.c b/drivers/modem/simcom/sim7080/sim7080_gps.c index 03d3c9a9369c2..2f48f20ca6f26 100644 --- a/drivers/modem/simcom/sim7080/sim7080_gps.c +++ b/drivers/modem/simcom/sim7080/sim7080_gps.c @@ -265,7 +265,53 @@ int mdm_sim7080_query_gnss(struct sim7080_gnss_data *data) return ret; } -int mdm_sim7080_start_gnss(void) +static uint8_t cgnscpy_ret; + +MODEM_CMD_DEFINE(on_cmd_cgnscpy) +{ + cgnscpy_ret = (uint8_t)strtoul(argv[0], NULL, 10); + LOG_INF("CGNSCPY: %u", cgnscpy_ret); + return 0; +} + +static int16_t xtra_diff_h, xtra_duration_h; + +MODEM_CMD_DEFINE(on_cmd_cgnsxtra) +{ + xtra_diff_h = (int16_t)strtol(argv[0], NULL, 10); + xtra_duration_h = (int16_t)strtol(argv[1], NULL, 10); + LOG_INF("XTRA validity: diff=%d, duration=%d, inject=%s,%s", + xtra_diff_h, + xtra_duration_h, + argv[2], + argv[3]); + return 0; +} + +int mdm_sim7080_query_xtra_validity(int16_t *diff_h, int16_t *duration_h) +{ + struct modem_cmd cmds[] = { MODEM_CMD("+CGNSXTRA: ", on_cmd_cgnsxtra, 4U, ",") }; + int ret = -EINVAL; + + if (!diff_h || !duration_h) { + goto out; + } + + ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, cmds, ARRAY_SIZE(cmds), "AT+CGNSXTRA", + &mdata.sem_response, K_SECONDS(2)); + if (ret != 0) { + LOG_ERR("Failed to query xtra validity"); + goto out; + } + + *diff_h = xtra_diff_h; + *duration_h = xtra_duration_h; + +out: + return ret; +} + +static int sim7080_start_gnss_ext(bool xtra) { int ret = -EALREADY; @@ -278,6 +324,7 @@ int mdm_sim7080_start_gnss(void) goto out; } + /* Power GNSS unit */ ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, NULL, 0U, "AT+CGNSPWR=1", &mdata.sem_response, K_SECONDS(2)); if (ret < 0) { @@ -285,6 +332,36 @@ int mdm_sim7080_start_gnss(void) goto out; } + if (xtra == false) { + goto coldstart; + } + + struct modem_cmd cmds[] = { MODEM_CMD("+CGNSCPY: ", on_cmd_cgnscpy, 1U, "") }; + + cgnscpy_ret = UINT8_MAX; + + /* Copy the xtra file to gnss unit */ + ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, cmds, ARRAY_SIZE(cmds), "AT+CGNSCPY", + &mdata.sem_response, K_SECONDS(5)); + if (ret < 0) { + LOG_WRN("Failed to copy xtra file. Performing cold start"); + goto coldstart; + } + + if (cgnscpy_ret != 0) { + LOG_WRN("CGNSCPY returned %u. Performing cold start", cgnscpy_ret); + goto coldstart; + } + + /* Enable xtra functionality */ + ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, NULL, 0U, "AT+CGNSXTRA=1", + &mdata.sem_response, K_SECONDS(5)); + if (ret < 0) { + LOG_WRN("Failed query xtra file validity. Performing cold start"); + goto coldstart; + } + +coldstart: ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, NULL, 0U, "AT+CGNSCOLD", &mdata.sem_response, K_SECONDS(2)); if (ret < 0) { @@ -297,6 +374,16 @@ int mdm_sim7080_start_gnss(void) return ret; } +int mdm_sim7080_start_gnss(void) +{ + return sim7080_start_gnss_ext(false); +} + +int mdm_sim7080_start_gnss_xtra(void) +{ + return sim7080_start_gnss_ext(true); +} + int mdm_sim7080_stop_gnss(void) { int ret = -EINVAL; @@ -317,3 +404,46 @@ int mdm_sim7080_stop_gnss(void) out: return ret; } + +int mdm_sim7080_download_xtra(uint8_t server_id, const char *f_name) +{ + char buf[sizeof("AT+HTTPTOFS=\"http://iot#.xtracloud.net/xtra3##_72h.bin\",\"/customer/Xtra3.bin\"")]; + int ret = -ENOTCONN; + + if (sim7080_get_state() != SIM7080_STATE_NETWORKING) { + LOG_WRN("Need network to download xtra file"); + goto out; + } + + ret = snprintk(buf, sizeof(buf), "AT+HTTPTOFS=\"http://iot%hhu.xtracloud.net/%s\",\"/customer/Xtra3.bin\"", + server_id, f_name); + if (ret < 0) { + LOG_ERR("Failed to format xtra download"); + goto out; + } + + mdata.http_status = 0; + + /* Download xtra file */ + ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, NULL, 0U, buf, + &mdata.sem_response, K_SECONDS(2)); + if (ret < 0) { + LOG_ERR("Failed to download xtra file"); + goto out; + } + + /* Wait for HTTP status code */ + ret = k_sem_take(&mdata.sem_http, K_SECONDS(60)); + if (ret != 0) { + LOG_ERR("Waiting for http completion failed"); + goto out; + } + + if (mdata.http_status != 200) { + LOG_ERR("HTTP request failed with: %u", mdata.http_status); + ret = -1; + } + +out: + return ret; +} diff --git a/include/zephyr/drivers/modem/simcom-sim7080.h b/include/zephyr/drivers/modem/simcom-sim7080.h index dcbb2247bbc8d..a3abeae741b07 100644 --- a/include/zephyr/drivers/modem/simcom-sim7080.h +++ b/include/zephyr/drivers/modem/simcom-sim7080.h @@ -10,6 +10,7 @@ #include #include +#include #ifdef __cplusplus extern "C" { @@ -253,6 +254,16 @@ int mdm_sim7080_stop_network(void); */ int mdm_sim7080_start_gnss(void); +/** + * @brief Starts the modem in gnss operation mode with xtra functionality. + * + * @return 0 on success. Otherwise <0 is returned. + * @note The modem needs to be booted for this function to work. + * Concurrent use of network and gnss is not possible. + * @note If enabling xtra functionality fails a normal cold start will be performed. + */ +int mdm_sim7080_start_gnss_xtra(void); + /** * @brief Stops the modem gnss operation mode. * @@ -260,6 +271,23 @@ int mdm_sim7080_start_gnss(void); */ int mdm_sim7080_stop_gnss(void); +/** + * @brief Download the XTRA file for assisted gnss. + * + * @param server_id Id of the server to download XTRA file from. + * @param f_name The name of the XTRA file to download. + * @return 0 on success. Otherwise <0 is returned. + */ +int mdm_sim7080_download_xtra(uint8_t server_id, const char *f_name); + +/** + * @brief Query the validity of the XTRA file. + * + * @param diff_h Difference between the local time and the XTRA inject time in hours. + * @param duration_h Valid time of the XTRA file in hours. + */ +int mdm_sim7080_query_xtra_validity(int16_t *diff_h, int16_t *duration_h); + /** * @brief Query gnss position form the modem. * From 690a12a6efb2010c3c58cf547dbe51a54d49195f Mon Sep 17 00:00:00 2001 From: Lukas Gehreke Date: Tue, 20 May 2025 08:52:27 +0200 Subject: [PATCH 21/28] drivers: modem: sim7080: added function to query local time Added funtion to query local time and added injection time to gnss xtra validity query function. Signed-off-by: Lukas Gehreke --- drivers/modem/simcom/sim7080/CMakeLists.txt | 3 +- drivers/modem/simcom/sim7080/sim7080.h | 2 + drivers/modem/simcom/sim7080/sim7080_gps.c | 11 ++- drivers/modem/simcom/sim7080/sim7080_meas.c | 51 ++++++++++++ drivers/modem/simcom/sim7080/sim7080_utils.c | 81 +++++++++++++++++++ include/zephyr/drivers/modem/simcom-sim7080.h | 12 ++- 6 files changed, 155 insertions(+), 5 deletions(-) create mode 100644 drivers/modem/simcom/sim7080/sim7080_utils.c diff --git a/drivers/modem/simcom/sim7080/CMakeLists.txt b/drivers/modem/simcom/sim7080/CMakeLists.txt index 2716036aea99c..1eba58cb002e6 100644 --- a/drivers/modem/simcom/sim7080/CMakeLists.txt +++ b/drivers/modem/simcom/sim7080/CMakeLists.txt @@ -14,4 +14,5 @@ zephyr_library_sources( sim7080_sms.c sim7080_ftp.c sim7080_gps.c - sim7080_meas.c) + sim7080_meas.c + sim7080_utils.c) diff --git a/drivers/modem/simcom/sim7080/sim7080.h b/drivers/modem/simcom/sim7080/sim7080.h index 89e6da3c5a627..5e51d437aa708 100644 --- a/drivers/modem/simcom/sim7080/sim7080.h +++ b/drivers/modem/simcom/sim7080/sim7080.h @@ -198,4 +198,6 @@ void sim7080_handle_sock_data_indication(int fd); void sim7080_handle_sock_state(int fd, uint8_t state); +int sim7080_utils_parse_time(uint8_t *date, uint8_t *time, struct tm *t); + #endif /* SIMCOM_SIM7080_H */ diff --git a/drivers/modem/simcom/sim7080/sim7080_gps.c b/drivers/modem/simcom/sim7080/sim7080_gps.c index 2f48f20ca6f26..e475e14f3e29a 100644 --- a/drivers/modem/simcom/sim7080/sim7080_gps.c +++ b/drivers/modem/simcom/sim7080/sim7080_gps.c @@ -275,28 +275,32 @@ MODEM_CMD_DEFINE(on_cmd_cgnscpy) } static int16_t xtra_diff_h, xtra_duration_h; +static struct tm *xtra_inject; MODEM_CMD_DEFINE(on_cmd_cgnsxtra) { xtra_diff_h = (int16_t)strtol(argv[0], NULL, 10); xtra_duration_h = (int16_t)strtol(argv[1], NULL, 10); + int ret = sim7080_utils_parse_time(argv[2], argv[3], xtra_inject); LOG_INF("XTRA validity: diff=%d, duration=%d, inject=%s,%s", xtra_diff_h, xtra_duration_h, argv[2], argv[3]); - return 0; + return ret; } -int mdm_sim7080_query_xtra_validity(int16_t *diff_h, int16_t *duration_h) +int mdm_sim7080_query_xtra_validity(int16_t *diff_h, int16_t *duration_h, struct tm *inject) { struct modem_cmd cmds[] = { MODEM_CMD("+CGNSXTRA: ", on_cmd_cgnsxtra, 4U, ",") }; int ret = -EINVAL; - if (!diff_h || !duration_h) { + if (!diff_h || !duration_h || !inject) { goto out; } + xtra_inject = inject; + ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, cmds, ARRAY_SIZE(cmds), "AT+CGNSXTRA", &mdata.sem_response, K_SECONDS(2)); if (ret != 0) { @@ -308,6 +312,7 @@ int mdm_sim7080_query_xtra_validity(int16_t *diff_h, int16_t *duration_h) *duration_h = xtra_duration_h; out: + xtra_inject = NULL; return ret; } diff --git a/drivers/modem/simcom/sim7080/sim7080_meas.c b/drivers/modem/simcom/sim7080/sim7080_meas.c index 1c4b391801f6b..681dfab7961bb 100644 --- a/drivers/modem/simcom/sim7080/sim7080_meas.c +++ b/drivers/modem/simcom/sim7080/sim7080_meas.c @@ -6,6 +6,7 @@ #include #include +#include #include LOG_MODULE_REGISTER(modem_sim7080_meas, CONFIG_MODEM_LOG_LEVEL); @@ -275,3 +276,53 @@ int mdm_sim7080_get_ue_sys_info(struct sim7080_ue_sys_info *info) out: return ret; } + +static struct tm *local_tm; + +MODEM_CMD_DEFINE(on_cmd_cclk) +{ + char *saveptr; + int ret = -1; + + /* +1 to skip leading " */ + char *date = strtok_r(argv[0] + 1, ",", &saveptr); + if (date == NULL) { + LOG_WRN("Failed to parse date"); + goto out; + } + + char *time = strtok_r(NULL, "\"", &saveptr); + if (time == NULL) { + LOG_WRN("Failed to parse time"); + goto out; + } + + ret = sim7080_utils_parse_time(date, time, local_tm); + +out: + return ret; +} + +int mdm_sim7080_get_local_time(struct tm *t) +{ + int ret = -1; + struct modem_cmd cmds[] = {MODEM_CMD("+CCLK: ", on_cmd_cclk, 1U, ",")}; + + if (sim7080_get_state() == SIM7080_STATE_OFF) { + goto out; + } + + if (!t) { + ret = -EINVAL; + goto out; + } + + local_tm = t; + + ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, cmds, ARRAY_SIZE(cmds), "AT+CCLK?", + &mdata.sem_response, K_SECONDS(2)); + +out: + local_tm = NULL; + return ret; +} diff --git a/drivers/modem/simcom/sim7080/sim7080_utils.c b/drivers/modem/simcom/sim7080/sim7080_utils.c new file mode 100644 index 0000000000000..dff468b4cbb3b --- /dev/null +++ b/drivers/modem/simcom/sim7080/sim7080_utils.c @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2025 metraTec GmbH + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include +LOG_MODULE_REGISTER(modem_simcom_sim7080_utils, CONFIG_MODEM_LOG_LEVEL); + +#include "sim7080.h" + +int sim7080_utils_parse_time(uint8_t *date, uint8_t *time, struct tm *t) +{ + char *saveptr; + int ret = -1; + + if (!date || !time || !t) { + ret = -EINVAL; + goto out; + } + + memset(t, 0, sizeof(*t)); + + char *tmp = strtok_r(date, "/", &saveptr); + if (tmp == NULL) { + LOG_WRN("Failed to parse year"); + goto out; + } + + t->tm_year = (int)strtol(tmp, NULL, 10) - 1900; + + tmp = strtok_r(NULL, "/", &saveptr); + if (tmp == NULL) { + LOG_WRN("Failed to parse month"); + goto out; + } + + t->tm_mon = (int)strtol(tmp, NULL, 10) - 1; + + tmp = strtok_r(NULL, "", &saveptr); + if (tmp == NULL) { + LOG_WRN("Failed to parse day"); + goto out; + } + + t->tm_mday = (int)strtol(tmp, NULL, 10); + + tmp = strtok_r(time, ":", &saveptr); + if (tmp == NULL) { + LOG_WRN("Failed to parse hour"); + goto out; + } + + t->tm_hour = (int)strtol(tmp, NULL, 10); + + tmp = strtok_r(NULL, ":", &saveptr); + if (tmp == NULL) { + LOG_WRN("Failed to parse minute"); + goto out; + } + + t->tm_min = (int)strtol(tmp, NULL, 10); + + tmp = strtok_r(NULL, "+", &saveptr); + if (tmp == NULL) { + LOG_WRN("Failed to parse second"); + goto out; + } + + t->tm_sec = (int)strtol(tmp, NULL, 10); + + /* Mark dst as not available */ + t->tm_isdst = -1; + + ret = 0; +out: + return ret; +} diff --git a/include/zephyr/drivers/modem/simcom-sim7080.h b/include/zephyr/drivers/modem/simcom-sim7080.h index a3abeae741b07..25415e9f1f9fa 100644 --- a/include/zephyr/drivers/modem/simcom-sim7080.h +++ b/include/zephyr/drivers/modem/simcom-sim7080.h @@ -285,8 +285,9 @@ int mdm_sim7080_download_xtra(uint8_t server_id, const char *f_name); * * @param diff_h Difference between the local time and the XTRA inject time in hours. * @param duration_h Valid time of the XTRA file in hours. + * @param inject Injection time of the XTRA file. */ -int mdm_sim7080_query_xtra_validity(int16_t *diff_h, int16_t *duration_h); +int mdm_sim7080_query_xtra_validity(int16_t *diff_h, int16_t *duration_h, struct tm *inject); /** * @brief Query gnss position form the modem. @@ -395,6 +396,15 @@ int mdm_sim7080_get_battery_charge(uint8_t *bcs, uint8_t *bcl, uint16_t *voltage */ int mdm_sim7080_get_ue_sys_info(struct sim7080_ue_sys_info *info); +/** + * Get the local time of the modem. + * + * @param t Time structure to fill. + * @return 0 on success. Otherwise a negative error is returned. + * @note Time is set by network. It may take some time for it to get valid. + */ +int mdm_sim7080_get_local_time(struct tm *t); + #ifdef __cplusplus } #endif From 2ba0bd4db48848b871baa0c608360d314372d402 Mon Sep 17 00:00:00 2001 From: Lukas Gehreke Date: Tue, 20 May 2025 14:34:48 +0200 Subject: [PATCH 22/28] drivers: modem: sim7080: querying xtra validity during gnss start Starting gnss with xtra functionality is only possible if the validity of the xtra file was queried. Enabling xtra will be skipped if the file is not valid Signed-off-by: Lukas Gehreke --- drivers/modem/simcom/sim7080/sim7080_gps.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/drivers/modem/simcom/sim7080/sim7080_gps.c b/drivers/modem/simcom/sim7080/sim7080_gps.c index e475e14f3e29a..6200724c62353 100644 --- a/drivers/modem/simcom/sim7080/sim7080_gps.c +++ b/drivers/modem/simcom/sim7080/sim7080_gps.c @@ -358,11 +358,26 @@ static int sim7080_start_gnss_ext(bool xtra) goto coldstart; } + /* Query the xtra file validity */ + int16_t diff, duration; + struct tm inject; + + ret = mdm_sim7080_query_xtra_validity(&diff, &duration, &inject); + if (ret != 0) { + LOG_WRN("Could not query xtra validity. Performing cold start"); + goto coldstart; + } + + if (diff < 0) { + LOG_WRN("XTRA file is not valid. Performing cold start"); + goto coldstart; + } + /* Enable xtra functionality */ ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, NULL, 0U, "AT+CGNSXTRA=1", &mdata.sem_response, K_SECONDS(5)); if (ret < 0) { - LOG_WRN("Failed query xtra file validity. Performing cold start"); + LOG_WRN("Failed to enable xtra. Performing cold start"); goto coldstart; } From d35f1ef25460c978933ddde881a69714cfcba91f Mon Sep 17 00:00:00 2001 From: Lukas Gehreke Date: Mon, 26 May 2025 13:04:21 +0200 Subject: [PATCH 23/28] drivers: modem: sim7080: added force reset function. Added function to forcefully reset the modem by holding the pwrkey for 15 seconds. Signed-off-by: Lukas Gehreke --- drivers/modem/simcom/sim7080/sim7080.c | 8 ++++++++ include/zephyr/drivers/modem/simcom-sim7080.h | 7 +++++++ 2 files changed, 15 insertions(+) diff --git a/drivers/modem/simcom/sim7080/sim7080.c b/drivers/modem/simcom/sim7080/sim7080.c index 19dc8fd45f4d9..e3b1ae4216f49 100644 --- a/drivers/modem/simcom/sim7080/sim7080.c +++ b/drivers/modem/simcom/sim7080/sim7080.c @@ -717,6 +717,14 @@ int mdm_sim7080_power_off(void) return ret; } +void mdm_sim7080_force_reset(void) +{ + LOG_DBG("Forcefully resetting modem"); + gpio_pin_set_dt(&power_gpio, 1); + k_sleep(K_SECONDS(15)); + gpio_pin_set_dt(&power_gpio, 0); +} + const char *mdm_sim7080_get_manufacturer(void) { return mdata.mdm_manufacturer; diff --git a/include/zephyr/drivers/modem/simcom-sim7080.h b/include/zephyr/drivers/modem/simcom-sim7080.h index 25415e9f1f9fa..082542a4bf34c 100644 --- a/include/zephyr/drivers/modem/simcom-sim7080.h +++ b/include/zephyr/drivers/modem/simcom-sim7080.h @@ -229,6 +229,13 @@ int mdm_sim7080_power_on(void); */ int mdm_sim7080_power_off(void); +/** + * Forcefully reset the modem by pulling pwrkey for 15 seconds. + * @note The state of the modem may be undefined after calling + * this function. Call mdm_sim7080_power_on after force reset. + */ +void mdm_sim7080_force_reset(void); + /** * @brief Activates the network operation mode of the modem. * From 23723dce221b1e054f2625035b6e4acdc3ac0789 Mon Sep 17 00:00:00 2001 From: Lukas Gehreke Date: Wed, 13 Aug 2025 08:11:16 +0200 Subject: [PATCH 24/28] drivers: modem: sim7080: Allwing ftp when networking is already active Added check that makes sure ftp works when the network context is already active. Signed-off-by: Lukas Gehreke --- drivers/modem/simcom/sim7080/sim7080_ftp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/modem/simcom/sim7080/sim7080_ftp.c b/drivers/modem/simcom/sim7080/sim7080_ftp.c index c33368ec47a8a..fc1af269cb925 100644 --- a/drivers/modem/simcom/sim7080/sim7080_ftp.c +++ b/drivers/modem/simcom/sim7080/sim7080_ftp.c @@ -106,7 +106,7 @@ int mdm_sim7080_ftp_get_start(const char *server, const char *user, const char * /* Start network. */ ret = mdm_sim7080_start_network(); - if (ret < 0) { + if (ret < 0 && ret != -EALREADY) { LOG_ERR("Failed to start network for FTP!"); return -1; } From d6127eb6a2c831da1742efc911273d19d369f778 Mon Sep 17 00:00:00 2001 From: Lukas Gehreke Date: Tue, 26 Aug 2025 11:55:04 +0200 Subject: [PATCH 25/28] drivers: modem: Fixed style issues of sim7080 driver Fixed zephyr style violations. Signed-off-by: Lukas Gehreke --- drivers/modem/simcom/sim7080/sim7080.c | 13 ++- drivers/modem/simcom/sim7080/sim7080.h | 2 +- drivers/modem/simcom/sim7080/sim7080_dns.c | 6 +- drivers/modem/simcom/sim7080/sim7080_ftp.c | 24 ++--- drivers/modem/simcom/sim7080/sim7080_gps.c | 19 ++-- drivers/modem/simcom/sim7080/sim7080_meas.c | 55 ++++++----- drivers/modem/simcom/sim7080/sim7080_pdp.c | 27 +++--- drivers/modem/simcom/sim7080/sim7080_sms.c | 4 +- drivers/modem/simcom/sim7080/sim7080_sock.c | 16 +-- drivers/modem/simcom/sim7080/sim7080_utils.c | 97 ++++++++++--------- include/zephyr/drivers/modem/simcom-sim7080.h | 8 +- 11 files changed, 140 insertions(+), 131 deletions(-) diff --git a/drivers/modem/simcom/sim7080/sim7080.c b/drivers/modem/simcom/sim7080/sim7080.c index e3b1ae4216f49..1053178242815 100644 --- a/drivers/modem/simcom/sim7080/sim7080.c +++ b/drivers/modem/simcom/sim7080/sim7080.c @@ -281,12 +281,13 @@ MODEM_CMD_DIRECT_DEFINE(on_cmd_tx_ready) * Handles pdp context urc. * * The urc has the form +APP PDP: ,. - * State can either be ACTIVE for activation or - * DEACTIVE if disabled. + * When activated ACTIVE is reported as state. + * All other states will be treated as deactivated. */ MODEM_CMD_DEFINE(on_urc_app_pdp) { bool active = strcmp(argv[1], "ACTIVE") == 0; + if (active) { mdata.status_flags |= SIM7080_STATUS_FLAG_PDP_ACTIVE; } else { @@ -466,12 +467,14 @@ static int modem_set_baudrate(uint32_t baudrate) char buf[sizeof("AT+IPR=##########")] = {0}; int ret = snprintk(buf, sizeof(buf), "AT+IPR=%u", baudrate); + if (ret < 0) { LOG_ERR("Failed to build command"); goto out; } - ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, NULL, 0U, buf, &mdata.sem_response, K_SECONDS(2)); + ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, NULL, 0U, buf, &mdata.sem_response, + K_SECONDS(2)); if (ret != 0) { LOG_ERR("Failed to set baudrate"); } @@ -516,7 +519,7 @@ int modem_autobaud(void) * @return 0 on success. Otherwise <0. * * @note Autobaud is only allowed during driver setup. - * In any other case a fixed baudrate should be used. + * In any other case a fixed baudrate should be used. */ static int modem_boot(bool allow_autobaud) { @@ -773,7 +776,7 @@ static int modem_init(const struct device *dev) k_sem_init(&mdata.sem_dns, 0, 1); k_sem_init(&mdata.sem_ftp, 0, 1); k_sem_init(&mdata.sem_http, 0, 1); - k_sem_init(&mdata.boot_sem, 0 ,1); + k_sem_init(&mdata.boot_sem, 0, 1); k_sem_init(&mdata.pdp_sem, 0, 1); k_work_queue_start(&modem_workq, modem_workq_stack, K_KERNEL_STACK_SIZEOF(modem_workq_stack), K_PRIO_COOP(7), NULL); diff --git a/drivers/modem/simcom/sim7080/sim7080.h b/drivers/modem/simcom/sim7080/sim7080.h index 5e51d437aa708..6ff1c52897edf 100644 --- a/drivers/modem/simcom/sim7080/sim7080.h +++ b/drivers/modem/simcom/sim7080/sim7080.h @@ -198,6 +198,6 @@ void sim7080_handle_sock_data_indication(int fd); void sim7080_handle_sock_state(int fd, uint8_t state); -int sim7080_utils_parse_time(uint8_t *date, uint8_t *time, struct tm *t); +int sim7080_utils_parse_time(uint8_t *date, uint8_t *time_str, struct tm *t); #endif /* SIMCOM_SIM7080_H */ diff --git a/drivers/modem/simcom/sim7080/sim7080_dns.c b/drivers/modem/simcom/sim7080/sim7080_dns.c index 2c57f88be564c..68416df39f900 100644 --- a/drivers/modem/simcom/sim7080/sim7080_dns.c +++ b/drivers/modem/simcom/sim7080/sim7080_dns.c @@ -53,7 +53,7 @@ MODEM_CMD_DEFINE(on_cmd_cdnsgip) *ipv4 = '\0'; net_addr_pton(dns_result.ai_family, ips, - &((struct sockaddr_in *)&dns_result_addr)->sin_addr); + &((struct sockaddr_in *)&dns_result_addr)->sin_addr); ret = 0; exit: @@ -65,7 +65,7 @@ MODEM_CMD_DEFINE(on_cmd_cdnsgip) * Perform a dns lookup. */ static int offload_getaddrinfo(const char *node, const char *service, - const struct zsock_addrinfo *hints, struct zsock_addrinfo **res) + const struct zsock_addrinfo *hints, struct zsock_addrinfo **res) { struct modem_cmd cmd[] = { MODEM_CMD("+CDNSGIP: ", on_cmd_cdnsgip, 2U, ",") }; char sendbuf[sizeof("AT+CDNSGIP=\"\",##,#####") + 128]; @@ -117,7 +117,7 @@ static int offload_getaddrinfo(const char *node, const char *service, snprintk(sendbuf, sizeof(sendbuf), "AT+CDNSGIP=\"%s\",10,20000", node); ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, cmd, ARRAY_SIZE(cmd), sendbuf, - &mdata.sem_dns, MDM_DNS_TIMEOUT); + &mdata.sem_dns, MDM_DNS_TIMEOUT); if (ret < 0) { return ret; } diff --git a/drivers/modem/simcom/sim7080/sim7080_ftp.c b/drivers/modem/simcom/sim7080/sim7080_ftp.c index fc1af269cb925..01bab067337d1 100644 --- a/drivers/modem/simcom/sim7080/sim7080_ftp.c +++ b/drivers/modem/simcom/sim7080/sim7080_ftp.c @@ -40,7 +40,7 @@ MODEM_CMD_DEFINE(on_cmd_ftpget) } out_len = net_buf_linearize(mdata.ftp.read_buffer, mdata.ftp.nread, data->rx_buf, - bytes_to_skip, nbytes); + bytes_to_skip, nbytes); if (out_len != nbytes) { LOG_WRN("FTP read size differs!"); } @@ -59,7 +59,7 @@ int mdm_sim7080_ftp_get_read(char *dst, size_t *size) /* Some error occurred. */ if (mdata.ftp.state == SIM7080_FTP_CONNECTION_STATE_ERROR || - mdata.ftp.state == SIM7080_FTP_CONNECTION_STATE_INITIAL) { + mdata.ftp.state == SIM7080_FTP_CONNECTION_STATE_INITIAL) { return SIM7080_FTP_RC_ERROR; } @@ -86,7 +86,7 @@ int mdm_sim7080_ftp_get_read(char *dst, size_t *size) } ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, cmds, ARRAY_SIZE(cmds), buffer, - &mdata.sem_response, MDM_CMD_TIMEOUT); + &mdata.sem_response, MDM_CMD_TIMEOUT); if (ret < 0) { *size = 0; return SIM7080_FTP_RC_ERROR; @@ -99,7 +99,7 @@ int mdm_sim7080_ftp_get_read(char *dst, size_t *size) } int mdm_sim7080_ftp_get_start(const char *server, const char *user, const char *passwd, - const char *file, const char *path) + const char *file, const char *path) { int ret; char buffer[256]; @@ -113,7 +113,7 @@ int mdm_sim7080_ftp_get_start(const char *server, const char *user, const char * /* Set connection id for ftp. */ ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, NULL, 0U, "AT+FTPCID=0", - &mdata.sem_response, MDM_CMD_TIMEOUT); + &mdata.sem_response, MDM_CMD_TIMEOUT); if (ret < 0) { LOG_WRN("Failed to set FTP Cid!"); return -1; @@ -127,7 +127,7 @@ int mdm_sim7080_ftp_get_start(const char *server, const char *user, const char * } ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, NULL, 0U, buffer, &mdata.sem_response, - MDM_CMD_TIMEOUT); + MDM_CMD_TIMEOUT); if (ret < 0) { LOG_WRN("Failed to set FTP Cid!"); return -1; @@ -141,7 +141,7 @@ int mdm_sim7080_ftp_get_start(const char *server, const char *user, const char * } ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, NULL, 0U, buffer, &mdata.sem_response, - MDM_CMD_TIMEOUT); + MDM_CMD_TIMEOUT); if (ret < 0) { LOG_WRN("Failed to set ftp user!"); return -1; @@ -155,7 +155,7 @@ int mdm_sim7080_ftp_get_start(const char *server, const char *user, const char * } ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, NULL, 0U, buffer, &mdata.sem_response, - MDM_CMD_TIMEOUT); + MDM_CMD_TIMEOUT); if (ret < 0) { LOG_WRN("Failed to set ftp password!"); return -1; @@ -169,7 +169,7 @@ int mdm_sim7080_ftp_get_start(const char *server, const char *user, const char * } ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, NULL, 0U, buffer, &mdata.sem_response, - MDM_CMD_TIMEOUT); + MDM_CMD_TIMEOUT); if (ret < 0) { LOG_WRN("Failed to set ftp filename!"); return -1; @@ -183,7 +183,7 @@ int mdm_sim7080_ftp_get_start(const char *server, const char *user, const char * } ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, NULL, 0U, buffer, &mdata.sem_response, - MDM_CMD_TIMEOUT); + MDM_CMD_TIMEOUT); if (ret < 0) { LOG_WRN("Failed to set ftp filename!"); return -1; @@ -197,7 +197,7 @@ int mdm_sim7080_ftp_get_start(const char *server, const char *user, const char * } ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, NULL, 0U, buffer, &mdata.sem_response, - MDM_CMD_TIMEOUT); + MDM_CMD_TIMEOUT); if (ret < 0) { LOG_WRN("Failed to set ftp path!"); return -1; @@ -210,7 +210,7 @@ int mdm_sim7080_ftp_get_start(const char *server, const char *user, const char * /* Start the ftp session. */ ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, NULL, 0U, "AT+FTPGET=1", - &mdata.sem_ftp, MDM_CMD_TIMEOUT); + &mdata.sem_ftp, MDM_CMD_TIMEOUT); if (ret < 0) { LOG_WRN("Failed to start session!"); return -1; diff --git a/drivers/modem/simcom/sim7080/sim7080_gps.c b/drivers/modem/simcom/sim7080/sim7080_gps.c index 6200724c62353..86bfc9ef34004 100644 --- a/drivers/modem/simcom/sim7080/sim7080_gps.c +++ b/drivers/modem/simcom/sim7080/sim7080_gps.c @@ -246,10 +246,10 @@ int mdm_sim7080_query_gnss(struct sim7080_gnss_data *data) return -1; } - memset(&gnss_data, 0, sizeof(gnss_data)); + memset(&gnss_data, 0, sizeof(gnss_data)); ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, cmds, ARRAY_SIZE(cmds), "AT+CGNSINF", - &mdata.sem_response, K_SECONDS(2)); + &mdata.sem_response, K_SECONDS(2)); if (ret < 0) { return ret; } @@ -282,6 +282,7 @@ MODEM_CMD_DEFINE(on_cmd_cgnsxtra) xtra_diff_h = (int16_t)strtol(argv[0], NULL, 10); xtra_duration_h = (int16_t)strtol(argv[1], NULL, 10); int ret = sim7080_utils_parse_time(argv[2], argv[3], xtra_inject); + LOG_INF("XTRA validity: diff=%d, duration=%d, inject=%s,%s", xtra_diff_h, xtra_duration_h, @@ -302,7 +303,7 @@ int mdm_sim7080_query_xtra_validity(int16_t *diff_h, int16_t *duration_h, struct xtra_inject = inject; ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, cmds, ARRAY_SIZE(cmds), "AT+CGNSXTRA", - &mdata.sem_response, K_SECONDS(2)); + &mdata.sem_response, K_SECONDS(2)); if (ret != 0) { LOG_ERR("Failed to query xtra validity"); goto out; @@ -331,7 +332,7 @@ static int sim7080_start_gnss_ext(bool xtra) /* Power GNSS unit */ ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, NULL, 0U, "AT+CGNSPWR=1", - &mdata.sem_response, K_SECONDS(2)); + &mdata.sem_response, K_SECONDS(2)); if (ret < 0) { LOG_ERR("Failed to power on gnss: %d", ret); goto out; @@ -347,7 +348,7 @@ static int sim7080_start_gnss_ext(bool xtra) /* Copy the xtra file to gnss unit */ ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, cmds, ARRAY_SIZE(cmds), "AT+CGNSCPY", - &mdata.sem_response, K_SECONDS(5)); + &mdata.sem_response, K_SECONDS(5)); if (ret < 0) { LOG_WRN("Failed to copy xtra file. Performing cold start"); goto coldstart; @@ -375,7 +376,7 @@ static int sim7080_start_gnss_ext(bool xtra) /* Enable xtra functionality */ ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, NULL, 0U, "AT+CGNSXTRA=1", - &mdata.sem_response, K_SECONDS(5)); + &mdata.sem_response, K_SECONDS(5)); if (ret < 0) { LOG_WRN("Failed to enable xtra. Performing cold start"); goto coldstart; @@ -383,7 +384,7 @@ static int sim7080_start_gnss_ext(bool xtra) coldstart: ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, NULL, 0U, "AT+CGNSCOLD", - &mdata.sem_response, K_SECONDS(2)); + &mdata.sem_response, K_SECONDS(2)); if (ret < 0) { LOG_ERR("Failed to start gnss: %d", ret); goto out; @@ -414,7 +415,7 @@ int mdm_sim7080_stop_gnss(void) } ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, NULL, 0U, "AT+CGNSPWR=0", - &mdata.sem_response, K_SECONDS(2)); + &mdata.sem_response, K_SECONDS(2)); if (ret < 0) { LOG_ERR("Failed to power on gnss: %d", ret); goto out; @@ -446,7 +447,7 @@ int mdm_sim7080_download_xtra(uint8_t server_id, const char *f_name) /* Download xtra file */ ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, NULL, 0U, buf, - &mdata.sem_response, K_SECONDS(2)); + &mdata.sem_response, K_SECONDS(2)); if (ret < 0) { LOG_ERR("Failed to download xtra file"); goto out; diff --git a/drivers/modem/simcom/sim7080/sim7080_meas.c b/drivers/modem/simcom/sim7080/sim7080_meas.c index 681dfab7961bb..3ed88c33eebd6 100644 --- a/drivers/modem/simcom/sim7080/sim7080_meas.c +++ b/drivers/modem/simcom/sim7080/sim7080_meas.c @@ -70,7 +70,7 @@ MODEM_CMD_DEFINE(on_cmd_cbc) int mdm_sim7080_get_battery_charge(uint8_t *bcs, uint8_t *bcl, uint16_t *voltage) { - int ret; + int ret; struct modem_cmd cmds[] = {MODEM_CMD("+CBC: ", on_cmd_cbc, 3U, ",")}; if (sim7080_get_state() == SIM7080_STATE_OFF) { @@ -79,7 +79,7 @@ int mdm_sim7080_get_battery_charge(uint8_t *bcs, uint8_t *bcl, uint16_t *voltage } ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, cmds, ARRAY_SIZE(cmds), "AT+CBC", - &mdata.sem_response, K_SECONDS(2)); + &mdata.sem_response, K_SECONDS(2)); if (ret < 0) { return ret; } @@ -92,18 +92,18 @@ int mdm_sim7080_get_battery_charge(uint8_t *bcs, uint8_t *bcl, uint16_t *voltage } static const uint8_t *ue_sys_mode_lut[] = { - "NO SERVICE", - "GSM", - "LTE CAT-M1", - "LTE NB-IOT", + "NO SERVICE", + "GSM", + "LTE CAT-M1", + "LTE NB-IOT", }; static const uint8_t *ue_op_mode_lut[] = { - "Online", - "Offline", - "Factory Test Mode", - "Reset", - "Low Power Mode", + "Online", + "Offline", + "Factory Test Mode", + "Reset", + "Low Power Mode", }; /** @@ -115,19 +115,20 @@ static const uint8_t *ue_op_mode_lut[] = { */ static int8_t lut_match(const uint8_t *s, const uint8_t **lut, uint8_t size) { - for (uint8_t i = 0; i < size; i++) { - if (strcmp(s, lut[i]) == 0) { - return i; - } - } + for (uint8_t i = 0; i < size; i++) { + if (strcmp(s, lut[i]) == 0) { + return i; + } + } - return -1; + return -1; } static int cpsi_parse_minus(uint8_t *s, uint16_t *a, uint16_t *b) { char *saveptr; char *tmp = strtok_r(s, "-", &saveptr); + if (tmp == NULL) { return -1; } @@ -247,13 +248,13 @@ MODEM_CMD_DEFINE(on_cmd_cpsi) } out: - return ret; + return ret; } int mdm_sim7080_get_ue_sys_info(struct sim7080_ue_sys_info *info) { - int ret = -1; - struct modem_cmd cmds[] = {MODEM_CMD("+CPSI: ", on_cmd_cpsi, 14U, ",")}; + int ret = -1; + struct modem_cmd cmds[] = {MODEM_CMD("+CPSI: ", on_cmd_cpsi, 14U, ",")}; if (sim7080_get_state() == SIM7080_STATE_OFF) { LOG_ERR("SIM7080 not powered on!"); @@ -268,13 +269,13 @@ int mdm_sim7080_get_ue_sys_info(struct sim7080_ue_sys_info *info) ue_sys_info = info; ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, cmds, ARRAY_SIZE(cmds), "AT+CPSI?", - &mdata.sem_response, K_SECONDS(2)); + &mdata.sem_response, K_SECONDS(2)); if (ret < 0) { goto out; } out: - return ret; + return ret; } static struct tm *local_tm; @@ -286,18 +287,20 @@ MODEM_CMD_DEFINE(on_cmd_cclk) /* +1 to skip leading " */ char *date = strtok_r(argv[0] + 1, ",", &saveptr); + if (date == NULL) { LOG_WRN("Failed to parse date"); goto out; } - char *time = strtok_r(NULL, "\"", &saveptr); - if (time == NULL) { + char *time_str = strtok_r(NULL, "\"", &saveptr); + + if (time_str == NULL) { LOG_WRN("Failed to parse time"); goto out; } - ret = sim7080_utils_parse_time(date, time, local_tm); + ret = sim7080_utils_parse_time(date, time_str, local_tm); out: return ret; @@ -320,7 +323,7 @@ int mdm_sim7080_get_local_time(struct tm *t) local_tm = t; ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, cmds, ARRAY_SIZE(cmds), "AT+CCLK?", - &mdata.sem_response, K_SECONDS(2)); + &mdata.sem_response, K_SECONDS(2)); out: local_tm = NULL; diff --git a/drivers/modem/simcom/sim7080/sim7080_pdp.c b/drivers/modem/simcom/sim7080/sim7080_pdp.c index 5a92d5d752016..72c43eab53d6a 100644 --- a/drivers/modem/simcom/sim7080/sim7080_pdp.c +++ b/drivers/modem/simcom/sim7080/sim7080_pdp.c @@ -66,14 +66,14 @@ void sim7080_rssi_query_work(struct k_work *work) int ret; ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, cmd, ARRAY_SIZE(cmd), send_cmd, - &mdata.sem_response, MDM_CMD_TIMEOUT); + &mdata.sem_response, MDM_CMD_TIMEOUT); if (ret < 0) { LOG_ERR("AT+CSQ ret:%d", ret); } if (work) { k_work_reschedule_for_queue(&modem_workq, &mdata.rssi_query_work, - K_SECONDS(RSSI_TIMEOUT_SECS)); + K_SECONDS(RSSI_TIMEOUT_SECS)); } } @@ -127,7 +127,7 @@ int sim7080_pdp_activate(void) counter = 0; while (counter++ < MDM_WAIT_FOR_RSSI_COUNT && - (mdata.mdm_rssi >= 0 || mdata.mdm_rssi <= -1000)) { + (mdata.mdm_rssi >= 0 || mdata.mdm_rssi <= -1000)) { k_sleep(MDM_WAIT_FOR_RSSI_DELAY); sim7080_rssi_query_work(NULL); } @@ -141,18 +141,19 @@ int sim7080_pdp_activate(void) struct modem_cmd cgatt_cmd[] = { MODEM_CMD("+CGATT: ", on_cmd_cgatt, 1U, "") }; ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, cgatt_cmd, - ARRAY_SIZE(cgatt_cmd), "AT+CGATT?", &mdata.sem_response, - MDM_CMD_TIMEOUT); + ARRAY_SIZE(cgatt_cmd), "AT+CGATT?", &mdata.sem_response, + MDM_CMD_TIMEOUT); if (ret < 0) { LOG_ERR("Failed to query cgatt"); goto error; } counter = 0; - while (counter++ < MDM_MAX_CGATT_WAITS && (mdata.status_flags & SIM7080_STATUS_FLAG_ATTACHED) == 0) { + while (counter++ < MDM_MAX_CGATT_WAITS && + (mdata.status_flags & SIM7080_STATUS_FLAG_ATTACHED) == 0) { ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, cgatt_cmd, - ARRAY_SIZE(cgatt_cmd), "AT+CGATT?", &mdata.sem_response, - MDM_CMD_TIMEOUT); + ARRAY_SIZE(cgatt_cmd), "AT+CGATT?", &mdata.sem_response, + MDM_CMD_TIMEOUT); if (ret < 0) { LOG_ERR("Failed to query cgatt"); goto error; @@ -182,11 +183,11 @@ int sim7080_pdp_activate(void) counter = 0; while (counter++ < MDM_MAX_CEREG_WAITS && mdata.mdm_registration != 1 && - mdata.mdm_registration != 5) { + mdata.mdm_registration != 5) { k_sleep(K_SECONDS(1)); ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, cmds, ARRAY_SIZE(cmds), buf, - &mdata.sem_response, MDM_CMD_TIMEOUT); + &mdata.sem_response, MDM_CMD_TIMEOUT); if (ret < 0) { LOG_ERR("Failed to query registration"); goto error; @@ -211,7 +212,7 @@ int sim7080_pdp_activate(void) * Now activate the pdp context and wait for confirmation. */ ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, NULL, 0, "AT+CNACT=0,1", - &mdata.sem_response, MDM_CMD_TIMEOUT); + &mdata.sem_response, MDM_CMD_TIMEOUT); if (ret < 0) { LOG_ERR("Could not activate PDP context."); goto error; @@ -229,7 +230,7 @@ int sim7080_pdp_activate(void) sim7080_change_state(SIM7080_STATE_NETWORKING); k_work_reschedule_for_queue(&modem_workq, &mdata.rssi_query_work, - K_SECONDS(RSSI_TIMEOUT_SECS)); + K_SECONDS(RSSI_TIMEOUT_SECS)); error: return ret; @@ -245,7 +246,7 @@ int sim7080_pdp_deactivate(void) } ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, NULL, 0, "AT+CNACT=0,0", - &mdata.sem_response, MDM_CMD_TIMEOUT); + &mdata.sem_response, MDM_CMD_TIMEOUT); if (ret < 0) { LOG_ERR("Could not deactivate PDP context."); goto out; diff --git a/drivers/modem/simcom/sim7080/sim7080_sms.c b/drivers/modem/simcom/sim7080/sim7080_sms.c index 2c4f2b256e611..118149f3561e5 100644 --- a/drivers/modem/simcom/sim7080/sim7080_sms.c +++ b/drivers/modem/simcom/sim7080/sim7080_sms.c @@ -362,7 +362,7 @@ int mdm_sim7080_read_sms(struct sim7080_sms_buffer *buffer) mdata.sms_buffer_pos = 0; ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, cmds, ARRAY_SIZE(cmds), "AT+CMGL=4", - &mdata.sem_response, K_SECONDS(20)); + &mdata.sem_response, K_SECONDS(20)); if (ret < 0) { return -1; } @@ -381,7 +381,7 @@ int mdm_sim7080_delete_sms(uint16_t index) } ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, NULL, 0, buf, &mdata.sem_response, - K_SECONDS(5)); + K_SECONDS(5)); if (ret < 0) { return -1; } diff --git a/drivers/modem/simcom/sim7080/sim7080_sock.c b/drivers/modem/simcom/sim7080/sim7080_sock.c index 971476e0210fd..66b52d9a141a4 100644 --- a/drivers/modem/simcom/sim7080/sim7080_sock.c +++ b/drivers/modem/simcom/sim7080/sim7080_sock.c @@ -77,7 +77,7 @@ static int offload_connect(void *obj, const struct sockaddr *addr, socklen_t add } ret = snprintk(buf, sizeof(buf), "AT+CAOPEN=%d,0,\"%s\",\"%s\",%d", sock->id, - protocol, ip_str, dst_port); + protocol, ip_str, dst_port); if (ret < 0) { LOG_ERR("Failed to build connect command. ID: %d, FD: %d", sock->id, sock->sock_fd); errno = ENOMEM; @@ -86,7 +86,7 @@ static int offload_connect(void *obj, const struct sockaddr *addr, socklen_t add mdata.socket_open_rc = 1; ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, cmd, ARRAY_SIZE(cmd), buf, - &mdata.sem_response, MDM_CONNECT_TIMEOUT); + &mdata.sem_response, MDM_CONNECT_TIMEOUT); if (ret < 0) { LOG_ERR("%s ret: %d", buf, ret); goto error; @@ -124,7 +124,7 @@ MODEM_CMD_DEFINE(on_cmd_casend) * then send a OK or ERROR. */ static ssize_t offload_sendto(void *obj, const void *buf, size_t len, int flags, - const struct sockaddr *dest_addr, socklen_t addrlen) + const struct sockaddr *dest_addr, socklen_t addrlen) { int ret; struct modem_socket *sock = (struct modem_socket *)obj; @@ -191,7 +191,7 @@ static ssize_t offload_sendto(void *obj, const void *buf, size_t len, int flags, /* Send CASEND */ mdata.current_sock_written = len; ret = modem_cmd_send_nolock(&mctx.iface, &mctx.cmd_handler, NULL, 0U, send_buf, NULL, - K_NO_WAIT); + K_NO_WAIT); if (ret < 0) { LOG_ERR("Failed to send CASEND"); goto exit; @@ -351,7 +351,7 @@ static ssize_t offload_recvfrom(void *obj, void *buf, size_t max_len, int flags, mdata.current_sock_fd = sock->sock_fd; ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, data_cmd, ARRAY_SIZE(data_cmd), - sendbuf, &mdata.sem_response, MDM_CMD_TIMEOUT); + sendbuf, &mdata.sem_response, MDM_CMD_TIMEOUT); if (ret < 0) { errno = -ret; ret = -1; @@ -432,7 +432,7 @@ static void socket_close(struct modem_socket *sock) snprintk(buf, sizeof(buf), "AT+CACLOSE=%d", sock->id); ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, NULL, 0U, buf, &mdata.sem_response, - MDM_CMD_TIMEOUT); + MDM_CMD_TIMEOUT); if (ret < 0) { LOG_ERR("%s ret: %d", buf, ret); } @@ -562,6 +562,7 @@ const struct socket_op_vtable offload_socket_fd_op_vtable = { void sim7080_handle_sock_data_indication(int fd) { struct modem_socket *sock = modem_socket_from_fd(&mdata.socket_config, fd); + if (!sock) { LOG_INF("No socket with fd %d", fd); return; @@ -577,6 +578,7 @@ void sim7080_handle_sock_data_indication(int fd) void sim7080_handle_sock_state(int fd, uint8_t state) { struct modem_socket *sock = modem_socket_from_fd(&mdata.socket_config, fd); + if (!sock) { LOG_INF("No socket with fd %d", fd); return; @@ -638,8 +640,6 @@ int mdm_sim7080_stop_network(void) goto out; } - //TODO: close sockets - ret = sim7080_pdp_deactivate(); out: diff --git a/drivers/modem/simcom/sim7080/sim7080_utils.c b/drivers/modem/simcom/sim7080/sim7080_utils.c index dff468b4cbb3b..a58745cad998f 100644 --- a/drivers/modem/simcom/sim7080/sim7080_utils.c +++ b/drivers/modem/simcom/sim7080/sim7080_utils.c @@ -12,70 +12,71 @@ LOG_MODULE_REGISTER(modem_simcom_sim7080_utils, CONFIG_MODEM_LOG_LEVEL); #include "sim7080.h" -int sim7080_utils_parse_time(uint8_t *date, uint8_t *time, struct tm *t) +int sim7080_utils_parse_time(uint8_t *date, uint8_t *time_str, struct tm *t) { - char *saveptr; - int ret = -1; + char *saveptr; + int ret = -1; - if (!date || !time || !t) { - ret = -EINVAL; - goto out; - } + if (!date || !time_str || !t) { + ret = -EINVAL; + goto out; + } - memset(t, 0, sizeof(*t)); + memset(t, 0, sizeof(*t)); - char *tmp = strtok_r(date, "/", &saveptr); - if (tmp == NULL) { - LOG_WRN("Failed to parse year"); - goto out; - } + char *tmp = strtok_r(date, "/", &saveptr); - t->tm_year = (int)strtol(tmp, NULL, 10) - 1900; + if (tmp == NULL) { + LOG_WRN("Failed to parse year"); + goto out; + } - tmp = strtok_r(NULL, "/", &saveptr); - if (tmp == NULL) { - LOG_WRN("Failed to parse month"); - goto out; - } + t->tm_year = (int)strtol(tmp, NULL, 10) - 1900; - t->tm_mon = (int)strtol(tmp, NULL, 10) - 1; + tmp = strtok_r(NULL, "/", &saveptr); + if (tmp == NULL) { + LOG_WRN("Failed to parse month"); + goto out; + } - tmp = strtok_r(NULL, "", &saveptr); - if (tmp == NULL) { - LOG_WRN("Failed to parse day"); - goto out; - } + t->tm_mon = (int)strtol(tmp, NULL, 10) - 1; - t->tm_mday = (int)strtol(tmp, NULL, 10); + tmp = strtok_r(NULL, "", &saveptr); + if (tmp == NULL) { + LOG_WRN("Failed to parse day"); + goto out; + } - tmp = strtok_r(time, ":", &saveptr); - if (tmp == NULL) { - LOG_WRN("Failed to parse hour"); - goto out; - } + t->tm_mday = (int)strtol(tmp, NULL, 10); - t->tm_hour = (int)strtol(tmp, NULL, 10); + tmp = strtok_r(time_str, ":", &saveptr); + if (tmp == NULL) { + LOG_WRN("Failed to parse hour"); + goto out; + } - tmp = strtok_r(NULL, ":", &saveptr); - if (tmp == NULL) { - LOG_WRN("Failed to parse minute"); - goto out; - } + t->tm_hour = (int)strtol(tmp, NULL, 10); - t->tm_min = (int)strtol(tmp, NULL, 10); + tmp = strtok_r(NULL, ":", &saveptr); + if (tmp == NULL) { + LOG_WRN("Failed to parse minute"); + goto out; + } - tmp = strtok_r(NULL, "+", &saveptr); - if (tmp == NULL) { - LOG_WRN("Failed to parse second"); - goto out; - } + t->tm_min = (int)strtol(tmp, NULL, 10); - t->tm_sec = (int)strtol(tmp, NULL, 10); + tmp = strtok_r(NULL, "+", &saveptr); + if (tmp == NULL) { + LOG_WRN("Failed to parse second"); + goto out; + } - /* Mark dst as not available */ - t->tm_isdst = -1; + t->tm_sec = (int)strtol(tmp, NULL, 10); - ret = 0; + /* Mark dst as not available */ + t->tm_isdst = -1; + + ret = 0; out: - return ret; + return ret; } diff --git a/include/zephyr/drivers/modem/simcom-sim7080.h b/include/zephyr/drivers/modem/simcom-sim7080.h index 082542a4bf34c..bc1b2bf29aacc 100644 --- a/include/zephyr/drivers/modem/simcom-sim7080.h +++ b/include/zephyr/drivers/modem/simcom-sim7080.h @@ -232,7 +232,7 @@ int mdm_sim7080_power_off(void); /** * Forcefully reset the modem by pulling pwrkey for 15 seconds. * @note The state of the modem may be undefined after calling - * this function. Call mdm_sim7080_power_on after force reset. + * this function. Call mdm_sim7080_power_on after force reset. */ void mdm_sim7080_force_reset(void); @@ -241,7 +241,7 @@ void mdm_sim7080_force_reset(void); * * @return 0 on success. Otherwise <0 is returned. * @note The modem needs to be booted for this function to work. - * Concurrent use of network and gnss is not possible. + * Concurrent use of network and gnss is not possible. */ int mdm_sim7080_start_network(void); @@ -257,7 +257,7 @@ int mdm_sim7080_stop_network(void); * * @return 0 on success. Otherwise <0 is returned. * @note The modem needs to be booted for this function to work. - * Concurrent use of network and gnss is not possible. + * Concurrent use of network and gnss is not possible. */ int mdm_sim7080_start_gnss(void); @@ -266,7 +266,7 @@ int mdm_sim7080_start_gnss(void); * * @return 0 on success. Otherwise <0 is returned. * @note The modem needs to be booted for this function to work. - * Concurrent use of network and gnss is not possible. + * Concurrent use of network and gnss is not possible. * @note If enabling xtra functionality fails a normal cold start will be performed. */ int mdm_sim7080_start_gnss_xtra(void); From 3ad5c2c3aa518efbb54cbf48aa6da63199a17330 Mon Sep 17 00:00:00 2001 From: Lukas Gehreke Date: Mon, 15 Sep 2025 09:16:09 +0200 Subject: [PATCH 26/28] drivers: modem: sim7080: removed error label in modem_setup Removed label because the compliance checks fail. Signed-off-by: Lukas Gehreke --- drivers/modem/simcom/sim7080/sim7080.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/modem/simcom/sim7080/sim7080.c b/drivers/modem/simcom/sim7080/sim7080.c index 1053178242815..43aeff0f97698 100644 --- a/drivers/modem/simcom/sim7080/sim7080.c +++ b/drivers/modem/simcom/sim7080/sim7080.c @@ -649,7 +649,7 @@ static int modem_setup(void) ret = modem_boot(true); if (ret < 0) { LOG_ERR("Booting modem failed!!"); - goto error; + return ret; } ret = modem_cmd_handler_setup_cmds(&mctx.iface, &mctx.cmd_handler, setup_cmds, @@ -657,13 +657,13 @@ static int modem_setup(void) MDM_REGISTRATION_TIMEOUT); if (ret < 0) { LOG_ERR("Failed to send init commands!"); - goto error; + return ret; } if (strcmp(mdata.mdm_model, "SIMCOM_SIM7080") != 0) { LOG_ERR("Wrong modem model: %s", mdata.mdm_model); ret = -EINVAL; - goto error; + return ret; } #if IS_ENABLED(CONFIG_MODEM_SIMCOM_SIM7080_BOOT_TYPE_CONSTRAINED) @@ -674,7 +674,6 @@ static int modem_setup(void) #error No boot type selected #endif -error: return ret; } From 0868162ef8c09ed35659e460f7d88029baabd6e4 Mon Sep 17 00:00:00 2001 From: Lukas Gehreke Date: Mon, 13 Oct 2025 11:39:44 +0200 Subject: [PATCH 27/28] drivers: modem: sim7080: Added missing doxygen docu to public header. Added missing doxygen comments to public header. Signed-off-by: Lukas Gehreke --- include/zephyr/drivers/modem/simcom-sim7080.h | 163 ++++++++++-------- 1 file changed, 87 insertions(+), 76 deletions(-) diff --git a/include/zephyr/drivers/modem/simcom-sim7080.h b/include/zephyr/drivers/modem/simcom-sim7080.h index bc1b2bf29aacc..2bb6a49346e5c 100644 --- a/include/zephyr/drivers/modem/simcom-sim7080.h +++ b/include/zephyr/drivers/modem/simcom-sim7080.h @@ -1,4 +1,6 @@ -/* +/** @file + * @brief Simcom SIM7080 modem public API header file. + * * Copyright (C) 2021 metraTec GmbH * * SPDX-License-Identifier: Apache-2.0 @@ -16,18 +18,23 @@ extern "C" { #endif +/** Maximum Length of GNSS UTC data */ #define SIM7080_GNSS_DATA_UTC_LEN 20 +/** Maximum SMS length */ #define SIM7080_SMS_MAX_LEN 160 +/** Maximum UE system information band size */ #define SIM7080_UE_SYS_INFO_BAND_SIZE 32 +/** Sim7080 modem state */ enum sim7080_state { - SIM7080_STATE_INIT = 0, - SIM7080_STATE_IDLE, - SIM7080_STATE_NETWORKING, - SIM7080_STATE_GNSS, - SIM7080_STATE_OFF, + SIM7080_STATE_INIT = 0, /**< Initial modem state */ + SIM7080_STATE_IDLE, /**< Modem idle */ + SIM7080_STATE_NETWORKING, /**< Network active */ + SIM7080_STATE_GNSS, /**< GNSS active */ + SIM7080_STATE_OFF, /**< Modem off */ }; +/** Sim7080 gnss data structure */ struct sim7080_gnss_data { /** * Whether gnss is powered or not. @@ -67,54 +74,47 @@ struct sim7080_gnss_data { uint16_t kmh; }; -/** - * Possible sms states in memory. - */ +/** Possible sms states in memory. */ enum sim7080_sms_stat { - SIM7080_SMS_STAT_REC_UNREAD = 0, - SIM7080_SMS_STAT_REC_READ, - SIM7080_SMS_STAT_STO_UNSENT, - SIM7080_SMS_STAT_STO_SENT, - SIM7080_SMS_STAT_ALL, + SIM7080_SMS_STAT_REC_UNREAD = 0, /**< Message unread */ + SIM7080_SMS_STAT_REC_READ, /**< Message read*/ + SIM7080_SMS_STAT_STO_UNSENT, /**< Message stored unsent */ + SIM7080_SMS_STAT_STO_SENT, /**< Message stored sent */ + SIM7080_SMS_STAT_ALL, /**< Status count */ }; -/** - * Possible ftp return codes. - */ +/** Possible ftp return codes. */ enum sim7080_ftp_rc { - /* Operation finished correctly. */ - SIM7080_FTP_RC_OK = 0, - /* Session finished. */ - SIM7080_FTP_RC_FINISHED, - /* An error occurred. */ - SIM7080_FTP_RC_ERROR, + SIM7080_FTP_RC_OK = 0, /**< Operation finished correctly. */ + SIM7080_FTP_RC_FINISHED, /**< Session finished. */ + SIM7080_FTP_RC_ERROR, /**< An error occurred. */ }; /** * Buffer structure for sms. */ struct sim7080_sms { - /* First octet of the sms. */ + /** First octet of the sms. */ uint8_t first_octet; - /* Message protocol identifier. */ + /** Message protocol identifier. */ uint8_t tp_pid; - /* Status of the sms in memory. */ + /** Status of the sms in memory. */ enum sim7080_sms_stat stat; - /* Index of the sms in memory. */ + /** Index of the sms in memory. */ uint16_t index; - /* Time the sms was received. */ + /** Time the sms was received. */ struct { - uint8_t year; - uint8_t month; - uint8_t day; - uint8_t hour; - uint8_t minute; - uint8_t second; - uint8_t timezone; + uint8_t year; /**< Current Year */ + uint8_t month; /**< Month of the year */ + uint8_t day; /**< Day of the month */ + uint8_t hour; /**< Hour of the day */ + uint8_t minute; /**< Minute */ + uint8_t second; /**< Second */ + uint8_t timezone; /**< Current timezone */ } time; - /* Buffered sms. */ + /** Buffered sms. */ char data[SIM7080_SMS_MAX_LEN + 1]; - /* Length of the sms in buffer. */ + /** Length of the sms in buffer. */ uint8_t data_len; }; @@ -122,90 +122,101 @@ struct sim7080_sms { * Buffer structure for sms reads. */ struct sim7080_sms_buffer { - /* sms structures to read to. */ + /** sms structures to read to. */ struct sim7080_sms *sms; - /* Number of sms structures. */ + /** Number of sms structures. */ uint8_t nsms; }; +/** UE system mode */ enum sim7080_ue_sys_mode { - SIM7080_UE_SYS_MODE_NO_SERVICE, - SIM7080_UE_SYS_MODE_GSM, - SIM7080_UE_SYS_MODE_LTE_CAT_M1, - SIM7080_UE_SYS_MODE_LTE_NB_IOT, + SIM7080_UE_SYS_MODE_NO_SERVICE, /**< No service */ + SIM7080_UE_SYS_MODE_GSM, /**< GSM */ + SIM7080_UE_SYS_MODE_LTE_CAT_M1, /**< LTE CAT M1 */ + SIM7080_UE_SYS_MODE_LTE_NB_IOT, /**< LTE NB IOT */ }; +/** UE operating mode */ enum sim7080_ue_op_mode { - SIM7080_UE_OP_MODE_ONLINE, - SIM7080_UE_OP_MODE_OFFLINE, - SIM7080_UE_OP_MODE_FACTORY_TEST_MODE, - SIM7080_UE_OP_MODE_RESET, - SIM7080_UE_OP_MODE_LOW_POWER_MODE, + SIM7080_UE_OP_MODE_ONLINE, /**< Online */ + SIM7080_UE_OP_MODE_OFFLINE, /**< Offline */ + SIM7080_UE_OP_MODE_FACTORY_TEST_MODE, /**< Factory test mode */ + SIM7080_UE_OP_MODE_RESET, /**< Reset */ + SIM7080_UE_OP_MODE_LOW_POWER_MODE, /**< Low power mode */ }; +/** + * Sim7080 ue system information structure for gsm. + */ struct sim7080_ue_sys_info_gsm { - /* Mobile country code */ + /** Mobile country code */ uint16_t mcc; - /* Mobile network code */ + /** Mobile network code */ uint16_t mcn; - /* Location area code */ + /** Location area code */ uint16_t lac; - /* Cell ID */ + /** Cell ID */ uint16_t cid; - /* Absolute radio frequency channel number */ + /** Absolute radio frequency channel number */ uint8_t arfcn[SIM7080_UE_SYS_INFO_BAND_SIZE + 1]; - /* RX level in dBm */ + /** RX level in dBm */ int16_t rx_lvl; - /* Track LO adjust */ + /** Track LO adjust */ int16_t track_lo_adjust; - /* C1 coefficient */ + /** C1 coefficient */ uint16_t c1; - /* C2 coefficient */ + /** C2 coefficient */ uint16_t c2; }; +/** + * Sim7080 ue system information structure for LTE. + */ struct sim7080_ue_sys_info_lte { - /* Mobile country code */ + /** Mobile country code */ uint16_t mcc; - /* Mobile network code */ + /** Mobile network code */ uint16_t mcn; - /* Tracing area code */ + /** Tracing area code */ uint16_t tac; - /* Serving Cell ID */ + /** Serving Cell ID */ uint32_t sci; - /* Physical Cell ID */ + /** Physical Cell ID */ uint16_t pci; - /* Frequency band */ + /** Frequency band */ uint8_t band[SIM7080_UE_SYS_INFO_BAND_SIZE + 1]; - /* E-UTRA absolute radio frequency channel number */ + /** E-UTRA absolute radio frequency channel number */ uint16_t earfcn; - /* Downlink bandwidth in MHz */ + /** Downlink bandwidth in MHz */ uint16_t dlbw; - /* Uplink bandwidth in MHz */ + /** Uplink bandwidth in MHz */ uint16_t ulbw; - /* Reference signal received quality in dB */ + /** Reference signal received quality in dB */ int16_t rsrq; - /* Reference signal received power in dBm */ + /** Reference signal received power in dBm */ int16_t rsrp; - /* Received signal strength indicator in dBm */ + /** Received signal strength indicator in dBm */ int16_t rssi; - /* Reference signal signal to noise ratio in dB */ + /** Reference signal signal to noise ratio in dB */ int16_t rssnr; - /* Signal to interference plus noise ratio in dB */ + /** Signal to interference plus noise ratio in dB */ int16_t sinr; }; +/** + * Sim7080 ue system information structure. + */ struct sim7080_ue_sys_info { - /* Refer to sim7080_ue_sys_mode */ + /** Refer to sim7080_ue_sys_mode */ enum sim7080_ue_sys_mode sys_mode; - /* Refer to sim7080_ue_op_mode */ + /** Refer to sim7080_ue_op_mode */ enum sim7080_ue_op_mode op_mode; union { - /* Only set if sys_mode is GSM */ + /** Only set if sys_mode is GSM */ struct sim7080_ue_sys_info_gsm gsm; - /* Only set if sys mode is LTE CAT-M1/NB-IOT */ + /** Only set if sys mode is LTE CAT-M1/NB-IOT */ struct sim7080_ue_sys_info_lte lte; - } cell; + } cell; /**< Cell information */ }; /** From fb71e4e823fae23d04b1e2c2ea5050e1cb376604 Mon Sep 17 00:00:00 2001 From: Lukas Gehreke Date: Mon, 13 Oct 2025 15:44:27 +0200 Subject: [PATCH 28/28] drivers: modem: sim7080: Made dns timeout and retry configurable Timeout and retries for DNS lookups were hardcoded. This commit introduces kconfig settings for the default values and functions for runtime configuration. Signed-off-by: Lukas Gehreke --- drivers/modem/simcom/sim7080/Kconfig | 14 +++++++++ drivers/modem/simcom/sim7080/sim7080.c | 3 ++ drivers/modem/simcom/sim7080/sim7080.h | 7 +++++ drivers/modem/simcom/sim7080/sim7080_dns.c | 31 ++++++++++++++++++- include/zephyr/drivers/modem/simcom-sim7080.h | 23 ++++++++++++++ 5 files changed, 77 insertions(+), 1 deletion(-) diff --git a/drivers/modem/simcom/sim7080/Kconfig b/drivers/modem/simcom/sim7080/Kconfig index 3d6d8f4a0fb68..34bee179b47f0 100644 --- a/drivers/modem/simcom/sim7080/Kconfig +++ b/drivers/modem/simcom/sim7080/Kconfig @@ -57,6 +57,20 @@ config MODEM_SIMCOM_SIM7080_BAUDRATE the modem is configured to use autobaud. The driver will then configure the modem to use a fixed baudrate for faster startups. +config MODEM_SIMCOM_SIM7080_DNS_DEFAULT_RECOUNT + int "Retry count for a DNS query" + range 0 10 + default 10 + help + The number of retries for a DNS lookup + +config MODEM_SIMCOM_SIM7080_DNS_DEFAULT_TIMEOUT + int "Timeout for a DNS query" + range 0 60000 + default 20000 + help + The timeout for DNS queries in milliseconds + choice MODEM_SIMCOM_SIM7080_RAT bool "Radio Access Technology Mode" default MODEM_SIMCOM_SIM7080_RAT_NB1 diff --git a/drivers/modem/simcom/sim7080/sim7080.c b/drivers/modem/simcom/sim7080/sim7080.c index 43aeff0f97698..d3cb6987dc2d5 100644 --- a/drivers/modem/simcom/sim7080/sim7080.c +++ b/drivers/modem/simcom/sim7080/sim7080.c @@ -832,6 +832,9 @@ static int modem_init(const struct device *dev) mdata.current_sock_fd = -1; mdata.current_sock_written = 0; + mdata.dns.recount = CONFIG_MODEM_SIMCOM_SIM7080_DNS_DEFAULT_RECOUNT; + mdata.dns.timeout = CONFIG_MODEM_SIMCOM_SIM7080_DNS_DEFAULT_TIMEOUT; + mdata.ftp.read_buffer = NULL; mdata.ftp.nread = 0; mdata.ftp.state = SIM7080_FTP_CONNECTION_STATE_INITIAL; diff --git a/drivers/modem/simcom/sim7080/sim7080.h b/drivers/modem/simcom/sim7080/sim7080.h index 6ff1c52897edf..57ca6c6e8a074 100644 --- a/drivers/modem/simcom/sim7080/sim7080.h +++ b/drivers/modem/simcom/sim7080/sim7080.h @@ -143,6 +143,13 @@ struct sim7080_data { uint8_t sms_buffer_pos; /* Status of the last http operation */ uint16_t http_status; + /* DNS related variables */ + struct { + /* Number of DNS retries */ + uint8_t recount; + /* Timeout in milliseconds */ + uint16_t timeout; + } dns; /* Ftp related variables. */ struct { /* User buffer for ftp data. */ diff --git a/drivers/modem/simcom/sim7080/sim7080_dns.c b/drivers/modem/simcom/sim7080/sim7080_dns.c index 68416df39f900..105de0ce3b294 100644 --- a/drivers/modem/simcom/sim7080/sim7080_dns.c +++ b/drivers/modem/simcom/sim7080/sim7080_dns.c @@ -115,7 +115,13 @@ static int offload_getaddrinfo(const char *node, const char *service, return DNS_EAI_NONAME; } - snprintk(sendbuf, sizeof(sendbuf), "AT+CDNSGIP=\"%s\",10,20000", node); + ret = snprintk(sendbuf, sizeof(sendbuf), "AT+CDNSGIP=\"%s\",%u,%u", node, + mdata.dns.recount, mdata.dns.timeout); + if (ret < 0) { + LOG_ERR("Formatting dns query failed"); + return ret; + } + ret = modem_cmd_send(&mctx.iface, &mctx.cmd_handler, cmd, ARRAY_SIZE(cmd), sendbuf, &mdata.sem_dns, MDM_DNS_TIMEOUT); if (ret < 0) { @@ -142,3 +148,26 @@ const struct socket_dns_offload offload_dns_ops = { .getaddrinfo = offload_getaddrinfo, .freeaddrinfo = offload_freeaddrinfo, }; + +int mdm_sim7080_dns_set_lookup_params(uint8_t recount, uint16_t timeout) +{ + if (recount > SIM7080_DNS_MAX_RECOUNT || timeout > SIM7080_DNS_MAX_TIMEOUT_MS) { + return -EINVAL; + } + + mdata.dns.recount = recount; + mdata.dns.timeout = timeout; + + return 0; +} + +void mdm_sim7080_dns_get_lookup_params(uint8_t *recount, uint16_t *timeout) +{ + if (recount) { + *recount = mdata.dns.recount; + } + + if (timeout) { + *timeout = mdata.dns.timeout; + } +} diff --git a/include/zephyr/drivers/modem/simcom-sim7080.h b/include/zephyr/drivers/modem/simcom-sim7080.h index 2bb6a49346e5c..0bafc04a5a683 100644 --- a/include/zephyr/drivers/modem/simcom-sim7080.h +++ b/include/zephyr/drivers/modem/simcom-sim7080.h @@ -24,6 +24,10 @@ extern "C" { #define SIM7080_SMS_MAX_LEN 160 /** Maximum UE system information band size */ #define SIM7080_UE_SYS_INFO_BAND_SIZE 32 +/** Maximum number of DNS retries */ +#define SIM7080_DNS_MAX_RECOUNT 10 +/** Maximum timeout for DNS queries in milliseconds */ +#define SIM7080_DNS_MAX_TIMEOUT_MS 60000 /** Sim7080 modem state */ enum sim7080_state { @@ -423,6 +427,25 @@ int mdm_sim7080_get_ue_sys_info(struct sim7080_ue_sys_info *info); */ int mdm_sim7080_get_local_time(struct tm *t); +/** + * Set the dns query lookup parameters. + * + * @param recount Number of retries per query. + * Maximum @c SIM7080_DNS_MAX_RECOUNT + * @param timeout Timeout for a dns query in milliseconds. + * Maximum @c SIM7080_DNS_MAX_TIMEOUT_MS + * @return 0 on success. Otherwise a negative error is returned. + */ +int mdm_sim7080_dns_set_lookup_params(uint8_t recount, uint16_t timeout); + +/** + * Get the dns query lookup parameters. + * + * @param recount [out] Number of retries per query. + * @param timeout [out] Timeout for a dns query in milliseconds. + */ +void mdm_sim7080_dns_get_lookup_params(uint8_t *recount, uint16_t *timeout); + #ifdef __cplusplus } #endif