Parser for AT commands and similar protocols
Diff: ATParser.cpp
- Revision:
- 9:9bcb87c27208
- Parent:
- 8:91515b168c70
- Child:
- 10:553f9ffaf657
--- a/ATParser.cpp Mon Jul 20 20:56:30 2015 +0000 +++ b/ATParser.cpp Mon Jul 20 21:28:39 2015 +0000 @@ -60,10 +60,9 @@ // 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) - return i; + return -1; } return i; @@ -71,12 +70,10 @@ int ATParser::read(char *data, int size) { int i; - for (i = 0; i < size; i++) { int c = getc(); - if (c < 0) - return i; + return -1; data[i] = c; } @@ -85,10 +82,85 @@ } +// printf/scanf handling +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) + return -1; + } + + return i; +} + +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] != '*') { + _buffer[offset++] = '%'; + _buffer[offset++] = '*'; + i++; + } else { + _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). + // 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) + return false; + + // Recieve next character + int c = getc(); + 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 + vsscanf(_buffer+offset, format, args); + return j; + } + } +} + + // Command parsing with line handling bool ATParser::vsend(const char *command, va_list args) { - flush(); - // Create and send command if (vsprintf(_buffer, command, args) < 0) return false; @@ -105,7 +177,7 @@ } #ifdef AT_ECHO - printf("AT> %s\r\n", _buffer); + ::printf("AT> %s\r\n", _buffer); #endif return true; @@ -152,7 +224,11 @@ // derails us. int j = 0; - while (j+1 < _buffer_size - offset) { + while (true) { + // Ran out of space + if (j+1 >= _buffer_size - offset) + return false; + // Recieve next character int c = getc(); if (c < 0) @@ -168,7 +244,7 @@ // We only succeed if all characters in the response are matched if (count == j) { #ifdef AT_ECHO - printf("AT= %s\r\n", _buffer+offset); + ::printf("AT= %s\r\n", _buffer+offset); #endif // Reuse the front end of the buffer memcpy(_buffer, response, i); @@ -185,7 +261,7 @@ // 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); + ::printf("AT< %s", _buffer+offset); #endif j = 0; } @@ -197,6 +273,22 @@ // Mapping to vararg functions +int ATParser::printf(const char *format, ...) { + va_list args; + va_start(args, format); + int res = vprintf(format, args); + va_end(args); + return res; +} + +int ATParser::scanf(const char *format, ...) { + va_list args; + va_start(args, format); + int res = vscanf(format, args); + va_end(args); + return res; +} + bool ATParser::send(const char *command, ...) { va_list args; va_start(args, command);