FRDM K64F Metronome

Committer:
ram54288
Date:
Sun May 14 18:35:07 2017 +0000
Revision:
0:a2cb7295a1f7
Initial commit

Who changed what in which revision?

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