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 00175 for (int i = 0; _buffer[i]; i++) { 00176 if (putc(_buffer[i]) < 0) { 00177 return false; 00178 } 00179 } 00180 00181 // Finish with newline// 00182 char s[] = "\x0d"; 00183 for (int i = 0; s[i]; i++){ 00184 if(putc(s[i]) < 0) 00185 printf("send <CR> error\n"); 00186 } 00187 00188 debug_if(dbg_on, "AT> %s\r\n", _buffer); 00189 return true; 00190 } 00191 00192 bool ATParser::vrecv(const char *response, va_list args) 00193 { 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 //printf("111111111c= %d\n", c); 00236 if (c < 0) { 00237 return false; 00238 } 00239 00240 if (c == 0x0d) 00241 c = '#'; 00242 00243 _buffer[offset + j++] = c; 00244 _buffer[offset + j] = 0; 00245 00246 // Check for oob data 00247 for (int k = 0; k < _oobs.size(); k++) { 00248 if (j == _oobs[k].len && memcmp( 00249 _oobs[k].prefix, _buffer+offset, _oobs[k].len) == 0) { 00250 debug_if(dbg_on, "AT! %s\r\n", _oobs[k].prefix); 00251 _oobs[k].cb(); 00252 00253 // oob may have corrupted non-reentrant buffer, 00254 // so we need to set it up again 00255 return vrecv(response, args); 00256 } 00257 } 00258 00259 // Check for match 00260 int count = -1; 00261 sscanf(_buffer+offset, _buffer, &count); 00262 //printf("_buffer+offset is %s, _buffer is %s\n", _buffer+offset, _buffer); 00263 00264 // We only succeed if all characters in the response are matched 00265 if (count == j) { 00266 debug_if(dbg_on, "AT= %s\r\n", _buffer+offset); 00267 // Reuse the front end of the buffer 00268 memcpy(_buffer, response, i); 00269 _buffer[i] = 0; 00270 00271 // Store the found results 00272 vsscanf(_buffer+offset, _buffer, args); 00273 00274 // Jump to next line and continue parsing 00275 response += i; 00276 break; 00277 } 00278 00279 // Clear the buffer when we hit a newline or ran out of space 00280 // running out of space usually means we ran into binary data 00281 if (c == '\n' || j+1 >= _buffer_size - offset || 00282 strcmp(&_buffer[offset + j-_delim_size], _delimiter) == 0) { 00283 00284 debug_if(dbg_on, "AT< %s", _buffer+offset); 00285 j = 0; 00286 } 00287 } 00288 } 00289 00290 return true; 00291 } 00292 00293 00294 //// Mapping to vararg functions 00295 //int ATParser::printf(const char *format, ...) 00296 //{ 00297 // va_list args; 00298 // va_start(args, format); 00299 // int res = vprintf(format, args); 00300 // va_end(args); 00301 // return res; 00302 //} 00303 00304 int ATParser::scanf(const char *format, ...) 00305 { 00306 va_list args; 00307 va_start(args, format); 00308 int res = vscanf(format, args); 00309 va_end(args); 00310 return res; 00311 } 00312 00313 bool ATParser::send(const char *command, ...) 00314 { 00315 va_list args; 00316 va_start(args, command); 00317 bool res = vsend(command, args); 00318 va_end(args); 00319 return res; 00320 } 00321 00322 bool ATParser::recv(const char *response, ...) 00323 { 00324 va_list args; 00325 va_start(args, response); 00326 bool res = vrecv(response, args); 00327 va_end(args); 00328 return res; 00329 } 00330 00331 00332 // oob registration 00333 void ATParser::oob(const char *prefix, Callback<void()> cb) 00334 { 00335 struct oob oob; 00336 oob.len = strlen(prefix); 00337 oob.prefix = prefix; 00338 oob.cb = cb; 00339 _oobs.push_back(oob); 00340 }
Generated on Fri Jul 15 2022 08:03:00 by
1.7.2