drivers/modem/modem_cmd_handler: Update API

There is currently not a clear separation between
user configuration and internal context when using the
modem_cmd_handler library. This update adds a clear
separation, placing user configuration in a seperate
struct passed to modem_cmd_handler_init alongside the
internal context modem_cmd_handler_data.

There is also a lack of documentation of the user
configurations, these have been added to the new config
struct.

The new API function modem_cmd_handler_process has been
added to remove the need for the user to directly access
the process member of the internal context. This ensures
that the user is not encouraged to access any internal
context members.

Some whitespace errors exist in the modem_cmd_handler.c
file, these are outside of the scope of this PR. These
can be addressed in a later PR as they are not functional
changes.

Signed-off-by: Bjarki Arge Andreasen <baa@trackunit.com>
This commit is contained in:
Bjarki Arge Andreasen 2022-11-21 07:51:33 +01:00 committed by Carles Cufí
parent a4afcf8c93
commit aa6ecc59d1
7 changed files with 175 additions and 72 deletions

View file

@ -177,8 +177,7 @@ static void gsm_rx(struct gsm_modem *gsm)
modem_iface_uart_rx_wait(&gsm->context.iface, K_FOREVER);
/* The handler will listen AT channel */
gsm->context.cmd_handler.process(&gsm->context.cmd_handler,
&gsm->context.iface);
modem_cmd_handler_process(&gsm->context.cmd_handler, &gsm->context.iface);
}
}
@ -1273,19 +1272,24 @@ static int gsm_init(const struct device *dev)
(void)k_mutex_init(&gsm->lock);
gsm->dev = dev;
gsm->cmd_handler_data.cmds[CMD_RESP] = response_cmds;
gsm->cmd_handler_data.cmds_len[CMD_RESP] = ARRAY_SIZE(response_cmds);
gsm->cmd_handler_data.match_buf = &gsm->cmd_match_buf[0];
gsm->cmd_handler_data.match_buf_len = sizeof(gsm->cmd_match_buf);
gsm->cmd_handler_data.buf_pool = &gsm_recv_pool;
gsm->cmd_handler_data.alloc_timeout = K_NO_WAIT;
gsm->cmd_handler_data.eol = "\r";
const struct modem_cmd_handler_config cmd_handler_config = {
.match_buf = &gsm->cmd_match_buf[0],
.match_buf_len = sizeof(gsm->cmd_match_buf),
.buf_pool = &gsm_recv_pool,
.alloc_timeout = K_NO_WAIT,
.eol = "\r",
.user_data = NULL,
.response_cmds = response_cmds,
.response_cmds_len = ARRAY_SIZE(response_cmds),
.unsol_cmds = NULL,
.unsol_cmds_len = 0,
};
(void)k_sem_init(&gsm->sem_response, 0, 1);
(void)k_sem_init(&gsm->sem_if_down, 0, 1);
ret = modem_cmd_handler_init(&gsm->context.cmd_handler,
&gsm->cmd_handler_data);
ret = modem_cmd_handler_init(&gsm->context.cmd_handler, &gsm->cmd_handler_data,
&cmd_handler_config);
if (ret < 0) {
LOG_DBG("cmd handler error %d", ret);
return ret;

View file

@ -646,25 +646,47 @@ void modem_cmd_handler_tx_unlock(struct modem_cmd_handler *handler)
}
int modem_cmd_handler_init(struct modem_cmd_handler *handler,
struct modem_cmd_handler_data *data)
struct modem_cmd_handler_data *data,
const struct modem_cmd_handler_config *config)
{
if (!handler || !data) {
/* Verify arguments */
if (handler == NULL || data == NULL || config == NULL) {
return -EINVAL;
}
if (!data->match_buf_len) {
/* Verify config */
if ((config->match_buf == NULL) ||
(config->match_buf_len == 0) ||
(config->buf_pool == NULL) ||
(NULL != config->response_cmds && 0 == config->response_cmds_len) ||
(NULL != config->unsol_cmds && 0 == config->unsol_cmds_len)) {
return -EINVAL;
}
if (data->eol == NULL) {
data->eol_len = 0;
} else {
data->eol_len = strlen(data->eol);
}
/* Assign data to command handler */
handler->cmd_handler_data = data;
/* Assign command process implementation to command handler */
handler->process = cmd_handler_process;
/* Store arguments */
data->match_buf = config->match_buf;
data->match_buf_len = config->match_buf_len;
data->buf_pool = config->buf_pool;
data->alloc_timeout = config->alloc_timeout;
data->eol = config->eol;
data->cmds[CMD_RESP] = config->response_cmds;
data->cmds_len[CMD_RESP] = config->response_cmds_len;
data->cmds[CMD_UNSOL] = config->unsol_cmds;
data->cmds_len[CMD_UNSOL] = config->unsol_cmds_len;
/* Process end of line */
data->eol_len = data->eol == NULL ? 0 : strlen(data->eol);
/* Store optional user data */
data->user_data = config->user_data;
/* Initialize command handler data members */
k_sem_init(&data->sem_tx_lock, 1, 1);
k_sem_init(&data->sem_parse_lock, 1, 1);

View file

@ -266,15 +266,56 @@ int modem_cmd_handler_setup_cmds_nolock(struct modem_iface *iface,
k_timeout_t timeout);
/**
* @brief Init command handler
* @brief Modem command handler configuration
*
* @param *handler: command handler to initialize
* @param *data: command handler data to use
* @details Contains user configuration which is used to set up
* command handler data context. The struct is initialized and then passed
* to modem_cmd_handler_init().
*
* @retval 0 if ok, < 0 if error.
* @param match_buf Buffer used for matching commands
* @param match_buf_len Length of buffer used for matching commands
* @param buf_pool Initialized buffer pool used to store incoming data
* @param alloc_timeout Timeout for allocating data in buffer pool
* @param eol End of line represented as string
* @param user_data Free to use data which can be retrieved from within command handlers
* @param response_cmds Array of response command handlers
* @param response_cmds_len Length of response command handlers array
* @param unsol_cmds Array of unsolicitet command handlers
* @param unsol_cmds_len Length of unsolicitet command handlers array
*/
struct modem_cmd_handler_config {
char *match_buf;
size_t match_buf_len;
struct net_buf_pool *buf_pool;
k_timeout_t alloc_timeout;
const char *eol;
void *user_data;
const struct modem_cmd *response_cmds;
size_t response_cmds_len;
const struct modem_cmd *unsol_cmds;
size_t unsol_cmds_len;
};
/**
* @brief Initialize modem command handler
*
* @details This function is called once for each command handler, before any
* incoming data is processed.
*
* @note All arguments passed to this function, including the referenced data
* contained in the setup struct, must persist as long as the command handler itself.
*
* @param handler Command handler to initialize
* @param data Command handler data to use
* @param setup Command handler setup
*
* @return -EINVAL if any argument is invalid
* @return 0 if successful
*/
int modem_cmd_handler_init(struct modem_cmd_handler *handler,
struct modem_cmd_handler_data *data);
struct modem_cmd_handler_data *data,
const struct modem_cmd_handler_config *config);
/**
* @brief Lock the modem for sending cmds
@ -299,6 +340,25 @@ int modem_cmd_handler_tx_lock(struct modem_cmd_handler *handler,
*/
void modem_cmd_handler_tx_unlock(struct modem_cmd_handler *handler);
/**
* @brief Process incoming data
*
* @details This function will process any data available from the interface
* using the command handler. The command handler will invoke any matching modem
* command which has been registered using @ref modem_cmd_handler_init_cmds or
* @ref modem_cmd_handler_update_cmds. Once handled, the function will return.
*
* @note This function should be invoked from a dedicated thread, which only handles
* commands.
*
* @param handler The handler wich will handle the command when processed
* @param iface The interface which receives incoming data
*/
static inline void modem_cmd_handler_process(struct modem_cmd_handler *handler,
struct modem_iface *iface)
{
handler->process(handler, iface);
}
#ifdef __cplusplus
}

View file

@ -850,7 +850,7 @@ static void modem_rx(void)
/* Wait for incoming data */
modem_iface_uart_rx_wait(&mctx.iface, K_FOREVER);
mctx.cmd_handler.process(&mctx.cmd_handler, &mctx.iface);
modem_cmd_handler_process(&mctx.cmd_handler, &mctx.iface);
}
}
@ -1153,17 +1153,22 @@ static int modem_init(const struct device *dev)
goto error;
}
/* cmd handler */
mdata.cmd_handler_data.cmds[CMD_RESP] = response_cmds;
mdata.cmd_handler_data.cmds_len[CMD_RESP] = ARRAY_SIZE(response_cmds);
mdata.cmd_handler_data.cmds[CMD_UNSOL] = unsol_cmds;
mdata.cmd_handler_data.cmds_len[CMD_UNSOL] = ARRAY_SIZE(unsol_cmds);
mdata.cmd_handler_data.match_buf = &mdata.cmd_match_buf[0];
mdata.cmd_handler_data.match_buf_len = sizeof(mdata.cmd_match_buf);
mdata.cmd_handler_data.buf_pool = &mdm_recv_pool;
mdata.cmd_handler_data.alloc_timeout = BUF_ALLOC_TIMEOUT;
mdata.cmd_handler_data.eol = "\r\n";
ret = modem_cmd_handler_init(&mctx.cmd_handler, &mdata.cmd_handler_data);
/* cmd handler setup */
const struct modem_cmd_handler_config cmd_handler_config = {
.match_buf = &mdata.cmd_match_buf[0],
.match_buf_len = sizeof(mdata.cmd_match_buf),
.buf_pool = &mdm_recv_pool,
.alloc_timeout = BUF_ALLOC_TIMEOUT,
.eol = "\r\n",
.user_data = NULL,
.response_cmds = response_cmds,
.response_cmds_len = ARRAY_SIZE(response_cmds),
.unsol_cmds = unsol_cmds,
.unsol_cmds_len = ARRAY_SIZE(unsol_cmds),
};
ret = modem_cmd_handler_init(&mctx.cmd_handler, &mdata.cmd_handler_data,
&cmd_handler_config);
if (ret < 0) {
goto error;
}

