Mistake on this page?
Report an issue in GitHub or email us
ATHandler.h
1 /*
2  * Copyright (c) 2017, Arm Limited and affiliates.
3  * SPDX-License-Identifier: Apache-2.0
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 
18 #ifndef AT_HANDLER_H_
19 #define AT_HANDLER_H_
20 
21 #include "platform/mbed_retarget.h"
22 
23 #include "events/EventQueue.h"
24 #include "PlatformMutex.h"
25 #include "nsapi_types.h"
26 
27 #include "PlatformMutex.h"
28 #include "Callback.h"
29 
30 namespace mbed {
31 
32 class FileHandle;
33 
34 /**
35  * If application calls associated FileHandle only from single thread context
36  * then locking between AT command and response is not needed. However,
37  * note that many cellular functions are called indirectly, for example with the socket API.
38  * If you are unsure, then AT_HANDLER_MUTEX must be defined.
39  */
40 #define AT_HANDLER_MUTEX
41 
42 extern const char *OK;
43 extern const char *CRLF;
44 
45 #define BUFF_SIZE 16
46 
47 /* AT Error types enumeration */
48 enum DeviceErrorType {
49  DeviceErrorTypeNoError = 0,
50  DeviceErrorTypeError, // AT ERROR
51  DeviceErrorTypeErrorCMS, // AT ERROR CMS
52  DeviceErrorTypeErrorCME // AT ERROR CME
53 };
54 
55 /** AT response error with error code and type */
56 struct device_err_t {
57  DeviceErrorType errType;
58  int errCode;
59 };
60 
61 /// Class for sending AT commands and parsing AT responses.
62 class ATHandler {
63 
64 public:
65  /** Constructor
66  *
67  * @param fh file handle used for reading AT responses and writing AT commands
68  * @param queue Event queue used to transfer sigio events to this thread
69  * @param timeout Timeout when reading for AT response
70  * @param output_delimiter delimiter used when parsing at responses, "\r" should be used as output_delimiter
71  * @param send_delay the minimum delay in ms between the end of last response and the beginning of a new command
72  */
73  ATHandler(FileHandle *fh, events::EventQueue &queue, uint32_t timeout, const char *output_delimiter, uint16_t send_delay = 0);
74  virtual ~ATHandler();
75 
76  /** Return used file handle.
77  *
78  * @return used file handle
79  */
80  FileHandle *get_file_handle();
81 
82  /** Get a new ATHandler instance, and update the linked list. Once the use of the ATHandler
83  * has finished, call to close() has to be made
84  *
85  * @param fileHandle filehandle used for reading AT responses and writing AT commands.
86  * If there is already an ATHandler with the same fileHandle pointer,
87  * then a pointer to that ATHandler instance will be returned with
88  * that ATHandler's queue, timeout, delimiter, send_delay and debug_on
89  * values
90  * @param queue Event queue used to transfer sigio events to this thread
91  * @param timeout Timeout when reading for AT response
92  * @param delimiter delimiter used when parsing at responses, "\r" should be used as output_delimiter
93  * @param send_delay the minimum delay in ms between the end of last response and the beginning of a new command
94  * @param debug_on Set true to enable debug traces
95  * @return NULL, if fileHandle is not set, or a pointer to an existing ATHandler, if the fileHandle is
96  * already in use. Otherwise a pointer to a new ATHandler instance is returned
97  */
98  static ATHandler *get_instance(FileHandle *fileHandle, events::EventQueue &queue, uint32_t timeout,
99  const char *delimiter, uint16_t send_delay, bool debug_on);
100 
101  /** Close and delete the current ATHandler instance, if the reference count to it is 0.
102  * Close() can be only called, if the ATHandler was opened with get_instance()
103  *
104  * @return NSAPI_ERROR_OK on success, NSAPI_ERROR_PARAMETER on failure
105  */
106  nsapi_error_t close();
107 
108  /** Locks the mutex for file handle if AT_HANDLER_MUTEX is defined.
109  */
110  void lock();
111 
112  /** Unlocks the mutex for file handle if AT_HANDLER_MUTEX is defined.
113  */
114  void unlock();
115 
116  /** Locks the mutex for file handle if AT_HANDLER_MUTEX is defined and returns the last error.
117  *
118  * @return last error that happened when parsing AT responses
119  */
120  nsapi_error_t unlock_return_error();
121 
122  /** Set callback function for URC
123  *
124  * @param prefix URC text to look for, e.g. "+CMTI:"
125  * @param callback function to call on prefix, or 0 to remove callback
126  */
127  void set_urc_handler(const char *prefix, Callback<void()> callback);
128 
129  ATHandler *_nextATHandler; // linked list
130 
131  /** returns the last error while parsing AT responses.
132  *
133  * @return last error
134  */
135  nsapi_error_t get_last_error() const;
136 
137  /** returns the last device error while parsing AT responses. Actually AT error (CME/CMS).
138  *
139  * @return last error struct device_err_t
140  */
141  device_err_t get_last_device_error() const;
142 
143  /** Increase reference count. Used for counting references to this instance.
144  * Note that this should be used with care, if the ATHandler was taken into use
145  * with get_instance()
146  */
147  void inc_ref_count();
148 
149  /** Decrease reference count. Used for counting references to this instance.
150  * Note that this should be used with care, if the ATHandler was taken into use
151  * with get_instance()
152  */
153  void dec_ref_count();
154 
155  /** Get the current reference count. Used for counting references to this instance.
156  *
157  * @return current reference count
158  */
159  int get_ref_count();
160 
161  /** Set timeout in milliseconds for AT commands
162  *
163  * @param timeout_milliseconds Timeout in milliseconds
164  * @param default_timeout Store as default timeout
165  */
166  void set_at_timeout(uint32_t timeout_milliseconds, bool default_timeout = false);
167 
168  /** Set timeout in milliseconds for all ATHandlers in the _atHandlers list
169  *
170  * @param timeout_milliseconds Timeout in milliseconds
171  * @param default_timeout Store as default timeout
172  */
173  static void set_at_timeout_list(uint32_t timeout_milliseconds, bool default_timeout = false);
174 
175  /** Restore timeout to previous timeout. Handy if there is a need to change timeout temporarily.
176  */
177  void restore_at_timeout();
178 
179  /** Clear pending error flag. By default, error is cleared only in lock().
180  */
181  void clear_error();
182 
183  /**
184  * Flushes the underlying stream
185  */
186  void flush();
187 
188  /** Tries to find oob's from the AT response. Call the urc callback if one is found.
189  */
190  void process_oob();
191 
192  /** Set file handle, which is used for reading AT responses and writing AT commands
193  *
194  * @param fh file handle used for reading AT responses and writing AT commands
195  */
196  void set_file_handle(FileHandle *fh);
197 
198  /** Set is file handle usable. Some situations like after going to data mode, file handle is not usable anymore.
199  * Any items in queue are not to be processed.
200  *
201  * @param usable true for usable filehandle
202  */
203  void set_is_filehandle_usable(bool usable);
204 
205  /** Synchronize AT command and response handling to modem.
206  *
207  * @param timeout_ms ATHandler timeout when trying to sync. Will be restored when function returns.
208  * @return true is synchronization was successful, false in case of failure
209  */
210  bool sync(int timeout_ms);
211 
212 protected:
213  void event();
214 #ifdef AT_HANDLER_MUTEX
215  PlatformMutex _fileHandleMutex;
216 #endif
217  FileHandle *_fileHandle;
218 private:
219  /** Remove urc handler from linked list of urc's
220  *
221  * @param prefix Register urc prefix for callback. Urc could be for example "+CMTI: "
222  */
223  void remove_urc_handler(const char *prefix);
224 
225  void set_error(nsapi_error_t err);
226 
227  events::EventQueue &_queue;
228  nsapi_error_t _last_err;
229  int _last_3gpp_error;
230  device_err_t _last_at_err;
231  uint16_t _oob_string_max_length;
232  char *_output_delimiter;
233 
234  struct oob_t {
235  const char *prefix;
236  int prefix_len;
237  Callback<void()> cb;
238  oob_t *next;
239  };
240  oob_t *_oobs;
241  uint32_t _at_timeout;
242  uint32_t _previous_at_timeout;
243 
244  uint16_t _at_send_delay;
245  uint64_t _last_response_stop;
246 
247  bool _oob_queued;
248  int32_t _ref_count;
249  bool _is_fh_usable;
250 
251  static ATHandler *_atHandlers;
252 
253  //*************************************
254 public:
255 
256  /** Starts the command writing by clearing the last error and writing the given command.
257  * In case of failure when writing, the last error is set to NSAPI_ERROR_DEVICE_ERROR.
258  *
259  * @param cmd AT command to be written to modem
260  */
261  virtual void cmd_start(const char *cmd);
262 
263  /** Writes integer type AT command subparameter. Starts with the delimiter if not the first param after cmd_start.
264  * In case of failure when writing, the last error is set to NSAPI_ERROR_DEVICE_ERROR.
265  *
266  * @param param int to be written to modem as AT command subparameter
267  */
268  void write_int(int32_t param);
269 
270  /** Writes string type AT command subparamater. Quotes are added to surround the given string.
271  * Starts with the delimiter if not the first param after cmd_start.
272  * In case of failure when writing, the last error is set to NSAPI_ERROR_DEVICE_ERROR.
273  *
274  * @param param string to be written to modem as AT command subparameter
275  * @param useQuotations flag indicating whether the string should be included in quotation marks
276  */
277  void write_string(const char *param, bool useQuotations = true);
278 
279  /** Stops the AT command by writing command-line terminator CR to mark command as finished.
280  */
281  void cmd_stop();
282 
283  /** Stops the AT command by writing command-line terminator CR to mark command as finished and reads the OK/ERROR response.
284  *
285  */
286  void cmd_stop_read_resp();
287 
288  /** Write bytes without any subparameter delimiters, such as comma.
289  * In case of failure when writing, the last error is set to NSAPI_ERROR_DEVICE_ERROR.
290  *
291  * @param data bytes to be written to modem
292  * @param len length of data string
293  *
294  * @return number of characters successfully written
295  */
296  size_t write_bytes(const uint8_t *data, size_t len);
297 
298  /** Sets the stop tag for the current scope (response/information response/element)
299  * Parameter's reading routines will stop the reading when such tag is found and will set the found flag.
300  * Consume routines will read everything until such tag is found.
301  *
302  * @param stop_tag_seq string to be set as stop tag
303  */
304  void set_stop_tag(const char *stop_tag_seq);
305 
306  /** Sets the delimiter between parameters or between elements of the information response.
307  * Parameter's reading routines will stop when such char is read.
308  *
309  * @param delimiter char to be set as _delimiter
310  */
311  void set_delimiter(char delimiter);
312 
313  /** Sets the delimiter to default value defined by DEFAULT_DELIMITER.
314  */
315  void set_default_delimiter();
316 
317  /** Defines behaviour for using or ignoring the delimiter within an AT command
318  *
319  * @param use_delimiter indicating if delimiter should be used or not
320  */
321  void use_delimiter(bool use_delimiter);
322 
323  /** Consumes the reading buffer up to the delimiter or stop_tag
324  *
325  * @param count number of parameters to be skipped
326  */
327  void skip_param(uint32_t count = 1);
328 
329  /** Consumes the given length from the reading buffer
330  *
331  * @param len length to be consumed from reading buffer
332  * @param count number of parameters to be skipped
333  */
334  void skip_param(ssize_t len, uint32_t count);
335 
336  /** Reads given number of bytes from receiving buffer without checking any subparameter delimiters, such as comma.
337  *
338  * @param buf output buffer for the read
339  * @param len maximum number of bytes to read
340  * @return number of successfully read bytes or -1 in case of error
341  */
342  ssize_t read_bytes(uint8_t *buf, size_t len);
343 
344  /** Reads chars from reading buffer. Terminates with null. Skips the quotation marks.
345  * Stops on delimiter or stop tag.
346  *
347  * @param str output buffer for the read
348  * @param size maximum number of chars to output including NULL
349  * @param read_even_stop_tag if true then try to read even if the stop tag was found previously
350  * @return length of output string or -1 in case of read timeout before delimiter or stop tag is found
351  */
352  ssize_t read_string(char *str, size_t size, bool read_even_stop_tag = false);
353 
354  /** Reads chars representing hex ascii values and converts them to the corresponding chars.
355  * For example: "4156" to "AV".
356  * Terminates with null. Skips the quotation marks.
357  * Stops on delimiter or stop tag.
358  *
359  * @param str output buffer for the read
360  * @param size maximum number of chars to output
361  * @return length of output string or -1 in case of read timeout before delimiter or stop tag is found
362  */
363  ssize_t read_hex_string(char *str, size_t size);
364 
365  /** Reads as string and converts result to integer. Supports only positive integers.
366  *
367  * @return the positive integer or -1 in case of error.
368  */
369  int32_t read_int();
370 
371  /** This looks for necessary matches: prefix, OK, ERROR, URCs and sets the correct scope.
372  *
373  * @param prefix string to be matched from receiving buffer. If not NULL and match succeeds, then scope
374  * will be set as information response(info_type)
375  * @param stop flag to indicate if we go to information response scope or not.
376  * (needed when nothing is expected to be received anymore after the prefix match:
377  * sms case: "> ", bc95 reboot case)
378  */
379  void resp_start(const char *prefix = NULL, bool stop = false);
380 
381  /** Ends all scopes starting from current scope.
382  * Consumes everything until the scope's stop tag is found, then
383  * goes to next scope until response scope is ending.
384  * URC match is checked during response scope ending,
385  * for every new line / CRLF.
386  *
387  *
388  * Possible sequence:
389  * element scope -> information response scope -> response scope
390  */
391  void resp_stop();
392 
393  /** Looks for matching the prefix given to resp_start() call.
394  * If needed, it ends the scope of a previous information response.
395  * Sets the information response scope if new prefix is found and response scope if prefix is not found.
396  *
397  * @return true if prefix defined for information response is not empty string and is found,
398  * false otherwise.
399  */
400  bool info_resp();
401 
402  /** Looks for matching the start tag.
403  * If needed, it ends the scope of a previous element.
404  * Sets the element scope if start tag is found and information response scope if start tag is not found.
405  *
406  * @param start_tag tag to be matched to begin parsing an element of an information response
407  * @return true if new element is found, false otherwise
408  */
409  bool info_elem(char start_tag);
410 
411  /** Consumes the received content until current stop tag is found.
412  *
413  * @return true if stop tag is found, false otherwise
414  */
415  bool consume_to_stop_tag();
416 
417  /** Return the last 3GPP error code.
418  * @return last 3GPP error code
419  */
420  int get_3gpp_error();
421 
422 public: // just for debugging
423  /**
424  * AT debugging, when enabled will print all data read and written,
425  * non-printable chars are printed as "[%d]".
426  *
427  * AT debug can be enabled at compile time using MBED_CONF_CELLULAR_DEBUG_AT flag or at runtime
428  * calling set_debug(). Note that MBED_CONF_MBED_TRACE_ENABLE must also be enabled.
429  *
430  * @param debug_on Enable/disable debugging
431  */
432  void set_debug(bool debug_on);
433 
434  /**
435  * Get degug state set by @ref set_debug
436  *
437  * @return current state of debug
438  */
439  bool get_debug() const;
440 
441  /** Set debug_on for all ATHandlers in the _atHandlers list
442  *
443  * @param debug_on Set true to enable debug traces
444  */
445  static void set_debug_list(bool debug_on);
446 
447 private:
448 
449  // should fit any prefix and int
450  char _recv_buff[BUFF_SIZE];
451  // reading position
452  size_t _recv_len;
453  // reading length
454  size_t _recv_pos;
455 
456  // resp_type: the part of the response that doesn't include the information response (+CMD1,+CMD2..)
457  // ends with OK or (CME)(CMS)ERROR
458  // info_type: the information response part of the response: starts with +CMD1 and ends with CRLF
459  // information response contains parameters or subsets of parameters (elements), both separated by comma
460  // elem_type: subsets of parameters that are part of information response, its parameters are separated by comma
461  enum ScopeType {RespType, InfoType, ElemType, NotSet};
462  void set_scope(ScopeType scope_type);
463  ScopeType _current_scope;
464 
465  struct tag_t {
466  char tag[7];
467  size_t len;
468  bool found;
469  };
470 
471  // tag to stop response scope
472  tag_t _resp_stop;
473  // tag to stop information response scope
474  tag_t _info_stop;
475  // tag to stop element scope
476  tag_t _elem_stop;
477  // reference to the stop tag of current scope (resp/info/elem)
478  tag_t *_stop_tag;
479 
480  // delimiter between parameters and also used for delimiting elements of information response
481  char _delimiter;
482  // set true on prefix match -> indicates start of an information response or of an element
483  bool _prefix_matched;
484  // set true on urc match
485  bool _urc_matched;
486  // set true on (CME)(CMS)ERROR
487  bool _error_found;
488  // Max length of OK,(CME)(CMS)ERROR and URCs
489  size_t _max_resp_length;
490 
491  // prefix set during resp_start and used to try matching possible information responses
492  char _info_resp_prefix[BUFF_SIZE];
493  bool _debug_on;
494  bool _cmd_start;
495  bool _use_delimiter;
496 
497  // time when a command or an URC processing was started
498  uint64_t _start_time;
499 
500  // Gets char from receiving buffer.
501  // Resets and fills the buffer if all are already read (receiving position equals receiving length).
502  // Returns a next char or -1 on failure (also sets error flag)
503  int get_char();
504  // Sets to 0 the reading position, reading length and the whole buffer content.
505  void reset_buffer();
506  // Reading position set to 0 and buffer's unread content moved to beginning
507  void rewind_buffer();
508  // Calculate remaining time for polling based on request start time and AT timeout.
509  // Returns 0 or time in ms for polling.
510  int poll_timeout(bool wait_for_timeout = true);
511  // Reads from serial to receiving buffer.
512  // Returns true on successful read OR false on timeout.
513  bool fill_buffer(bool wait_for_timeout = true);
514 
515  void set_tag(tag_t *tag_dest, const char *tag_seq);
516 
517  // Rewinds the receiving buffer and compares it against given str.
518  bool match(const char *str, size_t size);
519  // Iterates URCs and checks if they match the receiving buffer content.
520  // If URC match sets the scope to information response and after urc's cb returns
521  // finishes the information response scope(consumes to CRLF).
522  bool match_urc();
523  // Checks if any of the error strings are matching the receiving buffer content.
524  bool match_error();
525  // Checks if current char in buffer matches ch and consumes it,
526  // if no match lets the buffer unchanged.
527  bool consume_char(char ch);
528  // Consumes the received content until tag is found.
529  // Consumes the tag only if consume_tag flag is true.
530  bool consume_to_tag(const char *tag, bool consume_tag);
531  // Checks if receiving buffer contains OK, ERROR, URC or given prefix.
532  void resp(const char *prefix, bool check_urc);
533 
534 
535  ScopeType get_scope();
536 
537  // Consumes to information response stop tag which is CRLF. Sets scope to response.
538  void information_response_stop();
539  // Consumes to element stop tag. Sets scope to information response
540  void information_response_element_stop();
541 
542  // Reads the error code if expected and sets it as last error.
543  void at_error(bool error_code, DeviceErrorType error_type);
544 
545  /** Convert AT error code to 3GPP error codes
546  * @param err AT error code read from CME/CMS ERROR responses
547  * @param error_type error type (CMS/CME/ERROR)
548  */
549  void set_3gpp_error(int err, DeviceErrorType error_type);
550 
551  bool check_cmd_send();
552  size_t write(const void *data, size_t len);
553 
554  /** Copy content of one char buffer to another buffer and sets NULL terminator
555  *
556  * @param dest destination char buffer
557  * @param src source char buffer
558  * @param src_len number of bytes to copy
559  *
560  */
561  void set_string(char *dest, const char *src, size_t src_len);
562 
563  /** Finds occurrence of one char buffer inside another char buffer.
564  *
565  * @param dest destination char buffer
566  * @param dest_len length of dest
567  * @param src string to be searched for
568  * @param src_len length of string to be searched for
569  *
570  * @return pointer to first occurrence of src in dest
571  */
572  const char *mem_str(const char *dest, size_t dest_len, const char *src, size_t src_len);
573 
574  // check is urc is already added
575  bool find_urc_handler(const char *prefix);
576 
577  // print contents of a buffer to trace log
578  enum ATType {
579  AT_ERR,
580  AT_RX,
581  AT_TX
582  };
583  void debug_print(const char *p, int len, ATType type);
584 };
585 
586 } // namespace mbed
587 
588 #endif //AT_HANDLER_H_
EventQueue.
Definition: EventQueue.h:52
signed int nsapi_error_t
Type used to represent error codes.
Definition: nsapi_types.h:95
Class FileHandle.
Definition: FileHandle.h:46
Callback< R()> callback(R(*func)()=0)
Create a callback class with type inferred from the arguments.
Definition: Callback.h:3848
The PlatformMutex class is used to synchronize the execution of threads.
Definition: PlatformMutex.h:47
AT response error with error code and type.
Definition: ATHandler.h:56
Callback class based on template specialization.
Definition: Callback.h:39
Definition: AnalogIn.h:28
Class for sending AT commands and parsing AT responses.
Definition: ATHandler.h:62
Important Information for this Arm website

This site uses cookies to store information on your computer. By continuing to use our site, you consent to our cookies. If you are not happy with the use of these cookies, please review our Cookie Policy to learn how they can be disabled. By disabling cookies, some features of the site will not work.