Simulated product dispenser
Fork of mbed-cloud-workshop-connect-HTS221 by
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 Tue Jul 12 2022 19:12:11 by 1.7.2