#[cfg(test)]
mod tests;
use crate::{Bitrate, CanFrame, Error, ExtIdentifier, Identifier};
use defmt::Format;
#[derive(Debug, Eq, PartialEq, Format)]
#[non_exhaustive]
pub enum Command {
SetupWithBitrate {
bitrate: Bitrate,
},
Open,
Close,
TxStandard {
identifier: Identifier,
frame: CanFrame,
},
TxExt {
identifier: ExtIdentifier,
frame: CanFrame,
},
TxStandardRtr {
identifier: Identifier,
len: u8,
},
TxExtRtr {
identifier: ExtIdentifier,
len: u8,
},
ReadStatus,
ReadVersion,
ReadSerial,
SetRxTimestamp {
timestamp: bool,
},
}
impl Command {
pub const MAX_ENCODED_LEN: usize = 1 + 8 + 1 + 16 + 1;
pub fn decode(input: &[u8]) -> Result<Self, Error> {
let mut reader = Reader { input };
let op = reader.read_byte()?;
let cmd = match op {
b'S' => {
let bitrate = match reader.read_byte()? {
b'0' => Bitrate::_10kbit,
b'1' => Bitrate::_20kbit,
b'2' => Bitrate::_50kbit,
b'3' => Bitrate::_100kbit,
b'4' => Bitrate::_125kbit,
b'5' => Bitrate::_250kbit,
b'6' => Bitrate::_500kbit,
b'7' => Bitrate::_800kbit,
b'8' => Bitrate::_1mbit,
_ => return Err(Error::decode()),
};
Command::SetupWithBitrate { bitrate }
}
b'O' => Command::Open,
b'C' => Command::Close,
b't' => {
let identifier = reader.read_hex_identifier()?;
let len = reader.read_hex_u4()?;
if len > 8 {
return Err(Error::decode());
}
let frame = reader.read_frame(len)?;
Command::TxStandard { identifier, frame }
}
b'T' => {
let identifier = reader.read_hex_ext_identifier()?;
let len = reader.read_hex_u4()?;
if len > 8 {
return Err(Error::decode());
}
let frame = reader.read_frame(len)?;
Command::TxExt { identifier, frame }
}
b'r' => {
let identifier = reader.read_hex_identifier()?;
let len = reader.read_hex_u4()?;
if len > 8 {
return Err(Error::decode());
}
Command::TxStandardRtr { identifier, len }
}
b'R' => {
let identifier = reader.read_hex_ext_identifier()?;
let len = reader.read_hex_u4()?;
if len > 8 {
return Err(Error::decode());
}
Command::TxExtRtr { identifier, len }
}
b'F' => Command::ReadStatus,
b'V' => Command::ReadVersion,
b'N' => Command::ReadSerial,
b'Z' => {
let timestamp = match reader.read_byte()? {
b'0' => false,
b'1' => true,
_ => return Err(Error::decode()),
};
Command::SetRxTimestamp { timestamp }
}
_ => return Err(Error::decode()),
};
if reader.read_byte()? != b'\r' {
return Err(Error::decode());
}
if !reader.input.is_empty() {
return Err(Error::decode());
}
Ok(cmd)
}
}
#[derive(Default, Debug)]
pub struct CommandBuf {
bytes: [u8; Command::MAX_ENCODED_LEN],
used: u8,
}
impl CommandBuf {
pub const fn new() -> Self {
Self {
bytes: [0; Command::MAX_ENCODED_LEN],
used: 0,
}
}
pub fn tail_mut(&mut self) -> &mut [u8] {
&mut self.bytes[usize::from(self.used)..]
}
fn is_full(&self) -> bool {
usize::from(self.used) == Command::MAX_ENCODED_LEN
}
fn find_cr(&self, start: usize) -> Option<usize> {
self.bytes[start..usize::from(self.used)]
.iter()
.position(|b| *b == b'\r')
.map(|pos| pos + start)
}
pub fn advance_by(&mut self, amount: u8) -> impl Iterator<Item = Result<Command, Error>> + '_ {
self.used += amount;
assert!(usize::from(self.used) <= Command::MAX_ENCODED_LEN);
CommandIter { buf: self, pos: 0 }
}
}
struct CommandIter<'a> {
buf: &'a mut CommandBuf,
pos: u8,
}
impl Iterator for CommandIter<'_> {
type Item = Result<Command, Error>;
fn next(&mut self) -> Option<Self::Item> {
let pos = usize::from(self.pos);
let end = match self.buf.find_cr(pos) {
Some(pos) => pos,
None if pos == 0 && self.buf.is_full() => {
self.pos = Command::MAX_ENCODED_LEN as u8;
return Some(Err(Error::decode()));
}
None => return None,
};
let cmd = &self.buf.bytes[pos..end + 1];
self.pos += cmd.len() as u8;
Some(Command::decode(cmd))
}
}
impl Drop for CommandIter<'_> {
fn drop(&mut self) {
let decoded_end = usize::from(self.pos);
self.buf.bytes.copy_within(decoded_end.., 0);
self.buf.used -= decoded_end as u8;
}
}
#[derive(Eq, PartialEq)]
struct Reader<'a> {
input: &'a [u8],
}
impl<'a> Reader<'a> {
fn read_byte(&mut self) -> Result<u8, Error> {
match self.input {
[] => Err(Error::eof()),
[b, rest @ ..] => {
self.input = rest;
Ok(*b)
}
}
}
fn read_hex_digits(&mut self, digits: u8) -> Result<u32, Error> {
let mut val = 0;
for _ in 0..digits {
val <<= 4;
val |= unhex(self.read_byte()?)? as u32;
}
Ok(val)
}
fn read_hex_u4(&mut self) -> Result<u8, Error> {
Ok(self.read_hex_digits(1)? as u8)
}
fn read_hex_u8(&mut self) -> Result<u8, Error> {
Ok(self.read_hex_digits(2)? as u8)
}
fn read_hex_identifier(&mut self) -> Result<Identifier, Error> {
let raw = self.read_hex_digits(3)? as u16;
Identifier::from_raw(raw).ok_or(Error::decode())
}
fn read_hex_ext_identifier(&mut self) -> Result<ExtIdentifier, Error> {
let raw = self.read_hex_digits(8)?;
ExtIdentifier::from_raw(raw).ok_or(Error::decode())
}
fn read_frame(&mut self, len: u8) -> Result<CanFrame, Error> {
assert!(len <= 8);
let mut frame = CanFrame::new();
for _ in 0..len {
let byte = self.read_hex_u8()?;
frame.push(byte).unwrap();
}
Ok(frame)
}
}
fn unhex(digit: u8) -> Result<u8, Error> {
match digit {
b'0'..=b'9' => Ok(digit - b'0'),
b'A'..=b'F' => Ok(digit - b'A' + 10),
_ => Err(Error::decode()),
}
}