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 /** Set file handle, which is used for reading AT responses and writing AT commands 00090 * 00091 * @param fh file handle used for reading AT responses and writing AT commands 00092 */ 00093 void set_file_handle(FileHandle *fh); 00094 00095 /** Locks the mutex for file handle if AT_HANDLER_MUTEX is defined. 00096 */ 00097 void lock(); 00098 00099 /** Unlocks the mutex for file handle if AT_HANDLER_MUTEX is defined. 00100 */ 00101 void unlock(); 00102 00103 /** Locks the mutex for file handle if AT_HANDLER_MUTEX is defined and returns the last error. 00104 * 00105 * @return last error that happened when parsing AT responses 00106 */ 00107 nsapi_error_t unlock_return_error(); 00108 00109 /** Set the urc callback for urc. If urc is found when parsing AT responses, then call if called. 00110 * If urc is already set then it's not set twice. 00111 * 00112 * @param prefix Register urc prefix for callback. Urc could be for example "+CMTI: " 00113 * @param callback Callback, which is called if urc is found in AT response 00114 * @return NSAPI_ERROR_OK or NSAPI_ERROR_NO_MEMORY if no memory 00115 */ 00116 nsapi_error_t set_urc_handler(const char *prefix, mbed::Callback<void()> callback); 00117 00118 /** Remove urc handler from linked list of urc's 00119 * 00120 * @param prefix Register urc prefix for callback. Urc could be for example "+CMTI: " 00121 * @param callback Callback, which is called if urc is found in AT response 00122 */ 00123 void remove_urc_handler(const char *prefix, mbed::Callback<void()> callback); 00124 00125 ATHandler *_nextATHandler; // linked list 00126 00127 /** returns the last error while parsing AT responses. 00128 * 00129 * @return last error 00130 */ 00131 nsapi_error_t get_last_error() const; 00132 00133 /** returns the last device error while parsing AT responses. Actually AT error (CME/CMS). 00134 * 00135 * @return last error struct device_err_t 00136 */ 00137 device_err_t get_last_device_error() const; 00138 00139 /** Increase reference count. Used for counting references to this instance. 00140 */ 00141 void inc_ref_count(); 00142 00143 /** Decrease reference count. Used for counting references to this instance. 00144 */ 00145 void dec_ref_count(); 00146 00147 /** Get the current reference count. Used for counting references to this instance. 00148 * 00149 * @return current reference count 00150 */ 00151 int get_ref_count(); 00152 00153 /** Set timeout in milliseconds for AT commands 00154 * 00155 * @param timeout_milliseconds Timeout in milliseconds 00156 * @param default_timeout Store as default timeout 00157 */ 00158 void set_at_timeout(uint32_t timeout_milliseconds, bool default_timeout = false); 00159 00160 /** Restore timeout to previous timeout. Handy if there is a need to change timeout temporarily. 00161 */ 00162 void restore_at_timeout(); 00163 00164 /** Clear pending error flag. By default, error is cleared only in lock(). 00165 */ 00166 void clear_error(); 00167 00168 /** Tries to find oob's from the AT response. Call the urc callback if one is found. 00169 */ 00170 void process_oob(); 00171 00172 /** Set sigio for the current file handle. Sigio event goes through eventqueue so that it's handled in current thread. 00173 */ 00174 void set_filehandle_sigio(); 00175 00176 /** 00177 * Flushes the underlying stream 00178 */ 00179 void flush(); 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 as string and converts result to integer. Supports only positive integers. 00307 * 00308 * @return the positive integer or -1 in case of error. 00309 */ 00310 int32_t read_int(); 00311 00312 /** This looks for necessary matches: prefix, OK, ERROR, URCs and sets the correct scope. 00313 * 00314 * @param prefix string to be matched from receiving buffer. If not NULL and match succeeds, then scope 00315 * will be set as information response(info_type) 00316 * @param stop flag to indicate if we go to information response scope or not. 00317 * (needed when nothing is expected to be received anymore after the prefix match: 00318 * sms case: "> ", bc95 reboot case) 00319 */ 00320 void resp_start(const char *prefix = NULL, bool stop = false); 00321 00322 /** Ends all scopes starting from current scope. 00323 * Consumes everything until the scope's stop tag is found, then 00324 * goes to next scope until response scope is ending. 00325 * Possible sequence: 00326 * element scope -> information response scope -> response scope 00327 */ 00328 void resp_stop(); 00329 00330 /** Looks for matching the prefix given to resp_start() call. 00331 * If needed, it ends the scope of a previous information response. 00332 * Sets the information response scope if new prefix is found and response scope if prefix is not found. 00333 * 00334 * @return true if new information response is found, false otherwise 00335 */ 00336 bool info_resp(); 00337 00338 /** Looks for matching the start tag. 00339 * If needed, it ends the scope of a previous element. 00340 * Sets the element scope if start tag is found and information response scope if start tag is not found. 00341 * 00342 * @param start_tag tag to be matched to begin parsing an element of an information response 00343 * @return true if new element is found, false otherwise 00344 */ 00345 bool info_elem(char start_tag); 00346 00347 /** Consumes the received content until current stop tag is found. 00348 * 00349 * @return true if stop tag is found, false otherwise 00350 */ 00351 bool consume_to_stop_tag(); 00352 00353 /** Sets _debug_on flag. 00354 * 00355 * @param enable value to be set for _debug_on flag 00356 */ 00357 void enable_debug(bool enable); 00358 00359 /** Return the last 3GPP error code. 00360 * @return last 3GPP error code 00361 */ 00362 int get_3gpp_error(); 00363 00364 private: 00365 00366 // should fit any prefix and int 00367 char _recv_buff[BUFF_SIZE]; 00368 // reading position 00369 size_t _recv_len; 00370 // reading length 00371 size_t _recv_pos; 00372 00373 // resp_type: the part of the response that doesn't include the information response (+CMD1,+CMD2..) 00374 // ends with OK or (CME)(CMS)ERROR 00375 // info_type: the information response part of the response: starts with +CMD1 and ends with CRLF 00376 // information response contains parameters or subsets of parameters (elements), both separated by comma 00377 // elem_type: subsets of parameters that are part of information response, its parameters are separated by comma 00378 enum ScopeType {RespType, InfoType, ElemType, NotSet}; 00379 void set_scope(ScopeType scope_type); 00380 ScopeType _current_scope; 00381 00382 struct tag_t { 00383 char tag[7]; 00384 size_t len; 00385 bool found; 00386 }; 00387 00388 // tag to stop response scope 00389 tag_t _resp_stop; 00390 // tag to stop information response scope 00391 tag_t _info_stop; 00392 // tag to stop element scope 00393 tag_t _elem_stop; 00394 // reference to the stop tag of current scope (resp/info/elem) 00395 tag_t *_stop_tag; 00396 00397 // delimiter between parameters and also used for delimiting elements of information response 00398 char _delimiter; 00399 // set true on prefix match -> indicates start of an information response or of an element 00400 bool _prefix_matched; 00401 // set true on urc match 00402 bool _urc_matched; 00403 // set true on (CME)(CMS)ERROR 00404 bool _error_found; 00405 // Max length of OK,(CME)(CMS)ERROR and URCs 00406 size_t _max_resp_length; 00407 00408 // prefix set during resp_start and used to try matching possible information responses 00409 char _info_resp_prefix[BUFF_SIZE]; 00410 bool _debug_on; 00411 bool _cmd_start; 00412 00413 // Gets char from receiving buffer. 00414 // Resets and fills the buffer if all are already read (receiving position equals receiving length). 00415 int get_char(); 00416 // Sets to 0 the reading position, reading length and the whole buffer content. 00417 void reset_buffer(); 00418 // Reading position set to 0 and buffer's unread content moved to beginning 00419 void rewind_buffer(); 00420 // Reads from serial to receiving buffer. 00421 // Returns on first successful read OR on timeout. 00422 void fill_buffer(); 00423 00424 void set_tag(tag_t* tag_dest, const char *tag_seq); 00425 00426 // Rewinds the receiving buffer and compares it against given str. 00427 bool match(const char* str, size_t size); 00428 // Iterates URCs and checks if they match the receiving buffer content. 00429 // If URC match sets the scope to information response and after urc's cb returns 00430 // finishes the information response scope(consumes to CRLF). 00431 bool match_urc(); 00432 // Checks if any of the error strings are matching the receiving buffer content. 00433 bool match_error(); 00434 // Checks if current char in buffer matches ch and consumes it, 00435 // if no match lets the buffer unchanged. 00436 bool consume_char(char ch); 00437 // Consumes the received content until tag is found. 00438 // Consumes the tag only if consume_tag flag is true. 00439 bool consume_to_tag(const char *tag, bool consume_tag); 00440 // Checks if receiving buffer contains OK, ERROR, URC or given prefix. 00441 void resp(const char *prefix, bool check_urc); 00442 00443 00444 ScopeType get_scope(); 00445 00446 // Consumes to information response stop tag which is CRLF. Sets scope to response. 00447 void information_response_stop(); 00448 // Consumes to element stop tag. Sets scope to information response 00449 void information_response_element_stop(); 00450 00451 // Reads the error code if expected and sets it as last error. 00452 void at_error(bool error_code, DeviceErrorType error_type); 00453 00454 /** Convert AT error code to 3GPP error codes 00455 * @param err AT error code read from CME/CMS ERROR responses 00456 * @param error_type error type (CMS/CME/ERROR) 00457 */ 00458 void set_3gpp_error(int err, DeviceErrorType error_type); 00459 00460 bool check_cmd_send(); 00461 size_t write(const void *data, size_t len); 00462 00463 /** Copy content of one char buffer to another buffer and sets NULL terminator 00464 * 00465 * @param dest destination char buffer 00466 * @param src source char buffer 00467 * @param src_len number of bytes to copy 00468 * 00469 */ 00470 void set_string(char *dest, const char *src, size_t src_len); 00471 00472 /** Finds occurrence of one char buffer inside another char buffer. 00473 * 00474 * @param dest destination char buffer 00475 * @param dest_len length of dest 00476 * @param src string to be searched for 00477 * @param src_len length of string to be searched for 00478 * 00479 * @return pointer to first occurrence of src in dest 00480 */ 00481 const char* mem_str(const char* dest, size_t dest_len, const char* src, size_t src_len); 00482 00483 // check is urc is already added 00484 bool find_urc_handler(const char *prefix, mbed::Callback<void()> callback); 00485 }; 00486 00487 } // namespace mbed 00488 00489 #endif //AT_HANDLER_H_
Generated on Tue Jul 12 2022 15:17:16 by
1.7.2