Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Add runtime chat script support for modem_chat module #62703

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions drivers/modem/modem_cellular.c
Original file line number Diff line number Diff line change
Expand Up @@ -591,7 +591,7 @@ static void modem_cellular_run_init_script_event_handler(struct modem_cellular_d
switch (evt) {
case MODEM_CELLULAR_EVENT_BUS_OPENED:
modem_chat_attach(&data->chat, data->uart_pipe);
modem_chat_script_run(&data->chat, config->init_chat_script);
modem_chat_run_script_async(&data->chat, config->init_chat_script);
break;

case MODEM_CELLULAR_EVENT_SCRIPT_SUCCESS:
Expand Down Expand Up @@ -740,7 +740,7 @@ static void modem_cellular_run_dial_script_event_handler(struct modem_cellular_d
switch (evt) {
case MODEM_CELLULAR_EVENT_TIMEOUT:
modem_chat_attach(&data->chat, data->dlci1_pipe);
modem_chat_script_run(&data->chat, config->dial_chat_script);
modem_chat_run_script_async(&data->chat, config->dial_chat_script);
break;

case MODEM_CELLULAR_EVENT_SCRIPT_SUCCESS:
Expand Down
99 changes: 69 additions & 30 deletions include/zephyr/modem/chat.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,22 +35,20 @@ typedef void (*modem_chat_match_callback)(struct modem_chat *chat, char **argv,
* @brief Modem chat match
*/
struct modem_chat_match {
/* Match array */
/** Match array */
const uint8_t *match;
const uint8_t match_size;

/* Separators array */
/** Size of match */
uint8_t match_size;
/** Separators array */
const uint8_t *separators;
const uint8_t separators_size;

/* Set if modem chat instance shall use wildcards when matching */
const uint8_t wildcards : 1;

/* Set if script shall not continue to next step in case of match */
const uint8_t partial : 1;

/* Type of modem chat instance */
const modem_chat_match_callback callback;
/** Size of separators array */
uint8_t separators_size;
/** Set if modem chat instance shall use wildcards when matching */
uint8_t wildcards : 1;
/** Set if script shall not continue to next step in case of match */
uint8_t partial : 1;
/** Type of modem chat instance */
modem_chat_match_callback callback;
};

#define MODEM_CHAT_MATCH(_match, _separators, _callback) \
Expand Down Expand Up @@ -90,36 +88,47 @@ struct modem_chat_match {
* @brief Modem chat script chat
*/
struct modem_chat_script_chat {
/** Request to send to modem formatted as char string */
const char *request;
/** Request to send to modem */
const uint8_t *request;
/** Size of request */
uint8_t request_size;
jukkar marked this conversation as resolved.
Show resolved Hide resolved
/** Expected responses to request */
const struct modem_chat_match *const response_matches;
const struct modem_chat_match *response_matches;
/** Number of elements in expected responses */
const uint16_t response_matches_size;
uint16_t response_matches_size;
/** Timeout before chat script may continue to next step in milliseconds */
uint16_t timeout;
};

#define MODEM_CHAT_SCRIPT_CMD_RESP(_request, _response_match) \
{ \
.request = _request, .response_matches = &_response_match, \
.response_matches_size = 1, .timeout = 0, \
.request = (uint8_t *)(_request), \
.request_size = (uint8_t)(sizeof(_request) - 1), \
.response_matches = &_response_match, \
.response_matches_size = 1, \
.timeout = 0, \
}

#define MODEM_CHAT_SCRIPT_CMD_RESP_MULT(_request, _response_matches) \
{ \
.request = _request, .response_matches = _response_matches, \
.response_matches_size = ARRAY_SIZE(_response_matches), .timeout = 0, \
.request = (uint8_t *)(_request), \
.request_size = (uint8_t)(sizeof(_request) - 1), \
.response_matches = _response_matches, \
.response_matches_size = ARRAY_SIZE(_response_matches), \
.timeout = 0, \
}

#define MODEM_CHAT_SCRIPT_CMD_RESP_NONE(_request, _timeout) \
{ \
.request = _request, .response_matches = NULL, .response_matches_size = 0, \
.request = (uint8_t *)(_request), \
.request_size = (uint8_t)(sizeof(_request) - 1), \
.response_matches = NULL, \
.response_matches_size = 0, \
.timeout = _timeout, \
}

#define MODEM_CHAT_SCRIPT_CMDS_DEFINE(_sym, ...) \
const static struct modem_chat_script_chat _sym[] = {__VA_ARGS__}
const struct modem_chat_script_chat _sym[] = {__VA_ARGS__}

enum modem_chat_script_result {
MODEM_CHAT_SCRIPT_RESULT_SUCCESS,
Expand All @@ -146,15 +155,15 @@ struct modem_chat_script {
/** Array of script chats */
const struct modem_chat_script_chat *script_chats;
/** Elements in array of script chats */
const uint16_t script_chats_size;
uint16_t script_chats_size;
/** Array of abort matches */
const struct modem_chat_match *const abort_matches;
const struct modem_chat_match *abort_matches;
/** Number of elements in array of abort matches */
const uint16_t abort_matches_size;
uint16_t abort_matches_size;
/** Callback called when script execution terminates */
modem_chat_script_callback callback;
/** Timeout in seconds within which the script execution must terminate */
const uint32_t timeout;
uint32_t timeout;
};

#define MODEM_CHAT_SCRIPT_DEFINE(_sym, _script_chats, _abort_matches, _callback, _timeout) \
Expand Down Expand Up @@ -227,6 +236,8 @@ struct modem_chat {
struct k_work script_abort_work;
uint16_t script_chat_it;
atomic_t script_state;
enum modem_chat_script_result script_result;
struct k_sem script_stopped_sem;

/* Script sending */
uint16_t script_send_request_pos;
Expand Down Expand Up @@ -293,6 +304,18 @@ int modem_chat_init(struct modem_chat *chat, const struct modem_chat_config *con
*/
int modem_chat_attach(struct modem_chat *chat, struct modem_pipe *pipe);

/**
* @brief Run script asynchronously
* @param chat Chat instance
* @param script Script to run
* @returns 0 if script successfully started
* @returns -EBUSY if a script is currently running
* @returns -EPERM if modem pipe is not attached
* @returns -EINVAL if arguments or script is invalid
* @note Script runs asynchronously until complete or aborted.
*/
int modem_chat_run_script_async(struct modem_chat *chat, const struct modem_chat_script *script);

/**
* @brief Run script
* @param chat Chat instance
Expand All @@ -301,9 +324,25 @@ int modem_chat_attach(struct modem_chat *chat, struct modem_pipe *pipe);
* @returns -EBUSY if a script is currently running
* @returns -EPERM if modem pipe is not attached
* @returns -EINVAL if arguments or script is invalid
* @note Script runs asynchronously until complete or aborted.
* @note Script runs until complete or aborted.
*/
int modem_chat_script_run(struct modem_chat *chat, const struct modem_chat_script *script);
int modem_chat_run_script(struct modem_chat *chat, const struct modem_chat_script *script);

/**
* @brief Run script asynchronously
* @note Function exists for backwards compatibility and should be deprecated
* @param chat Chat instance
* @param script Script to run
* @returns 0 if script successfully started
* @returns -EBUSY if a script is currently running
* @returns -EPERM if modem pipe is not attached
* @returns -EINVAL if arguments or script is invalid
*/
static inline int modem_chat_script_run(struct modem_chat *chat,
const struct modem_chat_script *script)
{
return modem_chat_run_script_async(chat, script);
}

/**
* @brief Abort script
Expand Down
52 changes: 38 additions & 14 deletions subsys/modem/modem_chat.c
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,6 @@ static void modem_chat_script_stop(struct modem_chat *chat, enum modem_chat_scri
LOG_WRN("%s: timed out", chat->script->name);
}

/* Clear script running state */
atomic_clear_bit(&chat->script_state, MODEM_CHAT_SCRIPT_STATE_RUNNING_BIT);

/* Call back with result */
if (chat->script->callback != NULL) {
chat->script->callback(chat, result, chat->user_data);
Expand All @@ -88,6 +85,15 @@ static void modem_chat_script_stop(struct modem_chat *chat, enum modem_chat_scri

/* Cancel timeout work */
k_work_cancel_delayable(&chat->script_timeout_work);

/* Clear script running state */
atomic_clear_bit(&chat->script_state, MODEM_CHAT_SCRIPT_STATE_RUNNING_BIT);

/* Store result of script for script stoppted indication */
chat->script_result = result;

/* Indicate script stopped */
k_sem_give(&chat->script_stopped_sem);
}

static void modem_chat_script_send(struct modem_chat *chat)
Expand Down Expand Up @@ -129,8 +135,8 @@ static void modem_chat_script_next(struct modem_chat *chat, bool initial)
chat->matches_size[MODEM_CHAT_MATCHES_INDEX_RESPONSE] = script_chat->response_matches_size;

/* Check if work must be sent */
if (strlen(script_chat->request) > 0) {
LOG_DBG("sending: %s", script_chat->request);
if (script_chat->request_size > 0) {
LOG_DBG("sending: %.*s", script_chat->request_size, script_chat->request);
modem_chat_script_send(chat);
}
}
Expand Down Expand Up @@ -190,18 +196,17 @@ static bool modem_chat_script_send_request(struct modem_chat *chat)
const struct modem_chat_script_chat *script_chat =
&chat->script->script_chats[chat->script_chat_it];

uint16_t script_chat_request_size = strlen(script_chat->request);
uint8_t *script_chat_request_start;
uint16_t script_chat_request_remaining;
int ret;

/* Validate data to send */
if (script_chat_request_size == chat->script_send_request_pos) {
if (script_chat->request_size == chat->script_send_request_pos) {
return true;
}

script_chat_request_start = (uint8_t *)&script_chat->request[chat->script_send_request_pos];
script_chat_request_remaining = script_chat_request_size - chat->script_send_request_pos;
script_chat_request_remaining = script_chat->request_size - chat->script_send_request_pos;

/* Send data through pipe */
ret = modem_pipe_transmit(chat->pipe, script_chat_request_start,
Expand All @@ -216,7 +221,7 @@ static bool modem_chat_script_send_request(struct modem_chat *chat)
chat->script_send_request_pos += (uint16_t)ret;

/* Check if data remains */
if (chat->script_send_request_pos < script_chat_request_size) {
if (chat->script_send_request_pos < script_chat->request_size) {
return false;
}

Expand Down Expand Up @@ -680,9 +685,6 @@ static void modem_chat_pipe_callback(struct modem_pipe *pipe, enum modem_pipe_ev
}
}

/*********************************************************
* GLOBAL FUNCTIONS
*********************************************************/
int modem_chat_init(struct modem_chat *chat, const struct modem_chat_config *config)
{
__ASSERT_NO_MSG(chat != NULL);
Expand Down Expand Up @@ -711,6 +713,7 @@ int modem_chat_init(struct modem_chat *chat, const struct modem_chat_config *con
chat->matches_size[MODEM_CHAT_MATCHES_INDEX_UNSOL] = config->unsol_matches_size;
chat->process_timeout = config->process_timeout;
atomic_set(&chat->script_state, 0);
k_sem_init(&chat->script_stopped_sem, 0, 1);
k_work_init_delayable(&chat->process_work, modem_chat_process_handler);
k_work_init(&chat->script_run_work, modem_chat_script_run_handler);
k_work_init_delayable(&chat->script_timeout_work, modem_chat_script_timeout_handler);
Expand All @@ -730,7 +733,7 @@ int modem_chat_attach(struct modem_chat *chat, struct modem_pipe *pipe)
return 0;
}

int modem_chat_script_run(struct modem_chat *chat, const struct modem_chat_script *script)
int modem_chat_run_script_async(struct modem_chat *chat, const struct modem_chat_script *script)
{
bool script_is_running;

Expand All @@ -746,7 +749,7 @@ int modem_chat_script_run(struct modem_chat *chat, const struct modem_chat_scrip

/* Validate script commands */
for (uint16_t i = 0; i < script->script_chats_size; i++) {
if ((strlen(script->script_chats[i].request) == 0) &&
if ((script->script_chats[i].request_size == 0) &&
(script->script_chats[i].response_matches_size == 0)) {
return -EINVAL;
}
Expand All @@ -764,6 +767,25 @@ int modem_chat_script_run(struct modem_chat *chat, const struct modem_chat_scrip
return 0;
}

int modem_chat_run_script(struct modem_chat *chat, const struct modem_chat_script *script)
{
int ret;

k_sem_reset(&chat->script_stopped_sem);

ret = modem_chat_run_script_async(chat, script);
if (ret < 0) {
return ret;
}

ret = k_sem_take(&chat->script_stopped_sem, K_FOREVER);
if (ret < 0) {
return ret;
}

return chat->script_result == MODEM_CHAT_SCRIPT_RESULT_SUCCESS ? 0 : -EAGAIN;
}

void modem_chat_script_abort(struct modem_chat *chat)
{
k_work_submit(&chat->script_abort_work);
Expand All @@ -789,6 +811,8 @@ void modem_chat_release(struct modem_chat *chat)
chat->script = NULL;
chat->script_chat_it = 0;
atomic_set(&chat->script_state, 0);
chat->script_result = MODEM_CHAT_SCRIPT_RESULT_ABORT;
k_sem_reset(&chat->script_stopped_sem);
chat->script_send_request_pos = 0;
chat->script_send_delimiter_pos = 0;
chat->parse_match = NULL;
Expand Down
Loading
Loading