Vergil Cola
/
MQTTGateway2
Fork of my original MQTTGateway
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 00025 // getc/putc handling with timeouts 00026 int ATParser::putc(char c) 00027 { 00028 Timer timer; 00029 timer.start(); 00030 00031 while (true) { 00032 if (_serial->writeable()) { 00033 return _serial->putc(c); 00034 } 00035 if (timer.read_ms() > _timeout) { 00036 return -1; 00037 } 00038 } 00039 } 00040 00041 int ATParser::getc() 00042 { 00043 Timer timer; 00044 timer.start(); 00045 00046 while (true) { 00047 if (_serial->readable()) { 00048 return _serial->getc(); 00049 } 00050 if (timer.read_ms() > _timeout) { 00051 return -1; 00052 } 00053 } 00054 } 00055 00056 void ATParser::flush() 00057 { 00058 while (_serial->readable()) { 00059 _serial->getc(); 00060 } 00061 } 00062 00063 00064 // read/write handling with timeouts 00065 int ATParser::write(const char *data, int size) 00066 { 00067 int i = 0; 00068 for ( ; i < size; i++) { 00069 if (putc(data[i]) < 0) { 00070 return -1; 00071 } 00072 } 00073 return i; 00074 } 00075 00076 int ATParser::read(char *data, int size) 00077 { 00078 int i = 0; 00079 for ( ; i < size; i++) { 00080 int c = getc(); 00081 if (c < 0) { 00082 return -1; 00083 } 00084 data[i] = c; 00085 } 00086 return i; 00087 } 00088 00089 00090 // printf/scanf handling 00091 int ATParser::vprintf(const char *format, va_list args) 00092 { 00093 if (vsprintf(_buffer, format, args) < 0) { 00094 return false; 00095 } 00096 int i = 0; 00097 for ( ; _buffer[i]; i++) { 00098 if (putc(_buffer[i]) < 0) { 00099 return -1; 00100 } 00101 } 00102 return i; 00103 } 00104 00105 int ATParser::vscanf(const char *format, va_list args) 00106 { 00107 // Since format is const, we need to copy it into our buffer to 00108 // add the line's null terminator and clobber value-matches with asterisks. 00109 // 00110 // We just use the beginning of the buffer to avoid unnecessary allocations. 00111 int i = 0; 00112 int offset = 0; 00113 00114 while (format[i]) { 00115 if (format[i] == '%' && format[i+1] != '%' && format[i+1] != '*') { 00116 _buffer[offset++] = '%'; 00117 _buffer[offset++] = '*'; 00118 i++; 00119 } else { 00120 _buffer[offset++] = format[i++]; 00121 } 00122 } 00123 00124 // Scanf has very poor support for catching errors 00125 // fortunately, we can abuse the %n specifier to determine 00126 // if the entire string was matched. 00127 _buffer[offset++] = '%'; 00128 _buffer[offset++] = 'n'; 00129 _buffer[offset++] = 0; 00130 00131 // To workaround scanf's lack of error reporting, we actually 00132 // make two passes. One checks the validity with the modified 00133 // format string that only stores the matched characters (%n). 00134 // The other reads in the actual matched values. 00135 // 00136 // We keep trying the match until we succeed or some other error 00137 // derails us. 00138 int j = 0; 00139 00140 while (true) { 00141 // Ran out of space 00142 if (j+1 >= _buffer_size - offset) { 00143 return false; 00144 } 00145 // Recieve next character 00146 int c = getc(); 00147 if (c < 0) { 00148 return -1; 00149 } 00150 _buffer[offset + j++] = c; 00151 _buffer[offset + j] = 0; 00152 00153 // Check for match 00154 int count = -1; 00155 sscanf(_buffer+offset, _buffer, &count); 00156 00157 // We only succeed if all characters in the response are matched 00158 if (count == j) { 00159 // Store the found results 00160 vsscanf(_buffer+offset, format, args); 00161 return j; 00162 } 00163 } 00164 } 00165 00166 00167 // Command parsing with line handling 00168 bool ATParser::vsend(const char *command, va_list args) 00169 { 00170 // Create and send command 00171 if (vsprintf(_buffer, command, args) < 0) { 00172 return false; 00173 } 00174 for (int i = 0; _buffer[i]; i++) { 00175 if (putc(_buffer[i]) < 0) { 00176 return false; 00177 } 00178 } 00179 00180 // Finish with newline 00181 for (int i = 0; _delimiter[i]; i++) { 00182 if (putc(_delimiter[i]) < 0) { 00183 return false; 00184 } 00185 } 00186 00187 debug_if(dbg_on, "AT> %s\r\n", _buffer); 00188 return true; 00189 } 00190 00191 bool ATParser::vrecv(const char *response, va_list args) 00192 { 00193 // Iterate through each line in the expected response 00194 while (response[0]) { 00195 // Since response is const, we need to copy it into our buffer to 00196 // add the line's null terminator and clobber value-matches with asterisks. 00197 // 00198 // We just use the beginning of the buffer to avoid unnecessary allocations. 00199 int i = 0; 00200 int offset = 0; 00201 00202 while (response[i]) { 00203 if (memcmp(&response[i+1-_delim_size], _delimiter, _delim_size) == 0) { 00204 i++; 00205 break; 00206 } else if (response[i] == '%' && response[i+1] != '%' && response[i+1] != '*') { 00207 _buffer[offset++] = '%'; 00208 _buffer[offset++] = '*'; 00209 i++; 00210 } else { 00211 _buffer[offset++] = response[i++]; 00212 } 00213 } 00214 00215 // Scanf has very poor support for catching errors 00216 // fortunately, we can abuse the %n specifier to determine 00217 // if the entire string was matched. 00218 _buffer[offset++] = '%'; 00219 _buffer[offset++] = 'n'; 00220 _buffer[offset++] = 0; 00221 00222 // To workaround scanf's lack of error reporting, we actually 00223 // make two passes. One checks the validity with the modified 00224 // format string that only stores the matched characters (%n). 00225 // The other reads in the actual matched values. 00226 // 00227 // We keep trying the match until we succeed or some other error 00228 // derails us. 00229 int j = 0; 00230 00231 while (true) { 00232 // Recieve next character 00233 int c = getc(); 00234 if (c < 0) { 00235 return false; 00236 } 00237 _buffer[offset + j++] = c; 00238 _buffer[offset + j] = 0; 00239 00240 // Check for oob data 00241 for (int k = 0; k < _oobs.size(); k++) { 00242 if (j == _oobs[k].len && memcmp( 00243 _oobs[k].prefix, _buffer+offset, _oobs[k].len) == 0) { 00244 debug_if(dbg_on, "AT! %s\r\n", _oobs[k].prefix); 00245 _oobs[k].cb(); 00246 00247 // oob may have corrupted non-reentrant buffer, 00248 // so we need to set it up again 00249 return vrecv(response, args); 00250 } 00251 } 00252 00253 // Check for match 00254 int count = -1; 00255 sscanf(_buffer+offset, _buffer, &count); 00256 00257 // We only succeed if all characters in the response are matched 00258 if (count == j) { 00259 debug_if(dbg_on, "AT= %s\r\n", _buffer+offset); 00260 // Reuse the front end of the buffer 00261 memcpy(_buffer, response, i); 00262 _buffer[i] = 0; 00263 00264 // Store the found results 00265 vsscanf(_buffer+offset, _buffer, args); 00266 00267 // Jump to next line and continue parsing 00268 response += i; 00269 break; 00270 } 00271 00272 // Clear the buffer when we hit a newline or ran out of space 00273 // running out of space usually means we ran into binary data 00274 if (j+1 >= _buffer_size - offset || 00275 strcmp(&_buffer[offset + j-_delim_size], _delimiter) == 0) { 00276 00277 debug_if(dbg_on, "AT< %s", _buffer+offset); 00278 j = 0; 00279 } 00280 } 00281 } 00282 00283 return true; 00284 } 00285 00286 00287 // Mapping to vararg functions 00288 int ATParser::printf(const char *format, ...) 00289 { 00290 va_list args; 00291 va_start(args, format); 00292 int res = vprintf(format, args); 00293 va_end(args); 00294 return res; 00295 } 00296 00297 int ATParser::scanf(const char *format, ...) 00298 { 00299 va_list args; 00300 va_start(args, format); 00301 int res = vscanf(format, args); 00302 va_end(args); 00303 return res; 00304 } 00305 00306 bool ATParser::send(const char *command, ...) 00307 { 00308 va_list args; 00309 va_start(args, command); 00310 bool res = vsend(command, args); 00311 va_end(args); 00312 return res; 00313 } 00314 00315 bool ATParser::recv(const char *response, ...) 00316 { 00317 va_list args; 00318 va_start(args, response); 00319 bool res = vrecv(response, args); 00320 va_end(args); 00321 return res; 00322 } 00323 00324 00325 // oob registration 00326 void ATParser::oob(const char *prefix, Callback<void()> cb) 00327 { 00328 struct oob oob; 00329 oob.len = strlen(prefix); 00330 oob.prefix = prefix; 00331 oob.cb = cb; 00332 _oobs.push_back(oob); 00333 }
Generated on Tue Jul 12 2022 18:06:45 by 1.7.2