use crate::{Error, ReadWrite};
use core::convert::TryFrom;
use scroll::{ctx, Pread, Pwrite, LE};
impl From<scroll::Error> for Error {
fn from(_err: scroll::Error) -> Self {
Error::Parse
}
}
impl From<core::str::Utf8Error> for Error {
fn from(_err: core::str::Utf8Error) -> Self {
Error::Parse
}
}
impl From<std::io::Error> for Error {
fn from(_err: std::io::Error) -> Self {
Error::Arguments
}
}
#[derive(Debug, PartialEq)]
pub(crate) struct CommandResponse {
pub(crate) tag: u16,
pub(crate) status: CommandResponseStatus,
pub(crate) status_info: u8,
pub(crate) data: Vec<u8>,
}
#[derive(Debug, PartialEq)]
pub(crate) enum CommandResponseStatus {
Success = 0x00,
ParseError = 0x01,
ExecutionError = 0x02,
}
impl TryFrom<u8> for CommandResponseStatus {
type Error = Error;
fn try_from(val: u8) -> Result<Self, Self::Error> {
match val {
0 => Ok(CommandResponseStatus::Success),
1 => Ok(CommandResponseStatus::ParseError),
2 => Ok(CommandResponseStatus::ExecutionError),
_ => Err(Error::Parse),
}
}
}
#[derive(Debug, PartialEq)]
enum PacketType {
Inner = 0,
Final = 1,
StdOut = 2,
Stderr = 3,
}
impl TryFrom<u8> for PacketType {
type Error = Error;
fn try_from(val: u8) -> Result<Self, Self::Error> {
match val {
0 => Ok(PacketType::Inner),
1 => Ok(PacketType::Final),
2 => Ok(PacketType::StdOut),
3 => Ok(PacketType::Stderr),
_ => Err(Error::Parse),
}
}
}
impl<'a> ctx::TryFromCtx<'a, scroll::Endian> for CommandResponse {
type Error = Error;
fn try_from_ctx(this: &'a [u8], le: scroll::Endian) -> Result<(Self, usize), Self::Error> {
if this.len() < 4 {
return Err(Error::Parse);
}
let mut offset = 0;
let tag = this.gread_with::<u16>(&mut offset, le)?;
let status: u8 = this.gread_with::<u8>(&mut offset, le)?;
let status = CommandResponseStatus::try_from(status)?;
let status_info = this.gread_with::<u8>(&mut offset, le)?;
Ok((
CommandResponse {
tag,
status,
status_info,
data: this[offset..].to_vec(),
},
offset,
))
}
}
#[derive(Debug)]
pub(crate) struct Command {
id: u32,
tag: u16,
_reserved0: u8,
_reserved1: u8,
data: Vec<u8>,
}
impl Command {
pub(crate) fn new(id: u32, tag: u16, data: Vec<u8>) -> Self {
Self {
id,
tag,
_reserved0: 0,
_reserved1: 0,
data,
}
}
}
pub(crate) fn xmit(cmd: Command, d: &impl ReadWrite) -> Result<(), Error> {
log::debug!("{:?}", cmd);
let buffer = &mut [0_u8; 65];
let mut offset = 2;
buffer.gwrite_with(cmd.id, &mut offset, LE)?;
buffer.gwrite_with(cmd.tag, &mut offset, LE)?;
buffer.gwrite_with(cmd._reserved0, &mut offset, LE)?;
buffer.gwrite_with(cmd._reserved1, &mut offset, LE)?;
let mut count = if cmd.data.len() > 55 {
55
} else {
cmd.data.len()
};
buffer.gwrite(&cmd.data[..count], &mut offset)?;
if count == cmd.data.len() {
buffer[1] = (PacketType::Final as u8) << 6 | (offset - 2) as u8;
log::debug!("tx: {:02X?}", &buffer[..offset]);
return d.hf2_write(&buffer[..offset]).map(|_| ());
} else {
buffer[1] = (PacketType::Inner as u8) << 6 | (offset - 2) as u8;
log::debug!("tx: {:02X?}", &buffer[..offset]);
d.hf2_write(&buffer[..offset])?;
}
for chunk in cmd.data[count..].chunks(63) {
count += chunk.len();
if count == cmd.data.len() {
buffer[1] = (PacketType::Final as u8) << 6 | chunk.len() as u8;
} else {
buffer[1] = (PacketType::Inner as u8) << 6 | chunk.len() as u8;
}
buffer[2..(chunk.len() + 2)].copy_from_slice(chunk);
log::debug!("tx: {:02X?}", &buffer[..(chunk.len() + 2)]);
d.hf2_write(&buffer[..(chunk.len() + 2)])?;
}
Ok(())
}
pub(crate) fn rx(d: &impl ReadWrite) -> Result<CommandResponse, Error> {
let mut bitsnbytes: Vec<u8> = vec![];
let buffer = &mut [0_u8; 64];
let mut retries = 5;
'outer: while {
let count = d.hf2_read(buffer)?;
log::debug!("rx count: {:?}", count);
if count < 1 {
if retries <= 0 {
return Err(Error::Parse);
} else {
retries -= 1;
continue 'outer;
}
}
let ptype = PacketType::try_from(buffer[0] >> 6)?;
log::debug!("rx ptype: {:?}", ptype);
let len: usize = (buffer[0] & 0x3F) as usize;
log::debug!("rx len: {:?}", len);
if len >= count {
return Err(Error::Parse);
}
log::debug!(
"rx header: {:02X?} data: {:02X?}",
&buffer[0],
&buffer[1..(len + 1)]
);
bitsnbytes.extend_from_slice(&buffer[1..(len + 1)]);
ptype == PacketType::Inner
} {}
let resp = bitsnbytes.as_slice().pread_with(0, LE)?;
log::debug!("{:?}", resp);
Ok(resp)
}
#[cfg(test)]
mod tests {
use super::*;
#[allow(dead_code)]
pub struct MyMock<R, W>
where
R: Fn() -> Vec<u8>,
W: Fn(&[u8]) -> usize,
{
pub reader: R,
pub writer: W,
}
impl<R, W> ReadWrite for MyMock<R, W>
where
R: Fn() -> Vec<u8>,
W: Fn(&[u8]) -> usize,
{
fn hf2_write(&self, data: &[u8]) -> Result<usize, Error> {
let len = (&self.writer)(data);
Ok(len)
}
fn hf2_read(&self, buf: &mut [u8]) -> Result<usize, Error> {
let data = (self.reader)();
for (i, val) in data.iter().enumerate() {
buf[i] = *val
}
Ok(data.len())
}
}
#[test]
fn send_fragmented() {
let data: Vec<Vec<u8>> = vec![
vec![
0x00, 0x3f, 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00,
0x00, 0x00, 0x03, 0x20, 0xd7, 0x5e, 0x00, 0x00, 0x4d, 0x5f, 0x00, 0x00, 0x51, 0x5f,
0x00, 0x00, 0x4d, 0x5f, 0x00, 0x00, 0x4d, 0x5f, 0x00, 0x00, 0x4d, 0x5f, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x4d, 0x5f, 0x00, 0x00, 0x4d, 0x5f, 0x00,
],
vec![
0x00, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4d, 0x5f, 0x00, 0x00, 0x4d, 0x5f, 0x00,
0x00, 0x4d, 0x5f, 0x00, 0x00, 0x4d, 0x5f, 0x00, 0x00, 0x4d, 0x5f, 0x00, 0x00, 0x4d,
0x5f, 0x00, 0x00, 0x4d, 0x5f, 0x00, 0x00, 0x4d, 0x5f, 0x00, 0x00, 0x4d, 0x5f, 0x00,
0x00, 0x4d, 0x5f, 0x00, 0x00, 0x4d, 0x5f, 0x00, 0x00, 0x4d, 0x5f, 0x00, 0x00, 0x4d,
0x5f, 0x00, 0x00, 0x4d, 0x5f, 0x00, 0x00, 0x4d, 0x5f,
],
vec![
0x00, 0x3f, 0x00, 0x00, 0x4d, 0x5f, 0x00, 0x00, 0x4d, 0x5f, 0x00, 0x00, 0x4d, 0x5f,
0x00, 0x00, 0x4d, 0x5f, 0x00, 0x00, 0x4d, 0x5f, 0x00, 0x00, 0x4d, 0x5f, 0x00, 0x00,
0x4d, 0x5f, 0x00, 0x00, 0x4d, 0x5f, 0x00, 0x00, 0x4d, 0x5f, 0x00, 0x00, 0x4d, 0x5f,
0x00, 0x00, 0x4d, 0x5f, 0x00, 0x00, 0x4d, 0x5f, 0x00, 0x00, 0x4d, 0x5f, 0x00, 0x00,
0x4d, 0x5f, 0x00, 0x00, 0x4d, 0x5f, 0x00, 0x00, 0x4d,
],
vec![
0x00, 0x3f, 0x5f, 0x00, 0x00, 0x4d, 0x5f, 0x00, 0x00, 0x4d, 0x5f, 0x00, 0x00, 0x4d,
0x5f, 0x00, 0x00, 0x4d, 0x5f, 0x00, 0x00, 0x4d, 0x5f, 0x00, 0x00, 0x4d, 0x5f, 0x00,
0x00, 0x4d, 0x5f, 0x00, 0x00, 0x4d, 0x5f, 0x00, 0x00, 0x4d, 0x5f, 0x00, 0x00, 0x4d,
0x5f, 0x00, 0x00, 0x4d, 0x5f, 0x00, 0x00, 0x4d, 0x5f, 0x00, 0x00, 0x4d, 0x5f, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
],
vec![
0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x4d, 0x5f, 0x00, 0x00, 0x4d, 0x5f, 0x00, 0x00,
0x4d, 0x5f, 0x00, 0x00,
],
];
let le_page: Vec<u8> = vec![
0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x03, 0x20, 0xD7, 0x5E, 0x00, 0x00, 0x4D, 0x5F,
0x00, 0x00, 0x51, 0x5F, 0x00, 0x00, 0x4D, 0x5F, 0x00, 0x00, 0x4D, 0x5F, 0x00, 0x00,
0x4D, 0x5F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4D, 0x5F, 0x00, 0x00, 0x4D, 0x5F, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x4D, 0x5F, 0x00, 0x00, 0x4D, 0x5F, 0x00, 0x00, 0x4D, 0x5F,
0x00, 0x00, 0x4D, 0x5F, 0x00, 0x00, 0x4D, 0x5F, 0x00, 0x00, 0x4D, 0x5F, 0x00, 0x00,
0x4D, 0x5F, 0x00, 0x00, 0x4D, 0x5F, 0x00, 0x00, 0x4D, 0x5F, 0x00, 0x00, 0x4D, 0x5F,
0x00, 0x00, 0x4D, 0x5F, 0x00, 0x00, 0x4D, 0x5F, 0x00, 0x00, 0x4D, 0x5F, 0x00, 0x00,
0x4D, 0x5F, 0x00, 0x00, 0x4D, 0x5F, 0x00, 0x00, 0x4D, 0x5F, 0x00, 0x00, 0x4D, 0x5F,
0x00, 0x00, 0x4D, 0x5F, 0x00, 0x00, 0x4D, 0x5F, 0x00, 0x00, 0x4D, 0x5F, 0x00, 0x00,
0x4D, 0x5F, 0x00, 0x00, 0x4D, 0x5F, 0x00, 0x00, 0x4D, 0x5F, 0x00, 0x00, 0x4D, 0x5F,
0x00, 0x00, 0x4D, 0x5F, 0x00, 0x00, 0x4D, 0x5F, 0x00, 0x00, 0x4D, 0x5F, 0x00, 0x00,
0x4D, 0x5F, 0x00, 0x00, 0x4D, 0x5F, 0x00, 0x00, 0x4D, 0x5F, 0x00, 0x00, 0x4D, 0x5F,
0x00, 0x00, 0x4D, 0x5F, 0x00, 0x00, 0x4D, 0x5F, 0x00, 0x00, 0x4D, 0x5F, 0x00, 0x00,
0x4D, 0x5F, 0x00, 0x00, 0x4D, 0x5F, 0x00, 0x00, 0x4D, 0x5F, 0x00, 0x00, 0x4D, 0x5F,
0x00, 0x00, 0x4D, 0x5F, 0x00, 0x00, 0x4D, 0x5F, 0x00, 0x00, 0x4D, 0x5F, 0x00, 0x00,
0x4D, 0x5F, 0x00, 0x00, 0x4D, 0x5F, 0x00, 0x00, 0x4D, 0x5F, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4D, 0x5F, 0x00, 0x00,
0x4D, 0x5F, 0x00, 0x00, 0x4D, 0x5F, 0x00, 0x00,
];
let writer = |v: &[u8]| -> usize {
static mut I: usize = 0;
let res: &Vec<u8> = unsafe {
let res = &data[I];
I += 1;
res
};
assert_eq!(res.as_slice(), v);
v.len()
};
let mock = MyMock {
reader: || vec![],
writer,
};
let command = Command::new(0x0006, 4, le_page);
xmit(command, &mock).unwrap();
}
#[test]
fn receive_fragmented() {
let data: Vec<Vec<u8>> = vec![
vec![
0x3F, 0x04, 0x00, 0x00, 0x00, 0x55, 0x46, 0x32, 0x20, 0x42, 0x6F, 0x6F, 0x74, 0x6C,
0x6F, 0x61, 0x64, 0x65, 0x72, 0x20, 0x76, 0x33, 0x2E, 0x36, 0x2E, 0x30, 0x20, 0x53,
0x46, 0x48, 0x57, 0x52, 0x4F, 0x0D, 0x0A, 0x4D, 0x6F, 0x64, 0x65, 0x6C, 0x3A, 0x20,
0x50, 0x79, 0x47, 0x61, 0x6D, 0x65, 0x72, 0x0D, 0x0A, 0x42, 0x6F, 0x61, 0x72, 0x64,
0x2D, 0x49, 0x44, 0x3A, 0x20, 0x53, 0x41, 0x4D,
],
vec![
0x54, 0x44, 0x35, 0x31, 0x4A, 0x31, 0x39, 0x41, 0x2D, 0x50, 0x79, 0x47, 0x61, 0x6D,
0x65, 0x72, 0x2D, 0x4D, 0x34, 0x0D, 0x0A,
],
];
let result: Vec<u8> = vec![
0x55, 0x46, 0x32, 0x20, 0x42, 0x6F, 0x6F, 0x74, 0x6C, 0x6F, 0x61, 0x64, 0x65, 0x72,
0x20, 0x76, 0x33, 0x2E, 0x36, 0x2E, 0x30, 0x20, 0x53, 0x46, 0x48, 0x57, 0x52, 0x4F,
0x0D, 0x0A, 0x4D, 0x6F, 0x64, 0x65, 0x6C, 0x3A, 0x20, 0x50, 0x79, 0x47, 0x61, 0x6D,
0x65, 0x72, 0x0D, 0x0A, 0x42, 0x6F, 0x61, 0x72, 0x64, 0x2D, 0x49, 0x44, 0x3A, 0x20,
0x53, 0x41, 0x4D, 0x44, 0x35, 0x31, 0x4A, 0x31, 0x39, 0x41, 0x2D, 0x50, 0x79, 0x47,
0x61, 0x6D, 0x65, 0x72, 0x2D, 0x4D, 0x34, 0x0D, 0x0A,
];
let reader = || -> Vec<u8> {
static mut I: usize = 0;
let res: &Vec<u8> = unsafe {
let res = &data[I];
I += 1;
res
};
res.to_vec()
};
let mock = MyMock {
reader,
writer: |_v| 0,
};
let response = CommandResponse {
tag: 0x0004,
status: CommandResponseStatus::Success,
status_info: 0x00,
data: result.to_vec(),
};
let rsp = rx(&mock).unwrap();
assert_eq!(rsp, response);
}
}