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 #include "platform/mbed_chrono.h"
23 
24 #include "events/EventQueue.h"
25 #include "netsocket/nsapi_types.h"
26 
27 #include "Callback.h"
28 #include "rtos/Kernel.h"
29 
30 #include <cstdarg>
31 
32 #include "drivers/BufferedSerial.h"
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 #if defined AT_HANDLER_MUTEX && defined MBED_CONF_RTOS_PRESENT
43 #include "rtos/ConditionVariable.h"
44 #endif
45 
46 namespace mbed {
47 
48 class FileHandle;
49 
50 extern const char *OK;
51 extern const char *CRLF;
52 
53 #define BUFF_SIZE 32
54 
55 /* AT Error types enumeration */
56 enum DeviceErrorType {
57  DeviceErrorTypeNoError = 0,
58  DeviceErrorTypeError, // AT ERROR
59  DeviceErrorTypeErrorCMS, // AT ERROR CMS
60  DeviceErrorTypeErrorCME // AT ERROR CME
61 };
62 
63 /** AT response error with error code and type */
64 struct device_err_t {
65  DeviceErrorType errType;
66  int errCode;
67 };
68 
69 /// Class for sending AT commands and parsing AT responses.
70 class ATHandler {
71 
72 public:
73  /** Constructor
74  *
75  * @param fh file handle used for reading AT responses and writing AT commands
76  * @param queue Event queue used to transfer sigio events to this thread
77  * @param timeout Timeout when reading for AT response
78  * @param output_delimiter delimiter used when parsing at responses, "\r" should be used as output_delimiter
79  * @param send_delay the minimum delay in ms between the end of last response and the beginning of a new command
80  */
81  ATHandler(FileHandle *fh, events::EventQueue &queue, uint32_t timeout, const char *output_delimiter, uint16_t send_delay = 0);
82 
83  /** Constructor
84  *
85  * @param fh file handle used for reading AT responses and writing AT commands
86  * @param queue Event queue used to transfer sigio events to this thread
87  * @param timeout Timeout when reading for AT response
88  * @param output_delimiter delimiter used when parsing at responses, "\r" should be used as output_delimiter
89  * @param send_delay the minimum delay in ms between the end of last response and the beginning of a new command
90  */
91  ATHandler(FileHandle *fh, events::EventQueue &queue, mbed::chrono::milliseconds_u32 timeout, const char *output_delimiter, std::chrono::duration<uint16_t, std::milli> send_delay = std::chrono::milliseconds(0));
92 
93  ~ATHandler();
94 
95  /** Return used file handle.
96  *
97  * @return used file handle
98  */
99  FileHandle *get_file_handle();
100 
101  /** Locks the mutex for file handle if AT_HANDLER_MUTEX is defined.
102  */
103  void lock();
104 
105  /** Unlocks the mutex for file handle if AT_HANDLER_MUTEX is defined.
106  */
107  void unlock();
108 
109  /** Locks the mutex for file handle if AT_HANDLER_MUTEX is defined and returns the last error.
110  *
111  * @return last error that happened when parsing AT responses
112  */
113  nsapi_error_t unlock_return_error();
114 
115  /** Set callback function for URC
116  *
117  * @param prefix URC text to look for, e.g. "+CMTI:". Maximum length is BUFF_SIZE.
118  * @param callback function to call on prefix, or 0 to remove callback
119  */
120  void set_urc_handler(const char *prefix, Callback<void()> callback);
121 
122  /** returns the last error while parsing AT responses.
123  *
124  * @return last error
125  */
126  nsapi_error_t get_last_error() const;
127 
128  /** returns the last device error while parsing AT responses. Actually AT error (CME/CMS).
129  *
130  * @return last error struct device_err_t
131  */
132  device_err_t get_last_device_error() const;
133 
134  /** Set timeout in milliseconds for AT commands
135  *
136  * @param timeout_milliseconds Timeout in milliseconds
137  * @param default_timeout Store as default timeout
138  */
139  void set_at_timeout(uint32_t timeout_milliseconds, bool default_timeout = false);
140 
141  /** Set timeout in milliseconds for AT commands
142  *
143  * @param timeout Timeout in milliseconds
144  * @param default_timeout Store as default timeout
145  */
146  void set_at_timeout(mbed::chrono::milliseconds_u32 timeout, bool default_timeout = false);
147 
148  /** Restore timeout to previous timeout. Handy if there is a need to change timeout temporarily.
149  */
150  void restore_at_timeout();
151 
152  /** Clear pending error flag. By default, error is cleared only in lock().
153  */
154  void clear_error();
155 
156  /**
157  * Flushes the underlying stream
158  */
159  void flush();
160 
161  /** Tries to find oob's from the AT response. Call the urc callback if one is found.
162  */
163  void process_oob();
164 
165  /** Set is file handle usable. Some situations like after going to data mode, file handle is not usable anymore.
166  * Any items in queue are not to be processed.
167  *
168  * @param usable true for usable filehandle
169  */
170  void set_is_filehandle_usable(bool usable);
171 
172  /** Synchronize AT command and response handling to modem.
173  *
174  * @param timeout_ms ATHandler timeout when trying to sync. Will be restored when function returns.
175  * @return true is synchronization was successful, false in case of failure
176  */
177  bool sync(int timeout_ms);
178 
179  /** Synchronize AT command and response handling to modem.
180  *
181  * @param timeout ATHandler timeout when trying to sync. Will be restored when function returns.
182  * @return true is synchronization was successful, false in case of failure
183  */
184  bool sync(std::chrono::duration<int, std::milli> timeout);
185 
186  /** Sets the delay to be applied before sending any AT command.
187  *
188  * @param send_delay the minimum delay in ms between the end of last response and the beginning of a new command
189  */
190  void set_send_delay(uint16_t send_delay);
191 
192  /** Sets BufferedSerial filehandle to given baud rate
193  *
194  * @param baud_rate
195  */
196  void set_baud(int baud_rate);
197 
198  /** Starts the command writing by clearing the last error and writing the given command.
199  * In case of failure when writing, the last error is set to NSAPI_ERROR_DEVICE_ERROR.
200  *
201  * @param cmd AT command to be written to modem
202  */
203  void cmd_start(const char *cmd);
204 
205  /**
206  * @brief cmd_start_stop Starts an AT command, writes given variadic arguments and stops the command. Use this
207  * command when you need multiple response parameters to be handled.
208  * NOTE: Does not lock ATHandler for process!
209  *
210  * @param cmd AT command in form +<CMD> (will be used also in response reading, no extra chars allowed)
211  * @param cmd_chr Char to be added to specific AT command: '?', '=' or ''. Will be used as such so '=1' is valid as well.
212  * @param format Format string for variadic arguments to be added to AT command; No separator needed.
213  * Use %d for integer, %s for string and %b for byte string (requires 2 arguments: string and length)
214  */
215  void cmd_start_stop(const char *cmd, const char *cmd_chr, const char *format = "", ...);
216 
217  /**
218  * @brief at_cmd_str Send an AT command and read a single string response. Locks and unlocks ATHandler for operation
219  * @param cmd AT command in form +<CMD> (will be used also in response reading, no extra chars allowed)
220  * @param cmd_chr Char to be added to specific AT command: '?', '=' or ''. Will be used as such so '=1' is valid as well.
221  * @param resp_buf Response buffer
222  * @param resp_buf_size Response buffer size
223  * @param format Format string for variadic arguments to be added to AT command; No separator needed.
224  * Use %d for integer, %s for string and %b for byte string (requires 2 arguments: string and length)
225  * @return last error that happened when parsing AT responses
226  */
227  nsapi_error_t at_cmd_str(const char *cmd, const char *cmd_chr, char *resp_buf, size_t resp_buf_size, const char *format = "", ...);
228 
229  /**
230  * @brief at_cmd_int Send an AT command and read a single integer response. Locks and unlocks ATHandler for operation
231  * @param cmd AT command in form +<CMD> (will be used also in response reading, no extra chars allowed)
232  * @param cmd_chr Char to be added to specific AT command: '?', '=' or ''. Will be used as such so '=1' is valid as well.
233  * @param resp Integer to hold response
234  * @param format Format string for variadic arguments to be added to AT command; No separator needed.
235  * Use %d for integer, %s for string and %b for byte string (requires 2 arguments: string and length)
236  * @return last error that happened when parsing AT responses
237  */
238  nsapi_error_t at_cmd_int(const char *cmd, const char *cmd_chr, int &resp, const char *format = "", ...);
239 
240  /**
241  * @brief at_cmd_discard Send an AT command and read and discard a response. Locks and unlocks ATHandler for operation
242  * @param cmd AT command in form +<CMD> (will be used also in response reading, no extra chars allowed)
243  * @param cmd_chr Char to be added to specific AT command: '?', '=' or ''. Will be used as such so '=1' is valid as well.
244  * @param format Format string for variadic arguments to be added to AT command; No separator needed.
245  * Use %d for integer, %s for string and %b for byte string (requires 2 arguments: string and length)
246  * @return last error that happened when parsing AT responses
247  */
248  nsapi_error_t at_cmd_discard(const char *cmd, const char *cmd_chr, const char *format = "", ...);
249 
250  /** Writes integer type AT command subparameter. Starts with the delimiter if not the first param after cmd_start.
251  * In case of failure when writing, the last error is set to NSAPI_ERROR_DEVICE_ERROR.
252  *
253  * @param param int to be written to modem as AT command subparameter
254  */
255  void write_int(int32_t param);
256 
257  /** Writes string type AT command subparamater. Quotes are added to surround the given string.
258  * Starts with the delimiter if not the first param after cmd_start.
259  * In case of failure when writing, the last error is set to NSAPI_ERROR_DEVICE_ERROR.
260  *
261  * @param param string to be written to modem as AT command subparameter
262  * @param useQuotations flag indicating whether the string should be included in quotation marks
263  */
264  void write_string(const char *param, bool useQuotations = true);
265 
266  /** Stops the AT command by writing command-line terminator CR to mark command as finished.
267  */
268  void cmd_stop();
269 
270  /** Stops the AT command by writing command-line terminator CR to mark command as finished and reads the OK/ERROR response.
271  *
272  */
273  void cmd_stop_read_resp();
274 
275  /** Write bytes without any subparameter delimiters, such as comma.
276  * In case of failure when writing, the last error is set to NSAPI_ERROR_DEVICE_ERROR.
277  *
278  * @param data bytes to be written to modem
279  * @param len length of data string
280  *
281  * @return number of characters successfully written
282  */
283  size_t write_bytes(const uint8_t *data, size_t len);
284 
285  /** Sets the stop tag for the current scope (response/information response/element)
286  * Parameter's reading routines will stop the reading when such tag is found and will set the found flag.
287  * Consume routines will read everything until such tag is found.
288  *
289  * @param stop_tag_seq string to be set as stop tag
290  */
291  void set_stop_tag(const char *stop_tag_seq);
292 
293  /** Sets the delimiter between parameters or between elements of the information response.
294  * Parameter's reading routines will stop when such char is read.
295  *
296  * @param delimiter char to be set as _delimiter
297  */
298  void set_delimiter(char delimiter);
299 
300  /** Sets the delimiter to default value defined by DEFAULT_DELIMITER.
301  */
302  void set_default_delimiter();
303 
304  /** Defines behaviour for using or ignoring the delimiter within an AT command
305  *
306  * @param use_delimiter indicating if delimiter should be used or not
307  */
308  void use_delimiter(bool use_delimiter);
309 
310  /** Consumes the reading buffer up to the delimiter or stop_tag
311  *
312  * @param count number of parameters to be skipped
313  */
314  void skip_param(uint32_t count = 1);
315 
316  /** Consumes the given length from the reading buffer
317  *
318  * @param len length to be consumed from reading buffer
319  * @param count number of parameters to be skipped
320  */
321  void skip_param(ssize_t len, uint32_t count);
322 
323  /** Reads given number of bytes from receiving buffer without checking any subparameter delimiters, such as comma.
324  *
325  * @param buf output buffer for the read
326  * @param len maximum number of bytes to read
327  * @return number of successfully read bytes or -1 in case of error
328  */
329  ssize_t read_bytes(uint8_t *buf, size_t len);
330 
331  /** Reads chars from reading buffer. Terminates with null. Skips the quotation marks.
332  * Stops on delimiter or stop tag.
333  *
334  * @param str output buffer for the read
335  * @param size maximum number of chars to output including NULL
336  * @param read_even_stop_tag if true then try to read even if the stop tag was found previously
337  * @return length of output string or -1 in case of read timeout before delimiter or stop tag is found
338  */
339  ssize_t read_string(char *str, size_t size, bool read_even_stop_tag = false);
340 
341  /** Reads chars representing hex ascii values and converts them to the corresponding chars.
342  * For example: "4156" to "AV".
343  * Terminates with null. Skips the quotation marks.
344  * Stops on delimiter or stop tag.
345  *
346  * @param str output buffer for the read
347  * @param size maximum number of chars to output
348  * @return length of output string or -1 in case of read timeout before delimiter or stop tag is found
349  */
350  ssize_t read_hex_string(char *str, size_t size);
351 
352  /** Converts contained chars to their hex ascii value and writes the resulting string to the file handle
353  * For example: "AV" to "4156".
354  *
355  * @param str input buffer to be converted to hex ascii
356  * @param size of the input param str
357  */
358  void write_hex_string(const char *str, size_t size);
359 
360  /** Reads as string and converts result to integer. Supports only non-negative integers.
361  *
362  * @return the non-negative integer or -1 in case of error.
363  */
364  int32_t read_int();
365 
366  /** This looks for necessary matches: prefix, OK, ERROR, URCs and sets the correct scope.
367  *
368  * @param prefix string to be matched from receiving buffer. If not NULL and match succeeds, then scope
369  * will be set as information response(info_type)
370  * @param stop flag to indicate if we go to information response scope or not.
371  * (needed when nothing is expected to be received anymore after the prefix match:
372  * sms case: "> ", bc95 reboot case)
373  */
374  void resp_start(const char *prefix = NULL, bool stop = false);
375 
376  /** Ends all scopes starting from current scope.
377  * Consumes everything until the scope's stop tag is found, then
378  * goes to next scope until response scope is ending.
379  * URC match is checked during response scope ending,
380  * for every new line / CRLF.
381  *
382  *
383  * Possible sequence:
384  * element scope -> information response scope -> response scope
385  */
386  void resp_stop();
387 
388  /** Looks for matching the prefix given to resp_start() call.
389  * If needed, it ends the scope of a previous information response.
390  * Sets the information response scope if new prefix is found and response scope if prefix is not found.
391  *
392  * @return true if prefix defined for information response is not empty string and is found,
393  * false otherwise.
394  */
395  bool info_resp();
396 
397  /** Looks for matching the start tag.
398  * If needed, it ends the scope of a previous element.
399  * Sets the element scope if start tag is found and information response scope if start tag is not found.
400  *
401  * @param start_tag tag to be matched to begin parsing an element of an information response
402  * @return true if new element is found, false otherwise
403  */
404  bool info_elem(char start_tag);
405 
406  /** Consumes the received content until current stop tag is found.
407  *
408  * @return true if stop tag is found, false otherwise
409  */
410  bool consume_to_stop_tag();
411 
412  /** Return the last 3GPP error code.
413  * @return last 3GPP error code
414  */
415  int get_3gpp_error();
416 
417 public: // just for debugging
418  /**
419  * AT debugging, when enabled will print all data read and written,
420  * non-printable chars are printed as "[%d]".
421  *
422  * AT debug can be enabled at compile time using MBED_CONF_CELLULAR_DEBUG_AT flag or at runtime
423  * calling set_debug(). Note that MBED_CONF_MBED_TRACE_ENABLE must also be enabled.
424  *
425  * @param debug_on Enable/disable debugging
426  */
427  void set_debug(bool debug_on);
428 
429  /**
430  * Get degug state set by @ref set_debug
431  *
432  * @return current state of debug
433  */
434  bool get_debug() const;
435 
436 private: //Private structs & enums
437  struct tag_t {
438  char tag[7];
439  size_t len;
440  bool found;
441  };
442 
443  struct oob_t {
444  const char *prefix;
445  int prefix_len;
446  Callback<void()> cb;
447  oob_t *next;
448  };
449 
450  // resp_type: the part of the response that doesn't include the information response (+CMD1,+CMD2..)
451  // ends with OK or (CME)(CMS)ERROR
452  // info_type: the information response part of the response: starts with +CMD1 and ends with CRLF
453  // information response contains parameters or subsets of parameters (elements), both separated by comma
454  // elem_type: subsets of parameters that are part of information response, its parameters are separated by comma
455  enum ScopeType {
456  RespType,
457  InfoType,
458  ElemType,
459  NotSet
460  };
461 
462 private: //Private functions
463  void event();
464 
465  /** Increase reference count. Used for counting references to this instance.
466  * Note that this should be used with care, if the ATHandler was taken into use
467  * with get_instance()
468  */
469  void inc_ref_count();
470 
471  /** Decrease reference count. Used for counting references to this instance.
472  * Note that this should be used with care, if the ATHandler was taken into use
473  * with get_instance()
474  */
475  void dec_ref_count();
476 
477  /** Get the current reference count. Used for counting references to this instance.
478  *
479  * @return current reference count
480  */
481  int get_ref_count();
482 
483  /** Remove urc handler from linked list of urc's
484  *
485  * @param prefix Register urc prefix for callback. Urc could be for example "+CMTI: "
486  */
487  void remove_urc_handler(const char *prefix);
488 
489  void set_error(nsapi_error_t err);
490 
491  //Handles the arguments from given variadic list
492  void handle_args(const char *format, std::va_list list);
493 
494  //Starts an AT command based on given parameters
495  void handle_start(const char *cmd, const char *cmd_chr);
496 
497  //Checks that ATHandler does not have a pending error condition and filehandle is usable
498  bool ok_to_proceed();
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  void set_scope(ScopeType scope_type);
535 
536  ScopeType get_scope();
537 
538  // Consumes to information response stop tag which is CRLF. Sets scope to response.
539  void information_response_stop();
540  // Consumes to element stop tag. Sets scope to information response
541  void information_response_element_stop();
542 
543  // Reads the error code if expected and sets it as last error.
544  void at_error(bool error_code, DeviceErrorType error_type);
545 
546  /** Convert AT error code to 3GPP error codes
547  * @param err AT error code read from CME/CMS ERROR responses
548  * @param error_type error type (CMS/CME/ERROR)
549  */
550  void set_3gpp_error(int err, DeviceErrorType error_type);
551 
552  bool check_cmd_send();
553  size_t write(const void *data, size_t len);
554 
555  /** Finds occurrence of one char buffer inside another char buffer.
556  *
557  * @param dest destination char buffer
558  * @param dest_len length of dest
559  * @param src string to be searched for
560  * @param src_len length of string to be searched for
561  *
562  * @return pointer to first occurrence of src in dest
563  */
564  const char *mem_str(const char *dest, size_t dest_len, const char *src, size_t src_len);
565 
566  // check is urc is already added
567  bool find_urc_handler(const char *prefix);
568 
569  // print contents of a buffer to trace log
570  enum ATType {
571  AT_ERR,
572  AT_RX,
573  AT_TX
574  };
575 
576  void debug_print(const char *p, int len, ATType type);
577 
578 private: //Member variables
579 
580 #if defined AT_HANDLER_MUTEX && defined MBED_CONF_RTOS_PRESENT
581  rtos::Mutex _fileHandleMutex;
583 #endif
584  FileHandle *_fileHandle;
585 
586  events::EventQueue &_queue;
587  nsapi_error_t _last_err;
588  int _last_3gpp_error;
589  device_err_t _last_at_err;
590  uint16_t _oob_string_max_length;
591  char *_output_delimiter;
592 
593  oob_t *_oobs;
594  mbed::chrono::milliseconds_u32 _at_timeout;
595  mbed::chrono::milliseconds_u32 _previous_at_timeout;
596 
597  std::chrono::duration<uint16_t, std::milli> _at_send_delay;
598  rtos::Kernel::Clock::time_point _last_response_stop;
599 
600  int32_t _ref_count;
601  bool _is_fh_usable;
602 
603  // should fit any prefix and int
604  char _recv_buff[BUFF_SIZE];
605  // reading position
606  size_t _recv_len;
607  // reading length
608  size_t _recv_pos;
609 
610  ScopeType _current_scope;
611 
612  // tag to stop response scope
613  tag_t _resp_stop;
614  // tag to stop information response scope
615  tag_t _info_stop;
616  // tag to stop element scope
617  tag_t _elem_stop;
618  // reference to the stop tag of current scope (resp/info/elem)
619  tag_t *_stop_tag;
620 
621  // delimiter between parameters and also used for delimiting elements of information response
622  char _delimiter;
623  // set true on prefix match -> indicates start of an information response or of an element
624  bool _prefix_matched;
625  // set true on urc match
626  bool _urc_matched;
627  // set true on (CME)(CMS)ERROR
628  bool _error_found;
629  // Max length of OK,(CME)(CMS)ERROR and URCs
630  size_t _max_resp_length;
631 
632  // prefix set during resp_start and used to try matching possible information responses
633  char _info_resp_prefix[BUFF_SIZE];
634  bool _debug_on;
635  bool _cmd_start;
636  bool _use_delimiter;
637 
638  // time when a command or an URC processing was started
639  rtos::Kernel::Clock::time_point _start_time;
640  // eventqueue event id
641  int _event_id;
642 
643  char _cmd_buffer[BUFF_SIZE];
644 };
645 
646 } // namespace mbed
647 
648 #endif //AT_HANDLER_H_
EventQueue.
Definition: EventQueue.h:62
signed int nsapi_error_t
Type used to represent error codes.
Definition: nsapi_types.h:140
Class FileHandle.
Definition: FileHandle.h:46
Callback< R(ArgTs...)> callback(R(*func)(ArgTs...)=nullptr) noexcept
Create a callback class with type inferred from the arguments.
Definition: Callback.h:678
The Mutex class is used to synchronize the execution of threads.
Definition: Mutex.h:70
AT response error with error code and type.
Definition: ATHandler.h:64
The ConditionVariable class is a synchronization primitive that allows threads to wait until a partic...
Connected isochronous stream linked list.
Definition: lctr_int_cis.h:306
Callback class based on template specialization.
Definition: Callback.h:53
Definition: ATHandler.h:46
Class for sending AT commands and parsing AT responses.
Definition: ATHandler.h:70
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.