Version of easy-connect with the u-blox cellular platforms C027 and C030 added.
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 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 1.7.2