diff --git a/drivers/modem/Kconfig.cellular b/drivers/modem/Kconfig.cellular index 1d15350b48e0..acd7d472552e 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 || \ @@ -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 7ca2001697ff..717c19ebd8c5 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 @@ -616,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); @@ -2064,6 +2068,66 @@ 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), + #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), + 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); + +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) MODEM_CHAT_SCRIPT_CMDS_DEFINE(u_blox_sara_r4_init_chat_script_cmds, MODEM_CHAT_SCRIPT_CMD_RESP_NONE("AT", 100), @@ -2567,6 +2631,26 @@ 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, \ + &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); \ \ @@ -2730,6 +2814,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.