pub mod mock;
pub mod tapcp;
use crate::{
core::RegisterMap,
yellow_blocks::Address,
};
use casper_utils::design_sources::FpgaDesign;
use thiserror::Error;
#[derive(Error, Debug)]
pub enum Error {
#[error(transparent)]
Infallible(#[from] std::convert::Infallible),
#[error("Trying to transport through a packed struct yeilded a packing error")]
Packing(#[from] packed_struct::PackingError),
#[error("The requested device was not found - `{0}`")]
DeviceNotFound(String),
#[error(transparent)]
Mock(#[from] mock::Error),
#[error(transparent)]
Tapcp(#[from] tapcp::Error),
}
#[allow(clippy::module_name_repetitions)]
pub type TransportResult<T> = Result<T, Error>;
pub trait Serialize {
type Chunk;
fn serialize(&self) -> Self::Chunk;
}
pub trait Deserialize: Sized {
type Chunk;
type Error;
fn deserialize(chunk: Self::Chunk) -> Result<Self, Self::Error>;
}
macro_rules! ser_num {
($num:ty) => {
impl Serialize for $num {
type Chunk = [u8; core::mem::size_of::<$num>()];
fn serialize(&self) -> Self::Chunk {
self.to_be_bytes()
}
}
};
}
macro_rules! deser_num {
($num:ty) => {
impl Deserialize for $num {
type Chunk = [u8; core::mem::size_of::<$num>()];
type Error = std::convert::Infallible;
fn deserialize(chunk: Self::Chunk) -> Result<Self, Self::Error> {
Ok(<$num>::from_be_bytes(chunk))
}
}
};
}
ser_num!(u8);
ser_num!(u16);
ser_num!(u32);
ser_num!(u64);
ser_num!(u128);
ser_num!(i8);
ser_num!(i16);
ser_num!(i32);
ser_num!(i64);
ser_num!(i128);
ser_num!(f32);
ser_num!(f64);
deser_num!(u8);
deser_num!(u16);
deser_num!(u32);
deser_num!(u64);
deser_num!(u128);
deser_num!(i8);
deser_num!(i16);
deser_num!(i32);
deser_num!(i64);
deser_num!(i128);
deser_num!(f32);
deser_num!(f64);
impl<const N: usize> Serialize for [u8; N] {
type Chunk = Self;
fn serialize(&self) -> Self::Chunk {
*self
}
}
impl<const N: usize> Deserialize for [u8; N] {
type Chunk = Self;
type Error = std::convert::Infallible;
fn deserialize(chunk: Self::Chunk) -> Result<Self, Self::Error> {
Ok(chunk)
}
}
pub trait Transport {
fn is_running(&mut self) -> TransportResult<bool>;
fn read_n_bytes(&mut self, device: &str, offset: usize, n: usize) -> TransportResult<Vec<u8>>;
fn read_bytes<const N: usize>(
&mut self,
device: &str,
offset: usize,
) -> TransportResult<[u8; N]> {
Ok(self
.read_n_bytes(device, offset, N)?
.try_into()
.expect("We read exactly N bytes"))
}
fn read<T, const N: usize>(&mut self, device: &str, offset: usize) -> TransportResult<T>
where
T: Deserialize<Chunk = [u8; N]>,
Error: std::convert::From<<T as Deserialize>::Error>,
{
let bytes: [u8; N] = self.read_bytes(device, offset)?;
Ok(T::deserialize(bytes)?)
}
fn read_addr<T, const N: usize>(&mut self, device: &str) -> TransportResult<T>
where
T: Deserialize<Chunk = [u8; N]> + Address,
Error: std::convert::From<<T as Deserialize>::Error>,
{
let bytes: [u8; N] = self.read_bytes(device, T::addr() as usize)?;
Ok(T::deserialize(bytes)?)
}
fn write_bytes(&mut self, device: &str, offset: usize, data: &[u8]) -> TransportResult<()>;
fn write<T, const N: usize>(
&mut self,
device: &str,
offset: usize,
data: &T,
) -> TransportResult<()>
where
T: Serialize<Chunk = [u8; N]>,
{
self.write_bytes(device, offset, &data.serialize())
}
fn write_addr<T, const N: usize>(&mut self, device: &str, data: &T) -> TransportResult<()>
where
T: Serialize<Chunk = [u8; N]> + Address,
{
self.write_bytes(device, T::addr() as usize, &data.serialize())
}
fn listdev(&mut self) -> TransportResult<RegisterMap>;
fn program<D>(&mut self, design: &D, force: bool) -> TransportResult<()>
where
D: FpgaDesign;
fn deprogram(&mut self) -> TransportResult<()>;
}