#![doc = include_str!("../README.md")]
#![deny(unsafe_code, missing_docs)]
#![no_std]
use bitfield_struct::bitfield;
use core::include_str;
use core::marker::PhantomData;
pub struct Ad57xxShared<DEV, IC> {
spi: DEV,
cfg: Config,
pcfg: u16,
_ic: PhantomData<IC>,
}
impl<DEV, IC> Ad57xxShared<DEV, IC> {
pub(crate) fn create(spi: DEV) -> Self {
Ad57xxShared {
spi,
cfg: Config::default(),
pcfg: 0,
_ic: PhantomData,
}
}
pub fn destroy(self) -> DEV {
self.spi
}
}
trait Ad57xxPrivate {}
pub trait Ad57xx<DEV, E> where
u16: From<<Self as Ad57xx<DEV, E>>::PCFG> + Into<<Self as Ad57xx<DEV, E>>::PCFG>,
u8: From<<Self as Ad57xx<DEV, E>>::CH>,
u8: From<Command::<<Self as Ad57xx<DEV, E>>::CH>>,
{
type CH: Copy;
type PCFG: Copy;
fn spi_write(&mut self, payload: &[u8; 3]) -> Result<(), Error<E>>;
fn spi_read(&mut self, cmd: u8) -> Result<u16, Error<E>>;
fn set_dac_output(&mut self, chan: Self::CH, val: u16) -> Result<(), Error<E>> {
self.write(Command::DacRegister(chan), Data::DacValue(val))
}
fn set_config(&mut self, cfg: Config) -> Result<(), Error<E>>;
fn get_config(&mut self) -> Result<Config, Error<E>>;
fn set_power_config(&mut self, pcfg: Self::PCFG) -> Result<(), Error<E>>;
fn get_power_config(&mut self) -> Result<Self::PCFG, Error<E>>;
fn set_output_range(&mut self, chan: Self::CH, range: OutputRange) -> Result<(), Error<E>> {
self.write(Command::RangeSelectRegister(chan), Data::OutputRange(range))
}
fn clear_dacs(&mut self) -> Result<(), Error<E>> {
self.write(Command::<Self::CH>::ControlRegister(Function::Clear), Data::None)
}
fn load_dacs(&mut self) -> Result<(), Error<E>> {
self.write(Command::<Self::CH>::ControlRegister(Function::Load), Data::None)
}
fn write(&mut self, cmd: Command<Self::CH>, data: Data<Self::PCFG>) -> Result<(), Error<E>> {
let payload: [u8; 3] = match cmd {
Command::DacRegister(addr) => {
if let Data::DacValue(val) = data {
[
CommandByte::new()
.with_addr(u8::from(addr))
.with_reg(u8::from(cmd))
.into(),
(val >> 8) as u8,
val as u8,
]
} else {
return Err(Error::InvalidArgument);
}
}
Command::RangeSelectRegister(addr) => {
if let Data::OutputRange(val) = data {
[
CommandByte::new()
.with_addr(u8::from(addr))
.with_reg(u8::from(cmd))
.into(),
0x00,
val as u8,
]
} else {
return Err(Error::InvalidArgument);
}
}
Command::PowerControlRegister => {
if let Data::PowerControl(pcfg) = data {
[
CommandByte::new().with_reg(u8::from(cmd)).into(),
(u16::from(pcfg) >> 8) as u8,
(u16::from(pcfg)) as u8,
]
} else {
return Err(Error::InvalidArgument);
}
}
Command::ControlRegister(func) if func == Function::Config => {
if let Data::Control(cfg) = data {
[
CommandByte::new()
.with_reg(u8::from(cmd))
.with_addr(func as u8)
.into(),
0x00,
u8::from(cfg) as u8,
]
} else {
return Err(Error::InvalidArgument);
}
}
Command::ControlRegister(func) => {
if let Data::None = data {
[
CommandByte::new()
.with_reg(u8::from(cmd))
.with_addr(func as u8)
.into(),
0x00,
0x00,
]
} else {
return Err(Error::InvalidArgument);
}
}
};
self.spi_write(&payload)
}
fn read(&mut self, cmd: Command<Self::CH>) -> Result<Data<Self::PCFG>, Error<E>> {
let addr = match cmd {
Command::DacRegister(addr) => u8::from(addr),
Command::RangeSelectRegister(addr) => u8::from(addr),
Command::PowerControlRegister => 0,
Command::ControlRegister(function) => function as u8,
};
let cmd_byte = CommandByte::new()
.with_rw(true)
.with_reg(u8::from(cmd))
.with_addr(addr);
let data = self.spi_read(u8::from(cmd_byte))?;
match cmd {
Command::DacRegister(_) => Ok(Data::DacValue(data)),
Command::RangeSelectRegister(_) => Ok(Data::OutputRange(OutputRange::from(data))),
Command::PowerControlRegister => Ok(Data::PowerControl(data.into())),
Command::ControlRegister(func) if func == Function::Config => {
Ok(Data::Control(Config::from(data as u8)))
}
Command::ControlRegister(_) => Err(Error::ReadError),
}
}
}
#[derive(Debug)]
pub enum Error<E> {
Spi(E),
InvalidArgument,
ReadError,
}
#[derive(Debug)]
pub enum Data<PCFG> {
DacValue(u16),
OutputRange(OutputRange),
Control(Config),
PowerControl(PCFG),
None,
}
#[derive(Debug, Clone, Copy)]
#[repr(u8)]
pub enum Command<C> {
DacRegister(C),
RangeSelectRegister(C),
PowerControlRegister,
ControlRegister(Function),
}
impl<C> From<Command<C>> for u8 {
fn from(cmd: Command<C>) -> Self {
match cmd {
Command::DacRegister(_) => 0b000,
Command::RangeSelectRegister(_) => 0b001,
Command::PowerControlRegister => 0b010,
Command::ControlRegister(_) => 0b011,
}
}
}
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
#[repr(u8)]
pub enum Function {
Nop = 0b000,
Config = 0b001,
Clear = 0b100,
Load = 0b101,
}
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
#[repr(u16)]
pub enum OutputRange {
Unipolar5V = 0b000,
Unipolar10V = 0b001,
Unipolar10_8V = 0b010,
Bipolar5V = 0b011,
Bipolar10V = 0b100,
Bipolar10_8V = 0b101,
InvalidReadback,
}
impl From<u16> for OutputRange {
fn from(value: u16) -> Self {
match value {
0b000 => Self::Unipolar5V,
0b001 => Self::Unipolar10V,
0b010 => Self::Unipolar10_8V,
0b011 => Self::Bipolar5V,
0b100 => Self::Bipolar10V,
0b101 => Self::Bipolar10_8V,
_ => Self::InvalidReadback,
}
}
}
#[bitfield(u8)]
struct CommandByte {
#[bits(3)]
addr: u8,
#[bits(3)]
reg: u8,
#[bits(1)]
_zero: bool,
#[bits(1)]
rw: bool,
}
#[bitfield(u8)]
pub struct Config {
#[bits(default = false)]
pub sdo_disable: bool,
#[bits(default = false)]
pub clr_select: bool,
#[bits(default = true)]
pub clamp_enable: bool,
#[bits(default = false)]
pub(crate) tsd_enable: bool,
#[bits(4)]
_unused: u16,
}
#[doc(hidden)]
pub mod marker {
pub struct Ad57x4 {}
pub struct Ad57x2 {}
}
pub mod ad57x2;
pub mod ad57x4;
mod private {
use super::marker;
pub trait Sealed {}
impl Sealed for marker::Ad57x4 {}
impl Sealed for marker::Ad57x2 {}
}