From 6c12cc8833f794d34711fc4e36ea79b4c93c74d1 Mon Sep 17 00:00:00 2001 From: Markus Reiter Date: Thu, 18 Jan 2024 14:05:49 +0100 Subject: [PATCH] Re-add channel-specific types. --- README.md | 4 +- examples/all_channels.rs | 10 ++-- examples/linux.rs | 4 +- examples/typed.rs | 5 +- src/channel.rs | 96 ++++++++++++++++++++++++++++++++++ src/channels.rs | 62 ---------------------- src/devices/mode/continuous.rs | 8 +-- src/devices/mode/oneshot.rs | 10 ++-- src/lib.rs | 8 +-- tests/mux.rs | 10 ++-- tests/tier1.rs | 6 +-- 11 files changed, 129 insertions(+), 94 deletions(-) create mode 100644 src/channel.rs delete mode 100644 src/channels.rs diff --git a/README.md b/README.md index ebabc3f..024b8e9 100644 --- a/README.md +++ b/README.md @@ -80,13 +80,13 @@ Please find additional examples using hardware in this repository: [driver-examp use linux_embedded_hal::I2cdev; use nb::block; -use ads1x1x::{Ads1x1x, SlaveAddr, ChannelSelection}; +use ads1x1x::{channel, Ads1x1x, SlaveAddr}; fn main() { let dev = I2cdev::new("/dev/i2c-1").unwrap(); let address = SlaveAddr::default(); let mut adc = Ads1x1x::new_ads1013(dev, address); - let value = block!(adc.read(ChannelSelection::DifferentialA0A1)).unwrap(); + let value = block!(adc.read(channel::DifferentialA0A1)).unwrap(); println!("Measurement: {}", value); // get I2C device back let _dev = adc.destroy_ads1013(); diff --git a/examples/all_channels.rs b/examples/all_channels.rs index 1e2a5db..ddf8326 100644 --- a/examples/all_channels.rs +++ b/examples/all_channels.rs @@ -1,17 +1,17 @@ use linux_embedded_hal::I2cdev; use nb::block; -use ads1x1x::{Ads1x1x, ChannelSelection, SlaveAddr}; +use ads1x1x::{channel, Ads1x1x, SlaveAddr}; fn main() { let dev = I2cdev::new("/dev/i2c-1").unwrap(); let address = SlaveAddr::default(); let mut adc = Ads1x1x::new_ads1015(dev, address); let values = [ - block!(adc.read(ChannelSelection::SingleA0)).unwrap(), - block!(adc.read(ChannelSelection::SingleA1)).unwrap(), - block!(adc.read(ChannelSelection::SingleA2)).unwrap(), - block!(adc.read(ChannelSelection::SingleA3)).unwrap(), + block!(adc.read(channel::SingleA0)).unwrap(), + block!(adc.read(channel::SingleA1)).unwrap(), + block!(adc.read(channel::SingleA2)).unwrap(), + block!(adc.read(channel::SingleA3)).unwrap(), ]; for (channel, value) in values.iter().enumerate() { println!("Channel {}: {}", channel, value); diff --git a/examples/linux.rs b/examples/linux.rs index 471d19c..55eab64 100644 --- a/examples/linux.rs +++ b/examples/linux.rs @@ -1,13 +1,13 @@ use linux_embedded_hal::I2cdev; use nb::block; -use ads1x1x::{Ads1x1x, ChannelSelection, SlaveAddr}; +use ads1x1x::{channel, Ads1x1x, SlaveAddr}; fn main() { let dev = I2cdev::new("/dev/i2c-1").unwrap(); let address = SlaveAddr::default(); let mut adc = Ads1x1x::new_ads1013(dev, address); - let value = block!(adc.read(ChannelSelection::DifferentialA0A1)).unwrap(); + let value = block!(adc.read(channel::DifferentialA0A1)).unwrap(); println!("Measurement: {}", value); // get I2C device back let _dev = adc.destroy_ads1013(); diff --git a/examples/typed.rs b/examples/typed.rs index ba40ed4..6d6961c 100644 --- a/examples/typed.rs +++ b/examples/typed.rs @@ -5,9 +5,10 @@ use linux_embedded_hal::I2cdev; use nb::block; use ads1x1x::{ + channel, ic::{Ads1115, Resolution16Bit}, interface::I2cInterface, - Ads1x1x, ChannelSelection, SlaveAddr, + Ads1x1x, SlaveAddr, }; /// Type alias @@ -16,7 +17,7 @@ type Adc = Ads1x1x, Ads1115, Resolution16Bit, ads1x1x::mode /// Read a single value from channel A. /// Returns 0 on Error. pub fn read(adc: &mut Adc) -> i16 { - block!(adc.read(ChannelSelection::SingleA0)).unwrap_or(0) + block!(adc.read(channel::SingleA0)).unwrap_or(0) } fn main() { diff --git a/src/channel.rs b/src/channel.rs new file mode 100644 index 0000000..6abb2bc --- /dev/null +++ b/src/channel.rs @@ -0,0 +1,96 @@ +//! ADC input channels +use crate::{ic, Ads1x1x, BitFlags as BF, Config}; + +use private::ChannelSelection; + +/// Marker type for an ADC input channel. +pub trait Channel { + /// Get the channel. + fn channel(self) -> ChannelSelection; +} + +macro_rules! impl_channels { + ($(#[doc = $doc:expr] $CH:ident => [$($IC:ident),+]),+ $(,)?) => { + mod private { + #[derive(Debug, Clone, Copy)] + /// ADC input channel selection. + pub enum ChannelSelection { + $( + #[doc = $doc] + $CH, + )+ + } + } + + $( + #[doc = $doc] + pub struct $CH; + + $( + impl Channel> for $CH { + fn channel(self) -> ChannelSelection { + ChannelSelection::$CH + } + } + )+ + )+ + }; +} + +impl_channels!( + /// Measure signal on input channel 0 differentially to signal on input channel 1. + DifferentialA0A1 => [Ads1013, Ads1014, Ads1015, Ads1113, Ads1114, Ads1115], + /// Measure signal on input channel 0 differentially to signal on input channel 3. + DifferentialA0A3 => [Ads1015, Ads1115], + /// Measure signal on input channel 1 differentially to signal on input channel 3. + DifferentialA1A3 => [Ads1015, Ads1115], + /// Measure signal on input channel 3 differentially to signal on input channel 3. + DifferentialA2A3 => [Ads1015, Ads1115], + /// Measure single-ended signal on input channel 0. + SingleA0 => [Ads1015, Ads1115], + /// Measure single-ended signal on input channel 1. + SingleA1 => [Ads1015, Ads1115], + /// Measure single-ended signal on input channel 2. + SingleA2 => [Ads1015, Ads1115], + /// Measure single-ended signal on input channel 3. + SingleA3 => [Ads1015, Ads1115] +); + +impl Config { + pub(crate) fn with_mux_bits(&self, ch: ChannelSelection) -> Self { + match ch { + ChannelSelection::DifferentialA0A1 => self + .with_low(BF::MUX2) + .with_low(BF::MUX1) + .with_low(BF::MUX0), + ChannelSelection::DifferentialA0A3 => self + .with_low(BF::MUX2) + .with_low(BF::MUX1) + .with_high(BF::MUX0), + ChannelSelection::DifferentialA1A3 => self + .with_low(BF::MUX2) + .with_high(BF::MUX1) + .with_low(BF::MUX0), + ChannelSelection::DifferentialA2A3 => self + .with_low(BF::MUX2) + .with_high(BF::MUX1) + .with_high(BF::MUX0), + ChannelSelection::SingleA0 => self + .with_high(BF::MUX2) + .with_low(BF::MUX1) + .with_low(BF::MUX0), + ChannelSelection::SingleA1 => self + .with_high(BF::MUX2) + .with_low(BF::MUX1) + .with_high(BF::MUX0), + ChannelSelection::SingleA2 => self + .with_high(BF::MUX2) + .with_high(BF::MUX1) + .with_low(BF::MUX0), + ChannelSelection::SingleA3 => self + .with_high(BF::MUX2) + .with_high(BF::MUX1) + .with_high(BF::MUX0), + } + } +} diff --git a/src/channels.rs b/src/channels.rs deleted file mode 100644 index 96a1197..0000000 --- a/src/channels.rs +++ /dev/null @@ -1,62 +0,0 @@ -//! ADC input channels -use crate::{BitFlags as BF, Config}; - -/// ADC input channel selection -#[derive(Debug, Clone, Copy)] -pub enum ChannelSelection { - /// Measure single-ended signal on input channel 0 - SingleA0, - /// Measure single-ended signal on input channel 1 - SingleA1, - /// Measure single-ended signal on input channel 2 - SingleA2, - /// Measure single-ended signal on input channel 3 - SingleA3, - /// Measure signal on input channel 0 differentially to signal on input channel 1 - DifferentialA0A1, - /// Measure signal on input channel 0 differentially to signal on input channel 3 - DifferentialA0A3, - /// Measure signal on input channel 1 differentially to signal on input channel 3 - DifferentialA1A3, - /// Measure signal on input channel 2 differentially to signal on input channel 3 - DifferentialA2A3, -} - -impl Config { - pub(crate) fn with_mux_bits(&self, ch: ChannelSelection) -> Self { - match ch { - ChannelSelection::DifferentialA0A1 => self - .with_low(BF::MUX2) - .with_low(BF::MUX1) - .with_low(BF::MUX0), - ChannelSelection::DifferentialA0A3 => self - .with_low(BF::MUX2) - .with_low(BF::MUX1) - .with_high(BF::MUX0), - ChannelSelection::DifferentialA1A3 => self - .with_low(BF::MUX2) - .with_high(BF::MUX1) - .with_low(BF::MUX0), - ChannelSelection::DifferentialA2A3 => self - .with_low(BF::MUX2) - .with_high(BF::MUX1) - .with_high(BF::MUX0), - ChannelSelection::SingleA0 => self - .with_high(BF::MUX2) - .with_low(BF::MUX1) - .with_low(BF::MUX0), - ChannelSelection::SingleA1 => self - .with_high(BF::MUX2) - .with_low(BF::MUX1) - .with_high(BF::MUX0), - ChannelSelection::SingleA2 => self - .with_high(BF::MUX2) - .with_high(BF::MUX1) - .with_low(BF::MUX0), - ChannelSelection::SingleA3 => self - .with_high(BF::MUX2) - .with_high(BF::MUX1) - .with_high(BF::MUX0), - } - } -} diff --git a/src/devices/mode/continuous.rs b/src/devices/mode/continuous.rs index 1dca71e..d82ec6a 100644 --- a/src/devices/mode/continuous.rs +++ b/src/devices/mode/continuous.rs @@ -1,8 +1,8 @@ //! Continuous measurement mode use crate::{ - channels::ChannelSelection, conversion, devices::OperatingMode, interface, mode, Ads1x1x, - Error, ModeChangeError, Register, + conversion, devices::OperatingMode, interface, mode, Ads1x1x, Channel, Error, ModeChangeError, + Register, }; use core::marker::PhantomData; @@ -40,8 +40,8 @@ where /// 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); + pub fn select_channel>(&mut self, channel: CH) -> Result<(), Error> { + let config = self.config.with_mux_bits(channel.channel()); self.iface.write_register(Register::CONFIG, config.bits)?; self.config = config; Ok(()) diff --git a/src/devices/mode/oneshot.rs b/src/devices/mode/oneshot.rs index 8679fe1..75464e5 100644 --- a/src/devices/mode/oneshot.rs +++ b/src/devices/mode/oneshot.rs @@ -1,7 +1,7 @@ //! Common functions use crate::{ - conversion, devices::OperatingMode, interface, mode, Ads1x1x, BitFlags, ChannelSelection, - Config, Error, ModeChangeError, Register, + conversion, devices::OperatingMode, interface, mode, Ads1x1x, BitFlags, Channel, Config, Error, + ModeChangeError, Register, }; use core::marker::PhantomData; @@ -52,14 +52,15 @@ where /// 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> { + pub fn read>(&mut self, channel: CH) -> 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); + let config = self.config.with_mux_bits(channel.channel()); + let same_channel = self.config == config; if self.a_conversion_was_started && same_channel { // result is ready let value = self @@ -69,7 +70,6 @@ where 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; diff --git a/src/lib.rs b/src/lib.rs index 23cecfc..4a5cc6d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -128,13 +128,13 @@ //! //! ### Make a one-shot measurement //! ```no_run -//! use ads1x1x::{Ads1x1x, SlaveAddr, ChannelSelection}; +//! use ads1x1x::{channel, Ads1x1x, SlaveAddr}; //! 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 measurement = block!(adc.read(channel::DifferentialA0A1)).unwrap(); //! println!("Measurement: {}", measurement); //! let _dev = adc.destroy_ads1013(); // get I2C device back //! ``` @@ -234,8 +234,8 @@ impl BitFlags { const COMP_QUE0: u16 = 0b0000_0000_0000_0001; } -mod channels; -pub use crate::channels::ChannelSelection; +pub mod channel; +pub use channel::Channel; mod construction; mod conversion; pub use crate::conversion::{ConvertMeasurement, ConvertThreshold}; diff --git a/tests/mux.rs b/tests/mux.rs index 8b851a9..ac335b5 100644 --- a/tests/mux.rs +++ b/tests/mux.rs @@ -1,4 +1,4 @@ -use ads1x1x::ChannelSelection; +use ads1x1x::channel; use embedded_hal_mock::eh1::i2c::Transaction as I2cTrans; use nb::block; @@ -32,7 +32,7 @@ macro_rules! mux_test { I2cTrans::write_read(DEV_ADDR, vec![Register::CONVERSION], vec![0x80, 0x00]), ]; let mut dev = new(&transactions); - let measurement = block!(dev.read(ChannelSelection::$CS)).unwrap(); + let measurement = block!(dev.read(channel::$CS)).unwrap(); assert_eq!(-2048, measurement); destroy(dev); } @@ -66,8 +66,8 @@ macro_rules! mux_test { I2cTrans::write_read(DEV_ADDR, vec![Register::CONVERSION], vec![0x80, 0x00]), ]; let mut dev = new(&transactions); - assert_would_block!(dev.read(ChannelSelection::$CS)); - let measurement = block!(dev.read(ChannelSelection::$other_CS)).unwrap(); + assert_would_block!(dev.read(channel::$CS)); + let measurement = block!(dev.read(channel::$other_CS)).unwrap(); assert_eq!(-2048, measurement); destroy(dev); } @@ -88,7 +88,7 @@ macro_rules! mux_test { ]; let dev = new(&transactions); let mut dev = dev.into_continuous().ok().unwrap(); - dev.select_channel(ChannelSelection::$CS).unwrap(); + dev.select_channel(channel::$CS).unwrap(); destroy(dev); } } diff --git a/tests/tier1.rs b/tests/tier1.rs index 0ddd6fc..bbe9d6f 100644 --- a/tests/tier1.rs +++ b/tests/tier1.rs @@ -1,4 +1,4 @@ -use ads1x1x::{ChannelSelection, DataRate12Bit, DataRate16Bit}; +use ads1x1x::{channel, DataRate12Bit, DataRate16Bit}; use embedded_hal_mock::eh1::i2c::Transaction as I2cTrans; use nb::block; @@ -25,7 +25,7 @@ macro_rules! measure_tests { vec![config.msb(), config.lsb()], )]; let mut dev = $create(&transactions); - assert_would_block!(dev.read(ChannelSelection::DifferentialA0A1)); + assert_would_block!(dev.read(channel::DifferentialA0A1)); $destroy(dev); } } @@ -52,7 +52,7 @@ macro_rules! measure_tests { I2cTrans::write_read(DEV_ADDR, vec![Register::CONVERSION], vec![0x80, 0x00]), ]; let mut dev = $create(&transactions); - let measurement = block!(dev.read(ChannelSelection::DifferentialA0A1)).unwrap(); + let measurement = block!(dev.read(channel::DifferentialA0A1)).unwrap(); assert_eq!($expected, measurement); $destroy(dev); }