From 9c9fad6da543d7c54adf27024f5f26bac9a83a45 Mon Sep 17 00:00:00 2001 From: Kaspar Schleiser Date: Tue, 13 Dec 2016 14:34:13 +0100 Subject: [PATCH 1/9] drivers: initial commit of generic AT parser module --- drivers/Makefile.dep | 5 ++ drivers/at/Makefile | 1 + drivers/at/at.c | 209 +++++++++++++++++++++++++++++++++++++++++++ drivers/include/at.h | 173 +++++++++++++++++++++++++++++++++++ 4 files changed, 388 insertions(+) create mode 100644 drivers/at/Makefile create mode 100644 drivers/at/at.c create mode 100644 drivers/include/at.h diff --git a/drivers/Makefile.dep b/drivers/Makefile.dep index 4a690c0246..fd399515e6 100644 --- a/drivers/Makefile.dep +++ b/drivers/Makefile.dep @@ -21,6 +21,11 @@ ifneq (,$(filter apa102,$(USEMODULE))) FEATURES_REQUIRED += periph_gpio endif +ifneq (,$(filter at,$(USEMODULE))) + USEMODULE += fmt + USEMODULE += xtimer +endif + ifneq (,$(filter at30tse75x,$(USEMODULE))) USEMODULE += xtimer FEATURES_REQUIRED += periph_i2c diff --git a/drivers/at/Makefile b/drivers/at/Makefile new file mode 100644 index 0000000000..48422e909a --- /dev/null +++ b/drivers/at/Makefile @@ -0,0 +1 @@ +include $(RIOTBASE)/Makefile.base diff --git a/drivers/at/at.c b/drivers/at/at.c new file mode 100644 index 0000000000..06df0261c9 --- /dev/null +++ b/drivers/at/at.c @@ -0,0 +1,209 @@ +/* + * Copyright (C) 2017 Kaspar Schleiser + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +#include +#include + +#include "at.h" +#include "fmt.h" +#include "isrpipe.h" +#include "periph/uart.h" +#include "xtimer.h" + +#define ENABLE_DEBUG (0) +#include "debug.h" + +#ifndef AT_PRINT_INCOMING +#define AT_PRINT_INCOMING (0) +#endif + +int at_dev_init(at_dev_t *dev, uart_t uart, uint32_t baudrate, char *buf, size_t bufsize) +{ + dev->uart = uart; + isrpipe_init(&dev->isrpipe, buf, bufsize); + uart_init(uart, baudrate, (uart_rx_cb_t) isrpipe_write_one, + &dev->isrpipe); + + return 0; +} + +int at_expect_bytes(at_dev_t *dev, const char *bytes, size_t len, uint32_t timeout) +{ + while (len) { + char c; + int res; + if ((res = isrpipe_read_timeout(&dev->isrpipe, &c, 1, timeout)) == 1) { + if (AT_PRINT_INCOMING) { + print(&c, 1); + } + if (!(c == *bytes++)) { + return -1; + } + len--; + } + else { + return res; + } + } + + return 0; +} + +int at_send_cmd(at_dev_t *dev, const char *command, uint32_t timeout) +{ + unsigned cmdlen = strlen(command); + + uart_write(dev->uart, (const uint8_t *)command, cmdlen); + uart_write(dev->uart, (const uint8_t *)"\n", 1); + + if (at_expect_bytes(dev, command, cmdlen, timeout)) { + return -1; + } + + if (at_expect_bytes(dev, "\r\n", 2, timeout)) { + return -2; + } + + return 0; +} + +void at_drain(at_dev_t *dev) +{ + char _tmp[16]; + int res; + + do { + res = isrpipe_read_timeout(&dev->isrpipe, _tmp, sizeof(_tmp), 10000U); + } while (res > 0); +} + +ssize_t at_send_cmd_get_resp(at_dev_t *dev, const char *command, char *resp_buf, size_t len, uint32_t timeout) +{ + ssize_t res = -1; + + at_drain(dev); + + res = at_send_cmd(dev, command, timeout); + if (res) { + goto out; + } + + res = at_readline(dev, resp_buf, len, timeout); + if (res == 0) { + /* skip possible empty line */ + res = at_readline(dev, resp_buf, len, timeout); + } + +out: + return res; +} + +ssize_t at_send_cmd_get_lines(at_dev_t *dev, const char *command, char *resp_buf, size_t len, uint32_t timeout) +{ + ssize_t res = -1; + size_t bytes_left = len - 1; + char *pos = resp_buf; + + memset(resp_buf, '\0', len); + + at_drain(dev); + + res = at_send_cmd(dev, command, timeout); + if (res) { + goto out; + } + + while(1) { + res = at_readline(dev, pos, bytes_left, timeout); + if (res == 0) { + continue; + } + else if (res > 0) { + bytes_left -= res; + if ((res == 2) && (strncmp(pos, "OK", 2) == 0)) { + res = len - bytes_left; + break; + } + else if ((res == 5) && (strncmp(pos, "ERROR", 5) == 0)) { + return -1; + } + else if (strncmp(pos, "+CME ERROR:", 11) == 0) { + return -1; + } + else { + pos += res; + if (bytes_left) { + *pos++ = '\n'; + bytes_left--; + } + else { + return -1; + } + } + } + else { + break; + } + } + +out: + return res; +} + +int at_send_cmd_wait_ok(at_dev_t *dev, const char *command, uint32_t timeout) +{ + int res; + char resp_buf[32]; + + res = at_send_cmd_get_resp(dev, command, resp_buf, sizeof(resp_buf), timeout); + if (res > 0) { + if (strcmp(resp_buf, "OK") == 0) { + res = 0; + } + else { + res = -1; + } + } + + return res; +} + +ssize_t at_readline(at_dev_t *dev, char *resp_buf, size_t len, uint32_t timeout) +{ + ssize_t res = -1; + char *resp_pos = resp_buf; + + memset(resp_buf, 0, len); + + while (len) { + int read_res; + if ((read_res = isrpipe_read_timeout(&dev->isrpipe, resp_pos, 1, timeout)) == 1) { + if (AT_PRINT_INCOMING) { + print(resp_pos, read_res); + } + if (*resp_pos == '\r') { + continue; + } + if (*resp_pos == '\n') { + *resp_pos = '\0'; + res = resp_pos - resp_buf; + goto out; + } + + resp_pos += read_res; + len -= read_res; + } + else if (read_res == -ETIMEDOUT) { + res = -ETIMEDOUT; + break; + } + } + +out: + return res; +} diff --git a/drivers/include/at.h b/drivers/include/at.h new file mode 100644 index 0000000000..1637893ca3 --- /dev/null +++ b/drivers/include/at.h @@ -0,0 +1,173 @@ +/* + * Copyright (C) 2017 Kaspar Schleiser + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @defgroup drivers_at AT (Hayes) command set library + * @ingroup drivers + * @brief AT (Hayes) command set library + * + * This module provides functions to interact with devices using AT commands. + * + * Most functions compare the bytes echoed by the device with what they + * intended to send, and bail out if there's no match. + * + * Furthermore, the library tries to copy with difficulties regarding different + * line endings. It usually sends "", but expects + * "\LF\CR" as echo. + * + * As a debugging aid, when compiled with "-DAT_PRINT_INCOMING=1", every input + * byte gets printed. + * @{ + * + * @file + * + * @brief AT (Hayes) library interface + * @author Kaspar Schleiser + */ + +#ifndef AT_H +#define AT_H + +#include + +#include "isrpipe.h" +#include "periph/uart.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @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 */ +} at_dev_t; + + +/** + * @brief Initialize AT device struct + * + * @param[in] dev struct to initialize + * @param[in] uart UART the device is connected to + * @param[in] baudrate baudrate of the device + * @param[in] buf input buffer + * @param[in] bufsize size of @p buf + * + * @returns 0 on success + * @returns <0 otherwise + */ +int at_dev_init(at_dev_t *dev, uart_t uart, uint32_t baudrate, char *buf, size_t bufsize); + +/** + * @brief simple command helper + * + * This function sends an AT command to the device and waits for "OK". + * + * @param[in] dev device to operate on + * @param[in] command command string to send + * @param[in] timeout timeout (in usec) + * + * @returns 0 when device answers "OK" + * @returns <0 otherwise + */ +int at_send_cmd_wait_ok(at_dev_t *dev, const char *command, uint32_t timeout); + +/** + * @brief send AT command, wait for response + * + * This function will send the supplied @p command, then wait and return one + * line of response. + * + * A possible empty line will be skipped. + * + * @param[in] dev device to operate on + * @param[in] command command to send + * @param[out] resp_buf buffer for storing response + * @param[in] len len of @p buffer + * @param[in] timeout timeout (in usec) + * + * @returns lenght of response on success + * @returns <0 on error + */ +ssize_t at_send_cmd_get_resp(at_dev_t *dev, const char *command, char *resp_buf, size_t len, uint32_t timeout); + +/** + * @brief send AT command, wait for multiline response + * + * This function will send the supplied @p command, then return all response + * lines until the device sends "OK". + * + * If a line starts with "ERROR" or "+CME ERROR:", or the buffer is full, the + * function returns -1. + * + * @param[in] dev device to operate on + * @param[in] command command to send + * @param[out] resp_buf buffer for storing response + * @param[in] len len of @p buffer + * @param[in] timeout timeout (in usec) + * + * @returns lenght of response on success + * @returns <0 on error + */ +ssize_t at_send_cmd_get_lines(at_dev_t *dev, const char *command, char *resp_buf, size_t len, uint32_t timeout); + +/** + * @brief Expect bytes from device + * + * @param[in] dev device to operate on + * @param[in] bytes buffer containing bytes to expect + * @param[in] len number of bytes to expect + * @param[in] timeout timeout (in usec) + * + * @returns 0 on success + * @returns <0 otherwise + */ +int at_expect_bytes(at_dev_t *dev, const char *bytes, size_t len, uint32_t timeout); + +/** + * @brief send command to device + * + * @param[in] dev device to operate on + * @param[in] command command to send + * @param[in] timeout timeout (in usec) + * + * @returns 0 on success + * @returns <0 otherwise + */ +int at_send_cmd(at_dev_t *dev, const char *command, uint32_t timeout); + +/** + * @brief read a line from device + * + * @param[in] dev device to operate on + * @param[in] resp_buf buffer to store line + * @param[in] len size of @p buffer + * @param[in] timeout timeout (in usec) + * + * @returns line length on success + * @returns <0 on error + */ +ssize_t at_readline(at_dev_t *dev, char *resp_buf, size_t len, uint32_t timeout); + +/** + * @brief drain device input buffer + * + * This function drains any possible bytes waiting in the device's input + * buffer. + * + * @param[in] dev device to operate on + */ +void at_drain(at_dev_t *dev); + +#ifdef __cplusplus +} +#endif + +#endif /* AT_H */ From ee29b76c89c01678bc5dda4da88e5d544e485a68 Mon Sep 17 00:00:00 2001 From: Vincent Dupont Date: Thu, 13 Jul 2017 18:43:42 +0200 Subject: [PATCH 2/9] drivers/at: make EOL char configurable --- drivers/at/at.c | 4 ++-- drivers/include/at.h | 5 +++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/at/at.c b/drivers/at/at.c index 06df0261c9..ff0e9e2583 100644 --- a/drivers/at/at.c +++ b/drivers/at/at.c @@ -59,13 +59,13 @@ int at_send_cmd(at_dev_t *dev, const char *command, uint32_t timeout) unsigned cmdlen = strlen(command); uart_write(dev->uart, (const uint8_t *)command, cmdlen); - uart_write(dev->uart, (const uint8_t *)"\n", 1); + uart_write(dev->uart, (const uint8_t *)AT_END_OF_LINE, sizeof(AT_END_OF_LINE) - 1); if (at_expect_bytes(dev, command, cmdlen, timeout)) { return -1; } - if (at_expect_bytes(dev, "\r\n", 2, timeout)) { + if (at_expect_bytes(dev, AT_END_OF_LINE "\r\n", sizeof(AT_END_OF_LINE) + 1, timeout)) { return -2; } diff --git a/drivers/include/at.h b/drivers/include/at.h index 1637893ca3..a073ef3dc6 100644 --- a/drivers/include/at.h +++ b/drivers/include/at.h @@ -42,6 +42,11 @@ extern "C" { #endif +#ifndef AT_END_OF_LINE +/** End of line character to send after the AT command */ +#define AT_END_OF_LINE "\r" +#endif + /** * @brief AT device structure */ From 7340e773286acc2067f749abe51c5bea801696d3 Mon Sep 17 00:00:00 2001 From: Vincent Dupont Date: Thu, 13 Jul 2017 18:44:28 +0200 Subject: [PATCH 3/9] drivers/at: add at_send_cmd_wait_prompt and at_send_bytes --- drivers/at/at.c | 29 +++++++++++++++++++++++++++++ drivers/include/at.h | 24 ++++++++++++++++++++++++ 2 files changed, 53 insertions(+) diff --git a/drivers/at/at.c b/drivers/at/at.c index ff0e9e2583..aff5757dca 100644 --- a/drivers/at/at.c +++ b/drivers/at/at.c @@ -54,6 +54,11 @@ int at_expect_bytes(at_dev_t *dev, const char *bytes, size_t len, uint32_t timeo return 0; } +void at_send_bytes(at_dev_t *dev, const char *bytes, size_t len) +{ + uart_write(dev->uart, (const uint8_t *)bytes, len); +} + int at_send_cmd(at_dev_t *dev, const char *command, uint32_t timeout) { unsigned cmdlen = strlen(command); @@ -155,6 +160,30 @@ out: return res; } +int at_send_cmd_wait_prompt(at_dev_t *dev, const char *command, uint32_t timeout) +{ + unsigned cmdlen = strlen(command); + + at_drain(dev); + + uart_write(dev->uart, (const uint8_t *)command, cmdlen); + uart_write(dev->uart, (const uint8_t *)AT_END_OF_LINE, sizeof(AT_END_OF_LINE) - 1); + + if (at_expect_bytes(dev, command, cmdlen, timeout)) { + return -1; + } + + if (at_expect_bytes(dev, AT_END_OF_LINE "\n", sizeof(AT_END_OF_LINE), timeout)) { + return -2; + } + + if (at_expect_bytes(dev, ">", 1, timeout)) { + return -3; + } + + return 0; +} + int at_send_cmd_wait_ok(at_dev_t *dev, const char *command, uint32_t timeout) { int res; diff --git a/drivers/include/at.h b/drivers/include/at.h index a073ef3dc6..37608bee9d 100644 --- a/drivers/include/at.h +++ b/drivers/include/at.h @@ -84,6 +84,21 @@ int at_dev_init(at_dev_t *dev, uart_t uart, uint32_t baudrate, char *buf, size_t */ int at_send_cmd_wait_ok(at_dev_t *dev, const char *command, uint32_t timeout); +/** + * @brief send AT command, wait for a prompt + * + * This function will send the supplied @p command, then wait for the prompt (>) + * character and return + * + * @param[in] dev device to operate on + * @param[in] command command string to send + * @param[in] timeout timeout (in usec) + * + * @return 0 when prompt is received + * @return <0 otherwise + */ +int at_send_cmd_wait_prompt(at_dev_t *dev, const char *command, uint32_t timeout); + /** * @brief send AT command, wait for response * @@ -136,6 +151,15 @@ ssize_t at_send_cmd_get_lines(at_dev_t *dev, const char *command, char *resp_buf */ int at_expect_bytes(at_dev_t *dev, const char *bytes, size_t len, uint32_t timeout); +/** + * @brief Send raw bytes to a device + * + * @param[in] dev device to operate on + * @param[in] bytes buffer containing bytes to send + * @param[in] len number of bytes to send + */ +void at_send_bytes(at_dev_t *dev, const char *bytes, size_t len); + /** * @brief send command to device * From 0199f36bb33ff3f083b35d9728f8e5a768d4c284 Mon Sep 17 00:00:00 2001 From: Kaspar Schleiser Date: Mon, 28 Aug 2017 11:01:07 +0200 Subject: [PATCH 4/9] drivers: at: many improvements --- drivers/Makefile.dep | 6 +++-- drivers/at/at.c | 52 ++++++++++++++++++++++++++------------------ drivers/include/at.h | 50 ++++++++++++++++++++++++------------------ 3 files changed, 64 insertions(+), 44 deletions(-) diff --git a/drivers/Makefile.dep b/drivers/Makefile.dep index fd399515e6..1621e5ec5d 100644 --- a/drivers/Makefile.dep +++ b/drivers/Makefile.dep @@ -22,8 +22,10 @@ ifneq (,$(filter apa102,$(USEMODULE))) endif ifneq (,$(filter at,$(USEMODULE))) - USEMODULE += fmt - USEMODULE += xtimer + FEATURES_REQUIRED += periph_uart + USEMODULE += fmt + USEMODULE += xtimer + USEMODULE += isrpipe endif ifneq (,$(filter at30tse75x,$(USEMODULE))) diff --git a/drivers/at/at.c b/drivers/at/at.c index aff5757dca..ec37d8e8bc 100644 --- a/drivers/at/at.c +++ b/drivers/at/at.c @@ -32,19 +32,18 @@ int at_dev_init(at_dev_t *dev, uart_t uart, uint32_t baudrate, char *buf, size_t return 0; } -int at_expect_bytes(at_dev_t *dev, const char *bytes, size_t len, uint32_t timeout) +int at_expect_bytes(at_dev_t *dev, const char *bytes, uint32_t timeout) { - while (len) { + while (*bytes) { char c; int res; if ((res = isrpipe_read_timeout(&dev->isrpipe, &c, 1, timeout)) == 1) { if (AT_PRINT_INCOMING) { print(&c, 1); } - if (!(c == *bytes++)) { + if (c != *bytes++) { return -1; } - len--; } else { return res; @@ -61,17 +60,19 @@ void at_send_bytes(at_dev_t *dev, const char *bytes, size_t len) int at_send_cmd(at_dev_t *dev, const char *command, uint32_t timeout) { - unsigned cmdlen = strlen(command); + size_t cmdlen = strlen(command); uart_write(dev->uart, (const uint8_t *)command, cmdlen); - uart_write(dev->uart, (const uint8_t *)AT_END_OF_LINE, sizeof(AT_END_OF_LINE) - 1); + uart_write(dev->uart, (const uint8_t *)AT_SEND_EOL, AT_SEND_EOL_LEN); - if (at_expect_bytes(dev, command, cmdlen, timeout)) { - return -1; - } + if (AT_SEND_ECHO) { + if (at_expect_bytes(dev, command, timeout)) { + return -1; + } - if (at_expect_bytes(dev, AT_END_OF_LINE "\r\n", sizeof(AT_END_OF_LINE) + 1, timeout)) { - return -2; + if (at_expect_bytes(dev, AT_SEND_EOL "\r\n", timeout)) { + return -2; + } } return 0; @@ -83,13 +84,15 @@ void at_drain(at_dev_t *dev) int res; do { + /* consider no character within 10ms "drained" */ res = isrpipe_read_timeout(&dev->isrpipe, _tmp, sizeof(_tmp), 10000U); } while (res > 0); } -ssize_t at_send_cmd_get_resp(at_dev_t *dev, const char *command, char *resp_buf, size_t len, uint32_t timeout) +ssize_t at_send_cmd_get_resp(at_dev_t *dev, const char *command, + char *resp_buf, size_t len, uint32_t timeout) { - ssize_t res = -1; + ssize_t res; at_drain(dev); @@ -108,9 +111,10 @@ out: return res; } -ssize_t at_send_cmd_get_lines(at_dev_t *dev, const char *command, char *resp_buf, size_t len, uint32_t timeout) +ssize_t at_send_cmd_get_lines(at_dev_t *dev, const char *command, + char *resp_buf, size_t len, uint32_t timeout) { - ssize_t res = -1; + ssize_t res; size_t bytes_left = len - 1; char *pos = resp_buf; @@ -123,7 +127,7 @@ ssize_t at_send_cmd_get_lines(at_dev_t *dev, const char *command, char *resp_buf goto out; } - while(1) { + while (1) { res = at_readline(dev, pos, bytes_left, timeout); if (res == 0) { continue; @@ -140,6 +144,9 @@ ssize_t at_send_cmd_get_lines(at_dev_t *dev, const char *command, char *resp_buf else if (strncmp(pos, "+CME ERROR:", 11) == 0) { return -1; } + else if (strncmp(pos, "+CMS ERROR:", 11) == 0) { + return -1; + } else { pos += res; if (bytes_left) { @@ -167,17 +174,17 @@ int at_send_cmd_wait_prompt(at_dev_t *dev, const char *command, uint32_t timeout at_drain(dev); uart_write(dev->uart, (const uint8_t *)command, cmdlen); - uart_write(dev->uart, (const uint8_t *)AT_END_OF_LINE, sizeof(AT_END_OF_LINE) - 1); + uart_write(dev->uart, (const uint8_t *)AT_SEND_EOL, AT_SEND_EOL_LEN); - if (at_expect_bytes(dev, command, cmdlen, timeout)) { + if (at_expect_bytes(dev, command, timeout)) { return -1; } - if (at_expect_bytes(dev, AT_END_OF_LINE "\n", sizeof(AT_END_OF_LINE), timeout)) { + if (at_expect_bytes(dev, AT_SEND_EOL "\n", timeout)) { return -2; } - if (at_expect_bytes(dev, ">", 1, timeout)) { + if (at_expect_bytes(dev, ">", timeout)) { return -3; } @@ -187,7 +194,7 @@ int at_send_cmd_wait_prompt(at_dev_t *dev, const char *command, uint32_t timeout int at_send_cmd_wait_ok(at_dev_t *dev, const char *command, uint32_t timeout) { int res; - char resp_buf[32]; + char resp_buf[64]; res = at_send_cmd_get_resp(dev, command, resp_buf, sizeof(resp_buf), timeout); if (res > 0) { @@ -234,5 +241,8 @@ ssize_t at_readline(at_dev_t *dev, char *resp_buf, size_t len, uint32_t timeout) } out: + if (res < 0) { + *resp_buf = '\0'; + } return res; } diff --git a/drivers/include/at.h b/drivers/include/at.h index 37608bee9d..53e2991ab3 100644 --- a/drivers/include/at.h +++ b/drivers/include/at.h @@ -16,7 +16,7 @@ * Most functions compare the bytes echoed by the device with what they * intended to send, and bail out if there's no match. * - * Furthermore, the library tries to copy with difficulties regarding different + * Furthermore, the library tries to cope with difficulties regarding different * line endings. It usually sends "", but expects * "\LF\CR" as echo. * @@ -34,6 +34,7 @@ #define AT_H #include +#include #include "isrpipe.h" #include "periph/uart.h" @@ -42,11 +43,19 @@ extern "C" { #endif -#ifndef AT_END_OF_LINE +#ifndef AT_SEND_EOL /** End of line character to send after the AT command */ -#define AT_END_OF_LINE "\r" +#define AT_SEND_EOL "\r" #endif +#ifndef AT_SEND_ECHO +/** Enable/disable the expected echo after an AT command is sent */ +#define AT_SEND_ECHO 1 +#endif + +/** Shortcut for getting send end of line length */ +#define AT_SEND_EOL_LEN (sizeof(AT_SEND_EOL) - 1) + /** * @brief AT device structure */ @@ -55,7 +64,6 @@ typedef struct { uart_t uart; /**< UART device where the AT device is attached */ } at_dev_t; - /** * @brief Initialize AT device struct * @@ -71,7 +79,7 @@ typedef struct { int at_dev_init(at_dev_t *dev, uart_t uart, uint32_t baudrate, char *buf, size_t bufsize); /** - * @brief simple command helper + * @brief Simple command helper * * This function sends an AT command to the device and waits for "OK". * @@ -85,10 +93,10 @@ int at_dev_init(at_dev_t *dev, uart_t uart, uint32_t baudrate, char *buf, size_t int at_send_cmd_wait_ok(at_dev_t *dev, const char *command, uint32_t timeout); /** - * @brief send AT command, wait for a prompt + * @brief Send AT command, wait for a prompt * - * This function will send the supplied @p command, then wait for the prompt (>) - * character and return + * This function sends the supplied @p command, then waits for the prompt (>) + * character and returns * * @param[in] dev device to operate on * @param[in] command command string to send @@ -100,9 +108,9 @@ int at_send_cmd_wait_ok(at_dev_t *dev, const char *command, uint32_t timeout); int at_send_cmd_wait_prompt(at_dev_t *dev, const char *command, uint32_t timeout); /** - * @brief send AT command, wait for response + * @brief Send AT command, wait for response * - * This function will send the supplied @p command, then wait and return one + * This function sends the supplied @p command, then waits and returns one * line of response. * * A possible empty line will be skipped. @@ -113,15 +121,15 @@ int at_send_cmd_wait_prompt(at_dev_t *dev, const char *command, uint32_t timeout * @param[in] len len of @p buffer * @param[in] timeout timeout (in usec) * - * @returns lenght of response on success + * @returns length of response on success * @returns <0 on error */ ssize_t at_send_cmd_get_resp(at_dev_t *dev, const char *command, char *resp_buf, size_t len, uint32_t timeout); /** - * @brief send AT command, wait for multiline response + * @brief Send AT command, wait for multiline response * - * This function will send the supplied @p command, then return all response + * This function sends the supplied @p command, then returns all response * lines until the device sends "OK". * * If a line starts with "ERROR" or "+CME ERROR:", or the buffer is full, the @@ -133,7 +141,7 @@ ssize_t at_send_cmd_get_resp(at_dev_t *dev, const char *command, char *resp_buf, * @param[in] len len of @p buffer * @param[in] timeout timeout (in usec) * - * @returns lenght of response on success + * @returns length of response on success * @returns <0 on error */ ssize_t at_send_cmd_get_lines(at_dev_t *dev, const char *command, char *resp_buf, size_t len, uint32_t timeout); @@ -142,17 +150,16 @@ ssize_t at_send_cmd_get_lines(at_dev_t *dev, const char *command, char *resp_buf * @brief Expect bytes from device * * @param[in] dev device to operate on - * @param[in] bytes buffer containing bytes to expect - * @param[in] len number of bytes to expect + * @param[in] bytes buffer containing bytes to expect (NULL-terminated) * @param[in] timeout timeout (in usec) * * @returns 0 on success * @returns <0 otherwise */ -int at_expect_bytes(at_dev_t *dev, const char *bytes, size_t len, uint32_t timeout); +int at_expect_bytes(at_dev_t *dev, const char *bytes, uint32_t timeout); /** - * @brief Send raw bytes to a device + * @brief Send raw bytes to a device * * @param[in] dev device to operate on * @param[in] bytes buffer containing bytes to send @@ -161,7 +168,7 @@ int at_expect_bytes(at_dev_t *dev, const char *bytes, size_t len, uint32_t timeo void at_send_bytes(at_dev_t *dev, const char *bytes, size_t len); /** - * @brief send command to device + * @brief Send command to device * * @param[in] dev device to operate on * @param[in] command command to send @@ -173,7 +180,7 @@ void at_send_bytes(at_dev_t *dev, const char *bytes, size_t len); int at_send_cmd(at_dev_t *dev, const char *command, uint32_t timeout); /** - * @brief read a line from device + * @brief Read a line from device * * @param[in] dev device to operate on * @param[in] resp_buf buffer to store line @@ -186,7 +193,7 @@ int at_send_cmd(at_dev_t *dev, const char *command, uint32_t timeout); ssize_t at_readline(at_dev_t *dev, char *resp_buf, size_t len, uint32_t timeout); /** - * @brief drain device input buffer + * @brief Drain device input buffer * * This function drains any possible bytes waiting in the device's input * buffer. @@ -200,3 +207,4 @@ void at_drain(at_dev_t *dev); #endif #endif /* AT_H */ +/** @} */ From e3f26b2c15e3d6e6b1171ba4a123da5672b5c333 Mon Sep 17 00:00:00 2001 From: Vincent Dupont Date: Tue, 22 May 2018 12:52:27 +0200 Subject: [PATCH 5/9] tests: add at parser basic test app --- tests/at/Makefile | 6 ++++ tests/at/main.c | 90 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 96 insertions(+) create mode 100644 tests/at/Makefile create mode 100644 tests/at/main.c diff --git a/tests/at/Makefile b/tests/at/Makefile new file mode 100644 index 0000000000..af90778ada --- /dev/null +++ b/tests/at/Makefile @@ -0,0 +1,6 @@ +include ../Makefile.tests_common + +USEMODULE += shell +USEMODULE += at + +include $(RIOTBASE)/Makefile.include diff --git a/tests/at/main.c b/tests/at/main.c new file mode 100644 index 0000000000..63ed1a9585 --- /dev/null +++ b/tests/at/main.c @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2018 OTA keys S.A. + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup tests + * @{ + * + * @file + * @brief AT module test application + * + * @author Vincent Dupont + * + * @} + */ + +#include "at.h" +#include "shell.h" +#include "timex.h" + +static at_dev_t at_dev; +static char buf[256]; +static char resp[1024]; + +#ifndef UART_AT +#define UART_AT UART_DEV(1) +#endif + +#ifndef BAUDRATE_AT +#define BAUDRATE_AT 115200 +#endif + +static int init(int argc, char **argv) +{ + (void)argc; + (void)argv; + + at_dev_init(&at_dev, UART_AT, BAUDRATE_AT, buf, sizeof(buf)); + + return 0; +} + +static int send(int argc, char **argv) +{ + if (argc < 2) { + puts("Please enter a command"); + return 1; + } + + if (at_send_cmd_get_resp(&at_dev, argv[1], resp, sizeof(resp), 10 * US_PER_SEC) > 0) { + puts("Response:"); + puts(resp); + } + else { + puts("Error"); + } + + return 0; +} + +static int drain(int argc, char **argv) +{ + (void)argc; + (void)argv; + + at_drain(&at_dev); + + return 0; +} + +static const shell_command_t shell_commands[] = { + { "init", "Initialize AT device", init }, + { "send", "Send a command and wait response", send }, + { "drain", "Drain AT device", drain }, + { NULL, NULL, NULL }, +}; + +int main(void) +{ + puts("AT command test app"); + + /* run the shell */ + char line_buf[SHELL_DEFAULT_BUFSIZE]; + shell_run(shell_commands, line_buf, SHELL_DEFAULT_BUFSIZE); + return 0; +} From 331f8531b4b34f63a30ac8b14cdc9b7ce3169e60 Mon Sep 17 00:00:00 2001 From: Kaspar Schleiser Date: Tue, 22 May 2018 13:22:55 +0200 Subject: [PATCH 6/9] tests/at: add missing stdio.h include --- tests/at/main.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/at/main.c b/tests/at/main.c index 63ed1a9585..78e7274a7b 100644 --- a/tests/at/main.c +++ b/tests/at/main.c @@ -18,6 +18,8 @@ * @} */ +#include + #include "at.h" #include "shell.h" #include "timex.h" From 0b603a11fd43f26b81b912e76268a6fb9ea81c98 Mon Sep 17 00:00:00 2001 From: Kaspar Schleiser Date: Tue, 22 May 2018 13:23:10 +0200 Subject: [PATCH 7/9] tests/at: add nucleo32-f031 to BOARD_INSUFFICIENT_MEMORY --- tests/at/Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/at/Makefile b/tests/at/Makefile index af90778ada..de4acd8fa8 100644 --- a/tests/at/Makefile +++ b/tests/at/Makefile @@ -1,5 +1,7 @@ include ../Makefile.tests_common +BOARD_INSUFFICIENT_MEMORY += nucleo32-f031 + USEMODULE += shell USEMODULE += at From 0c9c00f976437d1f8b8da95d89423b90ede87d6f Mon Sep 17 00:00:00 2001 From: Alexandre Abadie Date: Tue, 22 May 2018 15:49:26 +0200 Subject: [PATCH 8/9] tests/at: improve shell and add README --- tests/{at => driver_at}/Makefile | 0 tests/driver_at/README.md | 8 ++++++++ tests/{at => driver_at}/main.c | 34 ++++++++++++++++++-------------- 3 files changed, 27 insertions(+), 15 deletions(-) rename tests/{at => driver_at}/Makefile (100%) create mode 100644 tests/driver_at/README.md rename tests/{at => driver_at}/main.c (72%) diff --git a/tests/at/Makefile b/tests/driver_at/Makefile similarity index 100% rename from tests/at/Makefile rename to tests/driver_at/Makefile diff --git a/tests/driver_at/README.md b/tests/driver_at/README.md new file mode 100644 index 0000000000..0edc0e2d17 --- /dev/null +++ b/tests/driver_at/README.md @@ -0,0 +1,8 @@ +Expected result +=============== +You should be presented with a RIOT shell that privides commands to +initialize an UART and send AT commands to an AT module. + +Background +========== +Test for the AT command parser driver. diff --git a/tests/at/main.c b/tests/driver_at/main.c similarity index 72% rename from tests/at/main.c rename to tests/driver_at/main.c index 78e7274a7b..1307287f77 100644 --- a/tests/at/main.c +++ b/tests/driver_at/main.c @@ -1,5 +1,6 @@ /* * Copyright (C) 2018 OTA keys S.A. + * 2018 Inria * * This file is subject to the terms and conditions of the GNU Lesser * General Public License v2.1. See the file LICENSE in the top level @@ -14,34 +15,38 @@ * @brief AT module test application * * @author Vincent Dupont + * @author Alexandre Abadie * * @} */ #include +#include #include "at.h" #include "shell.h" #include "timex.h" +#include "periph/uart.h" + static at_dev_t at_dev; static char buf[256]; static char resp[1024]; -#ifndef UART_AT -#define UART_AT UART_DEV(1) -#endif - -#ifndef BAUDRATE_AT -#define BAUDRATE_AT 115200 -#endif - static int init(int argc, char **argv) { (void)argc; (void)argv; - at_dev_init(&at_dev, UART_AT, BAUDRATE_AT, buf, sizeof(buf)); + if (argc < 3) { + printf("Usage: %s \n", argv[0]); + return 1; + } + + uint8_t uart = atoi(argv[1]); + uint32_t baudrate = atoi(argv[2]); + + at_dev_init(&at_dev, UART_DEV(uart), baudrate, buf, sizeof(buf)); return 0; } @@ -49,18 +54,17 @@ static int init(int argc, char **argv) static int send(int argc, char **argv) { if (argc < 2) { - puts("Please enter a command"); + printf("Usage: %s \n", argv[0]); return 1; } - if (at_send_cmd_get_resp(&at_dev, argv[1], resp, sizeof(resp), 10 * US_PER_SEC) > 0) { - puts("Response:"); - puts(resp); - } - else { + if (at_send_cmd_get_resp(&at_dev, argv[1], resp, sizeof(resp), 10 * US_PER_SEC) < 0) { puts("Error"); + return 1; } + printf("Response: %s\n", resp); + return 0; } From 88a978adfb6ee34c04b622f73e7200426cf9044e Mon Sep 17 00:00:00 2001 From: Vincent Dupont Date: Wed, 23 May 2018 10:38:05 +0200 Subject: [PATCH 9/9] tests/driver_at: improve test app --- tests/driver_at/main.c | 42 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 40 insertions(+), 2 deletions(-) diff --git a/tests/driver_at/main.c b/tests/driver_at/main.c index 1307287f77..ff421d2d1e 100644 --- a/tests/driver_at/main.c +++ b/tests/driver_at/main.c @@ -58,12 +58,48 @@ static int send(int argc, char **argv) return 1; } - if (at_send_cmd_get_resp(&at_dev, argv[1], resp, sizeof(resp), 10 * US_PER_SEC) < 0) { + ssize_t len; + if ((len = at_send_cmd_get_resp(&at_dev, argv[1], resp, sizeof(resp), 10 * US_PER_SEC)) < 0) { puts("Error"); return 1; } - printf("Response: %s\n", resp); + printf("Response (len=%d): %s\n", (int)len, resp); + + return 0; +} + +static int send_ok(int argc, char **argv) +{ + if (argc < 2) { + printf("Usage: %s \n", argv[0]); + return 1; + } + + if (at_send_cmd_wait_ok(&at_dev, argv[1], 10 * US_PER_SEC) < 0) { + puts("Error"); + return 1; + } + + puts("OK"); + + return 0; +} + +static int send_lines(int argc, char **argv) +{ + if (argc < 2) { + printf("Usage: %s \n", argv[0]); + return 1; + } + + ssize_t len; + if ((len = at_send_cmd_get_lines(&at_dev, argv[1], resp, sizeof(resp), 10 * US_PER_SEC)) < 0) { + puts("Error"); + return 1; + } + + printf("Response (len=%d): %s\n", (int)len, resp); return 0; } @@ -81,6 +117,8 @@ static int drain(int argc, char **argv) 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 }, { NULL, NULL, NULL }, };