modem_cellular: add U-Blox LARA-R6 and implement change of baudrate

U-Blox LARA-R6 was added to modem_cellular, and an additional state
was introduced where the UART baudrate is changed if the modem supports
it

Signed-off-by: Emil Lindqvist <emil@lindq.gr>
This commit is contained in:
Emil Lindqvist 2024-08-27 17:06:16 +02:00 committed by Anas Nashif
parent d1858d2074
commit 621338ec78
4 changed files with 211 additions and 4 deletions

View file

@ -180,6 +180,9 @@ Drivers and Sensors
* Modem
* Added support for the U-Blox LARA-R6 modem.
* Added support for setting the modem's UART baudrate during init.
* MIPI-DBI
* MSPI

View file

@ -17,7 +17,8 @@ config MODEM_CELLULAR
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_QUECTEL_EG25_G_ENABLED || \
DT_HAS_NORDIC_NRF91_SLM_ENABLED || DT_HAS_SQN_GM02S_ENABLED)
DT_HAS_NORDIC_NRF91_SLM_ENABLED || DT_HAS_SQN_GM02S_ENABLED || \
DT_HAS_U_BLOX_LARA_R6_ENABLED)
help
This driver uses the generic 3gpp AT commands, along
with the standard protocols CMUX and PPP, to configure
@ -55,4 +56,16 @@ config MODEM_CELLULAR_USER_PIPE_BUFFER_SIZES
int "The size of the buffers used for each user pipe in bytes."
default 128
config MODEM_CELLULAR_NEW_BAUDRATE
int "New baudrate to configure modem to, if supported"
range 9600 4000000
default 3000000 if DT_HAS_U_BLOX_LARA_R6_ENABLED
default 115200
config MODEM_CELLULAR_NEW_BAUDRATE_DELAY
int "Time modem takes to change baudrate, in milliseconds"
range 0 1000
default 100 if DT_HAS_U_BLOX_LARA_R6_ENABLED
default 300
endif

View file

