drivers: modem: Add support for commands that don't have a line ending

Some commands need to be processed before a "\r\n" is available and
there might also be commands that have "\r\n" as data but doesn't mean
the end of the command.

To solve this a MODEM_CMD_DIRECT has been added. cmd_handler_process()
will look for matching direct commands before checking if a whole line
is available for matching the normal commands.

A direct command can return either -EAGAIN, meaning that more data is
needed or it will return the number of bytes to skip forward, ie the
length of the command that was handled.

Signed-off-by: Tobias Svehagen <tobias.svehagen@gmail.com>
This commit is contained in:
Tobias Svehagen 2019-12-17 15:55:43 +01:00 committed by Jukka Rissanen
commit 990ab00e30
2 changed files with 73 additions and 0 deletions

View file

@ -70,6 +70,30 @@ static u16_t findcrlf(struct modem_cmd_handler_data *data,
return 0; return 0;
} }
static bool starts_with(struct net_buf *buf, const char *str)
{
int pos = 0;
while (buf && buf->len && *str) {
if (*(buf->data + pos) == *str) {
str++;
pos++;
if (pos >= buf->len) {
buf = buf->frags;
pos = 0;
}
} else {
return false;
}
}
if (*str == 0) {
return true;
}
return false;
}
/* /*
* Cmd Handler Functions * Cmd Handler Functions
*/ */
@ -208,6 +232,29 @@ static struct modem_cmd *find_cmd_match(struct modem_cmd_handler_data *data)
return NULL; return NULL;
} }
static struct modem_cmd *find_cmd_direct_match(
struct modem_cmd_handler_data *data)
{
int j, i;
for (j = 0; j < ARRAY_SIZE(data->cmds); j++) {
if (!data->cmds[j] || data->cmds_len[j] == 0U) {
continue;
}
for (i = 0; i < data->cmds_len[j]; i++) {
/* match start of cmd */
if (data->cmds[j][i].direct &&
(data->cmds[j][i].cmd[0] == '\0' ||
starts_with(data->rx_buf, data->cmds[j][i].cmd))) {
return &data->cmds[j][i];
}
}
}
return NULL;
}
static void cmd_handler_process(struct modem_cmd_handler *cmd_handler, static void cmd_handler_process(struct modem_cmd_handler *cmd_handler,
struct modem_iface *iface) struct modem_iface *iface)
{ {
@ -263,6 +310,19 @@ static void cmd_handler_process(struct modem_cmd_handler *cmd_handler,
break; break;
} }
cmd = find_cmd_direct_match(data);
if (cmd && cmd->func) {
ret = cmd->func(data, cmd->cmd_len, NULL, 0);
if (ret == -EAGAIN) {
/* Wait for more data */
break;
} else if (ret > 0) {
data->rx_buf = net_buf_skip(data->rx_buf, ret);
}
continue;
}
frag = NULL; frag = NULL;
/* locate next CR/LF */ /* locate next CR/LF */
len = findcrlf(data, &frag, &offset); len = findcrlf(data, &frag, &offset);

View file

@ -31,6 +31,18 @@ static int name_(struct modem_cmd_handler_data *data, u16_t len, \
.func = func_cb_, \ .func = func_cb_, \
.arg_count = acount_, \ .arg_count = acount_, \
.delim = adelim_, \ .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 = (u16_t)sizeof(cmd_)-1, \
.func = func_cb_, \
.arg_count = 0, \
.delim = "", \
.direct = true, \
} }
#define CMD_RESP 0 #define CMD_RESP 0
@ -47,6 +59,7 @@ struct modem_cmd {
const char *delim; const char *delim;
u16_t cmd_len; u16_t cmd_len;
u16_t arg_count; u16_t arg_count;
bool direct;
}; };
#define SETUP_CMD(cmd_send_, match_cmd_, func_cb_, num_param_, delim_) { \ #define SETUP_CMD(cmd_send_, match_cmd_, func_cb_, num_param_, delim_) { \