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 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 vrecv_start: 00194 // Iterate through each line in the expected response 00195 while (response[0]) { 00196 // Since response is const, we need to copy it into our buffer to 00197 // add the line's null terminator and clobber value-matches with asterisks. 00198 // 00199 // We just use the beginning of the buffer to avoid unnecessary allocations. 00200 int i = 0; 00201 int offset = 0; 00202 00203 while (response[i]) { 00204 if (memcmp(&response[i+1-_delim_size], _delimiter, _delim_size) == 0) { 00205 i++; 00206 break; 00207 } else if (response[i] == '%' && response[i+1] != '%' && response[i+1] != '*') { 00208 _buffer[offset++] = '%'; 00209 _buffer[offset++] = '*'; 00210 i++; 00211 } else { 00212 _buffer[offset++] = response[i++]; 00213 } 00214 } 00215 00216 // Scanf has very poor support for catching errors 00217 // fortunately, we can abuse the %n specifier to determine 00218 // if the entire string was matched. 00219 _buffer[offset++] = '%'; 00220 _buffer[offset++] = 'n'; 00221 _buffer[offset++] = 0; 00222 00223 // To workaround scanf's lack of error reporting, we actually 00224 // make two passes. One checks the validity with the modified 00225 // format string that only stores the matched characters (%n). 00226 // The other reads in the actual matched values. 00227 // 00228 // We keep trying the match until we succeed or some other error 00229 // derails us. 00230 int j = 0; 00231 00232 while (true) { 00233 // Recieve next character 00234 int c = getc(); 00235 if (c < 0) { 00236 return false; 00237 } 00238 _buffer[offset + j++] = c; 00239 _buffer[offset + j] = 0; 00240 00241 // Check for oob data 00242 for (int k = 0; k < _oobs.size(); k++) { 00243 if (j == _oobs[k].len && memcmp( 00244 _oobs[k].prefix, _buffer+offset, _oobs[k].len) == 0) { 00245 debug_if(dbg_on, "AT! %s\r\n", _oobs[k].prefix); 00246 _oobs[k].cb(); 00247 00248 // oob may have corrupted non-reentrant buffer, 00249 // so we need to set it up again. 00250 // Use goto to save stack usage rather than a 00251 // recursive approach. 00252 goto vrecv_start; 00253 } 00254 } 00255 00256 // Check for match 00257 int count = -1; 00258 sscanf(_buffer+offset, _buffer, &count); 00259 00260 // We only succeed if all characters in the response are matched 00261 if (count == j) { 00262 debug_if(dbg_on, "AT= %s\r\n", _buffer+offset); 00263 // Reuse the front end of the buffer 00264 memcpy(_buffer, response, i); 00265 _buffer[i] = 0; 00266 00267 // Store the found results 00268 vsscanf(_buffer+offset, _buffer, args); 00269 00270 // Jump to next line and continue parsing 00271 response += i; 00272 break; 00273 } 00274 00275 // Clear the buffer when we hit a newline or ran out of space 00276 // running out of space usually means we ran into binary data 00277 if (j+1 >= _buffer_size - offset || 00278 strcmp(&_buffer[offset + j-_delim_size], _delimiter) == 0) { 00279 00280 debug_if(dbg_on, "AT< %s", _buffer+offset); 00281 j = 0; 00282 } 00283 } 00284 } 00285 00286 return true; 00287 } 00288 00289 00290 // Mapping to vararg functions 00291 int ATParser::printf(const char *format, ...) 00292 { 00293 va_list args; 00294 va_start(args, format); 00295 int res = vprintf(format, args); 00296 va_end(args); 00297 return res; 00298 } 00299 00300 int ATParser::scanf(const char *format, ...) 00301 { 00302 va_list args; 00303 va_start(args, format); 00304 int res = vscanf(format, args); 00305 va_end(args); 00306 return res; 00307 } 00308 00309 bool ATParser::send(const char *command, ...) 00310 { 00311 va_list args; 00312 va_start(args, command); 00313 bool res = vsend(command, args); 00314 va_end(args); 00315 return res; 00316 } 00317 00318 bool ATParser::recv(const char *response, ...) 00319 { 00320 va_list args; 00321 va_start(args, response); 00322 bool res = vrecv(response, args); 00323 va_end(args); 00324 return res; 00325 } 00326 00327 00328 // oob registration 00329 void ATParser::oob(const char *prefix, Callback<void()> cb) 00330 { 00331 struct oob oob; 00332 oob.len = strlen(prefix); 00333 oob.prefix = prefix; 00334 oob.cb = cb; 00335 _oobs.push_back(oob); 00336 }
Generated on Tue Jul 12 2022 15:14:29 by
