From 955efd85ff29d21dc9e09bd30f9261a95542c85c Mon Sep 17 00:00:00 2001 From: Leandro Lanzieri Date: Mon, 22 Jun 2020 10:04:09 +0200 Subject: [PATCH] drivers/at: Add at_urc_isr module to process URCs upon arrival --- drivers/Makefile.dep | 8 +++ drivers/at/at.c | 95 ++++++++++++++++++++++++++++++---- drivers/include/at.h | 28 ++++++++++ makefiles/pseudomodules.inc.mk | 4 ++ tests/driver_at/Makefile | 5 +- 5 files changed, 128 insertions(+), 12 deletions(-) diff --git a/drivers/Makefile.dep b/drivers/Makefile.dep index 5fb5a3e9fc..6b23272755 100644 --- a/drivers/Makefile.dep +++ b/drivers/Makefile.dep @@ -43,6 +43,14 @@ ifneq (,$(filter at,$(USEMODULE))) USEMODULE += fmt USEMODULE += isrpipe USEMODULE += isrpipe_read_timeout + + _AT_ISR_MODULE := $(filter at_urc_isr_%,$(USEMODULE)) + ifneq (,$(_AT_ISR_MODULE)) + # pull in the correspondant event_thread_ module + USEMODULE += $(_AT_ISR_MODULE:at_urc_isr_%=event_thread_%) + USEMODULE += at_urc + USEMODULE += at_urc_isr + endif endif ifneq (,$(filter at24c%,$(USEMODULE))) diff --git a/drivers/at/at.c b/drivers/at/at.c index 6aa24cb87d..6cc8b59af7 100644 --- a/drivers/at/at.c +++ b/drivers/at/at.c @@ -14,6 +14,7 @@ #include "isrpipe.h" #include "isrpipe/read_timeout.h" #include "periph/uart.h" +#include "event/thread.h" #define ENABLE_DEBUG (0) #include "debug.h" @@ -22,39 +23,79 @@ #define AT_PRINT_INCOMING (0) #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) { 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); 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 res = 0; + +#if IS_USED(MODULE_AT_URC_ISR) + dev->awaiting_response = true; +#endif + while (*bytes) { char c; - int res; if ((res = isrpipe_read_timeout(&dev->isrpipe, (uint8_t *)&c, 1, timeout)) == 1) { if (AT_PRINT_INCOMING) { print(&c, 1); } if (c != *bytes++) { - return -1; + res = -1; + goto out; } } 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) @@ -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; +#if IS_USED(MODULE_AT_URC_ISR) + dev->awaiting_response = true; +#endif + while (len) { int read_res; 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); } @@ -86,9 +135,13 @@ int at_recv_bytes_until_string(at_dev_t *dev, const char *string, { size_t len = 0; char *_string = (char *)string; + int res = 0; + +#if IS_USED(MODULE_AT_URC_ISR) + dev->awaiting_response = true; +#endif while (*_string && len < *bytes_len) { - int res; char c; if ((res = isrpipe_read_timeout(&dev->isrpipe, (uint8_t *)&c, 1, timeout)) == 1) { if (AT_PRINT_INCOMING) { @@ -101,12 +154,16 @@ int at_recv_bytes_until_string(at_dev_t *dev, const char *string, len++; } else { - *bytes_len = len; - return res; + break; } } *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) @@ -134,10 +191,18 @@ void at_drain(at_dev_t *dev) uint8_t _tmp[16]; int res; +#if IS_USED(MODULE_AT_URC_ISR) + dev->awaiting_response = true; +#endif + do { /* consider no character within 10ms "drained" */ res = isrpipe_read_timeout(&dev->isrpipe, _tmp, sizeof(_tmp), 10000U); } 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, @@ -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; char *resp_pos = resp_buf; +#if IS_USED(MODULE_AT_URC_ISR) + dev->awaiting_response = true; +#endif + memset(resp_buf, 0, 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: +#if IS_USED(MODULE_AT_URC_ISR) + dev->awaiting_response = false; +#endif + if (res < 0) { *resp_buf = '\0'; } diff --git a/drivers/include/at.h b/drivers/include/at.h index 820704dd62..eaba93e8ab 100644 --- a/drivers/include/at.h +++ b/drivers/include/at.h @@ -22,6 +22,28 @@ * * As a debugging aid, when compiled with "-DAT_PRINT_INCOMING=1", every input * 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_` 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 @@ -42,6 +64,8 @@ #include "clist.h" #include "kernel_defines.h" +#include "event.h" + #ifdef __cplusplus extern "C" { #endif @@ -169,6 +193,10 @@ typedef struct { 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 */ +#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 } at_dev_t; diff --git a/makefiles/pseudomodules.inc.mk b/makefiles/pseudomodules.inc.mk index e3c53334f5..59b6378472 100644 --- a/makefiles/pseudomodules.inc.mk +++ b/makefiles/pseudomodules.inc.mk @@ -1,4 +1,8 @@ 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 += base64url PSEUDOMODULES += can_mbox diff --git a/tests/driver_at/Makefile b/tests/driver_at/Makefile index e0076869d3..da018542d4 100644 --- a/tests/driver_at/Makefile +++ b/tests/driver_at/Makefile @@ -2,6 +2,9 @@ include ../Makefile.tests_common USEMODULE += shell 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