drivers/at: Add at_urc_isr module to process URCs upon arrival
This commit is contained in:
parent
028c0d4b3c
commit
955efd85ff
@ -43,6 +43,14 @@ ifneq (,$(filter at,$(USEMODULE)))
|
|||||||
USEMODULE += fmt
|
USEMODULE += fmt
|
||||||
USEMODULE += isrpipe
|
USEMODULE += isrpipe
|
||||||
USEMODULE += isrpipe_read_timeout
|
USEMODULE += isrpipe_read_timeout
|
||||||
|
|
||||||
|
_AT_ISR_MODULE := $(filter at_urc_isr_%,$(USEMODULE))
|
||||||
|
ifneq (,$(_AT_ISR_MODULE))
|
||||||
|
# pull in the correspondant event_thread_<priority> module
|
||||||
|
USEMODULE += $(_AT_ISR_MODULE:at_urc_isr_%=event_thread_%)
|
||||||
|
USEMODULE += at_urc
|
||||||
|
USEMODULE += at_urc_isr
|
||||||
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifneq (,$(filter at24c%,$(USEMODULE)))
|
ifneq (,$(filter at24c%,$(USEMODULE)))
|
||||||
|
|||||||
@ -14,6 +14,7 @@
|
|||||||
#include "isrpipe.h"
|
#include "isrpipe.h"
|
||||||
#include "isrpipe/read_timeout.h"
|
#include "isrpipe/read_timeout.h"
|
||||||
#include "periph/uart.h"
|
#include "periph/uart.h"
|
||||||
|
#include "event/thread.h"
|
||||||
|
|
||||||
#define ENABLE_DEBUG (0)
|
#define ENABLE_DEBUG (0)
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
@ -22,39 +23,79 @@
|
|||||||
#define AT_PRINT_INCOMING (0)
|
#define AT_PRINT_INCOMING (0)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static void _isrpipe_write_one_wrapper(void *_isrpipe, uint8_t data)
|
#if defined(MODULE_AT_URC_ISR_LOW)
|
||||||
|
#define AT_EVENT_PRIO EVENT_PRIO_LOW
|
||||||
|
#elif defined(MODULE_AT_URC_ISR_MEDIUM)
|
||||||
|
#define AT_EVENT_PRIO EVENT_PRIO_MEDIUM
|
||||||
|
#elif defined(MODULE_AT_URC_ISR_HIGH)
|
||||||
|
#define AT_EVENT_PRIO EVENT_PRIO_HIGH
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(MODULE_AT_URC_ISR)
|
||||||
|
static void _event_process_urc(event_t *_event)
|
||||||
{
|
{
|
||||||
isrpipe_write_one(_isrpipe, data);
|
at_dev_t *dev = (at_dev_t *)container_of(_event, at_dev_t, event);
|
||||||
|
at_process_urc(dev, 1000);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static void _isrpipe_write_one_wrapper(void *_dev, uint8_t data)
|
||||||
|
{
|
||||||
|
at_dev_t *dev = (at_dev_t *) _dev;
|
||||||
|
isrpipe_write_one(&dev->isrpipe, data);
|
||||||
|
#if defined(MODULE_AT_URC_ISR)
|
||||||
|
if (data == AT_RECV_EOL_2[0] && !dev->awaiting_response) {
|
||||||
|
event_post(AT_EVENT_PRIO, &dev->event);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
int at_dev_init(at_dev_t *dev, uart_t uart, uint32_t baudrate, char *buf, size_t bufsize)
|
int at_dev_init(at_dev_t *dev, uart_t uart, uint32_t baudrate, char *buf, size_t bufsize)
|
||||||
{
|
{
|
||||||
dev->uart = uart;
|
dev->uart = uart;
|
||||||
|
|
||||||
|
#if IS_USED(MODULE_AT_URC_ISR)
|
||||||
|
dev->awaiting_response = false;
|
||||||
|
dev->event.handler = _event_process_urc;
|
||||||
|
#endif
|
||||||
|
|
||||||
isrpipe_init(&dev->isrpipe, (uint8_t *)buf, bufsize);
|
isrpipe_init(&dev->isrpipe, (uint8_t *)buf, bufsize);
|
||||||
|
|
||||||
return uart_init(uart, baudrate, _isrpipe_write_one_wrapper,
|
return uart_init(uart, baudrate, _isrpipe_write_one_wrapper,
|
||||||
&dev->isrpipe);
|
dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
int at_expect_bytes(at_dev_t *dev, const char *bytes, uint32_t timeout)
|
int at_expect_bytes(at_dev_t *dev, const char *bytes, uint32_t timeout)
|
||||||
{
|
{
|
||||||
|
int res = 0;
|
||||||
|
|
||||||
|
#if IS_USED(MODULE_AT_URC_ISR)
|
||||||
|
dev->awaiting_response = true;
|
||||||
|
#endif
|
||||||
|
|
||||||
while (*bytes) {
|
while (*bytes) {
|
||||||
char c;
|
char c;
|
||||||
int res;
|
|
||||||
if ((res = isrpipe_read_timeout(&dev->isrpipe, (uint8_t *)&c, 1, timeout)) == 1) {
|
if ((res = isrpipe_read_timeout(&dev->isrpipe, (uint8_t *)&c, 1, timeout)) == 1) {
|
||||||
if (AT_PRINT_INCOMING) {
|
if (AT_PRINT_INCOMING) {
|
||||||
print(&c, 1);
|
print(&c, 1);
|
||||||
}
|
}
|
||||||
if (c != *bytes++) {
|
if (c != *bytes++) {
|
||||||
return -1;
|
res = -1;
|
||||||
|
goto out;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return res;
|
goto out;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
res = 0;
|
||||||
|
|
||||||
return 0;
|
out:
|
||||||
|
#if IS_USED(MODULE_AT_URC_ISR)
|
||||||
|
dev->awaiting_response = false;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
void at_send_bytes(at_dev_t *dev, const char *bytes, size_t len)
|
void at_send_bytes(at_dev_t *dev, const char *bytes, size_t len)
|
||||||
@ -66,6 +107,10 @@ ssize_t at_recv_bytes(at_dev_t *dev, char *bytes, size_t len, uint32_t timeout)
|
|||||||
{
|
{
|
||||||
char *resp_pos = bytes;
|
char *resp_pos = bytes;
|
||||||
|
|
||||||
|
#if IS_USED(MODULE_AT_URC_ISR)
|
||||||
|
dev->awaiting_response = true;
|
||||||
|
#endif
|
||||||
|
|
||||||
while (len) {
|
while (len) {
|
||||||
int read_res;
|
int read_res;
|
||||||
if ((read_res = isrpipe_read_timeout(&dev->isrpipe, (uint8_t *)resp_pos,
|
if ((read_res = isrpipe_read_timeout(&dev->isrpipe, (uint8_t *)resp_pos,
|
||||||
@ -78,6 +123,10 @@ ssize_t at_recv_bytes(at_dev_t *dev, char *bytes, size_t len, uint32_t timeout)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if IS_USED(MODULE_AT_URC_ISR)
|
||||||
|
dev->awaiting_response = false;
|
||||||
|
#endif
|
||||||
|
|
||||||
return (resp_pos - bytes);
|
return (resp_pos - bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -86,9 +135,13 @@ int at_recv_bytes_until_string(at_dev_t *dev, const char *string,
|
|||||||
{
|
{
|
||||||
size_t len = 0;
|
size_t len = 0;
|
||||||
char *_string = (char *)string;
|
char *_string = (char *)string;
|
||||||
|
int res = 0;
|
||||||
|
|
||||||
|
#if IS_USED(MODULE_AT_URC_ISR)
|
||||||
|
dev->awaiting_response = true;
|
||||||
|
#endif
|
||||||
|
|
||||||
while (*_string && len < *bytes_len) {
|
while (*_string && len < *bytes_len) {
|
||||||
int res;
|
|
||||||
char c;
|
char c;
|
||||||
if ((res = isrpipe_read_timeout(&dev->isrpipe, (uint8_t *)&c, 1, timeout)) == 1) {
|
if ((res = isrpipe_read_timeout(&dev->isrpipe, (uint8_t *)&c, 1, timeout)) == 1) {
|
||||||
if (AT_PRINT_INCOMING) {
|
if (AT_PRINT_INCOMING) {
|
||||||
@ -101,12 +154,16 @@ int at_recv_bytes_until_string(at_dev_t *dev, const char *string,
|
|||||||
len++;
|
len++;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
*bytes_len = len;
|
break;
|
||||||
return res;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*bytes_len = len;
|
*bytes_len = len;
|
||||||
return 0;
|
|
||||||
|
#if IS_USED(MODULE_AT_URC_ISR)
|
||||||
|
dev->awaiting_response = false;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
int at_send_cmd(at_dev_t *dev, const char *command, uint32_t timeout)
|
int at_send_cmd(at_dev_t *dev, const char *command, uint32_t timeout)
|
||||||
@ -134,10 +191,18 @@ void at_drain(at_dev_t *dev)
|
|||||||
uint8_t _tmp[16];
|
uint8_t _tmp[16];
|
||||||
int res;
|
int res;
|
||||||
|
|
||||||
|
#if IS_USED(MODULE_AT_URC_ISR)
|
||||||
|
dev->awaiting_response = true;
|
||||||
|
#endif
|
||||||
|
|
||||||
do {
|
do {
|
||||||
/* consider no character within 10ms "drained" */
|
/* consider no character within 10ms "drained" */
|
||||||
res = isrpipe_read_timeout(&dev->isrpipe, _tmp, sizeof(_tmp), 10000U);
|
res = isrpipe_read_timeout(&dev->isrpipe, _tmp, sizeof(_tmp), 10000U);
|
||||||
} while (res > 0);
|
} while (res > 0);
|
||||||
|
|
||||||
|
#if IS_USED(MODULE_AT_URC_ISR)
|
||||||
|
dev->awaiting_response = false;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
ssize_t at_send_cmd_get_resp(at_dev_t *dev, const char *command,
|
ssize_t at_send_cmd_get_resp(at_dev_t *dev, const char *command,
|
||||||
@ -285,6 +350,10 @@ ssize_t at_readline(at_dev_t *dev, char *resp_buf, size_t len, bool keep_eol, ui
|
|||||||
ssize_t res = -1;
|
ssize_t res = -1;
|
||||||
char *resp_pos = resp_buf;
|
char *resp_pos = resp_buf;
|
||||||
|
|
||||||
|
#if IS_USED(MODULE_AT_URC_ISR)
|
||||||
|
dev->awaiting_response = true;
|
||||||
|
#endif
|
||||||
|
|
||||||
memset(resp_buf, 0, len);
|
memset(resp_buf, 0, len);
|
||||||
|
|
||||||
while (len) {
|
while (len) {
|
||||||
@ -315,6 +384,10 @@ ssize_t at_readline(at_dev_t *dev, char *resp_buf, size_t len, bool keep_eol, ui
|
|||||||
}
|
}
|
||||||
|
|
||||||
out:
|
out:
|
||||||
|
#if IS_USED(MODULE_AT_URC_ISR)
|
||||||
|
dev->awaiting_response = false;
|
||||||
|
#endif
|
||||||
|
|
||||||
if (res < 0) {
|
if (res < 0) {
|
||||||
*resp_buf = '\0';
|
*resp_buf = '\0';
|
||||||
}
|
}
|
||||||
|
|||||||
@ -22,6 +22,28 @@
|
|||||||
*
|
*
|
||||||
* As a debugging aid, when compiled with "-DAT_PRINT_INCOMING=1", every input
|
* As a debugging aid, when compiled with "-DAT_PRINT_INCOMING=1", every input
|
||||||
* byte gets printed.
|
* byte gets printed.
|
||||||
|
*
|
||||||
|
* ## Unsolicited Result Codes (URC) ##
|
||||||
|
* An unsolicited result code is a string message that is not triggered as a
|
||||||
|
* information text response to a previous AT command and can be output at any
|
||||||
|
* time to inform a specific event or status change.
|
||||||
|
*
|
||||||
|
* The module provides a basic URC handling by adding the `at_urc` module to the
|
||||||
|
* application. This allows to @ref at_add_urc "register" and
|
||||||
|
* @ref at_remove_urc "de-register" URC strings to check. Later,
|
||||||
|
* @ref at_process_urc can be called to check if any of the registered URCs have
|
||||||
|
* been detected. If a registered URC has been detected the correspondant
|
||||||
|
* @ref at_urc_t::cb "callback function" is called. The mode of operation
|
||||||
|
* requires that the user of the module processes periodically the URCs.
|
||||||
|
*
|
||||||
|
* Alternatively, one of the `at_urc_isr_<priority>` modules can be included.
|
||||||
|
* `priority` can be one of `low`, `medium` or `highest`, which correspond to
|
||||||
|
* the priority of the thread that processes the URCs. For more information on
|
||||||
|
* the priorities check the @ref sys_event module. This will extend the
|
||||||
|
* functionality of `at_urc` by processing the URCs when the @ref AT_RECV_EOL_2
|
||||||
|
* character is detected and there is no pending response. This works by posting
|
||||||
|
* an @ref sys_event "event" to an event thread that processes the URCs.
|
||||||
|
*
|
||||||
* @{
|
* @{
|
||||||
*
|
*
|
||||||
* @file
|
* @file
|
||||||
@ -42,6 +64,8 @@
|
|||||||
#include "clist.h"
|
#include "clist.h"
|
||||||
#include "kernel_defines.h"
|
#include "kernel_defines.h"
|
||||||
|
|
||||||
|
#include "event.h"
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
@ -169,6 +193,10 @@ typedef struct {
|
|||||||
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
|
#ifdef MODULE_AT_URC
|
||||||
clist_node_t urc_list; /**< list to keep track of all registered urc's */
|
clist_node_t urc_list; /**< list to keep track of all registered urc's */
|
||||||
|
#ifdef MODULE_AT_URC_ISR
|
||||||
|
bool awaiting_response; /**< indicates if the driver waits for a response */
|
||||||
|
event_t event; /**< event posted from ISR to process urc's */
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
} at_dev_t;
|
} at_dev_t;
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,8 @@
|
|||||||
PSEUDOMODULES += at_urc
|
PSEUDOMODULES += at_urc
|
||||||
|
PSEUDOMODULES += at_urc_isr
|
||||||
|
PSEUDOMODULES += at_urc_isr_low
|
||||||
|
PSEUDOMODULES += at_urc_isr_medium
|
||||||
|
PSEUDOMODULES += at_urc_isr_highest
|
||||||
PSEUDOMODULES += at24c%
|
PSEUDOMODULES += at24c%
|
||||||
PSEUDOMODULES += base64url
|
PSEUDOMODULES += base64url
|
||||||
PSEUDOMODULES += can_mbox
|
PSEUDOMODULES += can_mbox
|
||||||
|
|||||||
@ -2,6 +2,9 @@ include ../Makefile.tests_common
|
|||||||
|
|
||||||
USEMODULE += shell
|
USEMODULE += shell
|
||||||
USEMODULE += at
|
USEMODULE += at
|
||||||
USEMODULE += at_urc
|
USEMODULE += at_urc_isr_medium
|
||||||
|
|
||||||
|
# we are printing from the event thread, we need more stack
|
||||||
|
CFLAGS += -DEVENT_THREAD_MEDIUM_STACKSIZE=1024
|
||||||
|
|
||||||
include $(RIOTBASE)/Makefile.include
|
include $(RIOTBASE)/Makefile.include
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user