drivers: modem: add modem_cmd_send_ext()

There are currently modem_cmd_send() and modem_cmd_send_nolock()
functions, each with slightly different behavior regarding acquiring (or
not) sem_tx_lock. Introduce a generic function that will allow caller to
select behavior using flags.

While at it, add possibility to disable setting and unsetting command
handlers. This will be useful in situations when there are multiple
replies expected one after the other coming as a response to single
command. This is the case for example with ESP-AT driver, which expects
following data as response to AT+CIPSEND command:

  OK
  >

where 'OK' is handled by static CMD_RESP (so releasing response
semaphore right away), while '>' is handled by dynamic
CMD_HANDLER (which is releasing another semaphore). Keeping command
handlers in place allows to receive '>' without race condition because
of small period of time where command handlers are not set.

Convert modem_cmd_send_nolock() and modem_cmd_send() to static inline
functions, as they are just a specific invocation of
modem_cmd_send_ext() function.

Signed-off-by: Marcin Niestroj <m.niestroj@grinn-global.com>
This commit is contained in:
Marcin Niestroj 2021-07-02 16:38:28 +02:00 committed by Christopher Friedt
commit 1a4cb7e0e3
2 changed files with 66 additions and 46 deletions

View file

@ -467,12 +467,11 @@ int modem_cmd_handler_update_cmds(struct modem_cmd_handler_data *data,
return 0;
}
static int _modem_cmd_send(struct modem_iface *iface,
struct modem_cmd_handler *handler,
const struct modem_cmd *handler_cmds,
size_t handler_cmds_len,
const uint8_t *buf, struct k_sem *sem,
k_timeout_t timeout, bool no_tx_lock)
int modem_cmd_send_ext(struct modem_iface *iface,
struct modem_cmd_handler *handler,
const struct modem_cmd *handler_cmds,
size_t handler_cmds_len, const uint8_t *buf,
struct k_sem *sem, k_timeout_t timeout, int flags)
{
struct modem_cmd_handler_data *data;
int ret;
@ -490,14 +489,16 @@ static int _modem_cmd_send(struct modem_iface *iface,
}
data = (struct modem_cmd_handler_data *)(handler->cmd_handler_data);
if (!no_tx_lock) {
if (!(flags & MODEM_NO_TX_LOCK)) {
k_sem_take(&data->sem_tx_lock, K_FOREVER);
}
ret = modem_cmd_handler_update_cmds(data, handler_cmds,
handler_cmds_len, true);
if (ret < 0) {
goto unlock_tx_lock;
if (!(flags & MODEM_NO_SET_CMDS)) {
ret = modem_cmd_handler_update_cmds(data, handler_cmds,
handler_cmds_len, true);
if (ret < 0) {
goto unlock_tx_lock;
}
}
#if defined(CONFIG_MODEM_CONTEXT_VERBOSE_DEBUG)
@ -531,38 +532,19 @@ static int _modem_cmd_send(struct modem_iface *iface,
}
}
/* unset handlers and ignore any errors */
(void)modem_cmd_handler_update_cmds(data, NULL, 0U, false);
if (!(flags & MODEM_NO_UNSET_CMDS)) {
/* unset handlers and ignore any errors */
(void)modem_cmd_handler_update_cmds(data, NULL, 0U, false);
}
unlock_tx_lock:
if (!no_tx_lock) {
if (!(flags & MODEM_NO_TX_LOCK)) {
k_sem_give(&data->sem_tx_lock);
}
return ret;
}
int modem_cmd_send_nolock(struct modem_iface *iface,
struct modem_cmd_handler *handler,
const struct modem_cmd *handler_cmds,
size_t handler_cmds_len,
const uint8_t *buf, struct k_sem *sem,
k_timeout_t timeout)
{
return _modem_cmd_send(iface, handler, handler_cmds, handler_cmds_len,
buf, sem, timeout, true);
}
int modem_cmd_send(struct modem_iface *iface,
struct modem_cmd_handler *handler,
const struct modem_cmd *handler_cmds,
size_t handler_cmds_len, const uint8_t *buf,
struct k_sem *sem, k_timeout_t timeout)
{
return _modem_cmd_send(iface, handler, handler_cmds, handler_cmds_len,
buf, sem, timeout, false);
}
/* run a set of AT commands */
int modem_cmd_handler_setup_cmds(struct modem_iface *iface,
struct modem_cmd_handler *handler,

View file

@ -62,6 +62,13 @@ static int name_(struct modem_cmd_handler_data *data, uint16_t len, \
#define CMD_HANDLER 2
#define CMD_MAX 3
/*
* Flags for modem_send_cmd_ext.
*/
#define MODEM_NO_TX_LOCK BIT(0)
#define MODEM_NO_SET_CMDS BIT(1)
#define MODEM_NO_UNSET_CMDS BIT(2)
struct modem_cmd_handler_data;
struct modem_cmd {
@ -148,6 +155,28 @@ int modem_cmd_handler_update_cmds(struct modem_cmd_handler_data *data,
size_t handler_cmds_len,
bool reset_error_flag);
/**
* @brief send AT command to interface with behavior defined by flags
*
* This function is similar to @ref modem_cmd_send, but it allows to choose a
* specific behavior regarding acquiring tx_lock, setting and unsetting
* @a handler_cmds.
*
* @param *iface: interface to use
* @param *handler: command handler to use
* @param *buf: NULL terminated send buffer
* @param *sem: wait for response semaphore
* @param timeout: timeout of command
* @param flags: flags which influence behavior of command sending
*
* @retval 0 if ok, < 0 if error.
*/
int modem_cmd_send_ext(struct modem_iface *iface,
struct modem_cmd_handler *handler,
const struct modem_cmd *handler_cmds,
size_t handler_cmds_len, const uint8_t *buf,
struct k_sem *sem, k_timeout_t timeout, int flags);
/**
* @brief send AT command to interface w/o locking TX
*
@ -159,12 +188,17 @@ int modem_cmd_handler_update_cmds(struct modem_cmd_handler_data *data,
*
* @retval 0 if ok, < 0 if error.
*/
int modem_cmd_send_nolock(struct modem_iface *iface,
struct modem_cmd_handler *handler,
const struct modem_cmd *handler_cmds,
size_t handler_cmds_len,
const uint8_t *buf, struct k_sem *sem,
k_timeout_t timeout);
static inline int modem_cmd_send_nolock(struct modem_iface *iface,
struct modem_cmd_handler *handler,
const struct modem_cmd *handler_cmds,
size_t handler_cmds_len,
const uint8_t *buf, struct k_sem *sem,
k_timeout_t timeout)
{
return modem_cmd_send_ext(iface, handler, handler_cmds,
handler_cmds_len, buf, sem, timeout,
MODEM_NO_TX_LOCK);
}
/**
* @brief send AT command to interface w/ a TX lock
@ -177,11 +211,15 @@ int modem_cmd_send_nolock(struct modem_iface *iface,
*
* @retval 0 if ok, < 0 if error.
*/
int modem_cmd_send(struct modem_iface *iface,
struct modem_cmd_handler *handler,
const struct modem_cmd *handler_cmds,
size_t handler_cmds_len, const uint8_t *buf,
struct k_sem *sem, k_timeout_t timeout);
static inline int modem_cmd_send(struct modem_iface *iface,
struct modem_cmd_handler *handler,
const struct modem_cmd *handler_cmds,
size_t handler_cmds_len, const uint8_t *buf,
struct k_sem *sem, k_timeout_t timeout)
{
return modem_cmd_send_ext(iface, handler, handler_cmds,
handler_cmds_len, buf, sem, timeout, 0);
}
/**
* @brief send a series of AT commands w/ a TX lock