use {
crate::{
protocol::*,
traits::{FirmwareDevice, FirmwareStatus},
},
embedded_io_async::{Read, Write},
heapless::Vec,
postcard::{from_bytes, to_slice},
};
const FRAME_SIZE: usize = 1024;
pub struct Serial<T>
where
T: Read + Write,
{
status: FirmwareStatus<Vec<u8, 16>>,
transport: T,
buf: [u8; FRAME_SIZE],
}
impl<T> Serial<T>
where
T: Read + Write,
{
pub fn new(transport: T) -> Self {
Self {
transport,
buf: [0; FRAME_SIZE],
status: FirmwareStatus {
current_version: Vec::new(),
next_version: None,
next_offset: 0,
},
}
}
}
#[derive(Debug)]
pub enum SerialError<T, C> {
Transport(T),
Codec(C),
Other,
}
impl<T> FirmwareDevice for Serial<T>
where
T: Read + Write,
{
const MTU: usize = 968;
type Version = Vec<u8, 16>;
type Error = SerialError<T::Error, postcard::Error>;
async fn status(&mut self) -> Result<FirmwareStatus<Self::Version>, Self::Error> {
let _ = self
.transport
.read(&mut self.buf)
.await
.map_err(SerialError::Transport)?;
let status: Status = from_bytes(&self.buf).map_err(SerialError::Codec)?;
self.status.current_version = Vec::from_slice(&status.version).map_err(|_| SerialError::Other)?;
if let Some(update) = status.update {
self.status.next_offset = update.offset;
self.status
.next_version
.replace(Vec::from_slice(&update.version).map_err(|_| SerialError::Other)?);
}
Ok(self.status.clone())
}
async fn start(&mut self, version: &[u8]) -> Result<(), Self::Error> {
self.status.next_offset = 0;
self.status
.next_version
.replace(Vec::from_slice(version).map_err(|_| SerialError::Other)?);
Ok(())
}
async fn write(&mut self, offset: u32, data: &[u8]) -> Result<(), Self::Error> {
let command: Command = Command::new_write(self.status.next_version.as_ref().unwrap(), offset, data, None);
to_slice(&command, &mut self.buf).map_err(SerialError::Codec)?;
let _ = self.transport.write(&self.buf).await.map_err(SerialError::Transport)?;
Ok(())
}
async fn update(&mut self, version: &[u8], checksum: &[u8]) -> Result<(), Self::Error> {
let command: Command = Command::new_swap(version, checksum, None);
to_slice(&command, &mut self.buf).map_err(SerialError::Codec)?;
let _ = self.transport.write(&self.buf).await.map_err(SerialError::Transport)?;
Ok(())
}
async fn synced(&mut self) -> Result<(), Self::Error> {
let command: Command = Command::new_sync(&self.status.current_version, None, None);
to_slice(&command, &mut self.buf).map_err(SerialError::Codec)?;
let _ = self.transport.write(&self.buf).await.map_err(SerialError::Transport)?;
Ok(())
}
}