use core::marker::PhantomData;
use packbytes::{FromBytes, ToBytes, ByteArray};
use bilge::prelude::*;
use crate::pack_enum;
#[derive(PartialEq, Hash)]
pub struct Register<T, A> {
addr: A,
ty: PhantomData<T>,
}
impl<T, A:Copy> Register<T, A> {
pub const fn new(address: A) -> Self {
Self{addr: address, ty: PhantomData}
}
pub const fn address(&self) -> A {self.addr}
}
impl<T: FromBytes, A> Register<T, A> {
pub const fn size(&self) -> SlaveSize {T::Bytes::SIZE as SlaveSize}
}
impl<T, A:Copy> Clone for Register<T, A> {
fn clone(&self) -> Self {
Self::new(self.address())
}
}
impl<T, A:Copy> Copy for Register<T, A> {}
pub type SlaveSize = u16;
pub type VirtualSize = u32;
pub type SlaveRegister<T> = Register<T, SlaveSize>;
pub type VirtualRegister<T> = Register<T, VirtualSize>;
pub const ADDRESS: SlaveRegister<SlaveSize> = Register::new(0x0);
pub const ERROR: SlaveRegister<CommandError> = Register::new(0x2);
pub const LOSS: SlaveRegister<u16> = Register::new(0x3);
pub const VERSION: SlaveRegister<u8> = Register::new(0x5);
pub const DEVICE: SlaveRegister<Device> = Register::new(0x20);
pub const CLOCK: SlaveRegister<u64> = Register::new(0x86);
pub const MAPPING: SlaveRegister<MappingTable> = Register::new(0xff);
pub const USER: usize = 0x500;
#[derive(Clone, FromBytes, ToBytes, Debug)]
pub struct Device {
pub model: StringArray,
pub hardware_version: StringArray,
pub software_version: StringArray,
pub serial: StringArray,
}
#[derive(Clone, FromBytes, ToBytes, Debug)]
pub struct MappingTable {
pub size: u8,
pub map: [Mapping; 128],
}
#[derive(Copy, Clone, Default, FromBytes, ToBytes, Debug, PartialEq)]
pub struct Mapping {
pub virtual_start: u32,
pub slave_start: u16,
pub size: u16,
}
impl Default for MappingTable {
fn default() -> Self {
Self {
size: 0,
map: [Default::default(); 128],
}
}
}
impl MappingTable {
pub fn from_iter(iterable: impl IntoIterator<Item=Mapping>) -> Result<Self, &'static str> {
let mut table = Self::default();
for (i, item) in iterable.into_iter().enumerate() {
if i >= table.map.len() {
return Err("too many items for table");
}
table.map[i] = item;
table.size = u8::try_from(i).unwrap();
}
Ok(table)
}
}
#[bitsize(8)]
#[derive(Copy, Clone, Default, FromBits, Debug, PartialEq)]
pub enum CommandError {
#[default]
None = 0,
#[fallback]
Unknown = 255,
InvalidCommand = 1,
InvalidAccess = 2,
InvalidSize = 3,
InvalidRegister = 4,
InvalidMapping = 5,
}
pack_enum!(CommandError);
#[derive(Clone, Debug, Default, FromBytes, ToBytes)]
pub struct StringArray {
pub size: u8,
pub buffer: [u8; 31],
}
impl TryFrom<&str> for StringArray {
type Error = &'static str;
fn try_from(value: &str) -> Result<Self, Self::Error> {
let value = value.as_bytes();
let size = u8::try_from(value.len()) .map_err(|_| "input string exceeds maximum size")?;
let mut dst = Self {size, .. Default::default()};
if value.len() > dst.buffer.len()
{return Err("input string too long");}
dst.buffer[..value.len()] .copy_from_slice(value);
Ok(dst)
}
}
impl StringArray {
pub fn as_str(&self) -> Result<&'_ str, core::str::Utf8Error> {
str::from_utf8(&self.buffer[.. usize::from(self.size)])
}
}