View file

@ -808,7 +808,7 @@ static void modem_rx(void)
/* Wait for incoming data */
modem_iface_uart_rx_wait(&mctx.iface, K_FOREVER);
mctx.cmd_handler.process(&mctx.cmd_handler, &mctx.iface);
modem_cmd_handler_process(&mctx.cmd_handler, &mctx.iface);
}
}
@ -2349,16 +2349,21 @@ static int modem_init(const struct device *dev)
change_state(SIM7080_STATE_INIT);
/* Command handler. */
mdata.cmd_handler_data.cmds[CMD_RESP] = response_cmds;
mdata.cmd_handler_data.cmds_len[CMD_RESP] = ARRAY_SIZE(response_cmds);
mdata.cmd_handler_data.cmds[CMD_UNSOL] = unsolicited_cmds;
mdata.cmd_handler_data.cmds_len[CMD_UNSOL] = ARRAY_SIZE(unsolicited_cmds);
mdata.cmd_handler_data.match_buf = &mdata.cmd_match_buf[0];
mdata.cmd_handler_data.match_buf_len = sizeof(mdata.cmd_match_buf);
mdata.cmd_handler_data.buf_pool = &mdm_recv_pool;
mdata.cmd_handler_data.alloc_timeout = BUF_ALLOC_TIMEOUT;
mdata.cmd_handler_data.eol = "\r\n";
ret = modem_cmd_handler_init(&mctx.cmd_handler, &mdata.cmd_handler_data);
const struct modem_cmd_handler_config cmd_handler_config = {
.match_buf = &mdata.cmd_match_buf[0],
.match_buf_len = sizeof(mdata.cmd_match_buf),
.buf_pool = &mdm_recv_pool,
.alloc_timeout = BUF_ALLOC_TIMEOUT,
.eol = "\r\n",
.user_data = NULL,
.response_cmds = response_cmds,
.response_cmds_len = ARRAY_SIZE(response_cmds),
.unsol_cmds = unsolicited_cmds,
.unsol_cmds_len = ARRAY_SIZE(unsolicited_cmds),
};
ret = modem_cmd_handler_init(&mctx.cmd_handler, &mdata.cmd_handler_data,
&cmd_handler_config);
if (ret < 0) {
goto error;
}

