Rtos API example

Committer:
marcozecchini
Date:
Sat Feb 23 12:13:36 2019 +0000
Revision:
0:9fca2b23d0ba
final commit

Who changed what in which revision?

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