Added support for WNC M14A2A Cellular LTE Data Module.

Dependencies:   WNC14A2AInterface

Dependents:   http-example-wnc http-example-wnc-modified

Committer:
root@developer-sjc-cyan-compiler.local.mbed.org
Date:
Sun Apr 23 18:40:51 2017 +0000
Revision:
5:391eac6a0a94
Parent:
0:2563b0415d1f
Added tag att_cellular_K64_wnc_14A2A_20170423 for changeset daf182af022b

Who changed what in which revision?

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