-
Notifications
You must be signed in to change notification settings - Fork 31
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
[RFC] Allow streaming/chunked type #89
Comments
An example of an AT command that would benefit alot from streaming Example of `AT+UWSCAN`AT+UWSCAN After the implementation of framed queues, this could be solved using an additional pub enum ResponseHeader {
Complete,
Line,
Chunk,
} As well as the introduction of another AT wrapper type for responses, next to pub struct Lines<'a, A: AtatResp, const N: usize> {
consumer: &'a FrameConsumer<'a, N>,
}
impl<'a, A: AtatResp, const N: usize> Stream for Lines<'a, A, N> {
type item = A;
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
match self.consumer.peek() {
Some(Ok(ResponseHeader::Line(bytes)) => {
unsafe { self.consumer.dequeue_unchecked(); }
let s: A = A::parse(bytes);
Poll::Ready(Some(s))
}
// The next item in the queue is a new response
Some(Ok(ResponseHeader::Response(_)) => {
Poll::Ready(None)
}
// FIXME: Is this correct?
Some(Err(e)) => Poll::Ready(None),
None => Poll::Pending
}
}
}
impl<'a, A: AtatResp, const N: usize> Drop for Lines<'a, A, N> {
fn drop(&mut self) {
// Dequeue items until there are no more `ResponseHeader::Line`
while let Some(Ok(AtItem::Line(_)) = self.consumer.peek() {
self.consumer.dequeue();
}
}
} such that #[derive(Clone, AtatResp)]
pub struct Wifi {
ssid: String<64>
}
#[derive(Clone, AtatCmd)]
#[at_cmd("+USORD", Lines<'_, Wifi>)]
pub struct ScanWifi;
pub fn example_using_lines() {
match at_client.send(&ScanWifi) {
Err(nb::Error::WouldBlock) => {
// This would indicate that the first part of the response has yet to be received
}
Err(nb::Error::Other(_)) => {
// This would indicate that an actual error occured on the AT line,
// or a timeout occured while waiting for the first part of the response.
}
Ok(response) => {
// `at_client` is locked for the full lifetime of `response`,
// but the ingress part of `ATAT` should still be ingressing and pushing to the response queue.
loop {
match response.poll_next() {
Poll::Pending => {}
Poll::Ready(None) => break
Poll::Ready(w: Wifi) => {
// Found wifi accesspoints can be dealt with one at a time.
println!("Found wifi with ssid: {:?}", w.ssid);
}
}
}
}
}
} |
We were toying around with the idea of introducing a newtype wrapper that would allow for streaming/chunked payloads of AT commands.
Motivation
The main motivation would be to be able to reduce the stack usage of the library, by reducing the size of
BufLen
, as this currently needs to be able to hold the full WORST-CASE command length at all times. For all of our applications, that would be a socket ingress payload, usually in the magnitude of 512 bytes + overhead. Almost every other command we have in our applications of ATAT would be able to run with a much smallerBufLen
of say 128 bytes. This could probably be even further reduced by fixing #82.In our applications of ATAT,
BufLen
is 1024 bytes.Command types to consider
A typical command suitable for this would be
AT+USORD
:Syntax:
Response:
Example:
Implementation suggestion
Apart from above implementation steps, the
parse()
function of commands needs to be altered to handleAtItem::Response
& constructingStreaming
,and the
Digester
needs to be able to handle digesting in chunks. Perhaps a newStreamingDigester
would allow non-breaking changes?Considerations
Streaming
wrappercmd.parse(..)
would need to take a reference toself.res_c
, which might be tricky to get right?A::Response
might be tricky to get right?Above implementation suggestion will not be able to handleSee below comment on handlingVec<T>
response streaming.Vec<T>
futures::Stream
directly, or a similar self-defined trait. Unknown part would be how to handleself: Pin<&mut Self>, cx: &mut Context<'_>
Limitations
AtatCmd
at compile time)Streaming<'a, U128>
(U128
here) has to be equal toBufLen
, as theAtItem::Chunk
is dequeued on success. Could probably be allowed to<= BufLen
, if we kept a chunk index inStreaming
, and only dequeued the chunk on the remainder part, but i am not sure we would win anything by it?Further improvements
size_hint()
function somehow, on the responses where that would be known/can be calculated. For example for the aboveSocketData
, the size_hint would beresponse.length / 128
.The text was updated successfully, but these errors were encountered: