atat
atat copied to clipboard
[RFC] Allow streaming/chunked type
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 smaller BufLen
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
- Large byte payloads (eg. socket RX)
- Vec types (eg. wifi ssid scan or cellular operator scan)
A typical command suitable for this would be AT+USORD
:
Syntax:
AT+USORD=< socket >,< length >
Response:
+USORD: < socket >,< length >,< data in the ASCII [0x00,0xFF] range > OK
Example:
AT+USORD=3,16 +USORD: 3,16,"16 bytes of data" OK
Implementation suggestion
#[derive(Clone, AtatCmd)]
#[at_cmd("+USORD", SocketData)]
pub struct ReadSocketData {
#[at_arg(position = 0)]
pub socket: SocketHandle,
#[at_arg(position = 1)]
pub length: usize,
}
/// Example AT command with streaming payload
#[derive(Clone, AtatResp)]
pub struct SocketData<'a> {
#[at_arg(position = 0)]
pub socket: SocketHandle,
#[at_arg(position = 1)]
pub length: usize,
#[at_arg(position = 2)]
pub data: Streaming<'a, U128>,
}
pub fn example_using_stream() {
match at_client.send(&ReadSocketData { socket: SocketHandle(0), length: 512 }) {
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) => {
// `response.length` can be used to verify that all chunks are received in this case
println!("Socket: {:?}, length: {:?}", response.socket, response.length);
// `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.data.poll_next() {
Poll::Pending => {}
Poll::Ready(None) => break
Poll::Ready(chunk) => {
// Data can be enqueued to a socket buffer, one chunk at a time.
socket_layer.enqueue_slice(&chunk);
}
}
}
// Above loop should be possible to rewrite using async, as:
while let Some(chunk) in response.data.next().await {
// Data can be enqueued to a socket buffer, one chunk at a time.
socket_layer.enqueue_slice(&chunk);
}
}
}
}
// Below here is given by `ATAT`
pub type ResItem<BufLen> = Result<AtItem<BufLen>, InternalError>;
pub enum AtItem<BufLen> {
Response(Vec<u8, BufLen>),
Chunk(Vec<u8, BufLen>)
}
pub struct Streaming<'a, BufLen> {
consumer: &'a ResConsumer<BufLen>,
}
impl<'a, BufLen> Stream for Streaming<'a, BufLen> {
type item = Vec<u8, BufLen>;
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
match self.consumer.peek() {
Some(Ok(AtItem::Chunk(bytes)) => {
unsafe { self.consumer.dequeue_unchecked(); }
Poll::Ready(Some(bytes))
}
// The next item in the queue is a new response
Some(Ok(AtItem::Response(_)) => {
Poll::Ready(None)
}
// FIXME: Is this correct?
Some(Err(e)) => Poll::Ready(None),
None => Poll::Pending
}
}
}
impl<'a, BufLen> Drop for Streaming<'a, BufLen> {
fn drop(&mut self) {
// Dequeue items until there are no more `AtItem::Chunk`
while let Some(Ok(AtItem::Chunk(_)) = self.consumer.peek() {
self.consumer.dequeue();
}
}
}
Apart from above implementation steps, the parse()
function of commands needs to be altered to handle AtItem::Response
& constructing Streaming
,
and the Digester
needs to be able to handle digesting in chunks. Perhaps a new StreamingDigester
would allow non-breaking changes?
Considerations
- This should preferably not incour significant overhead if not using the
Streaming
wrapper -
cmd.parse(..)
would need to take a reference toself.res_c
, which might be tricky to get right? - The lifetime of
A::Response
might be tricky to get right? - ~~Above implementation suggestion will not be able to handle
Vec<T>
response streaming.~~ See below comment on handlingVec<T>
- Not sure if this should be implemented with
futures::Stream
directly, or a similar self-defined trait. Unknown part would be how to handleself: Pin<&mut Self>, cx: &mut Context<'_>
- Can this be applied to URC's as well?
Limitations
- The streaming parameter has to be the last parameter of the response! I think this will always be the case anyways, but am not sure? (This could be checked for any type deriving the
AtatCmd
at compile time) - The length / chunk-size of
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
- It would be awesome if we could fill out the
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
.
Above implementation suggestion will not be able to handle Vec<T> response streaming.
An example of an AT command that would benefit alot from streaming Vec<T>
like handling would be AT+UWSCAN
.
Example of `AT+UWSCAN`
AT+UWSCAN
+UWSCAN:EA63DA77C485,1,"emendo-Blackbird",1,-54,18,8,8
+UWSCAN:E063DA74C38A,1,"Blackbird-device",1,-62,18,8,8
+UWSCAN:6009C32A1811,1,"Factbird-Duo-768e8aa",1,-40,0,0,0
+UWSCAN:E063DA74A587,1,"Blackbird-device",1,-59,18,8,8
+UWSCAN:E063DA77C485,1,"Blackbird-device",1,-54,18,8,8
+UWSCAN:E663DA74A587,1,"emendo-guest",1,-60,18,8,8
+UWSCAN:E063DA74C38A,1,"Blackbird-device",1,-62,18,8,8
+UWSCAN:EA63DA74A587,1,"emendo-Blackbird",1,-59,18,8,8
+UWSCAN:E663DA77C485,1,"emendo-guest",1,-54,18,8,8
+UWSCAN:E263DA74C38A,1,"emendo-guest",1,-62,18,8,8
+UWSCAN:EA63DA77C485,1,"emendo-Blackbird",1,-54,18,8,8
+UWSCAN:F263DA74C38A,1,"emendo-Blackbird",1,-62,18,8,8
+UWSCAN:6009C32A1811,1,"Factbird-Duo-768e8aa",1,-39,0,0,0
+UWSCAN:E063DA74C38A,1,"Blackbird-device",1,-62,18,8,8
+UWSCAN:E063DA77C485,1,"Blackbird-device",1,-53,18,8,8
+UWSCAN:B4FBE4C732FD,1,"Blackbird-device",1,-76,18,8,8
+UWSCAN:E663DA77C485,1,"emendo-guest",1,-54,18,8,8
+UWSCAN:EA63DA77C485,1,"emendo-Blackbird",1,-53,18,8,8
+UWSCAN:E063DA74C38A,1,"Blackbird-device",1,-62,18,8,8
+UWSCAN:E263DA74C38A,1,"emendo-guest",1,-62,18,8,8
+UWSCAN:F263DA74C38A,1,"emendo-Blackbird",1,-62,18,8,8
+UWSCAN:E063DA74A587,1,"Blackbird-device",1,-60,18,8,8
+UWSCAN:B4FBE4C7325C,1,"Blackbird-device",1,-74,18,8,8
+UWSCAN:EA63DA77C485,1,"emendo-Blackbird",1,-53,18,8,8
+UWSCAN:BAFBE4C7325C,1,"emendo-guest",1,-75,18,8,8
+UWSCAN:E663DA74A587,1,"emendo-guest",1,-60,18,8,8
+UWSCAN:BAFBE4C732FD,1,"emendo-guest",1,-76,18,8,8
+UWSCAN:EA63DA74A587,1,"emendo-Blackbird",1,-60,18,8,8
+UWSCAN:EA63DA74A587,1,"emendo-Blackbird",1,-59,18,8,8
+UWSCAN:EA63DA74A587,1,"emendo-Blackbird",1,-60,18,8,8
+UWSCAN:BEFBE4C732FD,1,"emendo-Blackbird",1,-77,18,8,8
+UWSCAN:BEFBE4C7325C,1,"emendo-Blackbird",1,-75,18,8,8
+UWSCAN:E663DA74A587,1,"emendo-guest",1,-59,18,8,8
+UWSCAN:B4FBE4C7325C,1,"Blackbird-device",1,-75,18,8,8
+UWSCAN:E263DA74C38A,1,"emendo-guest",1,-62,18,8,8
+UWSCAN:EA63DA74A664,1,"emendo-Blackbird",6,-56,18,8,8
+UWSCAN:E063DA74A664,1,"Blackbird-device",6,-56,18,8,8
+UWSCAN:B4FBE4C7331A,1,"Blackbird-device",6,-65,18,8,8
+UWSCAN:E663DA74A664,1,"emendo-guest",6,-56,18,8,8
+UWSCAN:BAFBE4C7331A,1,"emendo-guest",6,-65,18,8,8
+UWSCAN:EA63DA74A664,1,"emendo-Blackbird",6,-56,18,8,8
+UWSCAN:BAFBE4C7331A,1,"emendo-guest",6,-65,18,8,8
+UWSCAN:BEFBE4C7331A,1,"emendo-Blackbird",6,-64,18,8,8
+UWSCAN:EA63DA74C515,1,"emendo-Blackbird",6,-69,18,8,8
+UWSCAN:E063DA74A664,1,"Blackbird-device",6,-56,18,8,8
+UWSCAN:B4FBE4C731AA,1,"Blackbird-device",6,-70,18,8,8
+UWSCAN:E663DA74A664,1,"emendo-guest",6,-55,18,8,8
+UWSCAN:E063DA74C515,1,"Blackbird-device",6,-69,18,8,8
+UWSCAN:EA63DA74A664,1,"emendo-Blackbird",6,-57,18,8,8
+UWSCAN:B4FBE4C7331A,1,"Blackbird-device",6,-65,18,8,8
+UWSCAN:E663DA74C515,1,"emendo-guest",6,-69,18,8,8
+UWSCAN:BAFBE4C7331A,1,"emendo-guest",6,-64,18,8,8
+UWSCAN:B4FBE4C731AA,1,"Blackbird-device",6,-71,18,8,8
+UWSCAN:BEFBE4C731AA,1,"emendo-Blackbird",6,-71,18,8,8
+UWSCAN:BEFBE4C7331A,1,"emendo-Blackbird",6,-65,18,8,8
+UWSCAN:BEFBE4C7331A,1,"emendo-Blackbird",6,-65,18,8,8
+UWSCAN:E663DA74C62C,1,"emendo-guest",11,-60,18,8,8
+UWSCAN:001E42258D9C,1,"RUT_8D9C_2G",11,-62,18,12,4
+UWSCAN:E063DA74A530,1,"Blackbird-device",11,-64,18,8,8
+UWSCAN:B4FBE4C731B2,1,"Blackbird-device",11,-71,18,8,8
+UWSCAN:B4FBE4C731B2,1,"Blackbird-device",11,-71,18,8,8
+UWSCAN:E663DA74A530,1,"emendo-guest",11,-64,18,8,8
+UWSCAN:E063DA74C62C,1,"Blackbird-device",11,-60,18,8,8
+UWSCAN:BAFBE4C731B2,1,"emendo-guest",11,-72,18,8,8
+UWSCAN:BEFBE4C731B2,1,"emendo-Blackbird",11,-72,18,8,8
+UWSCAN:E663DA74C62C,1,"emendo-guest",11,-60,18,8,8
+UWSCAN:EA63DA74A530,1,"emendo-Blackbird",11,-64,18,8,8
+UWSCAN:EA63DA74C62C,1,"emendo-Blackbird",11,-59,18,8,8
+UWSCAN:EA63DA74C62C,1,"emendo-Blackbird",11,-59,18,8,8
+UWSCAN:E063DA74C62C,1,"Blackbird-device",11,-59,18,8,8
+UWSCAN:E663DA74C62C,1,"emendo-guest",11,-60,18,8,8
+UWSCAN:001E42258D9C,1,"RUT_8D9C_2G",11,-60,18,12,4
+UWSCAN:E063DA74A530,1,"Blackbird-device",11,-64,18,8,8
+UWSCAN:E663DA74A530,1,"emendo-guest",11,-64,18,8,8
+UWSCAN:E663DA74A530,1,"emendo-guest",11,-64,18,8,8
+UWSCAN:EA63DA74A530,1,"emendo-Blackbird",11,-64,18,8,8
+UWSCAN:EA63DA74C62C,1,"emendo-Blackbird",11,-59,18,8,8
+UWSCAN:B4FBE4C731B2,1,"Blackbird-device",11,-71,18,8,8
+UWSCAN:60634C263349,1,"DWR-921-3348",11,-89,26,12,4
+UWSCAN:EA63DA74A530,1,"emendo-Blackbird",11,-64,18,8,8
+UWSCAN:9CB6D03EB4A3,1,"TEST",36,-41,0,0,0
+UWSCAN:9CB6D03EB4A3,1,"TEST",36,-41,0,0,0
+UWSCAN:EA63DA75C62C,1,"emendo-Blackbird",36,-57,18,8,8
+UWSCAN:E063DA75C62C,1,"Blackbird-device",36,-58,18,8,8
+UWSCAN:E663DA75C62C,1,"emendo-guest",36,-58,18,8,8
+UWSCAN:E063DA75C62C,1,"Blackbird-device",36,-58,18,8,8
+UWSCAN:E663DA75C62C,1,"emendo-guest",36,-58,18,8,8
+UWSCAN:EA63DA75C62C,1,"emendo-Blackbird",36,-58,18,8,8
+UWSCAN:EA63DA75C62C,1,"emendo-Blackbird",36,-58,18,8,8
+UWSCAN:E063DA75C62C,1,"Blackbird-device",36,-58,18,8,8
+UWSCAN:D8616240D55F,1,"ClickShare-ThinkingStudio",40,-88,18,8,8
+UWSCAN:D8616240D55F,1,"ClickShare-ThinkingStudio",40,-88,18,8,8
+UWSCAN:D8616240D55F,1,"ClickShare-ThinkingStudio",40,-88,18,8,8
+UWSCAN:B4FBE4C832FD,1,"Blackbird-device",44,-86,18,8,8
+UWSCAN:B4FBE4C832FD,1,"Blackbird-device",44,-87,18,8,8
+UWSCAN:BAFBE4C832FD,1,"emendo-guest",44,-87,18,8,8
+UWSCAN:BAFBE4C832FD,1,"emendo-guest",44,-87,18,8,8
+UWSCAN:BEFBE4C832FD,1,"emendo-Blackbird",44,-87,18,8,8
+UWSCAN:BEFBE4C832FD,1,"emendo-Blackbird",44,-87,18,8,8
+UWSCAN:B4FBE4C832FD,1,"Blackbird-device",44,-88,18,8,8
+UWSCAN:B4FBE4C8331A,1,"Blackbird-device",48,-70,18,8,8
+UWSCAN:BAFBE4C8331A,1,"emendo-guest",48,-71,18,8,8
+UWSCAN:BEFBE4C8331A,1,"emendo-Blackbird",48,-71,18,8,8
+UWSCAN:B4FBE4C8331A,1,"Blackbird-device",48,-71,18,8,8
+UWSCAN:BAFBE4C8331A,1,"emendo-guest",48,-71,18,8,8
+UWSCAN:BEFBE4C8331A,1,"emendo-Blackbird",48,-71,18,8,8
+UWSCAN:BAFBE4C8331A,1,"emendo-guest",48,-71,18,8,8
+UWSCAN:BEFBE4C831B2,1,"emendo-Blackbird",52,-79,18,8,8
+UWSCAN:B4FBE4C831B2,1,"Blackbird-device",52,-80,18,8,8
+UWSCAN:BAFBE4C831B2,1,"emendo-guest",52,-79,18,8,8
+UWSCAN:BEFBE4C831B2,1,"emendo-Blackbird",52,-85,18,8,8
+UWSCAN:B4FBE4C831B2,1,"Blackbird-device",52,-79,18,8,8
+UWSCAN:BAFBE4C831B2,1,"emendo-guest",52,-79,18,8,8
+UWSCAN:BEFBE4C831B2,1,"emendo-Blackbird",52,-79,18,8,8
+UWSCAN:B4FBE4C831B2,1,"Blackbird-device",52,-79,18,8,8
+UWSCAN:BAFBE4C831B2,1,"emendo-guest",52,-79,18,8,8
+UWSCAN:BEFBE4C831B2,1,"emendo-Blackbird",52,-79,18,8,8
+UWSCAN:BEFBE4C831B2,1,"emendo-Blackbird",52,-79,18,8,8
+UWSCAN:EA63DA75C515,1,"emendo-Blackbird",56,-80,18,8,8
+UWSCAN:E063DA75C38A,1,"Blackbird-device",56,-70,18,8,8
+UWSCAN:E063DA75C515,1,"Blackbird-device",56,-79,18,8,8
+UWSCAN:E263DA75C38A,1,"emendo-guest",56,-69,18,8,8
+UWSCAN:E663DA75C515,1,"emendo-guest",56,-79,18,8,8
+UWSCAN:F263DA75C38A,1,"emendo-Blackbird",56,-69,18,8,8
+UWSCAN:EA63DA75C515,1,"emendo-Blackbird",56,-79,18,8,8
+UWSCAN:E063DA75C38A,1,"Blackbird-device",56,-69,18,8,8
+UWSCAN:E063DA75C515,1,"Blackbird-device",56,-79,18,8,8
+UWSCAN:E063DA75C515,1,"Blackbird-device",56,-79,18,8,8
+UWSCAN:F263DA75C38A,1,"emendo-Blackbird",56,-69,18,8,8
+UWSCAN:E063DA75C38A,1,"Blackbird-device",56,-69,18,8,8
+UWSCAN:E063DA75C38A,1,"Blackbird-device",56,-69,18,8,8
+UWSCAN:E063DA75C38A,1,"Blackbird-device",56,-69,18,8,8
+UWSCAN:E063DA75C38A,1,"Blackbird-device",56,-69,18,8,8
+UWSCAN:E663DA75C515,1,"emendo-guest",56,-79,18,8,8
+UWSCAN:E263DA75C38A,1,"emendo-guest",56,-69,18,8,8
+UWSCAN:E263DA75C38A,1,"emendo-guest",56,-69,18,8,8
+UWSCAN:EA63DA75C515,1,"emendo-Blackbird",56,-79,18,8,8
+UWSCAN:F263DA75C38A,1,"emendo-Blackbird",56,-70,18,8,8
+UWSCAN:E063DA75C38A,1,"Blackbird-device",56,-70,18,8,8
+UWSCAN:E063DA75C515,1,"Blackbird-device",56,-79,18,8,8
+UWSCAN:E263DA75C38A,1,"emendo-guest",56,-69,18,8,8
+UWSCAN:E263DA75C38A,1,"emendo-guest",56,-69,18,8,8
+UWSCAN:F263DA75C38A,1,"emendo-Blackbird",56,-69,18,8,8
+UWSCAN:E663DA75C515,1,"emendo-guest",56,-79,18,8,8
+UWSCAN:F263DA75C38A,1,"emendo-Blackbird",56,-69,18,8,8
+UWSCAN:EA63DA75C515,1,"emendo-Blackbird",56,-79,18,8,8
+UWSCAN:EA63DA75C515,1,"emendo-Blackbird",56,-79,18,8,8
+UWSCAN:E063DA75C38A,1,"Blackbird-device",56,-69,18,8,8
+UWSCAN:E063DA75C515,1,"Blackbird-device",56,-79,18,8,8
+UWSCAN:E063DA75C515,1,"Blackbird-device",56,-79,18,8,8
+UWSCAN:E663DA75C515,1,"emendo-guest",56,-79,18,8,8
+UWSCAN:E663DA75C515,1,"emendo-guest",56,-79,18,8,8
+UWSCAN:EA63DA75C515,1,"emendo-Blackbird",56,-79,18,8,8
+UWSCAN:EA63DA75C515,1,"emendo-Blackbird",56,-79,18,8,8
+UWSCAN:EA63DA75C515,1,"emendo-Blackbird",56,-80,18,8,8
+UWSCAN:E063DA75C515,1,"Blackbird-device",56,-80,18,8,8
+UWSCAN:BEFBE4C8325C,1,"emendo-Blackbird",60,-78,18,8,8
+UWSCAN:B4FBE4C8325C,1,"Blackbird-device",60,-79,18,8,8
+UWSCAN:BAFBE4C8325C,1,"emendo-guest",60,-79,18,8,8
+UWSCAN:BEFBE4C8325C,1,"emendo-Blackbird",60,-79,18,8,8
+UWSCAN:B4FBE4C8325C,1,"Blackbird-device",60,-79,18,8,8
+UWSCAN:BAFBE4C8325C,1,"emendo-guest",60,-79,18,8,8
+UWSCAN:BAFBE4C8325C,1,"emendo-guest",60,-80,18,8,8
+UWSCAN:BEFBE4C8325C,1,"emendo-Blackbird",60,-80,18,8,8
+UWSCAN:BEFBE4C8325C,1,"emendo-Blackbird",60,-79,18,8,8
+UWSCAN:E063DA75A664,1,"Blackbird-device",64,-57,18,8,8
+UWSCAN:E663DA75A664,1,"emendo-guest",64,-58,18,8,8
+UWSCAN:EA63DA75A664,1,"emendo-Blackbird",64,-58,18,8,8
+UWSCAN:E063DA75A664,1,"Blackbird-device",64,-58,18,8,8
+UWSCAN:E663DA75A664,1,"emendo-guest",64,-57,18,8,8
+UWSCAN:E063DA75A664,1,"Blackbird-device",64,-57,18,8,8
+UWSCAN:E663DA75A664,1,"emendo-guest",64,-57,18,8,8
+UWSCAN:EA63DA75A664,1,"emendo-Blackbird",64,-58,18,8,8
+UWSCAN:E063DA75A664,1,"Blackbird-device",64,-57,18,8,8
+UWSCAN:E663DA75A664,1,"emendo-guest",64,-57,18,8,8
+UWSCAN:EA63DA75A664,1,"emendo-Blackbird",64,-58,18,8,8
+UWSCAN:E063DA75A664,1,"Blackbird-device",64,-58,18,8,8
+UWSCAN:EA63DA78C485,1,"emendo-Blackbird",100,-63,18,8,8
+UWSCAN:E063DA78C485,1,"Blackbird-device",100,-63,18,8,8
+UWSCAN:E663DA78C485,1,"emendo-guest",100,-63,18,8,8
+UWSCAN:EA63DA78C485,1,"emendo-Blackbird",100,-64,18,8,8
+UWSCAN:E063DA78C485,1,"Blackbird-device",100,-63,18,8,8
+UWSCAN:E663DA78C485,1,"emendo-guest",100,-64,18,8,8
+UWSCAN:EA63DA78C485,1,"emendo-Blackbird",100,-64,18,8,8
+UWSCAN:E663DA78C485,1,"emendo-guest",100,-64,18,8,8
+UWSCAN:E063DA78C485,1,"Blackbird-device",100,-64,18,8,8
+UWSCAN:E663DA78C485,1,"emendo-guest",100,-64,18,8,8
+UWSCAN:EA63DA78C485,1,"emendo-Blackbird",100,-64,18,8,8
+UWSCAN:EA63DA78C485,1,"emendo-Blackbird",100,-64,18,8,8
OK
After the implementation of framed queues, this could be solved using an additional ResponseHeader
variant as:
pub enum ResponseHeader {
Complete,
Line,
Chunk,
}
As well as the introduction of another AT wrapper type for responses, next to Streaming
:
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);
}
}
}
}
}
}