#![deny(warnings)]
#![no_std]
use embedded_hal::digital::v2::OutputPin;
#[derive(PartialEq, Copy, Clone)]
pub enum Channel {
A = 0,
B = 1,
C = 2,
D = 3,
E = 4,
F = 5,
G = 6,
H = 7,
NOMSG = 8,
BROADCAST = 9,
}
impl Channel {
pub fn from_index(index: u8) -> Channel {
match index {
0 => Channel::A,
1 => Channel::B,
2 => Channel::C,
3 => Channel::D,
4 => Channel::E,
5 => Channel::F,
6 => Channel::G,
7 => Channel::H,
_ => panic!("Unsupported index for dac8568 channel select"),
}
}
}
pub enum ControlType {
WriteToInputRegister = 0,
UpdateRegister = 1,
WriteToChannelAndUpdateAllRegisters = 2,
WriteToChannelAndUpdateSingleRegister = 3,
PowerDownComm = 4,
WriteToClearCodeRegister = 5,
WriteToLDACRegister = 6,
SoftwareReset = 7,
}
#[derive(Copy, Clone)]
pub struct Message {
prefix: u8, control: u8, address: u8, data: u16, feature: u8, }
impl Message {
pub fn get_internal_reference_message(internal: bool) -> Message {
Message {
prefix: 0x00,
control: 0x08,
address: 0x00,
data: 0x0000,
feature: if internal { 0x01 } else { 0x00 },
}
}
pub fn get_voltage_message(channel: Channel, value: u16, is_inverted: bool) -> Message {
let output = if is_inverted { u16::MAX - value } else { value };
Message {
prefix: 0,
control: ControlType::WriteToChannelAndUpdateSingleRegister as u8,
address: channel as u8,
data: output,
feature: 0,
}
}
pub fn get_payload(&self) -> [u8; 4] {
let mut payload: u32 = 0x00;
payload = payload | ((self.prefix as u32) << 28);
payload = payload | ((self.control as u32) << 24);
payload = payload | ((self.address as u32) << 20);
payload = payload | ((self.data as u32) << 4);
payload = payload | ((self.feature as u32) << 0);
payload.to_be_bytes()
}
}
pub struct Dac<SPI, SYNC> {
spi: SPI,
sync: SYNC,
is_inverted: bool,
}
#[derive(Copy, Clone, Debug)]
#[non_exhaustive]
pub enum DacError {
BusWriteError,
}
impl<SPI, SYNC> Dac<SPI, SYNC>
where
SPI: embedded_hal::blocking::spi::Write<u8>,
SYNC: OutputPin,
{
pub fn new(spi: SPI, sync: SYNC) -> Self {
Self {
spi,
sync,
is_inverted: false,
}
}
pub fn release(self) -> (SPI, SYNC) {
(self.spi, self.sync)
}
pub fn set_inverted_output(&mut self, state: bool) {
self.is_inverted = state;
}
pub fn set_voltage(&mut self, channel: Channel, voltage: u16) -> Result<(), DacError> {
let message = Message::get_voltage_message(channel, voltage, self.is_inverted);
self.write(message)
}
pub fn use_internal_reference(&mut self) -> Result<(), DacError> {
let message = Message::get_internal_reference_message(true);
self.write(message)
}
pub fn use_external_reference(&mut self) -> Result<(), DacError> {
let message = Message::get_internal_reference_message(false);
self.write(message)
}
fn write(&mut self, message: Message) -> Result<(), DacError> {
let command: [u8; 4] = message.get_payload();
self.sync.set_low().unwrap_or_default();
let result = self.spi.write(&command);
self.sync.set_high().unwrap_or_default();
match result {
Ok(v) => Ok(v),
Err(_e) => Err(DacError::BusWriteError),
}
}
}
#[cfg(test)]
mod tests {
#[test]
fn inverts_signal() {
let message = super::Message::get_voltage_message(super::Channel::A, 0, false);
assert_eq!(message.data, 0);
let message = super::Message::get_voltage_message(super::Channel::A, 0, true);
assert_eq!(message.data, u16::MAX);
}
}