#![no_std]
#[warn(missing_debug_implementations, missing_docs)]
use embedded_hal::{blocking::spi::Write, digital::v2::OutputPin};
pub struct AD5668<SPI, CS> {
spi: SPI,
chip_select: CS,
}
impl<SPI, CS, E> AD5668<SPI, CS>
where
SPI: Write<u8, Error = E>,
CS: OutputPin,
{
pub fn new(spi: SPI, mut chip_select: CS) -> Self {
chip_select.set_high().ok();
Self { spi, chip_select }
}
fn write_spi(&mut self, data: &[u8]) -> Result<(), E> {
self.chip_select.set_low().ok();
let result = self.spi.write(data);
self.chip_select.set_high().ok();
result
}
pub fn write_input_register(&mut self, address: Address, value: u16) -> Result<(), E> {
self.write_spi(&encode_update_command(
Command::WriteInputRegister,
address,
value,
))
}
pub fn update_dac_register(&mut self, address: Address, value: u16) -> Result<(), E> {
self.write_spi(&encode_update_command(
Command::UpdateDacRegister,
address,
value,
))
}
pub fn write_input_register_update_all(
&mut self,
address: Address,
value: u16,
) -> Result<(), E> {
self.write_spi(&encode_update_command(
Command::WriteInputUpdateAll,
address,
value,
))
}
pub fn write_and_update_dac_channel(&mut self, address: Address, value: u16) -> Result<(), E> {
self.write_spi(&encode_update_command(
Command::WriteUpdateDacChannel,
address,
value,
))
}
pub fn enable_internal_ref(&mut self) -> Result<(), E> {
self.write_spi(&[
Command::SetInternalRefRegister as u8,
0x00u8,
0x00u8,
InternalRef::Enabled as u8,
])
}
pub fn disable_internal_ref(&mut self) -> Result<(), E> {
self.write_spi(&[
Command::SetInternalRefRegister as u8,
0x00u8,
0x00u8,
InternalRef::Disabled as u8,
])
}
pub fn reset(&mut self) -> Result<(), E> {
self.write_spi(&[Command::Reset as u8, 0x00u8, 0x00u8, 0x00u8])
}
pub fn destroy(mut self) -> (SPI, CS) {
self.chip_select.set_low().ok();
(self.spi, self.chip_select)
}
}
fn encode_update_command(command: Command, address: Address, value: u16) -> [u8; 4] {
[
command as u8,
((address as u8) << 4) + (value >> 12) as u8,
(value >> 4) as u8,
(value << 4) as u8,
]
}
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
#[repr(u8)]
pub enum Address {
DacA = 0b0000,
DacB = 0b0001,
DacC = 0b0010,
DacD = 0b0011,
DacE = 0b0100,
DacF = 0b0101,
DacG = 0b0110,
DacH = 0b0111,
AllDacs = 0b1111,
}
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
#[repr(u8)]
pub enum InternalRef {
Disabled = 0x00u8,
Enabled = 0x01u8,
}
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
#[repr(u8)]
enum Command {
WriteInputRegister = 0b0000,
UpdateDacRegister = 0b0001,
WriteInputUpdateAll = 0b0010,
WriteUpdateDacChannel = 0b0011,
PowerDACUpDown = 0b0100,
LoadClearCodeRegister = 0b0101,
LoadLDACRegister = 0b0110,
Reset = 0b0111,
SetInternalRefRegister = 0b1000,
}
#[cfg(test)]
mod test {
use super::*;
use embedded_hal_mock::{pin, spi};
extern crate std;
use std::vec;
#[test]
pub fn should_encode_command() {
assert_eq!(
encode_update_command(Command::WriteUpdateDacChannel, Address::DacA, 0u16),
[0b00000011, 0b00000000, 0b00000000, 0b00000000],
)
}
#[test]
pub fn should_encode_address() {
assert_eq!(
encode_update_command(Command::WriteInputRegister, Address::AllDacs, 0u16),
[0b00000000, 0b11110000, 0b00000000, 0b00000000],
)
}
#[test]
pub fn should_encode_value() {
assert_eq!(
encode_update_command(Command::WriteInputRegister, Address::DacA, 0xffffu16),
[0b00000000, 0b00001111, 0b11111111, 0b11110000],
)
}
fn setup_mocks() -> (spi::Mock, pin::Mock) {
let spi = spi::Mock::new(&[]);
let chip_select = pin::Mock::new(&[
pin::Transaction::set(pin::State::High),
pin::Transaction::set(pin::State::Low),
pin::Transaction::set(pin::State::High),
]);
(spi, chip_select)
}
#[test]
pub fn should_init_chip_select_high() {
let (spi, mut chip_select) = setup_mocks();
chip_select.expect(&[
pin::Transaction::set(pin::State::High),
pin::Transaction::set(pin::State::Low),
]);
let dac = AD5668::new(spi, chip_select);
let (_, mut chip_select) = dac.destroy();
chip_select.done()
}
#[test]
pub fn should_enable_internal_ref() {
let (mut spi, chip_select) = setup_mocks();
spi.expect(&[spi::Transaction::write(vec![
0x08u8, 0x00u8, 0x00u8, 0x01u8,
])]);
let mut dac = AD5668::new(spi, chip_select);
dac.enable_internal_ref().unwrap();
}
#[test]
pub fn should_disable_internal_ref() {
let (mut spi, chip_select) = setup_mocks();
spi.expect(&[spi::Transaction::write(vec![
0x08u8, 0x00u8, 0x00u8, 0x00u8,
])]);
let mut dac = AD5668::new(spi, chip_select);
dac.disable_internal_ref().unwrap();
}
#[test]
pub fn should_send_reset_command() {
let (mut spi, chip_select) = setup_mocks();
spi.expect(&[spi::Transaction::write(vec![
0x07u8, 0x00u8, 0x00u8, 0x00u8,
])]);
let mut dac = AD5668::new(spi, chip_select);
dac.reset().unwrap();
}
}