User | Revision | Line number | New contents of line |
ganlikun |
0:06036f8bee2d
|
1
|
/* Copyright (c) 2017 ARM Limited
|
ganlikun |
0:06036f8bee2d
|
2
|
*
|
ganlikun |
0:06036f8bee2d
|
3
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
ganlikun |
0:06036f8bee2d
|
4
|
* you may not use this file except in compliance with the License.
|
ganlikun |
0:06036f8bee2d
|
5
|
* You may obtain a copy of the License at
|
ganlikun |
0:06036f8bee2d
|
6
|
*
|
ganlikun |
0:06036f8bee2d
|
7
|
* http://www.apache.org/licenses/LICENSE-2.0
|
ganlikun |
0:06036f8bee2d
|
8
|
*
|
ganlikun |
0:06036f8bee2d
|
9
|
* Unless required by applicable law or agreed to in writing, software
|
ganlikun |
0:06036f8bee2d
|
10
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
ganlikun |
0:06036f8bee2d
|
11
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
ganlikun |
0:06036f8bee2d
|
12
|
* See the License for the specific language governing permissions and
|
ganlikun |
0:06036f8bee2d
|
13
|
* limitations under the License.
|
ganlikun |
0:06036f8bee2d
|
14
|
*
|
ganlikun |
0:06036f8bee2d
|
15
|
* @section DESCRIPTION
|
ganlikun |
0:06036f8bee2d
|
16
|
*
|
ganlikun |
0:06036f8bee2d
|
17
|
* Parser for the AT command syntax
|
ganlikun |
0:06036f8bee2d
|
18
|
*
|
ganlikun |
0:06036f8bee2d
|
19
|
*/
|
ganlikun |
0:06036f8bee2d
|
20
|
|
ganlikun |
0:06036f8bee2d
|
21
|
#include "ATCmdParser.h"
|
ganlikun |
0:06036f8bee2d
|
22
|
#include "mbed_poll.h"
|
ganlikun |
0:06036f8bee2d
|
23
|
#include "mbed_debug.h"
|
ganlikun |
0:06036f8bee2d
|
24
|
|
ganlikun |
0:06036f8bee2d
|
25
|
#ifdef LF
|
ganlikun |
0:06036f8bee2d
|
26
|
#undef LF
|
ganlikun |
0:06036f8bee2d
|
27
|
#define LF 10
|
ganlikun |
0:06036f8bee2d
|
28
|
#else
|
ganlikun |
0:06036f8bee2d
|
29
|
#define LF 10
|
ganlikun |
0:06036f8bee2d
|
30
|
#endif
|
ganlikun |
0:06036f8bee2d
|
31
|
|
ganlikun |
0:06036f8bee2d
|
32
|
#ifdef CR
|
ganlikun |
0:06036f8bee2d
|
33
|
#undef CR
|
ganlikun |
0:06036f8bee2d
|
34
|
#define CR 13
|
ganlikun |
0:06036f8bee2d
|
35
|
#else
|
ganlikun |
0:06036f8bee2d
|
36
|
#define CR 13
|
ganlikun |
0:06036f8bee2d
|
37
|
#endif
|
ganlikun |
0:06036f8bee2d
|
38
|
|
ganlikun |
0:06036f8bee2d
|
39
|
// getc/putc handling with timeouts
|
ganlikun |
0:06036f8bee2d
|
40
|
int ATCmdParser::putc(char c)
|
ganlikun |
0:06036f8bee2d
|
41
|
{
|
ganlikun |
0:06036f8bee2d
|
42
|
pollfh fhs;
|
ganlikun |
0:06036f8bee2d
|
43
|
fhs.fh = _fh;
|
ganlikun |
0:06036f8bee2d
|
44
|
fhs.events = POLLOUT;
|
ganlikun |
0:06036f8bee2d
|
45
|
|
ganlikun |
0:06036f8bee2d
|
46
|
int count = poll(&fhs, 1, _timeout);
|
ganlikun |
0:06036f8bee2d
|
47
|
if (count > 0 && (fhs.revents & POLLOUT)) {
|
ganlikun |
0:06036f8bee2d
|
48
|
return _fh->write(&c, 1) == 1 ? 0 : -1;
|
ganlikun |
0:06036f8bee2d
|
49
|
} else {
|
ganlikun |
0:06036f8bee2d
|
50
|
return -1;
|
ganlikun |
0:06036f8bee2d
|
51
|
}
|
ganlikun |
0:06036f8bee2d
|
52
|
}
|
ganlikun |
0:06036f8bee2d
|
53
|
|
ganlikun |
0:06036f8bee2d
|
54
|
int ATCmdParser::getc()
|
ganlikun |
0:06036f8bee2d
|
55
|
{
|
ganlikun |
0:06036f8bee2d
|
56
|
pollfh fhs;
|
ganlikun |
0:06036f8bee2d
|
57
|
fhs.fh = _fh;
|
ganlikun |
0:06036f8bee2d
|
58
|
fhs.events = POLLIN;
|
ganlikun |
0:06036f8bee2d
|
59
|
|
ganlikun |
0:06036f8bee2d
|
60
|
int count = poll(&fhs, 1, _timeout);
|
ganlikun |
0:06036f8bee2d
|
61
|
if (count > 0 && (fhs.revents & POLLIN)) {
|
ganlikun |
0:06036f8bee2d
|
62
|
unsigned char ch;
|
ganlikun |
0:06036f8bee2d
|
63
|
return _fh->read(&ch, 1) == 1 ? ch : -1;
|
ganlikun |
0:06036f8bee2d
|
64
|
} else {
|
ganlikun |
0:06036f8bee2d
|
65
|
return -1;
|
ganlikun |
0:06036f8bee2d
|
66
|
}
|
ganlikun |
0:06036f8bee2d
|
67
|
}
|
ganlikun |
0:06036f8bee2d
|
68
|
|
ganlikun |
0:06036f8bee2d
|
69
|
void ATCmdParser::flush()
|
ganlikun |
0:06036f8bee2d
|
70
|
{
|
ganlikun |
0:06036f8bee2d
|
71
|
while (_fh->readable()) {
|
ganlikun |
0:06036f8bee2d
|
72
|
unsigned char ch;
|
ganlikun |
0:06036f8bee2d
|
73
|
_fh->read(&ch, 1);
|
ganlikun |
0:06036f8bee2d
|
74
|
}
|
ganlikun |
0:06036f8bee2d
|
75
|
}
|
ganlikun |
0:06036f8bee2d
|
76
|
|
ganlikun |
0:06036f8bee2d
|
77
|
|
ganlikun |
0:06036f8bee2d
|
78
|
// read/write handling with timeouts
|
ganlikun |
0:06036f8bee2d
|
79
|
int ATCmdParser::write(const char *data, int size)
|
ganlikun |
0:06036f8bee2d
|
80
|
{
|
ganlikun |
0:06036f8bee2d
|
81
|
int i = 0;
|
ganlikun |
0:06036f8bee2d
|
82
|
for ( ; i < size; i++) {
|
ganlikun |
0:06036f8bee2d
|
83
|
if (putc(data[i]) < 0) {
|
ganlikun |
0:06036f8bee2d
|
84
|
return -1;
|
ganlikun |
0:06036f8bee2d
|
85
|
}
|
ganlikun |
0:06036f8bee2d
|
86
|
}
|
ganlikun |
0:06036f8bee2d
|
87
|
return i;
|
ganlikun |
0:06036f8bee2d
|
88
|
}
|
ganlikun |
0:06036f8bee2d
|
89
|
|
ganlikun |
0:06036f8bee2d
|
90
|
int ATCmdParser::read(char *data, int size)
|
ganlikun |
0:06036f8bee2d
|
91
|
{
|
ganlikun |
0:06036f8bee2d
|
92
|
int i = 0;
|
ganlikun |
0:06036f8bee2d
|
93
|
for ( ; i < size; i++) {
|
ganlikun |
0:06036f8bee2d
|
94
|
int c = getc();
|
ganlikun |
0:06036f8bee2d
|
95
|
if (c < 0) {
|
ganlikun |
0:06036f8bee2d
|
96
|
return -1;
|
ganlikun |
0:06036f8bee2d
|
97
|
}
|
ganlikun |
0:06036f8bee2d
|
98
|
data[i] = c;
|
ganlikun |
0:06036f8bee2d
|
99
|
}
|
ganlikun |
0:06036f8bee2d
|
100
|
return i;
|
ganlikun |
0:06036f8bee2d
|
101
|
}
|
ganlikun |
0:06036f8bee2d
|
102
|
|
ganlikun |
0:06036f8bee2d
|
103
|
|
ganlikun |
0:06036f8bee2d
|
104
|
// printf/scanf handling
|
ganlikun |
0:06036f8bee2d
|
105
|
int ATCmdParser::vprintf(const char *format, va_list args)
|
ganlikun |
0:06036f8bee2d
|
106
|
{
|
ganlikun |
0:06036f8bee2d
|
107
|
|
ganlikun |
0:06036f8bee2d
|
108
|
if (vsprintf(_buffer, format, args) < 0) {
|
ganlikun |
0:06036f8bee2d
|
109
|
return false;
|
ganlikun |
0:06036f8bee2d
|
110
|
}
|
ganlikun |
0:06036f8bee2d
|
111
|
|
ganlikun |
0:06036f8bee2d
|
112
|
int i = 0;
|
ganlikun |
0:06036f8bee2d
|
113
|
for ( ; _buffer[i]; i++) {
|
ganlikun |
0:06036f8bee2d
|
114
|
if (putc(_buffer[i]) < 0) {
|
ganlikun |
0:06036f8bee2d
|
115
|
return -1;
|
ganlikun |
0:06036f8bee2d
|
116
|
}
|
ganlikun |
0:06036f8bee2d
|
117
|
}
|
ganlikun |
0:06036f8bee2d
|
118
|
return i;
|
ganlikun |
0:06036f8bee2d
|
119
|
}
|
ganlikun |
0:06036f8bee2d
|
120
|
|
ganlikun |
0:06036f8bee2d
|
121
|
int ATCmdParser::vscanf(const char *format, va_list args)
|
ganlikun |
0:06036f8bee2d
|
122
|
{
|
ganlikun |
0:06036f8bee2d
|
123
|
// Since format is const, we need to copy it into our buffer to
|
ganlikun |
0:06036f8bee2d
|
124
|
// add the line's null terminator and clobber value-matches with asterisks.
|
ganlikun |
0:06036f8bee2d
|
125
|
//
|
ganlikun |
0:06036f8bee2d
|
126
|
// We just use the beginning of the buffer to avoid unnecessary allocations.
|
ganlikun |
0:06036f8bee2d
|
127
|
int i = 0;
|
ganlikun |
0:06036f8bee2d
|
128
|
int offset = 0;
|
ganlikun |
0:06036f8bee2d
|
129
|
|
ganlikun |
0:06036f8bee2d
|
130
|
while (format[i]) {
|
ganlikun |
0:06036f8bee2d
|
131
|
if (format[i] == '%' && format[i+1] != '%' && format[i+1] != '*') {
|
ganlikun |
0:06036f8bee2d
|
132
|
_buffer[offset++] = '%';
|
ganlikun |
0:06036f8bee2d
|
133
|
_buffer[offset++] = '*';
|
ganlikun |
0:06036f8bee2d
|
134
|
i++;
|
ganlikun |
0:06036f8bee2d
|
135
|
} else {
|
ganlikun |
0:06036f8bee2d
|
136
|
_buffer[offset++] = format[i++];
|
ganlikun |
0:06036f8bee2d
|
137
|
}
|
ganlikun |
0:06036f8bee2d
|
138
|
}
|
ganlikun |
0:06036f8bee2d
|
139
|
|
ganlikun |
0:06036f8bee2d
|
140
|
// Scanf has very poor support for catching errors
|
ganlikun |
0:06036f8bee2d
|
141
|
// fortunately, we can abuse the %n specifier to determine
|
ganlikun |
0:06036f8bee2d
|
142
|
// if the entire string was matched.
|
ganlikun |
0:06036f8bee2d
|
143
|
_buffer[offset++] = '%';
|
ganlikun |
0:06036f8bee2d
|
144
|
_buffer[offset++] = 'n';
|
ganlikun |
0:06036f8bee2d
|
145
|
_buffer[offset++] = 0;
|
ganlikun |
0:06036f8bee2d
|
146
|
|
ganlikun |
0:06036f8bee2d
|
147
|
// To workaround scanf's lack of error reporting, we actually
|
ganlikun |
0:06036f8bee2d
|
148
|
// make two passes. One checks the validity with the modified
|
ganlikun |
0:06036f8bee2d
|
149
|
// format string that only stores the matched characters (%n).
|
ganlikun |
0:06036f8bee2d
|
150
|
// The other reads in the actual matched values.
|
ganlikun |
0:06036f8bee2d
|
151
|
//
|
ganlikun |
0:06036f8bee2d
|
152
|
// We keep trying the match until we succeed or some other error
|
ganlikun |
0:06036f8bee2d
|
153
|
// derails us.
|
ganlikun |
0:06036f8bee2d
|
154
|
int j = 0;
|
ganlikun |
0:06036f8bee2d
|
155
|
|
ganlikun |
0:06036f8bee2d
|
156
|
while (true) {
|
ganlikun |
0:06036f8bee2d
|
157
|
// Ran out of space
|
ganlikun |
0:06036f8bee2d
|
158
|
if (j+1 >= _buffer_size - offset) {
|
ganlikun |
0:06036f8bee2d
|
159
|
return false;
|
ganlikun |
0:06036f8bee2d
|
160
|
}
|
ganlikun |
0:06036f8bee2d
|
161
|
// Recieve next character
|
ganlikun |
0:06036f8bee2d
|
162
|
int c = getc();
|
ganlikun |
0:06036f8bee2d
|
163
|
if (c < 0) {
|
ganlikun |
0:06036f8bee2d
|
164
|
return -1;
|
ganlikun |
0:06036f8bee2d
|
165
|
}
|
ganlikun |
0:06036f8bee2d
|
166
|
_buffer[offset + j++] = c;
|
ganlikun |
0:06036f8bee2d
|
167
|
_buffer[offset + j] = 0;
|
ganlikun |
0:06036f8bee2d
|
168
|
|
ganlikun |
0:06036f8bee2d
|
169
|
// Check for match
|
ganlikun |
0:06036f8bee2d
|
170
|
int count = -1;
|
ganlikun |
0:06036f8bee2d
|
171
|
sscanf(_buffer+offset, _buffer, &count);
|
ganlikun |
0:06036f8bee2d
|
172
|
|
ganlikun |
0:06036f8bee2d
|
173
|
// We only succeed if all characters in the response are matched
|
ganlikun |
0:06036f8bee2d
|
174
|
if (count == j) {
|
ganlikun |
0:06036f8bee2d
|
175
|
// Store the found results
|
ganlikun |
0:06036f8bee2d
|
176
|
vsscanf(_buffer+offset, format, args);
|
ganlikun |
0:06036f8bee2d
|
177
|
return j;
|
ganlikun |
0:06036f8bee2d
|
178
|
}
|
ganlikun |
0:06036f8bee2d
|
179
|
}
|
ganlikun |
0:06036f8bee2d
|
180
|
}
|
ganlikun |
0:06036f8bee2d
|
181
|
|
ganlikun |
0:06036f8bee2d
|
182
|
|
ganlikun |
0:06036f8bee2d
|
183
|
// Command parsing with line handling
|
ganlikun |
0:06036f8bee2d
|
184
|
bool ATCmdParser::vsend(const char *command, va_list args)
|
ganlikun |
0:06036f8bee2d
|
185
|
{
|
ganlikun |
0:06036f8bee2d
|
186
|
// Create and send command
|
ganlikun |
0:06036f8bee2d
|
187
|
if (vsprintf(_buffer, command, args) < 0) {
|
ganlikun |
0:06036f8bee2d
|
188
|
return false;
|
ganlikun |
0:06036f8bee2d
|
189
|
}
|
ganlikun |
0:06036f8bee2d
|
190
|
|
ganlikun |
0:06036f8bee2d
|
191
|
for (int i = 0; _buffer[i]; i++) {
|
ganlikun |
0:06036f8bee2d
|
192
|
if (putc(_buffer[i]) < 0) {
|
ganlikun |
0:06036f8bee2d
|
193
|
return false;
|
ganlikun |
0:06036f8bee2d
|
194
|
}
|
ganlikun |
0:06036f8bee2d
|
195
|
}
|
ganlikun |
0:06036f8bee2d
|
196
|
|
ganlikun |
0:06036f8bee2d
|
197
|
// Finish with newline
|
ganlikun |
0:06036f8bee2d
|
198
|
for (size_t i = 0; _output_delimiter[i]; i++) {
|
ganlikun |
0:06036f8bee2d
|
199
|
if (putc(_output_delimiter[i]) < 0) {
|
ganlikun |
0:06036f8bee2d
|
200
|
return false;
|
ganlikun |
0:06036f8bee2d
|
201
|
}
|
ganlikun |
0:06036f8bee2d
|
202
|
}
|
ganlikun |
0:06036f8bee2d
|
203
|
|
ganlikun |
0:06036f8bee2d
|
204
|
debug_if(_dbg_on, "AT> %s\n", _buffer);
|
ganlikun |
0:06036f8bee2d
|
205
|
return true;
|
ganlikun |
0:06036f8bee2d
|
206
|
}
|
ganlikun |
0:06036f8bee2d
|
207
|
|
ganlikun |
0:06036f8bee2d
|
208
|
bool ATCmdParser::vrecv(const char *response, va_list args)
|
ganlikun |
0:06036f8bee2d
|
209
|
{
|
ganlikun |
0:06036f8bee2d
|
210
|
restart:
|
ganlikun |
0:06036f8bee2d
|
211
|
_aborted = false;
|
ganlikun |
0:06036f8bee2d
|
212
|
// Iterate through each line in the expected response
|
ganlikun |
0:06036f8bee2d
|
213
|
while (response[0]) {
|
ganlikun |
0:06036f8bee2d
|
214
|
// Since response is const, we need to copy it into our buffer to
|
ganlikun |
0:06036f8bee2d
|
215
|
// add the line's null terminator and clobber value-matches with asterisks.
|
ganlikun |
0:06036f8bee2d
|
216
|
//
|
ganlikun |
0:06036f8bee2d
|
217
|
// We just use the beginning of the buffer to avoid unnecessary allocations.
|
ganlikun |
0:06036f8bee2d
|
218
|
int i = 0;
|
ganlikun |
0:06036f8bee2d
|
219
|
int offset = 0;
|
ganlikun |
0:06036f8bee2d
|
220
|
bool whole_line_wanted = false;
|
ganlikun |
0:06036f8bee2d
|
221
|
|
ganlikun |
0:06036f8bee2d
|
222
|
while (response[i]) {
|
ganlikun |
0:06036f8bee2d
|
223
|
if (response[i] == '%' && response[i+1] != '%' && response[i+1] != '*') {
|
ganlikun |
0:06036f8bee2d
|
224
|
_buffer[offset++] = '%';
|
ganlikun |
0:06036f8bee2d
|
225
|
_buffer[offset++] = '*';
|
ganlikun |
0:06036f8bee2d
|
226
|
i++;
|
ganlikun |
0:06036f8bee2d
|
227
|
} else {
|
ganlikun |
0:06036f8bee2d
|
228
|
_buffer[offset++] = response[i++];
|
ganlikun |
0:06036f8bee2d
|
229
|
// Find linebreaks, taking care not to be fooled if they're in a %[^\n] conversion specification
|
ganlikun |
0:06036f8bee2d
|
230
|
if (response[i - 1] == '\n' && !(i >= 3 && response[i-3] == '[' && response[i-2] == '^')) {
|
ganlikun |
0:06036f8bee2d
|
231
|
whole_line_wanted = true;
|
ganlikun |
0:06036f8bee2d
|
232
|
break;
|
ganlikun |
0:06036f8bee2d
|
233
|
}
|
ganlikun |
0:06036f8bee2d
|
234
|
}
|
ganlikun |
0:06036f8bee2d
|
235
|
}
|
ganlikun |
0:06036f8bee2d
|
236
|
|
ganlikun |
0:06036f8bee2d
|
237
|
// Scanf has very poor support for catching errors
|
ganlikun |
0:06036f8bee2d
|
238
|
// fortunately, we can abuse the %n specifier to determine
|
ganlikun |
0:06036f8bee2d
|
239
|
// if the entire string was matched.
|
ganlikun |
0:06036f8bee2d
|
240
|
_buffer[offset++] = '%';
|
ganlikun |
0:06036f8bee2d
|
241
|
_buffer[offset++] = 'n';
|
ganlikun |
0:06036f8bee2d
|
242
|
_buffer[offset++] = 0;
|
ganlikun |
0:06036f8bee2d
|
243
|
|
ganlikun |
0:06036f8bee2d
|
244
|
debug_if(_dbg_on, "AT? %s\n", _buffer);
|
ganlikun |
0:06036f8bee2d
|
245
|
// To workaround scanf's lack of error reporting, we actually
|
ganlikun |
0:06036f8bee2d
|
246
|
// make two passes. One checks the validity with the modified
|
ganlikun |
0:06036f8bee2d
|
247
|
// format string that only stores the matched characters (%n).
|
ganlikun |
0:06036f8bee2d
|
248
|
// The other reads in the actual matched values.
|
ganlikun |
0:06036f8bee2d
|
249
|
//
|
ganlikun |
0:06036f8bee2d
|
250
|
// We keep trying the match until we succeed or some other error
|
ganlikun |
0:06036f8bee2d
|
251
|
// derails us.
|
ganlikun |
0:06036f8bee2d
|
252
|
int j = 0;
|
ganlikun |
0:06036f8bee2d
|
253
|
|
ganlikun |
0:06036f8bee2d
|
254
|
while (true) {
|
ganlikun |
0:06036f8bee2d
|
255
|
// Receive next character
|
ganlikun |
0:06036f8bee2d
|
256
|
int c = getc();
|
ganlikun |
0:06036f8bee2d
|
257
|
if (c < 0) {
|
ganlikun |
0:06036f8bee2d
|
258
|
debug_if(_dbg_on, "AT(Timeout)\n");
|
ganlikun |
0:06036f8bee2d
|
259
|
return false;
|
ganlikun |
0:06036f8bee2d
|
260
|
}
|
ganlikun |
0:06036f8bee2d
|
261
|
// Simplify newlines (borrowed from retarget.cpp)
|
ganlikun |
0:06036f8bee2d
|
262
|
if ((c == CR && _in_prev != LF) ||
|
ganlikun |
0:06036f8bee2d
|
263
|
(c == LF && _in_prev != CR)) {
|
ganlikun |
0:06036f8bee2d
|
264
|
_in_prev = c;
|
ganlikun |
0:06036f8bee2d
|
265
|
c = '\n';
|
ganlikun |
0:06036f8bee2d
|
266
|
} else if ((c == CR && _in_prev == LF) ||
|
ganlikun |
0:06036f8bee2d
|
267
|
(c == LF && _in_prev == CR)) {
|
ganlikun |
0:06036f8bee2d
|
268
|
_in_prev = c;
|
ganlikun |
0:06036f8bee2d
|
269
|
// onto next character
|
ganlikun |
0:06036f8bee2d
|
270
|
continue;
|
ganlikun |
0:06036f8bee2d
|
271
|
} else {
|
ganlikun |
0:06036f8bee2d
|
272
|
_in_prev = c;
|
ganlikun |
0:06036f8bee2d
|
273
|
}
|
ganlikun |
0:06036f8bee2d
|
274
|
_buffer[offset + j++] = c;
|
ganlikun |
0:06036f8bee2d
|
275
|
_buffer[offset + j] = 0;
|
ganlikun |
0:06036f8bee2d
|
276
|
|
ganlikun |
0:06036f8bee2d
|
277
|
// Check for oob data
|
ganlikun |
0:06036f8bee2d
|
278
|
for (struct oob *oob = _oobs; oob; oob = oob->next) {
|
ganlikun |
0:06036f8bee2d
|
279
|
if ((unsigned)j == oob->len && memcmp(
|
ganlikun |
0:06036f8bee2d
|
280
|
oob->prefix, _buffer+offset, oob->len) == 0) {
|
ganlikun |
0:06036f8bee2d
|
281
|
debug_if(_dbg_on, "AT! %s\n", oob->prefix);
|
ganlikun |
0:06036f8bee2d
|
282
|
oob->cb();
|
ganlikun |
0:06036f8bee2d
|
283
|
|
ganlikun |
0:06036f8bee2d
|
284
|
if (_aborted) {
|
ganlikun |
0:06036f8bee2d
|
285
|
debug_if(_dbg_on, "AT(Aborted)\n");
|
ganlikun |
0:06036f8bee2d
|
286
|
return false;
|
ganlikun |
0:06036f8bee2d
|
287
|
}
|
ganlikun |
0:06036f8bee2d
|
288
|
// oob may have corrupted non-reentrant buffer,
|
ganlikun |
0:06036f8bee2d
|
289
|
// so we need to set it up again
|
ganlikun |
0:06036f8bee2d
|
290
|
goto restart;
|
ganlikun |
0:06036f8bee2d
|
291
|
}
|
ganlikun |
0:06036f8bee2d
|
292
|
}
|
ganlikun |
0:06036f8bee2d
|
293
|
|
ganlikun |
0:06036f8bee2d
|
294
|
// Check for match
|
ganlikun |
0:06036f8bee2d
|
295
|
int count = -1;
|
ganlikun |
0:06036f8bee2d
|
296
|
if (whole_line_wanted && c != '\n') {
|
ganlikun |
0:06036f8bee2d
|
297
|
// Don't attempt scanning until we get delimiter if they included it in format
|
ganlikun |
0:06036f8bee2d
|
298
|
// This allows recv("Foo: %s\n") to work, and not match with just the first character of a string
|
ganlikun |
0:06036f8bee2d
|
299
|
// (scanf does not itself match whitespace in its format string, so \n is not significant to it)
|
ganlikun |
0:06036f8bee2d
|
300
|
} else {
|
ganlikun |
0:06036f8bee2d
|
301
|
sscanf(_buffer+offset, _buffer, &count);
|
ganlikun |
0:06036f8bee2d
|
302
|
}
|
ganlikun |
0:06036f8bee2d
|
303
|
|
ganlikun |
0:06036f8bee2d
|
304
|
// We only succeed if all characters in the response are matched
|
ganlikun |
0:06036f8bee2d
|
305
|
if (count == j) {
|
ganlikun |
0:06036f8bee2d
|
306
|
debug_if(_dbg_on, "AT= %s\n", _buffer+offset);
|
ganlikun |
0:06036f8bee2d
|
307
|
// Reuse the front end of the buffer
|
ganlikun |
0:06036f8bee2d
|
308
|
memcpy(_buffer, response, i);
|
ganlikun |
0:06036f8bee2d
|
309
|
_buffer[i] = 0;
|
ganlikun |
0:06036f8bee2d
|
310
|
|
ganlikun |
0:06036f8bee2d
|
311
|
// Store the found results
|
ganlikun |
0:06036f8bee2d
|
312
|
vsscanf(_buffer+offset, _buffer, args);
|
ganlikun |
0:06036f8bee2d
|
313
|
|
ganlikun |
0:06036f8bee2d
|
314
|
// Jump to next line and continue parsing
|
ganlikun |
0:06036f8bee2d
|
315
|
response += i;
|
ganlikun |
0:06036f8bee2d
|
316
|
break;
|
ganlikun |
0:06036f8bee2d
|
317
|
}
|
ganlikun |
0:06036f8bee2d
|
318
|
|
ganlikun |
0:06036f8bee2d
|
319
|
// Clear the buffer when we hit a newline or ran out of space
|
ganlikun |
0:06036f8bee2d
|
320
|
// running out of space usually means we ran into binary data
|
ganlikun |
0:06036f8bee2d
|
321
|
if (c == '\n' || j+1 >= _buffer_size - offset) {
|
ganlikun |
0:06036f8bee2d
|
322
|
debug_if(_dbg_on, "AT< %s", _buffer+offset);
|
ganlikun |
0:06036f8bee2d
|
323
|
j = 0;
|
ganlikun |
0:06036f8bee2d
|
324
|
}
|
ganlikun |
0:06036f8bee2d
|
325
|
}
|
ganlikun |
0:06036f8bee2d
|
326
|
}
|
ganlikun |
0:06036f8bee2d
|
327
|
|
ganlikun |
0:06036f8bee2d
|
328
|
return true;
|
ganlikun |
0:06036f8bee2d
|
329
|
}
|
ganlikun |
0:06036f8bee2d
|
330
|
|
ganlikun |
0:06036f8bee2d
|
331
|
// Mapping to vararg functions
|
ganlikun |
0:06036f8bee2d
|
332
|
int ATCmdParser::printf(const char *format, ...)
|
ganlikun |
0:06036f8bee2d
|
333
|
{
|
ganlikun |
0:06036f8bee2d
|
334
|
va_list args;
|
ganlikun |
0:06036f8bee2d
|
335
|
va_start(args, format);
|
ganlikun |
0:06036f8bee2d
|
336
|
int res = vprintf(format, args);
|
ganlikun |
0:06036f8bee2d
|
337
|
va_end(args);
|
ganlikun |
0:06036f8bee2d
|
338
|
return res;
|
ganlikun |
0:06036f8bee2d
|
339
|
}
|
ganlikun |
0:06036f8bee2d
|
340
|
|
ganlikun |
0:06036f8bee2d
|
341
|
int ATCmdParser::scanf(const char *format, ...)
|
ganlikun |
0:06036f8bee2d
|
342
|
{
|
ganlikun |
0:06036f8bee2d
|
343
|
va_list args;
|
ganlikun |
0:06036f8bee2d
|
344
|
va_start(args, format);
|
ganlikun |
0:06036f8bee2d
|
345
|
int res = vscanf(format, args);
|
ganlikun |
0:06036f8bee2d
|
346
|
va_end(args);
|
ganlikun |
0:06036f8bee2d
|
347
|
return res;
|
ganlikun |
0:06036f8bee2d
|
348
|
}
|
ganlikun |
0:06036f8bee2d
|
349
|
|
ganlikun |
0:06036f8bee2d
|
350
|
bool ATCmdParser::send(const char *command, ...)
|
ganlikun |
0:06036f8bee2d
|
351
|
{
|
ganlikun |
0:06036f8bee2d
|
352
|
va_list args;
|
ganlikun |
0:06036f8bee2d
|
353
|
va_start(args, command);
|
ganlikun |
0:06036f8bee2d
|
354
|
bool res = vsend(command, args);
|
ganlikun |
0:06036f8bee2d
|
355
|
va_end(args);
|
ganlikun |
0:06036f8bee2d
|
356
|
return res;
|
ganlikun |
0:06036f8bee2d
|
357
|
}
|
ganlikun |
0:06036f8bee2d
|
358
|
|
ganlikun |
0:06036f8bee2d
|
359
|
bool ATCmdParser::recv(const char *response, ...)
|
ganlikun |
0:06036f8bee2d
|
360
|
{
|
ganlikun |
0:06036f8bee2d
|
361
|
va_list args;
|
ganlikun |
0:06036f8bee2d
|
362
|
va_start(args, response);
|
ganlikun |
0:06036f8bee2d
|
363
|
bool res = vrecv(response, args);
|
ganlikun |
0:06036f8bee2d
|
364
|
va_end(args);
|
ganlikun |
0:06036f8bee2d
|
365
|
return res;
|
ganlikun |
0:06036f8bee2d
|
366
|
}
|
ganlikun |
0:06036f8bee2d
|
367
|
|
ganlikun |
0:06036f8bee2d
|
368
|
// oob registration
|
ganlikun |
0:06036f8bee2d
|
369
|
void ATCmdParser::oob(const char *prefix, Callback<void()> cb)
|
ganlikun |
0:06036f8bee2d
|
370
|
{
|
ganlikun |
0:06036f8bee2d
|
371
|
struct oob *oob = new struct oob;
|
ganlikun |
0:06036f8bee2d
|
372
|
oob->len = strlen(prefix);
|
ganlikun |
0:06036f8bee2d
|
373
|
oob->prefix = prefix;
|
ganlikun |
0:06036f8bee2d
|
374
|
oob->cb = cb;
|
ganlikun |
0:06036f8bee2d
|
375
|
oob->next = _oobs;
|
ganlikun |
0:06036f8bee2d
|
376
|
_oobs = oob;
|
ganlikun |
0:06036f8bee2d
|
377
|
}
|
ganlikun |
0:06036f8bee2d
|
378
|
|
ganlikun |
0:06036f8bee2d
|
379
|
void ATCmdParser::abort()
|
ganlikun |
0:06036f8bee2d
|
380
|
{
|
ganlikun |
0:06036f8bee2d
|
381
|
_aborted = true;
|
ganlikun |
0:06036f8bee2d
|
382
|
}
|