So far a dedicated buffer was used for data read from modem
interface. New net_bufs were allocated and filled later, which means
that data was lost when no more net_bufs were available in the pool.
Prevent data loss by allocating net_buf before attempting any read on
modem interface. Process incoming data in a loop as long as reading from
interface results in new data. Also remove dedicated buffer
(data->read_buf) and directly fill net_buf content instead. As a side
effect there are less memory copy operations and RAM usage is reduced.
Pre-allocated net_buf is now always appended to data->rx_buf. When there
was no (more) data read from interface to such net_buf, then this empty
net_buf will be on the end of data->rx_buf fragment list. Update
skipcrlf() and findcrlf() implementations to explicitly check for each
net_buf length, instead of blindly assuming them to have at least single
byte.
Signed-off-by: Marcin Niestroj <m.niestroj@grinn-global.com>
cmd_handler_process() does two major things:
- reads data from modem interface and fills data->rx_buf,
- processes data in data->rx_buf.
Split implementation accordingly to two separate functions, which
improves readability (less automatic variables to follow at once) and
simplifies refactoring of each action.
No functional change was intended in this commit.
Signed-off-by: Marcin Niestroj <m.niestroj@grinn-global.com>
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>
These changes enable applications to restart the networking stack which
was previously not possible without rebooting the device. This was a
major show-stopper because it made power management impossible, and
furthermore made it impossible to recover from a bad modem state without
rebooting.
This has been verified to work on a SIMCOM7600E modem, both with and
without CONFIG_GSM_MUX enabled.
Signed-off-by: Benjamin Lindqvist <benjamin.lindqvist@endian.se>
The char pointer that is logged could get scoped out and so should be
strduped before logging.
Signed-off-by: Benjamin Lindqvist <benjamin.lindqvist@endian.se>
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>
User is currently able to enable verbose packet debugging for
received packets. This commit enables the same for sent packets.
Signed-off-by: Jukka Rissanen <jukka.rissanen@linux.intel.com>
Some modem commands can determine if they have enough data pulled from
the modem to continue or not. Let's allow those functions to return
EAGAIN which means there's more data needed from the modem.
Signed-off-by: Michael Scott <mike@foundries.io>
Modem commands are setup with arg_count to denote the number of params
to parse before returning. Let's honor that setting and return once
we've parse them.
This fixes a run-on bug where the parser would find as many of the
parameters via the supplied delimiter as it could.
Signed-off-by: Michael Scott <mike@foundries.io>
For parsing purposes we need to add a NUL to the end of match_buf.
When there is no CR/LF in the incoming rx bufs then we fill match_buf
to its max size. This ended up with an off by one error which was
overflowing match_buf into the following data.
To account for this, let's fill the buffer to size - 1 so that we
leave room for the NUL at the end and stop corrupting data.
Signed-off-by: Michael Scott <mike@foundries.io>
- rename buf_len to match_len for clarity
- pass in modem_cmd_handler_data instead of buffer pointer directly
- buffer adjustments for the command length are kept inside
parse_params()
Signed-off-by: Michael Scott <mike@foundries.io>
This is a generic command handler implementation which uses the
supplied modem interface to process incoming data and hand it
back to the modem driver via callbacks defined for:
- modem responses
- unsolicited messages
- specified handlers for current operation
The individual modem drivers define functions as command handlers
via the MODEM_CMD_DEFINE() macro.
To use these handlers, a modem operation defines a series of
modem_cmd structures and passes them to the modem_cmd_send()
function. The modem_cmd includes data for:
- a matching string for when to execute the handler
- # of parameters to parse after the matching string
- delimeters for the parameters
Example modem driver setup code looks like this:
/* create modem context object */
static struct modem_context mctx;
/* net_buf receive pool */
NET_BUF_POOL_DEFINE(mdm_recv_pool, MDM_RECV_MAX_BUF,
MDM_RECV_BUF_SIZE, 0, NULL);
/* modem cmds */
static struct modem_cmd_handler_data cmd_handler_data;
static u8_t cmd_read_buf[MDM_RECV_BUF_SIZE];
static u8_t cmd_match_buf[MDM_RECV_BUF_SIZE];
/* modem response handlers */
static struct modem_cmd response_cmds[] = {
MODEM_CMD("OK", on_cmd_ok, 0U, ""),
MODEM_CMD("ERROR", on_cmd_error, 0U, ""),
MODEM_CMD("+CME ERROR: ", on_cmd_exterror, 1U, ""),
};
/* unsolicited handlers */
static struct modem_cmd unsol_cmds[] = {
MODEM_CMD("+UUSOCL: ", on_cmd_socknotifyclose, 1U, ""),
MODEM_CMD("+UUSORD: ", on_cmd_socknotifydata, 2U, ","),
MODEM_CMD("+UUSORF: ", on_cmd_socknotifydata, 2U, ","),
MODEM_CMD("+CREG: ", on_cmd_socknotifycreg, 1U, ""),
};
/* setup cmd handler data */
cmd_handler_data.cmds[CMD_RESP] = response_cmds;
cmd_handler_data.cmds_len[CMD_RESP] = ARRAY_SIZE(response_cmds);
cmd_handler_data.cmds[CMD_UNSOL] = unsol_cmds;
cmd_handler_data.cmds_len[CMD_UNSOL] = ARRAY_SIZE(unsol_cmds);
cmd_handler_data.read_buf = &cmd_read_buf[0];
cmd_handler_data.read_buf_len = sizeof(cmd_read_buf);
cmd_handler_data.match_buf = &cmd_match_buf[0];
cmd_handler_data.match_buf_len = sizeof(cmd_match_buf);
cmd_handler_data.buf_pool = &mdm_recv_pool;
cmd_handler_data.alloc_timeout = BUF_ALLOC_TIMEOUT;
ret = modem_cmd_handler_init(&mctx.cmd_handler, &cmd_handler_data);
Signed-off-by: Michael Scott <mike@foundries.io>