Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
ATParser.cpp
00001 /* Copyright (c) 2015 ARM Limited 00002 * 00003 * Licensed under the Apache License, Version 2.0 (the "License"); 00004 * you may not use this file except in compliance with the License. 00005 * You may obtain a copy of the License at 00006 * 00007 * http://www.apache.org/licenses/LICENSE-2.0 00008 * 00009 * Unless required by applicable law or agreed to in writing, software 00010 * distributed under the License is distributed on an "AS IS" BASIS, 00011 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00012 * See the License for the specific language governing permissions and 00013 * limitations under the License. 00014 * 00015 * @section DESCRIPTION 00016 * 00017 * Parser for the AT command syntax 00018 * 00019 */ 00020 00021 #include "ATParser.h" 00022 #include "mbed_debug.h" 00023 00024 #ifdef LF 00025 #undef LF 00026 #define LF 10 00027 #else 00028 #define LF 10 00029 #endif 00030 00031 #ifdef CR 00032 #undef CR 00033 #define CR 13 00034 #else 00035 #define CR 13 00036 #endif 00037 #define MIN(a,b) (((a)<(b))?(a):(b)) 00038 00039 // activate / de-activate debug 00040 #define dbg_on 0 00041 #define AT_DATA_PRINT 0 00042 #define AT_COMMAND_PRINT 0 00043 #define AT_HEXA_DATA 0 00044 00045 ATParser::ATParser(BufferedSpi &serial_spi, const char *delimiter, int buffer_size, int timeout) : 00046 _serial_spi(&serial_spi), 00047 _buffer_size(buffer_size), _in_prev(0), _oobs(NULL) 00048 { 00049 _buffer = new char[buffer_size]; 00050 setTimeout(timeout); 00051 setDelimiter(delimiter); 00052 } 00053 00054 00055 // getc/putc handling with timeouts 00056 int ATParser::putc(char c) 00057 { 00058 return _serial_spi->putc(c); 00059 } 00060 00061 int ATParser::getc() 00062 { 00063 return _serial_spi->getc(); 00064 } 00065 00066 void ATParser::flush() 00067 { 00068 _bufferMutex.lock(); 00069 while (_serial_spi->readable()) { 00070 _serial_spi->getc(); 00071 } 00072 _bufferMutex.unlock(); 00073 } 00074 00075 // read/write handling with timeouts 00076 int ATParser::write(const char *data, int size_of_data, int size_in_buff) 00077 { 00078 int i = 0; 00079 _bufferMutex.lock(); 00080 debug_if(dbg_on, "ATParser write: %d BYTES\r\n", size_of_data); 00081 debug_if(AT_DATA_PRINT, "ATParser write: (ASCII) ", size_of_data); 00082 for (; i < size_of_data; i++) { 00083 debug_if(AT_DATA_PRINT, "%c", data[i]); 00084 if (putc(data[i]) < 0) { 00085 debug_if(AT_DATA_PRINT, "\r\n"); 00086 _bufferMutex.unlock(); 00087 return -1; 00088 } 00089 } 00090 debug_if(AT_DATA_PRINT, "\r\n"); 00091 00092 _serial_spi->buffsend(size_of_data + size_in_buff); 00093 _bufferMutex.unlock(); 00094 00095 return (size_of_data + size_in_buff); 00096 } 00097 00098 int ATParser::read(char *data) 00099 { 00100 int readsize; 00101 int i = 0; 00102 00103 _bufferMutex.lock(); 00104 00105 //this->flush(); 00106 if (!_serial_spi->readable()) { 00107 readsize = _serial_spi->read(); 00108 } else { 00109 debug_if(dbg_on, "Pending data when reading from WIFI\r\n"); 00110 return -1; 00111 } 00112 00113 debug_if(dbg_on, "ATParser read: %d data avail in SPI\r\n", readsize); 00114 00115 if (readsize < 0) { 00116 _bufferMutex.unlock(); 00117 return -1; 00118 } 00119 00120 for (i = 0 ; i < readsize; i++) { 00121 int c = getc(); 00122 if (c < 0) { 00123 _bufferMutex.unlock(); 00124 return -1; 00125 } 00126 data[i] = c; 00127 } 00128 00129 #if AT_HEXA_DATA 00130 debug_if(AT_DATA_PRINT, "ATParser read: (HEXA) "); 00131 for (i = 0; i < readsize; i++) { 00132 debug_if(AT_DATA_PRINT, "%2X ", data[i]); 00133 if ((i + 1) % 20 == 0) { 00134 debug_if(AT_DATA_PRINT, "\r\n"); 00135 } 00136 } 00137 debug_if(AT_DATA_PRINT, "\r\n"); 00138 #endif 00139 debug_if(AT_DATA_PRINT, "ATParser read: (ASCII) "); 00140 for (i = 0; i < readsize; i++) { 00141 debug_if(AT_DATA_PRINT, "%c", data[i]); 00142 } 00143 debug_if(AT_DATA_PRINT, "\r\n"); 00144 00145 _bufferMutex.unlock(); 00146 00147 return (readsize); 00148 } 00149 00150 // printf/scanf handling 00151 int ATParser::vprintf(const char *format, va_list args) 00152 { 00153 _bufferMutex.lock(); 00154 if (vsprintf(_buffer, format, args) < 0) { 00155 _bufferMutex.unlock(); 00156 return false; 00157 } 00158 00159 int i = 0; 00160 for (; _buffer[i]; i++) { 00161 if (putc(_buffer[i]) < 0) { 00162 _bufferMutex.unlock(); 00163 return -1; 00164 } 00165 } 00166 _bufferMutex.unlock(); 00167 00168 return i; 00169 } 00170 00171 int ATParser::vscanf(const char *format, va_list args) 00172 { 00173 // Since format is const, we need to copy it into our buffer to 00174 // add the line's null terminator and clobber value-matches with asterisks. 00175 // 00176 // We just use the beginning of the buffer to avoid unnecessary allocations. 00177 int i = 0; 00178 int offset = 0; 00179 00180 _bufferMutex.lock(); 00181 00182 while (format[i]) { 00183 if (format[i] == '%' && format[i + 1] != '%' && format[i + 1] != '*') { 00184 _buffer[offset++] = '%'; 00185 _buffer[offset++] = '*'; 00186 i++; 00187 } else { 00188 _buffer[offset++] = format[i++]; 00189 } 00190 } 00191 00192 // Scanf has very poor support for catching errors 00193 // fortunately, we can abuse the %n specifier to determine 00194 // if the entire string was matched. 00195 _buffer[offset++] = '%'; 00196 _buffer[offset++] = 'n'; 00197 _buffer[offset++] = 0; 00198 00199 // To workaround scanf's lack of error reporting, we actually 00200 // make two passes. One checks the validity with the modified 00201 // format string that only stores the matched characters (%n). 00202 // The other reads in the actual matched values. 00203 // 00204 // We keep trying the match until we succeed or some other error 00205 // derails us. 00206 int j = 0; 00207 00208 while (true) { 00209 // Ran out of space 00210 if (j + 1 >= _buffer_size - offset) { 00211 _bufferMutex.unlock(); 00212 return false; 00213 } 00214 // Recieve next character 00215 int c = getc(); 00216 if (c < 0) { 00217 _bufferMutex.unlock(); 00218 return -1; 00219 } 00220 _buffer[offset + j++] = c; 00221 _buffer[offset + j] = 0; 00222 00223 // Check for match 00224 int count = -1; 00225 sscanf(_buffer + offset, _buffer, &count); 00226 00227 // We only succeed if all characters in the response are matched 00228 if (count == j) { 00229 // Store the found results 00230 vsscanf(_buffer + offset, format, args); 00231 _bufferMutex.unlock(); 00232 return j; 00233 } 00234 } 00235 } 00236 00237 00238 // Command parsing with line handling 00239 bool ATParser::vsend(const char *command, va_list args) 00240 { 00241 int i = 0, j = 0; 00242 _bufferMutex.lock(); 00243 // Create and send command 00244 if (vsprintf(_buffer, command, args) < 0) { 00245 _bufferMutex.unlock(); 00246 return false; 00247 } 00248 /* get buffer length */ 00249 for (i = 0; _buffer[i]; i++) { 00250 } 00251 00252 for (j = 0; _delimiter[j]; j++) { 00253 _buffer[i + j] = _delimiter[j]; 00254 } 00255 _buffer[i + j] = 0; // only to get a clean debug log 00256 00257 bool ret = !(_serial_spi->buffwrite(_buffer, i + j) < 0); 00258 00259 debug_if(AT_COMMAND_PRINT, "AT> %s\n", _buffer); 00260 _bufferMutex.unlock(); 00261 return ret; 00262 } 00263 00264 bool ATParser::vrecv(const char *response, va_list args) 00265 { 00266 _bufferMutex.lock(); 00267 00268 if (!_serial_spi->readable()) { 00269 // debug_if(dbg_on, "NO DATA, read again\r\n"); 00270 if (_serial_spi->read() < 0) { 00271 return false; 00272 } 00273 } 00274 // else { 00275 // debug_if(dbg_on, "Pending data\r\n"); 00276 // } 00277 00278 restart: 00279 _aborted = false; 00280 // Iterate through each line in the expected response 00281 while (response[0]) { 00282 // Since response is const, we need to copy it into our buffer to 00283 // add the line's null terminator and clobber value-matches with asterisks. 00284 // 00285 // We just use the beginning of the buffer to avoid unnecessary allocations. 00286 int i = 0; 00287 int offset = 0; 00288 bool whole_line_wanted = false; 00289 00290 while (response[i]) { 00291 if (response[i] == '%' && response[i + 1] != '%' && response[i + 1] != '*') { 00292 _buffer[offset++] = '%'; 00293 _buffer[offset++] = '*'; 00294 i++; 00295 } else { 00296 _buffer[offset++] = response[i++]; 00297 // Find linebreaks, taking care not to be fooled if they're in a %[^\n] conversion specification 00298 if (response[i - 1] == '\n' && !(i >= 3 && response[i - 3] == '[' && response[i - 2] == '^')) { 00299 whole_line_wanted = true; 00300 break; 00301 } 00302 } 00303 } 00304 00305 // Scanf has very poor support for catching errors 00306 // fortunately, we can abuse the %n specifier to determine 00307 // if the entire string was matched. 00308 _buffer[offset++] = '%'; 00309 _buffer[offset++] = 'n'; 00310 _buffer[offset++] = 0; 00311 00312 // debug_if(dbg_on, "ATParser vrecv: AT? ====%s====\n", _buffer); 00313 // To workaround scanf's lack of error reporting, we actually 00314 // make two passes. One checks the validity with the modified 00315 // format string that only stores the matched characters (%n). 00316 // The other reads in the actual matched values. 00317 // 00318 // We keep trying the match until we succeed or some other error 00319 // derails us. 00320 int j = 0; 00321 00322 while (true) { 00323 // Recieve next character 00324 int c = getc(); 00325 if (c < 0) { 00326 debug_if(dbg_on, "AT(Timeout)\n"); 00327 _bufferMutex.unlock(); 00328 return false; 00329 } 00330 00331 // debug_if(AT_DATA_PRINT, "%2X ", c); 00332 00333 _buffer[offset + j++] = c; 00334 _buffer[offset + j] = 0; 00335 00336 // Check for oob data 00337 for (struct oob *oob = _oobs; oob; oob = oob->next) { 00338 if ((unsigned)j == oob->len && memcmp( 00339 oob->prefix, _buffer + offset, oob->len) == 0) { 00340 debug_if(dbg_on, "AT! %s\n", oob->prefix); 00341 oob->cb(); 00342 00343 if (_aborted) { 00344 debug_if(dbg_on, "AT(Aborted)\n"); 00345 _bufferMutex.unlock(); 00346 return false; 00347 } 00348 // oob may have corrupted non-reentrant buffer, 00349 // so we need to set it up again 00350 goto restart; 00351 } 00352 } 00353 00354 // Check for match 00355 int count = -1; 00356 if (whole_line_wanted && c != '\n') { 00357 // Don't attempt scanning until we get delimiter if they included it in format 00358 // This allows recv("Foo: %s\n") to work, and not match with just the first character of a string 00359 // (scanf does not itself match whitespace in its format string, so \n is not significant to it) 00360 } else { 00361 sscanf(_buffer + offset, _buffer, &count); 00362 } 00363 00364 // We only succeed if all characters in the response are matched 00365 if (count == j) { 00366 debug_if(AT_COMMAND_PRINT, "AT= ====%s====\n", _buffer + offset); 00367 // Reuse the front end of the buffer 00368 memcpy(_buffer, response, i); 00369 _buffer[i] = 0; 00370 00371 // Store the found results 00372 vsscanf(_buffer + offset, _buffer, args); 00373 00374 // Jump to next line and continue parsing 00375 response += i; 00376 break; 00377 } 00378 00379 // Clear the buffer when we hit a newline or ran out of space 00380 // running out of space usually means we ran into binary data 00381 if ((c == '\n')) { 00382 // debug_if(dbg_on, "New line AT<<< %s", _buffer+offset); 00383 j = 0; 00384 } 00385 if ((j + 1 >= (_buffer_size - offset))) { 00386 00387 debug_if(dbg_on, "Out of space AT<<< %s, j=%d", _buffer + offset, j); 00388 j = 0; 00389 } 00390 } 00391 } 00392 00393 _bufferMutex.unlock(); 00394 00395 return true; 00396 } 00397 00398 00399 // Mapping to vararg functions 00400 int ATParser::printf(const char *format, ...) 00401 { 00402 va_list args; 00403 va_start(args, format); 00404 int res = vprintf(format, args); 00405 va_end(args); 00406 return res; 00407 } 00408 00409 int ATParser::scanf(const char *format, ...) 00410 { 00411 va_list args; 00412 va_start(args, format); 00413 int res = vscanf(format, args); 00414 va_end(args); 00415 return res; 00416 } 00417 00418 bool ATParser::send(const char *command, ...) 00419 { 00420 va_list args; 00421 va_start(args, command); 00422 bool res = vsend(command, args); 00423 va_end(args); 00424 return res; 00425 } 00426 00427 bool ATParser::recv(const char *response, ...) 00428 { 00429 va_list args; 00430 va_start(args, response); 00431 bool res = vrecv(response, args); 00432 va_end(args); 00433 return res; 00434 } 00435 00436 00437 // oob registration 00438 void ATParser::oob(const char *prefix, Callback<void()> cb) 00439 { 00440 struct oob *oob = new struct oob; 00441 oob->len = strlen(prefix); 00442 oob->prefix = prefix; 00443 oob->cb = cb; 00444 oob->next = _oobs; 00445 _oobs = oob; 00446 } 00447 00448 void ATParser::abort() 00449 { 00450 _aborted = true; 00451 } 00452 00453 00454
Generated on Mon Aug 29 2022 19:53:38 by
