mbed-os5 only for TYBLE16

Dependents:   TYBLE16_simple_data_logger TYBLE16_MP3_Air

Committer:
kenjiArai
Date:
Tue Dec 31 06:02:27 2019 +0000
Revision:
1:9db0e321a9f4
updated based on mbed-os5.15.0

Who changed what in which revision?

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