368 lines
10 KiB
C
368 lines
10 KiB
C
/** @file
|
|
* @brief Modem command handler header file.
|
|
*
|
|
* Text-based command handler implementation for modem context driver.
|
|
*/
|
|
|
|
/*
|
|
* Copyright (c) 2019 Foundries.io
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
#ifndef ZEPHYR_INCLUDE_DRIVERS_MODEM_MODEM_CMD_HANDLER_H_
|
|
#define ZEPHYR_INCLUDE_DRIVERS_MODEM_MODEM_CMD_HANDLER_H_
|
|
|
|
#include <zephyr/kernel.h>
|
|
|
|
#include "modem_context.h"
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
#define MODEM_CMD_DEFINE(name_) \
|
|
static int name_(struct modem_cmd_handler_data *data, uint16_t len, \
|
|
uint8_t **argv, uint16_t argc)
|
|
|
|
#define MODEM_CMD(cmd_, func_cb_, acount_, adelim_) { \
|
|
.cmd = cmd_, \
|
|
.cmd_len = (uint16_t)sizeof(cmd_)-1, \
|
|
.func = func_cb_, \
|
|
.arg_count_min = acount_, \
|
|
.arg_count_max = acount_, \
|
|
.delim = adelim_, \
|
|
.direct = false, \
|
|
}
|
|
|
|
#define MODEM_CMD_ARGS_MAX(cmd_, func_cb_, acount_, acountmax_, adelim_) { \
|
|
.cmd = cmd_, \
|
|
.cmd_len = (uint16_t)sizeof(cmd_)-1, \
|
|
.func = func_cb_, \
|
|
.arg_count_min = acount_, \
|
|
.arg_count_max = acountmax_, \
|
|
.delim = adelim_, \
|
|
.direct = false, \
|
|
}
|
|
|
|
#define MODEM_CMD_DIRECT_DEFINE(name_) MODEM_CMD_DEFINE(name_)
|
|
|
|
#define MODEM_CMD_DIRECT(cmd_, func_cb_) { \
|
|
.cmd = cmd_, \
|
|
.cmd_len = (uint16_t)sizeof(cmd_)-1, \
|
|
.func = func_cb_, \
|
|
.arg_count_min = 0, \
|
|
.arg_count_max = 0, \
|
|
.delim = "", \
|
|
.direct = true, \
|
|
}
|
|
|
|
#define CMD_RESP 0
|
|
#define CMD_UNSOL 1
|
|
#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 {
|
|
int (*func)(struct modem_cmd_handler_data *data, uint16_t len,
|
|
uint8_t **argv, uint16_t argc);
|
|
const char *cmd;
|
|
const char *delim;
|
|
uint16_t cmd_len;
|
|
uint16_t arg_count_min;
|
|
uint16_t arg_count_max;
|
|
bool direct;
|
|
};
|
|
|
|
#define SETUP_CMD(cmd_send_, match_cmd_, func_cb_, num_param_, delim_) { \
|
|
.send_cmd = cmd_send_, \
|
|
MODEM_CMD(match_cmd_, func_cb_, num_param_, delim_) \
|
|
}
|
|
|
|
#define SETUP_CMD_NOHANDLE(send_cmd_) \
|
|
SETUP_CMD(send_cmd_, NULL, NULL, 0U, NULL)
|
|
|
|
/* series of modem setup commands to run */
|
|
struct setup_cmd {
|
|
const char *send_cmd;
|
|
struct modem_cmd handle_cmd;
|
|
};
|
|
|
|
struct modem_cmd_handler_data {
|
|
const struct modem_cmd *cmds[CMD_MAX];
|
|
size_t cmds_len[CMD_MAX];
|
|
|
|
char *match_buf;
|
|
size_t match_buf_len;
|
|
|
|
int last_error;
|
|
|
|
const char *eol;
|
|
size_t eol_len;
|
|
|
|
/* rx net buffer */
|
|
struct net_buf *rx_buf;
|
|
|
|
/* allocation info */
|
|
struct net_buf_pool *buf_pool;
|
|
k_timeout_t alloc_timeout;
|
|
|
|
/* locks */
|
|
struct k_sem sem_tx_lock;
|
|
struct k_sem sem_parse_lock;
|
|
|
|
/* user data */
|
|
void *user_data;
|
|
};
|
|
|
|
/**
|
|
* @brief get the last error code
|
|
*
|
|
* @param data: command handler data reference
|
|
*
|
|
* @retval last handled error.
|
|
*/
|
|
int modem_cmd_handler_get_error(struct modem_cmd_handler_data *data);
|
|
|
|
/**
|
|
* @brief set the last error code
|
|
*
|
|
* @param data: command handler data reference
|
|
* @param error_code: error
|
|
*
|
|
* @retval 0 if ok, < 0 if error.
|
|
*/
|
|
int modem_cmd_handler_set_error(struct modem_cmd_handler_data *data,
|
|
int error_code);
|
|
|
|
/**
|
|
* @brief update the parser's handler commands
|
|
*
|
|
* @param data: handler data to use
|
|
* @param handler_cmds: commands to attach
|
|
* @param handler_cmds_len: size of commands array
|
|
* @param reset_error_flag: reset last error code
|
|
*
|
|
* @retval 0 if ok, < 0 if error.
|
|
*/
|
|
int modem_cmd_handler_update_cmds(struct modem_cmd_handler_data *data,
|
|
const struct modem_cmd *handler_cmds,
|
|
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 handler_cmds: commands to attach
|
|
* @param handler_cmds_len: size of commands array
|
|
* @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
|
|
*
|
|
* @param iface: interface to use
|
|
* @param handler: command handler to use
|
|
* @param handler_cmds: commands to attach
|
|
* @param handler_cmds_len: size of commands array
|
|
* @param buf: NULL terminated send buffer
|
|
* @param sem: wait for response semaphore
|
|
* @param timeout: timeout of command
|
|
*
|
|
* @retval 0 if ok, < 0 if error.
|
|
*/
|
|
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
|
|
*
|
|
* @param iface: interface to use
|
|
* @param handler: command handler to use
|
|
* @param handler_cmds: commands to attach
|
|
* @param handler_cmds_len: size of commands array
|
|
* @param buf: NULL terminated send buffer
|
|
* @param sem: wait for response semaphore
|
|
* @param timeout: timeout of command
|
|
*
|
|
* @retval 0 if ok, < 0 if error.
|
|
*/
|
|
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
|
|
*
|
|
* @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(struct modem_iface *iface,
|
|
struct modem_cmd_handler *handler,
|
|
const 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,
|
|
const struct setup_cmd *cmds,
|
|
size_t cmds_len, struct k_sem *sem,
|
|
k_timeout_t timeout);
|
|
|
|
/**
|
|
* @brief Modem command handler configuration
|
|
*
|
|
* @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,
|
|
const struct modem_cmd_handler_config *config);
|
|
|
|
/**
|
|
* @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. This function is 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 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);
|
|
|
|
/**
|
|
* @brief Unlock the modem for sending cmds
|
|
*
|
|
* @param handler: command handler to unlock
|
|
*/
|
|
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
|
|
}
|
|
#endif
|
|
|
|
#endif /* ZEPHYR_INCLUDE_DRIVERS_MODEM_MODEM_CMD_HANDLER_H_ */
|