Easily add all supported connectivity methods to your mbed OS project

Dependencies:   type-yd-driver

Committer:
MACRUM
Date:
Wed Jul 12 10:52:58 2017 +0000
Revision:
0:615f90842ce8
Initial commit

Who changed what in which revision?

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