You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2952 lines
111 KiB
2952 lines
111 KiB
/* |
|
* Copyright (c) 2023 Bjarki Arge Andreasen |
|
* |
|
* SPDX-License-Identifier: Apache-2.0 |
|
*/ |
|
|
|
#include <zephyr/kernel.h> |
|
#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> |
|
#include <zephyr/modem/pipelink.h> |
|
#include <zephyr/modem/ppp.h> |
|
#include <zephyr/modem/backend/uart.h> |
|
#include <zephyr/net/ppp.h> |
|
#include <zephyr/pm/device.h> |
|
#include <zephyr/sys/atomic.h> |
|
|
|
#include <zephyr/logging/log.h> |
|
LOG_MODULE_REGISTER(modem_cellular, CONFIG_MODEM_LOG_LEVEL); |
|
|
|
#include <string.h> |
|
#include <stdlib.h> |
|
|
|
#define MODEM_CELLULAR_PERIODIC_SCRIPT_TIMEOUT \ |
|
K_MSEC(CONFIG_MODEM_CELLULAR_PERIODIC_SCRIPT_MS) |
|
|
|
#define MODEM_CELLULAR_DATA_IMEI_LEN (16) |
|
#define MODEM_CELLULAR_DATA_MODEL_ID_LEN (65) |
|
#define MODEM_CELLULAR_DATA_IMSI_LEN (23) |
|
#define MODEM_CELLULAR_DATA_ICCID_LEN (22) |
|
#define MODEM_CELLULAR_DATA_MANUFACTURER_LEN (65) |
|
#define MODEM_CELLULAR_DATA_FW_VERSION_LEN (65) |
|
|
|
#define MODEM_CELLULAR_RESERVED_DLCIS (2) |
|
|
|
/* Magic constants */ |
|
#define CSQ_RSSI_UNKNOWN (99) |
|
#define CESQ_RSRP_UNKNOWN (255) |
|
#define CESQ_RSRQ_UNKNOWN (255) |
|
|
|
/* Magic numbers to units conversions */ |
|
#define CSQ_RSSI_TO_DB(v) (-113 + (2 * (rssi))) |
|
#define CESQ_RSRP_TO_DB(v) (-140 + (v)) |
|
#define CESQ_RSRQ_TO_DB(v) (-20 + ((v) / 2)) |
|
|
|
enum modem_cellular_state { |
|
MODEM_CELLULAR_STATE_IDLE = 0, |
|
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, |
|
MODEM_CELLULAR_STATE_OPEN_DLCI2, |
|
MODEM_CELLULAR_STATE_RUN_DIAL_SCRIPT, |
|
MODEM_CELLULAR_STATE_AWAIT_REGISTERED, |
|
MODEM_CELLULAR_STATE_CARRIER_ON, |
|
MODEM_CELLULAR_STATE_DORMANT, |
|
MODEM_CELLULAR_STATE_INIT_POWER_OFF, |
|
MODEM_CELLULAR_STATE_RUN_SHUTDOWN_SCRIPT, |
|
MODEM_CELLULAR_STATE_POWER_OFF_PULSE, |
|
MODEM_CELLULAR_STATE_AWAIT_POWER_OFF, |
|
}; |
|
|
|
enum modem_cellular_event { |
|
MODEM_CELLULAR_EVENT_RESUME = 0, |
|
MODEM_CELLULAR_EVENT_SUSPEND, |
|
MODEM_CELLULAR_EVENT_SCRIPT_SUCCESS, |
|
MODEM_CELLULAR_EVENT_SCRIPT_FAILED, |
|
MODEM_CELLULAR_EVENT_CMUX_CONNECTED, |
|
MODEM_CELLULAR_EVENT_DLCI1_OPENED, |
|
MODEM_CELLULAR_EVENT_DLCI2_OPENED, |
|
MODEM_CELLULAR_EVENT_TIMEOUT, |
|
MODEM_CELLULAR_EVENT_REGISTERED, |
|
MODEM_CELLULAR_EVENT_DEREGISTERED, |
|
MODEM_CELLULAR_EVENT_BUS_OPENED, |
|
MODEM_CELLULAR_EVENT_BUS_CLOSED, |
|
MODEM_CELLULAR_EVENT_PPP_DEAD, |
|
}; |
|
|
|
struct modem_cellular_data { |
|
/* UART backend */ |
|
struct modem_pipe *uart_pipe; |
|
struct modem_backend_uart uart_backend; |
|
uint8_t uart_backend_receive_buf[CONFIG_MODEM_CELLULAR_UART_BUFFER_SIZES]; |
|
uint8_t uart_backend_transmit_buf[CONFIG_MODEM_CELLULAR_UART_BUFFER_SIZES]; |
|
|
|
/* CMUX */ |
|
struct modem_cmux cmux; |
|
uint8_t cmux_receive_buf[CONFIG_MODEM_CMUX_WORK_BUFFER_SIZE]; |
|
uint8_t cmux_transmit_buf[CONFIG_MODEM_CMUX_WORK_BUFFER_SIZE]; |
|
|
|
struct modem_cmux_dlci dlci1; |
|
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_CMUX_WORK_BUFFER_SIZE]; |
|
/* DLCI 2 is only used for chat scripts. */ |
|
uint8_t dlci2_receive_buf[CONFIG_MODEM_CMUX_WORK_BUFFER_SIZE]; |
|
|
|
/* Modem chat */ |
|
struct modem_chat chat; |
|
uint8_t chat_receive_buf[CONFIG_MODEM_CELLULAR_CHAT_BUFFER_SIZE]; |
|
uint8_t *chat_delimiter; |
|
uint8_t *chat_filter; |
|
uint8_t *chat_argv[32]; |
|
|
|
/* Status */ |
|
enum cellular_registration_status registration_status_gsm; |
|
enum cellular_registration_status registration_status_gprs; |
|
enum cellular_registration_status registration_status_lte; |
|
uint8_t rssi; |
|
uint8_t rsrp; |
|
uint8_t rsrq; |
|
uint8_t imei[MODEM_CELLULAR_DATA_IMEI_LEN]; |
|
uint8_t model_id[MODEM_CELLULAR_DATA_MODEL_ID_LEN]; |
|
uint8_t imsi[MODEM_CELLULAR_DATA_IMSI_LEN]; |
|
uint8_t iccid[MODEM_CELLULAR_DATA_ICCID_LEN]; |
|
uint8_t manufacturer[MODEM_CELLULAR_DATA_MANUFACTURER_LEN]; |
|
uint8_t fw_version[MODEM_CELLULAR_DATA_FW_VERSION_LEN]; |
|
|
|
/* PPP */ |
|
struct modem_ppp *ppp; |
|
struct net_mgmt_event_callback net_mgmt_event_callback; |
|
|
|
enum modem_cellular_state state; |
|
const struct device *dev; |
|
struct k_work_delayable timeout_work; |
|
|
|
/* Power management */ |
|
struct k_sem suspended_sem; |
|
|
|
/* Event dispatcher */ |
|
struct k_work event_dispatch_work; |
|
uint8_t event_buf[8]; |
|
struct ring_buf event_rb; |
|
struct k_mutex event_rb_lock; |
|
}; |
|
|
|
struct modem_cellular_user_pipe { |
|
struct modem_cmux_dlci dlci; |
|
uint8_t dlci_address; |
|
uint8_t *dlci_receive_buf; |
|
uint16_t dlci_receive_buf_size; |
|
struct modem_pipe *pipe; |
|
struct modem_pipelink *pipelink; |
|
}; |
|
|
|
struct modem_cellular_config { |
|
const struct device *uart; |
|
struct gpio_dt_spec power_gpio; |
|
struct gpio_dt_spec reset_gpio; |
|
struct gpio_dt_spec wake_gpio; |
|
uint16_t power_pulse_duration_ms; |
|
uint16_t reset_pulse_duration_ms; |
|
uint16_t startup_time_ms; |
|
uint16_t shutdown_time_ms; |
|
bool autostarts; |
|
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; |
|
}; |
|
|
|
static const char *modem_cellular_state_str(enum modem_cellular_state state) |
|
{ |
|
switch (state) { |
|
case MODEM_CELLULAR_STATE_IDLE: |
|
return "idle"; |
|
case MODEM_CELLULAR_STATE_RESET_PULSE: |
|
return "reset pulse"; |
|
case MODEM_CELLULAR_STATE_POWER_ON_PULSE: |
|
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: |
|
return "connect cmux"; |
|
case MODEM_CELLULAR_STATE_OPEN_DLCI1: |
|
return "open dlci1"; |
|
case MODEM_CELLULAR_STATE_OPEN_DLCI2: |
|
return "open dlci2"; |
|
case MODEM_CELLULAR_STATE_AWAIT_REGISTERED: |
|
return "await registered"; |
|
case MODEM_CELLULAR_STATE_RUN_DIAL_SCRIPT: |
|
return "run dial script"; |
|
case MODEM_CELLULAR_STATE_CARRIER_ON: |
|
return "carrier on"; |
|
case MODEM_CELLULAR_STATE_DORMANT: |
|
return "dormant"; |
|
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: |
|
return "await power off"; |
|
} |
|
|
|
return ""; |
|
} |
|
|
|
static const char *modem_cellular_event_str(enum modem_cellular_event event) |
|
{ |
|
switch (event) { |
|
case MODEM_CELLULAR_EVENT_RESUME: |
|
return "resume"; |
|
case MODEM_CELLULAR_EVENT_SUSPEND: |
|
return "suspend"; |
|
case MODEM_CELLULAR_EVENT_SCRIPT_SUCCESS: |
|
return "script success"; |
|
case MODEM_CELLULAR_EVENT_SCRIPT_FAILED: |
|
return "script failed"; |
|
case MODEM_CELLULAR_EVENT_CMUX_CONNECTED: |
|
return "cmux connected"; |
|
case MODEM_CELLULAR_EVENT_DLCI1_OPENED: |
|
return "dlci1 opened"; |
|
case MODEM_CELLULAR_EVENT_DLCI2_OPENED: |
|
return "dlci2 opened"; |
|
case MODEM_CELLULAR_EVENT_TIMEOUT: |
|
return "timeout"; |
|
case MODEM_CELLULAR_EVENT_REGISTERED: |
|
return "registered"; |
|
case MODEM_CELLULAR_EVENT_DEREGISTERED: |
|
return "deregistered"; |
|
case MODEM_CELLULAR_EVENT_BUS_OPENED: |
|
return "bus opened"; |
|
case MODEM_CELLULAR_EVENT_BUS_CLOSED: |
|
return "bus closed"; |
|
case MODEM_CELLULAR_EVENT_PPP_DEAD: |
|
return "ppp dead"; |
|
} |
|
|
|
return ""; |
|
} |
|
|
|
static bool modem_cellular_gpio_is_enabled(const struct gpio_dt_spec *gpio) |
|
{ |
|
return gpio->port != NULL; |
|
} |
|
|
|
static void modem_cellular_notify_user_pipes_connected(struct modem_cellular_data *data) |
|
{ |
|
const struct modem_cellular_config *config = |
|
(const struct modem_cellular_config *)data->dev->config; |
|
struct modem_cellular_user_pipe *user_pipe; |
|
struct modem_pipelink *pipelink; |
|
|
|
for (uint8_t i = 0; i < config->user_pipes_size; i++) { |
|
user_pipe = &config->user_pipes[i]; |
|
pipelink = user_pipe->pipelink; |
|
modem_pipelink_notify_connected(pipelink); |
|
} |
|
} |
|
|
|
static void modem_cellular_notify_user_pipes_disconnected(struct modem_cellular_data *data) |
|
{ |
|
const struct modem_cellular_config *config = |
|
(const struct modem_cellular_config *)data->dev->config; |
|
struct modem_cellular_user_pipe *user_pipe; |
|
struct modem_pipelink *pipelink; |
|
|
|
for (uint8_t i = 0; i < config->user_pipes_size; i++) { |
|
user_pipe = &config->user_pipes[i]; |
|
pipelink = user_pipe->pipelink; |
|
modem_pipelink_notify_disconnected(pipelink); |
|
} |
|
} |
|
|
|
static void modem_cellular_enter_state(struct modem_cellular_data *data, |
|
enum modem_cellular_state state); |
|
|
|
static void modem_cellular_delegate_event(struct modem_cellular_data *data, |
|
enum modem_cellular_event evt); |
|
|
|
static void modem_cellular_event_handler(struct modem_cellular_data *data, |
|
enum modem_cellular_event evt); |
|
|
|
static void modem_cellular_bus_pipe_handler(struct modem_pipe *pipe, |
|
enum modem_pipe_event event, |
|
void *user_data) |
|
{ |
|
struct modem_cellular_data *data = (struct modem_cellular_data *)user_data; |
|
|
|
switch (event) { |
|
case MODEM_PIPE_EVENT_OPENED: |
|
modem_cellular_delegate_event(data, MODEM_CELLULAR_EVENT_BUS_OPENED); |
|
break; |
|
|
|
case MODEM_PIPE_EVENT_CLOSED: |
|
modem_cellular_delegate_event(data, MODEM_CELLULAR_EVENT_BUS_CLOSED); |
|
break; |
|
|
|
default: |
|
break; |
|
} |
|
} |
|
|
|
static void modem_cellular_dlci1_pipe_handler(struct modem_pipe *pipe, |
|
enum modem_pipe_event event, |
|
void *user_data) |
|
{ |
|
struct modem_cellular_data *data = (struct modem_cellular_data *)user_data; |
|
|
|
switch (event) { |
|
case MODEM_PIPE_EVENT_OPENED: |
|
modem_cellular_delegate_event(data, MODEM_CELLULAR_EVENT_DLCI1_OPENED); |
|
break; |
|
|
|
default: |
|
break; |
|
} |
|
} |
|
|
|
static void modem_cellular_dlci2_pipe_handler(struct modem_pipe *pipe, |
|
enum modem_pipe_event event, |
|
void *user_data) |
|
{ |
|
struct modem_cellular_data *data = (struct modem_cellular_data *)user_data; |
|
|
|
switch (event) { |
|
case MODEM_PIPE_EVENT_OPENED: |
|
modem_cellular_delegate_event(data, MODEM_CELLULAR_EVENT_DLCI2_OPENED); |
|
break; |
|
|
|
default: |
|
break; |
|
} |
|
} |
|
|
|
static void modem_cellular_chat_callback_handler(struct modem_chat *chat, |
|
enum modem_chat_script_result result, |
|
void *user_data) |
|
{ |
|
struct modem_cellular_data *data = (struct modem_cellular_data *)user_data; |
|
|
|
if (result == MODEM_CHAT_SCRIPT_RESULT_SUCCESS) { |
|
modem_cellular_delegate_event(data, MODEM_CELLULAR_EVENT_SCRIPT_SUCCESS); |
|
} else { |
|
modem_cellular_delegate_event(data, MODEM_CELLULAR_EVENT_SCRIPT_FAILED); |
|
} |
|
} |
|
|
|
static void modem_cellular_chat_on_imei(struct modem_chat *chat, char **argv, uint16_t argc, |
|
void *user_data) |
|
{ |
|
struct modem_cellular_data *data = (struct modem_cellular_data *)user_data; |
|
|
|
if (argc != 2) { |
|
return; |
|
} |
|
|
|
strncpy(data->imei, argv[1], sizeof(data->imei) - 1); |
|
} |
|
|
|
static void modem_cellular_chat_on_cgmm(struct modem_chat *chat, char **argv, uint16_t argc, |
|
void *user_data) |
|
{ |
|
struct modem_cellular_data *data = (struct modem_cellular_data *)user_data; |
|
|
|
if (argc != 2) { |
|
return; |
|
} |
|
|
|
strncpy(data->model_id, argv[1], sizeof(data->model_id) - 1); |
|
} |
|
|
|
static void modem_cellular_chat_on_cgmi(struct modem_chat *chat, char **argv, uint16_t argc, |
|
void *user_data) |
|
{ |
|
struct modem_cellular_data *data = (struct modem_cellular_data *)user_data; |
|
|
|
if (argc != 2) { |
|
return; |
|
} |
|
|
|
strncpy(data->manufacturer, argv[1], sizeof(data->manufacturer) - 1); |
|
} |
|
|
|
static void modem_cellular_chat_on_cgmr(struct modem_chat *chat, char **argv, uint16_t argc, |
|
void *user_data) |
|
{ |
|
struct modem_cellular_data *data = (struct modem_cellular_data *)user_data; |
|
|
|
if (argc != 2) { |
|
return; |
|
} |
|
|
|
strncpy(data->fw_version, argv[1], sizeof(data->fw_version) - 1); |
|
} |
|
|
|
static void modem_cellular_chat_on_csq(struct modem_chat *chat, char **argv, uint16_t argc, |
|
void *user_data) |
|
{ |
|
struct modem_cellular_data *data = (struct modem_cellular_data *)user_data; |
|
|
|
if (argc != 3) { |
|
return; |
|
} |
|
|
|
data->rssi = (uint8_t)atoi(argv[1]); |
|
} |
|
|
|
static void modem_cellular_chat_on_cesq(struct modem_chat *chat, char **argv, uint16_t argc, |
|
void *user_data) |
|
{ |
|
struct modem_cellular_data *data = (struct modem_cellular_data *)user_data; |
|
|
|
if (argc != 7) { |
|
return; |
|
} |
|
|
|
data->rsrq = (uint8_t)atoi(argv[5]); |
|
data->rsrp = (uint8_t)atoi(argv[6]); |
|
} |
|
|
|
static void modem_cellular_chat_on_iccid(struct modem_chat *chat, char **argv, uint16_t argc, |
|
void *user_data) |
|
{ |
|
struct modem_cellular_data *data = (struct modem_cellular_data *)user_data; |
|
|
|
if (argc != 2) { |
|
return; |
|
} |
|
|
|
strncpy(data->iccid, argv[1], sizeof(data->iccid) - 1); |
|
} |
|
|
|
static void modem_cellular_chat_on_imsi(struct modem_chat *chat, char **argv, uint16_t argc, |
|
void *user_data) |
|
{ |
|
struct modem_cellular_data *data = (struct modem_cellular_data *)user_data; |
|
|
|
if (argc != 2) { |
|
return; |
|
} |
|
|
|
strncpy(data->imsi, argv[1], sizeof(data->imsi) - 1); |
|
} |
|
|
|
static bool modem_cellular_is_registered(struct modem_cellular_data *data) |
|
{ |
|
return (data->registration_status_gsm == CELLULAR_REGISTRATION_REGISTERED_HOME) |
|
|| (data->registration_status_gsm == CELLULAR_REGISTRATION_REGISTERED_ROAMING) |
|
|| (data->registration_status_gprs == CELLULAR_REGISTRATION_REGISTERED_HOME) |
|
|| (data->registration_status_gprs == CELLULAR_REGISTRATION_REGISTERED_ROAMING) |
|
|| (data->registration_status_lte == CELLULAR_REGISTRATION_REGISTERED_HOME) |
|
|| (data->registration_status_lte == CELLULAR_REGISTRATION_REGISTERED_ROAMING); |
|
} |
|
|
|
static void modem_cellular_chat_on_cxreg(struct modem_chat *chat, char **argv, uint16_t argc, |
|
void *user_data) |
|
{ |
|
struct modem_cellular_data *data = (struct modem_cellular_data *)user_data; |
|
enum cellular_registration_status registration_status = 0; |
|
|
|
/* This receives both +C*REG? read command answers and unsolicited notifications. |
|
* Their syntax differs in that the former has one more parameter, <n>, which is first. |
|
*/ |
|
if (argc >= 3 && argv[2][0] != '"') { |
|
/* +CEREG: <n>,<stat>[,<tac>[...]] */ |
|
registration_status = atoi(argv[2]); |
|
} else if (argc >= 2) { |
|
/* +CEREG: <stat>[,<tac>[...]] */ |
|
registration_status = atoi(argv[1]); |
|
} else { |
|
return; |
|
} |
|
|
|
if (strcmp(argv[0], "+CREG: ") == 0) { |
|
data->registration_status_gsm = registration_status; |
|
} else if (strcmp(argv[0], "+CGREG: ") == 0) { |
|
data->registration_status_gprs = registration_status; |
|
} else { /* CEREG */ |
|
data->registration_status_lte = registration_status; |
|
} |
|
|
|
if (modem_cellular_is_registered(data)) { |
|
modem_cellular_delegate_event(data, MODEM_CELLULAR_EVENT_REGISTERED); |
|
} else { |
|
modem_cellular_delegate_event(data, MODEM_CELLULAR_EVENT_DEREGISTERED); |
|
} |
|
} |
|
|
|
MODEM_CHAT_MATCH_DEFINE(ok_match, "OK", "", NULL); |
|
MODEM_CHAT_MATCHES_DEFINE(allow_match, |
|
MODEM_CHAT_MATCH("OK", "", NULL), |
|
MODEM_CHAT_MATCH("ERROR", "", NULL)); |
|
|
|
MODEM_CHAT_MATCH_DEFINE(imei_match, "", "", modem_cellular_chat_on_imei); |
|
MODEM_CHAT_MATCH_DEFINE(cgmm_match, "", "", modem_cellular_chat_on_cgmm); |
|
MODEM_CHAT_MATCH_DEFINE(csq_match, "+CSQ: ", ",", modem_cellular_chat_on_csq); |
|
MODEM_CHAT_MATCH_DEFINE(cesq_match, "+CESQ: ", ",", modem_cellular_chat_on_cesq); |
|
MODEM_CHAT_MATCH_DEFINE(qccid_match __maybe_unused, "+QCCID: ", "", modem_cellular_chat_on_iccid); |
|
MODEM_CHAT_MATCH_DEFINE(iccid_match __maybe_unused, "+ICCID: ", "", modem_cellular_chat_on_iccid); |
|
MODEM_CHAT_MATCH_DEFINE(cimi_match __maybe_unused, "", "", modem_cellular_chat_on_imsi); |
|
MODEM_CHAT_MATCH_DEFINE(cgmi_match __maybe_unused, "", "", modem_cellular_chat_on_cgmi); |
|
MODEM_CHAT_MATCH_DEFINE(cgmr_match __maybe_unused, "", "", modem_cellular_chat_on_cgmr); |
|
|
|
MODEM_CHAT_MATCHES_DEFINE(unsol_matches, |
|
MODEM_CHAT_MATCH("+CREG: ", ",", modem_cellular_chat_on_cxreg), |
|
MODEM_CHAT_MATCH("+CEREG: ", ",", modem_cellular_chat_on_cxreg), |
|
MODEM_CHAT_MATCH("+CGREG: ", ",", modem_cellular_chat_on_cxreg)); |
|
|
|
MODEM_CHAT_MATCHES_DEFINE(abort_matches, MODEM_CHAT_MATCH("ERROR", "", NULL)); |
|
|
|
MODEM_CHAT_MATCHES_DEFINE(dial_abort_matches, |
|
MODEM_CHAT_MATCH("ERROR", "", NULL), |
|
MODEM_CHAT_MATCH("BUSY", "", NULL), |
|
MODEM_CHAT_MATCH("NO ANSWER", "", NULL), |
|
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) || \ |
|
DT_HAS_COMPAT_STATUS_OKAY(quectel_eg800q) || DT_HAS_COMPAT_STATUS_OKAY(quectel_eg25_g) || \ |
|
DT_HAS_COMPAT_STATUS_OKAY(quectel_bg95) || DT_HAS_COMPAT_STATUS_OKAY(simcom_a76xx) |
|
MODEM_CHAT_MATCH_DEFINE(connect_match, "CONNECT", "", NULL); |
|
#endif |
|
|
|
static void modem_cellular_log_state_changed(enum modem_cellular_state last_state, |
|
enum modem_cellular_state new_state) |
|
{ |
|
LOG_DBG("switch from %s to %s", modem_cellular_state_str(last_state), |
|
modem_cellular_state_str(new_state)); |
|
} |
|
|
|
static void modem_cellular_log_event(enum modem_cellular_event evt) |
|
{ |
|
LOG_DBG("event %s", modem_cellular_event_str(evt)); |
|
} |
|
|
|
static void modem_cellular_start_timer(struct modem_cellular_data *data, k_timeout_t timeout) |
|
{ |
|
k_work_schedule(&data->timeout_work, timeout); |
|
} |
|
|
|
static void modem_cellular_stop_timer(struct modem_cellular_data *data) |
|
{ |
|
k_work_cancel_delayable(&data->timeout_work); |
|
} |
|
|
|
static void modem_cellular_timeout_handler(struct k_work *item) |
|
{ |
|
struct k_work_delayable *dwork = k_work_delayable_from_work(item); |
|
struct modem_cellular_data *data = |
|
CONTAINER_OF(dwork, struct modem_cellular_data, timeout_work); |
|
|
|
modem_cellular_delegate_event(data, MODEM_CELLULAR_EVENT_TIMEOUT); |
|
} |
|
|
|
static void modem_cellular_event_dispatch_handler(struct k_work *item) |
|
{ |
|
struct modem_cellular_data *data = |
|
CONTAINER_OF(item, struct modem_cellular_data, event_dispatch_work); |
|
|
|
uint8_t events[sizeof(data->event_buf)]; |
|
uint8_t events_cnt; |
|
|
|
k_mutex_lock(&data->event_rb_lock, K_FOREVER); |
|
|
|
events_cnt = (uint8_t)ring_buf_get(&data->event_rb, events, sizeof(data->event_buf)); |
|
|
|
k_mutex_unlock(&data->event_rb_lock); |
|
|
|
for (uint8_t i = 0; i < events_cnt; i++) { |
|
modem_cellular_event_handler(data, (enum modem_cellular_event)events[i]); |
|
} |
|
} |
|
|
|
static void modem_cellular_delegate_event(struct modem_cellular_data *data, |
|
enum modem_cellular_event evt) |
|
{ |
|
k_mutex_lock(&data->event_rb_lock, K_FOREVER); |
|
ring_buf_put(&data->event_rb, (uint8_t *)&evt, 1); |
|
k_mutex_unlock(&data->event_rb_lock); |
|
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 = |
|
(const struct modem_cellular_config *)data->dev->config; |
|
|
|
if (modem_cellular_gpio_is_enabled(&config->wake_gpio)) { |
|
gpio_pin_set_dt(&config->wake_gpio, 0); |
|
} |
|
|
|
if (modem_cellular_gpio_is_enabled(&config->reset_gpio)) { |
|
gpio_pin_set_dt(&config->reset_gpio, 1); |
|
} |
|
|
|
modem_cellular_notify_user_pipes_disconnected(data); |
|
modem_chat_release(&data->chat); |
|
modem_ppp_release(data->ppp); |
|
modem_cmux_release(&data->cmux); |
|
modem_pipe_close_async(data->uart_pipe); |
|
k_sem_give(&data->suspended_sem); |
|
return 0; |
|
} |
|
|
|
static void modem_cellular_idle_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_RESUME: |
|
if (config->autostarts) { |
|
modem_cellular_enter_state(data, MODEM_CELLULAR_STATE_AWAIT_POWER_ON); |
|
break; |
|
} |
|
|
|
if (modem_cellular_gpio_is_enabled(&config->power_gpio)) { |
|
modem_cellular_enter_state(data, MODEM_CELLULAR_STATE_POWER_ON_PULSE); |
|
break; |
|
} |
|
|
|
if (modem_cellular_gpio_is_enabled(&config->reset_gpio)) { |
|
modem_cellular_enter_state(data, MODEM_CELLULAR_STATE_AWAIT_POWER_ON); |
|
break; |
|
} |
|
|
|
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: |
|
k_sem_give(&data->suspended_sem); |
|
break; |
|
|
|
default: |
|
break; |
|
} |
|
} |
|
|
|
static int modem_cellular_on_idle_state_leave(struct modem_cellular_data *data) |
|
{ |
|
const struct modem_cellular_config *config = |
|
(const struct modem_cellular_config *)data->dev->config; |
|
|
|
k_sem_take(&data->suspended_sem, K_NO_WAIT); |
|
|
|
if (modem_cellular_gpio_is_enabled(&config->reset_gpio)) { |
|
gpio_pin_set_dt(&config->reset_gpio, 0); |
|
} |
|
|
|
if (modem_cellular_gpio_is_enabled(&config->wake_gpio)) { |
|
gpio_pin_set_dt(&config->wake_gpio, 1); |
|
} |
|
|
|
return 0; |
|
} |
|
|
|
static int modem_cellular_on_reset_pulse_state_enter(struct modem_cellular_data *data) |
|
{ |
|
const struct modem_cellular_config *config = |
|
(const struct modem_cellular_config *)data->dev->config; |
|
|
|
if (modem_cellular_gpio_is_enabled(&config->wake_gpio)) { |
|
gpio_pin_set_dt(&config->wake_gpio, 0); |
|
} |
|
|
|
gpio_pin_set_dt(&config->reset_gpio, 1); |
|
modem_cellular_start_timer(data, K_MSEC(config->reset_pulse_duration_ms)); |
|
return 0; |
|
} |
|
|
|
static void modem_cellular_reset_pulse_event_handler(struct modem_cellular_data *data, |
|
enum modem_cellular_event evt) |
|
{ |
|
switch (evt) { |
|
case MODEM_CELLULAR_EVENT_TIMEOUT: |
|
modem_cellular_enter_state(data, MODEM_CELLULAR_STATE_AWAIT_POWER_ON); |
|
break; |
|
|
|
case MODEM_CELLULAR_EVENT_SUSPEND: |
|
modem_cellular_enter_state(data, MODEM_CELLULAR_STATE_IDLE); |
|
break; |
|
|
|
default: |
|
break; |
|
} |
|
} |
|
|
|
static int modem_cellular_on_reset_pulse_state_leave(struct modem_cellular_data *data) |
|
{ |
|
const struct modem_cellular_config *config = |
|
(const struct modem_cellular_config *)data->dev->config; |
|
|
|
gpio_pin_set_dt(&config->reset_gpio, 0); |
|
|
|
if (modem_cellular_gpio_is_enabled(&config->wake_gpio)) { |
|
gpio_pin_set_dt(&config->wake_gpio, 1); |
|
} |
|
|
|
modem_cellular_stop_timer(data); |
|
return 0; |
|
} |
|
|
|
static int modem_cellular_on_power_on_pulse_state_enter(struct modem_cellular_data *data) |
|
{ |
|
const struct modem_cellular_config *config = |
|
(const struct modem_cellular_config *)data->dev->config; |
|
|
|
gpio_pin_set_dt(&config->power_gpio, 1); |
|
modem_cellular_start_timer(data, K_MSEC(config->power_pulse_duration_ms)); |
|
return 0; |
|
} |
|
|
|
static void modem_cellular_power_on_pulse_event_handler(struct modem_cellular_data *data, |
|
enum modem_cellular_event evt) |
|
{ |
|
switch (evt) { |
|
case MODEM_CELLULAR_EVENT_TIMEOUT: |
|
modem_cellular_enter_state(data, MODEM_CELLULAR_STATE_AWAIT_POWER_ON); |
|
break; |
|
|
|
case MODEM_CELLULAR_EVENT_SUSPEND: |
|
modem_cellular_enter_state(data, MODEM_CELLULAR_STATE_IDLE); |
|
break; |
|
|
|
default: |
|
break; |
|
} |
|
} |
|
|
|
static int modem_cellular_on_power_on_pulse_state_leave(struct modem_cellular_data *data) |
|
{ |
|
const struct modem_cellular_config *config = |
|
(const struct modem_cellular_config *)data->dev->config; |
|
|
|
gpio_pin_set_dt(&config->power_gpio, 0); |
|
modem_cellular_stop_timer(data); |
|
return 0; |
|
} |
|
|
|
static int modem_cellular_on_await_power_on_state_enter(struct modem_cellular_data *data) |
|
{ |
|
const struct modem_cellular_config *config = |
|
(const struct modem_cellular_config *)data->dev->config; |
|
|
|
modem_cellular_start_timer(data, K_MSEC(config->startup_time_ms)); |
|
return 0; |
|
} |
|
|
|
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; |
|
|
|
case MODEM_CELLULAR_EVENT_SUSPEND: |
|
modem_cellular_enter_state(data, MODEM_CELLULAR_STATE_IDLE); |
|
break; |
|
|
|
default: |
|
break; |
|
} |
|
} |
|
|
|
static int modem_cellular_on_run_init_script_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_run_init_script_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; |
|
uint8_t imei_len; |
|
uint8_t link_addr_len; |
|
uint8_t *link_addr_ptr; |
|
int err; |
|
|
|
switch (evt) { |
|
case MODEM_CELLULAR_EVENT_BUS_OPENED: |
|
modem_chat_attach(&data->chat, data->uart_pipe); |
|
modem_chat_run_script_async(&data->chat, config->init_chat_script); |
|
break; |
|
|
|
case MODEM_CELLULAR_EVENT_SCRIPT_SUCCESS: |
|
/* Get link_addr_len least significant bytes from IMEI as a link address */ |
|
imei_len = MODEM_CELLULAR_DATA_IMEI_LEN - 1; /* Exclude str end */ |
|
link_addr_len = MIN(NET_LINK_ADDR_MAX_LENGTH, imei_len); |
|
link_addr_ptr = data->imei + (imei_len - link_addr_len); |
|
|
|
err = net_if_set_link_addr(modem_ppp_get_iface(data->ppp), link_addr_ptr, |
|
link_addr_len, NET_LINK_UNKNOWN); |
|
if (err) { |
|
LOG_WRN("Failed to set link address on PPP interface (%d)", err); |
|
} |
|
|
|
modem_chat_release(&data->chat); |
|
modem_pipe_attach(data->uart_pipe, modem_cellular_bus_pipe_handler, data); |
|
modem_pipe_close_async(data->uart_pipe); |
|
break; |
|
|
|
case MODEM_CELLULAR_EVENT_BUS_CLOSED: |
|
modem_cellular_enter_state(data, MODEM_CELLULAR_STATE_CONNECT_CMUX); |
|
break; |
|
|
|
case MODEM_CELLULAR_EVENT_SUSPEND: |
|
modem_cellular_enter_state(data, MODEM_CELLULAR_STATE_IDLE); |
|
break; |
|
|
|
case MODEM_CELLULAR_EVENT_SCRIPT_FAILED: |
|
if (modem_cellular_gpio_is_enabled(&config->power_gpio)) { |
|
modem_cellular_enter_state(data, MODEM_CELLULAR_STATE_POWER_ON_PULSE); |
|
break; |
|
} |
|
|
|
if (modem_cellular_gpio_is_enabled(&config->reset_gpio)) { |
|
modem_cellular_enter_state(data, MODEM_CELLULAR_STATE_RESET_PULSE); |
|
break; |
|
} |
|
|
|
modem_cellular_enter_state(data, MODEM_CELLULAR_STATE_IDLE); |
|
break; |
|
|
|
default: |
|
break; |
|
} |
|
} |
|
|
|
static int modem_cellular_on_connect_cmux_state_enter(struct modem_cellular_data *data) |
|
{ |
|
/* |
|
* Allow modem to switch bus into CMUX mode. Some modems disable UART RX while |
|
* switching, resulting in UART RX errors as bus is no longer pulled up by modem. |
|
*/ |
|
modem_cellular_start_timer(data, K_MSEC(100)); |
|
return 0; |
|
} |
|
|
|
static void modem_cellular_connect_cmux_event_handler(struct modem_cellular_data *data, |
|
enum modem_cellular_event evt) |
|
{ |
|
switch (evt) { |
|
case MODEM_CELLULAR_EVENT_TIMEOUT: |
|
modem_pipe_attach(data->uart_pipe, modem_cellular_bus_pipe_handler, data); |
|
modem_pipe_open_async(data->uart_pipe); |
|
break; |
|
|
|
case MODEM_CELLULAR_EVENT_BUS_OPENED: |
|
modem_cmux_attach(&data->cmux, data->uart_pipe); |
|
modem_cmux_connect_async(&data->cmux); |
|
break; |
|
|
|
case MODEM_CELLULAR_EVENT_CMUX_CONNECTED: |
|
modem_cellular_notify_user_pipes_connected(data); |
|
modem_cellular_enter_state(data, MODEM_CELLULAR_STATE_OPEN_DLCI1); |
|
break; |
|
|
|
case MODEM_CELLULAR_EVENT_SUSPEND: |
|
modem_cellular_enter_state(data, MODEM_CELLULAR_STATE_INIT_POWER_OFF); |
|
break; |
|
|
|
default: |
|
break; |
|
} |
|
} |
|
|
|
static int modem_cellular_on_open_dlci1_state_enter(struct modem_cellular_data *data) |
|
{ |
|
modem_pipe_attach(data->dlci1_pipe, modem_cellular_dlci1_pipe_handler, data); |
|
return modem_pipe_open_async(data->dlci1_pipe); |
|
} |
|
|
|
static void modem_cellular_open_dlci1_event_handler(struct modem_cellular_data *data, |
|
enum modem_cellular_event evt) |
|
{ |
|
switch (evt) { |
|
case MODEM_CELLULAR_EVENT_DLCI1_OPENED: |
|
modem_cellular_enter_state(data, MODEM_CELLULAR_STATE_OPEN_DLCI2); |
|
break; |
|
|
|
case MODEM_CELLULAR_EVENT_SUSPEND: |
|
modem_cellular_enter_state(data, MODEM_CELLULAR_STATE_INIT_POWER_OFF); |
|
break; |
|
|
|
default: |
|
break; |
|
} |
|
} |
|
|
|
static int modem_cellular_on_open_dlci1_state_leave(struct modem_cellular_data *data) |
|
{ |
|
modem_pipe_release(data->dlci1_pipe); |
|
return 0; |
|
} |
|
|
|
static int modem_cellular_on_open_dlci2_state_enter(struct modem_cellular_data *data) |
|
{ |
|
modem_pipe_attach(data->dlci2_pipe, modem_cellular_dlci2_pipe_handler, data); |
|
return modem_pipe_open_async(data->dlci2_pipe); |
|
} |
|
|
|
static void modem_cellular_open_dlci2_event_handler(struct modem_cellular_data *data, |
|
enum modem_cellular_event evt) |
|
{ |
|
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; |
|
|
|
case MODEM_CELLULAR_EVENT_SUSPEND: |
|
modem_cellular_enter_state(data, MODEM_CELLULAR_STATE_INIT_POWER_OFF); |
|
break; |
|
|
|
default: |
|
break; |
|
} |
|
} |
|
|
|
static int modem_cellular_on_open_dlci2_state_leave(struct modem_cellular_data *data) |
|
{ |
|
modem_pipe_release(data->dlci2_pipe); |
|
return 0; |
|
} |
|
|
|
static int modem_cellular_on_run_dial_script_state_enter(struct modem_cellular_data *data) |
|
{ |
|
/* Allow modem time to enter command mode before running dial script */ |
|
modem_cellular_start_timer(data, K_MSEC(100)); |
|
return 0; |
|
} |
|
|
|
static void modem_cellular_run_dial_script_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: |
|
modem_chat_attach(&data->chat, data->dlci1_pipe); |
|
modem_chat_run_script_async(&data->chat, config->dial_chat_script); |
|
break; |
|
case MODEM_CELLULAR_EVENT_SCRIPT_FAILED: |
|
modem_cellular_start_timer(data, MODEM_CELLULAR_PERIODIC_SCRIPT_TIMEOUT); |
|
break; |
|
case MODEM_CELLULAR_EVENT_SCRIPT_SUCCESS: |
|
modem_cellular_enter_state(data, MODEM_CELLULAR_STATE_AWAIT_REGISTERED); |
|
break; |
|
|
|
case MODEM_CELLULAR_EVENT_SUSPEND: |
|
modem_cellular_enter_state(data, MODEM_CELLULAR_STATE_INIT_POWER_OFF); |
|
break; |
|
|
|
default: |
|
break; |
|
} |
|
} |
|
|
|
static int modem_cellular_on_run_dial_script_state_leave(struct modem_cellular_data *data) |
|
{ |
|
modem_chat_release(&data->chat); |
|
return 0; |
|
} |
|
|
|
static int modem_cellular_on_await_registered_state_enter(struct modem_cellular_data *data) |
|
{ |
|
if (modem_ppp_attach(data->ppp, data->dlci1_pipe) < 0) { |
|
return -EAGAIN; |
|
} |
|
|
|
modem_cellular_start_timer(data, MODEM_CELLULAR_PERIODIC_SCRIPT_TIMEOUT); |
|
return modem_chat_attach(&data->chat, data->dlci2_pipe); |
|
} |
|
|
|
static void modem_cellular_await_registered_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_SCRIPT_SUCCESS: |
|
case MODEM_CELLULAR_EVENT_SCRIPT_FAILED: |
|
modem_cellular_start_timer(data, MODEM_CELLULAR_PERIODIC_SCRIPT_TIMEOUT); |
|
break; |
|
|
|
case MODEM_CELLULAR_EVENT_TIMEOUT: |
|
modem_chat_run_script_async(&data->chat, config->periodic_chat_script); |
|
break; |
|
|
|
case MODEM_CELLULAR_EVENT_REGISTERED: |
|
modem_cellular_enter_state(data, MODEM_CELLULAR_STATE_CARRIER_ON); |
|
break; |
|
|
|
case MODEM_CELLULAR_EVENT_SUSPEND: |
|
modem_cellular_enter_state(data, MODEM_CELLULAR_STATE_INIT_POWER_OFF); |
|
break; |
|
|
|
default: |
|
break; |
|
} |
|
} |
|
|
|
static int modem_cellular_on_await_registered_state_leave(struct modem_cellular_data *data) |
|
{ |
|
modem_cellular_stop_timer(data); |
|
return 0; |
|
} |
|
|
|
static int modem_cellular_on_carrier_on_state_enter(struct modem_cellular_data *data) |
|
{ |
|
net_if_carrier_on(modem_ppp_get_iface(data->ppp)); |
|
modem_cellular_start_timer(data, MODEM_CELLULAR_PERIODIC_SCRIPT_TIMEOUT); |
|
return 0; |
|
} |
|
|
|
static void modem_cellular_carrier_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_SCRIPT_SUCCESS: |
|
case MODEM_CELLULAR_EVENT_SCRIPT_FAILED: |
|
modem_cellular_start_timer(data, MODEM_CELLULAR_PERIODIC_SCRIPT_TIMEOUT); |
|
break; |
|
|
|
case MODEM_CELLULAR_EVENT_TIMEOUT: |
|
modem_chat_run_script_async(&data->chat, config->periodic_chat_script); |
|
break; |
|
|
|
case MODEM_CELLULAR_EVENT_DEREGISTERED: |
|
modem_cellular_enter_state(data, MODEM_CELLULAR_STATE_DORMANT); |
|
break; |
|
|
|
case MODEM_CELLULAR_EVENT_SUSPEND: |
|
net_if_carrier_off(modem_ppp_get_iface(data->ppp)); |
|
modem_chat_release(&data->chat); |
|
modem_ppp_release(data->ppp); |
|
modem_cellular_enter_state(data, MODEM_CELLULAR_STATE_INIT_POWER_OFF); |
|
break; |
|
|
|
default: |
|
break; |
|
} |
|
} |
|
|
|
static int modem_cellular_on_carrier_on_state_leave(struct modem_cellular_data *data) |
|
{ |
|
modem_cellular_stop_timer(data); |
|
|
|
return 0; |
|
} |
|
|
|
static int modem_cellular_on_dormant_state_enter(struct modem_cellular_data *data) |
|
{ |
|
net_if_dormant_on(modem_ppp_get_iface(data->ppp)); |
|
|
|
return 0; |
|
} |
|
|
|
static void modem_cellular_dormant_event_handler(struct modem_cellular_data *data, |
|
enum modem_cellular_event evt) |
|
{ |
|
switch (evt) { |
|
case MODEM_CELLULAR_EVENT_PPP_DEAD: |
|
modem_cellular_enter_state(data, MODEM_CELLULAR_STATE_RUN_DIAL_SCRIPT); |
|
break; |
|
|
|
default: |
|
break; |
|
} |
|
} |
|
|
|
static int modem_cellular_on_dormant_state_leave(struct modem_cellular_data *data) |
|
{ |
|
net_if_carrier_off(modem_ppp_get_iface(data->ppp)); |
|
modem_chat_release(&data->chat); |
|
modem_ppp_release(data->ppp); |
|
net_if_dormant_off(modem_ppp_get_iface(data->ppp)); |
|
|
|
return 0; |
|
} |
|
|
|
static int modem_cellular_on_init_power_off_state_enter(struct modem_cellular_data *data) |
|
{ |
|
modem_cellular_start_timer(data, K_MSEC(2000)); |
|
return 0; |
|
} |
|
|
|
static void modem_cellular_init_power_off_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: |
|
/* 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_begin_power_off_pulse(data); |
|
break; |
|
|
|
default: |
|
break; |
|
} |
|
} |
|
|
|
static int modem_cellular_on_init_power_off_state_leave(struct modem_cellular_data *data) |
|
{ |
|
modem_cellular_notify_user_pipes_disconnected(data); |
|
modem_chat_release(&data->chat); |
|
modem_ppp_release(data->ppp); |
|
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; |
|
} |
|
|
|
static void modem_cellular_power_off_pulse_event_handler(struct modem_cellular_data *data, |
|
enum modem_cellular_event evt) |
|
{ |
|
switch (evt) { |
|
case MODEM_CELLULAR_EVENT_TIMEOUT: |
|
modem_cellular_enter_state(data, MODEM_CELLULAR_STATE_AWAIT_POWER_OFF); |
|
break; |
|
|
|
default: |
|
break; |
|
} |
|
} |
|
|
|
static int modem_cellular_on_power_off_pulse_state_leave(struct modem_cellular_data *data) |
|
{ |
|
const struct modem_cellular_config *config = |
|
(const struct modem_cellular_config *)data->dev->config; |
|
|
|
gpio_pin_set_dt(&config->power_gpio, 0); |
|
modem_cellular_stop_timer(data); |
|
return 0; |
|
} |
|
|
|
static int modem_cellular_on_await_power_off_state_enter(struct modem_cellular_data *data) |
|
{ |
|
const struct modem_cellular_config *config = |
|
(const struct modem_cellular_config *)data->dev->config; |
|
|
|
modem_cellular_start_timer(data, K_MSEC(config->shutdown_time_ms)); |
|
return 0; |
|
} |
|
|
|
static void modem_cellular_await_power_off_event_handler(struct modem_cellular_data *data, |
|
enum modem_cellular_event evt) |
|
{ |
|
switch (evt) { |
|
case MODEM_CELLULAR_EVENT_TIMEOUT: |
|
modem_cellular_enter_state(data, MODEM_CELLULAR_STATE_IDLE); |
|
break; |
|
|
|
default: |
|
break; |
|
} |
|
} |
|
|
|
static int modem_cellular_on_state_enter(struct modem_cellular_data *data) |
|
{ |
|
int ret; |
|
|
|
switch (data->state) { |
|
case MODEM_CELLULAR_STATE_IDLE: |
|
ret = modem_cellular_on_idle_state_enter(data); |
|
break; |
|
|
|
case MODEM_CELLULAR_STATE_RESET_PULSE: |
|
ret = modem_cellular_on_reset_pulse_state_enter(data); |
|
break; |
|
|
|
case MODEM_CELLULAR_STATE_POWER_ON_PULSE: |
|
ret = modem_cellular_on_power_on_pulse_state_enter(data); |
|
break; |
|
|
|
case MODEM_CELLULAR_STATE_AWAIT_POWER_ON: |
|
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; |
|
|
|
case MODEM_CELLULAR_STATE_CONNECT_CMUX: |
|
ret = modem_cellular_on_connect_cmux_state_enter(data); |
|
break; |
|
|
|
case MODEM_CELLULAR_STATE_OPEN_DLCI1: |
|
ret = modem_cellular_on_open_dlci1_state_enter(data); |
|
break; |
|
|
|
case MODEM_CELLULAR_STATE_OPEN_DLCI2: |
|
ret = modem_cellular_on_open_dlci2_state_enter(data); |
|
break; |
|
|
|
case MODEM_CELLULAR_STATE_RUN_DIAL_SCRIPT: |
|
ret = modem_cellular_on_run_dial_script_state_enter(data); |
|
break; |
|
|
|
case MODEM_CELLULAR_STATE_AWAIT_REGISTERED: |
|
ret = modem_cellular_on_await_registered_state_enter(data); |
|
break; |
|
|
|
case MODEM_CELLULAR_STATE_CARRIER_ON: |
|
ret = modem_cellular_on_carrier_on_state_enter(data); |
|
break; |
|
|
|
case MODEM_CELLULAR_STATE_DORMANT: |
|
ret = modem_cellular_on_dormant_state_enter(data); |
|
break; |
|
|
|
case MODEM_CELLULAR_STATE_INIT_POWER_OFF: |
|
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; |
|
|
|
case MODEM_CELLULAR_STATE_AWAIT_POWER_OFF: |
|
ret = modem_cellular_on_await_power_off_state_enter(data); |
|
break; |
|
|
|
default: |
|
ret = 0; |
|
break; |
|
} |
|
|
|
return ret; |
|
} |
|
|
|
static int modem_cellular_on_state_leave(struct modem_cellular_data *data) |
|
{ |
|
int ret; |
|
|
|
switch (data->state) { |
|
case MODEM_CELLULAR_STATE_IDLE: |
|
ret = modem_cellular_on_idle_state_leave(data); |
|
break; |
|
|
|
case MODEM_CELLULAR_STATE_RESET_PULSE: |
|
ret = modem_cellular_on_reset_pulse_state_leave(data); |
|
break; |
|
|
|
case MODEM_CELLULAR_STATE_POWER_ON_PULSE: |
|
ret = modem_cellular_on_power_on_pulse_state_leave(data); |
|
break; |
|
|
|
case MODEM_CELLULAR_STATE_OPEN_DLCI1: |
|
ret = modem_cellular_on_open_dlci1_state_leave(data); |
|
break; |
|
|
|
case MODEM_CELLULAR_STATE_OPEN_DLCI2: |
|
ret = modem_cellular_on_open_dlci2_state_leave(data); |
|
break; |
|
|
|
case MODEM_CELLULAR_STATE_RUN_DIAL_SCRIPT: |
|
ret = modem_cellular_on_run_dial_script_state_leave(data); |
|
break; |
|
|
|
case MODEM_CELLULAR_STATE_AWAIT_REGISTERED: |
|
ret = modem_cellular_on_await_registered_state_leave(data); |
|
break; |
|
|
|
case MODEM_CELLULAR_STATE_CARRIER_ON: |
|
ret = modem_cellular_on_carrier_on_state_leave(data); |
|
break; |
|
|
|
case MODEM_CELLULAR_STATE_DORMANT: |
|
ret = modem_cellular_on_dormant_state_leave(data); |
|
break; |
|
|
|
case MODEM_CELLULAR_STATE_INIT_POWER_OFF: |
|
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; |
|
|
|
default: |
|
ret = 0; |
|
break; |
|
} |
|
|
|
return ret; |
|
} |
|
|
|
static void modem_cellular_enter_state(struct modem_cellular_data *data, |
|
enum modem_cellular_state state) |
|
{ |
|
int ret; |
|
|
|
ret = modem_cellular_on_state_leave(data); |
|
|
|
if (ret < 0) { |
|
LOG_WRN("failed to leave state, error: %i", ret); |
|
|
|
return; |
|
} |
|
|
|
data->state = state; |
|
ret = modem_cellular_on_state_enter(data); |
|
|
|
if (ret < 0) { |
|
LOG_WRN("failed to enter state error: %i", ret); |
|
} |
|
} |
|
|
|
static void modem_cellular_event_handler(struct modem_cellular_data *data, |
|
enum modem_cellular_event evt) |
|
{ |
|
enum modem_cellular_state state; |
|
|
|
state = data->state; |
|
|
|
modem_cellular_log_event(evt); |
|
|
|
switch (data->state) { |
|
case MODEM_CELLULAR_STATE_IDLE: |
|
modem_cellular_idle_event_handler(data, evt); |
|
break; |
|
|
|
case MODEM_CELLULAR_STATE_RESET_PULSE: |
|
modem_cellular_reset_pulse_event_handler(data, evt); |
|
break; |
|
|
|
case MODEM_CELLULAR_STATE_POWER_ON_PULSE: |
|
modem_cellular_power_on_pulse_event_handler(data, evt); |
|
break; |
|
|
|
case MODEM_CELLULAR_STATE_AWAIT_POWER_ON: |
|
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; |
|
|
|
case MODEM_CELLULAR_STATE_CONNECT_CMUX: |
|
modem_cellular_connect_cmux_event_handler(data, evt); |
|
break; |
|
|
|
case MODEM_CELLULAR_STATE_OPEN_DLCI1: |
|
modem_cellular_open_dlci1_event_handler(data, evt); |
|
break; |
|
|
|
case MODEM_CELLULAR_STATE_OPEN_DLCI2: |
|
modem_cellular_open_dlci2_event_handler(data, evt); |
|
break; |
|
|
|
case MODEM_CELLULAR_STATE_RUN_DIAL_SCRIPT: |
|
modem_cellular_run_dial_script_event_handler(data, evt); |
|
break; |
|
|
|
case MODEM_CELLULAR_STATE_AWAIT_REGISTERED: |
|
modem_cellular_await_registered_event_handler(data, evt); |
|
break; |
|
|
|
case MODEM_CELLULAR_STATE_CARRIER_ON: |
|
modem_cellular_carrier_on_event_handler(data, evt); |
|
break; |
|
|
|
case MODEM_CELLULAR_STATE_DORMANT: |
|
modem_cellular_dormant_event_handler(data, evt); |
|
break; |
|
|
|
case MODEM_CELLULAR_STATE_INIT_POWER_OFF: |
|
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); |
|
break; |
|
|
|
case MODEM_CELLULAR_STATE_POWER_OFF_PULSE: |
|
modem_cellular_power_off_pulse_event_handler(data, evt); |
|
break; |
|
|
|
case MODEM_CELLULAR_STATE_AWAIT_POWER_OFF: |
|
modem_cellular_await_power_off_event_handler(data, evt); |
|
break; |
|
} |
|
|
|
if (state != data->state) { |
|
modem_cellular_log_state_changed(state, data->state); |
|
} |
|
} |
|
|
|
static void modem_cellular_cmux_handler(struct modem_cmux *cmux, enum modem_cmux_event event, |
|
void *user_data) |
|
{ |
|
struct modem_cellular_data *data = (struct modem_cellular_data *)user_data; |
|
|
|
switch (event) { |
|
case MODEM_CMUX_EVENT_CONNECTED: |
|
modem_cellular_delegate_event(data, MODEM_CELLULAR_EVENT_CMUX_CONNECTED); |
|
break; |
|
|
|
default: |
|
break; |
|
} |
|
} |
|
|
|
MODEM_CHAT_SCRIPT_CMDS_DEFINE(get_signal_csq_chat_script_cmds, |
|
MODEM_CHAT_SCRIPT_CMD_RESP("AT+CSQ", csq_match), |
|
MODEM_CHAT_SCRIPT_CMD_RESP("", ok_match)); |
|
|
|
MODEM_CHAT_SCRIPT_DEFINE(get_signal_csq_chat_script, get_signal_csq_chat_script_cmds, |
|
abort_matches, modem_cellular_chat_callback_handler, 2); |
|
|
|
static inline int modem_cellular_csq_parse_rssi(uint8_t rssi, int16_t *value) |
|
{ |
|
/* AT+CSQ returns a response +CSQ: <rssi>,<ber> where: |
|
* - rssi is a integer from 0 to 31 whose values describes a signal strength |
|
* between -113 dBm for 0 and -51dbM for 31 or unknown for 99 |
|
* - ber is an integer from 0 to 7 that describes the error rate, it can also |
|
* be 99 for an unknown error rate |
|
*/ |
|
if (rssi == CSQ_RSSI_UNKNOWN) { |
|
return -EINVAL; |
|
} |
|
|
|
*value = (int16_t)CSQ_RSSI_TO_DB(rssi); |
|
return 0; |
|
} |
|
|
|
MODEM_CHAT_SCRIPT_CMDS_DEFINE(get_signal_cesq_chat_script_cmds, |
|
MODEM_CHAT_SCRIPT_CMD_RESP("AT+CESQ", cesq_match), |
|
MODEM_CHAT_SCRIPT_CMD_RESP("", ok_match)); |
|
|
|
MODEM_CHAT_SCRIPT_DEFINE(get_signal_cesq_chat_script, get_signal_cesq_chat_script_cmds, |
|
abort_matches, modem_cellular_chat_callback_handler, 2); |
|
|
|
/* AT+CESQ returns a response +CESQ: <rxlev>,<ber>,<rscp>,<ecn0>,<rsrq>,<rsrp> where: |
|
* - rsrq is a integer from 0 to 34 whose values describes the Reference Signal Receive |
|
* Quality between -20 dB for 0 and -3 dB for 34 (0.5 dB steps), or unknown for 255 |
|
* - rsrp is an integer from 0 to 97 that describes the Reference Signal Receive Power |
|
* between -140 dBm for 0 and -44 dBm for 97 (1 dBm steps), or unknown for 255 |
|
*/ |
|
static inline int modem_cellular_cesq_parse_rsrp(uint8_t rsrp, int16_t *value) |
|
{ |
|
if (rsrp == CESQ_RSRP_UNKNOWN) { |
|
return -EINVAL; |
|
} |
|
|
|
*value = (int16_t)CESQ_RSRP_TO_DB(rsrp); |
|
return 0; |
|
} |
|
|
|
static inline int modem_cellular_cesq_parse_rsrq(uint8_t rsrq, int16_t *value) |
|
{ |
|
if (rsrq == CESQ_RSRQ_UNKNOWN) { |
|
return -EINVAL; |
|
} |
|
|
|
*value = (int16_t)CESQ_RSRQ_TO_DB(rsrq); |
|
return 0; |
|
} |
|
|
|
static int modem_cellular_get_signal(const struct device *dev, |
|
const enum cellular_signal_type type, |
|
int16_t *value) |
|
{ |
|
int ret = -ENOTSUP; |
|
struct modem_cellular_data *data = (struct modem_cellular_data *)dev->data; |
|
|
|
if ((data->state != MODEM_CELLULAR_STATE_AWAIT_REGISTERED) && |
|
(data->state != MODEM_CELLULAR_STATE_CARRIER_ON)) { |
|
return -ENODATA; |
|
} |
|
|
|
/* Run chat script */ |
|
switch (type) { |
|
case CELLULAR_SIGNAL_RSSI: |
|
ret = modem_chat_run_script(&data->chat, &get_signal_csq_chat_script); |
|
break; |
|
|
|
case CELLULAR_SIGNAL_RSRP: |
|
case CELLULAR_SIGNAL_RSRQ: |
|
ret = modem_chat_run_script(&data->chat, &get_signal_cesq_chat_script); |
|
break; |
|
|
|
default: |
|
ret = -ENOTSUP; |
|
break; |
|
} |
|
|
|
/* Verify chat script ran successfully */ |
|
if (ret < 0) { |
|
return ret; |
|
} |
|
|
|
/* Parse received value */ |
|
switch (type) { |
|
case CELLULAR_SIGNAL_RSSI: |
|
ret = modem_cellular_csq_parse_rssi(data->rssi, value); |
|
break; |
|
|
|
case CELLULAR_SIGNAL_RSRP: |
|
ret = modem_cellular_cesq_parse_rsrp(data->rsrp, value); |
|
break; |
|
|
|
case CELLULAR_SIGNAL_RSRQ: |
|
ret = modem_cellular_cesq_parse_rsrq(data->rsrq, value); |
|
break; |
|
|
|
default: |
|
ret = -ENOTSUP; |
|
break; |
|
} |
|
|
|
return ret; |
|
} |
|
|
|
static int modem_cellular_get_modem_info(const struct device *dev, |
|
enum cellular_modem_info_type type, |
|
char *info, size_t size) |
|
{ |
|
int ret = 0; |
|
struct modem_cellular_data *data = (struct modem_cellular_data *)dev->data; |
|
|
|
switch (type) { |
|
case CELLULAR_MODEM_INFO_IMEI: |
|
strncpy(info, &data->imei[0], MIN(size, sizeof(data->imei))); |
|
break; |
|
case CELLULAR_MODEM_INFO_SIM_IMSI: |
|
strncpy(info, &data->imsi[0], MIN(size, sizeof(data->imsi))); |
|
break; |
|
case CELLULAR_MODEM_INFO_MANUFACTURER: |
|
strncpy(info, &data->manufacturer[0], MIN(size, sizeof(data->manufacturer))); |
|
break; |
|
case CELLULAR_MODEM_INFO_FW_VERSION: |
|
strncpy(info, &data->fw_version[0], MIN(size, sizeof(data->fw_version))); |
|
break; |
|
case CELLULAR_MODEM_INFO_MODEL_ID: |
|
strncpy(info, &data->model_id[0], MIN(size, sizeof(data->model_id))); |
|
break; |
|
case CELLULAR_MODEM_INFO_SIM_ICCID: |
|
strncpy(info, &data->iccid[0], MIN(size, sizeof(data->iccid))); |
|
break; |
|
default: |
|
ret = -ENODATA; |
|
break; |
|
} |
|
|
|
return ret; |
|
} |
|
static int modem_cellular_get_registration_status(const struct device *dev, |
|
enum cellular_access_technology tech, |
|
enum cellular_registration_status *status) |
|
{ |
|
int ret = 0; |
|
struct modem_cellular_data *data = (struct modem_cellular_data *)dev->data; |
|
|
|
switch (tech) { |
|
case CELLULAR_ACCESS_TECHNOLOGY_GSM: |
|
*status = data->registration_status_gsm; |
|
break; |
|
case CELLULAR_ACCESS_TECHNOLOGY_GPRS: |
|
case CELLULAR_ACCESS_TECHNOLOGY_UMTS: |
|
case CELLULAR_ACCESS_TECHNOLOGY_EDGE: |
|
*status = data->registration_status_gprs; |
|
break; |
|
case CELLULAR_ACCESS_TECHNOLOGY_LTE: |
|
case CELLULAR_ACCESS_TECHNOLOGY_LTE_CAT_M1: |
|
case CELLULAR_ACCESS_TECHNOLOGY_LTE_CAT_M2: |
|
case CELLULAR_ACCESS_TECHNOLOGY_NB_IOT: |
|
*status = data->registration_status_lte; |
|
break; |
|
default: |
|
ret = -ENODATA; |
|
break; |
|
} |
|
|
|
return ret; |
|
} |
|
|
|
static DEVICE_API(cellular, modem_cellular_api) = { |
|
.get_signal = modem_cellular_get_signal, |
|
.get_modem_info = modem_cellular_get_modem_info, |
|
.get_registration_status = modem_cellular_get_registration_status, |
|
}; |
|
|
|
#ifdef CONFIG_PM_DEVICE |
|
static int modem_cellular_pm_action(const struct device *dev, enum pm_device_action action) |
|
{ |
|
struct modem_cellular_data *data = (struct modem_cellular_data *)dev->data; |
|
int ret; |
|
|
|
switch (action) { |
|
case PM_DEVICE_ACTION_RESUME: |
|
modem_cellular_delegate_event(data, MODEM_CELLULAR_EVENT_RESUME); |
|
ret = 0; |
|
break; |
|
|
|
case PM_DEVICE_ACTION_SUSPEND: |
|
modem_cellular_delegate_event(data, MODEM_CELLULAR_EVENT_SUSPEND); |
|
ret = k_sem_take(&data->suspended_sem, K_SECONDS(30)); |
|
break; |
|
|
|
default: |
|
ret = -ENOTSUP; |
|
break; |
|
} |
|
|
|
return ret; |
|
} |
|
#endif /* CONFIG_PM_DEVICE */ |
|
|
|
static void net_mgmt_event_handler(struct net_mgmt_event_callback *cb, uint64_t mgmt_event, |
|
struct net_if *iface) |
|
{ |
|
struct modem_cellular_data *data = |
|
CONTAINER_OF(cb, struct modem_cellular_data, net_mgmt_event_callback); |
|
|
|
switch (mgmt_event) { |
|
case NET_EVENT_PPP_PHASE_DEAD: |
|
modem_cellular_delegate_event(data, MODEM_CELLULAR_EVENT_PPP_DEAD); |
|
break; |
|
|
|
default: |
|
break; |
|
} |
|
} |
|
|
|
static int modem_cellular_init(const struct device *dev) |
|
{ |
|
struct modem_cellular_data *data = (struct modem_cellular_data *)dev->data; |
|
struct modem_cellular_config *config = (struct modem_cellular_config *)dev->config; |
|
|
|
data->dev = dev; |
|
|
|
k_work_init_delayable(&data->timeout_work, modem_cellular_timeout_handler); |
|
|
|
k_work_init(&data->event_dispatch_work, modem_cellular_event_dispatch_handler); |
|
ring_buf_init(&data->event_rb, sizeof(data->event_buf), data->event_buf); |
|
|
|
k_sem_init(&data->suspended_sem, 0, 1); |
|
|
|
if (modem_cellular_gpio_is_enabled(&config->wake_gpio)) { |
|
gpio_pin_configure_dt(&config->wake_gpio, GPIO_OUTPUT_INACTIVE); |
|
} |
|
|
|
if (modem_cellular_gpio_is_enabled(&config->power_gpio)) { |
|
gpio_pin_configure_dt(&config->power_gpio, GPIO_OUTPUT_INACTIVE); |
|
} |
|
|
|
if (modem_cellular_gpio_is_enabled(&config->reset_gpio)) { |
|
gpio_pin_configure_dt(&config->reset_gpio, GPIO_OUTPUT_ACTIVE); |
|
} |
|
|
|
{ |
|
const struct modem_backend_uart_config uart_backend_config = { |
|
.uart = config->uart, |
|
.receive_buf = data->uart_backend_receive_buf, |
|
.receive_buf_size = ARRAY_SIZE(data->uart_backend_receive_buf), |
|
.transmit_buf = data->uart_backend_transmit_buf, |
|
.transmit_buf_size = ARRAY_SIZE(data->uart_backend_transmit_buf), |
|
}; |
|
|
|
data->uart_pipe = modem_backend_uart_init(&data->uart_backend, |
|
&uart_backend_config); |
|
|
|
data->cmd_pipe = NULL; |
|
} |
|
|
|
{ |
|
const struct modem_cmux_config cmux_config = { |
|
.callback = modem_cellular_cmux_handler, |
|
.user_data = data, |
|
.receive_buf = data->cmux_receive_buf, |
|
.receive_buf_size = ARRAY_SIZE(data->cmux_receive_buf), |
|
.transmit_buf = data->cmux_transmit_buf, |
|
.transmit_buf_size = ARRAY_SIZE(data->cmux_transmit_buf), |
|
}; |
|
|
|
modem_cmux_init(&data->cmux, &cmux_config); |
|
} |
|
|
|
{ |
|
const struct modem_cmux_dlci_config dlci1_config = { |
|
.dlci_address = 1, |
|
.receive_buf = data->dlci1_receive_buf, |
|
.receive_buf_size = ARRAY_SIZE(data->dlci1_receive_buf), |
|
}; |
|
|
|
data->dlci1_pipe = modem_cmux_dlci_init(&data->cmux, &data->dlci1, |
|
&dlci1_config); |
|
} |
|
|
|
{ |
|
const struct modem_cmux_dlci_config dlci2_config = { |
|
.dlci_address = 2, |
|
.receive_buf = data->dlci2_receive_buf, |
|
.receive_buf_size = ARRAY_SIZE(data->dlci2_receive_buf), |
|
}; |
|
|
|
data->dlci2_pipe = modem_cmux_dlci_init(&data->cmux, &data->dlci2, |
|
&dlci2_config); |
|
} |
|
|
|
for (uint8_t i = 0; i < config->user_pipes_size; i++) { |
|
struct modem_cellular_user_pipe *user_pipe = &config->user_pipes[i]; |
|
const struct modem_cmux_dlci_config user_dlci_config = { |
|
.dlci_address = user_pipe->dlci_address, |
|
.receive_buf = user_pipe->dlci_receive_buf, |
|
.receive_buf_size = user_pipe->dlci_receive_buf_size, |
|
}; |
|
|
|
user_pipe->pipe = modem_cmux_dlci_init(&data->cmux, &user_pipe->dlci, |
|
&user_dlci_config); |
|
|
|
modem_pipelink_init(user_pipe->pipelink, user_pipe->pipe); |
|
} |
|
|
|
{ |
|
const struct modem_chat_config chat_config = { |
|
.user_data = data, |
|
.receive_buf = data->chat_receive_buf, |
|
.receive_buf_size = ARRAY_SIZE(data->chat_receive_buf), |
|
.delimiter = data->chat_delimiter, |
|
.delimiter_size = strlen(data->chat_delimiter), |
|
.filter = data->chat_filter, |
|
.filter_size = data->chat_filter ? strlen(data->chat_filter) : 0, |
|
.argv = data->chat_argv, |
|
.argv_size = ARRAY_SIZE(data->chat_argv), |
|
.unsol_matches = unsol_matches, |
|
.unsol_matches_size = ARRAY_SIZE(unsol_matches), |
|
}; |
|
|
|
modem_chat_init(&data->chat, &chat_config); |
|
} |
|
|
|
{ |
|
net_mgmt_init_event_callback(&data->net_mgmt_event_callback, net_mgmt_event_handler, |
|
NET_EVENT_PPP_PHASE_DEAD); |
|
net_mgmt_add_event_callback(&data->net_mgmt_event_callback); |
|
} |
|
|
|
|
|
#ifndef CONFIG_PM_DEVICE |
|
modem_cellular_delegate_event(data, MODEM_CELLULAR_EVENT_RESUME); |
|
#else |
|
pm_device_init_suspended(dev); |
|
#endif /* CONFIG_PM_DEVICE */ |
|
|
|
return 0; |
|
} |
|
|
|
/* |
|
* Every modem uses two custom scripts to initialize the modem and dial out. |
|
* |
|
* The first script is named <dt driver compatible>_init_chat_script, with its |
|
* script commands named <dt driver compatible>_init_chat_script_cmds. This |
|
* script is sent to the modem after it has started up, and must configure the |
|
* modem to use CMUX. |
|
* |
|
* The second script is named <dt driver compatible>_dial_chat_script, with its |
|
* script commands named <dt driver compatible>_dial_chat_script_cmds. This |
|
* script is sent on a DLCI channel in command mode, and must request the modem |
|
* dial out and put the DLCI channel into data mode. |
|
*/ |
|
|
|
#if DT_HAS_COMPAT_STATUS_OKAY(quectel_bg95) |
|
MODEM_CHAT_SCRIPT_CMDS_DEFINE(quectel_bg95_init_chat_script_cmds, |
|
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("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+QCCID", qccid_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(quectel_bg95_init_chat_script, quectel_bg95_init_chat_script_cmds, |
|
abort_matches, modem_cellular_chat_callback_handler, 10); |
|
|
|
MODEM_CHAT_SCRIPT_CMDS_DEFINE(quectel_bg95_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("ATD*99***1#", connect_match)); |
|
|
|
MODEM_CHAT_SCRIPT_DEFINE(quectel_bg95_dial_chat_script, quectel_bg95_dial_chat_script_cmds, |
|
dial_abort_matches, modem_cellular_chat_callback_handler, 10); |
|
|
|
MODEM_CHAT_SCRIPT_CMDS_DEFINE(quectel_bg95_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(quectel_bg95_periodic_chat_script, |
|
quectel_bg95_periodic_chat_script_cmds, abort_matches, |
|
modem_cellular_chat_callback_handler, 4); |
|
#endif |
|
|
|
#if DT_HAS_COMPAT_STATUS_OKAY(quectel_eg25_g) |
|
MODEM_CHAT_SCRIPT_CMDS_DEFINE( |
|
quectel_eg25_g_init_chat_script_cmds, 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("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_NONE("AT+CMUX=0,0,5,127,10,3,30,10,2", 100)); |
|
|
|
MODEM_CHAT_SCRIPT_DEFINE(quectel_eg25_g_init_chat_script, quectel_eg25_g_init_chat_script_cmds, |
|
abort_matches, modem_cellular_chat_callback_handler, 10); |
|
|
|
MODEM_CHAT_SCRIPT_CMDS_DEFINE(quectel_eg25_g_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("ATD*99***1#", connect_match)); |
|
|
|
MODEM_CHAT_SCRIPT_DEFINE(quectel_eg25_g_dial_chat_script, quectel_eg25_g_dial_chat_script_cmds, |
|
dial_abort_matches, modem_cellular_chat_callback_handler, 10); |
|
|
|
MODEM_CHAT_SCRIPT_CMDS_DEFINE(quectel_eg25_g_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_CMD_RESP("AT+CSQ", csq_match)); |
|
|
|
MODEM_CHAT_SCRIPT_DEFINE(quectel_eg25_g_periodic_chat_script, |
|
quectel_eg25_g_periodic_chat_script_cmds, abort_matches, |
|
modem_cellular_chat_callback_handler, 4); |
|
#endif |
|
|
|
#if DT_HAS_COMPAT_STATUS_OKAY(quectel_eg800q) |
|
MODEM_CHAT_SCRIPT_CMDS_DEFINE(quectel_eg800q_init_chat_script_cmds, |
|
MODEM_CHAT_SCRIPT_CMD_RESP("AT", ok_match), |
|
MODEM_CHAT_SCRIPT_CMD_RESP("ATE0", ok_match), |
|
MODEM_CHAT_SCRIPT_CMD_RESP("AT+CFUN?", 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+CEREG=1", ok_match), |
|
MODEM_CHAT_SCRIPT_CMD_RESP("AT+CEREG?", 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(quectel_eg800q_init_chat_script, quectel_eg800q_init_chat_script_cmds, |
|
abort_matches, modem_cellular_chat_callback_handler, 30); |
|
|
|
MODEM_CHAT_SCRIPT_CMDS_DEFINE(quectel_eg800q_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), |
|
/* this at command is required as a small delay before performing |
|
* dialing, otherwise we get 'NO CARRIER' and abort |
|
*/ |
|
MODEM_CHAT_SCRIPT_CMD_RESP_NONE("AT", 500), |
|
MODEM_CHAT_SCRIPT_CMD_RESP("ATD*99***1#", connect_match),); |
|
|
|
MODEM_CHAT_SCRIPT_DEFINE(quectel_eg800q_dial_chat_script, quectel_eg800q_dial_chat_script_cmds, |
|
dial_abort_matches, modem_cellular_chat_callback_handler, 10); |
|
|
|
MODEM_CHAT_SCRIPT_CMDS_DEFINE(quectel_eg800q_periodic_chat_script_cmds, |
|
MODEM_CHAT_SCRIPT_CMD_RESP("AT+CEREG?", ok_match), |
|
MODEM_CHAT_SCRIPT_CMD_RESP("AT+CSQ", csq_match)); |
|
|
|
MODEM_CHAT_SCRIPT_DEFINE(quectel_eg800q_periodic_chat_script, |
|
quectel_eg800q_periodic_chat_script_cmds, abort_matches, |
|
modem_cellular_chat_callback_handler, 4); |
|
#endif |
|
|
|
#if DT_HAS_COMPAT_STATUS_OKAY(simcom_sim7080) |
|
MODEM_CHAT_SCRIPT_CMDS_DEFINE(simcom_sim7080_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_sim7080_init_chat_script, simcom_sim7080_init_chat_script_cmds, |
|
abort_matches, modem_cellular_chat_callback_handler, 10); |
|
|
|
MODEM_CHAT_SCRIPT_CMDS_DEFINE(simcom_sim7080_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(simcom_sim7080_dial_chat_script, simcom_sim7080_dial_chat_script_cmds, |
|
dial_abort_matches, modem_cellular_chat_callback_handler, 10); |
|
|
|
MODEM_CHAT_SCRIPT_CMDS_DEFINE(simcom_sim7080_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_sim7080_periodic_chat_script, |
|
simcom_sim7080_periodic_chat_script_cmds, abort_matches, |
|
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), |
|
/* 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), |
|
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), |
|
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("AT+CMUX=0,0,5,127", ok_match)); |
|
|
|
MODEM_CHAT_SCRIPT_DEFINE(u_blox_sara_r4_init_chat_script, u_blox_sara_r4_init_chat_script_cmds, |
|
abort_matches, modem_cellular_chat_callback_handler, 10); |
|
|
|
MODEM_CHAT_SCRIPT_CMDS_DEFINE(u_blox_sara_r4_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_sara_r4_dial_chat_script, u_blox_sara_r4_dial_chat_script_cmds, |
|
dial_abort_matches, modem_cellular_chat_callback_handler, 10); |
|
|
|
MODEM_CHAT_SCRIPT_CMDS_DEFINE(u_blox_sara_r4_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_sara_r4_periodic_chat_script, |
|
u_blox_sara_r4_periodic_chat_script_cmds, abort_matches, |
|
modem_cellular_chat_callback_handler, 4); |
|
#endif |
|
|
|
#if DT_HAS_COMPAT_STATUS_OKAY(u_blox_sara_r5) |
|
MODEM_CHAT_SCRIPT_CMDS_DEFINE(u_blox_sara_r5_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("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_sara_r5_init_chat_script, u_blox_sara_r5_init_chat_script_cmds, |
|
abort_matches, modem_cellular_chat_callback_handler, 10); |
|
|
|
MODEM_CHAT_SCRIPT_CMDS_DEFINE(u_blox_sara_r5_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_sara_r5_dial_chat_script, u_blox_sara_r5_dial_chat_script_cmds, |
|
dial_abort_matches, modem_cellular_chat_callback_handler, 10); |
|
|
|
MODEM_CHAT_SCRIPT_CMDS_DEFINE(u_blox_sara_r5_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_sara_r5_periodic_chat_script, |
|
u_blox_sara_r5_periodic_chat_script_cmds, abort_matches, |
|
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); |
|
|
|
/* NOTE: For some reason, a CMUX max frame size of 127 causes FCS errors in |
|
* this modem; larger or smaller doesn't. The modem's default value is 31, |
|
* which works well |
|
*/ |
|
MODEM_CHAT_SCRIPT_CMDS_DEFINE(u_blox_lara_r6_init_chat_script_cmds, |
|
|
|
/* U-blox LARA-R6 LWM2M client is enabled by default. Not only causes |
|
* this the modem to connect to U-blox's server on its own, it also |
|
* for some reason causes the modem to reply "Destination |
|
* unreachable" to DNS answers from DNS requests that we send |
|
*/ |
|
MODEM_CHAT_SCRIPT_CMD_RESP_MULT("AT+ULWM2M=1", allow_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), |
|
#if CONFIG_MODEM_CELLULAR_RAT_4G |
|
MODEM_CHAT_SCRIPT_CMD_RESP("AT+URAT=3", ok_match), |
|
#elif CONFIG_MODEM_CELLULAR_RAT_4G_3G |
|
MODEM_CHAT_SCRIPT_CMD_RESP("AT+URAT=3,2", ok_match), |
|
#elif CONFIG_MODEM_CELLULAR_RAT_4G_3G_2G |
|
MODEM_CHAT_SCRIPT_CMD_RESP("AT+URAT=3,2,0", ok_match), |
|
#endif |
|
#if CONFIG_MODEM_CELLULAR_CLEAR_FORBIDDEN |
|
MODEM_CHAT_SCRIPT_CMD_RESP("AT+CRSM=214,28539,0,0,12," |
|
"\"FFFFFFFFFFFFFFFFFFFFFFFF\"", |
|
ok_match), |
|
#endif |
|
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,31", 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", 1000), |
|
MODEM_CHAT_SCRIPT_CMD_RESP_NONE("AT", 1000), |
|
MODEM_CHAT_SCRIPT_CMD_RESP_NONE("AT", 1000), |
|
MODEM_CHAT_SCRIPT_CMD_RESP_NONE("AT", 1000), |
|
/* Turn off sleep mode */ |
|
MODEM_CHAT_SCRIPT_CMD_RESP("AT+KSLEEP=2", ok_match), |
|
/* Turn off PSM */ |
|
MODEM_CHAT_SCRIPT_CMD_RESP("AT+CPSMS=0", ok_match), |
|
/* Turn off eDRX */ |
|
MODEM_CHAT_SCRIPT_CMD_RESP("AT+CEDRXS=0", ok_match), |
|
MODEM_CHAT_SCRIPT_CMD_RESP("ATE0", ok_match), |
|
MODEM_CHAT_SCRIPT_CMD_RESP("AT+CFUN=1", ok_match), |
|
MODEM_CHAT_SCRIPT_CMD_RESP_MULT("AT+CGACT=0", allow_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+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+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(swir_hl7800_init_chat_script, swir_hl7800_init_chat_script_cmds, |
|
abort_matches, modem_cellular_chat_callback_handler, 10); |
|
|
|
MODEM_CHAT_SCRIPT_CMDS_DEFINE(swir_hl7800_dial_chat_script_cmds, |
|
MODEM_CHAT_SCRIPT_CMD_RESP("AT+CGDCONT=1,\"IP\"," |
|
"\""CONFIG_MODEM_CELLULAR_APN"\"", |
|
ok_match), |
|
MODEM_CHAT_SCRIPT_CMD_RESP("AT+KCNXCFG=1,\"GPRS\",\"" |
|
CONFIG_MODEM_CELLULAR_APN |
|
"\",,,\"IPV4\"", |
|
ok_match), |
|
MODEM_CHAT_SCRIPT_CMD_RESP("AT+WPPP=0", ok_match), |
|
MODEM_CHAT_SCRIPT_CMD_RESP("AT+CFUN=1", ok_match), |
|
MODEM_CHAT_SCRIPT_CMD_RESP("ATD*99***1#", connect_match)); |
|
|
|
MODEM_CHAT_SCRIPT_CMDS_DEFINE(swir_hl7800_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_DEFINE(swir_hl7800_periodic_chat_script, |
|
swir_hl7800_periodic_chat_script_cmds, abort_matches, |
|
modem_cellular_chat_callback_handler, 4); |
|
|
|
MODEM_CHAT_SCRIPT_DEFINE(swir_hl7800_dial_chat_script, swir_hl7800_dial_chat_script_cmds, |
|
dial_abort_matches, modem_cellular_chat_callback_handler, 10); |
|
#endif |
|
|
|
#if DT_HAS_COMPAT_STATUS_OKAY(telit_me910g1) || DT_HAS_COMPAT_STATUS_OKAY(telit_me310g1) |
|
MODEM_CHAT_SCRIPT_CMDS_DEFINE(telit_mex10g1_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+ICCID", iccid_match), |
|
MODEM_CHAT_SCRIPT_CMD_RESP("", ok_match), |
|
MODEM_CHAT_SCRIPT_CMD_RESP("AT+CIMI", cimi_match), |
|
MODEM_CHAT_SCRIPT_CMD_RESP("", ok_match), |
|
/* The Telit me910g1 often has an error trying |
|
* to set the PDP context. The radio must be on to set |
|
* the context, and this step must be successful. |
|
* It is moved to the init script to allow retries. |
|
*/ |
|
MODEM_CHAT_SCRIPT_CMD_RESP("AT+CGDCONT=1,\"IP\"," |
|
"\"" CONFIG_MODEM_CELLULAR_APN "\"", |
|
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("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+CFUN=1", ok_match), |
|
MODEM_CHAT_SCRIPT_CMD_RESP_NONE("AT+CMUX=0,0,5,127,10,3,30,10,2", |
|
300)); |
|
|
|
MODEM_CHAT_SCRIPT_DEFINE(telit_mex10g1_init_chat_script, telit_mex10g1_init_chat_script_cmds, |
|
abort_matches, modem_cellular_chat_callback_handler, 10); |
|
|
|
MODEM_CHAT_SCRIPT_CMDS_DEFINE(telit_mex10g1_dial_chat_script_cmds, |
|
MODEM_CHAT_SCRIPT_CMD_RESP("AT", ok_match), |
|
MODEM_CHAT_SCRIPT_CMD_RESP_NONE("ATD*99***1#", 0)); |
|
|
|
MODEM_CHAT_SCRIPT_DEFINE(telit_mex10g1_dial_chat_script, telit_mex10g1_dial_chat_script_cmds, |
|
dial_abort_matches, modem_cellular_chat_callback_handler, 10); |
|
|
|
MODEM_CHAT_SCRIPT_CMDS_DEFINE(telit_mex10g1_periodic_chat_script_cmds, |
|
MODEM_CHAT_SCRIPT_CMD_RESP("AT+CREG?", ok_match), |
|
MODEM_CHAT_SCRIPT_CMD_RESP("AT+CGREG?", ok_match), |
|
MODEM_CHAT_SCRIPT_CMD_RESP("AT+CEREG?", ok_match)); |
|
|
|
MODEM_CHAT_SCRIPT_DEFINE(telit_mex10g1_periodic_chat_script, |
|
telit_mex10g1_periodic_chat_script_cmds, abort_matches, |
|
modem_cellular_chat_callback_handler, 4); |
|
|
|
#endif |
|
|
|
#if DT_HAS_COMPAT_STATUS_OKAY(telit_me310g1) |
|
MODEM_CHAT_SCRIPT_CMDS_DEFINE(telit_me310g1_shutdown_chat_script_cmds, |
|
MODEM_CHAT_SCRIPT_CMD_RESP("AT#SHDN", ok_match)); |
|
|
|
MODEM_CHAT_SCRIPT_DEFINE(telit_me310g1_shutdown_chat_script, |
|
telit_me310g1_shutdown_chat_script_cmds, abort_matches, |
|
modem_cellular_chat_callback_handler, 15); |
|
|
|
#endif |
|
|
|
#if DT_HAS_COMPAT_STATUS_OKAY(nordic_nrf91_slm) |
|
MODEM_CHAT_SCRIPT_CMDS_DEFINE(nordic_nrf91_slm_init_chat_script_cmds, |
|
MODEM_CHAT_SCRIPT_CMD_RESP_MULT("AT", allow_match), |
|
MODEM_CHAT_SCRIPT_CMD_RESP("AT+CMEE=1", ok_match), |
|
MODEM_CHAT_SCRIPT_CMD_RESP("AT+CEREG=1", ok_match), |
|
MODEM_CHAT_SCRIPT_CMD_RESP("AT+CEREG?", 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#XCMUX=1", ok_match)); |
|
|
|
MODEM_CHAT_SCRIPT_DEFINE(nordic_nrf91_slm_init_chat_script, nordic_nrf91_slm_init_chat_script_cmds, |
|
abort_matches, modem_cellular_chat_callback_handler, 10); |
|
|
|
MODEM_CHAT_SCRIPT_CMDS_DEFINE(nordic_nrf91_slm_dial_chat_script_cmds, |
|
MODEM_CHAT_SCRIPT_CMD_RESP("AT+CFUN=4", ok_match), |
|
MODEM_CHAT_SCRIPT_CMD_RESP("AT+CFUN=1", ok_match), |
|
MODEM_CHAT_SCRIPT_CMD_RESP("AT#XCMUX=2", ok_match)); |
|
|
|
MODEM_CHAT_SCRIPT_DEFINE(nordic_nrf91_slm_dial_chat_script, nordic_nrf91_slm_dial_chat_script_cmds, |
|
dial_abort_matches, modem_cellular_chat_callback_handler, 10); |
|
|
|
MODEM_CHAT_SCRIPT_CMDS_DEFINE(nordic_nrf91_slm_periodic_chat_script_cmds, |
|
MODEM_CHAT_SCRIPT_CMD_RESP("AT+CEREG?", ok_match)); |
|
|
|
MODEM_CHAT_SCRIPT_DEFINE(nordic_nrf91_slm_periodic_chat_script, |
|
nordic_nrf91_slm_periodic_chat_script_cmds, abort_matches, |
|
modem_cellular_chat_callback_handler, 4); |
|
#endif |
|
|
|
#if DT_HAS_COMPAT_STATUS_OKAY(sqn_gm02s) |
|
MODEM_CHAT_SCRIPT_CMDS_DEFINE(sqn_gm02s_init_chat_script_cmds, |
|
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+CEREG=1", ok_match), |
|
MODEM_CHAT_SCRIPT_CMD_RESP("AT+CEREG?", 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+CMUX=0,0,5,127", ok_match)); |
|
|
|
MODEM_CHAT_SCRIPT_DEFINE(sqn_gm02s_init_chat_script, sqn_gm02s_init_chat_script_cmds, |
|
abort_matches, modem_cellular_chat_callback_handler, 10); |
|
|
|
MODEM_CHAT_SCRIPT_CMDS_DEFINE(sqn_gm02s_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_NONE("AT+CFUN=1", 10000), |
|
MODEM_CHAT_SCRIPT_CMD_RESP("ATD*99***1#", connect_match)); |
|
|
|
MODEM_CHAT_SCRIPT_DEFINE(sqn_gm02s_dial_chat_script, sqn_gm02s_dial_chat_script_cmds, |
|
dial_abort_matches, modem_cellular_chat_callback_handler, 15); |
|
|
|
MODEM_CHAT_SCRIPT_CMDS_DEFINE(sqn_gm02s_periodic_chat_script_cmds, |
|
MODEM_CHAT_SCRIPT_CMD_RESP("AT+CEREG?", ok_match)); |
|
|
|
MODEM_CHAT_SCRIPT_DEFINE(sqn_gm02s_periodic_chat_script, |
|
sqn_gm02s_periodic_chat_script_cmds, abort_matches, |
|
modem_cellular_chat_callback_handler, 4); |
|
#endif |
|
|
|
#define MODEM_CELLULAR_INST_NAME(name, inst) \ |
|
_CONCAT_4(name, _, DT_DRV_COMPAT, inst) |
|
|
|
#define MODEM_CELLULAR_DEFINE_USER_PIPE_DATA(inst, name, size) \ |
|
MODEM_PIPELINK_DT_INST_DEFINE(inst, name); \ |
|
static uint8_t MODEM_CELLULAR_INST_NAME(name, inst)[size] \ |
|
|
|
#define MODEM_CELLULAR_INIT_USER_PIPE(_inst, _name, _dlci_address) \ |
|
{ \ |
|
.dlci_address = _dlci_address, \ |
|
.dlci_receive_buf = MODEM_CELLULAR_INST_NAME(_name, _inst), \ |
|
.dlci_receive_buf_size = sizeof(MODEM_CELLULAR_INST_NAME(_name, _inst)), \ |
|
.pipelink = MODEM_PIPELINK_DT_INST_GET(_inst, _name), \ |
|
} |
|
|
|
#define MODEM_CELLULAR_DEFINE_USER_PIPES(inst, ...) \ |
|
static struct modem_cellular_user_pipe MODEM_CELLULAR_INST_NAME(user_pipes, inst)[] = { \ |
|
__VA_ARGS__ \ |
|
} |
|
|
|
#define MODEM_CELLULAR_GET_USER_PIPES(inst) \ |
|
MODEM_CELLULAR_INST_NAME(user_pipes, inst) |
|
|
|
/* Extract the first argument (pipe name) from a pair */ |
|
#define MODEM_CELLULAR_GET_PIPE_NAME_ARG(arg1, ...) arg1 |
|
|
|
/* Extract the second argument (DLCI address) from a pair */ |
|
#define MODEM_CELLULAR_GET_DLCI_ADDRESS_ARG(arg1, arg2, ...) arg2 |
|
|
|
/* Define user pipe data using instance and extracted pipe name */ |
|
#define MODEM_CELLULAR_DEFINE_USER_PIPE_DATA_HELPER(_args, inst) \ |
|
MODEM_CELLULAR_DEFINE_USER_PIPE_DATA(inst, \ |
|
MODEM_CELLULAR_GET_PIPE_NAME_ARG _args, \ |
|
CONFIG_MODEM_CELLULAR_USER_PIPE_BUFFER_SIZES) |
|
|
|
/* Initialize user pipe using instance, extracted pipe name, and DLCI address */ |
|
#define MODEM_CELLULAR_INIT_USER_PIPE_HELPER(_args, inst) \ |
|
MODEM_CELLULAR_INIT_USER_PIPE(inst, \ |
|
MODEM_CELLULAR_GET_PIPE_NAME_ARG _args, \ |
|
MODEM_CELLULAR_GET_DLCI_ADDRESS_ARG _args) |
|
|
|
/* |
|
* Define and initialize user pipes dynamically |
|
* Takes an instance and pairs of (pipe name, DLCI address) |
|
*/ |
|
#define MODEM_CELLULAR_DEFINE_AND_INIT_USER_PIPES(inst, ...) \ |
|
FOR_EACH_FIXED_ARG(MODEM_CELLULAR_DEFINE_USER_PIPE_DATA_HELPER, \ |
|
(;), inst, __VA_ARGS__); \ |
|
MODEM_CELLULAR_DEFINE_USER_PIPES( \ |
|
inst, \ |
|
FOR_EACH_FIXED_ARG(MODEM_CELLULAR_INIT_USER_PIPE_HELPER, \ |
|
(,), inst, __VA_ARGS__) \ |
|
); |
|
|
|
/* 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, \ |
|
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, {}), \ |
|
.reset_gpio = GPIO_DT_SPEC_INST_GET_OR(inst, mdm_reset_gpios, {}), \ |
|
.wake_gpio = GPIO_DT_SPEC_INST_GET_OR(inst, mdm_wake_gpios, {}), \ |
|
.power_pulse_duration_ms = (power_ms), \ |
|
.reset_pulse_duration_ms = (reset_ms), \ |
|
.startup_time_ms = (startup_ms), \ |
|
.shutdown_time_ms = (shutdown_ms), \ |
|
.autostarts = (start), \ |
|
.set_baudrate_chat_script = (set_baudrate_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)), \ |
|
}; \ |
|
\ |
|
PM_DEVICE_DT_INST_DEFINE(inst, modem_cellular_pm_action); \ |
|
\ |
|
DEVICE_DT_INST_DEFINE(inst, modem_cellular_init, PM_DEVICE_DT_INST_GET(inst), \ |
|
&MODEM_CELLULAR_INST_NAME(data, inst), \ |
|
&MODEM_CELLULAR_INST_NAME(config, inst), POST_KERNEL, 99, \ |
|
&modem_cellular_api); |
|
|
|
#define MODEM_CELLULAR_DEVICE_QUECTEL_BG95(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, 1500, 100, 10000, 5000, false, \ |
|
NULL, \ |
|
&quectel_bg95_init_chat_script, \ |
|
&quectel_bg95_dial_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); \ |
|
\ |
|
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, 1500, 500, 15000, 5000, false, \ |
|
NULL, \ |
|
&quectel_eg25_g_init_chat_script, \ |
|
&quectel_eg25_g_dial_chat_script, \ |
|
&quectel_eg25_g_periodic_chat_script, NULL) |
|
|
|
#define MODEM_CELLULAR_DEVICE_QUECTEL_EG800Q(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, 1500, 500, 15000, 5000, false, \ |
|
NULL, \ |
|
&quectel_eg800q_init_chat_script, \ |
|
&quectel_eg800q_dial_chat_script, \ |
|
&quectel_eg800q_periodic_chat_script, NULL) |
|
|
|
#define MODEM_CELLULAR_DEVICE_SIMCOM_SIM7080(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, 1500, 100, 10000, 5000, false, \ |
|
NULL, \ |
|
&simcom_sim7080_init_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); \ |
|
\ |
|
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, 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, NULL) |
|
|
|
#define MODEM_CELLULAR_DEVICE_U_BLOX_SARA_R5(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, 4), \ |
|
(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, NULL) |
|
|
|
#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, \ |
|
NULL) |
|
|
|
#define MODEM_CELLULAR_DEVICE_SWIR_HL7800(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, 1500, 100, 10000, 5000, false, \ |
|
NULL, \ |
|
&swir_hl7800_init_chat_script, \ |
|
&swir_hl7800_dial_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); \ |
|
\ |
|
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)) \ |
|
\ |
|
MODEM_CELLULAR_DEFINE_INSTANCE(inst, 5050, 250, 15000, 5000, false, \ |
|
NULL, \ |
|
&telit_mex10g1_init_chat_script, \ |
|
&telit_mex10g1_dial_chat_script, \ |
|
&telit_mex10g1_periodic_chat_script, \ |
|
NULL) |
|
|
|
#define MODEM_CELLULAR_DEVICE_TELIT_ME310G1(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)) \ |
|
\ |
|
MODEM_CELLULAR_DEFINE_INSTANCE(inst, 5050, 0 /* unused */, 1000, 15000, false, \ |
|
NULL, \ |
|
&telit_mex10g1_init_chat_script, \ |
|
&telit_mex10g1_dial_chat_script, \ |
|
&telit_mex10g1_periodic_chat_script, \ |
|
&telit_me310g1_shutdown_chat_script) |
|
|
|
#define MODEM_CELLULAR_DEVICE_NORDIC_NRF91_SLM(inst) \ |
|
MODEM_PPP_DEFINE(MODEM_CELLULAR_INST_NAME(ppp, inst), NULL, 98, 1500, 1500); \ |
|
\ |
|
static struct modem_cellular_data MODEM_CELLULAR_INST_NAME(data, inst) = { \ |
|
.chat_delimiter = "\r\n", \ |
|
.ppp = &MODEM_CELLULAR_INST_NAME(ppp, inst), \ |
|
}; \ |
|
\ |
|
MODEM_CELLULAR_DEFINE_AND_INIT_USER_PIPES(inst, \ |
|
(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, NULL) |
|
|
|
#define MODEM_CELLULAR_DEVICE_SQN_GM02S(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, 1500, 100, 2000, 5000, true, \ |
|
NULL, \ |
|
&sqn_gm02s_init_chat_script, \ |
|
&sqn_gm02s_dial_chat_script, \ |
|
&sqn_gm02s_periodic_chat_script, NULL) |
|
|
|
#define DT_DRV_COMPAT quectel_bg95 |
|
DT_INST_FOREACH_STATUS_OKAY(MODEM_CELLULAR_DEVICE_QUECTEL_BG95) |
|
#undef DT_DRV_COMPAT |
|
|
|
#define DT_DRV_COMPAT quectel_eg25_g |
|
DT_INST_FOREACH_STATUS_OKAY(MODEM_CELLULAR_DEVICE_QUECTEL_EG25_G) |
|
#undef DT_DRV_COMPAT |
|
|
|
#define DT_DRV_COMPAT quectel_eg800q |
|
DT_INST_FOREACH_STATUS_OKAY(MODEM_CELLULAR_DEVICE_QUECTEL_EG800Q) |
|
#undef DT_DRV_COMPAT |
|
|
|
#define DT_DRV_COMPAT simcom_sim7080 |
|
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 |
|
|
|
#define DT_DRV_COMPAT u_blox_sara_r5 |
|
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 |
|
|
|
#define DT_DRV_COMPAT telit_me910g1 |
|
DT_INST_FOREACH_STATUS_OKAY(MODEM_CELLULAR_DEVICE_TELIT_ME910G1) |
|
#undef DT_DRV_COMPAT |
|
|
|
#define DT_DRV_COMPAT telit_me310g1 |
|
DT_INST_FOREACH_STATUS_OKAY(MODEM_CELLULAR_DEVICE_TELIT_ME310G1) |
|
#undef DT_DRV_COMPAT |
|
|
|
#define DT_DRV_COMPAT nordic_nrf91_slm |
|
DT_INST_FOREACH_STATUS_OKAY(MODEM_CELLULAR_DEVICE_NORDIC_NRF91_SLM) |
|
#undef DT_DRV_COMPAT |
|
|
|
#define DT_DRV_COMPAT sqn_gm02s |
|
DT_INST_FOREACH_STATUS_OKAY(MODEM_CELLULAR_DEVICE_SQN_GM02S) |
|
#undef DT_DRV_COMPAT
|
|
|