Parser for AT commands and similar protocols
Fork of ATParser by
Revision 10:553f9ffaf657, committed 2015-07-26
- Comitter:
- sam_grove
- Date:
- Sun Jul 26 21:53:28 2015 +0000
- Parent:
- 9:9bcb87c27208
- Child:
- 11:fd406d4c4227
- Commit message:
- Small changes
Changed in this revision
--- a/ATParser.cpp Mon Jul 20 21:28:39 2015 +0000 +++ b/ATParser.cpp Sun Jul 26 21:53:28 2015 +0000 @@ -17,97 +17,102 @@ * Parser for the AT command syntax * */ - + #include "ATParser.h" - -// This can be defined to assist in debugging -#define AT_ECHO 1 +#include "mbed_debug.h" // getc/putc handling with timeouts -int ATParser::putc(char c) { +int ATParser::putc(char c) +{ Timer timer; timer.start(); - + while (true) { - if (_serial->writeable()) + if (_serial->writeable()) { return _serial->putc(c); - - if (timer.read_ms() > _timeout) + } + if (timer.read_ms() > _timeout) { return -1; + } } } -int ATParser::getc() { +int ATParser::getc() +{ Timer timer; timer.start(); - + while (true) { - if (_serial->readable()) + if (_serial->readable()) { return _serial->getc(); - - if (timer.read_ms() > _timeout) + } + if (timer.read_ms() > _timeout) { return -1; + } } } -void ATParser::flush() { - while (_serial->readable()) +void ATParser::flush() +{ + while (_serial->readable()) { _serial->getc(); + } } // read/write handling with timeouts -int ATParser::write(const char *data, int size) { - int i; - for (i = 0; i < size; i++) { - if (putc(data[i]) < 0) +int ATParser::write(const char *data, int size) +{ + int i = 0; + for ( ; i < size; i++) { + if (putc(data[i]) < 0) { return -1; + } } - return i; } -int ATParser::read(char *data, int size) { - int i; - for (i = 0; i < size; i++) { +int ATParser::read(char *data, int size) +{ + int i = 0; + for ( ; i < size; i++) { int c = getc(); - if (c < 0) + if (c < 0) { return -1; - + } data[i] = c; } - return i; } // printf/scanf handling -int ATParser::vprintf(const char *format, va_list args) { - if (vsprintf(_buffer, format, args) < 0) +int ATParser::vprintf(const char *format, va_list args) +{ + if (vsprintf(_buffer, format, args) < 0) { return false; - - int i; - for (i = 0; _buffer[i]; i++) { - if (putc(_buffer[i]) < 0) + } + int i = 0; + for ( ; _buffer[i]; i++) { + if (putc(_buffer[i]) < 0) { return -1; + } } - return i; } -int ATParser::vscanf(const char *format, va_list args) { +int ATParser::vscanf(const char *format, va_list args) +{ // Since format is const, we need to copy it into our buffer to // add the line's null terminator and clobber value-matches with asterisks. // // We just use the beginning of the buffer to avoid unnecessary allocations. int i = 0; int offset = 0; - + while (format[i]) { - if (format[i] == '%' && - format[i+1] != '%' && - format[i+1] != '*') { + if (format[i] == '%' && format[i+1] != '%' && format[i+1] != '*') { _buffer[offset++] = '%'; _buffer[offset++] = '*'; i++; @@ -115,40 +120,40 @@ _buffer[offset++] = format[i++]; } } - + // Scanf has very poor support for catching errors // fortunately, we can abuse the %n specifier to determine // if the entire string was matched. _buffer[offset++] = '%'; _buffer[offset++] = 'n'; _buffer[offset++] = 0; - + // To workaround scanf's lack of error reporting, we actually // make two passes. One checks the validity with the modified - // format string that only stores the matched characters (%n). + // format string that only stores the matched characters (%n). // The other reads in the actual matched values. // // We keep trying the match until we succeed or some other error // derails us. int j = 0; - + while (true) { // Ran out of space - if (j+1 >= _buffer_size - offset) + if (j+1 >= _buffer_size - offset) { return false; - + } // Recieve next character int c = getc(); - if (c < 0) + if (c < 0) { return -1; - + } _buffer[offset + j++] = c; _buffer[offset + j] = 0; - + // Check for match int count = -1; sscanf(_buffer+offset, _buffer, &count); - + // We only succeed if all characters in the response are matched if (count == j) { // Store the found results @@ -160,30 +165,31 @@ // Command parsing with line handling -bool ATParser::vsend(const char *command, va_list args) { +bool ATParser::vsend(const char *command, va_list args) +{ // Create and send command - if (vsprintf(_buffer, command, args) < 0) + if (vsprintf(_buffer, command, args) < 0) { return false; - + } for (int i = 0; _buffer[i]; i++) { - if (putc(_buffer[i]) < 0) + if (putc(_buffer[i]) < 0) { return false; + } } - + // Finish with newline for (int i = 0; _delimiter[i]; i++) { - if (putc(_delimiter[i]) < 0) + if (putc(_delimiter[i]) < 0) { return false; + } } - -#ifdef AT_ECHO - ::printf("AT> %s\r\n", _buffer); -#endif - + + debug_if(at_echo, "AT> %s\r\n", _buffer); return true; } -bool ATParser::vrecv(const char *response, va_list args) { +bool ATParser::vrecv(const char *response, va_list args) +{ // Iterate through each line in the expected response while (response[0]) { // Since response is const, we need to copy it into our buffer to @@ -192,14 +198,12 @@ // We just use the beginning of the buffer to avoid unnecessary allocations. int i = 0; int offset = 0; - + while (response[i]) { if (memcmp(&response[i+1-_delim_size], _delimiter, _delim_size) == 0) { i++; break; - } else if (response[i] == '%' && - response[i+1] != '%' && - response[i+1] != '*') { + } else if (response[i] == '%' && response[i+1] != '%' && response[i+1] != '*') { _buffer[offset++] = '%'; _buffer[offset++] = '*'; i++; @@ -207,73 +211,70 @@ _buffer[offset++] = response[i++]; } } - + // Scanf has very poor support for catching errors // fortunately, we can abuse the %n specifier to determine // if the entire string was matched. _buffer[offset++] = '%'; _buffer[offset++] = 'n'; _buffer[offset++] = 0; - + // To workaround scanf's lack of error reporting, we actually // make two passes. One checks the validity with the modified - // format string that only stores the matched characters (%n). + // format string that only stores the matched characters (%n). // The other reads in the actual matched values. // // We keep trying the match until we succeed or some other error // derails us. int j = 0; - + while (true) { // Ran out of space - if (j+1 >= _buffer_size - offset) + if (j+1 >= _buffer_size - offset) { return false; - + } // Recieve next character int c = getc(); - if (c < 0) + if (c < 0) { return false; - + } _buffer[offset + j++] = c; _buffer[offset + j] = 0; - + // Check for match int count = -1; sscanf(_buffer+offset, _buffer, &count); - + // We only succeed if all characters in the response are matched if (count == j) { -#ifdef AT_ECHO - ::printf("AT= %s\r\n", _buffer+offset); -#endif + debug_if(at_echo, "AT= %s\r\n", _buffer+offset); // Reuse the front end of the buffer memcpy(_buffer, response, i); _buffer[i] = 0; - + // Store the found results vsscanf(_buffer+offset, _buffer, args); - + // Jump to next line and continue parsing response += i; break; } - + // Clear the buffer when we hit a newline if (strcmp(&_buffer[offset + j-_delim_size], _delimiter) == 0) { -#ifdef AT_ECHO - ::printf("AT< %s", _buffer+offset); -#endif + debug_if(at_echo, "AT< %s", _buffer+offset); j = 0; } } } - + return true; } // Mapping to vararg functions -int ATParser::printf(const char *format, ...) { +int ATParser::printf(const char *format, ...) +{ va_list args; va_start(args, format); int res = vprintf(format, args); @@ -281,7 +282,8 @@ return res; } -int ATParser::scanf(const char *format, ...) { +int ATParser::scanf(const char *format, ...) +{ va_list args; va_start(args, format); int res = vscanf(format, args); @@ -289,7 +291,8 @@ return res; } -bool ATParser::send(const char *command, ...) { +bool ATParser::send(const char *command, ...) +{ va_list args; va_start(args, command); bool res = vsend(command, args); @@ -297,7 +300,8 @@ return res; } -bool ATParser::recv(const char *response, ...) { +bool ATParser::recv(const char *response, ...) +{ va_list args; va_start(args, response); bool res = vrecv(response, args);
--- a/ATParser.h Mon Jul 20 21:28:39 2015 +0000 +++ b/ATParser.h Sun Jul 26 21:53:28 2015 +0000 @@ -17,13 +17,12 @@ * Parser for the AT command syntax * */ - + #include "mbed.h" #include <cstdarg> - #include "BufferedSerial.h" - + /** * Parser class for parsing AT commands * @@ -41,17 +40,19 @@ * at.recv("OK"); * @endcode */ -class ATParser { +class ATParser +{ private: // Serial information BufferedSerial *_serial; int _buffer_size; char *_buffer; int _timeout; - + // Parsing information const char *_delimiter; int _delim_size; + uint8_t at_echo; public: /** @@ -62,22 +63,22 @@ * @param timeout timeout of the connection * @param delimiter string of characters to use as line delimiters */ - ATParser(BufferedSerial *serial, const char *delimiter = "\r\n", - int buffer_size = 256, int timeout = 8000) : - _serial(serial), - _buffer_size(buffer_size) { + ATParser(BufferedSerial &serial, const char *delimiter = "\r\n", int buffer_size = 256, int timeout = 8000, uint8_t echo = 0) : + _serial(&serial), + _buffer_size(buffer_size) { _buffer = new char[buffer_size]; setTimeout(timeout); setDelimiter(delimiter); + setEcho(echo); } - + /** * Destructor */ ~ATParser() { delete [] _buffer; } - + /** * Allows timeout to be changed between commands * @@ -86,7 +87,7 @@ void setTimeout(int timeout) { _timeout = timeout; } - + /** * Sets string of characters to use as line delimiters * @@ -98,19 +99,28 @@ } /** + * Allows echo to be on or off + * + * @param echo 1 for echo and 0 turns it off + */ + void setEcho(uint8_t echo) { + at_echo = (echo) ? 1 : 0; + } + + /** * Sends an AT command * * Sends a formatted command using printf style formatting * @see ::printf * - * @param command printf-like format string of command to send which + * @param command printf-like format string of command to send which * is appended with the specified delimiter * @param ... all printf-like arguments to insert into command * @return true only if command is successfully sent */ bool send(const char *command, ...); bool vsend(const char *command, va_list args); - + /** * Recieve an AT response * @@ -127,23 +137,23 @@ */ bool recv(const char *response, ...); bool vrecv(const char *response, va_list args); - - /** + + /** * Write a single byte to the underlying stream * * @param c The byte to write * @return The byte that was written or -1 during a timeout */ int putc(char c); - - /** + + /** * Get a single byte from the underlying stream * * @return The byte that was read or -1 during a timeout */ int getc(); - - /** + + /** * Write an array of bytes to the underlying stream * * @param data the array of bytes to write @@ -151,8 +161,8 @@ * @return number of bytes written or -1 on failure */ int write(const char *data, int size); - - /** + + /** * Read an array of bytes from the underlying stream * * @param data the destination for the read bytes @@ -160,7 +170,7 @@ * @return number of bytes read or -1 on failure */ int read(char *data, int size); - + /** * Direct printf to underlying stream * @see ::printf @@ -171,7 +181,7 @@ */ int printf(const char *format, ...); int vprintf(const char *format, va_list args); - + /** * Direct scanf on underlying stream * @see ::scanf @@ -182,7 +192,7 @@ */ int scanf(const char *format, ...); int vscanf(const char *format, va_list args); - + /** * Flushes the underlying stream */
--- a/BufferedSerial.lib Mon Jul 20 21:28:39 2015 +0000 +++ b/BufferedSerial.lib Sun Jul 26 21:53:28 2015 +0000 @@ -1,1 +1,1 @@ -http://developer.mbed.org/users/sam_grove/code/BufferedSerial/#9ee15ae3d1a3 +http://developer.mbed.org/users/sam_grove/code/BufferedSerial/#779304f9c5d2