Fork of my original MQTTGateway

Dependencies:   mbed-http

Committer:
vpcola
Date:
Sat Apr 08 14:43:14 2017 +0000
Revision:
0:a1734fe1ec4b
Initial commit

Who changed what in which revision?

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