1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00

drivers/at: Add at_urc_isr module to process URCs upon arrival

This commit is contained in:
Leandro Lanzieri 2020-06-22 10:04:09 +02:00
parent 028c0d4b3c
commit 955efd85ff
No known key found for this signature in database
GPG Key ID: 13559905E2EBEAA5
5 changed files with 128 additions and 12 deletions

View File

@ -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_<priority> module
USEMODULE += $(_AT_ISR_MODULE:at_urc_isr_%=event_thread_%)
USEMODULE += at_urc
USEMODULE += at_urc_isr
endif
endif
ifneq (,$(filter at24c%,$(USEMODULE)))

View File

@ -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';
}

View File

@ -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_<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
@ -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;

View File

@ -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

View File

@ -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