Simulated product dispenser

Dependencies:   HTS221

Fork of mbed-cloud-workshop-connect-HTS221 by Jim Carver

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers ATParser.cpp Source File

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