ATParser for X-NUCLEO-IDW01M1 module
Dependencies: BufferedSerial
Dependents: SPWF01SA-lapi-1 SPWF01SA Nucleo-AWS-IoT-mbed
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 CR "\r" 00181 //for (int i = 0; _delimiter[i]; i++) { 00182 if (putc(_delimiter[0]) < 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 bool delim_recv = false; 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 // Receive 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 match 00242 int count = -1; 00243 sscanf(_buffer+offset, _buffer, &count); 00244 00245 // We only succeed if all characters in the response are matched 00246 if(count==j) { 00247 //check if last input is a number 00248 if (_buffer[offset-6]=='%' && _buffer[offset-5]=='*' 00249 && (_buffer[offset-4]=='x' || _buffer[offset-4]=='d' || _buffer[offset-4]=='u')) 00250 { 00251 //if the last char is a number, keep getting the next character till CR 00252 while(true) 00253 { 00254 int c = getc(); 00255 if (c < 0) { 00256 return false; 00257 } 00258 if(c==0xD) {//there is no next number so exit from condition 00259 c = getc();//get rid of the following '\n' delimiter 00260 delim_recv = true; 00261 break; 00262 } 00263 else { 00264 _buffer[offset + j++] = c; 00265 _buffer[offset + j] = 0; 00266 } 00267 } 00268 } 00269 00270 debug_if(dbg_on, "AT= %s\r\n", _buffer+offset); 00271 // Reuse the front end of the buffer 00272 memcpy(_buffer, response, i); 00273 _buffer[i] = 0; 00274 00275 // Store the found results 00276 vsscanf(_buffer+offset, _buffer, args); 00277 00278 // Jump to next line and continue parsing 00279 response += i; 00280 00281 // receive trailing delimiters 00282 for(int i=0; !delim_recv && i<_delim_size; i++) { 00283 c = getc(); 00284 if(c < 0) 00285 break; 00286 } 00287 break; 00288 } 00289 00290 // Clear the buffer when we hit a newline or ran out of space 00291 // running out of space usually means we ran into binary data 00292 if (j+1 >= _buffer_size - offset || 00293 strcmp(&_buffer[offset + j-_delim_size], _delimiter) == 0) { 00294 00295 debug_if(dbg_on, "AT< %s", _buffer+offset); 00296 j = 0; 00297 } 00298 } 00299 } 00300 00301 return true; 00302 } 00303 00304 00305 // Mapping to vararg functions 00306 int ATParser::printf(const char *format, ...) 00307 { 00308 va_list args; 00309 va_start(args, format); 00310 int res = vprintf(format, args); 00311 va_end(args); 00312 return res; 00313 } 00314 00315 int ATParser::scanf(const char *format, ...) 00316 { 00317 va_list args; 00318 va_start(args, format); 00319 int res = vscanf(format, args); 00320 va_end(args); 00321 return res; 00322 } 00323 00324 bool ATParser::send(const char *command, ...) 00325 { 00326 va_list args; 00327 va_start(args, command); 00328 bool res = vsend(command, args); 00329 va_end(args); 00330 return res; 00331 } 00332 00333 bool ATParser::recv(const char *response, ...) 00334 { 00335 va_list args; 00336 va_start(args, response); 00337 bool res = vrecv(response, args); 00338 va_end(args); 00339 return res; 00340 }
Generated on Tue Jul 12 2022 18:49:22 by 1.7.2