From 3e3a790d9f70bfd6cb4210dfe09560d0385fdf5a Mon Sep 17 00:00:00 2001 From: Diego Barrios Romero Date: Sun, 11 Nov 2018 08:04:42 +0100 Subject: Reorganize modules --- src/channels.rs | 86 ++++++++++++++++++++++++++++++++++ src/construction/i2c.rs | 45 ++++++++++++++++++ src/construction/mod.rs | 3 ++ src/devices/ads1x1x/common.rs | 36 -------------- src/devices/ads1x1x/features/mod.rs | 5 -- src/devices/ads1x1x/features/tier1.rs | 83 -------------------------------- src/devices/ads1x1x/features/tier2.rs | 48 ------------------- src/devices/ads1x1x/mod.rs | 10 ---- src/devices/ads1x1x/mode/continuous.rs | 23 --------- src/devices/ads1x1x/mode/mod.rs | 47 ------------------- src/devices/ads1x1x/mode/oneshot.rs | 66 -------------------------- src/devices/channels.rs | 86 ---------------------------------- src/devices/common.rs | 36 ++++++++++++++ src/devices/construction/i2c.rs | 45 ------------------ src/devices/construction/mod.rs | 3 -- src/devices/features/mod.rs | 5 ++ src/devices/features/tier1.rs | 83 ++++++++++++++++++++++++++++++++ src/devices/features/tier2.rs | 48 +++++++++++++++++++ src/devices/ic.rs | 42 ----------------- src/devices/mod.rs | 16 ++++--- src/devices/mode/continuous.rs | 23 +++++++++ src/devices/mode/mod.rs | 47 +++++++++++++++++++ src/devices/mode/oneshot.rs | 66 ++++++++++++++++++++++++++ src/ic.rs | 42 +++++++++++++++++ src/lib.rs | 9 ++-- 25 files changed, 500 insertions(+), 503 deletions(-) create mode 100644 src/channels.rs create mode 100644 src/construction/i2c.rs create mode 100644 src/construction/mod.rs delete mode 100644 src/devices/ads1x1x/common.rs delete mode 100644 src/devices/ads1x1x/features/mod.rs delete mode 100644 src/devices/ads1x1x/features/tier1.rs delete mode 100644 src/devices/ads1x1x/features/tier2.rs delete mode 100644 src/devices/ads1x1x/mod.rs delete mode 100644 src/devices/ads1x1x/mode/continuous.rs delete mode 100644 src/devices/ads1x1x/mode/mod.rs delete mode 100644 src/devices/ads1x1x/mode/oneshot.rs delete mode 100644 src/devices/channels.rs create mode 100644 src/devices/common.rs delete mode 100644 src/devices/construction/i2c.rs delete mode 100644 src/devices/construction/mod.rs create mode 100644 src/devices/features/mod.rs create mode 100644 src/devices/features/tier1.rs create mode 100644 src/devices/features/tier2.rs delete mode 100644 src/devices/ic.rs create mode 100644 src/devices/mode/continuous.rs create mode 100644 src/devices/mode/mod.rs create mode 100644 src/devices/mode/oneshot.rs create mode 100644 src/ic.rs (limited to 'src') diff --git a/src/channels.rs b/src/channels.rs new file mode 100644 index 0000000..c202ad3 --- /dev/null +++ b/src/channels.rs @@ -0,0 +1,86 @@ +//! ADC input channels +use { Ads1x1x, ic, hal, Config, BitFlags as BF }; + +/// ADC input channel selection +#[allow(dead_code)] +pub mod channel { + /// Measure single-ended signal on input channel 0 + pub struct SingleA0; + /// Measure single-ended signal on input channel 1 + pub struct SingleA1; + /// Measure single-ended signal on input channel 2 + pub struct SingleA2; + /// Measure single-ended signal on input channel 3 + pub struct SingleA3; + /// Measure signal on input channel 0 differentially to signal on input channel 1 + pub struct DifferentialA0A1; + /// Measure signal on input channel 0 differentially to signal on input channel 3 + pub struct DifferentialA0A3; + /// Measure signal on input channel 1 differentially to signal on input channel 3 + pub struct DifferentialA1A3; + /// Measure signal on input channel 3 differentially to signal on input channel 3 + pub struct DifferentialA2A3; +} + +pub enum ChannelSelection { + SingleA0, + SingleA1, + SingleA2, + SingleA3, + DifferentialA0A1, + DifferentialA0A3, + DifferentialA1A3, + DifferentialA2A3, +} + +macro_rules! impl_channel { + ( $IC:ident, $CH:ident ) => { + impl hal::adc::Channel> for channel::$CH { + type ID = ChannelSelection; + + fn channel() -> Self::ID { + ChannelSelection::$CH + } + } + } +} + +impl_channel!(Ads1013, DifferentialA0A1); +impl_channel!(Ads1113, DifferentialA0A1); + +impl_channel!(Ads1014, DifferentialA0A1); +impl_channel!(Ads1114, DifferentialA0A1); + +impl_channel!(Ads1015, DifferentialA0A1); +impl_channel!(Ads1015, DifferentialA0A3); +impl_channel!(Ads1015, DifferentialA1A3); +impl_channel!(Ads1015, DifferentialA2A3); +impl_channel!(Ads1015, SingleA0); +impl_channel!(Ads1015, SingleA1); +impl_channel!(Ads1015, SingleA2); +impl_channel!(Ads1015, SingleA3); + +impl_channel!(Ads1115, DifferentialA0A1); +impl_channel!(Ads1115, DifferentialA0A3); +impl_channel!(Ads1115, DifferentialA1A3); +impl_channel!(Ads1115, DifferentialA2A3); +impl_channel!(Ads1115, SingleA0); +impl_channel!(Ads1115, SingleA1); +impl_channel!(Ads1115, SingleA2); +impl_channel!(Ads1115, SingleA3); + +impl Config { + pub(crate) fn with_mux_bits(&self, ch: ChannelSelection) -> Self { + use self::ChannelSelection as CS; + match ch { + CS::DifferentialA0A1 => self.with_low( BF::MUX2).with_low( BF::MUX1).with_low( BF::MUX0), + CS::DifferentialA0A3 => self.with_low( BF::MUX2).with_low( BF::MUX1).with_high(BF::MUX0), + CS::DifferentialA1A3 => self.with_low( BF::MUX2).with_high(BF::MUX1).with_low( BF::MUX0), + CS::DifferentialA2A3 => self.with_low( BF::MUX2).with_high(BF::MUX1).with_high(BF::MUX0), + CS::SingleA0 => self.with_high(BF::MUX2).with_low( BF::MUX1).with_low( BF::MUX0), + CS::SingleA1 => self.with_high(BF::MUX2).with_low( BF::MUX1).with_high(BF::MUX0), + CS::SingleA2 => self.with_high(BF::MUX2).with_high(BF::MUX1).with_low( BF::MUX0), + CS::SingleA3 => self.with_high(BF::MUX2).with_high(BF::MUX1).with_high(BF::MUX0), + } + } +} diff --git a/src/construction/i2c.rs b/src/construction/i2c.rs new file mode 100644 index 0000000..9ef18eb --- /dev/null +++ b/src/construction/i2c.rs @@ -0,0 +1,45 @@ +//! Constructor/destructor functions for devices using I2C interface. + +extern crate embedded_hal as hal; +use hal::blocking; +use core::marker::PhantomData; +use { Ads1x1x, DEVICE_BASE_ADDRESS, SlaveAddr, ic, Config, mode }; +use interface::I2cInterface; + + +macro_rules! impl_new_destroy { + ( $IC:ident, $create:ident, $destroy:ident ) => { + impl Ads1x1x, ic::$IC, mode::OneShot> + where + I2C: blocking::i2c::Write + blocking::i2c::WriteRead + { + /// Create a new instance of the device in OneShot mode. + pub fn $create(i2c: I2C, address: SlaveAddr) -> Self { + Ads1x1x { + iface: I2cInterface { + i2c, + address: address.addr(DEVICE_BASE_ADDRESS) + }, + config: Config::default(), + a_conversion_was_started: false, + _ic: PhantomData, + _mode: PhantomData + } + } + } + impl Ads1x1x, ic::$IC, MODE> + { + /// Destroy driver instance, return I²C bus instance. + pub fn $destroy(self) -> I2C { + self.iface.i2c + } + } + } +} + +impl_new_destroy!(Ads1013, new_ads1013, destroy_ads1013); +impl_new_destroy!(Ads1113, new_ads1113, destroy_ads1113); +impl_new_destroy!(Ads1014, new_ads1014, destroy_ads1014); +impl_new_destroy!(Ads1114, new_ads1114, destroy_ads1114); +impl_new_destroy!(Ads1015, new_ads1015, destroy_ads1015); +impl_new_destroy!(Ads1115, new_ads1115, destroy_ads1115); diff --git a/src/construction/mod.rs b/src/construction/mod.rs new file mode 100644 index 0000000..0873d88 --- /dev/null +++ b/src/construction/mod.rs @@ -0,0 +1,3 @@ +//! Construction / destruction functions + +mod i2c; diff --git a/src/devices/ads1x1x/common.rs b/src/devices/ads1x1x/common.rs deleted file mode 100644 index 5abb99c..0000000 --- a/src/devices/ads1x1x/common.rs +++ /dev/null @@ -1,36 +0,0 @@ -//! Common functions - -use { Ads1x1x, Error, Register, BitFlags, interface, Config, ic }; -use super::OperatingMode; - -impl Ads1x1x -where - DI: interface::WriteData, - IC: ic::Resolution -{ - pub(super) fn set_operating_mode(&mut self, mode: OperatingMode) -> Result<(), Error> { - let config; - match mode { - OperatingMode::OneShot => config = self.config.with_high(BitFlags::OP_MODE), - OperatingMode::Continuous => config = self.config.with_low(BitFlags::OP_MODE), - } - self.iface.write_register(Register::CONFIG, config.bits)?; - self.config = config; - Ok(()) - } - - /// Reset the internal state of this driver to the default values. - /// - /// *Note:* This does not alter the state or configuration of the device. - /// - /// This resets the cached configuration register value in this driver to - /// the power-up (reset) configuration of the device. - /// - /// This needs to be called after performing a reset on the device, for - /// example through an I2C general-call Reset command, which was not done - /// through this driver to ensure that the configurations in the device - /// and in the driver match. - pub fn reset_internal_driver_state(&mut self) { - self.config = Config::default(); - } -} diff --git a/src/devices/ads1x1x/features/mod.rs b/src/devices/ads1x1x/features/mod.rs deleted file mode 100644 index c24b7b4..0000000 --- a/src/devices/ads1x1x/features/mod.rs +++ /dev/null @@ -1,5 +0,0 @@ -//! Implementation of IC features separated in tiers depending on the hardware -//! support. - -mod tier1; -mod tier2; diff --git a/src/devices/ads1x1x/features/tier1.rs b/src/devices/ads1x1x/features/tier1.rs deleted file mode 100644 index 9f72b77..0000000 --- a/src/devices/ads1x1x/features/tier1.rs +++ /dev/null @@ -1,83 +0,0 @@ -//! Common functions - -use { Ads1x1x, DataRate, Error, Register, BitFlags, interface, ic }; - -impl Ads1x1x -where - DI: interface::WriteData, - IC: ic::Resolution -{ - /// Set data rate - pub fn set_data_rate(&mut self, rate: DataRate) -> Result<(), Error> { - let config; - match rate { - DataRate::Sps128 => config = self.config.with_low( BitFlags::DR2).with_low( BitFlags::DR1).with_low( BitFlags::DR0), - DataRate::Sps250 => config = self.config.with_low( BitFlags::DR2).with_low( BitFlags::DR1).with_high(BitFlags::DR0), - DataRate::Sps490 => config = self.config.with_low( BitFlags::DR2).with_high(BitFlags::DR1).with_low( BitFlags::DR0), - DataRate::Sps920 => config = self.config.with_low( BitFlags::DR2).with_high(BitFlags::DR1).with_high(BitFlags::DR0), - DataRate::Sps1600 => config = self.config.with_high(BitFlags::DR2).with_low( BitFlags::DR1).with_low( BitFlags::DR0), - DataRate::Sps2400 => config = self.config.with_high(BitFlags::DR2).with_low( BitFlags::DR1).with_high(BitFlags::DR0), - DataRate::Sps3300 => config = self.config.with_high(BitFlags::DR2).with_high(BitFlags::DR1).with_low( BitFlags::DR0), - } - self.iface.write_register(Register::CONFIG, config.bits)?; - self.config = config; - Ok(()) - } - - /// Set comparator lower threshold - pub fn set_low_threshold(&mut self, value: i16) -> Result<(), Error> { - let register_value = convert_threshold::(value)?; - self.iface.write_register(Register::LOW_TH, register_value) - } - - /// Set comparator upper threshold - pub fn set_high_threshold(&mut self, value: i16) -> Result<(), Error> { - let register_value = convert_threshold::(value)?; - self.iface.write_register(Register::HIGH_TH, register_value) - } -} - -fn convert_threshold(value: i16) -> Result> -where - IC: ic::Resolution -{ - if IC::BITS == ic::ResolutionBits::_12 { - if value < -2048 || value > 2047 { - return Err(Error::InvalidInputData); - } - Ok((value << 4) as u16) - } - else { - Ok(value as u16) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - fn assert_invalid_input_data(result: Result>) { - match result { - Err(Error::InvalidInputData) => (), - _ => panic!("InvalidInputData error was not returned.") - } - } - - #[test] - fn convert_12_bits() { - assert_invalid_input_data(convert_threshold::(2048)); - assert_invalid_input_data(convert_threshold::(-2049)); - - assert_eq!( 0, convert_threshold::(0).unwrap()); - assert_eq!(0x7FF0, convert_threshold::(2047).unwrap()); - assert_eq!(0x8000, convert_threshold::(-2048).unwrap()); - assert_eq!(0xFFF0, convert_threshold::(-1).unwrap()); - } - - #[test] - fn convert_16_bits() { - assert_eq!(0x7FFF, convert_threshold::(32767).unwrap()); - assert_eq!(0x8000, convert_threshold::(-32768).unwrap()); - } -} - diff --git a/src/devices/ads1x1x/features/tier2.rs b/src/devices/ads1x1x/features/tier2.rs deleted file mode 100644 index 43dce5c..0000000 --- a/src/devices/ads1x1x/features/tier2.rs +++ /dev/null @@ -1,48 +0,0 @@ -//! Tier 2 features. -//! -//! These are the features included only in ADS1x14, ADS1x15 - -use { Ads1x1x, Error, interface, ic, ComparatorMode, ComparatorPolarity, - ComparatorLatching, Register, BitFlags }; - -impl Ads1x1x -where - DI: interface::WriteData, - IC: ic::Resolution + ic::Tier2Features -{ - /// Set comparator mode - pub fn set_comparator_mode(&mut self, mode: ComparatorMode) -> Result<(), Error> { - let config; - match mode { - ComparatorMode::Traditional => config = self.config.with_low(BitFlags::COMP_MODE), - ComparatorMode::Window => config = self.config.with_high(BitFlags::COMP_MODE) - } - self.iface.write_register(Register::CONFIG, config.bits)?; - self.config = config; - Ok(()) - } - - /// Set comparator polarity - pub fn set_comparator_polarity(&mut self, polarity: ComparatorPolarity) -> Result<(), Error> { - let config; - match polarity { - ComparatorPolarity::ActiveLow => config = self.config.with_low( BitFlags::COMP_POL), - ComparatorPolarity::ActiveHigh => config = self.config.with_high(BitFlags::COMP_POL) - } - self.iface.write_register(Register::CONFIG, config.bits)?; - self.config = config; - Ok(()) - } - - /// Set comparator latching - pub fn set_comparator_latching(&mut self, latching: ComparatorLatching) -> Result<(), Error> { - let config; - match latching { - ComparatorLatching::Nonlatching => config = self.config.with_low( BitFlags::COMP_LAT), - ComparatorLatching::Latching => config = self.config.with_high(BitFlags::COMP_LAT) - } - self.iface.write_register(Register::CONFIG, config.bits)?; - self.config = config; - Ok(()) - } -} diff --git a/src/devices/ads1x1x/mod.rs b/src/devices/ads1x1x/mod.rs deleted file mode 100644 index 95d8907..0000000 --- a/src/devices/ads1x1x/mod.rs +++ /dev/null @@ -1,10 +0,0 @@ -//! Functions for all devices - -enum OperatingMode { - OneShot, - Continuous -} - -mod common; -mod mode; -mod features; diff --git a/src/devices/ads1x1x/mode/continuous.rs b/src/devices/ads1x1x/mode/continuous.rs deleted file mode 100644 index 1472478..0000000 --- a/src/devices/ads1x1x/mode/continuous.rs +++ /dev/null @@ -1,23 +0,0 @@ -//! Common functions - -use core::marker::PhantomData; -use { Ads1x1x, mode, Error, interface, ic }; -use super::super::OperatingMode; - -impl Ads1x1x -where - DI: interface::WriteData, - IC: ic::Resolution -{ - /// Change operating mode to OneShot - pub fn into_one_shot(mut self) -> Result, Error> { - self.set_operating_mode(OperatingMode::OneShot)?; - Ok(Ads1x1x { - iface: self.iface, - config: self.config, - a_conversion_was_started: self.a_conversion_was_started, - _ic: PhantomData, - _mode: PhantomData - }) - } -} diff --git a/src/devices/ads1x1x/mode/mod.rs b/src/devices/ads1x1x/mode/mod.rs deleted file mode 100644 index 8e0e012..0000000 --- a/src/devices/ads1x1x/mode/mod.rs +++ /dev/null @@ -1,47 +0,0 @@ -//! Functions for all devices specific to each operating mode - -use ic; -mod oneshot; -mod continuous; - -fn convert_measurement(register_data: u16) -> i16 -where - IC: ic::Resolution -{ - let value = register_data; - if IC::BITS == ic::ResolutionBits::_12 { - let is_negative = (value & 0b1000_0000_0000_0000) != 0; - if is_negative { - let value = 0b1111_0000_0000_0000 | (value >> 4); - value as i16 - } - else { - (value >> 4) as i16 - } - } - else { - value as i16 - } -} - - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn convert_12_bits() { - assert_eq!( 0, convert_measurement::(0)); - assert_eq!( 2047, convert_measurement::(0x7FFF)); - assert_eq!(-2048, convert_measurement::(0x8000)); - assert_eq!( -1, convert_measurement::(0xFFFF)); - } - - #[test] - fn convert_16_bits() { - assert_eq!( 0, convert_measurement::(0)); - assert_eq!( 32767, convert_measurement::(0x7FFF)); - assert_eq!(-32768, convert_measurement::(0x8000)); - assert_eq!( -1, convert_measurement::(0xFFFF)); - } -} diff --git a/src/devices/ads1x1x/mode/oneshot.rs b/src/devices/ads1x1x/mode/oneshot.rs deleted file mode 100644 index 7ff9ac9..0000000 --- a/src/devices/ads1x1x/mode/oneshot.rs +++ /dev/null @@ -1,66 +0,0 @@ -//! Common functions - -use core::marker::PhantomData; -use { Ads1x1x, mode, Error, Register, BitFlags, Config, ic }; -use { interface, hal, nb }; -use devices::ads1x1x::OperatingMode; -use devices::channels::ChannelSelection; -use super::convert_measurement; - -impl Ads1x1x -where - DI: interface::WriteData + interface::ReadData, - IC: ic::Resolution -{ - /// Change operating mode to Continuous - pub fn into_continuous(mut self) -> Result, Error> { - self.set_operating_mode(OperatingMode::Continuous)?; - Ok(Ads1x1x { - iface: self.iface, - config: self.config, - a_conversion_was_started: self.a_conversion_was_started, - _ic: PhantomData, - _mode: PhantomData - }) - } - - fn is_measurement_in_progress(&mut self) -> Result> { - let config = Config { - bits: self.iface.read_register(Register::CONFIG)? - }; - Ok(!config.is_high(BitFlags::OS)) - } - - fn trigger_measurement(&mut self, config: &Config) -> Result<(), Error> { - let config = config.with_high(BitFlags::OS); - self.iface.write_register(Register::CONFIG, config.bits) - } -} - -impl hal::adc::OneShot, i16, CH> for Ads1x1x -where - DI: interface::ReadData + interface::WriteData, - IC: ic::Resolution, - CH: hal::adc::Channel, ID = ChannelSelection> -{ - type Error = Error; - - /// Request that the ADC begin a conversion on the specified channel - fn read(&mut self, _channel: &mut CH) -> nb::Result { - //TODO for devices with MUX select channel, if it is the wrong one, return AlreadyInProgress or WrongChannel error - if self.is_measurement_in_progress().map_err(nb::Error::Other)? { - return Err(nb::Error::WouldBlock); - } - if self.a_conversion_was_started { - // result is ready - let value = self.iface.read_register(Register::CONVERSION).map_err(nb::Error::Other)?; - self.a_conversion_was_started = false; - return Ok(convert_measurement::(value)); - } - let config = self.config.with_mux_bits(CH::channel()); - self.trigger_measurement(&config).map_err(nb::Error::Other)?; - self.config = config; - self.a_conversion_was_started = true; - Err(nb::Error::WouldBlock) - } -} diff --git a/src/devices/channels.rs b/src/devices/channels.rs deleted file mode 100644 index c202ad3..0000000 --- a/src/devices/channels.rs +++ /dev/null @@ -1,86 +0,0 @@ -//! ADC input channels -use { Ads1x1x, ic, hal, Config, BitFlags as BF }; - -/// ADC input channel selection -#[allow(dead_code)] -pub mod channel { - /// Measure single-ended signal on input channel 0 - pub struct SingleA0; - /// Measure single-ended signal on input channel 1 - pub struct SingleA1; - /// Measure single-ended signal on input channel 2 - pub struct SingleA2; - /// Measure single-ended signal on input channel 3 - pub struct SingleA3; - /// Measure signal on input channel 0 differentially to signal on input channel 1 - pub struct DifferentialA0A1; - /// Measure signal on input channel 0 differentially to signal on input channel 3 - pub struct DifferentialA0A3; - /// Measure signal on input channel 1 differentially to signal on input channel 3 - pub struct DifferentialA1A3; - /// Measure signal on input channel 3 differentially to signal on input channel 3 - pub struct DifferentialA2A3; -} - -pub enum ChannelSelection { - SingleA0, - SingleA1, - SingleA2, - SingleA3, - DifferentialA0A1, - DifferentialA0A3, - DifferentialA1A3, - DifferentialA2A3, -} - -macro_rules! impl_channel { - ( $IC:ident, $CH:ident ) => { - impl hal::adc::Channel> for channel::$CH { - type ID = ChannelSelection; - - fn channel() -> Self::ID { - ChannelSelection::$CH - } - } - } -} - -impl_channel!(Ads1013, DifferentialA0A1); -impl_channel!(Ads1113, DifferentialA0A1); - -impl_channel!(Ads1014, DifferentialA0A1); -impl_channel!(Ads1114, DifferentialA0A1); - -impl_channel!(Ads1015, DifferentialA0A1); -impl_channel!(Ads1015, DifferentialA0A3); -impl_channel!(Ads1015, DifferentialA1A3); -impl_channel!(Ads1015, DifferentialA2A3); -impl_channel!(Ads1015, SingleA0); -impl_channel!(Ads1015, SingleA1); -impl_channel!(Ads1015, SingleA2); -impl_channel!(Ads1015, SingleA3); - -impl_channel!(Ads1115, DifferentialA0A1); -impl_channel!(Ads1115, DifferentialA0A3); -impl_channel!(Ads1115, DifferentialA1A3); -impl_channel!(Ads1115, DifferentialA2A3); -impl_channel!(Ads1115, SingleA0); -impl_channel!(Ads1115, SingleA1); -impl_channel!(Ads1115, SingleA2); -impl_channel!(Ads1115, SingleA3); - -impl Config { - pub(crate) fn with_mux_bits(&self, ch: ChannelSelection) -> Self { - use self::ChannelSelection as CS; - match ch { - CS::DifferentialA0A1 => self.with_low( BF::MUX2).with_low( BF::MUX1).with_low( BF::MUX0), - CS::DifferentialA0A3 => self.with_low( BF::MUX2).with_low( BF::MUX1).with_high(BF::MUX0), - CS::DifferentialA1A3 => self.with_low( BF::MUX2).with_high(BF::MUX1).with_low( BF::MUX0), - CS::DifferentialA2A3 => self.with_low( BF::MUX2).with_high(BF::MUX1).with_high(BF::MUX0), - CS::SingleA0 => self.with_high(BF::MUX2).with_low( BF::MUX1).with_low( BF::MUX0), - CS::SingleA1 => self.with_high(BF::MUX2).with_low( BF::MUX1).with_high(BF::MUX0), - CS::SingleA2 => self.with_high(BF::MUX2).with_high(BF::MUX1).with_low( BF::MUX0), - CS::SingleA3 => self.with_high(BF::MUX2).with_high(BF::MUX1).with_high(BF::MUX0), - } - } -} diff --git a/src/devices/common.rs b/src/devices/common.rs new file mode 100644 index 0000000..5abb99c --- /dev/null +++ b/src/devices/common.rs @@ -0,0 +1,36 @@ +//! Common functions + +use { Ads1x1x, Error, Register, BitFlags, interface, Config, ic }; +use super::OperatingMode; + +impl Ads1x1x +where + DI: interface::WriteData, + IC: ic::Resolution +{ + pub(super) fn set_operating_mode(&mut self, mode: OperatingMode) -> Result<(), Error> { + let config; + match mode { + OperatingMode::OneShot => config = self.config.with_high(BitFlags::OP_MODE), + OperatingMode::Continuous => config = self.config.with_low(BitFlags::OP_MODE), + } + self.iface.write_register(Register::CONFIG, config.bits)?; + self.config = config; + Ok(()) + } + + /// Reset the internal state of this driver to the default values. + /// + /// *Note:* This does not alter the state or configuration of the device. + /// + /// This resets the cached configuration register value in this driver to + /// the power-up (reset) configuration of the device. + /// + /// This needs to be called after performing a reset on the device, for + /// example through an I2C general-call Reset command, which was not done + /// through this driver to ensure that the configurations in the device + /// and in the driver match. + pub fn reset_internal_driver_state(&mut self) { + self.config = Config::default(); + } +} diff --git a/src/devices/construction/i2c.rs b/src/devices/construction/i2c.rs deleted file mode 100644 index 9ef18eb..0000000 --- a/src/devices/construction/i2c.rs +++ /dev/null @@ -1,45 +0,0 @@ -//! Constructor/destructor functions for devices using I2C interface. - -extern crate embedded_hal as hal; -use hal::blocking; -use core::marker::PhantomData; -use { Ads1x1x, DEVICE_BASE_ADDRESS, SlaveAddr, ic, Config, mode }; -use interface::I2cInterface; - - -macro_rules! impl_new_destroy { - ( $IC:ident, $create:ident, $destroy:ident ) => { - impl Ads1x1x, ic::$IC, mode::OneShot> - where - I2C: blocking::i2c::Write + blocking::i2c::WriteRead - { - /// Create a new instance of the device in OneShot mode. - pub fn $create(i2c: I2C, address: SlaveAddr) -> Self { - Ads1x1x { - iface: I2cInterface { - i2c, - address: address.addr(DEVICE_BASE_ADDRESS) - }, - config: Config::default(), - a_conversion_was_started: false, - _ic: PhantomData, - _mode: PhantomData - } - } - } - impl Ads1x1x, ic::$IC, MODE> - { - /// Destroy driver instance, return I²C bus instance. - pub fn $destroy(self) -> I2C { - self.iface.i2c - } - } - } -} - -impl_new_destroy!(Ads1013, new_ads1013, destroy_ads1013); -impl_new_destroy!(Ads1113, new_ads1113, destroy_ads1113); -impl_new_destroy!(Ads1014, new_ads1014, destroy_ads1014); -impl_new_destroy!(Ads1114, new_ads1114, destroy_ads1114); -impl_new_destroy!(Ads1015, new_ads1015, destroy_ads1015); -impl_new_destroy!(Ads1115, new_ads1115, destroy_ads1115); diff --git a/src/devices/construction/mod.rs b/src/devices/construction/mod.rs deleted file mode 100644 index 0873d88..0000000 --- a/src/devices/construction/mod.rs +++ /dev/null @@ -1,3 +0,0 @@ -//! Construction / destruction functions - -mod i2c; diff --git a/src/devices/features/mod.rs b/src/devices/features/mod.rs new file mode 100644 index 0000000..c24b7b4 --- /dev/null +++ b/src/devices/features/mod.rs @@ -0,0 +1,5 @@ +//! Implementation of IC features separated in tiers depending on the hardware +//! support. + +mod tier1; +mod tier2; diff --git a/src/devices/features/tier1.rs b/src/devices/features/tier1.rs new file mode 100644 index 0000000..9f72b77 --- /dev/null +++ b/src/devices/features/tier1.rs @@ -0,0 +1,83 @@ +//! Common functions + +use { Ads1x1x, DataRate, Error, Register, BitFlags, interface, ic }; + +impl Ads1x1x +where + DI: interface::WriteData, + IC: ic::Resolution +{ + /// Set data rate + pub fn set_data_rate(&mut self, rate: DataRate) -> Result<(), Error> { + let config; + match rate { + DataRate::Sps128 => config = self.config.with_low( BitFlags::DR2).with_low( BitFlags::DR1).with_low( BitFlags::DR0), + DataRate::Sps250 => config = self.config.with_low( BitFlags::DR2).with_low( BitFlags::DR1).with_high(BitFlags::DR0), + DataRate::Sps490 => config = self.config.with_low( BitFlags::DR2).with_high(BitFlags::DR1).with_low( BitFlags::DR0), + DataRate::Sps920 => config = self.config.with_low( BitFlags::DR2).with_high(BitFlags::DR1).with_high(BitFlags::DR0), + DataRate::Sps1600 => config = self.config.with_high(BitFlags::DR2).with_low( BitFlags::DR1).with_low( BitFlags::DR0), + DataRate::Sps2400 => config = self.config.with_high(BitFlags::DR2).with_low( BitFlags::DR1).with_high(BitFlags::DR0), + DataRate::Sps3300 => config = self.config.with_high(BitFlags::DR2).with_high(BitFlags::DR1).with_low( BitFlags::DR0), + } + self.iface.write_register(Register::CONFIG, config.bits)?; + self.config = config; + Ok(()) + } + + /// Set comparator lower threshold + pub fn set_low_threshold(&mut self, value: i16) -> Result<(), Error> { + let register_value = convert_threshold::(value)?; + self.iface.write_register(Register::LOW_TH, register_value) + } + + /// Set comparator upper threshold + pub fn set_high_threshold(&mut self, value: i16) -> Result<(), Error> { + let register_value = convert_threshold::(value)?; + self.iface.write_register(Register::HIGH_TH, register_value) + } +} + +fn convert_threshold(value: i16) -> Result> +where + IC: ic::Resolution +{ + if IC::BITS == ic::ResolutionBits::_12 { + if value < -2048 || value > 2047 { + return Err(Error::InvalidInputData); + } + Ok((value << 4) as u16) + } + else { + Ok(value as u16) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + fn assert_invalid_input_data(result: Result>) { + match result { + Err(Error::InvalidInputData) => (), + _ => panic!("InvalidInputData error was not returned.") + } + } + + #[test] + fn convert_12_bits() { + assert_invalid_input_data(convert_threshold::(2048)); + assert_invalid_input_data(convert_threshold::(-2049)); + + assert_eq!( 0, convert_threshold::(0).unwrap()); + assert_eq!(0x7FF0, convert_threshold::(2047).unwrap()); + assert_eq!(0x8000, convert_threshold::(-2048).unwrap()); + assert_eq!(0xFFF0, convert_threshold::(-1).unwrap()); + } + + #[test] + fn convert_16_bits() { + assert_eq!(0x7FFF, convert_threshold::(32767).unwrap()); + assert_eq!(0x8000, convert_threshold::(-32768).unwrap()); + } +} + diff --git a/src/devices/features/tier2.rs b/src/devices/features/tier2.rs new file mode 100644 index 0000000..43dce5c --- /dev/null +++ b/src/devices/features/tier2.rs @@ -0,0 +1,48 @@ +//! Tier 2 features. +//! +//! These are the features included only in ADS1x14, ADS1x15 + +use { Ads1x1x, Error, interface, ic, ComparatorMode, ComparatorPolarity, + ComparatorLatching, Register, BitFlags }; + +impl Ads1x1x +where + DI: interface::WriteData, + IC: ic::Resolution + ic::Tier2Features +{ + /// Set comparator mode + pub fn set_comparator_mode(&mut self, mode: ComparatorMode) -> Result<(), Error> { + let config; + match mode { + ComparatorMode::Traditional => config = self.config.with_low(BitFlags::COMP_MODE), + ComparatorMode::Window => config = self.config.with_high(BitFlags::COMP_MODE) + } + self.iface.write_register(Register::CONFIG, config.bits)?; + self.config = config; + Ok(()) + } + + /// Set comparator polarity + pub fn set_comparator_polarity(&mut self, polarity: ComparatorPolarity) -> Result<(), Error> { + let config; + match polarity { + ComparatorPolarity::ActiveLow => config = self.config.with_low( BitFlags::COMP_POL), + ComparatorPolarity::ActiveHigh => config = self.config.with_high(BitFlags::COMP_POL) + } + self.iface.write_register(Register::CONFIG, config.bits)?; + self.config = config; + Ok(()) + } + + /// Set comparator latching + pub fn set_comparator_latching(&mut self, latching: ComparatorLatching) -> Result<(), Error> { + let config; + match latching { + ComparatorLatching::Nonlatching => config = self.config.with_low( BitFlags::COMP_LAT), + ComparatorLatching::Latching => config = self.config.with_high(BitFlags::COMP_LAT) + } + self.iface.write_register(Register::CONFIG, config.bits)?; + self.config = config; + Ok(()) + } +} diff --git a/src/devices/ic.rs b/src/devices/ic.rs deleted file mode 100644 index 7b30f85..0000000 --- a/src/devices/ic.rs +++ /dev/null @@ -1,42 +0,0 @@ -/// ICs -use private; - -#[derive(PartialEq)] -pub enum ResolutionBits { - _12, - _16 -} - -pub trait Resolution : private::Sealed { - const BITS : ResolutionBits; -} - -macro_rules! ic_marker { - ($name:ident, $resolution:ident) => { - /// IC marker - pub struct $name(()); - impl Resolution for $name { - const BITS: ResolutionBits = ResolutionBits::$resolution; - } - }; -} - -ic_marker!(Ads1013, _12); -ic_marker!(Ads1113, _16); -ic_marker!(Ads1014, _12); -ic_marker!(Ads1114, _16); -ic_marker!(Ads1015, _12); -ic_marker!(Ads1115, _16); - -pub trait Tier2Features : private::Sealed { } - -macro_rules! tier2_features { - ($name:ident) => { - impl Tier2Features for $name {} - } -} - -tier2_features!(Ads1014); -tier2_features!(Ads1114); -tier2_features!(Ads1015); -tier2_features!(Ads1115); diff --git a/src/devices/mod.rs b/src/devices/mod.rs index c73d344..95d8907 100644 --- a/src/devices/mod.rs +++ b/src/devices/mod.rs @@ -1,6 +1,10 @@ -#[doc(hidden)] -pub mod ic; -mod ads1x1x; -mod construction; -mod channels; -pub use self::channels::channel; +//! Functions for all devices + +enum OperatingMode { + OneShot, + Continuous +} + +mod common; +mod mode; +mod features; diff --git a/src/devices/mode/continuous.rs b/src/devices/mode/continuous.rs new file mode 100644 index 0000000..1472478 --- /dev/null +++ b/src/devices/mode/continuous.rs @@ -0,0 +1,23 @@ +//! Common functions + +use core::marker::PhantomData; +use { Ads1x1x, mode, Error, interface, ic }; +use super::super::OperatingMode; + +impl Ads1x1x +where + DI: interface::WriteData, + IC: ic::Resolution +{ + /// Change operating mode to OneShot + pub fn into_one_shot(mut self) -> Result, Error> { + self.set_operating_mode(OperatingMode::OneShot)?; + Ok(Ads1x1x { + iface: self.iface, + config: self.config, + a_conversion_was_started: self.a_conversion_was_started, + _ic: PhantomData, + _mode: PhantomData + }) + } +} diff --git a/src/devices/mode/mod.rs b/src/devices/mode/mod.rs new file mode 100644 index 0000000..8e0e012 --- /dev/null +++ b/src/devices/mode/mod.rs @@ -0,0 +1,47 @@ +//! Functions for all devices specific to each operating mode + +use ic; +mod oneshot; +mod continuous; + +fn convert_measurement(register_data: u16) -> i16 +where + IC: ic::Resolution +{ + let value = register_data; + if IC::BITS == ic::ResolutionBits::_12 { + let is_negative = (value & 0b1000_0000_0000_0000) != 0; + if is_negative { + let value = 0b1111_0000_0000_0000 | (value >> 4); + value as i16 + } + else { + (value >> 4) as i16 + } + } + else { + value as i16 + } +} + + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn convert_12_bits() { + assert_eq!( 0, convert_measurement::(0)); + assert_eq!( 2047, convert_measurement::(0x7FFF)); + assert_eq!(-2048, convert_measurement::(0x8000)); + assert_eq!( -1, convert_measurement::(0xFFFF)); + } + + #[test] + fn convert_16_bits() { + assert_eq!( 0, convert_measurement::(0)); + assert_eq!( 32767, convert_measurement::(0x7FFF)); + assert_eq!(-32768, convert_measurement::(0x8000)); + assert_eq!( -1, convert_measurement::(0xFFFF)); + } +} diff --git a/src/devices/mode/oneshot.rs b/src/devices/mode/oneshot.rs new file mode 100644 index 0000000..30958ab --- /dev/null +++ b/src/devices/mode/oneshot.rs @@ -0,0 +1,66 @@ +//! Common functions + +use core::marker::PhantomData; +use { Ads1x1x, mode, Error, Register, BitFlags, Config, ic }; +use { interface, hal, nb }; +use devices::OperatingMode; +use channels::ChannelSelection; +use super::convert_measurement; + +impl Ads1x1x +where + DI: interface::WriteData + interface::ReadData, + IC: ic::Resolution +{ + /// Change operating mode to Continuous + pub fn into_continuous(mut self) -> Result, Error> { + self.set_operating_mode(OperatingMode::Continuous)?; + Ok(Ads1x1x { + iface: self.iface, + config: self.config, + a_conversion_was_started: self.a_conversion_was_started, + _ic: PhantomData, + _mode: PhantomData + }) + } + + fn is_measurement_in_progress(&mut self) -> Result> { + let config = Config { + bits: self.iface.read_register(Register::CONFIG)? + }; + Ok(!config.is_high(BitFlags::OS)) + } + + fn trigger_measurement(&mut self, config: &Config) -> Result<(), Error> { + let config = config.with_high(BitFlags::OS); + self.iface.write_register(Register::CONFIG, config.bits) + } +} + +impl hal::adc::OneShot, i16, CH> for Ads1x1x +where + DI: interface::ReadData + interface::WriteData, + IC: ic::Resolution, + CH: hal::adc::Channel, ID = ChannelSelection> +{ + type Error = Error; + + /// Request that the ADC begin a conversion on the specified channel + fn read(&mut self, _channel: &mut CH) -> nb::Result { + //TODO for devices with MUX select channel, if it is the wrong one, return AlreadyInProgress or WrongChannel error + if self.is_measurement_in_progress().map_err(nb::Error::Other)? { + return Err(nb::Error::WouldBlock); + } + if self.a_conversion_was_started { + // result is ready + let value = self.iface.read_register(Register::CONVERSION).map_err(nb::Error::Other)?; + self.a_conversion_was_started = false; + return Ok(convert_measurement::(value)); + } + let config = self.config.with_mux_bits(CH::channel()); + self.trigger_measurement(&config).map_err(nb::Error::Other)?; + self.config = config; + self.a_conversion_was_started = true; + Err(nb::Error::WouldBlock) + } +} diff --git a/src/ic.rs b/src/ic.rs new file mode 100644 index 0000000..7b30f85 --- /dev/null +++ b/src/ic.rs @@ -0,0 +1,42 @@ +/// ICs +use private; + +#[derive(PartialEq)] +pub enum ResolutionBits { + _12, + _16 +} + +pub trait Resolution : private::Sealed { + const BITS : ResolutionBits; +} + +macro_rules! ic_marker { + ($name:ident, $resolution:ident) => { + /// IC marker + pub struct $name(()); + impl Resolution for $name { + const BITS: ResolutionBits = ResolutionBits::$resolution; + } + }; +} + +ic_marker!(Ads1013, _12); +ic_marker!(Ads1113, _16); +ic_marker!(Ads1014, _12); +ic_marker!(Ads1114, _16); +ic_marker!(Ads1015, _12); +ic_marker!(Ads1115, _16); + +pub trait Tier2Features : private::Sealed { } + +macro_rules! tier2_features { + ($name:ident) => { + impl Tier2Features for $name {} + } +} + +tier2_features!(Ads1014); +tier2_features!(Ads1114); +tier2_features!(Ads1015); +tier2_features!(Ads1115); diff --git a/src/lib.rs b/src/lib.rs index ef016fb..3c7a383 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -285,12 +285,15 @@ pub struct Ads1x1x { #[doc(hidden)] pub mod interface; +#[doc(hidden)] +pub mod ic; +mod channels; mod devices; -pub use devices::ic; -pub use devices::channel; +mod construction; +pub use channels::channel; mod private { - use super::{ devices::ic, interface }; + use super::{ ic, interface }; pub trait Sealed {} impl Sealed for interface::I2cInterface {} -- cgit v1.2.3-54-g00ecf