Closed mschnell1 closed 1 year ago
I now found the "Manufacturer identification" example in the master branch repository,
trying to get this going
...
In my example project, I could insert, compile and execute the "ManufacturerId" code from this example but now get Err(Error)
instead of Err(Parse)
when sending ATI
(the modem I use returns ERROR
on AT+CGMI
). (I see the correct output of the modem in the ATAT trace.)
Weird: the string sent to the modem seems to be ATI=""
.
Now researching on how the example on GitHib avoids "Buffers"...
Hi.
Sorry about the missing documentation. I am not quite sure that I understand the actual issue you are facing, though?
the modem I use returns ERROR on AT+CGMI
This seems unrelated to ATAT? In that case your modem probably doesn't support +CGMI
?
Now researching on how the example on GitHib avoids "Buffers"...
But, it doesn't? And why would you avoid Buffers
? https://github.com/BlackbirdHQ/atat/blob/5a06fed2ee842c63619e397b572f5716d4be1b7f/examples/src/bin/std-tokio.rs#L19-L20
Thanks for the Reply !! Of course using the work in progress, I don't expect perfect documentation, but am very happy to be able to take advantage of the crate.
I now did test AT+GMI
instead of AT+CGMI
and this does work perfectly with my example code. (Sorry that I did not have checked this before).
So I rephrase the "issue" I see (not yet really knowing if the ATAT crate is the correct addressee for same, or something else related might be not happy with what I try).
OK, you state I should not try to avoid Buffers
. In fact I would not like to avoid it, but Buffers needs AtatUrc to be bound. And when using AtatUrc, the Urc Parser is called for the result and retunrs with an error in all tests I did before today.
I did intsall my on parser (using Buffers as before but doing my own struct to be submitted as a generic for the DefaultDigester)
let (ingress, client) = BUFFERS.split(
Tx { tx: tx_writer },
atat::DefaultDigester::<at::ModemTypeParser>::new(),
atat::Config::default(),
);
This in fact does call my parser, but afterwards the Urc parser is calld and again returns the error.
But the general "issue" (or misunderstanding at my side) is, that I assume that I should do something like
let res = client.send(&at::modem::test::QueryXXX {}).await;
to communicate with the modem, providing multiple QueryXXX structs (created by #[derive(Clone, Debug, AtatCmd)]
and #[at_cmd("...")]
) for the different communication tasks.
But before being able to do that, I need to instanciate ingress and for that use Buffers that needs to be givemn a single dedicate such QueryXXX struct. This currently does make sense for me.
Moreover I think I should be able to have mutiple parsers (or parser configurations) for dfferent modem commnications. I understand that BUFFERS
is static and should not be instanciated multiple times. So it would be necessary to swap the parser on the fly. Does that make any sense ?
Thanks for listening ! -Michael
I think I see where you go wrong in this :)
The generic you provide to Buffers
is required in order to parse URC's (Unsolicited response codes) See https://www.developershome.com/sms/resultCodes3.asp for info around what URC's are, if you are unfamiliar with AT command sets.
But the general "issue" (or misunderstanding at my side) is, that I assume that I should do something like let res = client.send(&at::modem::test::QueryXXX {}).await; to communicate with the modem, providing multiple QueryXXX structs (created by #[derive(Clone, Debug, AtatCmd)] and #[at_cmd("...")] ) for the different communication tasks.
The QueryXXX
structs earch represent a single AT command with their respective arguments, and a response struct given in the #[at_cmd("...")]
.
When you call .send(..).await
with such a request struct, it will convert it into an at string, for example AT+CGMI\r\n
, and wait for the response to arrive from the modem, terminated in a response code (Usually OK
or ERROR
)
If you do not wish to be able to parse URC's, you can just pass it an empty enum with derive(AtatUrc)
, and it won't ever match an URC.
Thanks a lot !
I'll continue researching ...
I seem to understand.
The Modem answer (other than OK
of ERROR
?? ) to any command is checked by the URC Parser, even though the goal of same is to handle unsolicited messages, spontanously sent by the Modem.
Maybe it does not make senses to do such Modem communication while unsolicited message might be coming.
Could it make sense to be able to switch the detection of unsolicited Messages on and off on the fly (without reinstanciating BUFFERS ) to allow for temporary biderectional Modem communication ?
BTW.: Obviously the URC parser does not like strings with leading Zeros and strings containing a :
. Seemingly such is not expected in an unsolicited modem message.
BTW2: The Modem I use responds to AT+QISTATE=?
by several different strings. Those are not compatible with parsing by the URC Parser. If I use a not empty response struct, even an answer OK
is detected as an error (while with AT+CGMI
a "normal" string is accepted).
Aftesr some discussions and researching, maybe I have a glimps of what is happening (or should be happening)
==
client.send(..).await;
an URC could come in before the answer to same and hence should be handled as aboveclient.send(..)
will not be confused with an URC string. Hence the URC parser should return Error()
in that case and nothing should happen on that behalf.Am I correct ?
Now the issue I face is that after doing client.send(..).await;
in fact both parsers are called (first the Digestr's and afterwards the Buffer's (URC) parser) and client.send(..).await;
returns the result provided by the URC parser (which is Error() in most cases). I feel the result of the URC parser should be used to ignore or handle the would-be URC string , and (if it's not a valid URC string "arm") the result of the digester's parser should be provided as a restult of client.send(..).await;
.
Thansk for listing ! -Michael
Am I correct ?
You are absolutely correct :+1: Couldn't have written it better :)
Now the issue I face is that after doing client.send(..).await; in fact both parsers are called (first the Digestr's and afterwards the Buffer's (URC) parser) and client.send(..).await; returns the result provided by the URC parser (which is Error() in most cases).
This does not sound like it is handled correct.. Not sure why that happens, though. Maybe @rmja has some insights with the newer URC handling?
Further research:
I seem to have found out that trying to change the parser for results of commands to be sent by doing a different implementation of the digester was a bad idea. Instead I need to impl
AtatCmd without deriving. (That already can be found in the examples in the current documentation, which I obviously was not able interpret correctly.)
Thus ATAT seems to work perfectly correct on the behalf I was hit by. I just need to implement a complete underived struct with impl
AtatCmd with it's own as_bytes() and parse() functions for any command (featuring a response from the modem) I want to use. (Explicitly implementing as_bytes(&self)
for sending instead of using #[at_cmd("...
which I conveniently did up till now
Correct ? Thanks a lot for listening ! -Michael
You are absolutely correct +1 Couldn't have written it better :)
Thanks ! Do you want me to write a draft of a documentation for the parts I do understand ? -Michael (needing to do such, anyway, to allow for cooperation on that project with my colleagues)
Absolutely! Any improvements to documentation is highly welcomed :+1:
Sorry for my ignorance. This can't be an issue as it seems to be a basic functionality, but I don't seem to get a grip at it:
To do code that runs, when an URC is sent by the modem I fetched a subscriber by
let subscriber = BUFFERS.urc_channel.subscribe();
I get a type UrcSubscription<'static, at::Urc>
which seems to be fine.
I understand that the correct way to go (when using tokio) is to spawn a thread by doing something like
tokio::spawn(task_urc_1(subscriber));
....
async fn task_urc_1<T>(mut subscriber: T) -> !
where
T: std::future::Future + Send + 'static,
{
...`
but here I get an error
dyn PubSubBehavior<urc::Urc> cannot be shared between threads safely ... required by a bound introduced by this call
A compiler suggestion says that the Send
Trait is not implemented for UrcSubscription
. and/ or atat::UrcSubscription
How should I proceed ?
-Michael
For a test I switched the tasks and do
let urc_message = urc_handle.await;
in
#[tokio::main]
async fn main() {
and did
async fn task_no_urc<'a>(
mut client: atat::asynch::Client<'a, atat_tokio::Tx, { atat_tokio::INGRESS_BUF_SIZE }>,
) -> ! {
for the client.send()
stuff.
This seems to work,.
But the "subscribe" paradigm, seems to suggest, that the goal is to allow for multiple threads to concurrently wait for urc messages and handle them. That definitely is a great idea and should be available !
Thanks for listening !
-Michael
Year, I think the subscriber should be Send somehow. The pub/sub behavior relies on embassy-sync, and I do not know if it supports it.
embessy-syc
in fact shows "impl !Send" for DynSubscriber
Thios is not the case with
https://docs.rs/embassy-sync/0.2.0/embassy_sync/pubsub/subscriber/struct.Subscriber.html
I don't see how the really nice subscribe mechanism for dispatching the URC messages to multiple threads / cores should work without Send. I have no experience at all with embassy, and did test only with tokio up till now. Hence I don't know if embassy might not require Send... -Michael
Did I inadvertently close this ?
Closing this and creating an issue for the remaining problem(s)
Need for improved documentation and/or examples.
(In the end, I want to use ATAT in an embedded project to implement a modem communication with an MQTT server, but of course at first I want to test simple stuff. ) Trying to use the best possible approach, seeing there were some relevant changes vs 0.18, I did some tokio enabled example code using the current "master" branch, on a Windows PC using the nightly rust build. in fact - with a help of a more educated colleague - I got something running. in fact I can client.send
ATE0
to the modem, which answersOK
and I get a result "Received OK (6/6)". That is fine. But when trying to do a simple command that expects a result string (e.g.ATI
orATS0=?
) I get Err(Parse). (I see the correct output of the modem in the ATAT trace.) In fact, I am not astonished about that, as I didto get a digester. (Using some fake at::Urc srtuct
and of course the "default" ("Urc") parser (using serdes) is not appropriate for handling the outputs of
ATI
andATS0=?
(last is000
).Hence I'd like to do/see an example (not using this type of "Buffers", which seemingly needs AtatUrc to be implemented) and/or documentation on how to do such "simple Stuff" with ATAT to get started.
Thanks for your great work !