View file

@ -942,7 +942,7 @@ static void modem_rx(void)
/* wait for incoming data */
modem_iface_uart_rx_wait(&mctx.iface, K_FOREVER);
mctx.cmd_handler.process(&mctx.cmd_handler, &mctx.iface);
modem_cmd_handler_process(&mctx.cmd_handler, &mctx.iface);
/* give up time if we have a solid stream of data */
k_yield();
@ -2149,17 +2149,21 @@ static int modem_init(const struct device *dev)
}
/* cmd handler */
mdata.cmd_handler_data.cmds[CMD_RESP] = response_cmds;
mdata.cmd_handler_data.cmds_len[CMD_RESP] = ARRAY_SIZE(response_cmds);
mdata.cmd_handler_data.cmds[CMD_UNSOL] = unsol_cmds;
mdata.cmd_handler_data.cmds_len[CMD_UNSOL] = ARRAY_SIZE(unsol_cmds);
mdata.cmd_handler_data.match_buf = &mdata.cmd_match_buf[0];
mdata.cmd_handler_data.match_buf_len = sizeof(mdata.cmd_match_buf);
mdata.cmd_handler_data.buf_pool = &mdm_recv_pool;
mdata.cmd_handler_data.alloc_timeout = K_NO_WAIT;
mdata.cmd_handler_data.eol = "\r";
ret = modem_cmd_handler_init(&mctx.cmd_handler,
&mdata.cmd_handler_data);
const struct modem_cmd_handler_config cmd_handler_config = {
.match_buf = &mdata.cmd_match_buf[0],
.match_buf_len = sizeof(mdata.cmd_match_buf),
.buf_pool = &mdm_recv_pool,
.alloc_timeout = K_NO_WAIT,
.eol = "\r",
.user_data = NULL,
.response_cmds = response_cmds,
.response_cmds_len = ARRAY_SIZE(response_cmds),
.unsol_cmds = unsol_cmds,
.unsol_cmds_len = ARRAY_SIZE(unsol_cmds),
};
ret = modem_cmd_handler_init(&mctx.cmd_handler, &mdata.cmd_handler_data,
&cmd_handler_config);
if (ret < 0) {
goto error;
}

