mirror of https://github.com/ARMmbed/mbed-os.git
ATCmdParser: merge scanf and recv functions.The goal is to give a configuration parameter for this function which would indicate are we trying to find a match from one line(scanf) or do we might end up processing multiple lines(recv) to find a match.
parent
1798c246cc
commit
15eb2a6e4f
|
@ -79,6 +79,24 @@ private:
|
||||||
};
|
};
|
||||||
oob *_oobs;
|
oob *_oobs;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Receive an AT response
|
||||||
|
*
|
||||||
|
* Receives a formatted response using scanf style formatting
|
||||||
|
* @see scanf
|
||||||
|
*
|
||||||
|
* Responses are parsed line at a time.
|
||||||
|
* If multiline is set to false parse only one line otherwise parse multiline response
|
||||||
|
* Any received data that does not match the response is ignored until
|
||||||
|
* a timeout occurs.
|
||||||
|
*
|
||||||
|
* @param response scanf-like format string of response to expect
|
||||||
|
* @param ... all scanf-like arguments to extract from response
|
||||||
|
* @param multiline determinate if parse one or multiple lines.
|
||||||
|
* @return number of bytes read or -1 on failure
|
||||||
|
*/
|
||||||
|
int vrecvscanf(const char *response, std::va_list args, bool multiline);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -124,68 +124,6 @@ int ATCmdParser::vprintf(const char *format, std::va_list args)
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ATCmdParser::vscanf(const char *format, std::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;
|
|
||||||
}
|
|
||||||
// Receive 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
|
// Command parsing with line handling
|
||||||
bool ATCmdParser::vsend(const char *command, std::va_list args)
|
bool ATCmdParser::vsend(const char *command, std::va_list args)
|
||||||
{
|
{
|
||||||
|
@ -211,7 +149,7 @@ bool ATCmdParser::vsend(const char *command, std::va_list args)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ATCmdParser::vrecv(const char *response, std::va_list args)
|
int ATCmdParser::vrecvscanf(const char *response, std::va_list args, bool multiline)
|
||||||
{
|
{
|
||||||
restart:
|
restart:
|
||||||
_aborted = false;
|
_aborted = false;
|
||||||
|
@ -259,17 +197,24 @@ restart:
|
||||||
int j = 0;
|
int j = 0;
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
|
// Ran out of space
|
||||||
|
if (j + 1 >= _buffer_size - offset) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
// If just peeking for OOBs, and at start of line, check
|
// If just peeking for OOBs, and at start of line, check
|
||||||
// readability
|
// readability
|
||||||
if (!response && j == 0 && !_fh->readable()) {
|
if (!response && j == 0 && !_fh->readable()) {
|
||||||
return false;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Receive next character
|
// Receive next character
|
||||||
int c = getc();
|
int c = getc();
|
||||||
if (c < 0) {
|
if (c < 0) {
|
||||||
debug_if(_dbg_on, "AT(Timeout)\n");
|
debug_if(_dbg_on, "AT(Timeout)\n");
|
||||||
return false;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Simplify newlines (borrowed from retarget.cpp)
|
// Simplify newlines (borrowed from retarget.cpp)
|
||||||
if ((c == CR && _in_prev != LF) ||
|
if ((c == CR && _in_prev != LF) ||
|
||||||
(c == LF && _in_prev != CR)) {
|
(c == LF && _in_prev != CR)) {
|
||||||
|
@ -283,10 +228,12 @@ restart:
|
||||||
} else {
|
} else {
|
||||||
_in_prev = c;
|
_in_prev = c;
|
||||||
}
|
}
|
||||||
|
|
||||||
_buffer[offset + j++] = c;
|
_buffer[offset + j++] = c;
|
||||||
_buffer[offset + j] = 0;
|
_buffer[offset + j] = 0;
|
||||||
|
|
||||||
// Check for oob data
|
// Check for oob data
|
||||||
|
if (multiline) {
|
||||||
for (struct oob *oob = _oobs; oob; oob = oob->next) {
|
for (struct oob *oob = _oobs; oob; oob = oob->next) {
|
||||||
if ((unsigned)j == oob->len && memcmp(
|
if ((unsigned)j == oob->len && memcmp(
|
||||||
oob->prefix, _buffer + offset, oob->len) == 0) {
|
oob->prefix, _buffer + offset, oob->len) == 0) {
|
||||||
|
@ -303,6 +250,7 @@ restart:
|
||||||
goto restart;
|
goto restart;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Check for match
|
// Check for match
|
||||||
int count = -1;
|
int count = -1;
|
||||||
|
@ -323,6 +271,10 @@ restart:
|
||||||
// Store the found results
|
// Store the found results
|
||||||
vsscanf(_buffer + offset, _buffer, args);
|
vsscanf(_buffer + offset, _buffer, args);
|
||||||
|
|
||||||
|
if (!multiline) {
|
||||||
|
return j;
|
||||||
|
}
|
||||||
|
|
||||||
// Jump to next line and continue parsing
|
// Jump to next line and continue parsing
|
||||||
response += i;
|
response += i;
|
||||||
break;
|
break;
|
||||||
|
@ -337,7 +289,17 @@ restart:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ATCmdParser::vscanf(const char *format, std::va_list args)
|
||||||
|
{
|
||||||
|
return vrecvscanf(format, args, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ATCmdParser::vrecv(const char *response, std::va_list args)
|
||||||
|
{
|
||||||
|
return (vrecvscanf(response, args, true)) > 0 ? true : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mapping to vararg functions
|
// Mapping to vararg functions
|
||||||
|
@ -354,7 +316,7 @@ int ATCmdParser::scanf(const char *format, ...)
|
||||||
{
|
{
|
||||||
std::va_list args;
|
std::va_list args;
|
||||||
va_start(args, format);
|
va_start(args, format);
|
||||||
int res = vscanf(format, args);
|
int res = vrecvscanf(format, args, false);
|
||||||
va_end(args);
|
va_end(args);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
@ -372,9 +334,9 @@ bool ATCmdParser::recv(const char *response, ...)
|
||||||
{
|
{
|
||||||
std::va_list args;
|
std::va_list args;
|
||||||
va_start(args, response);
|
va_start(args, response);
|
||||||
bool res = vrecv(response, args);
|
int res = vrecvscanf(response, args, true);
|
||||||
va_end(args);
|
va_end(args);
|
||||||
return res;
|
return (res > 0) ? true : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// oob registration
|
// oob registration
|
||||||
|
|
Loading…
Reference in New Issue