-
Notifications
You must be signed in to change notification settings - Fork 32
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
ATI response cannot be parsed as String, but can as Bytes #149
Comments
Hmm. Without any more context, it's a bit hard to tell why, but the main difference between bytes & string, is that a string reply must be quoted explicitly (So you cannot just parse a bytes response as a string response currently) |
Ah so I guess this is intended behaviour then. So only when the modem returns explicit |
Currently, this is the behavior, yes. I would have no objections against adding some sort of derive attribute option to the string implementation, that allows skipping the quotes in either end? I currently have no use cases for this myself, so I won't be adding it, but you are more than welcome to open a PR with it? 😃 |
I ran into this problem at work and came up with the following solution. I'm not particularly proud of it but it's an ok stopgap until something nicer comes along :) /// A helper to deserialize unquoted strings in AT responses.
struct UnquotedStringVisitor<const N: usize>;
impl<'de, const N: usize> Visitor<'de> for UnquotedStringVisitor<N> {
type Value = heapless::String<N>;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("an unquoted string")
}
fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E>
where
E: de::Error,
{
let s = std::str::from_utf8(v).map_err(serde::de::Error::custom)?;
if s.len() > N {
Err(serde::de::Error::custom("Source string too long"))
} else {
Ok(s.into())
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct UnquotedHeaplessString<const N: usize>(pub heapless::String<N>);
impl<'de, const N: usize> Deserialize<'de> for UnquotedHeaplessString<N> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let out = deserializer.deserialize_bytes(UnquotedStringVisitor)?;
Ok(Self(out))
}
}
impl<const N: usize> From<&str> for UnquotedHeaplessString<N> {
fn from(s: &str) -> Self {
Self(s.into())
}
}
impl<const N: usize> fmt::Display for UnquotedHeaplessString<N> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(&self.0)
}
} |
For me seemingly not. Using MQTT on a Quectel, I also see that I can't get the result of the messages, which feature two texts included in double quotes, when defining the elements in the OnReceive struct as heapless strings. This seems even more weird than the first post, as using double quotes for strings seems rather common. I in fact in that case do not get a Parse error, but no reaction by ATAT at all (other than log). I did doublecheck that the modem response fits the Urc enum arm definition. |
@ijager @MathiasKoch -Michael |
Are there already any derive attributes that define the behavior of the parser differently from what the main derive macro extracts from the type of the struct elements ? In the other issue thread I found |
I think you are mixing request/response and URCs here. For the request response it is all handled by AtatCmd and AtatResponse that can both be derived, URC parser has nothing to do with these at all |
I'm not in the office right now. I'll do more testing ASAP. (Hoping to be able to avoid the implementation of my own parser for the response of communication as simple as |
@mschnell1 I am also implementing Quectel MQTT commands for the EC25. Just managed to connect to a broker. Next step I think is also those URC's and some state machine to progress through the necessary commands. I did notice that other commands such as @MathiasKoch I am not particularly interested in the |
I managed to get a connection, subscribe to a topic, send a message to the topic and (via the log) see the correct topic update message from the server. Have you already been able to decently be notified by ATAT about a received topic massage from the broker ?
You can use the log feature of ATAT to see the complete dialog with the modem.
Up till now I don't get the QMTT response even though it is quoted. -Michael |
Yes when I turn on logging for atat it shows quotes, but when I sniff the communication with a serial - usb converter there are no quotes. So maybe the quotes are added somewhere in atat? I will try to implement subscribing today. |
Using MQTT on a Quectel, I also see that I can't get the result of the messages, which feature two texts included in double quotes, when defining the elements in the OnReceive struct as heapless strings. |
Edit: by some magic I now get a correct This happend after I added a |
Well, if you are receiving URC's that are not defined in the |
@mschnell1 I got it working now, the This is my Urc enum so far: #[derive(Clone, AtatUrc, Debug)]
pub enum Urc {
#[at_urc("+QMTOPEN")]
MqttOpen(commands::mqtt::urc::MqttOpen),
#[at_urc("+QMTCONN")]
MqttConnect(commands::mqtt::urc::MqttConnect),
#[at_urc("+QMTSUB")]
MqttSubscribe(commands::mqtt::urc::MQTTSubscribe),
#[at_urc("+QMTRECV")]
MQTTReceive(commands::mqtt::urc::MQTTReceive)
}
// and the urc structs
#[derive(Clone, Debug, AtatResp)]
pub struct MqttOpen {
pub client_idx: u8,
pub result: u8,
}
#[derive(Clone, Debug, AtatResp)]
pub struct MqttConnect {
pub client_idx: u8,
pub result: u8,
pub ret_code: u8,
}
#[derive(Clone, Debug, AtatResp)]
pub struct MQTTSubscribe {
pub client_idx: u8,
pub msg_id: u8,
pub result: u8,
pub value: u8,
}
#[derive(Clone, Debug, AtatResp)]
pub struct MQTTReceive {
pub client_idx: u8,
pub msg_id: u8,
pub topic: String<32>,
pub len: u8,
pub payload: String<32>
} Here is my full log output in case it helps:
And this is what I see on the uart lines: RDY
AT
OK
ATE1
OK
ATI
Quectel
EC25
Revision: EC25EFAR06A09M4G
OK
AT+CGMI
Quectel
OK
AT+CGMM
EC25
OK
AT+CGMR
EC25EFAR06A09M4G
OK
AT+CGDCONT=1,"IP","portalmmm.nl"
OK
AT+QIACT=1
OK
AT+QMTCFG="recv/mode",1,0,1
OK
AT+QMTOPEN=1,"mybroker.xyz",1883
OK
AT
OK
+QMTOPEN: 1,0
AT+QMTCONN=1,"Ingmar"
OK
+QMTCONN: 1,0,0
AT+QMTSUB=1,1,"blink",0
OK
+QMTSUB: 1,1,0,0
+QMTRECV: 1,0,"blink",5,"start"
+QMTRECV: 1,0,"blink",5,"hello" |
Nasty, but supposedly unavoidable. This seems to mean that any possible response by the modem needs to be covered in the Urc enum.... |
So far i haven't found a better approach, but to be fair most URC's are default disabled on most modems, and needs to be explicitly enabled. At least on the modems i have used? |
@ijager
but I still get the send() result: Any further idea ? Btw.: is it appropriate to do such "silly user" discussions in an "issue" thread ? -Michael |
Sorry for continuing being a PITA.....
Thanks for listening ! |
at_arg is documented as part of the relevant derive macro in atat_derive; https://github.com/BlackbirdHQ/atat/blob/master/atat_derive/src/lib.rs#L141-L165 |
As for two this is supported and i use it multiple places, but for now it requires you to split it into two commands as And then they can be used as: |
As for question 3, i think that requires more knowledge about the modem than i have at present, and sounds less like an atat question? If not i would need more info about what you are asking? |
I am using
It is actually a different crate:
There is also the matrix chat |
As far as I understand, the Modem can handle binary payload in such way:
Now the payload can contain any characters including quotes, comma, etc. Only by relying on the length parameter, the receiver can know the end of the payload. The "URC parser" needs to support this in some way. |
Ahh, yeah that is a very common way of doing it in AT commands, but it is not currently supported in ATAT :/ Contributions are welcomed. |
Yep that works.
|
Yep ! |
Sorry for continuing being a PITA. And after this I need to send a certain count of bytes as the raw payload. How to do this ? I get close to that by
This does seem to work. -Michael |
@ijager : How do you progress with MQTT ? |
I just implemented |
Yep. That does work fine for me, as well. I just did not find out how to be sure that the callback I get between the parts in fact is a "Prompt" (which ATAT seems to be detecting) or something else (such as an But In fact I would like to transfer binary data. The modem does handle this decently, but ATAT can't cope with a double quote or any bytes > 127 in the payload. Thanks, |
I noticed the following when trying out
atat
. When defining ATI response usingheapless::Bytes
it parses correctly.The response:
But when using
heapless::String
it results inError::Parse
.Perhaps still the same issue as in #86.
The text was updated successfully, but these errors were encountered: