Version of easy-connect with the u-blox cellular platforms C027 and C030 added.

Dependents:   HelloMQTT

Committer:
RobMeades
Date:
Fri Nov 03 13:01:23 2017 +0000
Revision:
6:304d3ba87a01
Parent:
0:19aa55d66228
Add comment concerning N2XX baud rate.

Who changed what in which revision?

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