Merge pull request #8542 from OTAkeys/pr/at_oob
drivers/at: at out-of-band data support for at commands parser
This commit is contained in:
commit
4ea93f3aea
@ -266,3 +266,52 @@ out:
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
#ifdef MODULE_AT_URC
|
||||
void at_add_urc(at_dev_t *dev, at_urc_t *urc)
|
||||
{
|
||||
assert(urc);
|
||||
assert(urc->code);
|
||||
assert(strlen(urc->code) != 0);
|
||||
assert(urc->cb);
|
||||
|
||||
clist_rpush(&dev->urc_list, &urc->list_node);
|
||||
}
|
||||
|
||||
void at_remove_urc(at_dev_t *dev, at_urc_t *urc)
|
||||
{
|
||||
clist_remove(&dev->urc_list, &urc->list_node);
|
||||
}
|
||||
|
||||
static int _check_urc(clist_node_t *node, void *arg)
|
||||
{
|
||||
const char *buf = arg;
|
||||
at_urc_t *urc = container_of(node, at_urc_t, list_node);
|
||||
|
||||
DEBUG("Trying to match with %s\n", urc->code);
|
||||
|
||||
if (strncmp(buf, urc->code, strlen(urc->code)) == 0) {
|
||||
urc->cb(urc->arg, buf);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void at_process_urc(at_dev_t *dev, uint32_t timeout)
|
||||
{
|
||||
char buf[AT_BUF_SIZE];
|
||||
|
||||
DEBUG("Processing URC (timeout=%" PRIu32 "us)\n", timeout);
|
||||
|
||||
ssize_t res;
|
||||
/* keep reading while received data are shorter than EOL */
|
||||
while ((res = at_readline(dev, buf, sizeof(buf), true, timeout)) <
|
||||
(ssize_t)sizeof(AT_RECV_EOL_1 AT_RECV_EOL_2) - 1) {
|
||||
if (res < 0) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
clist_foreach(&dev->urc_list, _check_urc, buf);
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -39,6 +39,7 @@
|
||||
|
||||
#include "isrpipe.h"
|
||||
#include "periph/uart.h"
|
||||
#include "clist.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@ -77,12 +78,41 @@ extern "C" {
|
||||
#define AT_RECV_ERROR "ERROR"
|
||||
#endif
|
||||
|
||||
#if defined(MODULE_AT_URC) || DOXYGEN
|
||||
#ifndef AT_BUF_SIZE
|
||||
/** Internal buffer size used to process unsolicited result code data */
|
||||
#define AT_BUF_SIZE (128)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Unsolicited result code callback
|
||||
*
|
||||
* @param[in] arg optional argument
|
||||
* @param[in] code urc string received from the device
|
||||
*/
|
||||
typedef void (*at_urc_cb_t)(void *arg, const char *code);
|
||||
|
||||
/**
|
||||
* @brief Unsolicited result code data structure
|
||||
*/
|
||||
typedef struct {
|
||||
clist_node_t list_node; /**< node list */
|
||||
at_urc_cb_t cb; /**< callback */
|
||||
const char *code; /**< URC string which must match */
|
||||
void *arg; /**< optional argument */
|
||||
} at_urc_t;
|
||||
|
||||
#endif /* MODULE_AT_URC */
|
||||
|
||||
/**
|
||||
* @brief AT device structure
|
||||
*/
|
||||
typedef struct {
|
||||
isrpipe_t isrpipe; /**< isrpipe used for getting data from uart */
|
||||
uart_t uart; /**< UART device where the AT device is attached */
|
||||
#ifdef MODULE_AT_URC
|
||||
clist_node_t urc_list; /**< list to keep track of all registered urc's */
|
||||
#endif
|
||||
} at_dev_t;
|
||||
|
||||
/**
|
||||
@ -226,6 +256,32 @@ ssize_t at_readline(at_dev_t *dev, char *resp_buf, size_t len, bool keep_eol, ui
|
||||
*/
|
||||
void at_drain(at_dev_t *dev);
|
||||
|
||||
#if defined(MODULE_AT_URC) || DOXYGEN
|
||||
/**
|
||||
* @brief Add a callback for an unsolicited response code
|
||||
*
|
||||
* @param[in] dev device to operate on
|
||||
* @param[in] urc unsolicited result code to register
|
||||
*/
|
||||
void at_add_urc(at_dev_t *dev, at_urc_t *urc);
|
||||
|
||||
/**
|
||||
* @brief Remove an unsolicited response code from the list
|
||||
*
|
||||
* @param[in] dev device to operate on
|
||||
* @param[in] urc unsolicited result code to remove
|
||||
*/
|
||||
void at_remove_urc(at_dev_t *dev, at_urc_t *urc);
|
||||
|
||||
/**
|
||||
* @brief Process out-of-band data received from the device
|
||||
*
|
||||
* @param[in] dev device to operate on
|
||||
* @param[in] timeout timeout (in usec)
|
||||
*/
|
||||
void at_process_urc(at_dev_t *dev, uint32_t timeout);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
PSEUDOMODULES += at_urc
|
||||
PSEUDOMODULES += auto_init_gnrc_rpl
|
||||
PSEUDOMODULES += can_mbox
|
||||
PSEUDOMODULES += can_pm
|
||||
|
||||
@ -4,5 +4,6 @@ BOARD_INSUFFICIENT_MEMORY += nucleo-f031k6
|
||||
|
||||
USEMODULE += shell
|
||||
USEMODULE += at
|
||||
USEMODULE += at_urc
|
||||
|
||||
include $(RIOTBASE)/Makefile.include
|
||||
|
||||
@ -22,6 +22,7 @@
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "at.h"
|
||||
#include "shell.h"
|
||||
@ -114,12 +115,101 @@ static int drain(int argc, char **argv)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef MODULE_AT_URC
|
||||
#ifndef MAX_URC_NB
|
||||
#define MAX_URC_NB 5
|
||||
#endif
|
||||
|
||||
#ifndef MAX_URC_LEN
|
||||
#define MAX_URC_LEN 32
|
||||
#endif
|
||||
|
||||
static at_urc_t urc_list[MAX_URC_NB];
|
||||
static char urc_str[MAX_URC_NB][MAX_URC_LEN];
|
||||
static bool urc_used[MAX_URC_NB];
|
||||
|
||||
static void _urc_cb(void *arg, const char *urc)
|
||||
{
|
||||
(void)arg;
|
||||
printf("urc received: %s\n", urc);
|
||||
}
|
||||
|
||||
static int add_urc(int argc, char **argv)
|
||||
{
|
||||
if (argc < 2) {
|
||||
printf("Usage: %s <urc>\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (strlen(argv[1]) > MAX_URC_LEN - 1) {
|
||||
puts("urc is too long");
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < MAX_URC_NB; i++) {
|
||||
if (!urc_used[i]) {
|
||||
strcpy(urc_str[i], argv[1]);
|
||||
urc_list[i].code = urc_str[i];
|
||||
urc_list[i].arg = NULL;
|
||||
urc_list[i].cb = _urc_cb;
|
||||
urc_used[i] = true;
|
||||
at_add_urc(&at_dev, &urc_list[i]);
|
||||
puts("urc registered");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
puts("Not enough memory, urc is not registered");
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int process_urc(int argc, char **argv)
|
||||
{
|
||||
if (argc < 2) {
|
||||
printf("Usage: %s <timeout>\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint32_t timeout = strtoul(argv[1], NULL, 0);
|
||||
at_process_urc(&at_dev, timeout);
|
||||
|
||||
puts("urc processed");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int remove_urc(int argc, char **argv)
|
||||
{
|
||||
if (argc < 2) {
|
||||
printf("Usage: %s <urc>\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < MAX_URC_NB; i++) {
|
||||
if (urc_used[i] && strcmp(urc_list[i].code, argv[1]) == 0) {
|
||||
at_remove_urc(&at_dev, &urc_list[i]);
|
||||
urc_used[i] = false;
|
||||
puts("urc removed");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
puts("urc not found");
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
static const shell_command_t shell_commands[] = {
|
||||
{ "init", "Initialize AT device", init },
|
||||
{ "send", "Send a command and wait response", send },
|
||||
{ "send_ok", "Send a command and wait OK", send_ok },
|
||||
{ "send_lines", "Send a command and wait lines", send_lines },
|
||||
{ "drain", "Drain AT device", drain },
|
||||
#ifdef MODULE_AT_URC
|
||||
{ "add_urc", "Register an URC", add_urc },
|
||||
{ "remove_urc", "De-register an URC", remove_urc },
|
||||
{ "process_urc", "Process the URCs", process_urc },
|
||||
#endif
|
||||
{ NULL, NULL, NULL },
|
||||
};
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user