Nicolas Borla / Mbed OS BBR_1Ebene
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 #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_