Fork of my MQTTGateway

Dependencies:   mbed-http

Committer:
vpcola
Date:
Sat Apr 08 14:45:51 2017 +0000
Revision:
0:f1d3878b8dd9
Initial commit

Who changed what in which revision?

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