From fa3ca008f52fd5b2f4519d1d1ebfa56d843959e8 Mon Sep 17 00:00:00 2001 From: Markus Reiter Date: Sat, 13 Jan 2024 22:08:49 +0100 Subject: [PATCH] Complete rewrite with separate struct for each version. --- README.md | 18 +- examples/all_channels.rs | 11 +- examples/linux.rs | 11 +- examples/trait.rs | 12 +- examples/typed.rs | 18 +- src/construction.rs | 42 ----- src/conversion.rs | 104 ------------ src/devices/common.rs | 87 ++++++---- src/devices/features/tier1.rs | 69 +++----- src/devices/features/tier2.rs | 298 +++++++++++++++++---------------- src/devices/mode/continuous.rs | 88 +++++----- src/devices/mode/oneshot.rs | 160 +++++++++--------- src/ic.rs | 112 +++++++++---- src/interface.rs | 31 ++-- src/lib.rs | 292 ++++++++++++++++++-------------- src/types.rs | 113 +++++++------ tests/common/mod.rs | 35 ++-- tests/construction.rs | 2 +- tests/mux.rs | 8 +- tests/tier1.rs | 26 +-- tests/tier2.rs | 8 +- 21 files changed, 741 insertions(+), 804 deletions(-) delete mode 100644 src/construction.rs delete mode 100644 src/conversion.rs diff --git a/README.md b/README.md index ebabc3f..8e6d7c9 100644 --- a/README.md +++ b/README.md @@ -69,27 +69,27 @@ Datasheets: To use this driver, import this crate and an `embedded_hal` implementation, then instantiate the appropriate device. In the following examples an instance of the device ADS1013 will be created -as an example. Other devices can be created with similar methods like: -`Ads1x1x::new_ads1114(...)`. +as an example. Please find additional examples using hardware in this repository: [driver-examples] [driver-examples]: https://github.com/eldruin/driver-examples ```rust +use ads1x1x::{Ads1013, SlaveAddr, ChannelSelection}; use linux_embedded_hal::I2cdev; use nb::block; -use ads1x1x::{Ads1x1x, SlaveAddr, ChannelSelection}; - fn main() { - let dev = I2cdev::new("/dev/i2c-1").unwrap(); - let address = SlaveAddr::default(); - let mut adc = Ads1x1x::new_ads1013(dev, address); + let i2c = I2cdev::new("/dev/i2c-1").unwrap(); + let mut adc = Ads1013::new(i2c, SlaveAddr::default()); + let value = block!(adc.read(ChannelSelection::DifferentialA0A1)).unwrap(); println!("Measurement: {}", value); - // get I2C device back - let _dev = adc.destroy_ads1013(); + + // Get the I2C peripheral back. + let i2c = adc.release(); + drop(i2c); } ``` diff --git a/examples/all_channels.rs b/examples/all_channels.rs index 1e2a5db..c123557 100644 --- a/examples/all_channels.rs +++ b/examples/all_channels.rs @@ -1,12 +1,11 @@ +use ads1x1x::{Ads1015, ChannelSelection, SlaveAddr}; use linux_embedded_hal::I2cdev; use nb::block; -use ads1x1x::{Ads1x1x, ChannelSelection, SlaveAddr}; - fn main() { - let dev = I2cdev::new("/dev/i2c-1").unwrap(); - let address = SlaveAddr::default(); - let mut adc = Ads1x1x::new_ads1015(dev, address); + let i2c = I2cdev::new("/dev/i2c-1").unwrap(); + let mut adc = Ads1015::new(i2c, SlaveAddr::default()); + let values = [ block!(adc.read(ChannelSelection::SingleA0)).unwrap(), block!(adc.read(ChannelSelection::SingleA1)).unwrap(), @@ -16,6 +15,4 @@ fn main() { for (channel, value) in values.iter().enumerate() { println!("Channel {}: {}", channel, value); } - // get I2C device back - let _dev = adc.destroy_ads1015(); } diff --git a/examples/linux.rs b/examples/linux.rs index 471d19c..18e4271 100644 --- a/examples/linux.rs +++ b/examples/linux.rs @@ -1,14 +1,11 @@ +use ads1x1x::{Ads1013, ChannelSelection, SlaveAddr}; use linux_embedded_hal::I2cdev; use nb::block; -use ads1x1x::{Ads1x1x, ChannelSelection, SlaveAddr}; - fn main() { - let dev = I2cdev::new("/dev/i2c-1").unwrap(); - let address = SlaveAddr::default(); - let mut adc = Ads1x1x::new_ads1013(dev, address); + let i2c = I2cdev::new("/dev/i2c-1").unwrap(); + let mut adc = Ads1013::new(i2c, SlaveAddr::default()); + let value = block!(adc.read(ChannelSelection::DifferentialA0A1)).unwrap(); println!("Measurement: {}", value); - // get I2C device back - let _dev = adc.destroy_ads1013(); } diff --git a/examples/trait.rs b/examples/trait.rs index 070d89c..6ddaded 100644 --- a/examples/trait.rs +++ b/examples/trait.rs @@ -1,11 +1,10 @@ // This example demonstrates the use of the `DynamicOneSot` trait to ease the usage -// of the `Ads1x1x` struct in functions. +// of the `Ads1x1x` structs in functions. +use ads1x1x::{Ads1115, ChannelSelection, DynamicOneShot, SlaveAddr}; use linux_embedded_hal::I2cdev; use nb::block; -use ads1x1x::{Ads1x1x, ChannelSelection, DynamicOneShot, SlaveAddr}; - /// Read a single value from channel A. /// Returns 0 on Error. pub fn read>(adc: &mut A) -> i16 { @@ -13,12 +12,9 @@ pub fn read>(adc: &mut A) -> i16 { } fn main() { - let dev = I2cdev::new("/dev/i2c-1").unwrap(); - let address = SlaveAddr::default(); - let mut adc = Ads1x1x::new_ads1115(dev, address); + let i2c = I2cdev::new("/dev/i2c-1").unwrap(); + let mut adc = Ads1115::new(i2c, SlaveAddr::default()); let value = read(&mut adc); println!("Measurement: {}", value); - // get I2C device back - let _dev = adc.destroy_ads1115(); } diff --git a/examples/typed.rs b/examples/typed.rs index ba40ed4..28198fb 100644 --- a/examples/typed.rs +++ b/examples/typed.rs @@ -1,17 +1,12 @@ -// This example demonstrates the use of a type alias for the `Ads1x1x` struct +// This example demonstrates the use of a type alias for the `Ads1115` struct // to ease usage in signatures. +use ads1x1x::{Ads1115, ChannelSelection, SlaveAddr}; use linux_embedded_hal::I2cdev; use nb::block; -use ads1x1x::{ - ic::{Ads1115, Resolution16Bit}, - interface::I2cInterface, - Ads1x1x, ChannelSelection, SlaveAddr, -}; - /// Type alias -type Adc = Ads1x1x, Ads1115, Resolution16Bit, ads1x1x::mode::OneShot>; +type Adc = Ads1115; /// Read a single value from channel A. /// Returns 0 on Error. @@ -20,12 +15,9 @@ pub fn read(adc: &mut Adc) -> i16 { } fn main() { - let dev = I2cdev::new("/dev/i2c-1").unwrap(); - let address = SlaveAddr::default(); - let mut adc = Ads1x1x::new_ads1115(dev, address); + let i2c = I2cdev::new("/dev/i2c-1").unwrap(); + let mut adc = Ads1115::new(i2c, SlaveAddr::default()); let value = read(&mut adc); println!("Measurement: {}", value); - // get I2C device back - let _dev = adc.destroy_ads1115(); } diff --git a/src/construction.rs b/src/construction.rs deleted file mode 100644 index 39a1e0d..0000000 --- a/src/construction.rs +++ /dev/null @@ -1,42 +0,0 @@ -//! Constructor/destructor functions. - -use crate::{ic, interface::I2cInterface, mode, Ads1x1x, Config, FullScaleRange, SlaveAddr}; -use core::marker::PhantomData; - -macro_rules! impl_new_destroy { - ( $IC:ident, $create:ident, $destroy:ident, $conv:ty ) => { - impl Ads1x1x, ic::$IC, $conv, mode::OneShot> - where - I2C: embedded_hal::i2c::I2c, - { - /// 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(), - }, - config: Config::default(), - fsr: FullScaleRange::default(), - a_conversion_was_started: false, - _conv: PhantomData, - _ic: PhantomData, - _mode: PhantomData, - } - } - } - impl Ads1x1x, ic::$IC, CONV, 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, ic::Resolution12Bit); -impl_new_destroy!(Ads1113, new_ads1113, destroy_ads1113, ic::Resolution16Bit); -impl_new_destroy!(Ads1014, new_ads1014, destroy_ads1014, ic::Resolution12Bit); -impl_new_destroy!(Ads1114, new_ads1114, destroy_ads1114, ic::Resolution16Bit); -impl_new_destroy!(Ads1015, new_ads1015, destroy_ads1015, ic::Resolution12Bit); -impl_new_destroy!(Ads1115, new_ads1115, destroy_ads1115, ic::Resolution16Bit); diff --git a/src/conversion.rs b/src/conversion.rs deleted file mode 100644 index 142de0e..0000000 --- a/src/conversion.rs +++ /dev/null @@ -1,104 +0,0 @@ -use crate::{ic, private, Error}; - -#[doc(hidden)] -pub trait ConvertThreshold: private::Sealed { - fn convert_threshold(value: i16) -> Result>; -} - -impl ConvertThreshold for ic::Resolution12Bit { - fn convert_threshold(value: i16) -> Result> { - if !(-2048..=2047).contains(&value) { - return Err(Error::InvalidInputData); - } - Ok((value << 4) as u16) - } -} - -impl ConvertThreshold for ic::Resolution16Bit { - fn convert_threshold(value: i16) -> Result> { - Ok(value as u16) - } -} - -#[doc(hidden)] -pub trait ConvertMeasurement: private::Sealed { - fn convert_measurement(register_data: u16) -> i16; -} - -impl ConvertMeasurement for ic::Resolution12Bit { - fn convert_measurement(register_data: u16) -> i16 { - let value = register_data; - 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 - } - } -} - -impl ConvertMeasurement for ic::Resolution16Bit { - fn convert_measurement(register_data: u16) -> i16 { - register_data as i16 - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn convert_measurement_12_bits() { - assert_eq!(0, ic::Resolution12Bit::convert_measurement(0)); - assert_eq!(2047, ic::Resolution12Bit::convert_measurement(0x7FFF)); - assert_eq!(-2048, ic::Resolution12Bit::convert_measurement(0x8000)); - assert_eq!(-1, ic::Resolution12Bit::convert_measurement(0xFFFF)); - } - - #[test] - fn convert_measurement_16_bits() { - assert_eq!(0, ic::Resolution16Bit::convert_measurement(0)); - assert_eq!(32767, ic::Resolution16Bit::convert_measurement(0x7FFF)); - assert_eq!(-32768, ic::Resolution16Bit::convert_measurement(0x8000)); - assert_eq!(-1, ic::Resolution16Bit::convert_measurement(0xFFFF)); - } - - fn assert_invalid_input_data(result: Result>) { - match result { - Err(Error::InvalidInputData) => (), - _ => panic!("InvalidInputData error was not returned."), - } - } - - #[test] - fn check_assert_matches() { - assert_invalid_input_data::<()>(Err(Error::InvalidInputData)); - } - - #[test] - #[should_panic] - fn check_assert_fails() { - assert_invalid_input_data::<()>(Ok(0)); - } - - fn convert_threshold>(value: i16) -> u16 { - T::convert_threshold(value).unwrap() - } - - #[test] - fn convert_threshold_12_bits() { - assert_invalid_input_data::<()>(ic::Resolution12Bit::convert_threshold(2048)); - assert_invalid_input_data::<()>(ic::Resolution12Bit::convert_threshold(-2049)); - assert_eq!(0, convert_threshold::(0)); - assert_eq!(0x7FF0, convert_threshold::(2047)); - assert_eq!(0x8000, convert_threshold::(-2048)); - assert_eq!(0xFFF0, convert_threshold::(-1)); - } - - #[test] - fn convert_threshold_16_bits() { - assert_eq!(0x7FFF, convert_threshold::(32767)); - assert_eq!(0x8000, convert_threshold::(-32768)); - } -} diff --git a/src/devices/common.rs b/src/devices/common.rs index 3ff59d9..4f8b7e6 100644 --- a/src/devices/common.rs +++ b/src/devices/common.rs @@ -1,41 +1,58 @@ //! Common functions -use crate::{devices::OperatingMode, interface, Ads1x1x, BitFlags, Config, Error, Register}; +use crate::{ + devices::OperatingMode, Ads1013, Ads1014, Ads1015, Ads1113, Ads1114, Ads1115, BitFlags, Config, + Error, Register, +}; -impl Ads1x1x -where - DI: interface::ReadWriteRegister, -{ - pub(super) fn set_operating_mode(&mut self, mode: OperatingMode) -> Result<(), Error> { - let config = match mode { - OperatingMode::OneShot => self.config.with_high(BitFlags::OP_MODE), - OperatingMode::Continuous => self.config.with_low(BitFlags::OP_MODE), - }; - self.iface.write_register(Register::CONFIG, config.bits)?; - self.config = config; - Ok(()) - } +macro_rules! impl_common_features { + ($Ads:ident) => { + impl $Ads + where + I2C: embedded_hal::i2c::I2c, + { + pub(super) fn set_operating_mode( + &mut self, + mode: OperatingMode, + ) -> Result<(), Error> { + let config = match mode { + OperatingMode::OneShot => self.config.with_high(BitFlags::OP_MODE), + OperatingMode::Continuous => self.config.with_low(BitFlags::OP_MODE), + }; + self.iface.write_register(Register::CONFIG, config.bits)?; + self.config = config; + Ok(()) + } - /// Read whether a measurement is currently in progress. - pub fn is_measurement_in_progress(&mut self) -> Result> { - let config = Config { - bits: self.iface.read_register(Register::CONFIG)?, - }; - Ok(!config.is_high(BitFlags::OS)) - } + /// Read whether a measurement is currently in progress. + pub fn is_measurement_in_progress(&mut self) -> Result> { + let config = Config { + bits: self.iface.read_register(Register::CONFIG)?, + }; + Ok(!config.is_high(BitFlags::OS)) + } - /// 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(); - } + /// 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(); + } + } + }; } + +impl_common_features!(Ads1013); +impl_common_features!(Ads1113); +impl_common_features!(Ads1014); +impl_common_features!(Ads1114); +impl_common_features!(Ads1015); +impl_common_features!(Ads1115); diff --git a/src/devices/features/tier1.rs b/src/devices/features/tier1.rs index f67162f..c526142 100644 --- a/src/devices/features/tier1.rs +++ b/src/devices/features/tier1.rs @@ -1,52 +1,31 @@ //! Common functions use crate::{ - ic, interface, Ads1x1x, BitFlags as BF, DataRate12Bit, DataRate16Bit, Error, Register, + Ads1013, Ads1014, Ads1015, Ads1113, Ads1114, Ads1115, DataRate12Bit, DataRate16Bit, Error, + Register, }; -impl Ads1x1x -where - DI: interface::ReadWriteRegister, -{ - /// Set data rate - pub fn set_data_rate(&mut self, rate: DataRate12Bit) -> Result<(), Error> { - use crate::DataRate12Bit as DR; - let cfg = self.config.clone(); - let config = match rate { - DR::Sps128 => cfg.with_low(BF::DR2).with_low(BF::DR1).with_low(BF::DR0), - DR::Sps250 => cfg.with_low(BF::DR2).with_low(BF::DR1).with_high(BF::DR0), - DR::Sps490 => cfg.with_low(BF::DR2).with_high(BF::DR1).with_low(BF::DR0), - DR::Sps920 => cfg.with_low(BF::DR2).with_high(BF::DR1).with_high(BF::DR0), - DR::Sps1600 => cfg.with_high(BF::DR2).with_low(BF::DR1).with_low(BF::DR0), - DR::Sps2400 => cfg.with_high(BF::DR2).with_low(BF::DR1).with_high(BF::DR0), - DR::Sps3300 => cfg.with_high(BF::DR2).with_high(BF::DR1).with_low(BF::DR0), - }; - self.iface.write_register(Register::CONFIG, config.bits)?; - self.config = config; - Ok(()) - } +macro_rules! impl_tier1_features { + ($Ads:ident, $DataRate:ty) => { + impl $Ads + where + I2C: embedded_hal::i2c::I2c, + { + /// Sets the data rate. + pub fn set_data_rate(&mut self, rate: $DataRate) -> Result<(), Error> { + let mut config = self.config.clone(); + rate.configure(&mut config); + self.iface.write_register(Register::CONFIG, config.bits)?; + self.config = config; + Ok(()) + } + } + }; } -impl Ads1x1x -where - DI: interface::ReadWriteRegister, -{ - /// Set data rate - pub fn set_data_rate(&mut self, rate: DataRate16Bit) -> Result<(), Error> { - use crate::DataRate16Bit as DR; - let cfg = self.config.clone(); - let config = match rate { - DR::Sps8 => cfg.with_low(BF::DR2).with_low(BF::DR1).with_low(BF::DR0), - DR::Sps16 => cfg.with_low(BF::DR2).with_low(BF::DR1).with_high(BF::DR0), - DR::Sps32 => cfg.with_low(BF::DR2).with_high(BF::DR1).with_low(BF::DR0), - DR::Sps64 => cfg.with_low(BF::DR2).with_high(BF::DR1).with_high(BF::DR0), - DR::Sps128 => cfg.with_high(BF::DR2).with_low(BF::DR1).with_low(BF::DR0), - DR::Sps250 => cfg.with_high(BF::DR2).with_low(BF::DR1).with_high(BF::DR0), - DR::Sps475 => cfg.with_high(BF::DR2).with_high(BF::DR1).with_low(BF::DR0), - DR::Sps860 => cfg.with_high(BF::DR2).with_high(BF::DR1).with_high(BF::DR0), - }; - self.iface.write_register(Register::CONFIG, config.bits)?; - self.config = config; - Ok(()) - } -} +impl_tier1_features!(Ads1013, DataRate12Bit); +impl_tier1_features!(Ads1014, DataRate12Bit); +impl_tier1_features!(Ads1015, DataRate12Bit); +impl_tier1_features!(Ads1113, DataRate16Bit); +impl_tier1_features!(Ads1114, DataRate16Bit); +impl_tier1_features!(Ads1115, DataRate16Bit); diff --git a/src/devices/features/tier2.rs b/src/devices/features/tier2.rs index dbd2883..224f8a1 100644 --- a/src/devices/features/tier2.rs +++ b/src/devices/features/tier2.rs @@ -3,157 +3,173 @@ //! These are the features included only in ADS1x14, ADS1x15 use crate::{ - conversion, ic, interface, Ads1x1x, BitFlags as BF, ComparatorLatching, ComparatorMode, + ic, Ads1014, Ads1015, Ads1114, Ads1115, BitFlags as BF, ComparatorLatching, ComparatorMode, ComparatorPolarity, ComparatorQueue, Error, FullScaleRange, Register, }; -impl Ads1x1x -where - DI: interface::ReadWriteRegister, - IC: ic::Tier2Features, - CONV: conversion::ConvertThreshold, -{ - /// Set the input voltage measurable range - /// - /// This configures the programmable gain amplifier and determines the measurable input voltage range. - pub fn set_full_scale_range(&mut self, range: FullScaleRange) -> Result<(), Error> { - use crate::FullScaleRange as FSR; - let cfg = self.config.clone(); - let config = match range { - FSR::Within6_144V => cfg.with_low(BF::PGA2).with_low(BF::PGA1).with_low(BF::PGA0), - FSR::Within4_096V => cfg - .with_low(BF::PGA2) - .with_low(BF::PGA1) - .with_high(BF::PGA0), - FSR::Within2_048V => cfg - .with_low(BF::PGA2) - .with_high(BF::PGA1) - .with_low(BF::PGA0), - FSR::Within1_024V => cfg - .with_low(BF::PGA2) - .with_high(BF::PGA1) - .with_high(BF::PGA0), - FSR::Within0_512V => cfg - .with_high(BF::PGA2) - .with_low(BF::PGA1) - .with_low(BF::PGA0), - FSR::Within0_256V => cfg - .with_high(BF::PGA2) - .with_low(BF::PGA1) - .with_high(BF::PGA0), - }; - self.iface.write_register(Register::CONFIG, config.bits)?; - self.config = config; - Ok(()) - } +macro_rules! impl_tier2_features { + ($Ads:ident, $conv:ty) => { + impl $Ads + where + I2C: embedded_hal::i2c::I2c, + { + /// Sets the input voltage measurable range. + /// + /// This configures the programmable gain amplifier (PGA) and determines the measurable input voltage range. + pub fn set_full_scale_range(&mut self, range: FullScaleRange) -> Result<(), Error> { + use crate::FullScaleRange as FSR; + let cfg = self.config.clone(); + let config = match range { + FSR::Within6_144V => { + cfg.with_low(BF::PGA2).with_low(BF::PGA1).with_low(BF::PGA0) + } + FSR::Within4_096V => cfg + .with_low(BF::PGA2) + .with_low(BF::PGA1) + .with_high(BF::PGA0), + FSR::Within2_048V => cfg + .with_low(BF::PGA2) + .with_high(BF::PGA1) + .with_low(BF::PGA0), + FSR::Within1_024V => cfg + .with_low(BF::PGA2) + .with_high(BF::PGA1) + .with_high(BF::PGA0), + FSR::Within0_512V => cfg + .with_high(BF::PGA2) + .with_low(BF::PGA1) + .with_low(BF::PGA0), + FSR::Within0_256V => cfg + .with_high(BF::PGA2) + .with_low(BF::PGA1) + .with_high(BF::PGA0), + }; + self.iface.write_register(Register::CONFIG, config.bits)?; + self.config = config; + Ok(()) + } - /// Set raw comparator lower threshold - /// - /// The input value must be within `[2047..-2048]` for 12-bit devices (`ADS101x`) - /// and within `[32767..-32768]` for 16-bit devices (`ADS111x`). The voltage that - /// these values correspond to must be calculated using the full-scale range - /// selected. See [`FullScaleRange`](enum.FullScaleRange.html). - pub fn set_low_threshold_raw(&mut self, value: i16) -> Result<(), Error> { - let register_value = CONV::convert_threshold(value)?; - self.iface.write_register(Register::LOW_TH, register_value) - } + /// Sets the raw comparator lower threshold. + /// + /// The input value must be within \[-2048, 2047\] for 12-bit devices (ADS1**0**1x) + /// and within \[-32768, 32767\] for 16-bit devices (ADS1**1**1x). The voltage that + /// these values correspond to must be calculated using the full-scale range + /// ([`FullScaleRange`]) selected. + pub fn set_low_threshold_raw(&mut self, value: i16) -> Result<(), Error> { + let register_value = <$conv>::convert_threshold(value)?; + self.iface.write_register(Register::LOW_TH, register_value) + } - /// Set raw comparator upper threshold - /// - /// The input value must be within `[2047..-2048]` for 12-bit devices (`ADS101x`) - /// and within `[32767..-32768]` for 16-bit devices (`ADS111x`). The voltage that - /// these values correspond to must be calculated using the full-scale range - /// selected. See [`FullScaleRange`](enum.FullScaleRange.html). - pub fn set_high_threshold_raw(&mut self, value: i16) -> Result<(), Error> { - let register_value = CONV::convert_threshold(value)?; - self.iface.write_register(Register::HIGH_TH, register_value) - } + /// Sets the raw comparator upper threshold. + /// + /// The input value must be within \[-2048, 2047\] for 12-bit devices (ADS101x) + /// and within \[-32768, 32767\] for 16-bit devices (ADS111x). The voltage that + /// these values correspond to must be calculated using the full-scale range + /// ([`FullScaleRange`]) selected. + pub fn set_high_threshold_raw(&mut self, value: i16) -> Result<(), Error> { + let register_value = <$conv>::convert_threshold(value)?; + self.iface.write_register(Register::HIGH_TH, register_value) + } - /// Set comparator mode - pub fn set_comparator_mode(&mut self, mode: ComparatorMode) -> Result<(), Error> { - let config = match mode { - ComparatorMode::Traditional => self.config.with_low(BF::COMP_MODE), - ComparatorMode::Window => self.config.with_high(BF::COMP_MODE), - }; - self.iface.write_register(Register::CONFIG, config.bits)?; - self.config = config; - Ok(()) - } + /// Sets the comparator mode. + pub fn set_comparator_mode(&mut self, mode: ComparatorMode) -> Result<(), Error> { + let config = match mode { + ComparatorMode::Traditional => self.config.with_low(BF::COMP_MODE), + ComparatorMode::Window => self.config.with_high(BF::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 => self.config.with_low(BF::COMP_POL), - ComparatorPolarity::ActiveHigh => self.config.with_high(BF::COMP_POL), - }; - self.iface.write_register(Register::CONFIG, config.bits)?; - self.config = config; - Ok(()) - } + /// Sets the comparator polarity. + pub fn set_comparator_polarity( + &mut self, + polarity: ComparatorPolarity, + ) -> Result<(), Error> { + let config = match polarity { + ComparatorPolarity::ActiveLow => self.config.with_low(BF::COMP_POL), + ComparatorPolarity::ActiveHigh => self.config.with_high(BF::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 => self.config.with_low(BF::COMP_LAT), - ComparatorLatching::Latching => self.config.with_high(BF::COMP_LAT), - }; - self.iface.write_register(Register::CONFIG, config.bits)?; - self.config = config; - Ok(()) - } + /// Sets the comparator latching. + pub fn set_comparator_latching( + &mut self, + latching: ComparatorLatching, + ) -> Result<(), Error> { + let config = match latching { + ComparatorLatching::Nonlatching => self.config.with_low(BF::COMP_LAT), + ComparatorLatching::Latching => self.config.with_high(BF::COMP_LAT), + }; + self.iface.write_register(Register::CONFIG, config.bits)?; + self.config = config; + Ok(()) + } - /// Activate comparator and set the alert queue - /// - /// The comparator can be disabled with [`disable_comparator()`](struct.Ads1x1x.html#method.disable_comparator) - pub fn set_comparator_queue(&mut self, queue: ComparatorQueue) -> Result<(), Error> { - let config = match queue { - ComparatorQueue::One => self.config.with_low(BF::COMP_QUE1).with_low(BF::COMP_QUE0), - ComparatorQueue::Two => self.config.with_low(BF::COMP_QUE1).with_high(BF::COMP_QUE0), - ComparatorQueue::Four => self.config.with_high(BF::COMP_QUE1).with_low(BF::COMP_QUE0), - }; - self.iface.write_register(Register::CONFIG, config.bits)?; - self.config = config; - Ok(()) - } + /// Activates the comparator and sets the alert queue. + /// + /// The comparator can be disabled with [`disable_comparator`](Self::disable_comparator). + pub fn set_comparator_queue(&mut self, queue: ComparatorQueue) -> Result<(), Error> { + let config = match queue { + ComparatorQueue::One => { + self.config.with_low(BF::COMP_QUE1).with_low(BF::COMP_QUE0) + } + ComparatorQueue::Two => { + self.config.with_low(BF::COMP_QUE1).with_high(BF::COMP_QUE0) + } + ComparatorQueue::Four => { + self.config.with_high(BF::COMP_QUE1).with_low(BF::COMP_QUE0) + } + }; + self.iface.write_register(Register::CONFIG, config.bits)?; + self.config = config; + Ok(()) + } - /// Disable comparator (default) - /// - /// This will set the ALERT/RDY pin to high-impedance. - /// The comparator can be enabled by setting the comparator queue. - /// See [`set_comparator_queue()`](struct.Ads1x1x.html#method.set_comparator_queue) - pub fn disable_comparator(&mut self) -> Result<(), Error> { - let config = self - .config - .with_high(BF::COMP_QUE1) - .with_high(BF::COMP_QUE0); - self.iface.write_register(Register::CONFIG, config.bits)?; - self.config = config; - Ok(()) - } + /// Disables the comparator. (default) + /// + /// This sets the ALERT/RDY pin to high-impedance. + /// + /// The comparator can be enabled by setting the comparator queue using + /// the [`set_comparator_queue`](Self::set_comparator_queue) mehtod. + pub fn disable_comparator(&mut self) -> Result<(), Error> { + let config = self + .config + .with_high(BF::COMP_QUE1) + .with_high(BF::COMP_QUE0); + self.iface.write_register(Register::CONFIG, config.bits)?; + self.config = config; + Ok(()) + } - /// Use the ALERT/RDY pin as conversion-ready pin. - /// - /// This the ALERT/RDY pin outputs the OS bit when in OneShot mode, and - /// provides a continuous-conversion ready pulse when in - /// continuous-conversion mode. - /// - /// When calling this the comparator will be disabled and the thresholds will be cleared. - pub fn use_alert_rdy_pin_as_ready(&mut self) -> Result<(), Error> { - if self.config - != self - .config - .with_high(BF::COMP_QUE1) - .with_high(BF::COMP_QUE0) - { - self.disable_comparator()?; + /// Sets the ALERT/RDY pin as conversion-ready pin. + /// + /// This the ALERT/RDY pin outputs the OS bit when in OneShot mode, and + /// provides a continuous-conversion ready pulse when in + /// continuous-conversion mode. + /// + /// When calling this the comparator will be disabled and the thresholds will be cleared. + pub fn use_alert_rdy_pin_as_ready(&mut self) -> Result<(), Error> { + if self.config + != self + .config + .with_high(BF::COMP_QUE1) + .with_high(BF::COMP_QUE0) + { + self.disable_comparator()?; + } + self.iface.write_register(Register::HIGH_TH, 0x8000)?; + self.iface.write_register(Register::LOW_TH, 0) + } } - self.iface.write_register(Register::HIGH_TH, 0x8000)?; - self.iface.write_register(Register::LOW_TH, 0) - } + }; } + +impl_tier2_features!(Ads1014, ic::Resolution12Bit); +impl_tier2_features!(Ads1015, ic::Resolution12Bit); +impl_tier2_features!(Ads1114, ic::Resolution16Bit); +impl_tier2_features!(Ads1115, ic::Resolution16Bit); diff --git a/src/devices/mode/continuous.rs b/src/devices/mode/continuous.rs index 1dca71e..f70fd5f 100644 --- a/src/devices/mode/continuous.rs +++ b/src/devices/mode/continuous.rs @@ -1,49 +1,57 @@ //! Continuous measurement mode use crate::{ - channels::ChannelSelection, conversion, devices::OperatingMode, interface, mode, Ads1x1x, - Error, ModeChangeError, Register, + channels::ChannelSelection, devices::OperatingMode, ic, mode, Ads1013, Ads1014, Ads1015, + Ads1113, Ads1114, Ads1115, Error, ModeChangeError, Register, }; use core::marker::PhantomData; -impl Ads1x1x -where - DI: interface::ReadWriteRegister, - CONV: conversion::ConvertMeasurement, -{ - /// Change operating mode to OneShot - pub fn into_one_shot( - mut self, - ) -> Result, ModeChangeError> { - if let Err(Error::I2C(e)) = self.set_operating_mode(OperatingMode::OneShot) { - return Err(ModeChangeError::I2C(e, self)); - } - Ok(Ads1x1x { - iface: self.iface, - config: self.config, - fsr: self.fsr, - a_conversion_was_started: false, - _conv: PhantomData, - _ic: PhantomData, - _mode: PhantomData, - }) - } +macro_rules! impl_continuous { + ($Ads:ident, $conv:ty) => { + impl $Ads + where + I2C: embedded_hal::i2c::I2c, + { + /// Changes operating mode to `OneShot`. + pub fn into_one_shot( + mut self, + ) -> Result<$Ads, ModeChangeError> { + if let Err(Error::I2C(e)) = self.set_operating_mode(OperatingMode::OneShot) { + return Err(ModeChangeError::I2C(e, self)); + } + Ok($Ads { + iface: self.iface, + config: self.config, + fsr: self.fsr, + a_conversion_was_started: false, + mode: PhantomData, + }) + } - /// Read the most recent measurement - pub fn read(&mut self) -> Result> { - let value = self.iface.read_register(Register::CONVERSION)?; - Ok(CONV::convert_measurement(value)) - } + /// Reads the most recent measurement. + pub fn read(&mut self) -> Result> { + let value = self.iface.read_register(Register::CONVERSION)?; + Ok(<$conv>::convert_measurement(value)) + } - /// Select the channel for measurements. - /// - /// Note that when changing the channel in continuous conversion mode, the - /// ongoing conversion will be completed. - /// The following conversions will use the new channel configuration. - pub fn select_channel(&mut self, channel: ChannelSelection) -> Result<(), Error> { - let config = self.config.with_mux_bits(channel); - self.iface.write_register(Register::CONFIG, config.bits)?; - self.config = config; - Ok(()) - } + /// Selects the channel for measurements. + /// + /// Note that when changing the channel in continuous conversion mode, the + /// ongoing conversion will be completed. + /// The following conversions will use the new channel configuration. + pub fn select_channel(&mut self, channel: ChannelSelection) -> Result<(), Error> { + let config = self.config.with_mux_bits(channel); + self.iface.write_register(Register::CONFIG, config.bits)?; + self.config = config; + Ok(()) + } + } + }; } + +impl_continuous!(Ads1013, ic::Resolution12Bit); +impl_continuous!(Ads1014, ic::Resolution12Bit); +impl_continuous!(Ads1015, ic::Resolution12Bit); +impl_continuous!(Ads1113, ic::Resolution16Bit); +impl_continuous!(Ads1114, ic::Resolution16Bit); +impl_continuous!(Ads1115, ic::Resolution16Bit); diff --git a/src/devices/mode/oneshot.rs b/src/devices/mode/oneshot.rs index 2139cad..144ae35 100644 --- a/src/devices/mode/oneshot.rs +++ b/src/devices/mode/oneshot.rs @@ -2,91 +2,91 @@ use core::marker::PhantomData; use crate::{ - conversion, devices::OperatingMode, interface, mode, Ads1x1x, BitFlags, ChannelSelection, - Config, DynamicOneShot, Error, ModeChangeError, Register, + devices::OperatingMode, ic, mode, Ads1013, Ads1014, Ads1015, Ads1113, Ads1114, Ads1115, + BitFlags, ChannelSelection, Config, DynamicOneShot, Error, ModeChangeError, Register, }; -impl Ads1x1x -where - DI: interface::ReadWriteRegister, - CONV: conversion::ConvertMeasurement, -{ - /// Change operating mode to Continuous - pub fn into_continuous( - mut self, - ) -> Result, ModeChangeError> { - if let Err(Error::I2C(e)) = self.set_operating_mode(OperatingMode::Continuous) { - return Err(ModeChangeError::I2C(e, self)); - } - Ok(Ads1x1x { - iface: self.iface, - config: self.config, - fsr: self.fsr, - a_conversion_was_started: true, - _conv: PhantomData, - _ic: PhantomData, - _mode: PhantomData, - }) - } +macro_rules! impl_one_shot { + ($Ads:ident, $conv:ty) => { + impl $Ads + where + I2C: embedded_hal::i2c::I2c, + { + /// Change operating mode to Continuous + pub fn into_continuous( + mut self, + ) -> Result<$Ads, ModeChangeError> { + if let Err(Error::I2C(e)) = self.set_operating_mode(OperatingMode::Continuous) { + return Err(ModeChangeError::I2C(e, self)); + } + Ok($Ads { + iface: self.iface, + config: self.config, + fsr: self.fsr, + a_conversion_was_started: true, + mode: PhantomData, + }) + } - fn trigger_measurement(&mut self, config: &Config) -> Result<(), Error> { - let config = config.with_high(BitFlags::OS); - self.iface.write_register(Register::CONFIG, config.bits) - } -} + 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 Ads1x1x -where - DI: interface::ReadWriteRegister, - CONV: conversion::ConvertMeasurement, -{ - /// Request that the ADC begin a conversion on the specified channel. - /// - /// The output value will be within `[2047..-2048]` for 12-bit devices - /// (`ADS101x`) and within `[32767..-32768]` for 16-bit devices (`ADS111x`). - /// The voltage that these values correspond to must be calculated using - /// the full-scale range selected. - /// See [`FullScaleRange`](enum.FullScaleRange.html). - /// - /// Returns `nb::Error::WouldBlock` while a measurement is in progress. - /// - /// In case a measurement was requested and after is it is finished a - /// measurement on a different channel is requested, a new measurement on - /// using the new channel selection is triggered. - pub fn read(&mut self, channel: ChannelSelection) -> nb::Result> { - if self - .is_measurement_in_progress() - .map_err(nb::Error::Other)? - { - return Err(nb::Error::WouldBlock); - } - let same_channel = self.config == self.config.with_mux_bits(channel); - if self.a_conversion_was_started && same_channel { - // result is ready - let value = self - .iface - .read_register(Register::CONVERSION) - .map_err(nb::Error::Other)?; - self.a_conversion_was_started = false; - return Ok(CONV::convert_measurement(value)); + /// Requests that the ADC begins a conversion on the specified channel. + /// + /// The output value will be within `[2047..-2048]` for 12-bit devices + /// (`ADS101x`) and within `[32767..-32768]` for 16-bit devices (`ADS111x`). + /// The voltage that these values correspond to must be calculated using + /// the full-scale range ([`FullScaleRange`](crate::FullScaleRange)) selected. + /// + /// Returns `nb::Error::WouldBlock` while a measurement is in progress. + /// + /// In case a measurement was requested and after is it is finished a + /// measurement on a different channel is requested, a new measurement on + /// using the new channel selection is triggered. + pub fn read(&mut self, channel: ChannelSelection) -> nb::Result> { + if self + .is_measurement_in_progress() + .map_err(nb::Error::Other)? + { + return Err(nb::Error::WouldBlock); + } + let same_channel = self.config == self.config.with_mux_bits(channel); + if self.a_conversion_was_started && same_channel { + // result is ready + let value = self + .iface + .read_register(Register::CONVERSION) + .map_err(nb::Error::Other)?; + self.a_conversion_was_started = false; + return Ok(<$conv>::convert_measurement(value)); + } + let config = self.config.with_mux_bits(channel); + self.trigger_measurement(&config) + .map_err(nb::Error::Other)?; + self.config = config; + self.a_conversion_was_started = true; + Err(nb::Error::WouldBlock) + } } - let config = self.config.with_mux_bits(channel); - self.trigger_measurement(&config) - .map_err(nb::Error::Other)?; - self.config = config; - self.a_conversion_was_started = true; - Err(nb::Error::WouldBlock) - } -} -impl DynamicOneShot for Ads1x1x -where - DI: interface::ReadWriteRegister, - CONV: conversion::ConvertMeasurement, -{ - type Error = Error; + impl DynamicOneShot for $Ads + where + I2C: embedded_hal::i2c::I2c, + { + type Error = Error; - fn read(&mut self, channel: ChannelSelection) -> nb::Result { - (*self).read(channel) - } + fn read(&mut self, channel: ChannelSelection) -> nb::Result { + (*self).read(channel) + } + } + }; } + +impl_one_shot!(Ads1013, ic::Resolution12Bit); +impl_one_shot!(Ads1014, ic::Resolution12Bit); +impl_one_shot!(Ads1015, ic::Resolution12Bit); +impl_one_shot!(Ads1113, ic::Resolution16Bit); +impl_one_shot!(Ads1114, ic::Resolution16Bit); +impl_one_shot!(Ads1115, ic::Resolution16Bit); diff --git a/src/ic.rs b/src/ic.rs index 8e4db42..b093553 100644 --- a/src/ic.rs +++ b/src/ic.rs @@ -1,34 +1,90 @@ -/// ICs -use crate::private; - -#[non_exhaustive] -pub struct Resolution12Bit; -#[non_exhaustive] -pub struct Resolution16Bit; - -macro_rules! ic_marker { - ($name:ident) => { - /// IC marker - pub struct $name(()); - }; +use crate::Error; + +pub(crate) struct Resolution12Bit; + +impl Resolution12Bit { + pub fn convert_threshold(value: i16) -> Result> { + if !(-2048..=2047).contains(&value) { + return Err(Error::InvalidInputData); + } + Ok((value << 4) as u16) + } + + pub fn convert_measurement(register_data: u16) -> i16 { + let value = register_data; + 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 + } + } } -ic_marker!(Ads1013); -ic_marker!(Ads1113); -ic_marker!(Ads1014); -ic_marker!(Ads1114); -ic_marker!(Ads1015); -ic_marker!(Ads1115); +pub(crate) struct Resolution16Bit; -pub trait Tier2Features: private::Sealed {} +impl Resolution16Bit { + pub fn convert_threshold(value: i16) -> Result> { + Ok(value as u16) + } -macro_rules! tier2_features { - ($name:ident) => { - impl Tier2Features for $name {} - }; + pub fn convert_measurement(register_data: u16) -> i16 { + register_data as i16 + } } -tier2_features!(Ads1014); -tier2_features!(Ads1114); -tier2_features!(Ads1015); -tier2_features!(Ads1115); +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn convert_measurement_12_bits() { + assert_eq!(0, Resolution12Bit::convert_measurement(0)); + assert_eq!(2047, Resolution12Bit::convert_measurement(0x7FFF)); + assert_eq!(-2048, Resolution12Bit::convert_measurement(0x8000)); + assert_eq!(-1, Resolution12Bit::convert_measurement(0xFFFF)); + } + + #[test] + fn convert_measurement_16_bits() { + assert_eq!(0, Resolution16Bit::convert_measurement(0)); + assert_eq!(32767, Resolution16Bit::convert_measurement(0x7FFF)); + assert_eq!(-32768, Resolution16Bit::convert_measurement(0x8000)); + assert_eq!(-1, Resolution16Bit::convert_measurement(0xFFFF)); + } + + fn assert_invalid_input_data(result: Result>) { + match result { + Err(Error::InvalidInputData) => (), + _ => panic!("InvalidInputData error was not returned."), + } + } + + #[test] + fn check_assert_matches() { + assert_invalid_input_data::<()>(Err(Error::InvalidInputData)); + } + + #[test] + #[should_panic] + fn check_assert_fails() { + assert_invalid_input_data::<()>(Ok(0)); + } + + #[test] + fn convert_threshold_12_bits() { + assert_invalid_input_data::<()>(Resolution12Bit::convert_threshold::<()>(2048)); + assert_invalid_input_data::<()>(Resolution12Bit::convert_threshold::<()>(-2049)); + assert_eq!(Ok(0), Resolution12Bit::convert_threshold::<()>(0)); + assert_eq!(Ok(0x7FF0), Resolution12Bit::convert_threshold::<()>(2047)); + assert_eq!(Ok(0x8000), Resolution12Bit::convert_threshold::<()>(-2048)); + assert_eq!(Ok(0xFFF0), Resolution12Bit::convert_threshold::<()>(-1)); + } + + #[test] + fn convert_threshold_16_bits() { + assert_eq!(Ok(0x7FFF), Resolution16Bit::convert_threshold::<()>(32767)); + assert_eq!(Ok(0x8000), Resolution16Bit::convert_threshold::<()>(-32768)); + } +} diff --git a/src/interface.rs b/src/interface.rs index dbb621d..d41238e 100644 --- a/src/interface.rs +++ b/src/interface.rs @@ -1,39 +1,28 @@ //! I2C interface -use crate::{private, Error}; +use crate::Error; /// I2C interface #[derive(Debug, Default)] -pub struct I2cInterface { - pub(crate) i2c: I2C, - pub(crate) address: u8, -} - -/// Read/write data from/to register. -pub trait ReadWriteRegister: private::Sealed { - /// Error type. - type Error; - - /// Reads a `u16` register. - fn read_register(&mut self, register: u8) -> Result>; - - /// Writes to a `u16` register. - fn write_register(&mut self, register: u8, data: u16) -> Result<(), Error>; +pub(crate) struct I2cInterface +where + I2C: embedded_hal::i2c::I2c, +{ + pub i2c: I2C, + pub address: u8, } -impl ReadWriteRegister for I2cInterface +impl I2cInterface where I2C: embedded_hal::i2c::I2c, { - type Error = E; - - fn write_register(&mut self, register: u8, data: u16) -> Result<(), Error> { + pub fn write_register(&mut self, register: u8, data: u16) -> Result<(), Error> { let data = data.to_be_bytes(); let payload: [u8; 3] = [register, data[0], data[1]]; self.i2c.write(self.address, &payload).map_err(Error::I2C) } - fn read_register(&mut self, register: u8) -> Result> { + pub fn read_register(&mut self, register: u8) -> Result> { let mut data = [0, 0]; self.i2c .write_read(self.address, &[register], &mut data) diff --git a/src/lib.rs b/src/lib.rs index f0c10a0..259dcb8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,38 +5,25 @@ //! [`embedded-hal`]: https://github.com/rust-embedded/embedded-hal //! //! This driver allows you to: -//! - Set the operating mode to one-shot or continuous. See: [`into_continuous()`]. -//! - Make a measurement in one-shot mode. See: [`read()`][read_os]. -//! - Start continuous conversion mode. See: [`start()`]. -//! - Read the last measurement made in continuous conversion mode. See: [`read()`][read_cont]. -//! - Set the data rate. See: [`set_data_rate()`]. -//! - Set the full-scale range (gain amplifier). See [`set_full_scale_range()`]. -//! - Read whether a measurement is in progress. See: [`is_measurement_in_progress()`]. -//! - Set the ALERT/RDY pin to be used as conversion-ready pin. See: [`use_alert_rdy_pin_as_ready()`]. +//! - Set the operating mode to one-shot or continuous. See [`Ads1115::into_one_shot`] and [`Ads1115::into_continuous`]. +//! - Take a measurement in one-shot mode. See [`Ads1115<_, OneShot>::read`][read_one_shot]. +//! - Read the last measurement made in continuous conversion mode. See [`Ads1115<_, Continuous>::read`][read_continous]. +//! - Set the data rate. See [`Ads1115::set_data_rate`]. +//! - Set the full-scale range (gain amplifier). See [`Ads1115::set_full_scale_range`]. +//! - Read whether a measurement is in progress. See [`Ads1115::is_measurement_in_progress`]. +//! - Set the ALERT/RDY pin to be used as conversion-ready pin. See [`Ads1115::use_alert_rdy_pin_as_ready`]. //! - Comparator: -//! - Set the low and high thresholds. See: [`set_high_threshold_raw()`]. -//! - Set the comparator mode. See: [`set_comparator_mode()`]. -//! - Set the comparator polarity. See: [`set_comparator_polarity()`]. -//! - Set the comparator latching. See: [`set_comparator_latching()`]. -//! - Set the comparator queue. See: [`set_comparator_queue()`]. -//! - Disable the comparator. See: [`disable_comparator()`]. -//! -//! [`into_continuous()`]: struct.Ads1x1x.html#method.into_continuous -//! [read_os]: struct.Ads1x1x.html#method.read -//! [`start()`]: struct.Ads1x1x.html#method.start -//! [read_cont]: struct.Ads1x1x.html#impl-OneShot%3CAds1x1x%3CDI%2C%20IC%2C%20CONV%2C%20OneShot%3E%2C%20i16%2C%20CH%3E -//! [`set_data_rate()`]: struct.Ads1x1x.html#method.set_data_rate -//! [`set_full_scale_range()`]: struct.Ads1x1x.html#method.set_full_scale_range -//! [`is_measurement_in_progress()`]: struct.Ads1x1x.html#method.is_measurement_in_progress -//! [`set_high_threshold_raw()`]: struct.Ads1x1x.html#method.set_high_threshold_raw -//! [`set_comparator_mode()`]: struct.Ads1x1x.html#method.set_comparator_mode -//! [`set_comparator_polarity()`]: struct.Ads1x1x.html#method.set_comparator_polarity -//! [`set_comparator_latching()`]: struct.Ads1x1x.html#method.set_comparator_latching -//! [`set_comparator_queue()`]: struct.Ads1x1x.html#method.set_comparator_queue -//! [`disable_comparator()`]: struct.Ads1x1x.html#method.disable_comparator -//! [`use_alert_rdy_pin_as_ready()`]: struct.Ads1x1x.html#method.use_alert_rdy_pin_as_ready -//! -//! ## The devices +//! - Set the low and high thresholds. See [`Ads1115::set_high_threshold_raw`]. +//! - Set the comparator mode. See [`Ads1115::set_comparator_mode`]. +//! - Set the comparator polarity. See [`Ads1115::set_comparator_polarity`]. +//! - Set the comparator latching. See [`Ads1115::set_comparator_latching`]. +//! - Set the comparator queue. See [`Ads1115::set_comparator_queue`]. +//! - Disable the comparator. See [`Ads1115::disable_comparator`]. +//! +//! [read_one_shot]: struct.Ads1115.html#method.read-1 +//! [read_continous]: struct.Ads1115.html#method.read +//! +//! # The devices //! //! The devices are precision, low power, 12/16-bit analog-to-digital //! converters (ADC) that provide all features necessary to measure the most @@ -72,84 +59,95 @@ //! - [ADS101x](http://www.ti.com/lit/ds/symlink/ads1015.pdf) //! - [ADS111x](http://www.ti.com/lit/ds/symlink/ads1115.pdf) //! -//! ## Usage examples (see also examples folder) +//! # Examples //! //! To use this driver, import this crate and an `embedded_hal` implementation, //! then instantiate the appropriate device. //! In the following examples an instance of the device ADS1013 will be created -//! as an example. Other devices can be created with similar methods like: -//! `Ads1x1x::new_ads1114(...)`. +//! as an example. //! //! Please find additional examples using hardware in this repository: [driver-examples] //! //! [driver-examples]: https://github.com/eldruin/driver-examples //! -//! ### Create a driver instance for the ADS1013 +//! ## Creating a Driver Instance for an ADS1013 //! //! ```no_run +//! # fn main() -> Result<(), Box> { +//! use ads1x1x::{Ads1013, SlaveAddr}; //! use linux_embedded_hal::I2cdev; -//! use ads1x1x::{Ads1x1x, SlaveAddr}; //! -//! let dev = I2cdev::new("/dev/i2c-1").unwrap(); -//! let address = SlaveAddr::default(); -//! let adc = Ads1x1x::new_ads1013(dev, address); -//! // do something... +//! let i2c = I2cdev::new("/dev/i2c-1")?; +//! let adc = Ads1013::new(i2c, SlaveAddr::default()); +//! +//! // Do something. //! -//! // get the I2C device back -//! let dev = adc.destroy_ads1013(); +//! // Get the I2C device back. +//! let i2c = adc.release(); +//! # drop(i2c); +//! # Ok(()) +//! # } //! ``` //! -//! ### Create a driver instance for the ADS1013 with an alternative address (method 1) +//! ### Creating a Driver Instance for an ADS1013 with an Alternative Address (Method 1) //! -//! ```no_run -//! use linux_embedded_hal::I2cdev; -//! use ads1x1x::{Ads1x1x, SlaveAddr}; +//! Using an alternative [`SlaveAddr`]. //! -//! let dev = I2cdev::new("/dev/i2c-1").unwrap(); -//! let address = SlaveAddr::Alt2; -//! let adc = Ads1x1x::new_ads1013(dev, address); +//! ```no_run +//! # fn main() -> Result<(), Box> { +//! # use ads1x1x::{Ads1013, SlaveAddr}; +//! # use linux_embedded_hal::I2cdev; +//! # +//! # let i2c = I2cdev::new("/dev/i2c-1")?; +//! let adc = Ads1013::new(i2c, SlaveAddr::Alt2); +//! # Ok(()) +//! # } //! ``` -//! ### Create a driver instance for the ADS1013 with an alternative address (method 2) +//! ### Creating a Driver Instance for an ADS1013 with an Alternative Address (Method 2) //! -//! Using helper `SlaveAddr` creation method depending on the connection of -//! the `ADDR` pin. +//! Using [`SlaveAddr`] constants, depending on the connection of the ADDR pin. //! //! ```no_run -//! use linux_embedded_hal::I2cdev; -//! use ads1x1x::{Ads1x1x, SlaveAddr}; -//! -//! let dev = I2cdev::new("/dev/i2c-1").unwrap(); -//! // `ADDR` pin connected to SDA results in the 0x4A effective address -//! let address = SlaveAddr::new_sda(); -//! let adc = Ads1x1x::new_ads1013(dev, address); +//! # fn main() -> Result<(), Box> { +//! # use ads1x1x::{Ads1013, SlaveAddr}; +//! # use linux_embedded_hal::I2cdev; +//! # +//! # let i2c = I2cdev::new("/dev/i2c-1")?; +//! // ADDR pin connected to SDA results in the `0x4A` effective address. +//! let adc = Ads1013::new(i2c, SlaveAddr::SDA); +//! # Ok(()) +//! # } //! ``` //! -//! ### Make a one-shot measurement +//! ## Taking a One-Shot Measurement +//! //! ```no_run -//! use ads1x1x::{Ads1x1x, SlaveAddr, ChannelSelection}; +//! # fn main() -> Result<(), Box> { +//! use ads1x1x::{Ads1013, SlaveAddr, ChannelSelection}; //! use linux_embedded_hal::I2cdev; //! use nb::block; //! -//! let dev = I2cdev::new("/dev/i2c-1").unwrap(); -//! let mut adc = Ads1x1x::new_ads1013(dev, SlaveAddr::default()); -//! let measurement = block!(adc.read(ChannelSelection::DifferentialA0A1)).unwrap(); +//! let i2c = I2cdev::new("/dev/i2c-1")?; +//! let mut adc = Ads1013::new(i2c, SlaveAddr::default()); +//! +//! let measurement = block!(adc.read(ChannelSelection::DifferentialA0A1))?; //! println!("Measurement: {}", measurement); -//! let _dev = adc.destroy_ads1013(); // get I2C device back +//! # Ok(()) +//! # } //! ``` //! -//! ### Change into continuous conversion mode and read the last measurement +//! ## Changing to Continuous Conversion Mode and Reading the Last Measurement //! //! Changing the mode may fail in case there was a communication error. //! In this case, you can retrieve the unchanged device from the error type. //! //! ```no_run +//! use ads1x1x::{Ads1013, ModeChangeError, SlaveAddr}; //! use linux_embedded_hal::I2cdev; -//! use ads1x1x::{Ads1x1x, ModeChangeError, SlaveAddr}; //! -//! let dev = I2cdev::new("/dev/i2c-1").unwrap(); -//! let address = SlaveAddr::default(); -//! let adc = Ads1x1x::new_ads1013(dev, address); +//! let i2c = I2cdev::new("/dev/i2c-1").unwrap(); +//! let adc = Ads1013::new(i2c, SlaveAddr::default()); //! match adc.into_continuous() { //! Err(ModeChangeError::I2C(e, adc)) => /* mode change failed handling */ panic!(), //! Ok(mut adc) => { @@ -160,21 +158,22 @@ //! ``` //! //! -//! ### Set the data rate +//! ## Setting the Data Rate //! For 12-bit devices, the available data rates are given by `DataRate12Bit`. //! For 16-bit devices, the available data rates are given by `DataRate16Bit`. //! //! ```no_run +//! use ads1x1x::{Ads1115, DataRate16Bit, SlaveAddr}; //! use linux_embedded_hal::I2cdev; -//! use ads1x1x::{Ads1x1x, DataRate16Bit, SlaveAddr}; //! -//! let dev = I2cdev::new("/dev/i2c-1").unwrap(); -//! let address = SlaveAddr::default(); -//! let mut adc = Ads1x1x::new_ads1115(dev, address); +//! let i2c = I2cdev::new("/dev/i2c-1").unwrap(); +//! let mut adc = Ads1115::new(i2c, SlaveAddr::default()); +//! //! adc.set_data_rate(DataRate16Bit::Sps860).unwrap(); //! ``` //! -//! ### Configure the comparator +//! ## Configuring the Comparator +//! //! Configure the comparator to assert when the voltage drops below -1.5V //! or goes above 1.5V in at least two consecutive conversions. Then the //! ALERT/RDY pin will be set high and it will be kept so until the @@ -182,15 +181,15 @@ //! the master. //! //! ```no_run -//! use linux_embedded_hal::I2cdev; //! use ads1x1x::{ -//! Ads1x1x, SlaveAddr, ComparatorQueue, ComparatorPolarity, +//! Ads1115, SlaveAddr, ComparatorQueue, ComparatorPolarity, //! ComparatorMode, ComparatorLatching, FullScaleRange //! }; +//! use linux_embedded_hal::I2cdev; +//! +//! let i2c = I2cdev::new("/dev/i2c-1").unwrap(); +//! let mut adc = Ads1015::new(i2c, SlaveAddr::default()); //! -//! let dev = I2cdev::new("/dev/i2c-1").unwrap(); -//! let address = SlaveAddr::default(); -//! let mut adc = Ads1x1x::new_ads1015(dev, address); //! adc.set_comparator_queue(ComparatorQueue::Two).unwrap(); //! adc.set_comparator_polarity(ComparatorPolarity::ActiveHigh).unwrap(); //! adc.set_comparator_mode(ComparatorMode::Window).unwrap(); @@ -203,68 +202,107 @@ #![deny(missing_docs)] #![no_std] -const DEVICE_BASE_ADDRESS: u8 = 0b100_1000; +use core::marker::PhantomData; + +mod channels; +pub use crate::channels::ChannelSelection; +mod devices; +mod ic; +mod interface; +use interface::I2cInterface; +mod types; +use crate::types::Config; +pub use crate::types::{ + mode, ComparatorLatching, ComparatorMode, ComparatorPolarity, ComparatorQueue, DataRate12Bit, + DataRate16Bit, DynamicOneShot, Error, FullScaleRange, ModeChangeError, SlaveAddr, +}; struct Register; + +#[rustfmt::skip] impl Register { const CONVERSION: u8 = 0x00; - const CONFIG: u8 = 0x01; - const LOW_TH: u8 = 0x02; - const HIGH_TH: u8 = 0x03; + const CONFIG: u8 = 0x01; + const LOW_TH: u8 = 0x02; + const HIGH_TH: u8 = 0x03; } struct BitFlags; + +#[rustfmt::skip] impl BitFlags { - const OS: u16 = 0b1000_0000_0000_0000; - const MUX2: u16 = 0b0100_0000_0000_0000; - const MUX1: u16 = 0b0010_0000_0000_0000; - const MUX0: u16 = 0b0001_0000_0000_0000; - const PGA2: u16 = 0b0000_1000_0000_0000; - const PGA1: u16 = 0b0000_0100_0000_0000; - const PGA0: u16 = 0b0000_0010_0000_0000; - const OP_MODE: u16 = 0b0000_0001_0000_0000; - const DR2: u16 = 0b0000_0000_1000_0000; - const DR1: u16 = 0b0000_0000_0100_0000; - const DR0: u16 = 0b0000_0000_0010_0000; + const OS: u16 = 0b1000_0000_0000_0000; + const MUX2: u16 = 0b0100_0000_0000_0000; + const MUX1: u16 = 0b0010_0000_0000_0000; + const MUX0: u16 = 0b0001_0000_0000_0000; + const PGA2: u16 = 0b0000_1000_0000_0000; + const PGA1: u16 = 0b0000_0100_0000_0000; + const PGA0: u16 = 0b0000_0010_0000_0000; + const OP_MODE: u16 = 0b0000_0001_0000_0000; + const DR2: u16 = 0b0000_0000_1000_0000; + const DR1: u16 = 0b0000_0000_0100_0000; + const DR0: u16 = 0b0000_0000_0010_0000; const COMP_MODE: u16 = 0b0000_0000_0001_0000; - const COMP_POL: u16 = 0b0000_0000_0000_1000; - const COMP_LAT: u16 = 0b0000_0000_0000_0100; + const COMP_POL: u16 = 0b0000_0000_0000_1000; + const COMP_LAT: u16 = 0b0000_0000_0000_0100; const COMP_QUE1: u16 = 0b0000_0000_0000_0010; const COMP_QUE0: u16 = 0b0000_0000_0000_0001; } -mod channels; -pub use crate::channels::ChannelSelection; -mod construction; -mod conversion; -pub use crate::conversion::{ConvertMeasurement, ConvertThreshold}; -mod devices; -#[doc(hidden)] -pub mod ic; -#[doc(hidden)] -pub mod interface; -mod types; -use crate::types::Config; -pub use crate::types::{ - mode, Ads1x1x, ComparatorLatching, ComparatorMode, ComparatorPolarity, ComparatorQueue, - DataRate12Bit, DataRate16Bit, DynamicOneShot, Error, FullScaleRange, ModeChangeError, - SlaveAddr, -}; - mod private { - use super::{ic, interface, Ads1x1x}; pub trait Sealed {} +} - impl Sealed for interface::I2cInterface {} - impl Sealed for Ads1x1x {} +macro_rules! impl_ads1x1x { + ($Ads:ident) => { + /// ADS1x1x ADC driver + #[derive(Debug)] + pub struct $Ads + where + I2C: embedded_hal::i2c::I2c, + { + pub(crate) iface: I2cInterface, + pub(crate) config: Config, + pub(crate) fsr: FullScaleRange, + pub(crate) a_conversion_was_started: bool, + pub(crate) mode: PhantomData, + } - impl Sealed for ic::Resolution12Bit {} - impl Sealed for ic::Resolution16Bit {} + impl $Ads + where + I2C: embedded_hal::i2c::I2c, + { + /// Create a new instance of the device in one-shot mode. + pub fn new(i2c: I2C, address: SlaveAddr) -> Self { + $Ads { + iface: I2cInterface { + i2c, + address: address.bits(), + }, + config: Config::default(), + fsr: FullScaleRange::default(), + a_conversion_was_started: false, + mode: PhantomData, + } + } + } + impl $Ads + where + I2C: embedded_hal::i2c::I2c, + { + /// Release the contained I²C peripheral. + pub fn release(self) -> I2C { + self.iface.i2c + } + } - impl Sealed for ic::Ads1013 {} - impl Sealed for ic::Ads1113 {} - impl Sealed for ic::Ads1014 {} - impl Sealed for ic::Ads1114 {} - impl Sealed for ic::Ads1015 {} - impl Sealed for ic::Ads1115 {} + impl private::Sealed for $Ads where I2C: embedded_hal::i2c::I2c {} + }; } + +impl_ads1x1x!(Ads1013); +impl_ads1x1x!(Ads1113); +impl_ads1x1x!(Ads1014); +impl_ads1x1x!(Ads1114); +impl_ads1x1x!(Ads1015); +impl_ads1x1x!(Ads1115); diff --git a/src/types.rs b/src/types.rs index 3d7eb2e..5aa0341 100644 --- a/src/types.rs +++ b/src/types.rs @@ -1,11 +1,9 @@ //! Type definitions. -use core::marker::PhantomData; - -use crate::{private, ChannelSelection}; +use crate::{private, BitFlags as BF, ChannelSelection}; /// Errors in this crate -#[derive(Debug)] +#[derive(Debug, PartialEq)] pub enum Error { /// I²C bus error I2C(E), @@ -27,10 +25,12 @@ pub enum ModeChangeError { /// Mode marker types pub mod mode { /// One-shot operating mode / power-down state (default) - pub struct OneShot(()); + #[non_exhaustive] + pub struct OneShot; /// Continuous conversion mode - pub struct Continuous(()); + #[non_exhaustive] + pub struct Continuous; } /// Data rate for ADS1013, ADS1014, ADS1015 @@ -52,6 +52,20 @@ pub enum DataRate12Bit { Sps3300, } +impl DataRate12Bit { + pub(crate) fn configure(self, cfg: &mut Config) { + *cfg = match self { + Self::Sps128 => cfg.with_low(BF::DR2).with_low(BF::DR1).with_low(BF::DR0), + Self::Sps250 => cfg.with_low(BF::DR2).with_low(BF::DR1).with_high(BF::DR0), + Self::Sps490 => cfg.with_low(BF::DR2).with_high(BF::DR1).with_low(BF::DR0), + Self::Sps920 => cfg.with_low(BF::DR2).with_high(BF::DR1).with_high(BF::DR0), + Self::Sps1600 => cfg.with_high(BF::DR2).with_low(BF::DR1).with_low(BF::DR0), + Self::Sps2400 => cfg.with_high(BF::DR2).with_low(BF::DR1).with_high(BF::DR0), + Self::Sps3300 => cfg.with_high(BF::DR2).with_high(BF::DR1).with_low(BF::DR0), + }; + } +} + /// Data rate for ADS1113, ADS1114, ADS1115 #[derive(Debug, Clone, Copy, PartialEq)] pub enum DataRate16Bit { @@ -73,6 +87,21 @@ pub enum DataRate16Bit { Sps860, } +impl DataRate16Bit { + pub(crate) fn configure(self, cfg: &mut Config) { + *cfg = match self { + Self::Sps8 => cfg.with_low(BF::DR2).with_low(BF::DR1).with_low(BF::DR0), + Self::Sps16 => cfg.with_low(BF::DR2).with_low(BF::DR1).with_high(BF::DR0), + Self::Sps32 => cfg.with_low(BF::DR2).with_high(BF::DR1).with_low(BF::DR0), + Self::Sps64 => cfg.with_low(BF::DR2).with_high(BF::DR1).with_high(BF::DR0), + Self::Sps128 => cfg.with_high(BF::DR2).with_low(BF::DR1).with_low(BF::DR0), + Self::Sps250 => cfg.with_high(BF::DR2).with_low(BF::DR1).with_high(BF::DR0), + Self::Sps475 => cfg.with_high(BF::DR2).with_high(BF::DR1).with_low(BF::DR0), + Self::Sps860 => cfg.with_high(BF::DR2).with_high(BF::DR1).with_high(BF::DR0), + }; + } +} + /// Comparator mode (only for ADS1x14, ADS1x15) #[derive(Debug, Clone, Copy, PartialEq)] pub enum ComparatorMode { @@ -182,45 +211,33 @@ impl Default for SlaveAddr { } impl SlaveAddr { - pub(crate) fn addr(self) -> u8 { - match self { - SlaveAddr::Default => crate::DEVICE_BASE_ADDRESS, - SlaveAddr::Alt1 => crate::DEVICE_BASE_ADDRESS + 1, - SlaveAddr::Alt2 => crate::DEVICE_BASE_ADDRESS + 2, - SlaveAddr::Alt3 => crate::DEVICE_BASE_ADDRESS + 3, - } - } - - /// Create `SlaveAddr` instance corresponding to the address - /// effective when connecting the pin `ADDR` to GND (0x48). + /// Address when the ADDR pin is connected to GND (`0x48`). /// /// See [Table 4 in the datasheet](https://www.ti.com/lit/ds/symlink/ads1115.pdf#%5B%7B%22num%22%3A716%2C%22gen%22%3A0%7D%2C%7B%22name%22%3A%22XYZ%22%7D%2C0%2C602.2%2C0%5D). - pub fn new_gnd() -> Self { - SlaveAddr::default() - } + pub const GND: Self = Self::Default; - /// Create `SlaveAddr` instance corresponding to the address - /// effective when connecting the pin `ADDR` to VDD (0x49). + /// Address when the ADDR pin is connected to VDD (`0x49`). /// /// See [Table 4 in the datasheet](https://www.ti.com/lit/ds/symlink/ads1115.pdf#%5B%7B%22num%22%3A716%2C%22gen%22%3A0%7D%2C%7B%22name%22%3A%22XYZ%22%7D%2C0%2C602.2%2C0%5D). - pub fn new_vdd() -> Self { - SlaveAddr::Alt1 - } + pub const VDD: Self = Self::Alt1; - /// Create `SlaveAddr` instance corresponding to the address - /// effective when connecting the pin `ADDR` to SDA (0x4A). + /// Address when the ADDR pin is connected to SDA (`0x4A`). /// /// See [Table 4 in the datasheet](https://www.ti.com/lit/ds/symlink/ads1115.pdf#%5B%7B%22num%22%3A716%2C%22gen%22%3A0%7D%2C%7B%22name%22%3A%22XYZ%22%7D%2C0%2C602.2%2C0%5D). - pub fn new_sda() -> Self { - SlaveAddr::Alt2 - } + pub const SDA: Self = Self::Alt2; - /// Create `SlaveAddr` instance corresponding to the address - /// effective when connecting the pin `ADDR` to SCL (0x4B). + /// Address when the ADDR pin is connected to SCL (`0x4B`). /// /// See [Table 4 in the datasheet](https://www.ti.com/lit/ds/symlink/ads1115.pdf#%5B%7B%22num%22%3A716%2C%22gen%22%3A0%7D%2C%7B%22name%22%3A%22XYZ%22%7D%2C0%2C602.2%2C0%5D). - pub fn new_scl() -> Self { - SlaveAddr::Alt3 + pub const SCL: Self = Self::Alt3; + + pub(crate) const fn bits(self) -> u8 { + match self { + SlaveAddr::Default => 0b1001000, + SlaveAddr::Alt1 => 0b1001001, + SlaveAddr::Alt2 => 0b1001010, + SlaveAddr::Alt3 => 0b1001011, + } } } @@ -253,18 +270,6 @@ impl Default for Config { } } -/// ADS1x1x ADC driver -#[derive(Debug, Default)] -pub struct Ads1x1x { - pub(crate) iface: DI, - pub(crate) config: Config, - pub(crate) fsr: FullScaleRange, - pub(crate) a_conversion_was_started: bool, - pub(crate) _conv: PhantomData, - pub(crate) _ic: PhantomData, - pub(crate) _mode: PhantomData, -} - /// Multi channel One-shot ADC pub trait DynamicOneShot: private::Sealed { /// Error type @@ -281,22 +286,22 @@ mod tests { #[test] fn can_get_default_address() { let addr = SlaveAddr::default(); - assert_eq!(0b100_1000, addr.addr()); + assert_eq!(0b100_1000, addr.bits()); } #[test] fn can_generate_alternative_addresses() { - assert_eq!(0b100_1001, SlaveAddr::Alt1.addr()); - assert_eq!(0b100_1010, SlaveAddr::Alt2.addr()); - assert_eq!(0b100_1011, SlaveAddr::Alt3.addr()); + assert_eq!(0b100_1001, SlaveAddr::Alt1.bits()); + assert_eq!(0b100_1010, SlaveAddr::Alt2.bits()); + assert_eq!(0b100_1011, SlaveAddr::Alt3.bits()); } #[test] fn can_generate_alternative_addresses_using_helper_constructors() { - assert_eq!(0b100_1000, SlaveAddr::new_gnd().addr()); - assert_eq!(0b100_1001, SlaveAddr::new_vdd().addr()); - assert_eq!(0b100_1010, SlaveAddr::new_sda().addr()); - assert_eq!(0b100_1011, SlaveAddr::new_scl().addr()); + assert_eq!(0b100_1000, SlaveAddr::GND.bits()); + assert_eq!(0b100_1001, SlaveAddr::VDD.bits()); + assert_eq!(0b100_1010, SlaveAddr::SDA.bits()); + assert_eq!(0b100_1011, SlaveAddr::SCL.bits()); } #[test] diff --git a/tests/common/mod.rs b/tests/common/mod.rs index 429479c..8937baf 100644 --- a/tests/common/mod.rs +++ b/tests/common/mod.rs @@ -1,4 +1,4 @@ -use ads1x1x::{ic, interface, mode, Ads1x1x, SlaveAddr}; +use ads1x1x::{mode, Ads1013, Ads1014, Ads1015, Ads1113, Ads1114, Ads1115, SlaveAddr}; use embedded_hal_mock::eh1::i2c::{Mock as I2cMock, Transaction as I2cTrans}; #[allow(unused)] @@ -67,38 +67,31 @@ impl Default for Config { } macro_rules! impl_new_destroy { - ($ic:ident, $create:ident, $destroy:ident, $conv:ty, $trans:ty, $iface:ty) => { + ($Ads:ident, $create:ident, $destroy:ident, $trans:ty) => { #[allow(unused)] - pub fn $create(transactions: &[$trans]) -> Ads1x1x<$iface, ic::$ic, $conv, mode::OneShot> { - Ads1x1x::$create(I2cMock::new(transactions), SlaveAddr::default()) + pub fn $create(transactions: &[$trans]) -> $Ads { + $Ads::new(I2cMock::new(transactions), SlaveAddr::default()) } #[allow(unused)] - pub fn $destroy(dev: Ads1x1x<$iface, ic::$ic, $conv, MODE>) { - dev.$destroy().done(); + pub fn $destroy(dev: $Ads) { + dev.release().done(); } }; } macro_rules! impl_new_destroy_i2c { - ($ic:ident, $create:ident, $destroy:ident, $conv:ty) => { - impl_new_destroy!( - $ic, - $create, - $destroy, - $conv, - I2cTrans, - interface::I2cInterface - ); + ($Ads:ident, $create:ident, $destroy:ident) => { + impl_new_destroy!($Ads, $create, $destroy, I2cTrans); }; } -impl_new_destroy_i2c!(Ads1013, new_ads1013, destroy_ads1013, ic::Resolution12Bit); -impl_new_destroy_i2c!(Ads1113, new_ads1113, destroy_ads1113, ic::Resolution16Bit); -impl_new_destroy_i2c!(Ads1014, new_ads1014, destroy_ads1014, ic::Resolution12Bit); -impl_new_destroy_i2c!(Ads1114, new_ads1114, destroy_ads1114, ic::Resolution16Bit); -impl_new_destroy_i2c!(Ads1015, new_ads1015, destroy_ads1015, ic::Resolution12Bit); -impl_new_destroy_i2c!(Ads1115, new_ads1115, destroy_ads1115, ic::Resolution16Bit); +impl_new_destroy_i2c!(Ads1013, new_ads1013, destroy_ads1013); +impl_new_destroy_i2c!(Ads1113, new_ads1113, destroy_ads1113); +impl_new_destroy_i2c!(Ads1014, new_ads1014, destroy_ads1014); +impl_new_destroy_i2c!(Ads1114, new_ads1114, destroy_ads1114); +impl_new_destroy_i2c!(Ads1015, new_ads1015, destroy_ads1015); +impl_new_destroy_i2c!(Ads1115, new_ads1115, destroy_ads1115); #[macro_export] macro_rules! assert_would_block { diff --git a/tests/construction.rs b/tests/construction.rs index 6d56526..ef2735b 100644 --- a/tests/construction.rs +++ b/tests/construction.rs @@ -10,7 +10,7 @@ macro_rules! impl_tests { use super::*; #[test] fn can_create() { - let dev = $create(&[]); + let i2c = $create(&[]); $destroy(dev); } } diff --git a/tests/mux.rs b/tests/mux.rs index 8b851a9..29f9cb1 100644 --- a/tests/mux.rs +++ b/tests/mux.rs @@ -31,7 +31,7 @@ macro_rules! mux_test { ), I2cTrans::write_read(DEV_ADDR, vec![Register::CONVERSION], vec![0x80, 0x00]), ]; - let mut dev = new(&transactions); + let mut i2c = new(&transactions); let measurement = block!(dev.read(ChannelSelection::$CS)).unwrap(); assert_eq!(-2048, measurement); destroy(dev); @@ -65,7 +65,7 @@ macro_rules! mux_test { ), I2cTrans::write_read(DEV_ADDR, vec![Register::CONVERSION], vec![0x80, 0x00]), ]; - let mut dev = new(&transactions); + let mut i2c = new(&transactions); assert_would_block!(dev.read(ChannelSelection::$CS)); let measurement = block!(dev.read(ChannelSelection::$other_CS)).unwrap(); assert_eq!(-2048, measurement); @@ -86,8 +86,8 @@ macro_rules! mux_test { vec![Register::CONFIG, config2.msb(), config2.lsb()], ), ]; - let dev = new(&transactions); - let mut dev = dev.into_continuous().ok().unwrap(); + let i2c = new(&transactions); + let mut i2c = dev.into_continuous().ok().unwrap(); dev.select_channel(ChannelSelection::$CS).unwrap(); destroy(dev); } diff --git a/tests/tier1.rs b/tests/tier1.rs index 0ddd6fc..5fe1e08 100644 --- a/tests/tier1.rs +++ b/tests/tier1.rs @@ -24,7 +24,7 @@ macro_rules! measure_tests { vec![Register::CONFIG], vec![config.msb(), config.lsb()], )]; - let mut dev = $create(&transactions); + let mut i2c = $create(&transactions); assert_would_block!(dev.read(ChannelSelection::DifferentialA0A1)); $destroy(dev); } @@ -51,7 +51,7 @@ macro_rules! measure_tests { ), I2cTrans::write_read(DEV_ADDR, vec![Register::CONVERSION], vec![0x80, 0x00]), ]; - let mut dev = $create(&transactions); + let mut i2c = $create(&transactions); let measurement = block!(dev.read(ChannelSelection::DifferentialA0A1)).unwrap(); assert_eq!($expected, measurement); $destroy(dev); @@ -64,8 +64,8 @@ macro_rules! measure_tests { I2cTrans::write(DEV_ADDR, vec![Register::CONFIG, config.msb(), config.lsb()]), I2cTrans::write_read(DEV_ADDR, vec![Register::CONVERSION], vec![0x80, 0x00]), ]; - let dev = $create(&transactions); - let mut dev = dev.into_continuous().ok().unwrap(); + let i2c = $create(&transactions); + let mut i2c = dev.into_continuous().ok().unwrap(); let measurement = dev.read().unwrap(); assert_eq!($expected, measurement); $destroy(dev); @@ -88,7 +88,7 @@ mod data_rate_12bit { DEV_ADDR, vec![Register::CONFIG, $config.msb(), $config.lsb()], )]; - let mut dev = new_ads1013(&transactions); + let mut i2c = new_ads1013(&transactions); dev.set_data_rate(DataRate12Bit::$variant).unwrap(); destroy_ads1013(dev); } @@ -164,7 +164,7 @@ mod data_rate_16bit { DEV_ADDR, vec![Register::CONFIG, $config.msb(), $config.lsb()], )]; - let mut dev = new_ads1113(&transactions); + let mut i2c = new_ads1113(&transactions); dev.set_data_rate(DataRate16Bit::$variant).unwrap(); destroy_ads1113(dev); } @@ -245,7 +245,7 @@ fn can_read_measurement_in_progress() { vec![Register::CONFIG], vec![config_os.msb(), config_os.lsb()], )]; - let mut dev = new_ads1013(&transactions); + let mut i2c = new_ads1013(&transactions); assert!(dev.is_measurement_in_progress().unwrap()); destroy_ads1013(dev); } @@ -258,7 +258,7 @@ fn can_read_measurement_not_in_progress() { vec![Register::CONFIG], vec![config_os.msb(), config_os.lsb()], )]; - let mut dev = new_ads1013(&transactions); + let mut i2c = new_ads1013(&transactions); assert!(!dev.is_measurement_in_progress().unwrap()); destroy_ads1013(dev); } @@ -270,8 +270,8 @@ fn can_convert_to_continuous() { DEV_ADDR, vec![Register::CONFIG, config.msb(), config.lsb()], )]; - let dev = new_ads1013(&transactions); - let dev = dev.into_continuous().ok().unwrap(); + let i2c = new_ads1013(&transactions); + let i2c = dev.into_continuous().ok().unwrap(); destroy_ads1013(dev); } @@ -289,8 +289,8 @@ fn can_convert_to_one_shot() { vec![Register::CONFIG, config_os.msb(), config_os.lsb()], ), ]; - let dev = new_ads1013(&transactions); - let dev = dev.into_continuous().ok().unwrap(); - let dev = dev.into_one_shot().ok().unwrap(); + let i2c = new_ads1013(&transactions); + let i2c = dev.into_continuous().ok().unwrap(); + let i2c = dev.into_one_shot().ok().unwrap(); destroy_ads1013(dev); } diff --git a/tests/tier2.rs b/tests/tier2.rs index 7d3a54f..79406a4 100644 --- a/tests/tier2.rs +++ b/tests/tier2.rs @@ -13,7 +13,7 @@ macro_rules! set_value_test { #[test] fn $name() { let transactions = [I2cTrans::write(DEV_ADDR, vec![Register::$reg, $msb, $lsb])]; - let mut dev = new_ads1014(&transactions); + let mut i2c = new_ads1014(&transactions); dev.$method($value).unwrap(); destroy_ads1014(dev); } @@ -89,7 +89,7 @@ fn can_disable_comparator() { DEV_ADDR, vec![Register::CONFIG, config.msb(), config.lsb()], )]; - let mut dev = new_ads1014(&transactions); + let mut i2c = new_ads1014(&transactions); dev.disable_comparator().unwrap(); destroy_ads1014(dev); } @@ -128,7 +128,7 @@ fn can_use_alert_rdy_pin_as_rdy_does_not_disable_comparator_if_already_disabled( I2cTrans::write(DEV_ADDR, vec![Register::HIGH_TH, 0b1000_0000, 0]), I2cTrans::write(DEV_ADDR, vec![Register::LOW_TH, 0, 0]), ]; - let mut dev = new_ads1014(&transactions); + let mut i2c = new_ads1014(&transactions); dev.use_alert_rdy_pin_as_ready().unwrap(); destroy_ads1014(dev); } @@ -154,7 +154,7 @@ fn can_use_alert_rdy_pin_as_rdy_disabled_comparator() { I2cTrans::write(DEV_ADDR, vec![Register::HIGH_TH, 0b1000_0000, 0]), I2cTrans::write(DEV_ADDR, vec![Register::LOW_TH, 0, 0]), ]; - let mut dev = new_ads1014(&transactions); + let mut i2c = new_ads1014(&transactions); dev.set_comparator_queue(ComparatorQueue::One).unwrap(); dev.use_alert_rdy_pin_as_ready().unwrap(); destroy_ads1014(dev);