Skip to content

Commit 15eb2a6

Browse files
author
Marcin Tomczyk
committed
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.
1 parent 1798c24 commit 15eb2a6

File tree

2 files changed

+62
-82
lines changed

2 files changed

+62
-82
lines changed

platform/ATCmdParser.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,24 @@ class ATCmdParser : private NonCopyable<ATCmdParser> {
7979
};
8080
oob *_oobs;
8181

82+
/**
83+
* Receive an AT response
84+
*
85+
* Receives a formatted response using scanf style formatting
86+
* @see scanf
87+
*
88+
* Responses are parsed line at a time.
89+
* If multiline is set to false parse only one line otherwise parse multiline response
90+
* Any received data that does not match the response is ignored until
91+
* a timeout occurs.
92+
*
93+
* @param response scanf-like format string of response to expect
94+
* @param ... all scanf-like arguments to extract from response
95+
* @param multiline determinate if parse one or multiple lines.
96+
* @return number of bytes read or -1 on failure
97+
*/
98+
int vrecvscanf(const char *response, std::va_list args, bool multiline);
99+
82100
public:
83101

84102
/**

platform/source/ATCmdParser.cpp

Lines changed: 44 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -124,68 +124,6 @@ int ATCmdParser::vprintf(const char *format, std::va_list args)
124124
return i;
125125
}
126126

127-
int ATCmdParser::vscanf(const char *format, std::va_list args)
128-
{
129-
// Since format is const, we need to copy it into our buffer to
130-
// add the line's null terminator and clobber value-matches with asterisks.
131-
//
132-
// We just use the beginning of the buffer to avoid unnecessary allocations.
133-
int i = 0;
134-
int offset = 0;
135-
136-
while (format[i]) {
137-
if (format[i] == '%' && format[i + 1] != '%' && format[i + 1] != '*') {
138-
_buffer[offset++] = '%';
139-
_buffer[offset++] = '*';
140-
i++;
141-
} else {
142-
_buffer[offset++] = format[i++];
143-
}
144-
}
145-
146-
// Scanf has very poor support for catching errors
147-
// fortunately, we can abuse the %n specifier to determine
148-
// if the entire string was matched.
149-
_buffer[offset++] = '%';
150-
_buffer[offset++] = 'n';
151-
_buffer[offset++] = 0;
152-
153-
// To workaround scanf's lack of error reporting, we actually
154-
// make two passes. One checks the validity with the modified
155-
// format string that only stores the matched characters (%n).
156-
// The other reads in the actual matched values.
157-
//
158-
// We keep trying the match until we succeed or some other error
159-
// derails us.
160-
int j = 0;
161-
162-
while (true) {
163-
// Ran out of space
164-
if (j + 1 >= _buffer_size - offset) {
165-
return false;
166-
}
167-
// Receive next character
168-
int c = getc();
169-
if (c < 0) {
170-
return -1;
171-
}
172-
_buffer[offset + j++] = c;
173-
_buffer[offset + j] = 0;
174-
175-
// Check for match
176-
int count = -1;
177-
sscanf(_buffer + offset, _buffer, &count);
178-
179-
// We only succeed if all characters in the response are matched
180-
if (count == j) {
181-
// Store the found results
182-
vsscanf(_buffer + offset, format, args);
183-
return j;
184-
}
185-
}
186-
}
187-
188-
189127
// Command parsing with line handling
190128
bool ATCmdParser::vsend(const char *command, std::va_list args)
191129
{
@@ -211,7 +149,7 @@ bool ATCmdParser::vsend(const char *command, std::va_list args)
211149
return true;
212150
}
213151

214-
bool ATCmdParser::vrecv(const char *response, std::va_list args)
152+
int ATCmdParser::vrecvscanf(const char *response, std::va_list args, bool multiline)
215153
{
216154
restart:
217155
_aborted = false;
@@ -259,17 +197,24 @@ bool ATCmdParser::vrecv(const char *response, std::va_list args)
259197
int j = 0;
260198

261199
while (true) {
200+
// Ran out of space
201+
if (j + 1 >= _buffer_size - offset) {
202+
return -1;
203+
}
204+
262205
// If just peeking for OOBs, and at start of line, check
263206
// readability
264207
if (!response && j == 0 && !_fh->readable()) {
265-
return false;
208+
return -1;
266209
}
210+
267211
// Receive next character
268212
int c = getc();
269213
if (c < 0) {
270214
debug_if(_dbg_on, "AT(Timeout)\n");
271-
return false;
215+
return -1;
272216
}
217+
273218
// Simplify newlines (borrowed from retarget.cpp)
274219
if ((c == CR && _in_prev != LF) ||
275220
(c == LF && _in_prev != CR)) {
@@ -283,24 +228,27 @@ bool ATCmdParser::vrecv(const char *response, std::va_list args)
283228
} else {
284229
_in_prev = c;
285230
}
231+
286232
_buffer[offset + j++] = c;
287233
_buffer[offset + j] = 0;
288234

289235
// Check for oob data
290-
for (struct oob *oob = _oobs; oob; oob = oob->next) {
291-
if ((unsigned)j == oob->len && memcmp(
292-
oob->prefix, _buffer + offset, oob->len) == 0) {
293-
debug_if(_dbg_on, "AT! %s\n", oob->prefix);
294-
_oob_cb_count++;
295-
oob->cb();
296-
297-
if (_aborted) {
298-
debug_if(_dbg_on, "AT(Aborted)\n");
299-
return false;
236+
if (multiline) {
237+
for (struct oob *oob = _oobs; oob; oob = oob->next) {
238+
if ((unsigned)j == oob->len && memcmp(
239+
oob->prefix, _buffer + offset, oob->len) == 0) {
240+
debug_if(_dbg_on, "AT! %s\n", oob->prefix);
241+
_oob_cb_count++;
242+
oob->cb();
243+
244+
if (_aborted) {
245+
debug_if(_dbg_on, "AT(Aborted)\n");
246+
return false;
247+
}
248+
// oob may have corrupted non-reentrant buffer,
249+
// so we need to set it up again
250+
goto restart;
300251
}
301-
// oob may have corrupted non-reentrant buffer,
302-
// so we need to set it up again
303-
goto restart;
304252
}
305253
}
306254

@@ -323,6 +271,10 @@ bool ATCmdParser::vrecv(const char *response, std::va_list args)
323271
// Store the found results
324272
vsscanf(_buffer + offset, _buffer, args);
325273

274+
if (!multiline) {
275+
return j;
276+
}
277+
326278
// Jump to next line and continue parsing
327279
response += i;
328280
break;
@@ -337,7 +289,17 @@ bool ATCmdParser::vrecv(const char *response, std::va_list args)
337289
}
338290
}
339291

340-
return true;
292+
return 1;
293+
}
294+
295+
int ATCmdParser::vscanf(const char *format, std::va_list args)
296+
{
297+
return vrecvscanf(format, args, false);
298+
}
299+
300+
bool ATCmdParser::vrecv(const char *response, std::va_list args)
301+
{
302+
return (vrecvscanf(response, args, true)) > 0 ? true : false;
341303
}
342304

343305
// Mapping to vararg functions
@@ -354,7 +316,7 @@ int ATCmdParser::scanf(const char *format, ...)
354316
{
355317
std::va_list args;
356318
va_start(args, format);
357-
int res = vscanf(format, args);
319+
int res = vrecvscanf(format, args, false);
358320
va_end(args);
359321
return res;
360322
}
@@ -372,9 +334,9 @@ bool ATCmdParser::recv(const char *response, ...)
372334
{
373335
std::va_list args;
374336
va_start(args, response);
375-
bool res = vrecv(response, args);
337+
int res = vrecvscanf(response, args, true);
376338
va_end(args);
377-
return res;
339+
return (res > 0) ? true : false;
378340
}
379341

380342
// oob registration

0 commit comments

Comments
 (0)