Skip to content
Snippets Groups Projects
Unverified Commit 4ea93f3a authored by Alexandre Abadie's avatar Alexandre Abadie Committed by GitHub
Browse files

Merge pull request #8542 from OTAkeys/pr/at_oob

drivers/at: at out-of-band data support for at commands parser
parents 4e9052e8 6aa2a55a
No related branches found
No related tags found
No related merge requests found
...@@ -266,3 +266,52 @@ out: ...@@ -266,3 +266,52 @@ out:
} }
return res; 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 @@ ...@@ -39,6 +39,7 @@
#include "isrpipe.h" #include "isrpipe.h"
#include "periph/uart.h" #include "periph/uart.h"
#include "clist.h"
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
...@@ -77,12 +78,41 @@ extern "C" { ...@@ -77,12 +78,41 @@ extern "C" {
#define AT_RECV_ERROR "ERROR" #define AT_RECV_ERROR "ERROR"
#endif #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 * @brief AT device structure
*/ */
typedef struct { typedef struct {
isrpipe_t isrpipe; /**< isrpipe used for getting data from uart */ isrpipe_t isrpipe; /**< isrpipe used for getting data from uart */
uart_t uart; /**< UART device where the AT device is attached */ 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; } 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 ...@@ -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); 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 #ifdef __cplusplus
} }
#endif #endif
......
PSEUDOMODULES += at_urc
PSEUDOMODULES += auto_init_gnrc_rpl PSEUDOMODULES += auto_init_gnrc_rpl
PSEUDOMODULES += can_mbox PSEUDOMODULES += can_mbox
PSEUDOMODULES += can_pm PSEUDOMODULES += can_pm
......
...@@ -4,5 +4,6 @@ BOARD_INSUFFICIENT_MEMORY += nucleo-f031k6 ...@@ -4,5 +4,6 @@ BOARD_INSUFFICIENT_MEMORY += nucleo-f031k6
USEMODULE += shell USEMODULE += shell
USEMODULE += at USEMODULE += at
USEMODULE += at_urc
include $(RIOTBASE)/Makefile.include include $(RIOTBASE)/Makefile.include
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h>
#include "at.h" #include "at.h"
#include "shell.h" #include "shell.h"
...@@ -114,12 +115,101 @@ static int drain(int argc, char **argv) ...@@ -114,12 +115,101 @@ static int drain(int argc, char **argv)
return 0; 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[] = { static const shell_command_t shell_commands[] = {
{ "init", "Initialize AT device", init }, { "init", "Initialize AT device", init },
{ "send", "Send a command and wait response", send }, { "send", "Send a command and wait response", send },
{ "send_ok", "Send a command and wait OK", send_ok }, { "send_ok", "Send a command and wait OK", send_ok },
{ "send_lines", "Send a command and wait lines", send_lines }, { "send_lines", "Send a command and wait lines", send_lines },
{ "drain", "Drain AT device", drain }, { "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 }, { NULL, NULL, NULL },
}; };
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment