use core::ops::{Deref, DerefMut}; use byteorder::{BigEndian, ByteOrder}; use bit_field::BitField; use super::*; pub trait Register { type Data: RegisterData; fn address(&self) -> u8; } pub trait RegisterData: Clone + Deref + DerefMut { fn empty() -> Self; } macro_rules! def_reg { ($Reg: ident, $reg: ident, $addr: expr, $size: expr) => { /// AD7172 register pub struct $Reg; impl Register for $Reg { /// Register contents type Data = $reg::Data; /// Register address fn address(&self) -> u8 { $addr } } mod $reg { /// Register contents #[derive(Clone)] pub struct Data(pub [u8; $size]); impl super::RegisterData for Data { /// Generate zeroed register contents fn empty() -> Self { Data([0; $size]) } } impl core::ops::Deref for Data { type Target = [u8]; fn deref(&self) -> &[u8] { &self.0 } } impl core::ops::DerefMut for Data { fn deref_mut(&mut self) -> &mut [u8] { &mut self.0 } } } }; ($Reg: ident, u8, $reg: ident, $addr: expr, $size: expr) => { pub struct $Reg { pub index: u8, } impl Register for $Reg { type Data = $reg::Data; fn address(&self) -> u8 { $addr + self.index } } mod $reg { #[derive(Clone)] pub struct Data(pub [u8; $size]); impl super::RegisterData for Data { fn empty() -> Self { Data([0; $size]) } } impl core::ops::Deref for Data { type Target = [u8]; fn deref(&self) -> &[u8] { &self.0 } } impl core::ops::DerefMut for Data { fn deref_mut(&mut self) -> &mut [u8] { &mut self.0 } } } } } macro_rules! reg_bit { ($getter: ident, $byte: expr, $bit: expr, $doc: expr) => { #[allow(unused)] #[doc = $doc] pub fn $getter(&self) -> bool { self.0[$byte].get_bit($bit) } }; ($getter: ident, $setter: ident, $byte: expr, $bit: expr, $doc: expr) => { #[allow(unused)] #[doc = $doc] pub fn $getter(&self) -> bool { self.0[$byte].get_bit($bit) } #[allow(unused)] #[doc = $doc] pub fn $setter(&mut self, value: bool) { self.0[$byte].set_bit($bit, value); } }; } macro_rules! reg_bits { ($getter: ident, $byte: expr, $bits: expr, $doc: expr) => { #[allow(unused)] #[doc = $doc] pub fn $getter(&self) -> u8 { self.0[$byte].get_bits($bits) } }; ($getter: ident, $setter: ident, $byte: expr, $bits: expr, $doc: expr) => { #[allow(unused)] #[doc = $doc] pub fn $getter(&self) -> u8 { self.0[$byte].get_bits($bits) } #[allow(unused)] #[doc = $doc] pub fn $setter(&mut self, value: u8) { self.0[$byte].set_bits($bits, value); } }; ($getter: ident, $byte: expr, $bits: expr, $ty: ty, $doc: expr) => { #[allow(unused)] #[doc = $doc] pub fn $getter(&self) -> $ty { self.0[$byte].get_bits($bits) as $ty } }; ($getter: ident, $setter: ident, $byte: expr, $bits: expr, $ty: ty, $doc: expr) => { #[allow(unused)] #[doc = $doc] pub fn $getter(&self) -> $ty { self.0[$byte].get_bits($bits).into() } #[allow(unused)] #[doc = $doc] pub fn $setter(&mut self, value: $ty) { self.0[$byte].set_bits($bits, value as u8); } }; } def_reg!(Status, status, 0x00, 1); impl status::Data { /// Is there new data to read? pub fn ready(&self) -> bool { ! self.not_ready() } reg_bit!(not_ready, 0, 7, "No data ready indicator"); reg_bits!(channel, 0, 0..=1, "Channel for which data is ready"); reg_bit!(adc_error, 0, 6, "ADC error"); reg_bit!(crc_error, 0, 5, "SPI CRC error"); reg_bit!(reg_error, 0, 4, "Register error"); } def_reg!(AdcMode, adc_mode, 0x01, 2); impl adc_mode::Data { reg_bits!(delay, set_delay, 0, 0..=2, "Delay after channel switch"); reg_bit!(sing_cyc, set_sing_cyc, 0, 5, "Can only used with single channel"); reg_bit!(hide_delay, set_hide_delay, 0, 6, "Hide delay"); reg_bit!(ref_en, set_ref_en, 0, 7, "Enable internal reference, output buffered 2.5 V to REFOUT"); reg_bits!(clockset, set_clocksel, 1, 2..=3, "Clock source"); reg_bits!(mode, set_mode, 1, 4..=6, Mode, "Operating mode"); } def_reg!(IfMode, if_mode, 0x02, 2); impl if_mode::Data { reg_bits!(crc, set_crc, 1, 2..=3, ChecksumMode, "SPI checksum mode"); } def_reg!(Data, data, 0x04, 3); impl data::Data { pub fn data(&self) -> u32 { (u32::from(self.0[0]) << 16) | (u32::from(self.0[1]) << 8) | u32::from(self.0[2]) } } def_reg!(GpioCon, gpio_con, 0x06, 2); impl gpio_con::Data { reg_bit!(sync_en, set_sync_en, 0, 3, "Enables the SYNC/ERROR pin as a sync input"); } def_reg!(Id, id, 0x07, 2); impl id::Data { pub fn id(&self) -> u16 { BigEndian::read_u16(&self.0) } } def_reg!(Channel, u8, channel, 0x10, 2); impl channel::Data { reg_bit!(enabled, set_enabled, 0, 7, "Channel enabled"); reg_bits!(setup, set_setup, 0, 4..=5, "Setup number"); /// Which input is connected to positive input of this channel #[allow(unused)] pub fn a_in_pos(&self) -> Input { ((self.0[0].get_bits(0..=1) << 3) | self.0[1].get_bits(5..=7)).into() } /// Set which input is connected to positive input of this channel #[allow(unused)] pub fn set_a_in_pos(&mut self, value: Input) { let value = value as u8; self.0[0].set_bits(0..=1, value >> 3); self.0[1].set_bits(5..=7, value & 0x7); } reg_bits!(a_in_neg, set_a_in_neg, 1, 0..=4, Input, "Which input is connected to negative input of this channel"); } def_reg!(SetupCon, u8, setup_con, 0x20, 2); impl setup_con::Data { reg_bit!(bipolar, set_bipolar, 0, 4, "Unipolar (`false`) or bipolar (`true`) coded output"); reg_bit!(refbuf_pos, set_refbuf_pos, 0, 3, "Enable REF+ input buffer"); reg_bit!(refbuf_neg, set_refbuf_neg, 0, 2, "Enable REF- input buffer"); reg_bit!(ainbuf_pos, set_ainbuf_pos, 0, 1, "Enable AIN+ input buffer"); reg_bit!(ainbuf_neg, set_ainbuf_neg, 0, 0, "Enable AIN- input buffer"); reg_bit!(burnout_en, 1, 7, "enables a 10 µA current source on the positive analog input selected and a 10 µA current sink on the negative analog input selected"); reg_bits!(ref_sel, set_ref_sel, 1, 4..=5, RefSource, "Select reference source for conversion"); } def_reg!(FiltCon, u8, filt_con, 0x28, 2); impl filt_con::Data { reg_bit!(sinc3_map, 0, 7, "If set, mapping of filter register changes to directly program the decimation rate of the sinc3 filter"); reg_bit!(enh_filt_en, set_enh_filt_en, 0, 3, "Enable postfilters for enhanced 50Hz and 60Hz rejection"); reg_bits!(enh_filt, set_enh_filt, 0, 0..=2, PostFilter, "Select postfilters for enhanced 50Hz and 60Hz rejection"); reg_bits!(order, set_order, 1, 5..=6, DigitalFilterOrder, "order of the digital filter that processes the modulator data"); reg_bits!(odr, set_odr, 1, 0..=4, "Output data rate"); } def_reg!(Offset, u8, offset, 0x30, 3); impl offset::Data { #[allow(unused)] pub fn offset(&self) -> u32 { (u32::from(self.0[0]) << 16) | (u32::from(self.0[1]) << 8) | u32::from(self.0[2]) } #[allow(unused)] pub fn set_offset(&mut self, value: u32) { self.0[0] = (value >> 16) as u8; self.0[1] = (value >> 8) as u8; self.0[2] = value as u8; } } def_reg!(Gain, u8, gain, 0x38, 3); impl gain::Data { #[allow(unused)] pub fn gain(&self) -> u32 { (u32::from(self.0[0]) << 16) | (u32::from(self.0[1]) << 8) | u32::from(self.0[2]) } #[allow(unused)] pub fn set_gain(&mut self, value: u32) { self.0[0] = (value >> 16) as u8; self.0[1] = (value >> 8) as u8; self.0[2] = value as u8; } }