my customized lib

Committer:
DuyLionTran
Date:
Sun Nov 26 15:08:14 2017 +0000
Revision:
0:8094b249013c
Initial commit

Who changed what in which revision?

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