AT (Hayes) command set library.
More...
AT (Hayes) command set library.
This module provides functions to interact with devices using AT commands.
Most functions compare the bytes echoed by the device with what they intended to send, and bail out if there's no match.
Furthermore, the library tries to cope with difficulties regarding different line endings. It usually sends <command><CR>
, but expects <command>\LF\CR
as echo.
As a debugging aid, when compiled with -DAT_PRINT_INCOMING=1
, every input byte gets printed.
Command echoing
Most DCEs (Data Circuit-terminating Equipment, aka modem) support command echoing and enable it by default, and so does this driver. If you disabled echoing on the DCE, you can compile this driver NOT to expect echoing by defining CONFIG_AT_SEND_SKIP_ECHO. Note, if the driver is NOT expecting command echoing but the DCE is echoing, it should work just fine if and only if the EOL sequences of both DCE and DTE (Data Terminal Equipmend - i.e. the device using this driver) match, i.e. AT_RECV_EOL_1 AT_RECV_EOL_2 == AT_SEND_EOL
. In other words, if you are unsure about the echoing behavior of the DCE or want to support both, set AT_SEND_EOL = AT_RECV_EOL_1 AT_RECV_EOL_2 and define CONFIG_AT_SEND_SKIP_ECHO. This works because the URC (Unsolicited Result Code) logic will intercept the echoes (see below).
Unsolicited Result Codes (URC)
An unsolicited result code is a string message that is not triggered as a information text response to a previous AT command and can be output at any time to inform a specific event or status change.
Some DCEs (Data Circuit-terminating Equipment, aka modem), like the LTE modules from uBlox define a grace period where URCs are guaranteed NOT to be sent as the time span between:
- the command EOL character reception AND command being internally accepted
- the EOL character of the last response line
As follows, there is an indeterminate amount of time between:
- the command EOL character being sent
- the command EOL character reception AND command being internally accepted, i.e. the begin of the grace period
In other words, we can get a URC (or more?) just after issuing the command and before the first line of response. The net effect is that such URCs will appear to be the first line of response to the last issued command.
Regardless of whether URC handling is enabled or not, URC interception mechanics depend on command echoing:
- echo enabled: by observation, it seems that the grace period begins BEFORE the echoed command. This has the advantage that we ALWAYS know what the first line of response must look like and so if it doesn't, then it's a URC. Thus, any procedure that calls at_send_cmd() internally will catch any URC.
- echo disabled: commands that expect a particular type of response (e.g. at_send_cmd_get_resp_wait_ok() with a non-trivial prefix, at_send_cmd_wait_ok() etc.) will catch any URC. For the rest, it is the application's responsibility to decide whether the received answer is an URC or not and if yes, then at_postprocess_urc() can be called with the response as parameter.
URC handling can be enabled by adding the at_urc
module to the application. This allows to register and de-register URC strings to check. Later, URCs can be processed in three different ways:
- automatically, whenever any at_* method that intercepts URCs is called. Such methods are marked in their docstring
- manually, by calling at_process_urc() periodically
- manually, by calling at_postprocess_urc() with an URC as parameter. The URC is assumed to have been obtained from the device through methods that do not automatically handle URCs (for example through at_recv_bytes()) If a registered URC has been detected the correspondent callback function is called.
Error reporting
Most DCEs (Data Circuit-terminating Equipment, aka modem) can return extra error information instead of the rather opaque "ERROR" message. They have the form:
+CMS ERROR: err_code>
for SMS-related commands
+CME ERROR: <err_code>
for other commands
For +CME
, this behavior is usually off by default and can be toggled with: AT+CMEE=<type>
where <type>
may be:
- 0 disable extended error reporting, return
ERROR
- 1 enable extended error reporting, with
<err_code>
integer
- 2 enable extended error reporting, with
<err_code>
as string Check your DCE's manual for more information.
Some of the API calls below support detailed error reporting. Whenever they detect extended error responses, -AT_ERR_EXTENDED is returned and <err_code>
can be retrieved by calling at_get_err_info().
|
file | at.h |
| AT (Hayes) library interface.
|
|
|
typedef void(* | at_urc_cb_t) (void *arg, const char *code) |
| Unsolicited result code callback.
|
|
|
static char const * | at_get_err_info (at_dev_t const *dev) |
| Get extended error information of the last command sent.
|
|
int | at_dev_init (at_dev_t *dev, at_dev_init_t const *init) |
| Initialize AT device struct.
|
|
int | at_send_cmd_wait_ok (at_dev_t *dev, const char *command, uint32_t timeout) |
| Simple command helper.
|
|
int | at_send_cmd_wait_prompt (at_dev_t *dev, const char *command, uint32_t timeout) |
| Send AT command, wait for a prompt.
|
|
int | at_wait_prompt (at_dev_t *dev, uint32_t timeout) |
| Waits for the prompt character (>).
|
|
ssize_t | at_send_cmd_get_resp (at_dev_t *dev, const char *command, char *resp_buf, size_t len, uint32_t timeout) |
| Send AT command, wait for response.
|
|
ssize_t | at_get_resp_with_prefix (at_dev_t *dev, const char *resp_prefix, char *resp_buf, size_t len, uint32_t timeout) |
| Wait for a response with a specific prefix.
|
|
ssize_t | at_send_cmd_get_resp_wait_ok (at_dev_t *dev, const char *command, const char *resp_prefix, char *resp_buf, size_t len, uint32_t timeout) |
| Send AT command, wait for response plus OK.
|
|
ssize_t | at_send_cmd_get_lines (at_dev_t *dev, const char *command, char *resp_buf, size_t len, uint32_t timeout) |
| Send AT command, wait for multiline response.
|
|
int | at_expect_bytes (at_dev_t *dev, const char *bytes, uint32_t timeout) |
| Expect bytes from device.
|
|
int | at_wait_bytes (at_dev_t *dev, const char *bytes, uint32_t timeout) |
| Repeatedly calls at_expect_bytes() until a match or timeout occurs.
|
|
int | at_recv_bytes_until_string (at_dev_t *dev, const char *string, char *bytes, size_t *bytes_len, uint32_t timeout) |
| Receives bytes into bytes buffer until the string pattern string is received or the buffer is full.
|
|
void | at_send_bytes (at_dev_t *dev, const char *bytes, size_t len) |
| Send raw bytes to a device.
|
|
ssize_t | at_recv_bytes (at_dev_t *dev, char *bytes, size_t len, uint32_t timeout) |
| Receive raw bytes from a device.
|
|
int | at_send_cmd (at_dev_t *dev, const char *command, uint32_t timeout) |
| Send command to device.
|
|
int | at_parse_resp (at_dev_t *dev, char const *resp) |
| Parse a response from the device.
|
|
ssize_t | at_readline (at_dev_t *dev, char *resp_buf, size_t len, bool keep_eol, uint32_t timeout) |
| Read a line from device.
|
|
ssize_t | at_readline_skip_empty (at_dev_t *dev, char *resp_buf, size_t len, bool keep_eol, uint32_t timeout) |
| Read a line from device, skipping a possibly empty line.
|
|
int | at_wait_ok (at_dev_t *dev, uint32_t timeout) |
| Wait for an OK response.
|
|
void | at_drain (at_dev_t *dev) |
| Drain device input buffer.
|
|
void | at_dev_poweron (at_dev_t *dev) |
| Power device on.
|
|
void | at_dev_poweroff (at_dev_t *dev) |
| Power device off.
|
|
void | at_add_urc (at_dev_t *dev, at_urc_t *urc) |
| Add a callback for an unsolicited response code.
|
|
void | at_remove_urc (at_dev_t *dev, at_urc_t *urc) |
| Remove an unsolicited response code from the list.
|
|
void | at_process_urc (at_dev_t *dev, uint32_t timeout) |
| Process out-of-band data received from the device.
|
|
void | at_postprocess_urc (at_dev_t *dev, char *buf) |
| Process one URC from the provided buffer.
|
|
void | at_postprocess_urc_all (at_dev_t *dev, char *buf) |
| Process all URCs from the provided buffer.
|
|
◆ AT_ERR_EXTENDED
#define AT_ERR_EXTENDED 200 |
Error cause can be further investigated.
Definition at line 216 of file at.h.
◆ AT_SEND_EOL_LEN
Shortcut for getting send end of line length.
Definition at line 219 of file at.h.
◆ at_urc_cb_t
typedef void(* at_urc_cb_t) (void *arg, const char *code) |
Unsolicited result code callback.
- Parameters
-
[in] | arg | optional argument |
[in] | code | urc string received from the device |
Definition at line 201 of file at.h.
◆ at_add_urc()
Add a callback for an unsolicited response code.
- Parameters
-
[in] | dev | device to operate on |
[in] | urc | unsolicited result code to register |
◆ at_dev_init()
Initialize AT device struct.
- Parameters
-
[in] | dev | struct to initialize |
[in] | init | init struct, may be destroyed after return |
- Return values
-
success | code UART_OK on success |
error | code UART_NODEV or UART_NOBAUD otherwise |
◆ at_dev_poweroff()
Power device off.
- Parameters
-
[in] | dev | device to power off |
◆ at_dev_poweron()
Power device on.
- Parameters
-
[in] | dev | device to power on |
◆ at_drain()
Drain device input buffer.
This function drains any possible bytes waiting in the device's input buffer.
- Parameters
-
[in] | dev | device to operate on |
◆ at_expect_bytes()
int at_expect_bytes |
( |
at_dev_t * |
dev, |
|
|
const char * |
bytes, |
|
|
uint32_t |
timeout |
|
) |
| |
Expect bytes from device.
- Parameters
-
[in] | dev | device to operate on |
[in] | bytes | buffer containing bytes to expect (NULL-terminated) |
[in] | timeout | timeout (in usec) |
- Return values
-
◆ at_get_err_info()
static char const * at_get_err_info |
( |
at_dev_t const * |
dev | ) |
|
|
inlinestatic |
Get extended error information of the last command sent.
If a previous at_* method returned with -AT_ERR_EXTENDED, you can retrieve a pointer to the error string with this.
- Parameters
-
[in] | dev | device to operate on |
- Return values
-
string | containing the error value. |
Definition at line 267 of file at.h.
◆ at_get_resp_with_prefix()
ssize_t at_get_resp_with_prefix |
( |
at_dev_t * |
dev, |
|
|
const char * |
resp_prefix, |
|
|
char * |
resp_buf, |
|
|
size_t |
len, |
|
|
uint32_t |
timeout |
|
) |
| |
Wait for a response with a specific prefix.
If the provided prefix is NULL or empty, this behaves just like at_readline_skip_empty(). Otherwise, it repeatedly calls at_readline_skip_empty() and:
- if the prefix matches: discards the prefix from the response, copies the rest to
resp_buf
, stops and returns the resulting response length
- if the prefix does not match:
- if the response is OK: stops and returns 0
- if the response is ERROR/CMx ERROR: stops and returns <0
- none of the above: handles response as URC and repeats with the next line
- Parameters
-
[in] | dev | device to operate on |
[in] | resp_prefix | expected prefix in the response |
[out] | resp_buf | buffer for storing response |
[in] | len | len of buffer |
[in] | timeout | timeout (in usec) |
- Return values
-
n | response length if the prefix of the response matches |
0 | if the response was OK |
-AT_ERR_EXTENDED | if failed and a error code can be retrieved with at_get_err_info() (i.e. DCE answered with CMx ERROR ) |
<0 | on error |
◆ at_parse_resp()
int at_parse_resp |
( |
at_dev_t * |
dev, |
|
|
char const * |
resp |
|
) |
| |
Parse a response from the device.
This is always called automatically in functions that may return -AT_ERR_EXTENDED. However, if you read the response by other methods (e.g. with at_recv_bytes()), you might want to call this on the response so that you don't have to parse it yourself.
- Return values
-
0 | if the response is "OK" |
-AT_ERR_EXTENDED | if the response is +CMx ERROR: <err> , and <err> has been successfully copied to dev->rp_buf |
-1 | if the response is "ERROR", or +CMx ERROR: <err> but <err> could not be copied |
1 | otherwise |
◆ at_postprocess_urc()
void at_postprocess_urc |
( |
at_dev_t * |
dev, |
|
|
char * |
buf |
|
) |
| |
Process one URC from the provided buffer.
Useful if you e.g. called at_send_cmd_get_lines() and the first lines are URCs.
- Parameters
-
[in] | dev | device to operate on |
[in] | buf | buffer containing an URC |
◆ at_postprocess_urc_all()
void at_postprocess_urc_all |
( |
at_dev_t * |
dev, |
|
|
char * |
buf |
|
) |
| |
Process all URCs from the provided buffer.
Useful if you e.g. called at_recv_bytes(), found what you were interested in, and there might be some URCs left in the buffer.
- Parameters
-
[in] | dev | device to operate on |
[in] | buf | buffer containing URCs |
◆ at_process_urc()
void at_process_urc |
( |
at_dev_t * |
dev, |
|
|
uint32_t |
timeout |
|
) |
| |
Process out-of-band data received from the device.
- Parameters
-
[in] | dev | device to operate on |
[in] | timeout | timeout (in usec) |
◆ at_readline()
ssize_t at_readline |
( |
at_dev_t * |
dev, |
|
|
char * |
resp_buf, |
|
|
size_t |
len, |
|
|
bool |
keep_eol, |
|
|
uint32_t |
timeout |
|
) |
| |
Read a line from device.
Stops at the first DCE EOL sequence. The response is guaranteed null-terminated.
- Parameters
-
[in] | dev | device to operate on |
[in] | resp_buf | buffer to store line |
[in] | len | size of resp_buf |
[in] | keep_eol | true to keep the trailing EOL sequence in the response |
[in] | timeout | timeout (in usec) |
- Return values
-
n | line length on success |
-ENOBUFS | if the supplied buffer was to small. |
<0 | on error |
◆ at_readline_skip_empty()
ssize_t at_readline_skip_empty |
( |
at_dev_t * |
dev, |
|
|
char * |
resp_buf, |
|
|
size_t |
len, |
|
|
bool |
keep_eol, |
|
|
uint32_t |
timeout |
|
) |
| |
Read a line from device, skipping a possibly empty line.
Stops at the first DCE EOL sequence AFTER any non-EOL sequence. The response is guaranteed null-terminated.
- Parameters
-
[in] | dev | device to operate on |
[in] | resp_buf | buffer to store line |
[in] | len | size of resp_buf |
[in] | keep_eol | true to keep the trailing EOL sequence in the response |
[in] | timeout | timeout (in usec) |
- Return values
-
n | line length on success |
-ENOBUFS | if the supplied buffer was to small. |
<0 | on error |
◆ at_recv_bytes()
ssize_t at_recv_bytes |
( |
at_dev_t * |
dev, |
|
|
char * |
bytes, |
|
|
size_t |
len, |
|
|
uint32_t |
timeout |
|
) |
| |
Receive raw bytes from a device.
- Parameters
-
[in] | dev | device to operate on |
[in] | bytes | buffer where store received bytes |
[in] | len | maximum number of bytes to receive |
[in] | timeout | timeout (in usec) of inactivity to finish read |
- Return values
-
n | Number of bytes read, eventually zero if no bytes available |
◆ at_recv_bytes_until_string()
int at_recv_bytes_until_string |
( |
at_dev_t * |
dev, |
|
|
const char * |
string, |
|
|
char * |
bytes, |
|
|
size_t * |
bytes_len, |
|
|
uint32_t |
timeout |
|
) |
| |
Receives bytes into bytes
buffer until the string pattern string
is received or the buffer is full.
- Parameters
-
[in] | dev | device to operate on |
[in] | string | string pattern to expect |
[out] | bytes | buffer to store received bytes |
[in,out] | bytes_len | pointer to the maximum number of bytes to receive. On return stores the amount of received bytes. |
[in] | timeout | timeout (in usec) of inactivity to finish read |
- Return values
-
◆ at_remove_urc()
Remove an unsolicited response code from the list.
- Parameters
-
[in] | dev | device to operate on |
[in] | urc | unsolicited result code to remove |
◆ at_send_bytes()
void at_send_bytes |
( |
at_dev_t * |
dev, |
|
|
const char * |
bytes, |
|
|
size_t |
len |
|
) |
| |
Send raw bytes to a device.
- Parameters
-
[in] | dev | device to operate on |
[in] | bytes | buffer containing bytes to send |
[in] | len | number of bytes to send |
◆ at_send_cmd()
int at_send_cmd |
( |
at_dev_t * |
dev, |
|
|
const char * |
command, |
|
|
uint32_t |
timeout |
|
) |
| |
Send command to device.
Some URCs may be handled.
- Parameters
-
[in] | dev | device to operate on |
[in] | command | command to send |
[in] | timeout | timeout (in usec) |
- Return values
-
◆ at_send_cmd_get_lines()
ssize_t at_send_cmd_get_lines |
( |
at_dev_t * |
dev, |
|
|
const char * |
command, |
|
|
char * |
resp_buf, |
|
|
size_t |
len, |
|
|
uint32_t |
timeout |
|
) |
| |
Send AT command, wait for multiline response.
This function sends the supplied command
, then returns all response lines until the device sends "OK". The response is guaranteed null-terminated.
Some URCs are automatically handled. The first m response lines can be URCs. In that case, at_postprocess_urc() can be called with each line as parameter.
If a line contains a DTE error response, this function stops and returns accordingly. Any lines received prior to that are considered to be URCs and thus handled.
- Parameters
-
[in] | dev | device to operate on |
[in] | command | command to send |
[out] | resp_buf | buffer for storing response |
[in] | len | len of resp_buf |
[in] | timeout | timeout (in usec) |
- Return values
-
n | length of response on success |
-AT_ERR_EXTENDED | if failed and a error code can be retrieved with at_get_err_info() (i.e. DCE answered with CMx ERROR ) |
-ENOBUFS | if the supplied buffer was to small. |
<0 | other failures |
◆ at_send_cmd_get_resp()
ssize_t at_send_cmd_get_resp |
( |
at_dev_t * |
dev, |
|
|
const char * |
command, |
|
|
char * |
resp_buf, |
|
|
size_t |
len, |
|
|
uint32_t |
timeout |
|
) |
| |
Send AT command, wait for response.
This function sends the supplied command
, then waits and returns one line of response. The response is guaranteed null-terminated.
Some URCs are automatically handled. The response returned can be an URC. In that case, at_postprocess_urc() can be called with the response as parameter.
A possible empty line will be skipped.
- Parameters
-
[in] | dev | device to operate on |
[in] | command | command to send |
[out] | resp_buf | buffer for storing response |
[in] | len | len of buffer |
[in] | timeout | timeout (in usec) |
- Return values
-
n | length of response on success |
-ENOBUFS | if the supplied buffer was to small. |
<0 | on error |
◆ at_send_cmd_get_resp_wait_ok()
ssize_t at_send_cmd_get_resp_wait_ok |
( |
at_dev_t * |
dev, |
|
|
const char * |
command, |
|
|
const char * |
resp_prefix, |
|
|
char * |
resp_buf, |
|
|
size_t |
len, |
|
|
uint32_t |
timeout |
|
) |
| |
Send AT command, wait for response plus OK.
This function sends the supplied command
, then waits and returns one line of response. The response is guaranteed null-terminated.
Calls following in order:
URCs are automatically handled. If no prefix is provided, the response may be an URC. In that case, at_postprocess_urc() can be called with the response as parameter.
- Parameters
-
[in] | dev | device to operate on |
[in] | command | command to send |
[in] | resp_prefix | expected prefix in the response |
[out] | resp_buf | buffer for storing response |
[in] | len | len of buffer |
[in] | timeout | timeout (in usec) |
- Return values
-
n | length of response on success |
-AT_ERR_EXTENDED | if failed and a error code can be retrieved with at_get_err_info() (i.e. DCE answered with CMx ERROR ) |
-ENOBUFS | if the supplied buffer was to small. |
<0 | other failures |
◆ at_send_cmd_wait_ok()
int at_send_cmd_wait_ok |
( |
at_dev_t * |
dev, |
|
|
const char * |
command, |
|
|
uint32_t |
timeout |
|
) |
| |
Simple command helper.
This function sends an AT command to the device and waits for "OK".
URCs are automatically handled
- Parameters
-
[in] | dev | device to operate on |
[in] | command | command string to send |
[in] | timeout | timeout (in usec) |
- Return values
-
0 | when device answers "OK" |
-AT_ERR_EXTENDED | if failed and a error code can be retrieved with at_get_err_info() (i.e. DCE answered with CMx ERROR ) |
<0 | other failures |
◆ at_send_cmd_wait_prompt()
int at_send_cmd_wait_prompt |
( |
at_dev_t * |
dev, |
|
|
const char * |
command, |
|
|
uint32_t |
timeout |
|
) |
| |
Send AT command, wait for a prompt.
This function sends the supplied command
, then waits for the prompt (>) character and returns
URCs are automatically handled
- Parameters
-
[in] | dev | device to operate on |
[in] | command | command string to send |
[in] | timeout | timeout (in usec) |
- Return values
-
0 | when prompt is received |
-AT_ERR_EXTENDED | if failed and a error code can be retrieved with at_get_err_info() (i.e. DCE answered with CMx ERROR ) |
<0 | other failures |
◆ at_wait_bytes()
int at_wait_bytes |
( |
at_dev_t * |
dev, |
|
|
const char * |
bytes, |
|
|
uint32_t |
timeout |
|
) |
| |
Repeatedly calls at_expect_bytes() until a match or timeout occurs.
- Parameters
-
[in] | dev | device to operate on |
[in] | bytes | buffer containing bytes to expect (NULL-terminated) |
[in] | timeout | timeout (in usec) |
- Return values
-
◆ at_wait_ok()
int at_wait_ok |
( |
at_dev_t * |
dev, |
|
|
uint32_t |
timeout |
|
) |
| |
Wait for an OK response.
Useful when crafting the command-response sequence by yourself.
URCs are automatically handled
- Parameters
-
[in] | dev | device to operate on |
[in] | timeout | timeout (in usec) |
- Return values
-
0 | when device answers "OK" |
-AT_ERR_EXTENDED | if failed and a error code can be retrieved with at_get_err_info() (i.e. DCE answered with CMx ERROR ) |
<0 | other failures |
◆ at_wait_prompt()
int at_wait_prompt |
( |
at_dev_t * |
dev, |
|
|
uint32_t |
timeout |
|
) |
| |
Waits for the prompt character (>).
- Parameters
-
[in] | dev | device to operate on |
[in] | timeout | timeout (in usec) |
- Return values
-
0 | when prompt is received |
-AT_ERR_EXTENDED | if failed and a error code can be retrieved with at_get_err_info() (i.e. DCE answered with CMx ERROR ) |
<0 | other failures |