Knight KE / Mbed OS Game_Master
Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers ATHandler.h Source File

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