From 6766cc137fc36112f2f174d0c961be2ce81a9b44 Mon Sep 17 00:00:00 2001 From: Olivier Lalonde Date: Fri, 16 May 2025 17:37:09 -0400 Subject: [PATCH 1/4] modem_cellular: Add support for the simcom a76xx modem Add support for the simcom a76xx modem which is similar to the simcom 7080 but has a few key differences. Tested with a simcom A7672SA module but as there is a single simcom A76XX AT commands manual, the driver should work with other modems of the series. Signed-off-by: Olivier Lalonde --- drivers/modem/Kconfig.cellular | 2 +- drivers/modem/modem_cellular.c | 72 ++++++++++++++++++- dts/bindings/modem/simcom,a76xx.yaml | 13 ++++ samples/net/cellular_modem/Kconfig | 12 ++++ samples/net/cellular_modem/README.rst | 8 +++ .../boards/nrf52840dk_nrf52840.conf | 3 + .../boards/nrf52840dk_nrf52840.overlay | 27 +++++++ samples/net/cellular_modem/src/main.c | 2 +- subsys/modem/Kconfig | 2 +- 9 files changed, 137 insertions(+), 4 deletions(-) create mode 100644 dts/bindings/modem/simcom,a76xx.yaml create mode 100644 samples/net/cellular_modem/Kconfig create mode 100644 samples/net/cellular_modem/boards/nrf52840dk_nrf52840.conf create mode 100644 samples/net/cellular_modem/boards/nrf52840dk_nrf52840.overlay diff --git a/drivers/modem/Kconfig.cellular b/drivers/modem/Kconfig.cellular index 1d15350b48e0..2773b0f9d5ca 100644 --- a/drivers/modem/Kconfig.cellular +++ b/drivers/modem/Kconfig.cellular @@ -14,7 +14,7 @@ config MODEM_CELLULAR select NET_L2_PPP_OPTION_MRU select NET_L2_PPP_PAP select NET_L2_PPP_MGMT - depends on (DT_HAS_QUECTEL_BG95_ENABLED || \ + depends on (DT_HAS_QUECTEL_BG95_ENABLED || DT_HAS_SIMCOM_A76XX_ENABLED || \ DT_HAS_SIMCOM_SIM7080_ENABLED || DT_HAS_U_BLOX_SARA_R4_ENABLED || \ DT_HAS_U_BLOX_SARA_R5_ENABLED || DT_HAS_SWIR_HL7800_ENABLED || \ DT_HAS_TELIT_ME910G1_ENABLED || DT_HAS_TELIT_ME310G1_ENABLED || \ diff --git a/drivers/modem/modem_cellular.c b/drivers/modem/modem_cellular.c index 7ca2001697ff..0dd55ecf1ca8 100644 --- a/drivers/modem/modem_cellular.c +++ b/drivers/modem/modem_cellular.c @@ -525,7 +525,9 @@ MODEM_CHAT_MATCHES_DEFINE(dial_abort_matches, MODEM_CHAT_MATCH("NO CARRIER", "", NULL), MODEM_CHAT_MATCH("NO DIALTONE", "", NULL)); -#if DT_HAS_COMPAT_STATUS_OKAY(swir_hl7800) || DT_HAS_COMPAT_STATUS_OKAY(sqn_gm02s) +#if DT_HAS_COMPAT_STATUS_OKAY(swir_hl7800) || \ + DT_HAS_COMPAT_STATUS_OKAY(sqn_gm02s) || \ + DT_HAS_COMPAT_STATUS_OKAY(simcom_a76xx) MODEM_CHAT_MATCH_DEFINE(connect_match, "CONNECT", "", NULL); #endif @@ -2064,6 +2066,51 @@ MODEM_CHAT_SCRIPT_DEFINE(simcom_sim7080_periodic_chat_script, modem_cellular_chat_callback_handler, 4); #endif +#if DT_HAS_COMPAT_STATUS_OKAY(simcom_a76xx) +MODEM_CHAT_SCRIPT_CMDS_DEFINE(simcom_a76xx_init_chat_script_cmds, + MODEM_CHAT_SCRIPT_CMD_RESP_NONE("AT", 100), + MODEM_CHAT_SCRIPT_CMD_RESP_NONE("AT", 100), + MODEM_CHAT_SCRIPT_CMD_RESP_NONE("AT", 100), + MODEM_CHAT_SCRIPT_CMD_RESP_NONE("AT", 100), + MODEM_CHAT_SCRIPT_CMD_RESP("ATE0", ok_match), + MODEM_CHAT_SCRIPT_CMD_RESP("AT+CFUN=4", ok_match), + MODEM_CHAT_SCRIPT_CMD_RESP("AT+CMEE=1", ok_match), + MODEM_CHAT_SCRIPT_CMD_RESP("AT+CREG=1", ok_match), + MODEM_CHAT_SCRIPT_CMD_RESP("AT+CGREG=1", ok_match), + MODEM_CHAT_SCRIPT_CMD_RESP("AT+CEREG=1", ok_match), + MODEM_CHAT_SCRIPT_CMD_RESP("AT+CREG?", ok_match), + MODEM_CHAT_SCRIPT_CMD_RESP("AT+CEREG?", ok_match), + MODEM_CHAT_SCRIPT_CMD_RESP("AT+CGREG?", ok_match), + MODEM_CHAT_SCRIPT_CMD_RESP("AT+CGSN", imei_match), + MODEM_CHAT_SCRIPT_CMD_RESP("", ok_match), + MODEM_CHAT_SCRIPT_CMD_RESP("AT+CGMM", cgmm_match), + MODEM_CHAT_SCRIPT_CMD_RESP("", ok_match), + MODEM_CHAT_SCRIPT_CMD_RESP_NONE("AT+CMUX=0,0,5,127", 300)); + +MODEM_CHAT_SCRIPT_DEFINE(simcom_a76xx_init_chat_script, simcom_a76xx_init_chat_script_cmds, + abort_matches, modem_cellular_chat_callback_handler, 10); + +MODEM_CHAT_SCRIPT_CMDS_DEFINE(simcom_a76xx_dial_chat_script_cmds, + MODEM_CHAT_SCRIPT_CMD_RESP("AT+CGDCONT=1,\"IP\"," + "\""CONFIG_MODEM_CELLULAR_APN"\"", + ok_match), + MODEM_CHAT_SCRIPT_CMD_RESP_MULT("AT+CGACT=0,1", allow_match), + MODEM_CHAT_SCRIPT_CMD_RESP("AT+CFUN=1", ok_match), + MODEM_CHAT_SCRIPT_CMD_RESP("ATD*99***1#", connect_match),); + +MODEM_CHAT_SCRIPT_DEFINE(simcom_a76xx_dial_chat_script, simcom_a76xx_dial_chat_script_cmds, + dial_abort_matches, modem_cellular_chat_callback_handler, 10); + +MODEM_CHAT_SCRIPT_CMDS_DEFINE(simcom_a76xx_periodic_chat_script_cmds, + MODEM_CHAT_SCRIPT_CMD_RESP("AT+CREG?", ok_match), + MODEM_CHAT_SCRIPT_CMD_RESP("AT+CEREG?", ok_match), + MODEM_CHAT_SCRIPT_CMD_RESP("AT+CGREG?", ok_match)); + +MODEM_CHAT_SCRIPT_DEFINE(simcom_a76xx_periodic_chat_script, + simcom_a76xx_periodic_chat_script_cmds, abort_matches, + modem_cellular_chat_callback_handler, 4); +#endif + #if DT_HAS_COMPAT_STATUS_OKAY(u_blox_sara_r4) MODEM_CHAT_SCRIPT_CMDS_DEFINE(u_blox_sara_r4_init_chat_script_cmds, MODEM_CHAT_SCRIPT_CMD_RESP_NONE("AT", 100), @@ -2567,6 +2614,25 @@ MODEM_CHAT_SCRIPT_DEFINE(sqn_gm02s_periodic_chat_script, &simcom_sim7080_dial_chat_script, \ &simcom_sim7080_periodic_chat_script, NULL) +#define MODEM_CELLULAR_DEVICE_SIMCOM_A76XX(inst) \ + MODEM_PPP_DEFINE(MODEM_CELLULAR_INST_NAME(ppp, inst), NULL, 98, 1500, 64); \ + \ + static struct modem_cellular_data MODEM_CELLULAR_INST_NAME(data, inst) = { \ + .chat_delimiter = "\r", \ + .chat_filter = "\n", \ + .ppp = &MODEM_CELLULAR_INST_NAME(ppp, inst), \ + }; \ + \ + MODEM_CELLULAR_DEFINE_AND_INIT_USER_PIPES(inst, \ + (user_pipe_0, 3), \ + (user_pipe_1, 4)) \ + \ + MODEM_CELLULAR_DEFINE_INSTANCE(inst, 500, 100, 20000, 5000, false, \ + NULL, \ + &simcom_a76xx_init_chat_script, \ + &simcom_a76xx_dial_chat_script, \ + &simcom_a76xx_periodic_chat_script, NULL) + #define MODEM_CELLULAR_DEVICE_U_BLOX_SARA_R4(inst) \ MODEM_PPP_DEFINE(MODEM_CELLULAR_INST_NAME(ppp, inst), NULL, 98, 1500, 64); \ \ @@ -2730,6 +2796,10 @@ DT_INST_FOREACH_STATUS_OKAY(MODEM_CELLULAR_DEVICE_QUECTEL_EG25_G) DT_INST_FOREACH_STATUS_OKAY(MODEM_CELLULAR_DEVICE_SIMCOM_SIM7080) #undef DT_DRV_COMPAT +#define DT_DRV_COMPAT simcom_a76xx +DT_INST_FOREACH_STATUS_OKAY(MODEM_CELLULAR_DEVICE_SIMCOM_A76XX) +#undef DT_DRV_COMPAT + #define DT_DRV_COMPAT u_blox_sara_r4 DT_INST_FOREACH_STATUS_OKAY(MODEM_CELLULAR_DEVICE_U_BLOX_SARA_R4) #undef DT_DRV_COMPAT diff --git a/dts/bindings/modem/simcom,a76xx.yaml b/dts/bindings/modem/simcom,a76xx.yaml new file mode 100644 index 000000000000..8b55f5f5a6b6 --- /dev/null +++ b/dts/bindings/modem/simcom,a76xx.yaml @@ -0,0 +1,13 @@ +# Copyright (C) 2021 metraTec GmbH +# SPDX-License-Identifier: Apache-2.0 + +description: Simcom A76XX modem + +compatible: "simcom,a76xx" + +include: uart-device.yaml + +properties: + mdm-power-gpios: + type: phandle-array + required: true diff --git a/samples/net/cellular_modem/Kconfig b/samples/net/cellular_modem/Kconfig new file mode 100644 index 000000000000..1fa2fde03204 --- /dev/null +++ b/samples/net/cellular_modem/Kconfig @@ -0,0 +1,12 @@ +# Copyright (c) 2025 Olivier Lalonde +# SPDX-License-Identifier: Apache-2.0 + +# Configuration options for cellular modem sample + +mainmenu "Cellular modem sample application" + +config SAMPLE_CELLULAR_MODEM_ENDPOINT_HOSTNAME + string "Endpoint hostname" + default "test-endpoint.com" + +source "Kconfig.zephyr" \ No newline at end of file diff --git a/samples/net/cellular_modem/README.rst b/samples/net/cellular_modem/README.rst index d46f61f958d8..8fb78d999d98 100644 --- a/samples/net/cellular_modem/README.rst +++ b/samples/net/cellular_modem/README.rst @@ -55,3 +55,11 @@ Next, the UART API must be specified using ``CONFIG_UART_INTERRUPT_DRIVEN=y`` or ``CONFIG_UART_ASYNC_API=y``. The driver doesn't support UART polling. Lastly, the APN must be configured using ``CONFIG_MODEM_CELLULAR_APN=""``. + +Server setup +************ + +.. code-block:: shell + git clone --depth=1 https://github.com/zephyrproject-rtos/zephyr.git + cd zephyr/samples/net/cellular_modem/server + python te.py \ No newline at end of file diff --git a/samples/net/cellular_modem/boards/nrf52840dk_nrf52840.conf b/samples/net/cellular_modem/boards/nrf52840dk_nrf52840.conf new file mode 100644 index 000000000000..28df0d33eb15 --- /dev/null +++ b/samples/net/cellular_modem/boards/nrf52840dk_nrf52840.conf @@ -0,0 +1,3 @@ +# Otherwise we run into DLCI buffer overruns (maybe due to lack of UART hardware flow control?) +CONFIG_MODEM_CMUX_WORK_BUFFER_SIZE=1507 +CONFIG_NET_IPV6=n \ No newline at end of file diff --git a/samples/net/cellular_modem/boards/nrf52840dk_nrf52840.overlay b/samples/net/cellular_modem/boards/nrf52840dk_nrf52840.overlay new file mode 100644 index 000000000000..b6010ffecc84 --- /dev/null +++ b/samples/net/cellular_modem/boards/nrf52840dk_nrf52840.overlay @@ -0,0 +1,27 @@ +/ { + aliases { + modem = &modem; + }; +}; + +/* Tested with Simcom A7672SA module connected via UART + * TX: P1.2 + * RX: P1.1 + * PWRKEY: P0.02 + */ +&uart1 { + compatible = "nordic,nrf-uarte"; + status = "okay"; + current-speed = <115200>; + /* The module I tested with doesn't expose RCS/CTS pins + * hw-flow-control; + */ + + pinctrl-0 = <&uart1_default>; + + modem: modem { + compatible = "simcom,a76xx"; + status = "okay"; + mdm-power-gpios = <&gpio0 2 (GPIO_ACTIVE_HIGH)>; + }; +}; diff --git a/samples/net/cellular_modem/src/main.c b/samples/net/cellular_modem/src/main.c index b332bc4f7546..60fc248f4109 100644 --- a/samples/net/cellular_modem/src/main.c +++ b/samples/net/cellular_modem/src/main.c @@ -15,7 +15,7 @@ #include -#define SAMPLE_TEST_ENDPOINT_HOSTNAME ("test-endpoint.com") +#define SAMPLE_TEST_ENDPOINT_HOSTNAME CONFIG_SAMPLE_CELLULAR_MODEM_ENDPOINT_HOSTNAME #define SAMPLE_TEST_ENDPOINT_UDP_ECHO_PORT (7780) #define SAMPLE_TEST_ENDPOINT_UDP_RECEIVE_PORT (7781) #define SAMPLE_TEST_PACKET_SIZE (1024) diff --git a/subsys/modem/Kconfig b/subsys/modem/Kconfig index 211c5fa084f1..265fb0c7b426 100644 --- a/subsys/modem/Kconfig +++ b/subsys/modem/Kconfig @@ -35,7 +35,7 @@ config MODEM_CMUX_DEFAULT_MTU_127 DT_HAS_SIMCOM_SIM7080_ENABLED || DT_HAS_U_BLOX_SARA_R4_ENABLED || \ DT_HAS_U_BLOX_SARA_R5_ENABLED || DT_HAS_SWIR_HL7800_ENABLED || \ DT_HAS_TELIT_ME910G1_ENABLED || DT_HAS_TELIT_ME310G1_ENABLED || \ - DT_HAS_SQN_GM02S_ENABLED) + DT_HAS_SQN_GM02S_ENABLED || DT_HAS_SIMCOM_A76XX_ENABLED) help Use the default MTU size of 127 bytes for the CMUX module on certain modems. This must match the AT+CMUX commands in the modem_cellular driver. From 460656935931337de23ecdcf8b42b1f7ef8aaba4 Mon Sep 17 00:00:00 2001 From: Olivier Lalonde Date: Fri, 16 May 2025 19:14:06 -0400 Subject: [PATCH 2/4] modem_cellular: simcom a76xx: add shutdown script Add a shutdown script to the a76xx modem driver. Signed-off-by: Olivier Lalonde --- drivers/modem/modem_cellular.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/drivers/modem/modem_cellular.c b/drivers/modem/modem_cellular.c index 0dd55ecf1ca8..bca23494af48 100644 --- a/drivers/modem/modem_cellular.c +++ b/drivers/modem/modem_cellular.c @@ -2109,6 +2109,14 @@ MODEM_CHAT_SCRIPT_CMDS_DEFINE(simcom_a76xx_periodic_chat_script_cmds, MODEM_CHAT_SCRIPT_DEFINE(simcom_a76xx_periodic_chat_script, simcom_a76xx_periodic_chat_script_cmds, abort_matches, modem_cellular_chat_callback_handler, 4); + +MODEM_CHAT_SCRIPT_CMDS_DEFINE(simcom_a76xx_shutdown_chat_script_cmds, + MODEM_CHAT_SCRIPT_CMD_RESP("AT+CPOF", ok_match)); + +MODEM_CHAT_SCRIPT_DEFINE(simcom_a76xx_shutdown_chat_script, + simcom_a76xx_shutdown_chat_script_cmds, abort_matches, + modem_cellular_chat_callback_handler, 15); + #endif #if DT_HAS_COMPAT_STATUS_OKAY(u_blox_sara_r4) @@ -2614,7 +2622,7 @@ MODEM_CHAT_SCRIPT_DEFINE(sqn_gm02s_periodic_chat_script, &simcom_sim7080_dial_chat_script, \ &simcom_sim7080_periodic_chat_script, NULL) -#define MODEM_CELLULAR_DEVICE_SIMCOM_A76XX(inst) \ +#define MODEM_CELLULAR_DEVICE_SIMCOM_A76XX(inst) \ MODEM_PPP_DEFINE(MODEM_CELLULAR_INST_NAME(ppp, inst), NULL, 98, 1500, 64); \ \ static struct modem_cellular_data MODEM_CELLULAR_INST_NAME(data, inst) = { \ @@ -2629,9 +2637,10 @@ MODEM_CHAT_SCRIPT_DEFINE(sqn_gm02s_periodic_chat_script, \ MODEM_CELLULAR_DEFINE_INSTANCE(inst, 500, 100, 20000, 5000, false, \ NULL, \ - &simcom_a76xx_init_chat_script, \ - &simcom_a76xx_dial_chat_script, \ - &simcom_a76xx_periodic_chat_script, NULL) + &simcom_a76xx_init_chat_script, \ + &simcom_a76xx_dial_chat_script, \ + &simcom_a76xx_periodic_chat_script, \ + &simcom_a76xx_shutdown_chat_script) #define MODEM_CELLULAR_DEVICE_U_BLOX_SARA_R4(inst) \ MODEM_PPP_DEFINE(MODEM_CELLULAR_INST_NAME(ppp, inst), NULL, 98, 1500, 64); \ From 5135b5a90cdaf2a761593c3e23621af1629224c9 Mon Sep 17 00:00:00 2001 From: Olivier Lalonde Date: Fri, 16 May 2025 20:16:18 -0400 Subject: [PATCH 3/4] modem_cellular: reset if carrier/dormant state in idle state Fixes a bug that prevent PPP from reconnecting when modem was restarted. Signed-off-by: Olivier Lalonde --- drivers/modem/modem_cellular.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/modem/modem_cellular.c b/drivers/modem/modem_cellular.c index bca23494af48..da3656bbd375 100644 --- a/drivers/modem/modem_cellular.c +++ b/drivers/modem/modem_cellular.c @@ -618,6 +618,8 @@ static int modem_cellular_on_idle_state_enter(struct modem_cellular_data *data) } modem_cellular_notify_user_pipes_disconnected(data); + net_if_carrier_off(modem_ppp_get_iface(data->ppp)); + net_if_dormant_off(modem_ppp_get_iface(data->ppp)); modem_chat_release(&data->chat); modem_ppp_release(data->ppp); modem_cmux_release(&data->cmux); From ae99709db0b0c4bb2eef1733a93e1c1e70dbb81b Mon Sep 17 00:00:00 2001 From: Olivier Lalonde Date: Sat, 17 May 2025 00:09:56 -0400 Subject: [PATCH 4/4] modem_celullar: simcom a76xx: optionally power on GNSS Optionally power on the GNSS module of simcom a76xx during the chat init script. This is necessary because it does not seem possible to power on the GNSS once the modem is in CMUX mode. Configurable through `CONFIG_MODEM_CELLULAR_POWER_ON_GNSS`. Signed-off-by: Olivier Lalonde --- drivers/modem/Kconfig.cellular | 4 ++++ drivers/modem/modem_cellular.c | 7 +++++++ 2 files changed, 11 insertions(+) diff --git a/drivers/modem/Kconfig.cellular b/drivers/modem/Kconfig.cellular index 2773b0f9d5ca..acd7d472552e 100644 --- a/drivers/modem/Kconfig.cellular +++ b/drivers/modem/Kconfig.cellular @@ -63,4 +63,8 @@ config MODEM_CELLULAR_NEW_BAUDRATE_DELAY default 100 if DT_HAS_U_BLOX_LARA_R6_ENABLED default 300 +config MODEM_CELLULAR_POWER_ON_GNSS + bool "Power on the modem's GNSS module" + depends on DT_HAS_SIMCOM_A76XX_ENABLED + default n endif diff --git a/drivers/modem/modem_cellular.c b/drivers/modem/modem_cellular.c index da3656bbd375..717c19ebd8c5 100644 --- a/drivers/modem/modem_cellular.c +++ b/drivers/modem/modem_cellular.c @@ -2075,6 +2075,13 @@ MODEM_CHAT_SCRIPT_CMDS_DEFINE(simcom_a76xx_init_chat_script_cmds, MODEM_CHAT_SCRIPT_CMD_RESP_NONE("AT", 100), MODEM_CHAT_SCRIPT_CMD_RESP_NONE("AT", 100), MODEM_CHAT_SCRIPT_CMD_RESP("ATE0", ok_match), + #ifdef CONFIG_MODEM_CELLULAR_POWER_ON_GNSS + /* Power on the GNSS module. + * We need to do this early, otherwise it does not work when + * doing it later (e.g. from a user pipe). + */ + MODEM_CHAT_SCRIPT_CMD_RESP_MULT("AT+CGNSSPWR=1", allow_match), + #endif MODEM_CHAT_SCRIPT_CMD_RESP("AT+CFUN=4", ok_match), MODEM_CHAT_SCRIPT_CMD_RESP("AT+CMEE=1", ok_match), MODEM_CHAT_SCRIPT_CMD_RESP("AT+CREG=1", ok_match),