View file

@ -205,8 +205,7 @@ static void esp_rx(struct esp_data *data)
/* wait for incoming data */
modem_iface_uart_rx_wait(&data->mctx.iface, K_FOREVER);
data->mctx.cmd_handler.process(&data->mctx.cmd_handler,
&data->mctx.iface);
modem_cmd_handler_process(&data->mctx.cmd_handler, &data->mctx.iface);
/* give up time if we have a solid stream of data */
k_yield();
@ -1270,17 +1269,21 @@ static int esp_init(const struct device *dev)
k_thread_name_set(&data->workq.thread, "esp_workq");
/* cmd handler */
data->cmd_handler_data.cmds[CMD_RESP] = response_cmds;
data->cmd_handler_data.cmds_len[CMD_RESP] = ARRAY_SIZE(response_cmds);
data->cmd_handler_data.cmds[CMD_UNSOL] = unsol_cmds;
data->cmd_handler_data.cmds_len[CMD_UNSOL] = ARRAY_SIZE(unsol_cmds);
data->cmd_handler_data.match_buf = &data->cmd_match_buf[0];
data->cmd_handler_data.match_buf_len = sizeof(data->cmd_match_buf);
data->cmd_handler_data.buf_pool = &mdm_recv_pool;
data->cmd_handler_data.alloc_timeout = K_NO_WAIT;
data->cmd_handler_data.eol = "\r\n";
ret = modem_cmd_handler_init(&data->mctx.cmd_handler,
&data->cmd_handler_data);
const struct modem_cmd_handler_config cmd_handler_config = {
.match_buf = &data->cmd_match_buf[0],
.match_buf_len = sizeof(data->cmd_match_buf),
.buf_pool = &mdm_recv_pool,
.alloc_timeout = K_NO_WAIT,
.eol = "\r\n",
.user_data = NULL,
.response_cmds = response_cmds,
.response_cmds_len = ARRAY_SIZE(response_cmds),
.unsol_cmds = unsol_cmds,
.unsol_cmds_len = ARRAY_SIZE(unsol_cmds),
};
ret = modem_cmd_handler_init(&data->mctx.cmd_handler, &data->cmd_handler_data,
&cmd_handler_config);
if (ret < 0) {
goto error;
}