Skip to content

Commit 611b6be

Browse files
author
Marcin Tomczyk
committed
ATCmdParser: merge scanf and recv functions
1 parent 1798c24 commit 611b6be

File tree

2 files changed

+61
-111
lines changed

2 files changed

+61
-111
lines changed

platform/ATCmdParser.h

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,7 @@ class ATCmdParser : private NonCopyable<ATCmdParser> {
222222
*/
223223
bool recv(const char *response, ...) MBED_SCANF_METHOD(1, 2);
224224

225-
bool vrecv(const char *response, std::va_list args);
225+
int vrecvscanf(const char *response, std::va_list args, bool isscnf);
226226

227227
/**
228228
* Write a single byte to the underlying stream
@@ -282,8 +282,6 @@ class ATCmdParser : private NonCopyable<ATCmdParser> {
282282
*/
283283
int scanf(const char *format, ...) MBED_SCANF_METHOD(1, 2);
284284

285-
int vscanf(const char *format, std::va_list args);
286-
287285
/**
288286
* Attach a callback for out-of-band data
289287
*

platform/source/ATCmdParser.cpp

Lines changed: 60 additions & 108 deletions
Original file line numberDiff line numberDiff line change
@@ -124,94 +124,7 @@ 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-
189-
// Command parsing with line handling
190-
bool ATCmdParser::vsend(const char *command, std::va_list args)
191-
{
192-
// Create and send command
193-
if (vsprintf(_buffer, command, args) < 0) {
194-
return false;
195-
}
196-
197-
for (int i = 0; _buffer[i]; i++) {
198-
if (putc(_buffer[i]) < 0) {
199-
return false;
200-
}
201-
}
202-
203-
// Finish with newline
204-
for (size_t i = 0; _output_delimiter[i]; i++) {
205-
if (putc(_output_delimiter[i]) < 0) {
206-
return false;
207-
}
208-
}
209-
210-
debug_if(_dbg_on, "AT> %s\n", _buffer);
211-
return true;
212-
}
213-
214-
bool ATCmdParser::vrecv(const char *response, std::va_list args)
127+
int ATCmdParser::vrecvscanf(const char *response, std::va_list args, bool issacnf)
215128
{
216129
restart:
217130
_aborted = false;
@@ -259,20 +172,27 @@ bool ATCmdParser::vrecv(const char *response, std::va_list args)
259172
int j = 0;
260173

261174
while (true) {
175+
// Ran out of space
176+
if (j + 1 >= _buffer_size - offset) {
177+
return -1;
178+
}
179+
262180
// If just peeking for OOBs, and at start of line, check
263181
// readability
264-
if (!response && j == 0 && !_fh->readable()) {
265-
return false;
182+
if (!issacnf && !response && j == 0 && !_fh->readable()) {
183+
return -1;
266184
}
185+
267186
// Receive next character
268187
int c = getc();
269188
if (c < 0) {
270189
debug_if(_dbg_on, "AT(Timeout)\n");
271-
return false;
190+
return -1;
272191
}
192+
273193
// Simplify newlines (borrowed from retarget.cpp)
274194
if ((c == CR && _in_prev != LF) ||
275-
(c == LF && _in_prev != CR)) {
195+
(c == LF && _in_prev != CR)) {
276196
_in_prev = c;
277197
c = '\n';
278198
} else if ((c == CR && _in_prev == LF) ||
@@ -283,24 +203,27 @@ bool ATCmdParser::vrecv(const char *response, std::va_list args)
283203
} else {
284204
_in_prev = c;
285205
}
206+
286207
_buffer[offset + j++] = c;
287208
_buffer[offset + j] = 0;
288209

289210
// 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;
211+
if(!issacnf) {
212+
for (struct oob *oob = _oobs; oob; oob = oob->next) {
213+
if ((unsigned)j == oob->len && memcmp(
214+
oob->prefix, _buffer + offset, oob->len) == 0) {
215+
debug_if(_dbg_on, "AT! %s\n", oob->prefix);
216+
_oob_cb_count++;
217+
oob->cb();
218+
219+
if (_aborted) {
220+
debug_if(_dbg_on, "AT(Aborted)\n");
221+
return false;
222+
}
223+
// oob may have corrupted non-reentrant buffer,
224+
// so we need to set it up again
225+
goto restart;
300226
}
301-
// oob may have corrupted non-reentrant buffer,
302-
// so we need to set it up again
303-
goto restart;
304227
}
305228
}
306229

@@ -323,6 +246,10 @@ bool ATCmdParser::vrecv(const char *response, std::va_list args)
323246
// Store the found results
324247
vsscanf(_buffer + offset, _buffer, args);
325248

249+
if(issacnf) {
250+
return j;
251+
}
252+
326253
// Jump to next line and continue parsing
327254
response += i;
328255
break;
@@ -337,6 +264,31 @@ bool ATCmdParser::vrecv(const char *response, std::va_list args)
337264
}
338265
}
339266

267+
return 1;
268+
}
269+
270+
// Command parsing with line handling
271+
bool ATCmdParser::vsend(const char *command, std::va_list args)
272+
{
273+
// Create and send command
274+
if (vsprintf(_buffer, command, args) < 0) {
275+
return false;
276+
}
277+
278+
for (int i = 0; _buffer[i]; i++) {
279+
if (putc(_buffer[i]) < 0) {
280+
return false;
281+
}
282+
}
283+
284+
// Finish with newline
285+
for (size_t i = 0; _output_delimiter[i]; i++) {
286+
if (putc(_output_delimiter[i]) < 0) {
287+
return false;
288+
}
289+
}
290+
291+
debug_if(_dbg_on, "AT> %s\n", _buffer);
340292
return true;
341293
}
342294

@@ -354,7 +306,7 @@ int ATCmdParser::scanf(const char *format, ...)
354306
{
355307
std::va_list args;
356308
va_start(args, format);
357-
int res = vscanf(format, args);
309+
int res = vrecvscanf(format, args, true);
358310
va_end(args);
359311
return res;
360312
}
@@ -372,9 +324,9 @@ bool ATCmdParser::recv(const char *response, ...)
372324
{
373325
std::va_list args;
374326
va_start(args, response);
375-
bool res = vrecv(response, args);
327+
int res = vrecvscanf(response, args, false);
376328
va_end(args);
377-
return res;
329+
return (res > 0) ? true : false;
378330
}
379331

380332
// oob registration

0 commit comments

Comments
 (0)