@ -8,6 +8,7 @@
#include <zephyr/device.h>
#include <zephyr/drivers/gpio.h>
#include <zephyr/drivers/cellular.h>
#include <zephyr/drivers/uart.h>
#include <zephyr/modem/chat.h>
#include <zephyr/modem/cmux.h>
#include <zephyr/modem/pipe.h>
@ -51,6 +52,7 @@ enum modem_cellular_state {
MODEM_CELLULAR_STATE_RESET_PULSE,
MODEM_CELLULAR_STATE_POWER_ON_PULSE,
MODEM_CELLULAR_STATE_AWAIT_POWER_ON,
MODEM_CELLULAR_STATE_SET_BAUDRATE,
MODEM_CELLULAR_STATE_RUN_INIT_SCRIPT,
MODEM_CELLULAR_STATE_CONNECT_CMUX,
MODEM_CELLULAR_STATE_OPEN_DLCI1,
@ -157,6 +159,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 *set_baudrate_chat_script;
struct modem_cellular_user_pipe *user_pipes;
uint8_t user_pipes_size;
};
@ -172,6 +175,8 @@ static const char *modem_cellular_state_str(enum modem_cellular_state state)
return "power pulse";
case MODEM_CELLULAR_STATE_AWAIT_POWER_ON:
return "await power on";
case MODEM_CELLULAR_STATE_SET_BAUDRATE:
return "set baudrate";
case MODEM_CELLULAR_STATE_RUN_INIT_SCRIPT:
return "run init script";
case MODEM_CELLULAR_STATE_CONNECT_CMUX:
@ -605,7 +610,11 @@ static void modem_cellular_idle_event_handler(struct modem_cellular_data *data,
break;
}
modem_cellular_enter_state(data, MODEM_CELLULAR_STATE_RUN_INIT_SCRIPT);
if (config->set_baudrate_chat_script != NULL) {
modem_cellular_enter_state(data, MODEM_CELLULAR_STATE_SET_BAUDRATE);
} else {
modem_cellular_enter_state(data, MODEM_CELLULAR_STATE_RUN_INIT_SCRIPT);
}
break;
case MODEM_CELLULAR_EVENT_SUSPEND:
@ -717,8 +726,77 @@ static int modem_cellular_on_await_power_on_state_enter(struct modem_cellular_da
static void modem_cellular_await_power_on_event_handler(struct modem_cellular_data *data,
enum modem_cellular_event evt)
{
const struct modem_cellular_config *config =
(const struct modem_cellular_config *)data->dev->config;
switch (evt) {
case MODEM_CELLULAR_EVENT_TIMEOUT:
if (config->set_baudrate_chat_script != NULL) {
modem_cellular_enter_state(data, MODEM_CELLULAR_STATE_SET_BAUDRATE);
} else {
modem_cellular_enter_state(data, MODEM_CELLULAR_STATE_RUN_INIT_SCRIPT);
}
break;
case MODEM_CELLULAR_EVENT_SUSPEND:
modem_cellular_enter_state(data, MODEM_CELLULAR_STATE_IDLE);
break;
default:
break;
}
}
static int modem_cellular_on_set_baudrate_state_enter(struct modem_cellular_data *data)
{
modem_pipe_attach(data->uart_pipe, modem_cellular_bus_pipe_handler, data);
return modem_pipe_open_async(data->uart_pipe);
}
static void modem_cellular_set_baudrate_event_handler(struct modem_cellular_data *data,
enum modem_cellular_event evt)
{
const struct modem_cellular_config *config =
(const struct modem_cellular_config *)data->dev->config;
struct uart_config cfg = {0};
int ret;
switch (evt) {
case MODEM_CELLULAR_EVENT_BUS_OPENED:
modem_chat_attach(&data->chat, data->uart_pipe);
modem_chat_run_script_async(&data->chat, config->set_baudrate_chat_script);
break;
case MODEM_CELLULAR_EVENT_SCRIPT_SUCCESS:
/* Let modem reconfigure */
modem_cellular_start_timer(data, K_MSEC(CONFIG_MODEM_CELLULAR_NEW_BAUDRATE_DELAY));
break;
case MODEM_CELLULAR_EVENT_SCRIPT_FAILED:
/* Some modems save the new speed on first change, meaning the
* modem is already at the new baudrate, meaning no reply. So
* ignore any failures and continue as if baudrate is already set
*/
LOG_DBG("no reply from modem, assuming baudrate is already set");
__fallthrough;
case MODEM_CELLULAR_EVENT_TIMEOUT:
modem_chat_release(&data->chat);
modem_pipe_attach(data->uart_pipe, modem_cellular_bus_pipe_handler, data);
modem_pipe_close_async(data->uart_pipe);
ret = uart_config_get(config->uart, &cfg);
if (ret < 0) {
LOG_ERR("Failed to get UART configuration (%d)", ret);
break;
}
cfg.baudrate = CONFIG_MODEM_CELLULAR_NEW_BAUDRATE;
ret = uart_configure(config->uart, &cfg);
if (ret < 0) {
LOG_ERR("Failed to set new baudrate (%d)", ret);
break;
}
break;
case MODEM_CELLULAR_EVENT_BUS_CLOSED:
modem_cellular_enter_state(data, MODEM_CELLULAR_STATE_RUN_INIT_SCRIPT);
break;
@ -1121,6 +1199,10 @@ static int modem_cellular_on_state_enter(struct modem_cellular_data *data)
ret = modem_cellular_on_await_power_on_state_enter(data);
break;
case MODEM_CELLULAR_STATE_SET_BAUDRATE:
ret = modem_cellular_on_set_baudrate_state_enter(data);
break;
case MODEM_CELLULAR_STATE_RUN_INIT_SCRIPT:
ret = modem_cellular_on_run_init_script_state_enter(data);
break;
@ -1269,6 +1351,10 @@ static void modem_cellular_event_handler(struct modem_cellular_data *data,
modem_cellular_await_power_on_event_handler(data, evt);
break;
case MODEM_CELLULAR_STATE_SET_BAUDRATE:
modem_cellular_set_baudrate_event_handler(data, evt);
break;
case MODEM_CELLULAR_STATE_RUN_INIT_SCRIPT:
modem_cellular_run_init_script_event_handler(data, evt);
break;
@ -1899,6 +1985,61 @@ MODEM_CHAT_SCRIPT_DEFINE(u_blox_sara_r5_periodic_chat_script,
modem_cellular_chat_callback_handler, 4);
#endif
#if DT_HAS_COMPAT_STATUS_OKAY(u_blox_lara_r6)
MODEM_CHAT_SCRIPT_CMDS_DEFINE(u_blox_lara_r6_set_baudrate_chat_script_cmds,
MODEM_CHAT_SCRIPT_CMD_RESP("ATE0", ok_match),
MODEM_CHAT_SCRIPT_CMD_RESP("AT+IPR="
STRINGIFY(CONFIG_MODEM_CELLULAR_NEW_BAUDRATE), ok_match));
MODEM_CHAT_SCRIPT_DEFINE(u_blox_lara_r6_set_baudrate_chat_script,
u_blox_lara_r6_set_baudrate_chat_script_cmds,
abort_matches, modem_cellular_chat_callback_handler, 1);
MODEM_CHAT_SCRIPT_CMDS_DEFINE(u_blox_lara_r6_init_chat_script_cmds,
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("AT+CGMI", cgmi_match),
MODEM_CHAT_SCRIPT_CMD_RESP("", ok_match),
MODEM_CHAT_SCRIPT_CMD_RESP("AT+CGMR", cgmr_match),
MODEM_CHAT_SCRIPT_CMD_RESP("", ok_match),
MODEM_CHAT_SCRIPT_CMD_RESP("AT+CIMI", cimi_match),
MODEM_CHAT_SCRIPT_CMD_RESP("", ok_match),
MODEM_CHAT_SCRIPT_CMD_RESP("AT+CMUX=0,0,5,127", ok_match));
MODEM_CHAT_SCRIPT_DEFINE(u_blox_lara_r6_init_chat_script, u_blox_lara_r6_init_chat_script_cmds,
abort_matches, modem_cellular_chat_callback_handler, 10);
MODEM_CHAT_SCRIPT_CMDS_DEFINE(u_blox_lara_r6_dial_chat_script_cmds,
MODEM_CHAT_SCRIPT_CMD_RESP_MULT("AT+CGACT=0,1", allow_match),
MODEM_CHAT_SCRIPT_CMD_RESP("AT+CGDCONT=1,\"IP\","
"\""CONFIG_MODEM_CELLULAR_APN"\"",
ok_match),
MODEM_CHAT_SCRIPT_CMD_RESP("AT+CFUN=1", ok_match),
MODEM_CHAT_SCRIPT_CMD_RESP_NONE("ATD*99***1#", 0),);
MODEM_CHAT_SCRIPT_DEFINE(u_blox_lara_r6_dial_chat_script, u_blox_lara_r6_dial_chat_script_cmds,
dial_abort_matches, modem_cellular_chat_callback_handler, 10);
MODEM_CHAT_SCRIPT_CMDS_DEFINE(u_blox_lara_r6_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(u_blox_lara_r6_periodic_chat_script,
u_blox_lara_r6_periodic_chat_script_cmds, abort_matches,
modem_cellular_chat_callback_handler, 4);
#endif
#if DT_HAS_COMPAT_STATUS_OKAY(swir_hl7800)
MODEM_CHAT_SCRIPT_CMDS_DEFINE(swir_hl7800_init_chat_script_cmds,
MODEM_CHAT_SCRIPT_CMD_RESP_NONE("AT", 100),
@ -2142,6 +2283,7 @@ MODEM_CHAT_SCRIPT_DEFINE(sqn_gm02s_periodic_chat_script,
/* Helper to define modem instance */
#define MODEM_CELLULAR_DEFINE_INSTANCE(inst, power_ms, reset_ms, startup_ms, shutdown_ms, start, \
set_baudrate_script, \
init_script, \
dial_script, \
periodic_script) \
@ -2154,8 +2296,9 @@ MODEM_CHAT_SCRIPT_DEFINE(sqn_gm02s_periodic_chat_script,
.startup_time_ms = (startup_ms), \
.shutdown_time_ms = (shutdown_ms), \
.autostarts = (start), \
.init_chat_script = (init_script), \
.dial_chat_script = (dial_script), \
.set_baudrate_chat_script = (set_baudrate_script), \
.init_chat_script = (init_script), \
.dial_chat_script = (dial_script), \
.periodic_chat_script = (periodic_script), \
.user_pipes = MODEM_CELLULAR_GET_USER_PIPES(inst), \
.user_pipes_size = ARRAY_SIZE(MODEM_CELLULAR_GET_USER_PIPES(inst)), \
@ -2182,6 +2325,7 @@ MODEM_CHAT_SCRIPT_DEFINE(sqn_gm02s_periodic_chat_script,
(user_pipe_1, 4)) \
\
MODEM_CELLULAR_DEFINE_INSTANCE(inst, 1500, 100, 10000, 5000, false, \
NULL, \
&quectel_bg95_init_chat_script, \
&quectel_bg95_dial_chat_script, \
&quectel_bg95_periodic_chat_script)
@ -2200,6 +2344,7 @@ MODEM_CHAT_SCRIPT_DEFINE(sqn_gm02s_periodic_chat_script,
(user_pipe_1, 4)) \
\
MODEM_CELLULAR_DEFINE_INSTANCE(inst, 1500, 500, 15000, 5000, false, \
NULL, \
&quectel_eg25_g_init_chat_script, \
&quectel_eg25_g_dial_chat_script, \
&quectel_eg25_g_periodic_chat_script)
@ -2218,6 +2363,7 @@ MODEM_CHAT_SCRIPT_DEFINE(sqn_gm02s_periodic_chat_script,
(user_pipe_1, 4)) \
\
MODEM_CELLULAR_DEFINE_INSTANCE(inst, 1500, 100, 10000, 5000, false, \
NULL, \
&simcom_sim7080_init_chat_script, \
&simcom_sim7080_dial_chat_script, \
&simcom_sim7080_periodic_chat_script)
@ -2236,6 +2382,7 @@ MODEM_CHAT_SCRIPT_DEFINE(sqn_gm02s_periodic_chat_script,
(user_pipe_0, 4)) \
\
MODEM_CELLULAR_DEFINE_INSTANCE(inst, 1500, 100, 10000, 5000, false, \
NULL, \
&u_blox_sara_r4_init_chat_script, \
&u_blox_sara_r4_dial_chat_script, \
&u_blox_sara_r4_periodic_chat_script)
@ -2254,10 +2401,30 @@ MODEM_CHAT_SCRIPT_DEFINE(sqn_gm02s_periodic_chat_script,
(user_pipe_0, 3)) \
\
MODEM_CELLULAR_DEFINE_INSTANCE(inst, 1500, 100, 1500, 13000, true, \
NULL, \
&u_blox_sara_r5_init_chat_script, \
&u_blox_sara_r5_dial_chat_script, \
&u_blox_sara_r5_periodic_chat_script)
#define MODEM_CELLULAR_DEVICE_U_BLOX_LARA_R6(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, \
(gnss_pipe, 3), \
(user_pipe_0, 4)) \
\
MODEM_CELLULAR_DEFINE_INSTANCE(inst, 1500, 100, 9000, 5000, false, \
&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)
#define MODEM_CELLULAR_DEVICE_SWIR_HL7800(inst) \
MODEM_PPP_DEFINE(MODEM_CELLULAR_INST_NAME(ppp, inst), NULL, 98, 1500, 64); \
\
@ -2272,6 +2439,7 @@ MODEM_CHAT_SCRIPT_DEFINE(sqn_gm02s_periodic_chat_script,
(user_pipe_1, 4)) \
\
MODEM_CELLULAR_DEFINE_INSTANCE(inst, 1500, 100, 10000, 5000, false, \
NULL, \
&swir_hl7800_init_chat_script, \
&swir_hl7800_dial_chat_script, \
&swir_hl7800_periodic_chat_script)
@ -2289,6 +2457,7 @@ MODEM_CHAT_SCRIPT_DEFINE(sqn_gm02s_periodic_chat_script,
(user_pipe_0, 3)) \
\
MODEM_CELLULAR_DEFINE_INSTANCE(inst, 5050, 250, 15000, 5000, false, \
NULL, \
&telit_me910g1_init_chat_script, \
&telit_me910g1_dial_chat_script, \
&telit_me910g1_periodic_chat_script)
@ -2305,6 +2474,7 @@ MODEM_CHAT_SCRIPT_DEFINE(sqn_gm02s_periodic_chat_script,
(gnss_pipe, 3)) \
\
MODEM_CELLULAR_DEFINE_INSTANCE(inst, 100, 100, 2000, 10000, false, \
NULL, \
&nordic_nrf91_slm_init_chat_script, \
&nordic_nrf91_slm_dial_chat_script, \
&nordic_nrf91_slm_periodic_chat_script)
@ -2323,6 +2493,7 @@ MODEM_CHAT_SCRIPT_DEFINE(sqn_gm02s_periodic_chat_script,
(user_pipe_1, 4)) \
\
MODEM_CELLULAR_DEFINE_INSTANCE(inst, 1500, 100, 2000, 5000, true, \
NULL, \
&sqn_gm02s_init_chat_script, \
&sqn_gm02s_dial_chat_script, \
&sqn_gm02s_periodic_chat_script)
@ -2347,6 +2518,10 @@ DT_INST_FOREACH_STATUS_OKAY(MODEM_CELLULAR_DEVICE_U_BLOX_SARA_R4)
DT_INST_FOREACH_STATUS_OKAY(MODEM_CELLULAR_DEVICE_U_BLOX_SARA_R5)
#undef DT_DRV_COMPAT
#define DT_DRV_COMPAT u_blox_lara_r6
DT_INST_FOREACH_STATUS_OKAY(MODEM_CELLULAR_DEVICE_U_BLOX_LARA_R6)
#undef DT_DRV_COMPAT
#define DT_DRV_COMPAT swir_hl7800
DT_INST_FOREACH_STATUS_OKAY(MODEM_CELLULAR_DEVICE_SWIR_HL7800)
#undef DT_DRV_COMPAT

View file

@ -0,0 +1,16 @@
# Copyright (c) 2024, lindq.gr
# SPDX-License-Identifier: Apache-2.0
description: u-blox LARA-R6 modem
compatible: "u-blox,lara-r6"
include: uart-device.yaml
properties:
mdm-power-gpios:
type: phandle-array
required: true
mdm-reset-gpios:
type: phandle-array