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.
Fork of ATParser by
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 match 00241 int count = -1; 00242 sscanf(_buffer+offset, _buffer, &count); 00243 00244 // We only succeed if all characters in the response are matched 00245 if (count == j) { 00246 debug_if(dbg_on, "AT= %s\r\n", _buffer+offset); 00247 // Reuse the front end of the buffer 00248 memcpy(_buffer, response, i); 00249 _buffer[i] = 0; 00250 00251 // Store the found results 00252 vsscanf(_buffer+offset, _buffer, args); 00253 00254 // Jump to next line and continue parsing 00255 response += i; 00256 break; 00257 } 00258 00259 // Clear the buffer when we hit a newline or ran out of space 00260 // running out of space usually means we ran into binary data 00261 if (j+1 >= _buffer_size - offset || 00262 strcmp(&_buffer[offset + j-_delim_size], _delimiter) == 0) { 00263 00264 debug_if(dbg_on, "AT< %s", _buffer+offset); 00265 j = 0; 00266 } 00267 } 00268 } 00269 00270 return true; 00271 } 00272 00273 00274 // Mapping to vararg functions 00275 int ATParser::printf(const char *format, ...) 00276 { 00277 va_list args; 00278 va_start(args, format); 00279 int res = vprintf(format, args); 00280 va_end(args); 00281 return res; 00282 } 00283 00284 int ATParser::scanf(const char *format, ...) 00285 { 00286 va_list args; 00287 va_start(args, format); 00288 int res = vscanf(format, args); 00289 va_end(args); 00290 return res; 00291 } 00292 00293 bool ATParser::send(const char *command, ...) 00294 { 00295 va_list args; 00296 va_start(args, command); 00297 bool res = vsend(command, args); 00298 va_end(args); 00299 return res; 00300 } 00301 00302 bool ATParser::recv(const char *response, ...) 00303 { 00304 va_list args; 00305 va_start(args, response); 00306 bool res = vrecv(response, args); 00307 va_end(args); 00308 return res; 00309 }
Generated on Tue Jul 26 2022 02:33:47 by
