001

Committer:
ganlikun
Date:
Sun Jun 12 14:02:44 2022 +0000
Revision:
0:13413ea9a877
00

Who changed what in which revision?

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