drivers: modem: cmd_handler: Allow locking TX

A semaphore is used by modem_cmd_handler to protect against concurrent
UART access. This is only used for the duration of sending a command,
but there are cases when one wants to prevent UART access for other
reasons, such as when powering off the modem.

This commit exposes functionality for hogging this semaphore without
having to send a command. Furthermore, a non-locking equivalent for
modem_cmd_handler_setup_cmds is added which was previously missing.

Signed-off-by: Benjamin Lindqvist <benjamin.lindqvist@endian.se>
This commit is contained in:
Benjamin Lindqvist 2020-10-09 13:01:29 +02:00 committed by Jukka Rissanen
parent eb2e89aecf
commit 820bb07c81
2 changed files with 88 additions and 1 deletions

View file

@ -563,6 +563,57 @@ int modem_cmd_handler_setup_cmds(struct modem_iface *iface,
return ret;
}
/* run a set of AT commands, without lock */
int modem_cmd_handler_setup_cmds_nolock(struct modem_iface *iface,
struct modem_cmd_handler *handler,
struct setup_cmd *cmds, size_t cmds_len,
struct k_sem *sem, k_timeout_t timeout)
{
int ret = 0, i;
for (i = 0; i < cmds_len; i++) {
if (i) {
k_sleep(K_MSEC(50));
}
if (cmds[i].handle_cmd.cmd && cmds[i].handle_cmd.func) {
ret = modem_cmd_send_nolock(iface, handler,
&cmds[i].handle_cmd, 1U,
cmds[i].send_cmd,
sem, timeout);
} else {
ret = modem_cmd_send_nolock(iface, handler,
NULL, 0, cmds[i].send_cmd,
sem, timeout);
}
if (ret < 0) {
LOG_ERR("command %s ret:%d",
log_strdup(cmds[i].send_cmd), ret);
break;
}
}
return ret;
}
int modem_cmd_handler_tx_lock(struct modem_cmd_handler *handler,
k_timeout_t timeout)
{
struct modem_cmd_handler_data *data;
data = (struct modem_cmd_handler_data *)(handler->cmd_handler_data);
return k_sem_take(&data->sem_tx_lock, timeout);
}
void modem_cmd_handler_tx_unlock(struct modem_cmd_handler *handler)
{
struct modem_cmd_handler_data *data;
data = (struct modem_cmd_handler_data *)(handler->cmd_handler_data);
k_sem_give(&data->sem_tx_lock);
}
int modem_cmd_handler_init(struct modem_cmd_handler *handler,
struct modem_cmd_handler_data *data)
{

View file

@ -173,7 +173,7 @@ int modem_cmd_send(struct modem_iface *iface,
const uint8_t *buf, struct k_sem *sem, k_timeout_t timeout);
/**
* @brief send a series of AT commands
* @brief send a series of AT commands w/ a TX lock
*
* @param *iface: interface to use
* @param *handler: command handler to use
@ -189,6 +189,23 @@ int modem_cmd_handler_setup_cmds(struct modem_iface *iface,
struct setup_cmd *cmds, size_t cmds_len,
struct k_sem *sem, k_timeout_t timeout);
/**
* @brief send a series of AT commands w/o locking TX
*
* @param *iface: interface to use
* @param *handler: command handler to use
* @param *cmds: array of setup commands to send
* @param cmds_len: size of the setup command array
* @param *sem: wait for response semaphore
* @param timeout: timeout of command
*
* @retval 0 if ok, < 0 if error.
*/
int modem_cmd_handler_setup_cmds_nolock(struct modem_iface *iface,
struct modem_cmd_handler *handler,
struct setup_cmd *cmds, size_t cmds_len,
struct k_sem *sem, k_timeout_t timeout);
/**
* @brief Init command handler
*
@ -200,6 +217,25 @@ int modem_cmd_handler_setup_cmds(struct modem_iface *iface,
int modem_cmd_handler_init(struct modem_cmd_handler *handler,
struct modem_cmd_handler_data *data);
/**
* @brief Lock the modem for sending cmds
*
* This is semaphore-based rather than mutex based, which means there's no
* requirements of thread ownership for the user. These functions are useful
* when one needs to prevent threads from sending UART data to the modem for an
* extended period of time (for example during modem reset).
*
* @param *handler: command handler to lock
* @param lock: set true to lock, false to unlock
* @param timeout: give up after timeout
*
* @retval 0 if ok, < 0 if error.
*/
int modem_cmd_handler_tx_lock(struct modem_cmd_handler *handler,
k_timeout_t timeout);
void modem_cmd_handler_tx_unlock(struct modem_cmd_handler *handler);
#ifdef __cplusplus
}
#endif