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.
ATHandler.h
00001 /* 00002 * Copyright (c) 2017, Arm Limited and affiliates. 00003 * SPDX-License-Identifier: Apache-2.0 00004 * 00005 * Licensed under the Apache License, Version 2.0 (the "License"); 00006 * you may not use this file except in compliance with the License. 00007 * You may obtain a copy of the License at 00008 * 00009 * http://www.apache.org/licenses/LICENSE-2.0 00010 * 00011 * Unless required by applicable law or agreed to in writing, software 00012 * distributed under the License is distributed on an "AS IS" BASIS, 00013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00014 * See the License for the specific language governing permissions and 00015 * limitations under the License. 00016 */ 00017 00018 #ifndef AT_HANDLER_H_ 00019 #define AT_HANDLER_H_ 00020 00021 #include "platform/mbed_retarget.h" 00022 #include "stdio.h" 00023 00024 #include "EventQueue.h" 00025 #include "PlatformMutex.h" 00026 #include "nsapi_types.h" 00027 00028 #include "PlatformMutex.h" 00029 #include "Callback.h" 00030 #include "EventQueue.h" 00031 00032 namespace mbed { 00033 00034 class FileHandle; 00035 00036 /** 00037 * If application calls associated FileHandle only from single thread context 00038 * then locking between AT command and response is not needed. However, 00039 * note that many cellular functions are called indirectly, for example with the socket API. 00040 * If you are unsure, then AT_HANDLER_MUTEX must be defined. 00041 */ 00042 #define AT_HANDLER_MUTEX 00043 00044 extern const char *OK; 00045 extern const char *CRLF; 00046 00047 #define BUFF_SIZE 16 00048 00049 /* AT Error types enumeration */ 00050 enum DeviceErrorType { 00051 DeviceErrorTypeNoError = 0, 00052 DeviceErrorTypeError, // AT ERROR 00053 DeviceErrorTypeErrorCMS, // AT ERROR CMS 00054 DeviceErrorTypeErrorCME // AT ERROR CME 00055 }; 00056 00057 /* struct used when getting at response error. Defines error code and type */ 00058 struct device_err_t { 00059 DeviceErrorType errType; 00060 int errCode; 00061 }; 00062 00063 /** Class ATHandler 00064 * 00065 * Class for sending AT commands and parsing AT responses. 00066 */ 00067 class ATHandler 00068 { 00069 00070 public: 00071 /** Constructor 00072 * 00073 * @param fh file handle used for reading AT responses and writing AT commands 00074 * @param queue Event queue used to transfer sigio events to this thread 00075 * @param timeout Timeout when reading for AT response 00076 * @param output_delimiter delimiter used when parsing at responses, "\r" should be used as output_delimiter 00077 */ 00078 ATHandler(FileHandle *fh, events::EventQueue &queue, int timeout, const char *output_delimiter); 00079 ~ATHandler(); 00080 00081 /** Return used file handle. 00082 * 00083 * @return used file handle 00084 */ 00085 FileHandle *get_file_handle(); 00086 00087 /** Set file handle, which is used for reading AT responses and writing AT commands 00088 * 00089 * @param fh file handle used for reading AT responses and writing AT commands 00090 */ 00091 void set_file_handle(FileHandle *fh); 00092 00093 /** Locks the mutex for file handle if AT_HANDLER_MUTEX is defined. 00094 */ 00095 void lock(); 00096 00097 /** Unlocks the mutex for file handle if AT_HANDLER_MUTEX is defined. 00098 */ 00099 void unlock(); 00100 00101 /** Locks the mutex for file handle if AT_HANDLER_MUTEX is defined and returns the last error. 00102 * 00103 * @return last error that happened when parsing AT responses 00104 */ 00105 nsapi_error_t unlock_return_error(); 00106 00107 /** Set the urc callback for urc. If urc is found when parsing AT responses, then call if called. 00108 * 00109 * @param prefix Register urc prefix for callback. Urc could be for example "+CMTI: " 00110 * @param callback Callback, which is called if urc is found in AT response 00111 */ 00112 void set_urc_handler(const char *prefix, mbed::Callback<void()> callback); 00113 00114 ATHandler *_nextATHandler; // linked list 00115 00116 /** returns the last error while parsing AT responses. 00117 * 00118 * @return last error 00119 */ 00120 nsapi_error_t get_last_error() const; 00121 00122 /** returns the last device error while parsing AT responses. Actually AT error (CME/CMS). 00123 * 00124 * @return last error struct device_err_t 00125 */ 00126 device_err_t get_last_device_error() const; 00127 00128 /** Increase reference count. Used for counting references to this instance. 00129 */ 00130 void inc_ref_count(); 00131 00132 /** Decrease reference count. Used for counting references to this instance. 00133 */ 00134 void dec_ref_count(); 00135 00136 /** Get the current reference count. Used for counting references to this instance. 00137 * 00138 * @return current reference count 00139 */ 00140 int get_ref_count(); 00141 00142 /** Set timeout in milliseconds for AT commands 00143 * 00144 * @param timeout_milliseconds Timeout in milliseconds 00145 * @param default_timeout Store as default timeout 00146 */ 00147 void set_at_timeout(uint32_t timeout_milliseconds, bool default_timeout = false); 00148 00149 /** Restore timeout to previous timeout. Handy if there is a need to change timeout temporarily. 00150 */ 00151 void restore_at_timeout(); 00152 00153 /** Clear pending error flag. By default, error is cleared only in lock(). 00154 */ 00155 void clear_error(); 00156 00157 /** Tries to find oob's from the AT response. Call the urc callback if one is found. 00158 */ 00159 void process_oob(); 00160 00161 /** Set sigio for the current file handle. Sigio event goes through eventqueue so that it's handled in current thread. 00162 */ 00163 void set_filehandle_sigio(); 00164 00165 /** 00166 * Flushes the underlying stream 00167 */ 00168 void flush(); 00169 00170 protected: 00171 void event(); 00172 #ifdef AT_HANDLER_MUTEX 00173 PlatformMutex _fileHandleMutex; 00174 #endif 00175 FileHandle *_fileHandle; 00176 private: 00177 00178 void set_error(nsapi_error_t err); 00179 00180 events::EventQueue &_queue; 00181 nsapi_error_t _last_err; 00182 int _last_3gpp_error; 00183 device_err_t _last_at_err; 00184 uint16_t _oob_string_max_length; 00185 char *_output_delimiter; 00186 uint8_t _output_delimiter_length; 00187 00188 struct oob_t { 00189 bool matching_to_received; 00190 const char *prefix; 00191 mbed::Callback<void()> cb; 00192 oob_t *next; 00193 }; 00194 oob_t *_oobs; 00195 bool _response_terminated; 00196 uint32_t _at_timeout; 00197 uint32_t _previous_at_timeout; 00198 00199 bool _fh_sigio_set; 00200 00201 bool _processing; 00202 int32_t _ref_count; 00203 00204 //************************************* 00205 public: 00206 00207 /** Starts the command writing by clearing the last error and writing the given command. 00208 * In case of failure when writing, the last error is set to NSAPI_ERROR_DEVICE_ERROR. 00209 * 00210 * @param cmd AT command to be written to modem 00211 */ 00212 void cmd_start(const char* cmd); 00213 00214 /** Writes integer type AT command subparameter. Starts with the delimiter if not the first param after cmd_start. 00215 * In case of failure when writing, the last error is set to NSAPI_ERROR_DEVICE_ERROR. 00216 * 00217 * @param param int to be written to modem as AT command subparameter 00218 */ 00219 void write_int(int32_t param); 00220 00221 /** Writes string type AT command subparamater. Quotes are added to surround the given string. 00222 * Starts with the delimiter if not the first param after cmd_start. 00223 * In case of failure when writing, the last error is set to NSAPI_ERROR_DEVICE_ERROR. 00224 * 00225 * @param param string to be written to modem as AT command subparameter 00226 * @param useQuotations flag indicating whether the string should be included in quotation marks 00227 */ 00228 void write_string(const char* param, bool useQuotations = true); 00229 00230 /** Stops the AT command by writing command-line terminator CR to mark command as finished. 00231 */ 00232 void cmd_stop(); 00233 00234 /** Write bytes without any subparameter delimiters, such as comma. 00235 * In case of failure when writing, the last error is set to NSAPI_ERROR_DEVICE_ERROR. 00236 * 00237 * @param data bytes to be written to modem 00238 * @param len length of data string 00239 * 00240 * @return number of characters successfully written 00241 */ 00242 size_t write_bytes(const uint8_t *data, size_t len); 00243 00244 /** Sets the stop tag for the current scope (response/information response/element) 00245 * Parameter's reading routines will stop the reading when such tag is found and will set the found flag. 00246 * Consume routines will read everything until such tag is found. 00247 * 00248 * @param stop_tag_seq string to be set as stop tag 00249 */ 00250 void set_stop_tag(const char *stop_tag_seq); 00251 00252 /** Sets the delimiter between parameters or between elements of the information response. 00253 * Parameter's reading routines will stop when such char is read. 00254 * 00255 * @param delimiter char to be set as _delimiter 00256 */ 00257 void set_delimiter(char delimiter); 00258 00259 /** Sets the delimiter to default value defined by DEFAULT_DELIMITER. 00260 */ 00261 void set_default_delimiter(); 00262 00263 /** Consumes the reading buffer up to the delimiter or stop_tag 00264 * 00265 * @param count number of parameters to be skipped 00266 */ 00267 void skip_param(uint32_t count = 1); 00268 00269 /** Consumes the given length from the reading buffer 00270 * 00271 * @param len length to be consumed from reading buffer 00272 * @param count number of parameters to be skipped 00273 */ 00274 void skip_param(ssize_t len, uint32_t count); 00275 00276 /** Reads given number of bytes from receiving buffer without checking any subparameter delimiters, such as comma. 00277 * 00278 * @param buf output buffer for the read 00279 * @param len maximum number of bytes to read 00280 * @return number of successfully read bytes or -1 in case of error 00281 */ 00282 ssize_t read_bytes(uint8_t *buf, size_t len); 00283 00284 /** Reads chars from reading buffer. Terminates with null. Skips the quotation marks. 00285 * Stops on delimiter or stop tag. 00286 * 00287 * @param str output buffer for the read 00288 * @param size maximum number of chars to output 00289 * @param read_even_stop_tag if true then try to read even if the stop tag was found previously 00290 * @return length of output string or -1 in case of read timeout before delimiter or stop tag is found 00291 */ 00292 ssize_t read_string(char *str, size_t size, bool read_even_stop_tag = false); 00293 00294 /** Reads as string and converts result to integer. Supports only positive integers. 00295 * 00296 * @return the positive integer or -1 in case of error. 00297 */ 00298 int32_t read_int(); 00299 00300 /** This looks for necessary matches: prefix, OK, ERROR, URCs and sets the correct scope. 00301 * 00302 * @param prefix string to be matched from receiving buffer. If not NULL and match succeeds, then scope 00303 * will be set as information response(info_type) 00304 * @param stop flag to indicate if we go to information response scope or not. 00305 * (needed when nothing is expected to be received anymore after the prefix match: 00306 * sms case: "> ", bc95 reboot case) 00307 */ 00308 void resp_start(const char *prefix = NULL, bool stop = false); 00309 00310 /** Ends all scopes starting from current scope. 00311 * Consumes everything until the scope's stop tag is found, then 00312 * goes to next scope until response scope is ending. 00313 * Possible sequence: 00314 * element scope -> information response scope -> response scope 00315 */ 00316 void resp_stop(); 00317 00318 /** Looks for matching the prefix given to resp_start() call. 00319 * If needed, it ends the scope of a previous information response. 00320 * Sets the information response scope if new prefix is found and response scope if prefix is not found. 00321 * 00322 * @return true if new information response is found, false otherwise 00323 */ 00324 bool info_resp(); 00325 00326 /** Looks for matching the start tag. 00327 * If needed, it ends the scope of a previous element. 00328 * Sets the element scope if start tag is found and information response scope if start tag is not found. 00329 * 00330 * @param start_tag tag to be matched to begin parsing an element of an information response 00331 * @return true if new element is found, false otherwise 00332 */ 00333 bool info_elem(char start_tag); 00334 00335 /** Consumes the received content until current stop tag is found. 00336 * 00337 * @return true if stop tag is found, false otherwise 00338 */ 00339 bool consume_to_stop_tag(); 00340 00341 /** Sets _debug_on flag. 00342 * 00343 * @param enable value to be set for _debug_on flag 00344 */ 00345 void enable_debug(bool enable); 00346 00347 /** Return the last 3GPP error code. 00348 * @return last 3GPP error code 00349 */ 00350 int get_3gpp_error(); 00351 00352 private: 00353 00354 // should fit any prefix and int 00355 char _recv_buff[BUFF_SIZE]; 00356 // reading position 00357 size_t _recv_len; 00358 // reading length 00359 size_t _recv_pos; 00360 00361 // resp_type: the part of the response that doesn't include the information response (+CMD1,+CMD2..) 00362 // ends with OK or (CME)(CMS)ERROR 00363 // info_type: the information response part of the response: starts with +CMD1 and ends with CRLF 00364 // information response contains parameters or subsets of parameters (elements), both separated by comma 00365 // elem_type: subsets of parameters that are part of information response, its parameters are separated by comma 00366 enum ScopeType {RespType, InfoType, ElemType, NotSet}; 00367 void set_scope(ScopeType scope_type); 00368 ScopeType _current_scope; 00369 00370 struct tag_t { 00371 char tag[7]; 00372 size_t len; 00373 bool found; 00374 }; 00375 00376 // tag to stop response scope 00377 tag_t _resp_stop; 00378 // tag to stop information response scope 00379 tag_t _info_stop; 00380 // tag to stop element scope 00381 tag_t _elem_stop; 00382 // reference to the stop tag of current scope (resp/info/elem) 00383 tag_t *_stop_tag; 00384 00385 // delimiter between parameters and also used for delimiting elements of information response 00386 char _delimiter; 00387 // set true on prefix match -> indicates start of an information response or of an element 00388 bool _prefix_matched; 00389 // set true on urc match 00390 bool _urc_matched; 00391 // set true on (CME)(CMS)ERROR 00392 bool _error_found; 00393 // Max length of OK,(CME)(CMS)ERROR and URCs 00394 size_t _max_resp_length; 00395 00396 // prefix set during resp_start and used to try matching possible information responses 00397 char _info_resp_prefix[BUFF_SIZE]; 00398 bool _debug_on; 00399 bool _cmd_start; 00400 00401 // Gets char from receiving buffer. 00402 // Resets and fills the buffer if all are already read (receiving position equals receiving length). 00403 int get_char(); 00404 // Sets to 0 the reading position, reading length and the whole buffer content. 00405 void reset_buffer(); 00406 // Reading position set to 0 and buffer's unread content moved to beginning 00407 void rewind_buffer(); 00408 // Reads from serial to receiving buffer. 00409 // Returns on first successful read OR on timeout. 00410 void fill_buffer(); 00411 00412 void set_tag(tag_t* tag_dest, const char *tag_seq); 00413 00414 // Rewinds the receiving buffer and compares it against given str. 00415 bool match(const char* str, size_t size); 00416 // Iterates URCs and checks if they match the receiving buffer content. 00417 // If URC match sets the scope to information response and after urc's cb returns 00418 // finishes the information response scope(consumes to CRLF). 00419 bool match_urc(); 00420 // Checks if any of the error strings are matching the receiving buffer content. 00421 bool match_error(); 00422 // Checks if current char in buffer matches ch and consumes it, 00423 // if no match lets the buffer unchanged. 00424 bool consume_char(char ch); 00425 // Consumes the received content until tag is found. 00426 // Consumes the tag only if consume_tag flag is true. 00427 bool consume_to_tag(const char *tag, bool consume_tag); 00428 // Checks if receiving buffer contains OK, ERROR, URC or given prefix. 00429 void resp(const char *prefix, bool check_urc); 00430 00431 00432 ScopeType get_scope(); 00433 00434 // Consumes to information response stop tag which is CRLF. Sets scope to response. 00435 void information_response_stop(); 00436 // Consumes to element stop tag. Sets scope to information response 00437 void information_response_element_stop(); 00438 00439 // Reads the error code if expected and sets it as last error. 00440 void at_error(bool error_code, DeviceErrorType error_type); 00441 00442 /** Convert AT error code to 3GPP error codes 00443 * @param err AT error code read from CME/CMS ERROR responses 00444 * @param error_type error type (CMS/CME/ERROR) 00445 */ 00446 void set_3gpp_error(int err, DeviceErrorType error_type); 00447 00448 bool check_cmd_send(); 00449 bool write_char(char c); 00450 00451 /** Copy content of one char buffer to another buffer and sets NULL terminator 00452 * 00453 * @param dest destination char buffer 00454 * @param src source char buffer 00455 * @param src_len number of bytes to copy 00456 * 00457 */ 00458 void set_string(char *dest, const char *src, size_t src_len); 00459 00460 /** Finds occurrence of one char buffer inside another char buffer. 00461 * 00462 * @param dest destination char buffer 00463 * @param dest_len length of dest 00464 * @param src string to be searched for 00465 * @param src_len length of string to be searched for 00466 * 00467 * @return pointer to first occurrence of src in dest 00468 */ 00469 const char* mem_str(const char* dest, size_t dest_len, const char* src, size_t src_len); 00470 }; 00471 00472 } // namespace mbed 00473 00474 #endif //AT_HANDLER_H_
Generated on Tue Jul 12 2022 13:29:25 by
