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