Toyomasa Watarai
/
Mbed-example-WS-W27
Mbed Cloud example program for workshop in W27 2018.
Embed:
(wiki syntax)
Show/hide line numbers
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 #define dbg_on 0 00040 //#define TRACE_AT_DATA 1 00041 00042 // getc/putc handling with timeouts 00043 int ATParser::putc(char c) 00044 { 00045 return _serial_spi->putc(c); 00046 } 00047 00048 int ATParser::getc() 00049 { 00050 return _serial_spi->getc(); 00051 } 00052 00053 void ATParser::flush() 00054 { 00055 _bufferMutex.lock(); 00056 while (_serial_spi->readable()) { 00057 _serial_spi->getc(); 00058 } 00059 _bufferMutex.unlock(); 00060 } 00061 00062 // read/write handling with timeouts 00063 int ATParser::write(const char *data, int size_of_data, int size_in_buff) 00064 { 00065 int i = 0; 00066 _bufferMutex.lock(); 00067 for ( ; i < size_of_data; i++) { 00068 if (putc(data[i]) < 0) { 00069 _bufferMutex.unlock(); 00070 return -1; 00071 } 00072 } 00073 00074 _serial_spi->buffsend(size_of_data + size_in_buff); 00075 _bufferMutex.unlock(); 00076 return (size_of_data + size_in_buff); 00077 } 00078 00079 int ATParser::read(char *data) 00080 { 00081 int readsize; 00082 int i = 0; 00083 00084 _bufferMutex.lock(); 00085 00086 //this->flush(); 00087 if(!_serial_spi->readable()) { 00088 readsize = _serial_spi->read(); 00089 } else { 00090 error("Pending data when reading from WIFI\r\n"); 00091 return -1; 00092 } 00093 00094 debug_if(dbg_on, "Avail in SPI %d\r\n", readsize); 00095 00096 if ( readsize < 0) { 00097 _bufferMutex.unlock(); 00098 return -1; 00099 } 00100 00101 for (i = 0 ; i < readsize; i++) { 00102 int c = getc(); 00103 if (c < 0) { 00104 _bufferMutex.unlock(); 00105 return -1; 00106 } 00107 data[i] = c; 00108 } 00109 00110 #if TRACE_AT_DATA 00111 debug_if(dbg_on, "AT<< %d BYTES\r\n", readsize); 00112 for (i = 0; i < readsize; i++) { 00113 debug_if(dbg_on, "%2X ", data[i]); 00114 } 00115 debug_if(dbg_on, "\r\n"); 00116 #endif 00117 00118 _bufferMutex.unlock(); 00119 00120 return (readsize); 00121 } 00122 00123 // printf/scanf handling 00124 int ATParser::vprintf(const char *format, va_list args) 00125 { 00126 _bufferMutex.lock(); 00127 if (vsprintf(_buffer, format, args) < 0) { 00128 _bufferMutex.unlock(); 00129 return false; 00130 } 00131 00132 int i = 0; 00133 for ( ; _buffer[i]; i++) { 00134 if (putc(_buffer[i]) < 0) { 00135 _bufferMutex.unlock(); 00136 return -1; 00137 } 00138 } 00139 _bufferMutex.unlock(); 00140 00141 return i; 00142 } 00143 00144 int ATParser::vscanf(const char *format, va_list args) 00145 { 00146 // Since format is const, we need to copy it into our buffer to 00147 // add the line's null terminator and clobber value-matches with asterisks. 00148 // 00149 // We just use the beginning of the buffer to avoid unnecessary allocations. 00150 int i = 0; 00151 int offset = 0; 00152 00153 _bufferMutex.lock(); 00154 00155 while (format[i]) { 00156 if (format[i] == '%' && format[i+1] != '%' && format[i+1] != '*') { 00157 _buffer[offset++] = '%'; 00158 _buffer[offset++] = '*'; 00159 i++; 00160 } else { 00161 _buffer[offset++] = format[i++]; 00162 } 00163 } 00164 00165 // Scanf has very poor support for catching errors 00166 // fortunately, we can abuse the %n specifier to determine 00167 // if the entire string was matched. 00168 _buffer[offset++] = '%'; 00169 _buffer[offset++] = 'n'; 00170 _buffer[offset++] = 0; 00171 00172 // To workaround scanf's lack of error reporting, we actually 00173 // make two passes. One checks the validity with the modified 00174 // format string that only stores the matched characters (%n). 00175 // The other reads in the actual matched values. 00176 // 00177 // We keep trying the match until we succeed or some other error 00178 // derails us. 00179 int j = 0; 00180 00181 while (true) { 00182 // Ran out of space 00183 if (j+1 >= _buffer_size - offset) { 00184 _bufferMutex.unlock(); 00185 return false; 00186 } 00187 // Recieve next character 00188 int c = getc(); 00189 if (c < 0) { 00190 _bufferMutex.unlock(); 00191 return -1; 00192 } 00193 _buffer[offset + j++] = c; 00194 _buffer[offset + j] = 0; 00195 00196 // Check for match 00197 int count = -1; 00198 sscanf(_buffer+offset, _buffer, &count); 00199 00200 // We only succeed if all characters in the response are matched 00201 if (count == j) { 00202 // Store the found results 00203 vsscanf(_buffer+offset, format, args); 00204 _bufferMutex.unlock(); 00205 return j; 00206 } 00207 } 00208 } 00209 00210 00211 // Command parsing with line handling 00212 bool ATParser::vsend(const char *command, va_list args) 00213 { 00214 int i=0, j=0; 00215 _bufferMutex.lock(); 00216 // Create and send command 00217 if (vsprintf(_buffer, command, args) < 0) { 00218 _bufferMutex.unlock(); 00219 return false; 00220 } 00221 /* get buffer length */ 00222 for (i = 0; _buffer[i]; i++) { 00223 } 00224 00225 for (j=0; _delimiter[j]; j++) { 00226 _buffer[i+j] = _delimiter[j]; 00227 } 00228 _buffer[i+j]=0; // only to get a clean debug log 00229 00230 bool ret = !(_serial_spi->buffwrite(_buffer, i+j) < 0); 00231 00232 debug_if(dbg_on, "AT> %s\n", _buffer); 00233 _bufferMutex.unlock(); 00234 return ret; 00235 } 00236 00237 bool ATParser::vrecv(const char *response, va_list args) 00238 { 00239 _bufferMutex.lock(); 00240 /* Read from the wifi module, fill _rxbuffer */ 00241 //this->flush(); 00242 if(!_serial_spi->readable()) { 00243 debug_if(dbg_on, "NO DATA, read again\r\n"); 00244 if (_serial_spi->read() < 0) { 00245 return false; 00246 } 00247 } else { 00248 debug_if(dbg_on, "Pending data\r\n"); 00249 } 00250 restart: 00251 _aborted = false; 00252 // Iterate through each line in the expected response 00253 while (response[0]) { 00254 // Since response is const, we need to copy it into our buffer to 00255 // add the line's null terminator and clobber value-matches with asterisks. 00256 // 00257 // We just use the beginning of the buffer to avoid unnecessary allocations. 00258 int i = 0; 00259 int offset = 0; 00260 bool whole_line_wanted = false; 00261 00262 while (response[i]) { 00263 if (response[i] == '%' && response[i+1] != '%' && response[i+1] != '*') { 00264 _buffer[offset++] = '%'; 00265 _buffer[offset++] = '*'; 00266 i++; 00267 } else { 00268 _buffer[offset++] = response[i++]; 00269 // Find linebreaks, taking care not to be fooled if they're in a %[^\n] conversion specification 00270 if (response[i - 1] == '\n' && !(i >= 3 && response[i-3] == '[' && response[i-2] == '^')) { 00271 whole_line_wanted = true; 00272 break; 00273 } 00274 } 00275 } 00276 00277 // Scanf has very poor support for catching errors 00278 // fortunately, we can abuse the %n specifier to determine 00279 // if the entire string was matched. 00280 _buffer[offset++] = '%'; 00281 _buffer[offset++] = 'n'; 00282 _buffer[offset++] = 0; 00283 00284 debug_if(dbg_on, "AT? ====%s====\n", _buffer); 00285 // To workaround scanf's lack of error reporting, we actually 00286 // make two passes. One checks the validity with the modified 00287 // format string that only stores the matched characters (%n). 00288 // The other reads in the actual matched values. 00289 // 00290 // We keep trying the match until we succeed or some other error 00291 // derails us. 00292 int j = 0; 00293 00294 while (true) { 00295 // Recieve next character 00296 int c = getc(); 00297 if (c < 0) { 00298 debug_if(dbg_on, "AT(Timeout)\n"); 00299 _bufferMutex.unlock(); 00300 return false; 00301 } 00302 00303 #if TRACE_AT_DATA 00304 debug_if(dbg_on, "%2X ", c); 00305 #endif 00306 _buffer[offset + j++] = c; 00307 _buffer[offset + j] = 0; 00308 00309 // Check for oob data 00310 for (struct oob *oob = _oobs; oob; oob = oob->next) { 00311 if ((unsigned)j == oob->len && memcmp( 00312 oob->prefix, _buffer+offset, oob->len) == 0) { 00313 debug_if(dbg_on, "AT! %s\n", oob->prefix); 00314 oob->cb(); 00315 00316 if (_aborted) { 00317 debug_if(dbg_on, "AT(Aborted)\n"); 00318 _bufferMutex.unlock(); 00319 return false; 00320 } 00321 // oob may have corrupted non-reentrant buffer, 00322 // so we need to set it up again 00323 goto restart; 00324 } 00325 } 00326 00327 // Check for match 00328 int count = -1; 00329 if (whole_line_wanted && c != '\n') { 00330 // Don't attempt scanning until we get delimiter if they included it in format 00331 // This allows recv("Foo: %s\n") to work, and not match with just the first character of a string 00332 // (scanf does not itself match whitespace in its format string, so \n is not significant to it) 00333 } else { 00334 sscanf(_buffer+offset, _buffer, &count); 00335 } 00336 00337 // We only succeed if all characters in the response are matched 00338 if (count == j) { 00339 debug_if(dbg_on, "AT= ====%s====\n", _buffer + offset); 00340 // Reuse the front end of the buffer 00341 memcpy(_buffer, response, i); 00342 _buffer[i] = 0; 00343 00344 // Store the found results 00345 vsscanf(_buffer+offset, _buffer, args); 00346 00347 // Jump to next line and continue parsing 00348 response += i; 00349 break; 00350 } 00351 00352 // Clear the buffer when we hit a newline or ran out of space 00353 // running out of space usually means we ran into binary data 00354 if ((c == '\n') ) { 00355 debug_if(dbg_on, "New line AT<<< %s", _buffer+offset); 00356 j = 0; 00357 } 00358 if ((j + 1 >= (_buffer_size - offset))) { 00359 00360 debug_if(dbg_on, "Out of space AT<<< %s, j=%d", _buffer+offset, j); 00361 j = 0; 00362 } 00363 } 00364 } 00365 00366 _bufferMutex.unlock(); 00367 00368 return true; 00369 } 00370 00371 00372 // Mapping to vararg functions 00373 int ATParser::printf(const char *format, ...) 00374 { 00375 va_list args; 00376 va_start(args, format); 00377 int res = vprintf(format, args); 00378 va_end(args); 00379 return res; 00380 } 00381 00382 int ATParser::scanf(const char *format, ...) 00383 { 00384 va_list args; 00385 va_start(args, format); 00386 int res = vscanf(format, args); 00387 va_end(args); 00388 return res; 00389 } 00390 00391 bool ATParser::send(const char *command, ...) 00392 { 00393 va_list args; 00394 va_start(args, command); 00395 bool res = vsend(command, args); 00396 va_end(args); 00397 return res; 00398 } 00399 00400 bool ATParser::recv(const char *response, ...) 00401 { 00402 va_list args; 00403 va_start(args, response); 00404 bool res = vrecv(response, args); 00405 va_end(args); 00406 return res; 00407 } 00408 00409 00410 // oob registration 00411 void ATParser::oob(const char *prefix, Callback<void()> cb) 00412 { 00413 struct oob *oob = new struct oob; 00414 oob->len = strlen(prefix); 00415 oob->prefix = prefix; 00416 oob->cb = cb; 00417 oob->next = _oobs; 00418 _oobs = oob; 00419 } 00420 00421 void ATParser::abort() 00422 { 00423 _aborted = true; 00424 } 00425 00426 00427
Generated on Tue Jul 12 2022 16:22:04 by 1.7.2