Skip to content

Commit

Permalink
Add a SimpleClient, that does request/response without background tas…
Browse files Browse the repository at this point in the history
…ks and URC handling
  • Loading branch information
MathiasKoch committed Feb 16, 2024
1 parent 74bc5e3 commit 8ca2777
Show file tree
Hide file tree
Showing 3 changed files with 156 additions and 1 deletion.
2 changes: 1 addition & 1 deletion atat/src/asynch/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ impl<'a, W: Write, const INGRESS_BUF_SIZE: usize> Client<'a, W, INGRESS_BUF_SIZE
}

async fn send_request(&mut self, len: usize) -> Result<(), Error> {
if len < 50 {
if len < 500 {
debug!("Sending command: {:?}", LossyStr(&self.buf[..len]));
} else {
debug!("Sending command with long payload ({} bytes)", len);
Expand Down
2 changes: 2 additions & 0 deletions atat/src/asynch/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
mod client;
mod simple_client;

pub use client::Client;
pub use simple_client::SimpleClient;

use crate::{AtatCmd, Error};

Expand Down
153 changes: 153 additions & 0 deletions atat/src/asynch/simple_client.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
use super::AtatClient;
use crate::{helpers::LossyStr, AtatCmd, Config, DigestResult, Digester, Error, Response};
use embassy_time::{Duration, Timer};
use embedded_io_async::{Read, Write};

pub struct SimpleClient<'a, RW: Read + Write, D: Digester> {
rw: RW,
digester: D,
buf: &'a mut [u8],
pos: usize,
config: Config,
cooldown_timer: Option<Timer>,
}

impl<'a, RW: Read + Write, D: Digester> SimpleClient<'a, RW, D> {
pub fn new(rw: RW, digester: D, buf: &'a mut [u8], config: Config) -> Self {
Self {
rw,
digester,
buf,
config,
pos: 0,
cooldown_timer: None,
}
}

async fn send_request(&mut self, len: usize) -> Result<(), Error> {
if len < 50 {
debug!("Sending command: {:?}", LossyStr(&self.buf[..len]));
} else {
debug!("Sending command with long payload ({} bytes)", len);
}

self.wait_cooldown_timer().await;

// Write request
self.rw
.write_all(&self.buf[..len])
.await
.map_err(|_| Error::Write)?;
self.rw.flush().await.map_err(|_| Error::Write)?;

self.start_cooldown_timer();
Ok(())
}

async fn wait_response<'guard>(&'guard mut self) -> Result<Response<256>, Error> {
loop {
match self.rw.read(&mut self.buf[self.pos..]).await {
Ok(n) => {
self.pos += n;
}
_ => return Err(Error::Read),
};

debug!("Buffer contents: '{:?}'", LossyStr(&self.buf[..self.pos]));

while self.pos > 0 {
let (res, swallowed) = match self.digester.digest(&self.buf[..self.pos]) {
(DigestResult::None, swallowed) => {
if swallowed > 0 {
debug!(
"Received echo or whitespace ({}/{}): {:?}",
swallowed,
self.pos,
LossyStr(&self.buf[..swallowed])
);
}
(None, swallowed)
}
(DigestResult::Urc(urc_line), swallowed) => {
warn!("Unable to handle URC! Ignoring: {:?}", LossyStr(urc_line));
(None, swallowed)
}
(DigestResult::Prompt(prompt), swallowed) => {
debug!("Received prompt ({}/{})", swallowed, self.pos);

(Some(Response::Prompt(prompt)), swallowed)
}
(DigestResult::Response(resp), swallowed) => {
match &resp {
Ok(r) => {
if r.is_empty() {
debug!("Received OK ({}/{})", swallowed, self.pos)

Check warning on line 84 in atat/src/asynch/simple_client.rs

View workflow job for this annotation

GitHub Actions / clippy

consider adding a `;` to the last statement for consistent formatting

warning: consider adding a `;` to the last statement for consistent formatting --> atat/src/asynch/simple_client.rs:84:37 | 84 | ... debug!("Received OK ({}/{})", swallowed, self.pos) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: add a `;` here: `debug!("Received OK ({}/{})", swallowed, self.pos);` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#semicolon_if_nothing_returned
} else {
debug!(
"Received response ({}/{}): {:?}",
swallowed,
self.pos,
LossyStr(r)
);
}
}
Err(e) => {
warn!(
"Received error response ({}/{}): {:?}",
swallowed, self.pos, e
);
}
}

(Some(resp.into()), swallowed)
}
};

if swallowed == 0 {
break;
}

self.consume(swallowed);

if let Some(resp) = res {
return Ok(resp);
}
}
}
}

fn consume(&mut self, amt: usize) {
self.buf.copy_within(amt..self.pos, 0);
self.pos -= amt;
}

fn start_cooldown_timer(&mut self) {
self.cooldown_timer = Some(Timer::after(self.config.cmd_cooldown));
}

async fn wait_cooldown_timer(&mut self) {
if let Some(cooldown) = self.cooldown_timer.take() {
cooldown.await

Check warning on line 130 in atat/src/asynch/simple_client.rs

View workflow job for this annotation

GitHub Actions / clippy

consider adding a `;` to the last statement for consistent formatting

warning: consider adding a `;` to the last statement for consistent formatting --> atat/src/asynch/simple_client.rs:130:13 | 130 | cooldown.await | ^^^^^^^^^^^^^^ help: add a `;` here: `cooldown.await;` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#semicolon_if_nothing_returned
}
}
}

impl<RW: Read + Write, D: Digester> AtatClient for SimpleClient<'_, RW, D> {
async fn send<Cmd: AtatCmd>(&mut self, cmd: &Cmd) -> Result<Cmd::Response, Error> {
let len = cmd.write(&mut self.buf);

Check warning on line 137 in atat/src/asynch/simple_client.rs

View workflow job for this annotation

GitHub Actions / clippy

this expression creates a reference which is immediately dereferenced by the compiler

warning: this expression creates a reference which is immediately dereferenced by the compiler --> atat/src/asynch/simple_client.rs:137:29 | 137 | let len = cmd.write(&mut self.buf); | ^^^^^^^^^^^^^ help: change this to: `self.buf` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrow

self.send_request(len).await?;
if !Cmd::EXPECTS_RESPONSE_CODE {
cmd.parse(Ok(&[]))
} else {
let response = embassy_time::with_timeout(
Duration::from_millis(Cmd::MAX_TIMEOUT_MS.into()),
self.wait_response(),
)
.await
.map_err(|_| Error::Timeout)??;

cmd.parse((&response).into())
}

Check warning on line 151 in atat/src/asynch/simple_client.rs

View workflow job for this annotation

GitHub Actions / clippy

unnecessary boolean `not` operation

warning: unnecessary boolean `not` operation --> atat/src/asynch/simple_client.rs:140:9 | 140 | / if !Cmd::EXPECTS_RESPONSE_CODE { 141 | | cmd.parse(Ok(&[])) 142 | | } else { 143 | | let response = embassy_time::with_timeout( ... | 150 | | cmd.parse((&response).into()) 151 | | } | |_________^ | = help: remove the `!` and swap the blocks of the `if`/`else` = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#if_not_else
}
}

0 comments on commit 8ca2777

Please sign in to comment.