#![no_std]
use crate::registers::WriteRegister;
use embedded_hal::spi::SpiDevice;
pub mod registers;
const CHANNELS_PER_REGISTER: usize = 6;
const CHANNELS_PER_IC: usize = 12;
#[derive(Debug, PartialEq, Clone, Copy)]
pub enum Error {
SpiError,
CommunicationError,
InitFailed,
NotInitialized,
InvalidChannel,
}
pub type OperationResult = Result<(), Error>;
pub struct Bd18378<'a, SPI: SpiDevice> {
spi: &'a mut SPI,
is_initialized: bool,
channel_enable: [bool; CHANNELS_PER_IC],
}
impl<'a, SPI: SpiDevice> Bd18378<'a, SPI> {
pub fn new(spi: &'a mut SPI) -> Self {
Bd18378 {
spi,
is_initialized: false,
channel_enable: [false; CHANNELS_PER_IC],
}
}
pub fn init(&mut self) -> OperationResult {
let mut old_data = [0x00u8, 0x00u8];
let seq = Self::get_init_sequence();
let mut first = true;
for (reg, value) in seq.iter() {
let data = self.write_register(*reg, *value)?;
if !first && data != old_data {
return Err(Error::CommunicationError);
}
old_data = [*reg as u8, *value];
first = false;
}
self.reset_status_register()?;
self.is_initialized = true;
Ok(())
}
pub fn is_initialized(&self) -> bool {
self.is_initialized
}
pub fn enable_channel(&mut self, ch: usize) -> OperationResult {
if ch >= self.channel_enable.len() {
return Err(Error::InvalidChannel);
}
self.check_initialized()?;
self.channel_enable[ch] = true;
Ok(())
}
pub fn disable_channel(&mut self, ch: usize) -> OperationResult {
if ch >= self.channel_enable.len() {
return Err(Error::InvalidChannel);
}
self.check_initialized()?;
self.channel_enable[ch] = false;
Ok(())
}
pub fn update_all_channels(&mut self) -> OperationResult {
self.check_initialized()?;
let first_group_value = self.compute_channel_group_value(0, CHANNELS_PER_REGISTER, 0);
self.write_register(WriteRegister::ChannelEnable00To05, first_group_value)?;
let second_group_value = self.compute_channel_group_value(
CHANNELS_PER_REGISTER,
CHANNELS_PER_IC,
CHANNELS_PER_REGISTER,
);
self.write_register(WriteRegister::ChannelEnable06To11, second_group_value)?;
Ok(())
}
pub fn set_channel_calibration(&mut self, ch: usize, calibration: u8) -> OperationResult {
if ch >= self.channel_enable.len() {
return Err(Error::InvalidChannel);
}
self.check_initialized()?;
let register =
WriteRegister::try_from(WriteRegister::ChannelCalibration00 as u8 + ch as u8).unwrap();
self.write_register(register, calibration)?;
Ok(())
}
pub fn set_all_channel_calibration(&mut self, calibration: &[u8; CHANNELS_PER_IC]) -> OperationResult {
self.check_initialized()?;
for ch in 0..CHANNELS_PER_IC {
let register =
WriteRegister::try_from(WriteRegister::ChannelCalibration00 as u8 + ch as u8)
.unwrap();
self.write_register(register, calibration[ch])?;
}
Ok(())
}
fn compute_channel_group_value(&self, start: usize, end: usize, offset: usize) -> u8 {
let mut group_value = 0u8;
for ch in start..end {
if self.channel_enable[ch] {
group_value |= 1 << (ch - offset);
}
}
group_value
}
fn write_register(&mut self, register: WriteRegister, value: u8) -> Result<[u8; 2], Error> {
let mut data = [register as u8, value];
let result = self.spi.transfer_in_place(&mut data);
if result.is_ok() {
Ok(data)
} else {
Err(Error::SpiError)
}
}
fn reset_status_register(&mut self) -> OperationResult {
let _ = self.write_register(WriteRegister::StatusReset, 0b0011_1111u8)?;
Ok(())
}
fn check_initialized(&self) -> OperationResult {
if !self.is_initialized {
return Err(Error::NotInitialized);
}
Ok(())
}
fn _lock_register(&mut self) -> Result<(), ()> {
Ok(())
}
const fn get_init_sequence() -> [(WriteRegister, u8); 15] {
[
(WriteRegister::SoftwareReset, 0b1010_0001u8),
(WriteRegister::SoftwareReset, 0b1010_0001u8),
(WriteRegister::ReservedB5, 0b1001_1110u8),
(WriteRegister::ReservedB6, 0b0000_0000u8),
(WriteRegister::ReservedB5, 0b1001_1110u8),
(WriteRegister::ReservedB7, 0b0000_0000u8),
(WriteRegister::ReservedB5, 0b1001_1110u8),
(WriteRegister::ReservedB8, 0b0000_0000u8),
(WriteRegister::ReservedB5, 0b1001_1110u8),
(WriteRegister::ReservedB9, 0b0000_0000u8),
(WriteRegister::Reserved79, 0b1101_0110u8),
(WriteRegister::Reserved7A, 0b0000_0000u8),
(WriteRegister::Reserved79, 0b1101_0110u8),
(WriteRegister::Reserved7B, 0b0000_0000u8),
(WriteRegister::SoftwareReset, 0b1010_0001u8),
]
}
}