From 5e32dac1b9066f55d7d7fddf300769c40a11c88d Mon Sep 17 00:00:00 2001 From: Markus Reiter Date: Fri, 12 Jan 2024 20:24:51 +0100 Subject: [PATCH 01/14] Use `non_exhaustive`. --- src/ic.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/ic.rs b/src/ic.rs index 56dfc6a..8e4db42 100644 --- a/src/ic.rs +++ b/src/ic.rs @@ -1,8 +1,10 @@ /// ICs use crate::private; -pub struct Resolution12Bit(pub(crate) ()); -pub struct Resolution16Bit(pub(crate) ()); +#[non_exhaustive] +pub struct Resolution12Bit; +#[non_exhaustive] +pub struct Resolution16Bit; macro_rules! ic_marker { ($name:ident) => { From 57dc7d833e424fe440437855e6a666f8b8f28254 Mon Sep 17 00:00:00 2001 From: Markus Reiter Date: Sat, 13 Jan 2024 20:05:57 +0100 Subject: [PATCH 02/14] Improve docs. --- CHANGELOG.md | 2 +- README.md | 5 ++-- src/channel.rs | 3 +- src/devices/common.rs | 4 +-- src/devices/features/mod.rs | 3 +- src/devices/features/tier1.rs | 6 ++-- src/devices/features/tier2.rs | 54 +++++++++++++++++----------------- src/devices/mode/continuous.rs | 8 ++--- src/devices/mode/mod.rs | 2 -- src/devices/mode/oneshot.rs | 13 ++++---- src/lib.rs | 28 ++++++++++-------- src/types.rs | 14 ++++----- 12 files changed, 71 insertions(+), 71 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 788abc2..28f41cc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -49,7 +49,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. When changing into continuous mode the measurements are started and to stop one can simply change into one-shot mode. (This is how the hardware does it anyway). The one-shot mode is not affected. - When changing the mode an I2C communication error can occur but the unchanged device + When changing the mode an I²C communication error can occur but the unchanged device can now be retrieved. ## [0.1.0] - 2018-11-21 diff --git a/README.md b/README.md index 9ef686d..0ba4f49 100644 --- a/README.md +++ b/README.md @@ -48,7 +48,7 @@ thermocouples. The devices operate either in continuous-conversion mode, or in a single-shot mode that automatically powers down after a conversion. Single-shot mode significantly reduces current consumption during idle -periods. Data is transferred through I2C. +periods. Data is transferred through I²C. Here is a comparison of the caracteristics of the devices: @@ -70,8 +70,7 @@ 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] diff --git a/src/channel.rs b/src/channel.rs index 4b7555e..4d6e028 100644 --- a/src/channel.rs +++ b/src/channel.rs @@ -1,4 +1,5 @@ -//! ADC input channels +//! ADC input channels. + use crate::{ic, Ads1x1x, BitFlags as BF, Config}; use private::ChannelSelection; diff --git a/src/devices/common.rs b/src/devices/common.rs index 53cb050..66a6d97 100644 --- a/src/devices/common.rs +++ b/src/devices/common.rs @@ -1,4 +1,4 @@ -//! Common functions +//! Common functions. use crate::{devices::OperatingMode, Ads1x1x, BitFlags, Config, Error, Register}; @@ -30,7 +30,7 @@ where Ok(()) } - /// Read whether a measurement is currently in progress. + /// Checks whether a measurement is currently in progress. pub fn is_measurement_in_progress(&mut self) -> Result> { let config = Config { bits: self.read_register(Register::CONFIG)?, diff --git a/src/devices/features/mod.rs b/src/devices/features/mod.rs index c24b7b4..e64f25a 100644 --- a/src/devices/features/mod.rs +++ b/src/devices/features/mod.rs @@ -1,5 +1,4 @@ -//! Implementation of IC features separated in tiers depending on the hardware -//! support. +//! 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 index c6aa8cd..3a8beb9 100644 --- a/src/devices/features/tier1.rs +++ b/src/devices/features/tier1.rs @@ -1,4 +1,4 @@ -//! Common functions +//! Features supported on all ADS1x1x devices. use crate::{ic, Ads1x1x, BitFlags as BF, DataRate12Bit, DataRate16Bit, Error, Register}; @@ -6,7 +6,7 @@ impl Ads1x1x where I2C: embedded_hal::i2c::I2c, { - /// Set data rate + /// Sets the data rate. pub fn set_data_rate(&mut self, rate: DataRate12Bit) -> Result<(), Error> { use crate::DataRate12Bit as DR; let cfg = self.config.clone(); @@ -29,7 +29,7 @@ impl Ads1x1x where I2C: embedded_hal::i2c::I2c, { - /// Set data rate + /// Sets the data rate. pub fn set_data_rate(&mut self, rate: DataRate16Bit) -> Result<(), Error> { use crate::DataRate16Bit as DR; let cfg = self.config.clone(); diff --git a/src/devices/features/tier2.rs b/src/devices/features/tier2.rs index 5f25b41..fe36a72 100644 --- a/src/devices/features/tier2.rs +++ b/src/devices/features/tier2.rs @@ -1,6 +1,4 @@ -//! Tier 2 features. -//! -//! These are the features included only in ADS1x14, ADS1x15 +//! Features only supported by ADS1x14 and ADS1x15 devices. use crate::{ conversion, ic, Ads1x1x, BitFlags as BF, ComparatorLatching, ComparatorMode, @@ -13,9 +11,9 @@ where IC: ic::Tier2Features, CONV: conversion::ConvertThreshold, { - /// Set the input voltage measurable range + /// Sets the input voltage measurable range. /// - /// This configures the programmable gain amplifier and determines the measurable input voltage 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(); @@ -47,29 +45,31 @@ where Ok(()) } - /// Set raw comparator lower threshold + /// Sets the raw comparator lower threshold. + /// + /// The voltage that these values correspond to must be calculated using the + /// full-scale range ([`FullScaleRange`]) selected. /// /// 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). + /// and within `[32767..-32768]` for 16-bit devices (`ADS111x`). pub fn set_low_threshold_raw(&mut self, value: i16) -> Result<(), Error> { let register_value = CONV::convert_threshold(value)?; self.write_register(Register::LOW_TH, register_value) } - /// Set raw comparator upper threshold + /// Sets the raw comparator upper threshold. + /// + /// The voltage that these values correspond to must be calculated using the + /// full-scale range ([`FullScaleRange`]) selected. /// /// 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). + /// and within `[32767..-32768]` for 16-bit devices (`ADS111x`). pub fn set_high_threshold_raw(&mut self, value: i16) -> Result<(), Error> { let register_value = CONV::convert_threshold(value)?; self.write_register(Register::HIGH_TH, register_value) } - /// Set comparator mode + /// 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), @@ -80,7 +80,7 @@ where Ok(()) } - /// Set comparator polarity + /// Sets the comparator polarity. pub fn set_comparator_polarity( &mut self, polarity: ComparatorPolarity, @@ -94,7 +94,7 @@ where Ok(()) } - /// Set comparator latching + /// Sets the comparator latching. pub fn set_comparator_latching( &mut self, latching: ComparatorLatching, @@ -108,9 +108,9 @@ where Ok(()) } - /// Activate comparator and set the alert queue + /// Activates the comparator and sets the alert queue. /// - /// The comparator can be disabled with [`disable_comparator()`](struct.Ads1x1x.html#method.disable_comparator) + /// 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), @@ -122,11 +122,12 @@ where Ok(()) } - /// Disable comparator (default) + /// Disables the comparator. (default) + /// + /// This sets the ALERT/RDY pin to high-impedance. /// - /// 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) + /// The comparator can be enabled by setting the comparator queue using + /// the [`set_comparator_queue`](Self::set_comparator_queue) method. pub fn disable_comparator(&mut self) -> Result<(), Error> { let config = self .config @@ -137,13 +138,12 @@ where Ok(()) } - /// Use the ALERT/RDY pin as conversion-ready pin. + /// Enables the ALERT/RDY pin as conversion-ready function. /// - /// 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 in one-shot mode, this makes the ALERT/RDY pin output the OS bit, + /// in continuous-conversion mode, provides a continuous-conversion ready pulse. /// - /// When calling this the comparator will be reset to default and the thresholds will be cleared. + /// When calling this the comparator will be reset to default and any thresholds will be cleared. pub fn use_alert_rdy_pin_as_ready(&mut self) -> Result<(), Error> { if self.config != self diff --git a/src/devices/mode/continuous.rs b/src/devices/mode/continuous.rs index edc87c2..d514a9a 100644 --- a/src/devices/mode/continuous.rs +++ b/src/devices/mode/continuous.rs @@ -1,4 +1,4 @@ -//! Continuous measurement mode +//! Continuous measurement mode. use crate::{ conversion, devices::OperatingMode, mode, Ads1x1x, ChannelId, Error, ModeChangeError, Register, @@ -10,7 +10,7 @@ where I2C: embedded_hal::i2c::I2c, CONV: conversion::ConvertMeasurement, { - /// Change operating mode to OneShot + /// Changes to one-shot operating mode. pub fn into_one_shot( mut self, ) -> Result, ModeChangeError> { @@ -29,13 +29,13 @@ where }) } - /// Read the most recent measurement + /// Reads the most recent measurement. pub fn read(&mut self) -> Result> { let value = self.read_register(Register::CONVERSION)?; Ok(CONV::convert_measurement(value)) } - /// Select the channel for measurements. + /// Selects the channel used for measurements. /// /// Note that when changing the channel in continuous conversion mode, the /// ongoing conversion will be completed. diff --git a/src/devices/mode/mod.rs b/src/devices/mode/mod.rs index 670ebe9..356c67a 100644 --- a/src/devices/mode/mod.rs +++ b/src/devices/mode/mod.rs @@ -1,4 +1,2 @@ -//! Functions for all devices specific to each operating mode - mod continuous; mod oneshot; diff --git a/src/devices/mode/oneshot.rs b/src/devices/mode/oneshot.rs index 10cdadb..22b6d51 100644 --- a/src/devices/mode/oneshot.rs +++ b/src/devices/mode/oneshot.rs @@ -1,16 +1,18 @@ -//! Common functions +//! One-shot measurement mode. + +use core::marker::PhantomData; + use crate::{ conversion, devices::OperatingMode, mode, Ads1x1x, BitFlags, ChannelId, Config, Error, ModeChangeError, Register, }; -use core::marker::PhantomData; impl Ads1x1x where I2C: embedded_hal::i2c::I2c, CONV: conversion::ConvertMeasurement, { - /// Change operating mode to Continuous + /// Changes to continuous operating mode. pub fn into_continuous( mut self, ) -> Result, ModeChangeError> { @@ -40,13 +42,12 @@ where I2C: embedded_hal::i2c::I2c, CONV: conversion::ConvertMeasurement, { - /// Request that the ADC begin a conversion on the specified channel. + /// 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 selected. - /// See [`FullScaleRange`](enum.FullScaleRange.html). + /// the full-scale range ([`FullScaleRange`](crate::FullScaleRange)) selected. /// /// Returns `nb::Error::WouldBlock` while a measurement is in progress. /// diff --git a/src/lib.rs b/src/lib.rs index 2a7597d..2e111a4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -36,7 +36,7 @@ //! [`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 +//! # 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 @@ -55,7 +55,7 @@ //! The devices operate either in continuous-conversion mode, or in a //! single-shot mode that automatically powers down after a conversion. //! Single-shot mode significantly reduces current consumption during idle -//! periods. Data is transferred through I2C. +//! periods. Data is transferred through I²C. //! //! Here is a comparison of the caracteristics of the devices: //! @@ -72,19 +72,17 @@ //! - [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(...)`. +//! In the following examples an instance of the device ADS1013 will be created. //! //! Please find additional examples using hardware in this repository: [driver-examples] //! //! [driver-examples]: https://github.com/eldruin/driver-examples //! -//! ### Create a driver instance for an ADS1013 with the default address. +//! ## Creating a Driver Instance for an ADS1013 //! //! ```no_run //! use linux_embedded_hal::I2cdev; @@ -98,7 +96,7 @@ //! let dev = adc.destroy_ads1013(); //! ``` //! -//! ### Create a driver instance for an ADS1013 with the ADDR pin connected to SDA. +//! ## Creating a driver instance for an ADS1013 with the ADDR pin connected to SDA. //! //! ```no_run //! use linux_embedded_hal::I2cdev; @@ -108,7 +106,8 @@ //! let adc = Ads1x1x::new_ads1013(dev, TargetAddr::Sda); //! ``` //! -//! ### Make a one-shot measurement +//! ## Taking a One-Shot Measurement +//! //! ```no_run //! use ads1x1x::{channel, Ads1x1x, TargetAddr}; //! use linux_embedded_hal::I2cdev; @@ -121,7 +120,7 @@ //! let _dev = adc.destroy_ads1013(); // get I2C device back //! ``` //! -//! ### 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. @@ -133,7 +132,9 @@ //! let dev = I2cdev::new("/dev/i2c-1").unwrap(); //! let adc = Ads1x1x::new_ads1013(dev, TargetAddr::default()); //! match adc.into_continuous() { -//! Err(ModeChangeError::I2C(e, adc)) => /* mode change failed handling */ panic!(), +//! Err(ModeChangeError::I2C(e, adc)) => { +//! panic!("Mode change failed: {e}") +//! }, //! Ok(mut adc) => { //! let measurement = adc.read().unwrap(); //! // ... @@ -142,7 +143,7 @@ //! ``` //! //! -//! ### 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`. //! @@ -155,7 +156,8 @@ //! 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 diff --git a/src/types.rs b/src/types.rs index 1e4b075..e240780 100644 --- a/src/types.rs +++ b/src/types.rs @@ -31,7 +31,7 @@ pub mod mode { pub struct Continuous(()); } -/// Data rate for ADS1013, ADS1014, ADS1015 +/// Data rate for ADS101x. #[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Ord, PartialOrd, Hash)] pub enum DataRate12Bit { /// 128 SPS @@ -51,7 +51,7 @@ pub enum DataRate12Bit { Sps3300, } -/// Data rate for ADS1113, ADS1114, ADS1115 +/// Data rate for ADS111x. #[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Ord, PartialOrd, Hash)] pub enum DataRate16Bit { /// 8 SPS @@ -73,7 +73,7 @@ pub enum DataRate16Bit { Sps860, } -/// Comparator mode (only for ADS1x14, ADS1x15) +/// Comparator mode (only for ADS1x14, ADS1x15). #[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Ord, PartialOrd, Hash)] pub enum ComparatorMode { #[default] @@ -92,7 +92,7 @@ pub enum ComparatorMode { Window, } -/// Comparator polarity (only for ADS1x14, ADS1x15) +/// Comparator polarity (only for ADS1x14, ADS1x15). #[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Ord, PartialOrd, Hash)] pub enum ComparatorPolarity { #[default] @@ -102,7 +102,7 @@ pub enum ComparatorPolarity { ActiveHigh, } -/// Comparator latching (only for ADS1x14, ADS1x15) +/// Comparator latching (only for ADS1x14, ADS1x15). /// /// Select whether the ALERT/RDY pin latches after being asserted or clears /// after conversions are within the margin of the upper and lower @@ -123,7 +123,7 @@ pub enum ComparatorLatching { Latching, } -/// Comparator alert queue (only for ADS1x14, ADS1x15) +/// Comparator alert queue (only for ADS1x14, ADS1x15). /// /// The default state of the comparator is deactivated. It can be activated by setting /// the comparator queue. @@ -138,7 +138,7 @@ pub enum ComparatorQueue { Four, } -/// Full-scale range configuration for the programmable gain amplifier (PGA) (only for ADS1x14, ADS1x15) +/// Full-scale range configuration for the programmable gain amplifier (PGA) (only for ADS1x14, ADS1x15). /// /// This sets the input voltage measurable range. /// The FSR is fixed at ±2.048 V in the ADS1x13. From 6c229d24b06e336c02f58e05788f3fcfcc9a348a Mon Sep 17 00:00:00 2001 From: Markus Reiter Date: Sat, 13 Jan 2024 20:05:57 +0100 Subject: [PATCH 03/14] Complete rewrite with separate struct for each version. # Conflicts: # README.md # examples/all_channels.rs # examples/linux.rs # examples/typed.rs # src/construction.rs # src/devices/features/tier2.rs # src/lib.rs # tests/common/mod.rs # Conflicts: # src/channel.rs # src/devices/common.rs # src/devices/features/tier1.rs # src/devices/features/tier2.rs # src/devices/mode/continuous.rs # src/devices/mode/oneshot.rs # src/lib.rs # src/types.rs --- README.md | 42 ++--- examples/all_channels.rs | 9 +- examples/linux.rs | 9 +- examples/typed.rs | 14 +- src/channel.rs | 12 +- src/construction.rs | 40 ----- src/conversion.rs | 104 ------------ src/devices/common.rs | 87 ++++++---- src/devices/features/tier1.rs | 71 +++----- src/devices/features/tier2.rs | 299 +++++++++++++++++---------------- src/devices/mode/continuous.rs | 93 +++++----- src/devices/mode/oneshot.rs | 141 ++++++++-------- src/ic.rs | 112 +++++++++--- src/lib.rs | 190 ++++++++++++--------- src/types.rs | 52 ++++-- tests/common/mod.rs | 28 +-- tests/construction.rs | 4 +- tests/mux.rs | 22 +-- tests/tier1.rs | 58 +++---- tests/tier2.rs | 26 +-- 20 files changed, 695 insertions(+), 718 deletions(-) delete mode 100644 src/construction.rs delete mode 100644 src/conversion.rs diff --git a/README.md b/README.md index 0ba4f49..6505eef 100644 --- a/README.md +++ b/README.md @@ -13,21 +13,21 @@ analog-to-digital converters (ADC), based on the [`embedded-hal`] traits. [Introductory blog post] 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()`. -- Start continuous conversion mode. See: `start()`. -- Read the last measurement made in continuous conversion mode. See: `read()`. -- 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_continuous`. +- Make a measurement in one-shot mode. See `Ads1115::read`. +- Start continuous conversion mode. See `Ads1115::start`. +- Read the last measurement made in continuous conversion mode. See `Ads1115::read`. +- Set the data rate. See `Ads1115::set_data_rate`. +- Set the full-scale range (gain amplifier). Se `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()`. + - 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`. ## The devices @@ -77,18 +77,20 @@ Please find additional examples using hardware in this repository: [driver-examp [driver-examples]: https://github.com/eldruin/driver-examples ```rust +use ads1x1x::{channel, Ads1013, TargetAddr}; use linux_embedded_hal::I2cdev; use nb::block; -use ads1x1x::{channel, Ads1x1x, TargetAddr}; - fn main() { - let dev = I2cdev::new("/dev/i2c-1").unwrap(); - let mut adc = Ads1x1x::new_ads1013(dev, TargetAddr::default()); + let i2c = I2cdev::new("/dev/i2c-1").unwrap(); + let mut adc = Ads1013::new(i2c, TargetAddr::default()); + let value = block!(adc.read(channel::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 283f834..6814c57 100644 --- a/examples/all_channels.rs +++ b/examples/all_channels.rs @@ -1,11 +1,12 @@ use linux_embedded_hal::I2cdev; use nb::block; -use ads1x1x::{channel, Ads1x1x, TargetAddr}; +use ads1x1x::{channel, Ads1015, TargetAddr}; fn main() { - let dev = I2cdev::new("/dev/i2c-1").unwrap(); - let mut adc = Ads1x1x::new_ads1015(dev, TargetAddr::default()); + let i2c = I2cdev::new("/dev/i2c-1").unwrap(); + let mut adc = Ads1015::new(i2c, TargetAddr::default()); + let values = [ block!(adc.read(channel::SingleA0)).unwrap(), block!(adc.read(channel::SingleA1)).unwrap(), @@ -15,6 +16,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 6bf735c..79e4b9e 100644 --- a/examples/linux.rs +++ b/examples/linux.rs @@ -1,13 +1,12 @@ use linux_embedded_hal::I2cdev; use nb::block; -use ads1x1x::{channel, Ads1x1x, TargetAddr}; +use ads1x1x::{channel, Ads1013, TargetAddr}; fn main() { - let dev = I2cdev::new("/dev/i2c-1").unwrap(); - let mut adc = Ads1x1x::new_ads1013(dev, TargetAddr::default()); + let i2c = I2cdev::new("/dev/i2c-1").unwrap(); + let mut adc = Ads1013::new(i2c, TargetAddr::default()); + 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 11a6373..f0e4e16 100644 --- a/examples/typed.rs +++ b/examples/typed.rs @@ -4,14 +4,10 @@ use linux_embedded_hal::I2cdev; use nb::block; -use ads1x1x::{ - channel, - ic::{Ads1115, Resolution16Bit}, - Ads1x1x, TargetAddr, -}; +use ads1x1x::{channel, mode, Ads1115, TargetAddr}; /// Type alias -type Adc = Ads1x1x; +type Adc = Ads1115; /// Read a single value from channel A. /// Returns 0 on Error. @@ -20,11 +16,9 @@ pub fn read(adc: &mut Adc) -> i16 { } fn main() { - let dev = I2cdev::new("/dev/i2c-1").unwrap(); - let mut adc = Ads1x1x::new_ads1115(dev, TargetAddr::default()); + let i2c = I2cdev::new("/dev/i2c-1").unwrap(); + let mut adc = Ads1115::new(i2c, TargetAddr::default()); let value = read(&mut adc); println!("Measurement: {}", value); - // get I2C device back - let _dev = adc.destroy_ads1115(); } diff --git a/src/channel.rs b/src/channel.rs index 4d6e028..2883b69 100644 --- a/src/channel.rs +++ b/src/channel.rs @@ -1,18 +1,20 @@ //! ADC input channels. -use crate::{ic, Ads1x1x, BitFlags as BF, Config}; +use crate::{Ads1013, Ads1014, Ads1015, Ads1113, Ads1114, Ads1115, BitFlags as BF, Config}; use private::ChannelSelection; /// Marker type for an ADC input channel. -pub trait ChannelId { +pub trait ChannelId: private::Sealed { /// Get the channel. fn channel_id() -> ChannelSelection; } macro_rules! impl_channels { - ($(#[doc = $doc:expr] $CH:ident => [$($IC:ident),+]),+ $(,)?) => { + ($(#[doc = $doc:expr] $CH:ident => [$($Ads:ident),+]),+ $(,)?) => { mod private { + pub trait Sealed {} + #[derive(Debug, Clone, Copy)] /// ADC input channel selection. pub enum ChannelSelection { @@ -27,8 +29,10 @@ macro_rules! impl_channels { #[doc = $doc] pub struct $CH; + impl private::Sealed for $CH {} + $( - impl ChannelId> for $CH { + impl ChannelId<$Ads> for $CH { fn channel_id() -> ChannelSelection { ChannelSelection::$CH } diff --git a/src/construction.rs b/src/construction.rs deleted file mode 100644 index 84ee8ad..0000000 --- a/src/construction.rs +++ /dev/null @@ -1,40 +0,0 @@ -//! Constructor/destructor functions. - -use crate::{ic, mode, Ads1x1x, Config, FullScaleRange, TargetAddr}; -use core::marker::PhantomData; - -macro_rules! impl_new_destroy { - ( $IC:ident, $create:ident, $destroy:ident, $conv:ty ) => { - impl Ads1x1x - where - I2C: embedded_hal::i2c::I2c, - { - /// Create a new instance of the device in OneShot mode. - pub fn $create(i2c: I2C, address: TargetAddr) -> Self { - Ads1x1x { - i2c, - address: address.bits(), - config: Config::default(), - fsr: FullScaleRange::default(), - a_conversion_was_started: false, - _conv: PhantomData, - _ic: PhantomData, - _mode: PhantomData, - } - } - } - impl Ads1x1x { - /// Destroy driver instance, return I²C bus instance. - pub fn $destroy(self) -> I2C { - self.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 66a6d97..bee4b7e 100644 --- a/src/devices/common.rs +++ b/src/devices/common.rs @@ -1,40 +1,61 @@ //! Common functions. -use crate::{devices::OperatingMode, Ads1x1x, BitFlags, Config, Error, Register}; +use crate::{ + devices::OperatingMode, Ads1013, Ads1014, Ads1015, Ads1113, Ads1114, Ads1115, BitFlags, Config, + Error, Register, +}; -impl Ads1x1x -where - I2C: embedded_hal::i2c::I2c, -{ - pub(super) 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) - } +macro_rules! impl_common_features { + ($Ads:ident) => { + impl $Ads + where + I2C: embedded_hal::i2c::I2c, + { + pub(super) 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) + } - pub(super) fn read_register(&mut self, register: u8) -> Result> { - let mut data = [0, 0]; - self.i2c - .write_read(self.address, &[register], &mut data) - .map_err(Error::I2C) - .and(Ok(u16::from_be_bytes(data))) - } + pub(super) fn read_register(&mut self, register: u8) -> Result> { + let mut data = [0, 0]; + self.i2c + .write_read(self.address, &[register], &mut data) + .map_err(Error::I2C) + .and(Ok(u16::from_be_bytes(data))) + } - 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.write_register(Register::CONFIG, config.bits)?; - self.config = config; - Ok(()) - } + 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.write_register(Register::CONFIG, config.bits)?; + self.config = config; + Ok(()) + } - /// Checks whether a measurement is currently in progress. - pub fn is_measurement_in_progress(&mut self) -> Result> { - let config = Config { - bits: self.read_register(Register::CONFIG)?, - }; - Ok(!config.is_high(BitFlags::OS)) - } + /// Checks whether a measurement is currently in progress. + pub fn is_measurement_in_progress(&mut self) -> Result> { + let config = Config { + bits: self.read_register(Register::CONFIG)?, + }; + Ok(!config.is_high(BitFlags::OS)) + } + } + }; } + +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 3a8beb9..017089c 100644 --- a/src/devices/features/tier1.rs +++ b/src/devices/features/tier1.rs @@ -1,50 +1,31 @@ //! Features supported on all ADS1x1x devices. -use crate::{ic, Ads1x1x, BitFlags as BF, DataRate12Bit, DataRate16Bit, Error, Register}; +use crate::{ + Ads1013, Ads1014, Ads1015, Ads1113, Ads1114, Ads1115, DataRate12Bit, DataRate16Bit, Error, + Register, +}; -impl Ads1x1x -where - I2C: embedded_hal::i2c::I2c, -{ - /// Sets the 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.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.write_register(Register::CONFIG, config.bits)?; + self.config = config; + Ok(()) + } + } + }; } -impl Ads1x1x -where - I2C: embedded_hal::i2c::I2c, -{ - /// Sets the 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.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 fe36a72..1fc4225 100644 --- a/src/devices/features/tier2.rs +++ b/src/devices/features/tier2.rs @@ -1,159 +1,172 @@ //! Features only supported by ADS1x14 and ADS1x15 devices. use crate::{ - conversion, ic, Ads1x1x, BitFlags as BF, ComparatorLatching, ComparatorMode, + ic, Ads1014, Ads1015, Ads1114, Ads1115, BitFlags as BF, ComparatorLatching, ComparatorMode, ComparatorPolarity, ComparatorQueue, Error, FullScaleRange, Register, }; -impl Ads1x1x -where - I2C: embedded_hal::i2c::I2c, - IC: ic::Tier2Features, - CONV: conversion::ConvertThreshold, -{ - /// 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.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.write_register(Register::CONFIG, config.bits)?; + self.config = config; + Ok(()) + } - /// Sets the raw comparator lower threshold. - /// - /// The voltage that these values correspond to must be calculated using the - /// full-scale range ([`FullScaleRange`]) selected. - /// - /// The input value must be within `[2047..-2048]` for 12-bit devices (`ADS101x`) - /// and within `[32767..-32768]` for 16-bit devices (`ADS111x`). - pub fn set_low_threshold_raw(&mut self, value: i16) -> Result<(), Error> { - let register_value = CONV::convert_threshold(value)?; - self.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.write_register(Register::LOW_TH, register_value) + } - /// Sets the raw comparator upper threshold. - /// - /// The voltage that these values correspond to must be calculated using the - /// full-scale range ([`FullScaleRange`]) selected. - /// - /// The input value must be within `[2047..-2048]` for 12-bit devices (`ADS101x`) - /// and within `[32767..-32768]` for 16-bit devices (`ADS111x`). - pub fn set_high_threshold_raw(&mut self, value: i16) -> Result<(), Error> { - let register_value = CONV::convert_threshold(value)?; - self.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.write_register(Register::HIGH_TH, register_value) + } - /// 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.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.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.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.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.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.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.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.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) method. - pub fn disable_comparator(&mut self) -> Result<(), Error> { - let config = self - .config - .with_high(BF::COMP_QUE1) - .with_high(BF::COMP_QUE0); - self.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) method. + pub fn disable_comparator(&mut self) -> Result<(), Error> { + let config = self + .config + .with_high(BF::COMP_QUE1) + .with_high(BF::COMP_QUE0); + self.write_register(Register::CONFIG, config.bits)?; + self.config = config; + Ok(()) + } - /// Enables the ALERT/RDY pin as conversion-ready function. - /// - /// When in one-shot mode, this makes the ALERT/RDY pin output the OS bit, - /// in continuous-conversion mode, provides a continuous-conversion ready pulse. - /// - /// When calling this the comparator will be reset to default and any 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.set_comparator_queue(ComparatorQueue::default())?; + /// Enables the ALERT/RDY pin as conversion-ready function. + /// + /// When in one-shot mode, this makes the ALERT/RDY pin output the OS bit, + /// in continuous-conversion mode, provides a continuous-conversion ready pulse. + /// + /// When calling this the comparator will be reset to default and any 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.set_comparator_queue(ComparatorQueue::default())?; + } + self.write_register(Register::HIGH_TH, 0x8000)?; + self.write_register(Register::LOW_TH, 0) + } } - self.write_register(Register::HIGH_TH, 0x8000)?; - self.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 d514a9a..d5905c9 100644 --- a/src/devices/mode/continuous.rs +++ b/src/devices/mode/continuous.rs @@ -1,50 +1,61 @@ //! Continuous measurement mode. use crate::{ - conversion, devices::OperatingMode, mode, Ads1x1x, ChannelId, Error, ModeChangeError, Register, + devices::OperatingMode, ic, mode, Ads1013, Ads1014, Ads1015, Ads1113, Ads1114, Ads1115, + ChannelId, Error, ModeChangeError, Register, }; use core::marker::PhantomData; -impl Ads1x1x -where - I2C: embedded_hal::i2c::I2c, - CONV: conversion::ConvertMeasurement, -{ - /// Changes to one-shot operating mode. - 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 { - i2c: self.i2c, - address: self.address, - 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 to one-shot operating mode. + 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 { + i2c: self.i2c, + address: self.address, + config: self.config, + a_conversion_was_started: false, + mode: PhantomData, + }) + } - /// Reads the most recent measurement. - pub fn read(&mut self) -> Result> { - let value = self.read_register(Register::CONVERSION)?; - Ok(CONV::convert_measurement(value)) - } + /// Reads the most recent measurement. + pub fn read(&mut self) -> Result> { + let value = self.read_register(Register::CONVERSION)?; + Ok(<$conv>::convert_measurement(value)) + } - /// Selects the channel used 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. - #[allow(unused_variables)] - pub fn select_channel>(&mut self, channel: CH) -> Result<(), Error> { - let config = self.config.with_mux_bits(CH::channel_id()); - self.write_register(Register::CONFIG, config.bits)?; - self.config = config; - Ok(()) - } + /// Selects the channel used 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. + #[allow(unused_variables)] + pub fn select_channel>( + &mut self, + channel: CH, + ) -> Result<(), Error> { + let config = self.config.with_mux_bits(CH::channel_id()); + self.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 22b6d51..e52dde0 100644 --- a/src/devices/mode/oneshot.rs +++ b/src/devices/mode/oneshot.rs @@ -3,79 +3,80 @@ use core::marker::PhantomData; use crate::{ - conversion, devices::OperatingMode, mode, Ads1x1x, BitFlags, ChannelId, Config, Error, - ModeChangeError, Register, + devices::OperatingMode, ic, mode, Ads1013, Ads1014, Ads1015, Ads1113, Ads1114, Ads1115, + BitFlags, ChannelId, Config, Error, ModeChangeError, Register, }; -impl Ads1x1x -where - I2C: embedded_hal::i2c::I2c, - CONV: conversion::ConvertMeasurement, -{ - /// Changes to continuous operating mode. - 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 { - i2c: self.i2c, - address: self.address, - 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, + { + /// Changes to continuous operating mode. + 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 { + i2c: self.i2c, + address: self.address, + config: self.config, + a_conversion_was_started: true, + mode: PhantomData, + }) + } - fn trigger_measurement(&mut self, config: &Config) -> Result<(), Error> { - let config = config.with_high(BitFlags::OS); - self.write_register(Register::CONFIG, config.bits) - } -} + fn trigger_measurement(&mut self, config: &Config) -> Result<(), Error> { + let config = config.with_high(BitFlags::OS); + self.write_register(Register::CONFIG, config.bits) + } -impl Ads1x1x -where - I2C: embedded_hal::i2c::I2c, - CONV: conversion::ConvertMeasurement, -{ - /// 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. - #[allow(unused_variables)] - 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 config = self.config.with_mux_bits(CH::channel_id()); - let same_channel = self.config == config; - if self.a_conversion_was_started && same_channel { - // result is ready - let value = self - .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. + #[allow(unused_variables)] + 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 config = self.config.with_mux_bits(CH::channel_id()); + let same_channel = self.config == config; + if self.a_conversion_was_started && same_channel { + // result is ready + let value = self + .read_register(Register::CONVERSION) + .map_err(nb::Error::Other)?; + self.a_conversion_was_started = false; + return Ok(<$conv>::convert_measurement(value)); + } + self.trigger_measurement(&config) + .map_err(nb::Error::Other)?; + self.config = config; + self.a_conversion_was_started = true; + Err(nb::Error::WouldBlock) + } } - self.trigger_measurement(&config) - .map_err(nb::Error::Other)?; - self.config = config; - self.a_conversion_was_started = true; - Err(nb::Error::WouldBlock) - } + }; } + +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/lib.rs b/src/lib.rs index 2e111a4..78c126a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,36 +5,23 @@ //! [`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_continuous]. +//! - 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-1 -//! [`start()`]: struct.Ads1x1x.html#method.start -//! [read_cont]: struct.Ads1x1x.html#method.read -//! [`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 +//! - 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_continuous]: struct.Ads1115.html#method.read //! //! # The devices //! @@ -85,39 +72,51 @@ //! ## Creating a Driver Instance for an ADS1013 //! //! ```no_run +//! # fn main() -> Result<(), Box> { +//! use ads1x1x::{Ads1013, TargetAddr}; //! use linux_embedded_hal::I2cdev; -//! use ads1x1x::{Ads1x1x, TargetAddr}; //! -//! let dev = I2cdev::new("/dev/i2c-1").unwrap(); -//! let adc = Ads1x1x::new_ads1013(dev, TargetAddr::default()); -//! // do something... +//! let i2c = I2cdev::new("/dev/i2c-1")?; +//! let adc = Ads1013::new(i2c, TargetAddr::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(()) +//! # } //! ``` //! //! ## Creating a driver instance for an ADS1013 with the ADDR pin connected to SDA. //! //! ```no_run -//! use linux_embedded_hal::I2cdev; -//! use ads1x1x::{Ads1x1x, TargetAddr}; -//! -//! let dev = I2cdev::new("/dev/i2c-1").unwrap(); -//! let adc = Ads1x1x::new_ads1013(dev, TargetAddr::Sda); +//! # fn main() -> Result<(), Box> { +//! # use ads1x1x::{Ads1013, TargetAddr}; +//! # 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, TargetAddr::Sda); +//! # Ok(()) +//! # } //! ``` //! //! ## Taking a One-Shot Measurement //! //! ```no_run -//! use ads1x1x::{channel, Ads1x1x, TargetAddr}; +//! # fn main() -> Result<(), Box> { +//! use ads1x1x::{channel, Ads1013, TargetAddr}; //! use linux_embedded_hal::I2cdev; //! use nb::block; //! -//! let dev = I2cdev::new("/dev/i2c-1").unwrap(); -//! let mut adc = Ads1x1x::new_ads1013(dev, TargetAddr::default()); -//! let measurement = block!(adc.read(channel::DifferentialA0A1)).unwrap(); +//! let i2c = I2cdev::new("/dev/i2c-1")?; +//! let mut adc = Ads1013::new(i2c, TargetAddr::default()); +//! +//! let measurement = block!(adc.read(channel::DifferentialA0A1))?; //! println!("Measurement: {}", measurement); -//! let _dev = adc.destroy_ads1013(); // get I2C device back +//! # Ok(()) +//! # } //! ``` //! //! ## Changing to Continuous Conversion Mode and Reading the Last Measurement @@ -126,11 +125,11 @@ //! In this case, you can retrieve the unchanged device from the error type. //! //! ```no_run +//! use ads1x1x::{Ads1013, ModeChangeError, TargetAddr}; //! use linux_embedded_hal::I2cdev; -//! use ads1x1x::{Ads1x1x, ModeChangeError, TargetAddr}; //! -//! let dev = I2cdev::new("/dev/i2c-1").unwrap(); -//! let adc = Ads1x1x::new_ads1013(dev, TargetAddr::default()); +//! let i2c = I2cdev::new("/dev/i2c-1").unwrap(); +//! let adc = Ads1013::new(i2c, TargetAddr::default()); //! match adc.into_continuous() { //! Err(ModeChangeError::I2C(e, adc)) => { //! panic!("Mode change failed: {e}") @@ -148,11 +147,12 @@ //! For 16-bit devices, the available data rates are given by `DataRate16Bit`. //! //! ```no_run +//! use ads1x1x::{Ads1115, DataRate16Bit, TargetAddr}; //! use linux_embedded_hal::I2cdev; -//! use ads1x1x::{Ads1x1x, DataRate16Bit, TargetAddr}; //! -//! let dev = I2cdev::new("/dev/i2c-1").unwrap(); -//! let mut adc = Ads1x1x::new_ads1115(dev, TargetAddr::default()); +//! let i2c = I2cdev::new("/dev/i2c-1").unwrap(); +//! let mut adc = Ads1115::new(i2c, TargetAddr::default()); +//! //! adc.set_data_rate(DataRate16Bit::Sps860).unwrap(); //! ``` //! @@ -165,15 +165,15 @@ //! the controller. //! //! ```no_run -//! use linux_embedded_hal::I2cdev; //! use ads1x1x::{ -//! Ads1x1x, TargetAddr, ComparatorQueue, ComparatorPolarity, +//! Ads1115, TargetAddr, ComparatorQueue, ComparatorPolarity, //! ComparatorMode, ComparatorLatching, FullScaleRange //! }; +//! use linux_embedded_hal::I2cdev; +//! +//! let i2c = I2cdev::new("/dev/i2c-1").unwrap(); +//! let mut adc = Ads1015::new(i2c, TargetAddr::default()); //! -//! let dev = I2cdev::new("/dev/i2c-1").unwrap(); -//! let address = TargetAddr::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(); @@ -186,6 +186,19 @@ #![deny(missing_docs)] #![no_std] +use core::marker::PhantomData; + +pub mod channel; +pub use channel::ChannelId; +mod devices; +mod ic; +mod types; +use crate::types::Config; +pub use crate::types::{ + mode, ComparatorLatching, ComparatorMode, ComparatorPolarity, ComparatorQueue, DataRate12Bit, + DataRate16Bit, Error, FullScaleRange, ModeChangeError, TargetAddr, +}; + struct Register; impl Register { const CONVERSION: u8 = 0x00; @@ -214,34 +227,43 @@ impl BitFlags { const COMP_QUE0: u16 = 0b0000_0000_0000_0001; } -pub mod channel; -pub use channel::ChannelId; -mod construction; -mod conversion; -pub use crate::conversion::{ConvertMeasurement, ConvertThreshold}; -mod devices; -#[doc(hidden)] -pub mod ic; -mod types; -use crate::types::Config; -pub use crate::types::{ - mode, Ads1x1x, ComparatorLatching, ComparatorMode, ComparatorPolarity, ComparatorQueue, - DataRate12Bit, DataRate16Bit, Error, FullScaleRange, ModeChangeError, TargetAddr, -}; - -mod private { - use super::{ic, Ads1x1x}; - pub trait Sealed {} - - impl Sealed for Ads1x1x {} +macro_rules! impl_ads1x1x { + ($Ads:ident) => { + /// ADS1x1x ADC driver + #[derive(Debug)] + pub struct $Ads { + pub(crate) i2c: I2C, + pub(crate) address: u8, + pub(crate) config: Config, + pub(crate) a_conversion_was_started: bool, + pub(crate) mode: PhantomData, + } - impl Sealed for ic::Resolution12Bit {} - impl Sealed for ic::Resolution16Bit {} + impl $Ads { + /// Create a new instance of the device in one-shot mode. + pub fn new(i2c: I2C, address: TargetAddr) -> Self { + $Ads { + i2c, + address: address.bits(), + config: Config::default(), + a_conversion_was_started: false, + mode: PhantomData, + } + } + } - 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 $Ads { + /// Release the contained I²C peripheral. + pub fn release(self) -> I2C { + self.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 e240780..2980ee3 100644 --- a/src/types.rs +++ b/src/types.rs @@ -1,9 +1,9 @@ //! Type definitions. -use core::marker::PhantomData; +use crate::BitFlags as BF; /// Errors in this crate -#[derive(Debug)] +#[derive(Debug, PartialEq)] pub enum Error { /// I²C bus error I2C(E), @@ -25,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 ADS101x. @@ -51,6 +53,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 ADS111x. #[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Ord, PartialOrd, Hash)] pub enum DataRate16Bit { @@ -73,6 +89,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, Default, Clone, Copy, PartialEq, Eq, Ord, PartialOrd, Hash)] pub enum ComparatorMode { @@ -220,19 +251,6 @@ impl Default for Config { } } -/// ADS1x1x ADC driver -#[derive(Debug, Default)] -pub struct Ads1x1x { - pub(crate) i2c: I2C, - pub(crate) address: u8, - 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, -} - #[cfg(test)] mod tests { use crate::{FullScaleRange, TargetAddr}; diff --git a/tests/common/mod.rs b/tests/common/mod.rs index 3e10894..ada6985 100644 --- a/tests/common/mod.rs +++ b/tests/common/mod.rs @@ -1,4 +1,4 @@ -use ads1x1x::{ic, mode, Ads1x1x, TargetAddr}; +use ads1x1x::{mode, Ads1013, Ads1014, Ads1015, Ads1113, Ads1114, Ads1115, TargetAddr}; use embedded_hal_mock::eh1::i2c::{Mock as I2cMock, Transaction as I2cTrans}; #[allow(unused)] @@ -67,31 +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), TargetAddr::default()) + pub fn $create(transactions: &[$trans]) -> $Ads { + $Ads::new(I2cMock::new(transactions), TargetAddr::default()) } #[allow(unused)] - pub fn $destroy(dev: Ads1x1x<$iface, ic::$ic, $conv, MODE>) { - dev.$destroy().done(); + pub fn $destroy(adc: $Ads) { + adc.release().done(); } }; } macro_rules! impl_new_destroy_i2c { - ($ic:ident, $create:ident, $destroy:ident, $conv:ty) => { - impl_new_destroy!($ic, $create, $destroy, $conv, I2cTrans, I2cMock); + ($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..dedc0ed 100644 --- a/tests/construction.rs +++ b/tests/construction.rs @@ -10,8 +10,8 @@ macro_rules! impl_tests { use super::*; #[test] fn can_create() { - let dev = $create(&[]); - $destroy(dev); + let adc = $create(&[]); + $destroy(adc); } } }; diff --git a/tests/mux.rs b/tests/mux.rs index ac335b5..2d2f2c6 100644 --- a/tests/mux.rs +++ b/tests/mux.rs @@ -31,10 +31,10 @@ 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(channel::$CS)).unwrap(); + let mut adc = new(&transactions); + let measurement = block!(adc.read(channel::$CS)).unwrap(); assert_eq!(-2048, measurement); - destroy(dev); + destroy(adc); } #[test] @@ -65,11 +65,11 @@ 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(channel::$CS)); - let measurement = block!(dev.read(channel::$other_CS)).unwrap(); + let mut adc = new(&transactions); + assert_would_block!(adc.read(channel::$CS)); + let measurement = block!(adc.read(channel::$other_CS)).unwrap(); assert_eq!(-2048, measurement); - destroy(dev); + destroy(adc); } #[test] @@ -86,10 +86,10 @@ macro_rules! mux_test { vec![Register::CONFIG, config2.msb(), config2.lsb()], ), ]; - let dev = new(&transactions); - let mut dev = dev.into_continuous().ok().unwrap(); - dev.select_channel(channel::$CS).unwrap(); - destroy(dev); + let adc = new(&transactions); + let mut adc = adc.into_continuous().ok().unwrap(); + adc.select_channel(channel::$CS).unwrap(); + destroy(adc); } } }; diff --git a/tests/tier1.rs b/tests/tier1.rs index bbe9d6f..d2008ba 100644 --- a/tests/tier1.rs +++ b/tests/tier1.rs @@ -24,9 +24,9 @@ macro_rules! measure_tests { vec![Register::CONFIG], vec![config.msb(), config.lsb()], )]; - let mut dev = $create(&transactions); - assert_would_block!(dev.read(channel::DifferentialA0A1)); - $destroy(dev); + let mut adc = $create(&transactions); + assert_would_block!(adc.read(channel::DifferentialA0A1)); + $destroy(adc); } } @@ -51,10 +51,10 @@ 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(channel::DifferentialA0A1)).unwrap(); + let mut adc = $create(&transactions); + let measurement = block!(adc.read(channel::DifferentialA0A1)).unwrap(); assert_eq!($expected, measurement); - $destroy(dev); + $destroy(adc); } #[test] @@ -64,11 +64,11 @@ 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 measurement = dev.read().unwrap(); + let adc = $create(&transactions); + let mut adc = adc.into_continuous().ok().unwrap(); + let measurement = adc.read().unwrap(); assert_eq!($expected, measurement); - $destroy(dev); + $destroy(adc); } } }; @@ -88,9 +88,9 @@ mod data_rate_12bit { DEV_ADDR, vec![Register::CONFIG, $config.msb(), $config.lsb()], )]; - let mut dev = new_ads1013(&transactions); - dev.set_data_rate(DataRate12Bit::$variant).unwrap(); - destroy_ads1013(dev); + let mut adc = new_ads1013(&transactions); + adc.set_data_rate(DataRate12Bit::$variant).unwrap(); + destroy_ads1013(adc); } }; } @@ -164,9 +164,9 @@ mod data_rate_16bit { DEV_ADDR, vec![Register::CONFIG, $config.msb(), $config.lsb()], )]; - let mut dev = new_ads1113(&transactions); - dev.set_data_rate(DataRate16Bit::$variant).unwrap(); - destroy_ads1113(dev); + let mut adc = new_ads1113(&transactions); + adc.set_data_rate(DataRate16Bit::$variant).unwrap(); + destroy_ads1113(adc); } }; } @@ -245,9 +245,9 @@ fn can_read_measurement_in_progress() { vec![Register::CONFIG], vec![config_os.msb(), config_os.lsb()], )]; - let mut dev = new_ads1013(&transactions); - assert!(dev.is_measurement_in_progress().unwrap()); - destroy_ads1013(dev); + let mut adc = new_ads1013(&transactions); + assert!(adc.is_measurement_in_progress().unwrap()); + destroy_ads1013(adc); } #[test] @@ -258,9 +258,9 @@ fn can_read_measurement_not_in_progress() { vec![Register::CONFIG], vec![config_os.msb(), config_os.lsb()], )]; - let mut dev = new_ads1013(&transactions); - assert!(!dev.is_measurement_in_progress().unwrap()); - destroy_ads1013(dev); + let mut adc = new_ads1013(&transactions); + assert!(!adc.is_measurement_in_progress().unwrap()); + destroy_ads1013(adc); } #[test] @@ -270,9 +270,9 @@ 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(); - destroy_ads1013(dev); + let adc = new_ads1013(&transactions); + let adc = adc.into_continuous().ok().unwrap(); + destroy_ads1013(adc); } #[test] @@ -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(); - destroy_ads1013(dev); + let adc = new_ads1013(&transactions); + let adc = adc.into_continuous().ok().unwrap(); + let adc = adc.into_one_shot().ok().unwrap(); + destroy_ads1013(adc); } diff --git a/tests/tier2.rs b/tests/tier2.rs index e29b67b..d8869f7 100644 --- a/tests/tier2.rs +++ b/tests/tier2.rs @@ -13,9 +13,9 @@ 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); - dev.$method($value).unwrap(); - destroy_ads1014(dev); + let mut adc = new_ads1014(&transactions); + adc.$method($value).unwrap(); + destroy_ads1014(adc); } }; } @@ -89,9 +89,9 @@ fn can_disable_comparator() { DEV_ADDR, vec![Register::CONFIG, config.msb(), config.lsb()], )]; - let mut dev = new_ads1014(&transactions); - dev.disable_comparator().unwrap(); - destroy_ads1014(dev); + let mut adc = new_ads1014(&transactions); + adc.disable_comparator().unwrap(); + destroy_ads1014(adc); } mod can_set_comparator_queue { @@ -128,9 +128,9 @@ 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); - dev.use_alert_rdy_pin_as_ready().unwrap(); - destroy_ads1014(dev); + let mut adc = new_ads1014(&transactions); + adc.use_alert_rdy_pin_as_ready().unwrap(); + destroy_ads1014(adc); } #[test] @@ -154,10 +154,10 @@ 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); - dev.set_comparator_queue(ComparatorQueue::One).unwrap(); - dev.use_alert_rdy_pin_as_ready().unwrap(); - destroy_ads1014(dev); + let mut adc = new_ads1014(&transactions); + adc.set_comparator_queue(ComparatorQueue::One).unwrap(); + adc.use_alert_rdy_pin_as_ready().unwrap(); + destroy_ads1014(adc); } mod can_set_full_scale_range { From 0d91387947c14bc1b53a934df34cf000bba6e22b Mon Sep 17 00:00:00 2001 From: Markus Reiter Date: Sat, 13 Jan 2024 23:36:36 +0100 Subject: [PATCH 04/14] Remove alias usage. --- src/devices/features/tier2.rs | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/src/devices/features/tier2.rs b/src/devices/features/tier2.rs index 1fc4225..fe3776b 100644 --- a/src/devices/features/tier2.rs +++ b/src/devices/features/tier2.rs @@ -15,29 +15,34 @@ macro_rules! impl_tier2_features { /// /// 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 + FullScaleRange::Within6_144V => self + .config + .with_low(BF::PGA2) + .with_low(BF::PGA1) + .with_low(BF::PGA0), + FullScaleRange::Within4_096V => self + .config .with_low(BF::PGA2) .with_low(BF::PGA1) .with_high(BF::PGA0), - FSR::Within2_048V => cfg + FullScaleRange::Within2_048V => self + .config .with_low(BF::PGA2) .with_high(BF::PGA1) .with_low(BF::PGA0), - FSR::Within1_024V => cfg + FullScaleRange::Within1_024V => self + .config .with_low(BF::PGA2) .with_high(BF::PGA1) .with_high(BF::PGA0), - FSR::Within0_512V => cfg + FullScaleRange::Within0_512V => self + .config .with_high(BF::PGA2) .with_low(BF::PGA1) .with_low(BF::PGA0), - FSR::Within0_256V => cfg + FullScaleRange::Within0_256V => self + .config .with_high(BF::PGA2) .with_low(BF::PGA1) .with_high(BF::PGA0), From 8f7c1692238462feb433439b5f5f36b3e133b177 Mon Sep 17 00:00:00 2001 From: Markus Reiter Date: Fri, 19 Jan 2024 18:04:59 +0100 Subject: [PATCH 05/14] Align constants. --- src/lib.rs | 36 ++++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 78c126a..9eb5ab9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -200,29 +200,33 @@ pub use crate::types::{ }; 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; } From f699f271ae7b48051e07ceaa298b49fd616aa813 Mon Sep 17 00:00:00 2001 From: Markus Reiter Date: Sun, 14 Jan 2024 01:27:38 +0100 Subject: [PATCH 06/14] Improve docs. --- README.md | 2 +- src/lib.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 6505eef..8b12f6c 100644 --- a/README.md +++ b/README.md @@ -88,7 +88,7 @@ fn main() { let value = block!(adc.read(channel::DifferentialA0A1)).unwrap(); println!("Measurement: {}", value); - // Get the I2C peripheral back. + // Get the I²C peripheral back. let i2c = adc.release(); drop(i2c); } diff --git a/src/lib.rs b/src/lib.rs index 9eb5ab9..1621930 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -81,7 +81,7 @@ //! //! // Do something. //! -//! // Get the I2C device back. +//! // Get the I²C device back. //! let i2c = adc.release(); //! # drop(i2c); //! # Ok(()) From 30d335563bfd87a950a10dedc9ca8e71564215c2 Mon Sep 17 00:00:00 2001 From: Markus Reiter Date: Fri, 19 Jan 2024 17:58:12 +0100 Subject: [PATCH 07/14] Fix variant used in example. --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 1621930..c833e9e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -166,7 +166,7 @@ //! //! ```no_run //! use ads1x1x::{ -//! Ads1115, TargetAddr, ComparatorQueue, ComparatorPolarity, +//! Ads1015, TargetAddr, ComparatorQueue, ComparatorPolarity, //! ComparatorMode, ComparatorLatching, FullScaleRange //! }; //! use linux_embedded_hal::I2cdev; From 719c2c2494de294ebf34fd4393da082f338dc98f Mon Sep 17 00:00:00 2001 From: Markus Reiter Date: Sun, 14 Jan 2024 00:55:35 +0100 Subject: [PATCH 08/14] Remove custom error. # Conflicts: # src/lib.rs --- src/devices/mode/continuous.rs | 12 ++++++------ src/devices/mode/oneshot.rs | 10 ++++++---- src/lib.rs | 6 +++--- src/types.rs | 11 ----------- 4 files changed, 15 insertions(+), 24 deletions(-) diff --git a/src/devices/mode/continuous.rs b/src/devices/mode/continuous.rs index d5905c9..afb4ec4 100644 --- a/src/devices/mode/continuous.rs +++ b/src/devices/mode/continuous.rs @@ -2,7 +2,7 @@ use crate::{ devices::OperatingMode, ic, mode, Ads1013, Ads1014, Ads1015, Ads1113, Ads1114, Ads1115, - ChannelId, Error, ModeChangeError, Register, + ChannelId, Error, Register, }; use core::marker::PhantomData; @@ -13,11 +13,11 @@ macro_rules! impl_continuous { I2C: embedded_hal::i2c::I2c, { /// Changes to one-shot operating mode. - 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)); + /// + /// On error, returns a pair of the error and the current instance. + pub fn into_one_shot(mut self) -> Result<$Ads, (Error, Self)> { + if let Err(e) = self.set_operating_mode(OperatingMode::OneShot) { + return Err((e, self)); } Ok($Ads { i2c: self.i2c, diff --git a/src/devices/mode/oneshot.rs b/src/devices/mode/oneshot.rs index e52dde0..309b662 100644 --- a/src/devices/mode/oneshot.rs +++ b/src/devices/mode/oneshot.rs @@ -4,7 +4,7 @@ use core::marker::PhantomData; use crate::{ devices::OperatingMode, ic, mode, Ads1013, Ads1014, Ads1015, Ads1113, Ads1114, Ads1115, - BitFlags, ChannelId, Config, Error, ModeChangeError, Register, + BitFlags, ChannelId, Config, Error, Register, }; macro_rules! impl_one_shot { @@ -14,11 +14,13 @@ macro_rules! impl_one_shot { I2C: embedded_hal::i2c::I2c, { /// Changes to continuous operating mode. + /// + /// On error, returns a pair of the error and the current instance. 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)); + ) -> Result<$Ads, (Error, Self)> { + if let Err(e) = self.set_operating_mode(OperatingMode::Continuous) { + return Err((e, self)); } Ok($Ads { i2c: self.i2c, diff --git a/src/lib.rs b/src/lib.rs index c833e9e..7b42a76 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -125,13 +125,13 @@ //! In this case, you can retrieve the unchanged device from the error type. //! //! ```no_run -//! use ads1x1x::{Ads1013, ModeChangeError, TargetAddr}; +//! use ads1x1x::{Ads1013, TargetAddr}; //! use linux_embedded_hal::I2cdev; //! //! let i2c = I2cdev::new("/dev/i2c-1").unwrap(); //! let adc = Ads1013::new(i2c, TargetAddr::default()); //! match adc.into_continuous() { -//! Err(ModeChangeError::I2C(e, adc)) => { +//! Err((e, adc)) => { //! panic!("Mode change failed: {e}") //! }, //! Ok(mut adc) => { @@ -196,7 +196,7 @@ mod types; use crate::types::Config; pub use crate::types::{ mode, ComparatorLatching, ComparatorMode, ComparatorPolarity, ComparatorQueue, DataRate12Bit, - DataRate16Bit, Error, FullScaleRange, ModeChangeError, TargetAddr, + DataRate16Bit, Error, FullScaleRange, TargetAddr, }; struct Register; diff --git a/src/types.rs b/src/types.rs index 2980ee3..4793b3a 100644 --- a/src/types.rs +++ b/src/types.rs @@ -11,17 +11,6 @@ pub enum Error { InvalidInputData, } -/// Error type for mode changes. -/// -/// This allows to retrieve the unchanged device in case of an error. -pub enum ModeChangeError { - /// I²C bus error while changing mode. - /// - /// `E` is the error that happened. - /// `DEV` is the device with the mode unchanged. - I2C(E, DEV), -} - /// Mode marker types pub mod mode { /// One-shot operating mode / power-down state (default) From 923effbde3641d449b213e87f3a35bda00481f43 Mon Sep 17 00:00:00 2001 From: Markus Reiter Date: Fri, 19 Jan 2024 17:58:55 +0100 Subject: [PATCH 09/14] Make `convert_threshold` panic. --- src/devices/features/tier2.rs | 49 ++++++++++++++++++++++----------- src/ic.rs | 51 +++++++++++++++-------------------- 2 files changed, 55 insertions(+), 45 deletions(-) diff --git a/src/devices/features/tier2.rs b/src/devices/features/tier2.rs index fe3776b..c548883 100644 --- a/src/devices/features/tier2.rs +++ b/src/devices/features/tier2.rs @@ -5,8 +5,27 @@ use crate::{ ComparatorPolarity, ComparatorQueue, Error, FullScaleRange, Register, }; +macro_rules! doc_threshold { + (-32768, 32767) => { + "" + }; + ($th_low:literal, $th_high:literal) => { + concat!( + "The given value must be within \\[", + stringify!($th_low), + ", ", + stringify!($th_high), + "\\].\n\n# Panics\n\nPanics if the threshold is outside the \\[", + stringify!($th_low), + ", ", + stringify!($th_high), + "\\] range." + ) + }; +} + macro_rules! impl_tier2_features { - ($Ads:ident, $conv:ty) => { + ($Ads:ident, $conv:ty, [$($th_range:tt)+]) => { impl $Ads where I2C: embedded_hal::i2c::I2c, @@ -54,23 +73,23 @@ macro_rules! impl_tier2_features { /// 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. + /// The voltage that these values correspond to must be calculated using the + /// full-scale range ([`FullScaleRange`]) selected. + /// + #[doc = doc_threshold!($($th_range)+)] pub fn set_low_threshold_raw(&mut self, value: i16) -> Result<(), Error> { - let register_value = <$conv>::convert_threshold(value)?; + let register_value = <$conv>::convert_threshold(value); self.write_register(Register::LOW_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. + /// The voltage that these values correspond to must be calculated using the + /// full-scale range ([`FullScaleRange`]) selected. + /// + #[doc = doc_threshold!($($th_range)+)] pub fn set_high_threshold_raw(&mut self, value: i16) -> Result<(), Error> { - let register_value = <$conv>::convert_threshold(value)?; + let register_value = <$conv>::convert_threshold(value); self.write_register(Register::HIGH_TH, register_value) } @@ -171,7 +190,7 @@ macro_rules! impl_tier2_features { }; } -impl_tier2_features!(Ads1014, ic::Resolution12Bit); -impl_tier2_features!(Ads1015, ic::Resolution12Bit); -impl_tier2_features!(Ads1114, ic::Resolution16Bit); -impl_tier2_features!(Ads1115, ic::Resolution16Bit); +impl_tier2_features!(Ads1014, ic::Resolution12Bit, [-2048, 2047]); +impl_tier2_features!(Ads1015, ic::Resolution12Bit, [-2048, 2047]); +impl_tier2_features!(Ads1114, ic::Resolution16Bit, [-32768, 32767]); +impl_tier2_features!(Ads1115, ic::Resolution16Bit, [-32768, 32767]); diff --git a/src/ic.rs b/src/ic.rs index b093553..76ac94d 100644 --- a/src/ic.rs +++ b/src/ic.rs @@ -1,13 +1,12 @@ -use crate::Error; - pub(crate) struct Resolution12Bit; impl Resolution12Bit { - pub fn convert_threshold(value: i16) -> Result> { + pub fn convert_threshold(value: i16) -> u16 { if !(-2048..=2047).contains(&value) { - return Err(Error::InvalidInputData); + panic!("Threshold must be between -2048 and 2047, but is {value}.") } - Ok((value << 4) as u16) + + (value << 4) as u16 } pub fn convert_measurement(register_data: u16) -> i16 { @@ -25,8 +24,8 @@ impl Resolution12Bit { pub(crate) struct Resolution16Bit; impl Resolution16Bit { - pub fn convert_threshold(value: i16) -> Result> { - Ok(value as u16) + pub fn convert_threshold(value: i16) -> u16 { + value as u16 } pub fn convert_measurement(register_data: u16) -> i16 { @@ -39,7 +38,7 @@ mod tests { use super::*; #[test] - fn convert_measurement_12_bits() { + fn convert_measurement_12bit() { assert_eq!(0, Resolution12Bit::convert_measurement(0)); assert_eq!(2047, Resolution12Bit::convert_measurement(0x7FFF)); assert_eq!(-2048, Resolution12Bit::convert_measurement(0x8000)); @@ -47,44 +46,36 @@ mod tests { } #[test] - fn convert_measurement_16_bits() { + fn convert_measurement_16bit() { 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)); + fn convert_threshold_12bit() { + assert_eq!(0, Resolution12Bit::convert_threshold(0)); + assert_eq!(0x7FF0, Resolution12Bit::convert_threshold(2047)); + assert_eq!(0x8000, Resolution12Bit::convert_threshold(-2048)); + assert_eq!(0xFFF0, Resolution12Bit::convert_threshold(-1)); } #[test] #[should_panic] - fn check_assert_fails() { - assert_invalid_input_data::<()>(Ok(0)); + fn convert_threshold_12bit_invalid_low() { + Resolution12Bit::convert_threshold(-2049); } #[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)); + #[should_panic] + fn convert_threshold_12bit_invalid_high() { + Resolution12Bit::convert_threshold(2048); } #[test] - fn convert_threshold_16_bits() { - assert_eq!(Ok(0x7FFF), Resolution16Bit::convert_threshold::<()>(32767)); - assert_eq!(Ok(0x8000), Resolution16Bit::convert_threshold::<()>(-32768)); + fn convert_threshold_16bit() { + assert_eq!(0x7FFF, Resolution16Bit::convert_threshold(32767)); + assert_eq!(0x8000, Resolution16Bit::convert_threshold(-32768)); } } From 5b3838a2d54463bc599f7a0147cc3d2a7d221617 Mon Sep 17 00:00:00 2001 From: Markus Reiter Date: Sun, 14 Jan 2024 01:55:23 +0100 Subject: [PATCH 10/14] Move `mode` module to separate file. --- src/lib.rs | 4 +++- src/mode.rs | 9 +++++++++ src/types.rs | 11 ----------- 3 files changed, 12 insertions(+), 12 deletions(-) create mode 100644 src/mode.rs diff --git a/src/lib.rs b/src/lib.rs index 7b42a76..830f99f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -195,9 +195,11 @@ mod ic; mod types; use crate::types::Config; pub use crate::types::{ - mode, ComparatorLatching, ComparatorMode, ComparatorPolarity, ComparatorQueue, DataRate12Bit, + ComparatorLatching, ComparatorMode, ComparatorPolarity, ComparatorQueue, DataRate12Bit, DataRate16Bit, Error, FullScaleRange, TargetAddr, }; +pub mod mode; +pub use mode::*; struct Register; diff --git a/src/mode.rs b/src/mode.rs new file mode 100644 index 0000000..da60d3d --- /dev/null +++ b/src/mode.rs @@ -0,0 +1,9 @@ +//! ADS1x1x operation modes. + +/// Marker type for an ADS1x1x in one-shot mode. +#[non_exhaustive] +pub struct OneShot; + +/// Marker type for an ADS1x1x in continuous conversion mode. +#[non_exhaustive] +pub struct Continuous; diff --git a/src/types.rs b/src/types.rs index 4793b3a..7b2ac5c 100644 --- a/src/types.rs +++ b/src/types.rs @@ -11,17 +11,6 @@ pub enum Error { InvalidInputData, } -/// Mode marker types -pub mod mode { - /// One-shot operating mode / power-down state (default) - #[non_exhaustive] - pub struct OneShot; - - /// Continuous conversion mode - #[non_exhaustive] - pub struct Continuous; -} - /// Data rate for ADS101x. #[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Ord, PartialOrd, Hash)] pub enum DataRate12Bit { From 44ffd3d91297849310ca93745108a362346ada8e Mon Sep 17 00:00:00 2001 From: Markus Reiter Date: Sun, 14 Jan 2024 03:34:35 +0100 Subject: [PATCH 11/14] Use bitflags and register traits. --- Cargo.toml | 3 +- src/channel.rs | 52 ++++---- src/devices/common.rs | 33 +---- src/devices/features/tier1.rs | 6 +- src/devices/features/tier2.rs | 92 +++++-------- src/devices/mode/continuous.rs | 24 ++-- src/devices/mode/oneshot.rs | 28 ++-- src/ic.rs | 81 ----------- src/lib.rs | 86 ++++++------ src/register.rs | 236 +++++++++++++++++++++++++++++++++ src/types.rs | 148 +++++++++++++-------- tests/common/mod.rs | 4 +- tests/mux.rs | 10 +- tests/tier1.rs | 104 +++++++-------- tests/tier2.rs | 72 +++++----- 15 files changed, 557 insertions(+), 422 deletions(-) delete mode 100644 src/ic.rs create mode 100644 src/register.rs diff --git a/Cargo.toml b/Cargo.toml index 6cadb28..8d63b6e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,8 +21,9 @@ include = [ edition = "2021" [dependencies] -nb = "1" +bitflags = "2" embedded-hal = "1" +nb = "1" [dev-dependencies] embedded-hal-mock = { version = "0.10", default-features = false, features = ["eh1"] } diff --git a/src/channel.rs b/src/channel.rs index 2883b69..98e0ce7 100644 --- a/src/channel.rs +++ b/src/channel.rs @@ -1,6 +1,5 @@ //! ADC input channels. - -use crate::{Ads1013, Ads1014, Ads1015, Ads1113, Ads1114, Ads1115, BitFlags as BF, Config}; +use crate::{Ads1013, Ads1014, Ads1015, Ads1113, Ads1114, Ads1115, Config}; use private::ChannelSelection; @@ -65,37 +64,36 @@ 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), + .difference(Self::MUX2) + .difference(Self::MUX1) + .difference(Self::MUX0), ChannelSelection::DifferentialA0A3 => self - .with_low(BF::MUX2) - .with_low(BF::MUX1) - .with_high(BF::MUX0), + .difference(Self::MUX2) + .difference(Self::MUX1) + .union(Self::MUX0), ChannelSelection::DifferentialA1A3 => self - .with_low(BF::MUX2) - .with_high(BF::MUX1) - .with_low(BF::MUX0), + .difference(Self::MUX2) + .union(Self::MUX1) + .difference(Self::MUX0), ChannelSelection::DifferentialA2A3 => self - .with_low(BF::MUX2) - .with_high(BF::MUX1) - .with_high(BF::MUX0), + .difference(Self::MUX2) + .union(Self::MUX1) + .union(Self::MUX0), ChannelSelection::SingleA0 => self - .with_high(BF::MUX2) - .with_low(BF::MUX1) - .with_low(BF::MUX0), + .union(Self::MUX2) + .difference(Self::MUX1) + .difference(Self::MUX0), ChannelSelection::SingleA1 => self - .with_high(BF::MUX2) - .with_low(BF::MUX1) - .with_high(BF::MUX0), + .union(Self::MUX2) + .difference(Self::MUX1) + .union(Self::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), + .union(Self::MUX2) + .union(Self::MUX1) + .difference(Self::MUX0), + ChannelSelection::SingleA3 => { + self.union(Self::MUX2).union(Self::MUX1).union(Self::MUX0) + } } } } diff --git a/src/devices/common.rs b/src/devices/common.rs index bee4b7e..f5c69cf 100644 --- a/src/devices/common.rs +++ b/src/devices/common.rs @@ -1,8 +1,7 @@ //! Common functions. use crate::{ - devices::OperatingMode, Ads1013, Ads1014, Ads1015, Ads1113, Ads1114, Ads1115, BitFlags, Config, - Error, Register, + devices::OperatingMode, Ads1013, Ads1014, Ads1015, Ads1113, Ads1114, Ads1115, Config, Error, }; macro_rules! impl_common_features { @@ -11,43 +10,23 @@ macro_rules! impl_common_features { where I2C: embedded_hal::i2c::I2c, { - pub(super) 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) - } - - pub(super) fn read_register(&mut self, register: u8) -> Result> { - let mut data = [0, 0]; - self.i2c - .write_read(self.address, &[register], &mut data) - .map_err(Error::I2C) - .and(Ok(u16::from_be_bytes(data))) - } - 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), + OperatingMode::OneShot => self.config.union(Config::MODE), + OperatingMode::Continuous => self.config.difference(Config::MODE), }; - self.write_register(Register::CONFIG, config.bits)?; + self.write_reg_u16(config)?; self.config = config; Ok(()) } /// Checks whether a measurement is currently in progress. pub fn is_measurement_in_progress(&mut self) -> Result> { - let config = Config { - bits: self.read_register(Register::CONFIG)?, - }; - Ok(!config.is_high(BitFlags::OS)) + let config = self.read_reg_u16::()?; + Ok(!config.contains(Config::OS)) } } }; diff --git a/src/devices/features/tier1.rs b/src/devices/features/tier1.rs index 017089c..6a1f34a 100644 --- a/src/devices/features/tier1.rs +++ b/src/devices/features/tier1.rs @@ -2,7 +2,6 @@ use crate::{ Ads1013, Ads1014, Ads1015, Ads1113, Ads1114, Ads1115, DataRate12Bit, DataRate16Bit, Error, - Register, }; macro_rules! impl_tier1_features { @@ -13,9 +12,8 @@ macro_rules! impl_tier1_features { { /// 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.write_register(Register::CONFIG, config.bits)?; + let config = rate.configure(self.config); + self.write_reg_u16(config)?; self.config = config; Ok(()) } diff --git a/src/devices/features/tier2.rs b/src/devices/features/tier2.rs index c548883..8ec3443 100644 --- a/src/devices/features/tier2.rs +++ b/src/devices/features/tier2.rs @@ -1,8 +1,9 @@ //! Features only supported by ADS1x14 and ADS1x15 devices. use crate::{ - ic, Ads1014, Ads1015, Ads1114, Ads1115, BitFlags as BF, ComparatorLatching, ComparatorMode, - ComparatorPolarity, ComparatorQueue, Error, FullScaleRange, Register, + register::{Conversion12, Conversion16, HiThresh, LoThresh}, + Ads1014, Ads1015, Ads1114, Ads1115, ComparatorLatching, ComparatorMode, ComparatorPolarity, + ComparatorQueue, Config, Error, FullScaleRange, }; macro_rules! doc_threshold { @@ -34,39 +35,8 @@ macro_rules! impl_tier2_features { /// /// 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> { - let config = match range { - FullScaleRange::Within6_144V => self - .config - .with_low(BF::PGA2) - .with_low(BF::PGA1) - .with_low(BF::PGA0), - FullScaleRange::Within4_096V => self - .config - .with_low(BF::PGA2) - .with_low(BF::PGA1) - .with_high(BF::PGA0), - FullScaleRange::Within2_048V => self - .config - .with_low(BF::PGA2) - .with_high(BF::PGA1) - .with_low(BF::PGA0), - FullScaleRange::Within1_024V => self - .config - .with_low(BF::PGA2) - .with_high(BF::PGA1) - .with_high(BF::PGA0), - FullScaleRange::Within0_512V => self - .config - .with_high(BF::PGA2) - .with_low(BF::PGA1) - .with_low(BF::PGA0), - FullScaleRange::Within0_256V => self - .config - .with_high(BF::PGA2) - .with_low(BF::PGA1) - .with_high(BF::PGA0), - }; - self.write_register(Register::CONFIG, config.bits)?; + let config = range.configure(self.config); + self.write_reg_u16(config)?; self.config = config; Ok(()) } @@ -79,7 +49,7 @@ macro_rules! impl_tier2_features { #[doc = doc_threshold!($($th_range)+)] pub fn set_low_threshold_raw(&mut self, value: i16) -> Result<(), Error> { let register_value = <$conv>::convert_threshold(value); - self.write_register(Register::LOW_TH, register_value) + self.write_reg_u16(LoThresh(register_value)) } /// Sets the raw comparator upper threshold. @@ -90,16 +60,16 @@ macro_rules! impl_tier2_features { #[doc = doc_threshold!($($th_range)+)] pub fn set_high_threshold_raw(&mut self, value: i16) -> Result<(), Error> { let register_value = <$conv>::convert_threshold(value); - self.write_register(Register::HIGH_TH, register_value) + self.write_reg_u16(HiThresh(register_value)) } /// 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), + ComparatorMode::Traditional => self.config.difference(Config::COMP_MODE), + ComparatorMode::Window => self.config.union(Config::COMP_MODE), }; - self.write_register(Register::CONFIG, config.bits)?; + self.write_reg_u16(config)?; self.config = config; Ok(()) } @@ -110,10 +80,10 @@ macro_rules! impl_tier2_features { 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), + ComparatorPolarity::ActiveLow => self.config.difference(Config::COMP_POL), + ComparatorPolarity::ActiveHigh => self.config.union(Config::COMP_POL), }; - self.write_register(Register::CONFIG, config.bits)?; + self.write_reg_u16(config)?; self.config = config; Ok(()) } @@ -124,10 +94,10 @@ macro_rules! impl_tier2_features { 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), + ComparatorLatching::Nonlatching => self.config.difference(Config::COMP_LAT), + ComparatorLatching::Latching => self.config.union(Config::COMP_LAT), }; - self.write_register(Register::CONFIG, config.bits)?; + self.write_reg_u16(config)?; self.config = config; Ok(()) } @@ -138,16 +108,16 @@ macro_rules! impl_tier2_features { 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) + self.config.difference(Config::COMP_QUE1).difference(Config::COMP_QUE0) } ComparatorQueue::Two => { - self.config.with_low(BF::COMP_QUE1).with_high(BF::COMP_QUE0) + self.config.difference(Config::COMP_QUE1).union(Config::COMP_QUE0) } ComparatorQueue::Four => { - self.config.with_high(BF::COMP_QUE1).with_low(BF::COMP_QUE0) + self.config.union(Config::COMP_QUE1).difference(Config::COMP_QUE0) } }; - self.write_register(Register::CONFIG, config.bits)?; + self.write_reg_u16(config)?; self.config = config; Ok(()) } @@ -161,9 +131,9 @@ macro_rules! impl_tier2_features { pub fn disable_comparator(&mut self) -> Result<(), Error> { let config = self .config - .with_high(BF::COMP_QUE1) - .with_high(BF::COMP_QUE0); - self.write_register(Register::CONFIG, config.bits)?; + .union(Config::COMP_QUE1) + .union(Config::COMP_QUE0); + self.write_reg_u16(config)?; self.config = config; Ok(()) } @@ -178,19 +148,19 @@ macro_rules! impl_tier2_features { if self.config != self .config - .with_high(BF::COMP_QUE1) - .with_high(BF::COMP_QUE0) + .union(Config::COMP_QUE1) + .union(Config::COMP_QUE0) { self.set_comparator_queue(ComparatorQueue::default())?; } - self.write_register(Register::HIGH_TH, 0x8000)?; - self.write_register(Register::LOW_TH, 0) + self.write_reg_u16(HiThresh(0x8000))?; + self.write_reg_u16(LoThresh(0)) } } }; } -impl_tier2_features!(Ads1014, ic::Resolution12Bit, [-2048, 2047]); -impl_tier2_features!(Ads1015, ic::Resolution12Bit, [-2048, 2047]); -impl_tier2_features!(Ads1114, ic::Resolution16Bit, [-32768, 32767]); -impl_tier2_features!(Ads1115, ic::Resolution16Bit, [-32768, 32767]); +impl_tier2_features!(Ads1014, Conversion12, [-2048, 2047]); +impl_tier2_features!(Ads1015, Conversion12, [-2048, 2047]); +impl_tier2_features!(Ads1114, Conversion16, [-32768, 32767]); +impl_tier2_features!(Ads1115, Conversion16, [-32768, 32767]); diff --git a/src/devices/mode/continuous.rs b/src/devices/mode/continuous.rs index afb4ec4..2a62a82 100644 --- a/src/devices/mode/continuous.rs +++ b/src/devices/mode/continuous.rs @@ -1,8 +1,10 @@ //! Continuous measurement mode. use crate::{ - devices::OperatingMode, ic, mode, Ads1013, Ads1014, Ads1015, Ads1113, Ads1114, Ads1115, - ChannelId, Error, Register, + devices::OperatingMode, + mode, + register::{Conversion12, Conversion16}, + Ads1013, Ads1014, Ads1015, Ads1113, Ads1114, Ads1115, ChannelId, Error, }; use core::marker::PhantomData; @@ -30,8 +32,8 @@ macro_rules! impl_continuous { /// Reads the most recent measurement. pub fn read(&mut self) -> Result> { - let value = self.read_register(Register::CONVERSION)?; - Ok(<$conv>::convert_measurement(value)) + let value = self.read_reg_u16::<$conv>()?; + Ok(<$conv>::convert_measurement(value.0)) } /// Selects the channel used for measurements. @@ -45,7 +47,7 @@ macro_rules! impl_continuous { channel: CH, ) -> Result<(), Error> { let config = self.config.with_mux_bits(CH::channel_id()); - self.write_register(Register::CONFIG, config.bits)?; + self.write_reg_u16(config)?; self.config = config; Ok(()) } @@ -53,9 +55,9 @@ macro_rules! impl_continuous { }; } -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); +impl_continuous!(Ads1013, Conversion12); +impl_continuous!(Ads1014, Conversion12); +impl_continuous!(Ads1015, Conversion12); +impl_continuous!(Ads1113, Conversion16); +impl_continuous!(Ads1114, Conversion16); +impl_continuous!(Ads1115, Conversion16); diff --git a/src/devices/mode/oneshot.rs b/src/devices/mode/oneshot.rs index 309b662..155e227 100644 --- a/src/devices/mode/oneshot.rs +++ b/src/devices/mode/oneshot.rs @@ -3,8 +3,10 @@ use core::marker::PhantomData; use crate::{ - devices::OperatingMode, ic, mode, Ads1013, Ads1014, Ads1015, Ads1113, Ads1114, Ads1115, - BitFlags, ChannelId, Config, Error, Register, + devices::OperatingMode, + mode, + register::{Conversion12, Conversion16}, + Ads1013, Ads1014, Ads1015, Ads1113, Ads1114, Ads1115, ChannelId, Config, Error, }; macro_rules! impl_one_shot { @@ -32,8 +34,8 @@ macro_rules! impl_one_shot { } fn trigger_measurement(&mut self, config: &Config) -> Result<(), Error> { - let config = config.with_high(BitFlags::OS); - self.write_register(Register::CONFIG, config.bits) + let config = config.union(Config::OS); + self.write_reg_u16(config) } /// Requests that the ADC begins a conversion on the specified channel. @@ -60,11 +62,9 @@ macro_rules! impl_one_shot { let same_channel = self.config == config; if self.a_conversion_was_started && same_channel { // result is ready - let value = self - .read_register(Register::CONVERSION) - .map_err(nb::Error::Other)?; + let value = self.read_reg_u16::<$conv>().map_err(nb::Error::Other)?; self.a_conversion_was_started = false; - return Ok(<$conv>::convert_measurement(value)); + return Ok(<$conv>::convert_measurement(value.0)); } self.trigger_measurement(&config) .map_err(nb::Error::Other)?; @@ -76,9 +76,9 @@ macro_rules! impl_one_shot { }; } -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); +impl_one_shot!(Ads1013, Conversion12); +impl_one_shot!(Ads1014, Conversion12); +impl_one_shot!(Ads1015, Conversion12); +impl_one_shot!(Ads1113, Conversion16); +impl_one_shot!(Ads1114, Conversion16); +impl_one_shot!(Ads1115, Conversion16); diff --git a/src/ic.rs b/src/ic.rs deleted file mode 100644 index 76ac94d..0000000 --- a/src/ic.rs +++ /dev/null @@ -1,81 +0,0 @@ -pub(crate) struct Resolution12Bit; - -impl Resolution12Bit { - pub fn convert_threshold(value: i16) -> u16 { - if !(-2048..=2047).contains(&value) { - panic!("Threshold must be between -2048 and 2047, but is {value}.") - } - - (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 - } - } -} - -pub(crate) struct Resolution16Bit; - -impl Resolution16Bit { - pub fn convert_threshold(value: i16) -> u16 { - value as u16 - } - - pub fn convert_measurement(register_data: u16) -> i16 { - register_data as i16 - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn convert_measurement_12bit() { - 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_16bit() { - 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)); - } - - #[test] - fn convert_threshold_12bit() { - assert_eq!(0, Resolution12Bit::convert_threshold(0)); - assert_eq!(0x7FF0, Resolution12Bit::convert_threshold(2047)); - assert_eq!(0x8000, Resolution12Bit::convert_threshold(-2048)); - assert_eq!(0xFFF0, Resolution12Bit::convert_threshold(-1)); - } - - #[test] - #[should_panic] - fn convert_threshold_12bit_invalid_low() { - Resolution12Bit::convert_threshold(-2049); - } - - #[test] - #[should_panic] - fn convert_threshold_12bit_invalid_high() { - Resolution12Bit::convert_threshold(2048); - } - - #[test] - fn convert_threshold_16bit() { - assert_eq!(0x7FFF, Resolution16Bit::convert_threshold(32767)); - assert_eq!(0x8000, Resolution16Bit::convert_threshold(-32768)); - } -} diff --git a/src/lib.rs b/src/lib.rs index 830f99f..4c332de 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -191,66 +191,34 @@ use core::marker::PhantomData; pub mod channel; pub use channel::ChannelId; mod devices; -mod ic; mod types; -use crate::types::Config; -pub use crate::types::{ +pub use types::{ ComparatorLatching, ComparatorMode, ComparatorPolarity, ComparatorQueue, DataRate12Bit, DataRate16Bit, Error, FullScaleRange, TargetAddr, }; pub mod mode; pub use mode::*; - -struct Register; - -#[rustfmt::skip] -impl Register { - const CONVERSION: u8 = 0x00; - 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 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_QUE1: u16 = 0b0000_0000_0000_0010; - const COMP_QUE0: u16 = 0b0000_0000_0000_0001; -} +pub(crate) mod register; +use register::{Config, ReadReg, WriteReg}; macro_rules! impl_ads1x1x { - ($Ads:ident) => { - /// ADS1x1x ADC driver + ($name:expr, $Ads:ident) => { + #[doc = concat!("An ", $name, " ADC.")] #[derive(Debug)] pub struct $Ads { pub(crate) i2c: I2C, - pub(crate) address: u8, + pub(crate) address: TargetAddr, pub(crate) config: Config, pub(crate) a_conversion_was_started: bool, pub(crate) mode: PhantomData, } impl $Ads { - /// Create a new instance of the device in one-shot mode. + #[doc = concat!("Creates a new ", $name, " instance in one-shot mode.")] pub fn new(i2c: I2C, address: TargetAddr) -> Self { $Ads { i2c, - address: address.bits(), + address, config: Config::default(), a_conversion_was_started: false, mode: PhantomData, @@ -258,8 +226,32 @@ macro_rules! impl_ads1x1x { } } + impl $Ads + where + I2C: embedded_hal::i2c::I2c, + { + pub(crate) fn read_reg_u16>(&mut self) -> Result> { + let mut buf = [0, 0]; + self.i2c + .write_read(self.address.bits(), &[R::ADDR], &mut buf) + .map_err(Error::I2C)?; + Ok(R::from_reg(u16::from_be_bytes(buf))) + } + + pub(crate) fn write_reg_u16>( + &mut self, + reg: R, + ) -> Result<(), Error> { + let buf = reg.to_reg().to_be_bytes(); + let payload: [u8; 3] = [R::ADDR, buf[0], buf[1]]; + self.i2c + .write(self.address.bits(), &payload) + .map_err(Error::I2C) + } + } + impl $Ads { - /// Release the contained I²C peripheral. + /// Releases the contained I²C peripheral. pub fn release(self) -> I2C { self.i2c } @@ -267,9 +259,9 @@ macro_rules! impl_ads1x1x { }; } -impl_ads1x1x!(Ads1013); -impl_ads1x1x!(Ads1113); -impl_ads1x1x!(Ads1014); -impl_ads1x1x!(Ads1114); -impl_ads1x1x!(Ads1015); -impl_ads1x1x!(Ads1115); +impl_ads1x1x!("ADS1013", Ads1013); +impl_ads1x1x!("ADS1113", Ads1113); +impl_ads1x1x!("ADS1014", Ads1014); +impl_ads1x1x!("ADS1114", Ads1114); +impl_ads1x1x!("ADS1015", Ads1015); +impl_ads1x1x!("ADS1115", Ads1115); diff --git a/src/register.rs b/src/register.rs new file mode 100644 index 0000000..76d12e5 --- /dev/null +++ b/src/register.rs @@ -0,0 +1,236 @@ +/// Read a register. +pub trait ReadReg +where + Self: Sized, +{ + /// Register address. + const ADDR: u8; + + /// Read a register. + fn from_reg(reg: R) -> Self; +} + +/// Write a register. +pub trait WriteReg: ReadReg { + /// Write a register. + fn to_reg(self) -> R; +} + +macro_rules! register { + (@impl_read_reg $Reg:ident : $addr:literal : $RegTy:ty) => { + impl ReadReg<$RegTy> for $Reg { + const ADDR: u8 = $addr; + + #[inline] + fn from_reg(reg: $RegTy) -> Self { + $Reg::from_bits_truncate(reg) + } + } + }; + (@impl_write_reg $Reg:ident : $addr:literal : $RegTy:ty) => { + impl WriteReg<$RegTy> for $Reg { + fn to_reg(self) -> $RegTy { + self.bits() + } + } + }; + ( + #[doc = $name:expr] + $vis:vis struct $Reg:ident($RegTy:ty): $addr:literal; + ) => { + #[doc = concat!($name, " register (`", stringify!($addr), "`)")] + $vis struct $Reg(pub(crate) $RegTy); + + impl $Reg { + const fn from_bits_truncate(bits: $RegTy) -> Self { + Self(bits) + } + + const fn bits(self) -> $RegTy { + self.0 + } + } + + register!(@impl_read_reg $Reg: $addr: $RegTy); + register!(@impl_write_reg $Reg: $addr: $RegTy); + }; + ( + #[doc = $name:expr] + $vis:vis struct $Reg:ident : $addr:literal : $RegTy:ty { + $( + $(#[$inner:ident $($args:tt)*])* + const $const_name:ident = $const_value:expr; + )* + } + ) => { + ::bitflags::bitflags! { + #[doc = concat!($name, " register (`", stringify!($addr), "`)")] + #[derive(Debug, Clone, Copy, PartialEq, Eq)] + $vis struct $Reg: $RegTy { + $( + $(#[$inner $($args)*])* + const $const_name = $const_value; + )* + } + } + + register!(@impl_read_reg $Reg: $addr: $RegTy); + register!(@impl_write_reg $Reg: $addr: $RegTy); + }; +} + +register! { + /// 12-bit Conversion + pub struct Conversion12(u16): 0x00; +} + +impl Conversion12 { + pub fn convert_threshold(value: i16) -> u16 { + if !(-2048..=2047).contains(&value) { + panic!("Threshold must be between -2048 and 2047, but is {value}.") + } + + (value << 4) as u16 + } + + pub const 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 + } + } +} + +register! { + /// 16-bit Conversion + pub struct Conversion16(u16): 0x00; +} + +impl Conversion16 { + pub const fn convert_threshold(value: i16) -> u16 { + value as u16 + } + + pub const fn convert_measurement(register_data: u16) -> i16 { + register_data as i16 + } +} + +register! { + /// Config + pub struct Config: 0x01: u16 { + /// Operational status or single-shot conversion start + const OS = 0b10000000_00000000; + /// Input multiplexer configuration bit 2 (ADS1115 only) + const MUX2 = 0b01000000_00000000; + /// Input multiplexer configuration bit 1 (ADS1115 only) + const MUX1 = 0b00100000_00000000; + /// Input multiplexer configuration bit 0 (ADS1115 only) + const MUX0 = 0b00010000_00000000; + /// Programmable gain amplifier configuration bit 2 + const PGA2 = 0b00001000_00000000; + /// Programmable gain amplifier configuration bit 1 + const PGA1 = 0b00000100_00000000; + /// Programmable gain amplifier configuration bit 0 + const PGA0 = 0b00000010_00000000; + /// Device operating mode + const MODE = 0b00000001_00000000; + /// Data rate bit 2 + const DR2 = 0b00000000_10000000; + /// Data rate bit 1 + const DR1 = 0b00000000_01000000; + /// Data rate bit ß + const DR0 = 0b00000000_00100000; + /// Comparator mode (ADS1114 and ADS1115 only) + const COMP_MODE = 0b00000000_00010000; + /// Comparator polarity (ADS1114 and ADS1115 only) + const COMP_POL = 0b00000000_00001000; + /// Latching comparator (ADS1114 and ADS1115 only) + const COMP_LAT = 0b00000000_00000100; + /// Comparator queue and disable bit 1 (ADS1114 and ADS1115 only) + const COMP_QUE1 = 0b00000000_00000010; + /// Comparator queue and disable bit 0 (ADS1114 and ADS1115 only) + const COMP_QUE0 = 0b00000000_00000001; + + /// Input multiplexer configuration (ADS1115 only) + const MUX = Self::MUX2.bits() | Self::MUX1.bits() | Self::MUX0.bits(); + /// Programmable gain amplifier configuration + const PGA = Self::PGA2.bits() | Self::PGA1.bits() | Self::PGA0.bits(); + /// Data rate + const DR = Self::DR2.bits() | Self::DR1.bits() | Self::DR0.bits(); + /// Comparator queue and disable (ADS1114 and ADS1115 only) + const COMP_QUE = Self::COMP_QUE1.bits() | Self::COMP_QUE0.bits(); + } +} + +impl Default for Config { + fn default() -> Self { + Self::OS + .union(Self::PGA1) + .union(Self::MODE) + .union(Self::DR2) + .union(Self::COMP_QUE1) + .union(Self::COMP_QUE0) + } +} + +register! { + /// Lo_thresh + pub struct LoThresh(u16): 0x02; +} + +register! { + /// Hi_thresh + pub struct HiThresh(u16): 0x03; +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn convert_measurement_12bit() { + assert_eq!(0, Conversion12::convert_measurement(0)); + assert_eq!(2047, Conversion12::convert_measurement(0x7FFF)); + assert_eq!(-2048, Conversion12::convert_measurement(0x8000)); + assert_eq!(-1, Conversion12::convert_measurement(0xFFFF)); + } + + #[test] + fn convert_measurement_16bit() { + assert_eq!(0, Conversion16::convert_measurement(0)); + assert_eq!(32767, Conversion16::convert_measurement(0x7FFF)); + assert_eq!(-32768, Conversion16::convert_measurement(0x8000)); + assert_eq!(-1, Conversion16::convert_measurement(0xFFFF)); + } + + #[test] + fn convert_threshold_12bit() { + assert_eq!(0, Conversion12::convert_threshold(0)); + assert_eq!(0x7FF0, Conversion12::convert_threshold(2047)); + assert_eq!(0x8000, Conversion12::convert_threshold(-2048)); + assert_eq!(0xFFF0, Conversion12::convert_threshold(-1)); + } + + #[test] + #[should_panic] + fn convert_threshold_12bit_invalid_low() { + Conversion12::convert_threshold(-2049); + } + + #[test] + #[should_panic] + fn convert_threshold_12bit_invalid_high() { + Conversion12::convert_threshold(2048); + } + + #[test] + fn convert_threshold_16bit() { + assert_eq!(0x7FFF, Conversion16::convert_threshold(32767)); + assert_eq!(0x8000, Conversion16::convert_threshold(-32768)); + } +} diff --git a/src/types.rs b/src/types.rs index 7b2ac5c..514937d 100644 --- a/src/types.rs +++ b/src/types.rs @@ -1,6 +1,6 @@ //! Type definitions. -use crate::BitFlags as BF; +use crate::Config; /// Errors in this crate #[derive(Debug, PartialEq)] @@ -32,16 +32,37 @@ pub enum DataRate12Bit { } 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), - }; + pub(crate) fn configure(self, cfg: Config) -> Config { + match self { + Self::Sps128 => cfg + .difference(Config::DR2) + .difference(Config::DR1) + .difference(Config::DR0), + Self::Sps250 => cfg + .difference(Config::DR2) + .difference(Config::DR1) + .union(Config::DR0), + Self::Sps490 => cfg + .difference(Config::DR2) + .union(Config::DR1) + .difference(Config::DR0), + Self::Sps920 => cfg + .difference(Config::DR2) + .union(Config::DR1) + .union(Config::DR0), + Self::Sps1600 => cfg + .union(Config::DR2) + .difference(Config::DR1) + .difference(Config::DR0), + Self::Sps2400 => cfg + .union(Config::DR2) + .difference(Config::DR1) + .union(Config::DR0), + Self::Sps3300 => cfg + .union(Config::DR2) + .union(Config::DR1) + .difference(Config::DR0), + } } } @@ -68,17 +89,38 @@ pub enum DataRate16Bit { } 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), - }; + pub(crate) fn configure(self, cfg: Config) -> Config { + match self { + Self::Sps8 => cfg + .difference(Config::DR2) + .difference(Config::DR1) + .difference(Config::DR0), + Self::Sps16 => cfg + .difference(Config::DR2) + .difference(Config::DR1) + .union(Config::DR0), + Self::Sps32 => cfg + .difference(Config::DR2) + .union(Config::DR1) + .difference(Config::DR0), + Self::Sps64 => cfg + .difference(Config::DR2) + .union(Config::DR1) + .union(Config::DR0), + Self::Sps128 => cfg + .union(Config::DR2) + .difference(Config::DR1) + .difference(Config::DR0), + Self::Sps250 => cfg + .union(Config::DR2) + .difference(Config::DR1) + .union(Config::DR0), + Self::Sps475 => cfg + .union(Config::DR2) + .union(Config::DR1) + .difference(Config::DR0), + Self::Sps860 => cfg.union(Config::DR2).union(Config::DR1).union(Config::DR0), + } } } @@ -169,7 +211,38 @@ pub enum FullScaleRange { Within0_256V, } -/// A target address. +impl FullScaleRange { + pub(crate) fn configure(self, config: Config) -> Config { + match self { + Self::Within6_144V => config + .difference(Config::PGA2) + .difference(Config::PGA1) + .difference(Config::PGA0), + Self::Within4_096V => config + .difference(Config::PGA2) + .difference(Config::PGA1) + .union(Config::PGA0), + Self::Within2_048V => config + .difference(Config::PGA2) + .union(Config::PGA1) + .difference(Config::PGA0), + Self::Within1_024V => config + .difference(Config::PGA2) + .union(Config::PGA1) + .union(Config::PGA0), + Self::Within0_512V => config + .union(Config::PGA2) + .difference(Config::PGA1) + .difference(Config::PGA0), + Self::Within0_256V => config + .union(Config::PGA2) + .difference(Config::PGA1) + .union(Config::PGA0), + } + } +} + +/// A slave address. /// /// 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). #[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Ord, PartialOrd, Hash)] @@ -200,35 +273,6 @@ impl TargetAddr { } } -#[derive(Debug, Clone, PartialEq)] -pub(crate) struct Config { - pub(crate) bits: u16, -} - -impl Config { - pub(crate) fn is_high(&self, mask: u16) -> bool { - (self.bits & mask) != 0 - } - - pub(crate) fn with_high(&self, mask: u16) -> Self { - Config { - bits: self.bits | mask, - } - } - - pub(crate) fn with_low(&self, mask: u16) -> Self { - Config { - bits: self.bits & !mask, - } - } -} - -impl Default for Config { - fn default() -> Self { - Config { bits: 0x8583 } - } -} - #[cfg(test)] mod tests { use crate::{FullScaleRange, TargetAddr}; diff --git a/tests/common/mod.rs b/tests/common/mod.rs index ada6985..2849ac0 100644 --- a/tests/common/mod.rs +++ b/tests/common/mod.rs @@ -40,12 +40,12 @@ pub struct Config { #[allow(dead_code)] impl Config { - pub fn with_high(&self, mask: u16) -> Self { + pub fn union(&self, mask: u16) -> Self { Config { bits: self.bits | mask, } } - pub fn with_low(&self, mask: u16) -> Self { + pub fn difference(&self, mask: u16) -> Self { Config { bits: self.bits & !mask, } diff --git a/tests/mux.rs b/tests/mux.rs index 2d2f2c6..89fadf0 100644 --- a/tests/mux.rs +++ b/tests/mux.rs @@ -16,7 +16,7 @@ macro_rules! mux_test { #[test] fn can_read() { let default_config = Config::default(); - let config = Config::default().with_high(BF::OS).with_high($config_bits); + let config = Config::default().union(BF::OS).union($config_bits); let transactions = [ I2cTrans::write_read( DEV_ADDR, @@ -40,8 +40,8 @@ macro_rules! mux_test { #[test] fn read_then_read_different_triggers_new_measurement() { let default_config = Config::default(); - let config = Config::default().with_high(BF::OS).with_high($config_bits); - let other_config = Config::default().with_high($other_config_bits); + let config = Config::default().union(BF::OS).union($config_bits); + let other_config = Config::default().union($other_config_bits); let transactions = [ I2cTrans::write_read( DEV_ADDR, @@ -74,8 +74,8 @@ macro_rules! mux_test { #[test] fn continuous_can_select_channel() { - let config1 = Config::default().with_low(BF::OP_MODE); - let config2 = config1.with_high($config_bits); + let config1 = Config::default().difference(BF::OP_MODE); + let config2 = config1.union($config_bits); let transactions = [ I2cTrans::write( DEV_ADDR, diff --git a/tests/tier1.rs b/tests/tier1.rs index d2008ba..1094731 100644 --- a/tests/tier1.rs +++ b/tests/tier1.rs @@ -18,7 +18,7 @@ macro_rules! measure_tests { #[test] fn read_if_measurement_in_progress() { - let config = Config::default().with_low(BF::OS); + let config = Config::default().difference(BF::OS); let transactions = [I2cTrans::write_read( DEV_ADDR, vec![Register::CONFIG], @@ -33,7 +33,7 @@ macro_rules! measure_tests { #[test] fn can_measure() { let default_config = Config::default(); - let config_with_os = Config::default().with_high(BF::OS); + let config_with_os = Config::default().union(BF::OS); let transactions = [ I2cTrans::write_read( DEV_ADDR, @@ -59,7 +59,7 @@ macro_rules! measure_tests { #[test] fn can_measure_continuous() { - let config = Config::default().with_low(BF::OP_MODE); + let config = Config::default().difference(BF::OP_MODE); let transactions = [ I2cTrans::write(DEV_ADDR, vec![Register::CONFIG, config.msb(), config.lsb()]), I2cTrans::write_read(DEV_ADDR, vec![Register::CONVERSION], vec![0x80, 0x00]), @@ -99,57 +99,57 @@ mod data_rate_12bit { sps128, Sps128, Config::default() - .with_low(BF::DR2) - .with_low(BF::DR1) - .with_low(BF::DR0) + .difference(BF::DR2) + .difference(BF::DR1) + .difference(BF::DR0) ); test!( sps250, Sps250, Config::default() - .with_low(BF::DR2) - .with_low(BF::DR1) - .with_high(BF::DR0) + .difference(BF::DR2) + .difference(BF::DR1) + .union(BF::DR0) ); test!( sps490, Sps490, Config::default() - .with_low(BF::DR2) - .with_high(BF::DR1) - .with_low(BF::DR0) + .difference(BF::DR2) + .union(BF::DR1) + .difference(BF::DR0) ); test!( sps920, Sps920, Config::default() - .with_low(BF::DR2) - .with_high(BF::DR1) - .with_high(BF::DR0) + .difference(BF::DR2) + .union(BF::DR1) + .union(BF::DR0) ); test!( sps1600, Sps1600, Config::default() - .with_high(BF::DR2) - .with_low(BF::DR1) - .with_low(BF::DR0) + .union(BF::DR2) + .difference(BF::DR1) + .difference(BF::DR0) ); test!( sps2400, Sps2400, Config::default() - .with_high(BF::DR2) - .with_low(BF::DR1) - .with_high(BF::DR0) + .union(BF::DR2) + .difference(BF::DR1) + .union(BF::DR0) ); test!( sps3300, Sps3300, Config::default() - .with_high(BF::DR2) - .with_high(BF::DR1) - .with_low(BF::DR0) + .union(BF::DR2) + .union(BF::DR1) + .difference(BF::DR0) ); } @@ -175,71 +175,71 @@ mod data_rate_16bit { sps8, Sps8, Config::default() - .with_low(BF::DR2) - .with_low(BF::DR1) - .with_low(BF::DR0) + .difference(BF::DR2) + .difference(BF::DR1) + .difference(BF::DR0) ); test!( sps16, Sps16, Config::default() - .with_low(BF::DR2) - .with_low(BF::DR1) - .with_high(BF::DR0) + .difference(BF::DR2) + .difference(BF::DR1) + .union(BF::DR0) ); test!( sps32, Sps32, Config::default() - .with_low(BF::DR2) - .with_high(BF::DR1) - .with_low(BF::DR0) + .difference(BF::DR2) + .union(BF::DR1) + .difference(BF::DR0) ); test!( sps64, Sps64, Config::default() - .with_low(BF::DR2) - .with_high(BF::DR1) - .with_high(BF::DR0) + .difference(BF::DR2) + .union(BF::DR1) + .union(BF::DR0) ); test!( sps128, Sps128, Config::default() - .with_high(BF::DR2) - .with_low(BF::DR1) - .with_low(BF::DR0) + .union(BF::DR2) + .difference(BF::DR1) + .difference(BF::DR0) ); test!( sps250, Sps250, Config::default() - .with_high(BF::DR2) - .with_low(BF::DR1) - .with_high(BF::DR0) + .union(BF::DR2) + .difference(BF::DR1) + .union(BF::DR0) ); test!( sps475, Sps475, Config::default() - .with_high(BF::DR2) - .with_high(BF::DR1) - .with_low(BF::DR0) + .union(BF::DR2) + .union(BF::DR1) + .difference(BF::DR0) ); test!( sps860, Sps860, Config::default() - .with_high(BF::DR2) - .with_high(BF::DR1) - .with_high(BF::DR0) + .union(BF::DR2) + .union(BF::DR1) + .union(BF::DR0) ); } #[test] fn can_read_measurement_in_progress() { - let config_os = Config::default().with_low(BF::OS); + let config_os = Config::default().difference(BF::OS); let transactions = [I2cTrans::write_read( DEV_ADDR, vec![Register::CONFIG], @@ -252,7 +252,7 @@ fn can_read_measurement_in_progress() { #[test] fn can_read_measurement_not_in_progress() { - let config_os = Config::default().with_high(BF::OS); + let config_os = Config::default().union(BF::OS); let transactions = [I2cTrans::write_read( DEV_ADDR, vec![Register::CONFIG], @@ -265,7 +265,7 @@ fn can_read_measurement_not_in_progress() { #[test] fn can_convert_to_continuous() { - let config = Config::default().with_low(BF::OP_MODE); + let config = Config::default().difference(BF::OP_MODE); let transactions = [I2cTrans::write( DEV_ADDR, vec![Register::CONFIG, config.msb(), config.lsb()], @@ -277,7 +277,7 @@ fn can_convert_to_continuous() { #[test] fn can_convert_to_one_shot() { - let config_cont = Config::default().with_low(BF::OP_MODE); + let config_cont = Config::default().difference(BF::OP_MODE); let config_os = Config::default(); let transactions = [ I2cTrans::write( diff --git a/tests/tier2.rs b/tests/tier2.rs index d8869f7..d70c296 100644 --- a/tests/tier2.rs +++ b/tests/tier2.rs @@ -38,13 +38,13 @@ mod can_set_comparator_mode { traditional, set_comparator_mode, ComparatorMode::Traditional, - Config::default().with_low(BF::COMP_MODE) + Config::default().difference(BF::COMP_MODE) ); config_test!( window, set_comparator_mode, ComparatorMode::Window, - Config::default().with_high(BF::COMP_MODE) + Config::default().union(BF::COMP_MODE) ); } @@ -54,13 +54,13 @@ mod can_set_comparator_polarity { low, set_comparator_polarity, ComparatorPolarity::ActiveLow, - Config::default().with_low(BF::COMP_POL) + Config::default().difference(BF::COMP_POL) ); config_test!( high, set_comparator_polarity, ComparatorPolarity::ActiveHigh, - Config::default().with_high(BF::COMP_POL) + Config::default().union(BF::COMP_POL) ); } @@ -70,21 +70,19 @@ mod can_set_comparator_latching { non, set_comparator_latching, ComparatorLatching::Nonlatching, - Config::default().with_low(BF::COMP_LAT) + Config::default().difference(BF::COMP_LAT) ); config_test!( lat, set_comparator_latching, ComparatorLatching::Latching, - Config::default().with_high(BF::COMP_LAT) + Config::default().union(BF::COMP_LAT) ); } #[test] fn can_disable_comparator() { - let config = Config::default() - .with_high(BF::COMP_QUE1) - .with_high(BF::COMP_QUE0); + let config = Config::default().union(BF::COMP_QUE1).union(BF::COMP_QUE0); let transactions = [I2cTrans::write( DEV_ADDR, vec![Register::CONFIG, config.msb(), config.lsb()], @@ -101,24 +99,24 @@ mod can_set_comparator_queue { set_comparator_queue, ComparatorQueue::One, Config::default() - .with_low(BF::COMP_QUE1) - .with_low(BF::COMP_QUE0) + .difference(BF::COMP_QUE1) + .difference(BF::COMP_QUE0) ); config_test!( two, set_comparator_queue, ComparatorQueue::Two, Config::default() - .with_low(BF::COMP_QUE1) - .with_high(BF::COMP_QUE0) + .difference(BF::COMP_QUE1) + .union(BF::COMP_QUE0) ); config_test!( four, set_comparator_queue, ComparatorQueue::Four, Config::default() - .with_high(BF::COMP_QUE1) - .with_low(BF::COMP_QUE0) + .union(BF::COMP_QUE1) + .difference(BF::COMP_QUE0) ); } @@ -136,11 +134,9 @@ fn can_use_alert_rdy_pin_as_rdy_does_not_disable_comparator_if_already_disabled( #[test] fn can_use_alert_rdy_pin_as_rdy_disabled_comparator() { let config = Config::default() - .with_low(BF::COMP_QUE1) - .with_low(BF::COMP_QUE0); - let config_disabled_comp = Config::default() - .with_high(BF::COMP_QUE1) - .with_low(BF::COMP_QUE0); + .difference(BF::COMP_QUE1) + .difference(BF::COMP_QUE0); + let config_disabled_comp = Config::default().union(BF::COMP_QUE1).union(BF::COMP_QUE0); let transactions = [ I2cTrans::write(DEV_ADDR, vec![Register::CONFIG, config.msb(), config.lsb()]), I2cTrans::write( @@ -167,53 +163,53 @@ mod can_set_full_scale_range { set_full_scale_range, FullScaleRange::Within6_144V, Config::default() - .with_low(BF::PGA2) - .with_low(BF::PGA1) - .with_low(BF::PGA0) + .difference(BF::PGA2) + .difference(BF::PGA1) + .difference(BF::PGA0) ); config_test!( fsr4, set_full_scale_range, FullScaleRange::Within4_096V, Config::default() - .with_low(BF::PGA2) - .with_low(BF::PGA1) - .with_high(BF::PGA0) + .difference(BF::PGA2) + .difference(BF::PGA1) + .union(BF::PGA0) ); config_test!( fsr2, set_full_scale_range, FullScaleRange::Within2_048V, Config::default() - .with_low(BF::PGA2) - .with_high(BF::PGA1) - .with_low(BF::PGA0) + .difference(BF::PGA2) + .union(BF::PGA1) + .difference(BF::PGA0) ); config_test!( fsr1, set_full_scale_range, FullScaleRange::Within1_024V, Config::default() - .with_low(BF::PGA2) - .with_high(BF::PGA1) - .with_high(BF::PGA0) + .difference(BF::PGA2) + .union(BF::PGA1) + .union(BF::PGA0) ); config_test!( fsr0_5, set_full_scale_range, FullScaleRange::Within0_512V, Config::default() - .with_high(BF::PGA2) - .with_low(BF::PGA1) - .with_low(BF::PGA0) + .union(BF::PGA2) + .difference(BF::PGA1) + .difference(BF::PGA0) ); config_test!( fsr0_2, set_full_scale_range, FullScaleRange::Within0_256V, Config::default() - .with_high(BF::PGA2) - .with_low(BF::PGA1) - .with_high(BF::PGA0) + .union(BF::PGA2) + .difference(BF::PGA1) + .union(BF::PGA0) ); } From d193af4e5d8938772ff7dadabc1b20607b52a454 Mon Sep 17 00:00:00 2001 From: Markus Reiter Date: Sun, 14 Jan 2024 06:13:36 +0100 Subject: [PATCH 12/14] Remove `OperatingMode`. --- src/devices/common.rs | 17 +---------------- src/devices/features/tier2.rs | 4 ++-- src/devices/mod.rs | 6 ------ src/devices/mode/continuous.rs | 8 ++++---- src/devices/mode/oneshot.rs | 10 +++++----- src/lib.rs | 9 +++------ src/register.rs | 25 ++++++++----------------- 7 files changed, 23 insertions(+), 56 deletions(-) diff --git a/src/devices/common.rs b/src/devices/common.rs index f5c69cf..0538e7a 100644 --- a/src/devices/common.rs +++ b/src/devices/common.rs @@ -1,8 +1,6 @@ //! Common functions. -use crate::{ - devices::OperatingMode, Ads1013, Ads1014, Ads1015, Ads1113, Ads1114, Ads1115, Config, Error, -}; +use crate::{register::Config, Ads1013, Ads1014, Ads1015, Ads1113, Ads1114, Ads1115, Error}; macro_rules! impl_common_features { ($Ads:ident) => { @@ -10,19 +8,6 @@ macro_rules! impl_common_features { 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.union(Config::MODE), - OperatingMode::Continuous => self.config.difference(Config::MODE), - }; - self.write_reg_u16(config)?; - self.config = config; - Ok(()) - } - /// Checks whether a measurement is currently in progress. pub fn is_measurement_in_progress(&mut self) -> Result> { let config = self.read_reg_u16::()?; diff --git a/src/devices/features/tier2.rs b/src/devices/features/tier2.rs index 8ec3443..ca43734 100644 --- a/src/devices/features/tier2.rs +++ b/src/devices/features/tier2.rs @@ -1,9 +1,9 @@ //! Features only supported by ADS1x14 and ADS1x15 devices. use crate::{ - register::{Conversion12, Conversion16, HiThresh, LoThresh}, + register::{Config, Conversion12, Conversion16, HiThresh, LoThresh}, Ads1014, Ads1015, Ads1114, Ads1115, ComparatorLatching, ComparatorMode, ComparatorPolarity, - ComparatorQueue, Config, Error, FullScaleRange, + ComparatorQueue, Error, FullScaleRange, }; macro_rules! doc_threshold { diff --git a/src/devices/mod.rs b/src/devices/mod.rs index 01efeba..104862f 100644 --- a/src/devices/mod.rs +++ b/src/devices/mod.rs @@ -1,9 +1,3 @@ -#[derive(Debug, Clone, Copy)] -enum OperatingMode { - OneShot, - Continuous, -} - mod common; mod features; mod mode; diff --git a/src/devices/mode/continuous.rs b/src/devices/mode/continuous.rs index 2a62a82..ef11308 100644 --- a/src/devices/mode/continuous.rs +++ b/src/devices/mode/continuous.rs @@ -1,9 +1,8 @@ //! Continuous measurement mode. use crate::{ - devices::OperatingMode, mode, - register::{Conversion12, Conversion16}, + register::{Config, Conversion12, Conversion16}, Ads1013, Ads1014, Ads1015, Ads1113, Ads1114, Ads1115, ChannelId, Error, }; use core::marker::PhantomData; @@ -18,13 +17,14 @@ macro_rules! impl_continuous { /// /// On error, returns a pair of the error and the current instance. pub fn into_one_shot(mut self) -> Result<$Ads, (Error, Self)> { - if let Err(e) = self.set_operating_mode(OperatingMode::OneShot) { + let config = self.config.union(Config::MODE); + if let Err(e) = self.write_reg_u16(config) { return Err((e, self)); } Ok($Ads { i2c: self.i2c, address: self.address, - config: self.config, + config, a_conversion_was_started: false, mode: PhantomData, }) diff --git a/src/devices/mode/oneshot.rs b/src/devices/mode/oneshot.rs index 155e227..5228261 100644 --- a/src/devices/mode/oneshot.rs +++ b/src/devices/mode/oneshot.rs @@ -3,10 +3,9 @@ use core::marker::PhantomData; use crate::{ - devices::OperatingMode, mode, - register::{Conversion12, Conversion16}, - Ads1013, Ads1014, Ads1015, Ads1113, Ads1114, Ads1115, ChannelId, Config, Error, + register::{Config, Conversion12, Conversion16}, + Ads1013, Ads1014, Ads1015, Ads1113, Ads1114, Ads1115, ChannelId, Error, }; macro_rules! impl_one_shot { @@ -21,13 +20,14 @@ macro_rules! impl_one_shot { pub fn into_continuous( mut self, ) -> Result<$Ads, (Error, Self)> { - if let Err(e) = self.set_operating_mode(OperatingMode::Continuous) { + let config = self.config.difference(Config::MODE); + if let Err(e) = self.write_reg_u16(config) { return Err((e, self)); } Ok($Ads { i2c: self.i2c, address: self.address, - config: self.config, + config, a_conversion_was_started: true, mode: PhantomData, }) diff --git a/src/lib.rs b/src/lib.rs index 4c332de..97a2085 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -199,7 +199,7 @@ pub use types::{ pub mod mode; pub use mode::*; pub(crate) mod register; -use register::{Config, ReadReg, WriteReg}; +use register::{Config, Reg}; macro_rules! impl_ads1x1x { ($name:expr, $Ads:ident) => { @@ -230,7 +230,7 @@ macro_rules! impl_ads1x1x { where I2C: embedded_hal::i2c::I2c, { - pub(crate) fn read_reg_u16>(&mut self) -> Result> { + pub(crate) fn read_reg_u16>(&mut self) -> Result> { let mut buf = [0, 0]; self.i2c .write_read(self.address.bits(), &[R::ADDR], &mut buf) @@ -238,10 +238,7 @@ macro_rules! impl_ads1x1x { Ok(R::from_reg(u16::from_be_bytes(buf))) } - pub(crate) fn write_reg_u16>( - &mut self, - reg: R, - ) -> Result<(), Error> { + pub(crate) fn write_reg_u16>(&mut self, reg: R) -> Result<(), Error> { let buf = reg.to_reg().to_be_bytes(); let payload: [u8; 3] = [R::ADDR, buf[0], buf[1]]; self.i2c diff --git a/src/register.rs b/src/register.rs index 76d12e5..5778383 100644 --- a/src/register.rs +++ b/src/register.rs @@ -1,34 +1,27 @@ -/// Read a register. -pub trait ReadReg +pub trait Reg where Self: Sized, { /// Register address. const ADDR: u8; - /// Read a register. + /// Converts from a register value. fn from_reg(reg: R) -> Self; -} -/// Write a register. -pub trait WriteReg: ReadReg { - /// Write a register. + /// Converts to a register value. fn to_reg(self) -> R; } macro_rules! register { - (@impl_read_reg $Reg:ident : $addr:literal : $RegTy:ty) => { - impl ReadReg<$RegTy> for $Reg { + (@impl_reg $Reg:ident : $addr:literal : $RegTy:ty) => { + impl Reg<$RegTy> for $Reg { const ADDR: u8 = $addr; #[inline] fn from_reg(reg: $RegTy) -> Self { $Reg::from_bits_truncate(reg) } - } - }; - (@impl_write_reg $Reg:ident : $addr:literal : $RegTy:ty) => { - impl WriteReg<$RegTy> for $Reg { + fn to_reg(self) -> $RegTy { self.bits() } @@ -51,8 +44,7 @@ macro_rules! register { } } - register!(@impl_read_reg $Reg: $addr: $RegTy); - register!(@impl_write_reg $Reg: $addr: $RegTy); + register!(@impl_reg $Reg: $addr: $RegTy); }; ( #[doc = $name:expr] @@ -74,8 +66,7 @@ macro_rules! register { } } - register!(@impl_read_reg $Reg: $addr: $RegTy); - register!(@impl_write_reg $Reg: $addr: $RegTy); + register!(@impl_reg $Reg: $addr: $RegTy); }; } From dca7dd9a571949db2f4820ed0a050c9b474faedb Mon Sep 17 00:00:00 2001 From: Markus Reiter Date: Sun, 14 Jan 2024 07:38:03 +0100 Subject: [PATCH 13/14] Simplify `use_alert_rdy_pin_as_ready`. --- src/devices/features/tier2.rs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/devices/features/tier2.rs b/src/devices/features/tier2.rs index ca43734..916b316 100644 --- a/src/devices/features/tier2.rs +++ b/src/devices/features/tier2.rs @@ -145,15 +145,11 @@ macro_rules! impl_tier2_features { /// /// When calling this the comparator will be reset to default and any thresholds will be cleared. pub fn use_alert_rdy_pin_as_ready(&mut self) -> Result<(), Error> { - if self.config - != self - .config - .union(Config::COMP_QUE1) - .union(Config::COMP_QUE0) + if !self.config.contains(Config::COMP_QUE) { self.set_comparator_queue(ComparatorQueue::default())?; } - self.write_reg_u16(HiThresh(0x8000))?; + self.write_reg_u16(HiThresh(0b1000000000000000))?; self.write_reg_u16(LoThresh(0)) } } From 1d5c6b5a07bf63308af02cf8f0aa84a04fe6818b Mon Sep 17 00:00:00 2001 From: Markus Reiter Date: Mon, 24 Jun 2024 23:46:56 +0200 Subject: [PATCH 14/14] Remove unused `InvalidInputData` error. --- src/devices/common.rs | 4 ++-- src/devices/features/tier1.rs | 8 ++------ src/devices/features/tier2.rs | 20 ++++++++++---------- src/devices/mode/continuous.rs | 11 ++++------- src/devices/mode/oneshot.rs | 10 ++++------ src/lib.rs | 13 +++++-------- src/types.rs | 9 --------- 7 files changed, 27 insertions(+), 48 deletions(-) diff --git a/src/devices/common.rs b/src/devices/common.rs index 0538e7a..ab1134a 100644 --- a/src/devices/common.rs +++ b/src/devices/common.rs @@ -1,6 +1,6 @@ //! Common functions. -use crate::{register::Config, Ads1013, Ads1014, Ads1015, Ads1113, Ads1114, Ads1115, Error}; +use crate::{register::Config, Ads1013, Ads1014, Ads1015, Ads1113, Ads1114, Ads1115}; macro_rules! impl_common_features { ($Ads:ident) => { @@ -9,7 +9,7 @@ macro_rules! impl_common_features { I2C: embedded_hal::i2c::I2c, { /// Checks whether a measurement is currently in progress. - pub fn is_measurement_in_progress(&mut self) -> Result> { + pub fn is_measurement_in_progress(&mut self) -> Result { let config = self.read_reg_u16::()?; Ok(!config.contains(Config::OS)) } diff --git a/src/devices/features/tier1.rs b/src/devices/features/tier1.rs index 6a1f34a..5a90661 100644 --- a/src/devices/features/tier1.rs +++ b/src/devices/features/tier1.rs @@ -1,8 +1,4 @@ -//! Features supported on all ADS1x1x devices. - -use crate::{ - Ads1013, Ads1014, Ads1015, Ads1113, Ads1114, Ads1115, DataRate12Bit, DataRate16Bit, Error, -}; +use crate::{Ads1013, Ads1014, Ads1015, Ads1113, Ads1114, Ads1115, DataRate12Bit, DataRate16Bit}; macro_rules! impl_tier1_features { ($Ads:ident, $DataRate:ty) => { @@ -11,7 +7,7 @@ macro_rules! impl_tier1_features { I2C: embedded_hal::i2c::I2c, { /// Sets the data rate. - pub fn set_data_rate(&mut self, rate: $DataRate) -> Result<(), Error> { + pub fn set_data_rate(&mut self, rate: $DataRate) -> Result<(), E> { let config = rate.configure(self.config); self.write_reg_u16(config)?; self.config = config; diff --git a/src/devices/features/tier2.rs b/src/devices/features/tier2.rs index 916b316..3e99aa8 100644 --- a/src/devices/features/tier2.rs +++ b/src/devices/features/tier2.rs @@ -3,7 +3,7 @@ use crate::{ register::{Config, Conversion12, Conversion16, HiThresh, LoThresh}, Ads1014, Ads1015, Ads1114, Ads1115, ComparatorLatching, ComparatorMode, ComparatorPolarity, - ComparatorQueue, Error, FullScaleRange, + ComparatorQueue, FullScaleRange, }; macro_rules! doc_threshold { @@ -34,7 +34,7 @@ macro_rules! impl_tier2_features { /// 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> { + pub fn set_full_scale_range(&mut self, range: FullScaleRange) -> Result<(), E> { let config = range.configure(self.config); self.write_reg_u16(config)?; self.config = config; @@ -47,7 +47,7 @@ macro_rules! impl_tier2_features { /// full-scale range ([`FullScaleRange`]) selected. /// #[doc = doc_threshold!($($th_range)+)] - pub fn set_low_threshold_raw(&mut self, value: i16) -> Result<(), Error> { + pub fn set_low_threshold_raw(&mut self, value: i16) -> Result<(), E> { let register_value = <$conv>::convert_threshold(value); self.write_reg_u16(LoThresh(register_value)) } @@ -58,13 +58,13 @@ macro_rules! impl_tier2_features { /// full-scale range ([`FullScaleRange`]) selected. /// #[doc = doc_threshold!($($th_range)+)] - pub fn set_high_threshold_raw(&mut self, value: i16) -> Result<(), Error> { + pub fn set_high_threshold_raw(&mut self, value: i16) -> Result<(), E> { let register_value = <$conv>::convert_threshold(value); self.write_reg_u16(HiThresh(register_value)) } /// Sets the comparator mode. - pub fn set_comparator_mode(&mut self, mode: ComparatorMode) -> Result<(), Error> { + pub fn set_comparator_mode(&mut self, mode: ComparatorMode) -> Result<(), E> { let config = match mode { ComparatorMode::Traditional => self.config.difference(Config::COMP_MODE), ComparatorMode::Window => self.config.union(Config::COMP_MODE), @@ -78,7 +78,7 @@ macro_rules! impl_tier2_features { pub fn set_comparator_polarity( &mut self, polarity: ComparatorPolarity, - ) -> Result<(), Error> { + ) -> Result<(), E> { let config = match polarity { ComparatorPolarity::ActiveLow => self.config.difference(Config::COMP_POL), ComparatorPolarity::ActiveHigh => self.config.union(Config::COMP_POL), @@ -92,7 +92,7 @@ macro_rules! impl_tier2_features { pub fn set_comparator_latching( &mut self, latching: ComparatorLatching, - ) -> Result<(), Error> { + ) -> Result<(), E> { let config = match latching { ComparatorLatching::Nonlatching => self.config.difference(Config::COMP_LAT), ComparatorLatching::Latching => self.config.union(Config::COMP_LAT), @@ -105,7 +105,7 @@ macro_rules! impl_tier2_features { /// 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> { + pub fn set_comparator_queue(&mut self, queue: ComparatorQueue) -> Result<(), E> { let config = match queue { ComparatorQueue::One => { self.config.difference(Config::COMP_QUE1).difference(Config::COMP_QUE0) @@ -128,7 +128,7 @@ macro_rules! impl_tier2_features { /// /// The comparator can be enabled by setting the comparator queue using /// the [`set_comparator_queue`](Self::set_comparator_queue) method. - pub fn disable_comparator(&mut self) -> Result<(), Error> { + pub fn disable_comparator(&mut self) -> Result<(), E> { let config = self .config .union(Config::COMP_QUE1) @@ -144,7 +144,7 @@ macro_rules! impl_tier2_features { /// in continuous-conversion mode, provides a continuous-conversion ready pulse. /// /// When calling this the comparator will be reset to default and any thresholds will be cleared. - pub fn use_alert_rdy_pin_as_ready(&mut self) -> Result<(), Error> { + pub fn use_alert_rdy_pin_as_ready(&mut self) -> Result<(), E> { if !self.config.contains(Config::COMP_QUE) { self.set_comparator_queue(ComparatorQueue::default())?; diff --git a/src/devices/mode/continuous.rs b/src/devices/mode/continuous.rs index ef11308..3d0865d 100644 --- a/src/devices/mode/continuous.rs +++ b/src/devices/mode/continuous.rs @@ -3,7 +3,7 @@ use crate::{ mode, register::{Config, Conversion12, Conversion16}, - Ads1013, Ads1014, Ads1015, Ads1113, Ads1114, Ads1115, ChannelId, Error, + Ads1013, Ads1014, Ads1015, Ads1113, Ads1114, Ads1115, ChannelId, }; use core::marker::PhantomData; @@ -16,7 +16,7 @@ macro_rules! impl_continuous { /// Changes to one-shot operating mode. /// /// On error, returns a pair of the error and the current instance. - pub fn into_one_shot(mut self) -> Result<$Ads, (Error, Self)> { + pub fn into_one_shot(mut self) -> Result<$Ads, (E, Self)> { let config = self.config.union(Config::MODE); if let Err(e) = self.write_reg_u16(config) { return Err((e, self)); @@ -31,7 +31,7 @@ macro_rules! impl_continuous { } /// Reads the most recent measurement. - pub fn read(&mut self) -> Result> { + pub fn read(&mut self) -> Result { let value = self.read_reg_u16::<$conv>()?; Ok(<$conv>::convert_measurement(value.0)) } @@ -42,10 +42,7 @@ macro_rules! impl_continuous { /// ongoing conversion will be completed. /// The following conversions will use the new channel configuration. #[allow(unused_variables)] - pub fn select_channel>( - &mut self, - channel: CH, - ) -> Result<(), Error> { + pub fn select_channel>(&mut self, channel: CH) -> Result<(), E> { let config = self.config.with_mux_bits(CH::channel_id()); self.write_reg_u16(config)?; self.config = config; diff --git a/src/devices/mode/oneshot.rs b/src/devices/mode/oneshot.rs index 5228261..0ef89c1 100644 --- a/src/devices/mode/oneshot.rs +++ b/src/devices/mode/oneshot.rs @@ -5,7 +5,7 @@ use core::marker::PhantomData; use crate::{ mode, register::{Config, Conversion12, Conversion16}, - Ads1013, Ads1014, Ads1015, Ads1113, Ads1114, Ads1115, ChannelId, Error, + Ads1013, Ads1014, Ads1015, Ads1113, Ads1114, Ads1115, ChannelId, }; macro_rules! impl_one_shot { @@ -17,9 +17,7 @@ macro_rules! impl_one_shot { /// Changes to continuous operating mode. /// /// On error, returns a pair of the error and the current instance. - pub fn into_continuous( - mut self, - ) -> Result<$Ads, (Error, Self)> { + pub fn into_continuous(mut self) -> Result<$Ads, (E, Self)> { let config = self.config.difference(Config::MODE); if let Err(e) = self.write_reg_u16(config) { return Err((e, self)); @@ -33,7 +31,7 @@ macro_rules! impl_one_shot { }) } - fn trigger_measurement(&mut self, config: &Config) -> Result<(), Error> { + fn trigger_measurement(&mut self, config: &Config) -> Result<(), E> { let config = config.union(Config::OS); self.write_reg_u16(config) } @@ -51,7 +49,7 @@ macro_rules! impl_one_shot { /// measurement on a different channel is requested, a new measurement on /// using the new channel selection is triggered. #[allow(unused_variables)] - pub fn read>(&mut self, channel: CH) -> nb::Result> { + pub fn read>(&mut self, channel: CH) -> nb::Result { if self .is_measurement_in_progress() .map_err(nb::Error::Other)? diff --git a/src/lib.rs b/src/lib.rs index 97a2085..c4c38ed 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -194,7 +194,7 @@ mod devices; mod types; pub use types::{ ComparatorLatching, ComparatorMode, ComparatorPolarity, ComparatorQueue, DataRate12Bit, - DataRate16Bit, Error, FullScaleRange, TargetAddr, + DataRate16Bit, FullScaleRange, TargetAddr, }; pub mod mode; pub use mode::*; @@ -230,20 +230,17 @@ macro_rules! impl_ads1x1x { where I2C: embedded_hal::i2c::I2c, { - pub(crate) fn read_reg_u16>(&mut self) -> Result> { + pub(crate) fn read_reg_u16>(&mut self) -> Result { let mut buf = [0, 0]; self.i2c - .write_read(self.address.bits(), &[R::ADDR], &mut buf) - .map_err(Error::I2C)?; + .write_read(self.address.bits(), &[R::ADDR], &mut buf)?; Ok(R::from_reg(u16::from_be_bytes(buf))) } - pub(crate) fn write_reg_u16>(&mut self, reg: R) -> Result<(), Error> { + pub(crate) fn write_reg_u16>(&mut self, reg: R) -> Result<(), E> { let buf = reg.to_reg().to_be_bytes(); let payload: [u8; 3] = [R::ADDR, buf[0], buf[1]]; - self.i2c - .write(self.address.bits(), &payload) - .map_err(Error::I2C) + self.i2c.write(self.address.bits(), &payload) } } diff --git a/src/types.rs b/src/types.rs index 514937d..65739dc 100644 --- a/src/types.rs +++ b/src/types.rs @@ -2,15 +2,6 @@ use crate::Config; -/// Errors in this crate -#[derive(Debug, PartialEq)] -pub enum Error { - /// I²C bus error - I2C(E), - /// Invalid input data provided - InvalidInputData, -} - /// Data rate for ADS101x. #[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Ord, PartialOrd, Hash)] pub enum DataRate12Bit {