Skip to content

modem_cellular: Add support for the simcom a76xx modem #90081

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion drivers/modem/Kconfig.cellular
Original file line number Diff line number Diff line change
Expand Up @@ -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 || \
Expand Down Expand Up @@ -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
90 changes: 89 additions & 1 deletion drivers/modem/modem_cellular.c
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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),
#if 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),
Expand Down Expand Up @@ -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); \
\
Expand Down Expand Up @@ -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
Expand Down
13 changes: 13 additions & 0 deletions dts/bindings/modem/simcom,a76xx.yaml
Original file line number Diff line number Diff line change
@@ -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
12 changes: 12 additions & 0 deletions samples/net/cellular_modem/Kconfig
Original file line number Diff line number Diff line change
@@ -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"
8 changes: 8 additions & 0 deletions samples/net/cellular_modem/README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
3 changes: 3 additions & 0 deletions samples/net/cellular_modem/boards/nrf52840dk_nrf52840.conf
Original file line number Diff line number Diff line change
@@ -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
27 changes: 27 additions & 0 deletions samples/net/cellular_modem/boards/nrf52840dk_nrf52840.overlay
Original file line number Diff line number Diff line change
@@ -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)>;
};
};
2 changes: 1 addition & 1 deletion samples/net/cellular_modem/src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@

#include <zephyr/drivers/cellular.h>

#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)
Expand Down
2 changes: 1 addition & 1 deletion subsys/modem/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down