use crate::{
decode::{Decode, DecodeError, DecodeErrorKind},
encode::{Encode, MessageEncoder},
varint::VarU16,
version::Version,
};
use super::{COMMAND_HEADER, REPLY_HEADER};
pub mod cmds {
pub const ACK: u8 = 0x33;
pub const QUERY_1: u8 = 0x21;
pub const USER_CDC: u8 = 0x56;
pub const CON_CDC: u8 = 0x58;
pub const SYSTEM_VERSION: u8 = 0xA4;
pub const EEPROM_ERASE: u8 = 0x31;
pub const USER_ENTER: u8 = 0x60;
pub const USER_CATALOG: u8 = 0x61;
pub const FLASH_ERASE: u8 = 0x63;
pub const FLASH_WRITE: u8 = 0x64;
pub const FLASH_READ: u8 = 0x65;
pub const USER_EXIT: u8 = 0x66;
pub const USER_PLAY: u8 = 0x67;
pub const USER_STOP: u8 = 0x68;
pub const COMPONENT_GET: u8 = 0x69;
pub const USER_SLOT_GET: u8 = 0x78;
pub const USER_SLOT_SET: u8 = 0x79;
pub const BRAIN_NAME_GET: u8 = 0x44;
}
use bitflags::bitflags;
use cmds::{QUERY_1, SYSTEM_VERSION};
#[derive(Clone, Copy, Eq, PartialEq)]
pub struct CdcCommandPacket<const CMD: u8, P: Encode> {
payload: P,
}
impl<const CMD: u8, P: Encode> CdcCommandPacket<CMD, P> {
pub const HEADER: [u8; 4] = COMMAND_HEADER;
pub fn new(payload: P) -> Self {
Self { payload }
}
}
impl<const CMD: u8, P: Encode> Encode for CdcCommandPacket<CMD, P> {
fn size(&self) -> usize {
let payload_size = self.payload.size();
5 + if payload_size == 0 {
0
} else if payload_size > (u8::MAX >> 1) as _ {
2
} else {
1
} + payload_size
}
fn encode(&self, data: &mut [u8]) {
Self::HEADER.encode(data);
data[4] = CMD;
let payload_size = self.payload.size();
if payload_size > 0 {
let mut enc = MessageEncoder::new_with_position(data, 5);
enc.write(&VarU16::new(payload_size as u16));
enc.write(&self.payload);
}
}
}
#[derive(Clone, Copy, Eq, PartialEq)]
pub struct CdcReplyPacket<const CMD: u8, P: Decode> {
pub size: u16,
pub payload: P,
}
impl<const CMD: u8, P: Decode> CdcReplyPacket<CMD, P> {
pub const HEADER: [u8; 2] = REPLY_HEADER;
}
impl<const CMD: u8, P: Decode> Decode for CdcReplyPacket<CMD, P> {
fn decode(data: &mut &[u8]) -> Result<Self, DecodeError> {
if <[u8; 2]>::decode(data)? != Self::HEADER {
return Err(DecodeError::new::<Self>(DecodeErrorKind::InvalidHeader));
}
let cmd = u8::decode(data)?;
if cmd != CMD {
return Err(DecodeError::new::<Self>(DecodeErrorKind::UnexpectedByte {
name: "cmd",
value: cmd,
expected: &[CMD],
}));
}
let payload_size = VarU16::decode(data)?.into_inner();
let mut payload_data = data
.get(0..(payload_size as usize))
.ok_or_else(|| DecodeError::new::<Self>(DecodeErrorKind::UnexpectedEnd))?;
*data = &data[(payload_size as usize)..];
let payload = P::decode(&mut payload_data)?;
Ok(Self {
size: payload_size,
payload,
})
}
}
pub type SystemVersionPacket = CdcCommandPacket<SYSTEM_VERSION, ()>;
pub type SystemVersionReplyPacket = CdcReplyPacket<SYSTEM_VERSION, SystemVersionReplyPayload>;
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub struct SystemVersionReplyPayload {
pub version: Version,
pub product_type: ProductType,
pub flags: ProductFlags,
}
impl Decode for SystemVersionReplyPayload {
fn decode(data: &mut &[u8]) -> Result<Self, DecodeError> {
let version = Version::decode(data)?;
let product_type = ProductType::decode(data)?;
let flags = ProductFlags::from_bits_truncate(u8::decode(data)?);
Ok(Self {
version,
product_type,
flags,
})
}
}
pub type Query1Packet = CdcCommandPacket<QUERY_1, ()>;
pub type Query1ReplyPacket = CdcReplyPacket<QUERY_1, Query1ReplyPayload>;
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub struct Query1ReplyPayload {
pub version_1: u32,
pub version_2: u32,
pub boot_source: u8,
pub count: u8,
}
impl Decode for Query1ReplyPayload {
fn decode(data: &mut &[u8]) -> Result<Self, DecodeError> {
let version_1 = u32::decode(data)?;
let version_2 = u32::decode(data)?;
let boot_source = u8::decode(data)?;
let count = u8::decode(data)?;
Ok(Self {
version_1,
version_2,
boot_source,
count,
})
}
}
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
#[repr(u16)]
pub enum ProductType {
V5Brain = 0x10,
ExpBrain = 0x60,
Controller = 0x11,
}
impl Decode for ProductType {
fn decode(data: &mut &[u8]) -> Result<Self, DecodeError> {
let data = <[u8; 2]>::decode(data)?;
match data[1] {
0x10 => Ok(Self::V5Brain),
0x60 => Ok(Self::ExpBrain),
0x11 => Ok(Self::Controller),
v => Err(DecodeError::new::<Self>(DecodeErrorKind::UnexpectedByte {
name: "ProductType",
value: v,
expected: &[0x10, 0x11, 0x60],
})),
}
}
}
bitflags! {
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub struct ProductFlags: u8 {
const CONNECTED_CABLE = 1 << 0;
const CONNECTED_WIRELESS = 1 << 1;
}
}