Committer:
ganlikun
Date:
Mon Oct 24 15:19:39 2022 +0000
Revision:
0:06036f8bee2d
11

Who changed what in which revision?

UserRevisionLine numberNew 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 }