modem_cellular: Add support to define a shutdown script for cellular modems
Add support to define a shutdown script for cellular modems, i.e. AT commands to shutdown the modem. This allows to shutdown the modem much quicker compared to using a power pulse which saves power. Signed-off-by: Niklas Gürtler <niklas.guertler@e-obs.de>
This commit is contained in:
parent
193023b075
commit
93330b07f2
1 changed files with 94 additions and 15 deletions
|
|
@ -61,6 +61,7 @@ enum modem_cellular_state {
|
|||
MODEM_CELLULAR_STATE_AWAIT_REGISTERED,
|
||||
MODEM_CELLULAR_STATE_CARRIER_ON,
|
||||
MODEM_CELLULAR_STATE_INIT_POWER_OFF,
|
||||
MODEM_CELLULAR_STATE_RUN_SHUTDOWN_SCRIPT,
|
||||
MODEM_CELLULAR_STATE_POWER_OFF_PULSE,
|
||||
MODEM_CELLULAR_STATE_AWAIT_POWER_OFF,
|
||||
};
|
||||
|
|
@ -96,6 +97,8 @@ struct modem_cellular_data {
|
|||
struct modem_cmux_dlci dlci2;
|
||||
struct modem_pipe *dlci1_pipe;
|
||||
struct modem_pipe *dlci2_pipe;
|
||||
/* Points to dlci2_pipe or NULL. Used for shutdown script if not NULL */
|
||||
struct modem_pipe *cmd_pipe;
|
||||
uint8_t dlci1_receive_buf[CONFIG_MODEM_CELLULAR_CMUX_MAX_FRAME_SIZE];
|
||||
/* DLCI 2 is only used for chat scripts. */
|
||||
uint8_t dlci2_receive_buf[CONFIG_MODEM_CELLULAR_CHAT_BUFFER_SIZES];
|
||||
|
|
@ -159,6 +162,7 @@ struct modem_cellular_config {
|
|||
const struct modem_chat_script *init_chat_script;
|
||||
const struct modem_chat_script *dial_chat_script;
|
||||
const struct modem_chat_script *periodic_chat_script;
|
||||
const struct modem_chat_script *shutdown_chat_script;
|
||||
const struct modem_chat_script *set_baudrate_chat_script;
|
||||
struct modem_cellular_user_pipe *user_pipes;
|
||||
uint8_t user_pipes_size;
|
||||
|
|
@ -193,6 +197,8 @@ static const char *modem_cellular_state_str(enum modem_cellular_state state)
|
|||
return "carrier on";
|
||||
case MODEM_CELLULAR_STATE_INIT_POWER_OFF:
|
||||
return "init power off";
|
||||
case MODEM_CELLULAR_STATE_RUN_SHUTDOWN_SCRIPT:
|
||||
return "run shutdown script";
|
||||
case MODEM_CELLULAR_STATE_POWER_OFF_PULSE:
|
||||
return "power off pulse";
|
||||
case MODEM_CELLULAR_STATE_AWAIT_POWER_OFF:
|
||||
|
|
@ -569,6 +575,20 @@ static void modem_cellular_delegate_event(struct modem_cellular_data *data,
|
|||
k_work_submit(&data->event_dispatch_work);
|
||||
}
|
||||
|
||||
static void modem_cellular_begin_power_off_pulse(struct modem_cellular_data *data)
|
||||
{
|
||||
const struct modem_cellular_config *config =
|
||||
(const struct modem_cellular_config *)data->dev->config;
|
||||
|
||||
modem_pipe_close_async(data->uart_pipe);
|
||||
|
||||
if (modem_cellular_gpio_is_enabled(&config->power_gpio)) {
|
||||
modem_cellular_enter_state(data, MODEM_CELLULAR_STATE_POWER_OFF_PULSE);
|
||||
} else {
|
||||
modem_cellular_enter_state(data, MODEM_CELLULAR_STATE_IDLE);
|
||||
}
|
||||
}
|
||||
|
||||
static int modem_cellular_on_idle_state_enter(struct modem_cellular_data *data)
|
||||
{
|
||||
const struct modem_cellular_config *config =
|
||||
|
|
@ -941,6 +961,7 @@ static void modem_cellular_open_dlci2_event_handler(struct modem_cellular_data *
|
|||
{
|
||||
switch (evt) {
|
||||
case MODEM_CELLULAR_EVENT_DLCI2_OPENED:
|
||||
data->cmd_pipe = data->dlci2_pipe;
|
||||
modem_cellular_enter_state(data, MODEM_CELLULAR_STATE_RUN_DIAL_SCRIPT);
|
||||
break;
|
||||
|
||||
|
|
@ -1089,7 +1110,6 @@ static int modem_cellular_on_carrier_on_state_leave(struct modem_cellular_data *
|
|||
|
||||
static int modem_cellular_on_init_power_off_state_enter(struct modem_cellular_data *data)
|
||||
{
|
||||
modem_pipe_close_async(data->uart_pipe);
|
||||
modem_cellular_start_timer(data, K_MSEC(2000));
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1102,12 +1122,15 @@ static void modem_cellular_init_power_off_event_handler(struct modem_cellular_da
|
|||
|
||||
switch (evt) {
|
||||
case MODEM_CELLULAR_EVENT_TIMEOUT:
|
||||
if (modem_cellular_gpio_is_enabled(&config->power_gpio)) {
|
||||
modem_cellular_enter_state(data, MODEM_CELLULAR_STATE_POWER_OFF_PULSE);
|
||||
/* Shutdown script can only be used if cmd_pipe is available, i.e. we are not in
|
||||
* some intermediary state without a pipe for commands available
|
||||
*/
|
||||
if (config->shutdown_chat_script != NULL && data->cmd_pipe != NULL) {
|
||||
modem_cellular_enter_state(data, MODEM_CELLULAR_STATE_RUN_SHUTDOWN_SCRIPT);
|
||||
break;
|
||||
}
|
||||
|
||||
modem_cellular_enter_state(data, MODEM_CELLULAR_STATE_IDLE);
|
||||
modem_cellular_begin_power_off_pulse(data);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
|
@ -1123,11 +1146,50 @@ static int modem_cellular_on_init_power_off_state_leave(struct modem_cellular_da
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int modem_cellular_on_run_shutdown_script_state_enter(struct modem_cellular_data *data)
|
||||
{
|
||||
const struct modem_cellular_config *config =
|
||||
(const struct modem_cellular_config *)data->dev->config;
|
||||
|
||||
modem_chat_attach(&data->chat, data->cmd_pipe);
|
||||
return modem_chat_run_script_async(&data->chat, config->shutdown_chat_script);
|
||||
}
|
||||
|
||||
static void modem_cellular_run_shutdown_script_event_handler(struct modem_cellular_data *data,
|
||||
enum modem_cellular_event evt)
|
||||
{
|
||||
switch (evt) {
|
||||
case MODEM_CELLULAR_EVENT_SCRIPT_FAILED:
|
||||
data->cmd_pipe = NULL;
|
||||
|
||||
/* If shutdown by software failed, try by power pulse if possible */
|
||||
modem_cellular_begin_power_off_pulse(data);
|
||||
|
||||
break;
|
||||
|
||||
case MODEM_CELLULAR_EVENT_SCRIPT_SUCCESS:
|
||||
modem_pipe_close_async(data->uart_pipe);
|
||||
data->cmd_pipe = NULL;
|
||||
modem_cellular_enter_state(data, MODEM_CELLULAR_STATE_IDLE);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int modem_cellular_on_run_shutdown_script_state_leave(struct modem_cellular_data *data)
|
||||
{
|
||||
modem_chat_release(&data->chat);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int modem_cellular_on_power_off_pulse_state_enter(struct modem_cellular_data *data)
|
||||
{
|
||||
const struct modem_cellular_config *config =
|
||||
(const struct modem_cellular_config *)data->dev->config;
|
||||
|
||||
data->cmd_pipe = NULL;
|
||||
gpio_pin_set_dt(&config->power_gpio, 1);
|
||||
modem_cellular_start_timer(data, K_MSEC(config->power_pulse_duration_ms));
|
||||
return 0;
|
||||
|
|
@ -1235,6 +1297,10 @@ static int modem_cellular_on_state_enter(struct modem_cellular_data *data)
|
|||
ret = modem_cellular_on_init_power_off_state_enter(data);
|
||||
break;
|
||||
|
||||
case MODEM_CELLULAR_STATE_RUN_SHUTDOWN_SCRIPT:
|
||||
ret = modem_cellular_on_run_shutdown_script_state_enter(data);
|
||||
break;
|
||||
|
||||
case MODEM_CELLULAR_STATE_POWER_OFF_PULSE:
|
||||
ret = modem_cellular_on_power_off_pulse_state_enter(data);
|
||||
break;
|
||||
|
|
@ -1292,6 +1358,10 @@ static int modem_cellular_on_state_leave(struct modem_cellular_data *data)
|
|||
ret = modem_cellular_on_init_power_off_state_leave(data);
|
||||
break;
|
||||
|
||||
case MODEM_CELLULAR_STATE_RUN_SHUTDOWN_SCRIPT:
|
||||
ret = modem_cellular_on_run_shutdown_script_state_leave(data);
|
||||
break;
|
||||
|
||||
case MODEM_CELLULAR_STATE_POWER_OFF_PULSE:
|
||||
ret = modem_cellular_on_power_off_pulse_state_leave(data);
|
||||
break;
|
||||
|
|
@ -1387,6 +1457,9 @@ static void modem_cellular_event_handler(struct modem_cellular_data *data,
|
|||
modem_cellular_init_power_off_event_handler(data, evt);
|
||||
break;
|
||||
|
||||
case MODEM_CELLULAR_STATE_RUN_SHUTDOWN_SCRIPT:
|
||||
modem_cellular_run_shutdown_script_event_handler(data, evt);
|
||||
|
||||
case MODEM_CELLULAR_STATE_POWER_OFF_PULSE:
|
||||
modem_cellular_power_off_pulse_event_handler(data, evt);
|
||||
break;
|
||||
|
|
@ -1655,6 +1728,8 @@ static int modem_cellular_init(const struct device *dev)
|
|||
|
||||
data->uart_pipe = modem_backend_uart_init(&data->uart_backend,
|
||||
&uart_backend_config);
|
||||
|
||||
data->cmd_pipe = NULL;
|
||||
}
|
||||
|
||||
{
|
||||
|
|
@ -2290,7 +2365,8 @@ MODEM_CHAT_SCRIPT_DEFINE(sqn_gm02s_periodic_chat_script,
|
|||
set_baudrate_script, \
|
||||
init_script, \
|
||||
dial_script, \
|
||||
periodic_script) \
|
||||
periodic_script, \
|
||||
shutdown_script) \
|
||||
static const struct modem_cellular_config MODEM_CELLULAR_INST_NAME(config, inst) = { \
|
||||
.uart = DEVICE_DT_GET(DT_INST_BUS(inst)), \
|
||||
.power_gpio = GPIO_DT_SPEC_INST_GET_OR(inst, mdm_power_gpios, {}), \
|
||||
|
|
@ -2304,6 +2380,7 @@ MODEM_CHAT_SCRIPT_DEFINE(sqn_gm02s_periodic_chat_script,
|
|||
.init_chat_script = (init_script), \
|
||||
.dial_chat_script = (dial_script), \
|
||||
.periodic_chat_script = (periodic_script), \
|
||||
.shutdown_chat_script = (shutdown_script), \
|
||||
.user_pipes = MODEM_CELLULAR_GET_USER_PIPES(inst), \
|
||||
.user_pipes_size = ARRAY_SIZE(MODEM_CELLULAR_GET_USER_PIPES(inst)), \
|
||||
}; \
|
||||
|
|
@ -2332,7 +2409,7 @@ MODEM_CHAT_SCRIPT_DEFINE(sqn_gm02s_periodic_chat_script,
|
|||
NULL, \
|
||||
&quectel_bg95_init_chat_script, \
|
||||
&quectel_bg95_dial_chat_script, \
|
||||
&quectel_bg95_periodic_chat_script)
|
||||
&quectel_bg95_periodic_chat_script, NULL)
|
||||
|
||||
#define MODEM_CELLULAR_DEVICE_QUECTEL_EG25_G(inst) \
|
||||
MODEM_PPP_DEFINE(MODEM_CELLULAR_INST_NAME(ppp, inst), NULL, 98, 1500, 64); \
|
||||
|
|
@ -2351,7 +2428,7 @@ MODEM_CHAT_SCRIPT_DEFINE(sqn_gm02s_periodic_chat_script,
|
|||
NULL, \
|
||||
&quectel_eg25_g_init_chat_script, \
|
||||
&quectel_eg25_g_dial_chat_script, \
|
||||
&quectel_eg25_g_periodic_chat_script)
|
||||
&quectel_eg25_g_periodic_chat_script, NULL)
|
||||
|
||||
#define MODEM_CELLULAR_DEVICE_SIMCOM_SIM7080(inst) \
|
||||
MODEM_PPP_DEFINE(MODEM_CELLULAR_INST_NAME(ppp, inst), NULL, 98, 1500, 64); \
|
||||
|
|
@ -2370,7 +2447,7 @@ MODEM_CHAT_SCRIPT_DEFINE(sqn_gm02s_periodic_chat_script,
|
|||
NULL, \
|
||||
&simcom_sim7080_init_chat_script, \
|
||||
&simcom_sim7080_dial_chat_script, \
|
||||
&simcom_sim7080_periodic_chat_script)
|
||||
&simcom_sim7080_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); \
|
||||
|
|
@ -2389,7 +2466,7 @@ MODEM_CHAT_SCRIPT_DEFINE(sqn_gm02s_periodic_chat_script,
|
|||
NULL, \
|
||||
&u_blox_sara_r4_init_chat_script, \
|
||||
&u_blox_sara_r4_dial_chat_script, \
|
||||
&u_blox_sara_r4_periodic_chat_script)
|
||||
&u_blox_sara_r4_periodic_chat_script, NULL)
|
||||
|
||||
#define MODEM_CELLULAR_DEVICE_U_BLOX_SARA_R5(inst) \
|
||||
MODEM_PPP_DEFINE(MODEM_CELLULAR_INST_NAME(ppp, inst), NULL, 98, 1500, 64); \
|
||||
|
|
@ -2408,7 +2485,7 @@ MODEM_CHAT_SCRIPT_DEFINE(sqn_gm02s_periodic_chat_script,
|
|||
NULL, \
|
||||
&u_blox_sara_r5_init_chat_script, \
|
||||
&u_blox_sara_r5_dial_chat_script, \
|
||||
&u_blox_sara_r5_periodic_chat_script)
|
||||
&u_blox_sara_r5_periodic_chat_script, NULL)
|
||||
|
||||
#define MODEM_CELLULAR_DEVICE_U_BLOX_LARA_R6(inst) \
|
||||
MODEM_PPP_DEFINE(MODEM_CELLULAR_INST_NAME(ppp, inst), NULL, 98, 1500, 64); \
|
||||
|
|
@ -2427,7 +2504,8 @@ MODEM_CHAT_SCRIPT_DEFINE(sqn_gm02s_periodic_chat_script,
|
|||
&u_blox_lara_r6_set_baudrate_chat_script, \
|
||||
&u_blox_lara_r6_init_chat_script, \
|
||||
&u_blox_lara_r6_dial_chat_script, \
|
||||
&u_blox_lara_r6_periodic_chat_script)
|
||||
&u_blox_lara_r6_periodic_chat_script, \
|
||||
NULL )
|
||||
|
||||
#define MODEM_CELLULAR_DEVICE_SWIR_HL7800(inst) \
|
||||
MODEM_PPP_DEFINE(MODEM_CELLULAR_INST_NAME(ppp, inst), NULL, 98, 1500, 64); \
|
||||
|
|
@ -2446,7 +2524,7 @@ MODEM_CHAT_SCRIPT_DEFINE(sqn_gm02s_periodic_chat_script,
|
|||
NULL, \
|
||||
&swir_hl7800_init_chat_script, \
|
||||
&swir_hl7800_dial_chat_script, \
|
||||
&swir_hl7800_periodic_chat_script)
|
||||
&swir_hl7800_periodic_chat_script, NULL)
|
||||
|
||||
#define MODEM_CELLULAR_DEVICE_TELIT_ME910G1(inst) \
|
||||
MODEM_PPP_DEFINE(MODEM_CELLULAR_INST_NAME(ppp, inst), NULL, 98, 1500, 64); \
|
||||
|
|
@ -2464,7 +2542,8 @@ MODEM_CHAT_SCRIPT_DEFINE(sqn_gm02s_periodic_chat_script,
|
|||
NULL, \
|
||||
&telit_me910g1_init_chat_script, \
|
||||
&telit_me910g1_dial_chat_script, \
|
||||
&telit_me910g1_periodic_chat_script)
|
||||
&telit_me910g1_periodic_chat_script, \
|
||||
NULL)
|
||||
|
||||
#define MODEM_CELLULAR_DEVICE_NORDIC_NRF91_SLM(inst) \
|
||||
MODEM_PPP_DEFINE(MODEM_CELLULAR_INST_NAME(ppp, inst), NULL, 98, 1500, 1500); \
|
||||
|
|
@ -2481,7 +2560,7 @@ MODEM_CHAT_SCRIPT_DEFINE(sqn_gm02s_periodic_chat_script,
|
|||
NULL, \
|
||||
&nordic_nrf91_slm_init_chat_script, \
|
||||
&nordic_nrf91_slm_dial_chat_script, \
|
||||
&nordic_nrf91_slm_periodic_chat_script)
|
||||
&nordic_nrf91_slm_periodic_chat_script, NULL)
|
||||
|
||||
#define MODEM_CELLULAR_DEVICE_SQN_GM02S(inst) \
|
||||
MODEM_PPP_DEFINE(MODEM_CELLULAR_INST_NAME(ppp, inst), NULL, 98, 1500, 64); \
|
||||
|
|
@ -2500,7 +2579,7 @@ MODEM_CHAT_SCRIPT_DEFINE(sqn_gm02s_periodic_chat_script,
|
|||
NULL, \
|
||||
&sqn_gm02s_init_chat_script, \
|
||||
&sqn_gm02s_dial_chat_script, \
|
||||
&sqn_gm02s_periodic_chat_script)
|
||||
&sqn_gm02s_periodic_chat_script, NULL)
|
||||
|
||||
#define DT_DRV_COMPAT quectel_bg95
|
||||
DT_INST_FOREACH_STATUS_OKAY(MODEM_CELLULAR_DEVICE_QUECTEL_BG95)
|
||||
|
|
|
|||
Loading…
Reference in a new issue