-
Notifications
You must be signed in to change notification settings - Fork 2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
drivers/at: parse +CME/+CMS responses and save error value #20289
Conversation
|
@@ -88,18 +96,54 @@ static void _isrpipe_write_one_wrapper(void *_dev, uint8_t data) | |||
#endif | |||
} | |||
|
|||
int at_dev_init(at_dev_t *dev, uart_t uart, uint32_t baudrate, char *buf, size_t bufsize) | |||
int at_dev_init(at_dev_t *dev, at_dev_init_t const *init) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Argument list was getting too long.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is that really a problem?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think a long argument list is less visible. Especially when it comes to similar-typed arguments - we have two buffers now.
@@ -224,8 +268,7 @@ int at_send_cmd(at_dev_t *dev, const char *command, uint32_t timeout) | |||
return -1; | |||
} | |||
|
|||
if (at_expect_bytes(dev, CONFIG_AT_SEND_EOL AT_RECV_EOL_1 AT_RECV_EOL_2, | |||
timeout)) { | |||
if (at_expect_bytes(dev, CONFIG_AT_SEND_EOL, timeout)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- this was buggy.
AT_RECV_EOL_1 AT_RECV_EOL_2
is returned no matter if the command echoing feature is enabled or not. - some commands do not reply with a newline at all, most notably the prompt commands (on Ublox LTE modules, they return
>
directly instead of e.g.\r\n>
). As most commands parse the response withat_readline_skip_empty()
, this newline pruning is no longer needed here. The only exception isat_send_cmd_get_lines()
, which adds empty lines to the response too. It is now patched that it skips the first empty line.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
BTW. I created #20281 because it allows me to see exactly what the modem is returning for an AT command. For example:
2024-01-24 22:26:30,373 # send 1 AT+COPS?
2024-01-24 22:26:30,374 # UART_DEV(1) TX: AT+COPS?
> 2024-01-24 22:26:30,401 # Success: UART_DEV(1) RX: [AT+COPS?\r\r\n]
2024-01-24 22:26:30,403 # Success: UART_DEV(1) RX: [+COPS: 0\r\n]
2024-01-24 22:26:30,404 # Success: UART_DEV(1) RX: [\r\n]
2024-01-24 22:26:30,405 # Success: UART_DEV(1) RX: [OK\r\n]
@@ -2,8 +2,11 @@ include ../Makefile.drivers_common | |||
|
|||
USEMODULE += shell | |||
USEMODULE += at | |||
USEMODULE += at_urc_isr_medium |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Async URC handling is broken. See this issue.
The title of this PR does not really cover the actual redesign that is going on. |
Funny note. This evening I started looking at the |
Looks good. Nice way of detecting echoes! |
Right, so next step is to fix the URC handling (as a first step, synchronously only). I wonder if I should open a separate PR for that, or to add it here and change the name to something like drivers/at: redesign error reporting and URC handling. |
drivers/at/at.c
Outdated
res = at_parse_resp(dev, pos); | ||
|
||
switch (res) { | ||
case 0: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please add a short comment
drivers/include/at.h
Outdated
@@ -177,6 +198,8 @@ typedef struct { | |||
typedef struct { | |||
isrpipe_t isrpipe; /**< isrpipe used for getting data from uart */ | |||
uart_t uart; /**< UART device where the AT device is attached */ | |||
char *err_buf; /**< error buffer */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is an error buffer?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See line 61.
@@ -88,18 +96,54 @@ static void _isrpipe_write_one_wrapper(void *_dev, uint8_t data) | |||
#endif | |||
} | |||
|
|||
int at_dev_init(at_dev_t *dev, uart_t uart, uint32_t baudrate, char *buf, size_t bufsize) | |||
int at_dev_init(at_dev_t *dev, at_dev_init_t const *init) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is that really a problem?
drivers/include/at.h
Outdated
uint32_t baudrate; /**< UART device baudrate */ | ||
char *rx_buf; /**< UART rx buffer */ | ||
size_t rx_buf_size; /**< UART rx buffer size */ | ||
char *err_buf; /**< error buffer */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can this be NULL
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it make sense to allow this?
There was no error reporting before, so if a user doesn't need this, they might not want to pay for the additional buffer.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll have a look at this next week, it makes sense.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, on a second thought, it cannot be easily done. The whole PR revolves around the idea that there is always a buffer that can be used for response analysis - either the response buffer, if the command returns a response to the user; or the error buffer otherwise.
However, for the integer error value case, this buffer can be very small, just to hold a response like +CME ERROR: 1234
. I can document this.
drivers/at/at.c
Outdated
size_t const cmx_prefix_len = strlen("+CMx ERROR: "); | ||
if (strncmp("+CME ERROR: ", resp, cmx_prefix_len) && | ||
strncmp("+CMS ERROR: ", resp, cmx_prefix_len)) { | ||
// A command may return either one or the other, we need not differentiate |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The comment should mention that it is the "otherwise" condition.
In other words, it is NOT prefix "+CME ERROR: "
AND it is NOT prefix "+CMS ERROR: "
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My concerns have been addressed, just some small comments.
CI is complaining about trailing whitespaces, you want to fix those.
* | ||
* @retval success code UART_OK on success | ||
* @retval error code UART_NODEV or UART_NOBAUD otherwise | ||
*/ | ||
int at_dev_init(at_dev_t *dev, uart_t uart, uint32_t baudrate, char *buf, size_t bufsize); | ||
int at_dev_init(at_dev_t *dev, at_dev_init_t const *init); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
int at_dev_init(at_dev_t *dev, at_dev_init_t const *init); | |
int at_dev_init(at_dev_t *dev, const at_dev_init_t *init); |
feels more idiomatic
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't know about that. I use east const for consistency, e.g.
char const *const c;
is more consistent than
const char *const c;
in the sense that const
applies to whatever is to the left
size_t resp_len = strlen(resp); | ||
if (resp_len + 1 > dev->rp_buf_size) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
size_t resp_len = strlen(resp); | |
if (resp_len + 1 > dev->rp_buf_size) { | |
size_t resp_len = strlen(resp) + 1; | |
if (resp_len > dev->rp_buf_size) { |
is a bit nicer to read
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It means response string length and I want to keep it consistent across the whole file, otherwise it might get confusing quickly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please squash
Parse +CME/+CMS responses and save error value
Contribution description
Motivation
Modems, especially mobile ones, can be very shaky. As such, in the scope of debugging, it is very helpful to know failure reasons.
Luckily, many modems can offer detailed error codes. Once this feature is enabled, they will answer with
+CME ERROR: <error_code>
(or+CMS ERROR: <error_code>
for SMS-related commands), where<error_code>
is either an integer error code or a string. This is much better than the standardERROR
response, which provides no further information.Unfortunately, in the current state, the AT driver does not parse any errors. Generally, if the response is not
OK
then-1
is returned and that's it.Contribution
This patch enables extended error parsing. If a
+CME/+CMS
answer is detected, most functions will return-AT_ERR_EXTENDED
, and the<error_code>
will be available in a buffer for further inspection.Design considerations
I tried to keep the changes at a minimum, maintain API compatibility and offer a clean solution at the same time. At the end, I had to sacrifice on change minimalism. As follows, this is a big PR. Individual changes are annotated inline.
Anyway, some generalities:
<error_response>
is retrievable from a buffer instead of parsing and returning it as an error code because, depending modem configuration, it might be a string. Let the user handle that.Testing procedure
See tests/drivers/at/tests-with-config/emulate_dce.py.