Skip to content

Commit

Permalink
Rename AdcChannel to Voltmeter and add Ammeter.
Browse files Browse the repository at this point in the history
  • Loading branch information
reitermarkus committed Jan 19, 2024
1 parent 9ed5035 commit c3b96f0
Show file tree
Hide file tree
Showing 2 changed files with 182 additions and 51 deletions.
129 changes: 97 additions & 32 deletions embedded-hal-async/src/adc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,19 @@

pub use embedded_hal::adc::{Error, ErrorKind, ErrorType};

/// Read data from an ADC.
///
/// # Note for Implementers
///
/// This should wait until data is ready and then read it.
/// Asynchronous voltmeter for measuring voltage.
///
/// # Examples
///
/// In the first naive example, [`AdcChannel`] is implemented
/// In the first naive example, [`Voltmeter`] is implemented
/// using a spin loop and only returns once data is ready.
///
/// ```
/// # use embedded_hal_async::adc::{AdcChannel, ErrorKind, ErrorType, Error};
/// #
/// struct MySpinningAdc;
/// use embedded_hal_async::adc::{ErrorKind, ErrorType, Error, Voltmeter};
///
/// struct MySpinningVoltmeter;
///
/// impl MySpinningAdc {
/// impl MySpinningVoltmeter {
/// pub fn is_ready(&mut self) -> bool {
/// // Just pretend this returns `false` the first few times.
/// true
Expand All @@ -29,21 +25,21 @@ pub use embedded_hal::adc::{Error, ErrorKind, ErrorType};
/// }
/// }
///
/// impl ErrorType for MySpinningAdc {
/// impl ErrorType for MySpinningVoltmeter {
/// type Error = ErrorKind;
/// }
///
/// impl AdcChannel for MySpinningAdc {
/// impl Voltmeter for MySpinningVoltmeter {
/// async fn measure_nv(&mut self) -> Result<i64, Self::Error> {
/// Ok(self.measure_mv().await? as i64 * 1_000_000)
/// }
///
/// async fn measure_mv(&mut self) -> Result<i32, Self::Error> {
/// async fn measure_mv(&mut self) -> Result<i16, Self::Error> {
/// while !self.is_ready() {
/// core::hint::spin_loop();
/// }
///
/// Ok(self.data() as i32)
/// Ok(self.data() as i16)
/// }
/// }
/// ```
Expand All @@ -52,28 +48,31 @@ pub use embedded_hal::adc::{Error, ErrorKind, ErrorType};
/// When the “ready pin” goes high, data is ready.
///
/// ```
/// # use embedded_hal_async::{adc::{self, ErrorKind, ErrorType, Error, AdcChannel}, digital::{self, Wait, Error as _, ErrorType as _}};
/// #
/// struct MyWaitingAdc<T> {
/// use embedded_hal_async::{
/// adc::{self, ErrorKind, ErrorType, Error, Voltmeter},
/// digital::{self, Wait, Error as _, ErrorType as _},
/// };
///
/// struct MyWaitingVoltmeter<T> {
/// ready_pin: T,
/// };
///
/// impl<T> MyWaitingAdc<T> {
/// impl<T> MyWaitingVoltmeter<T> {
/// pub fn data(&mut self) -> u16 {
/// 3300
/// }
/// }
///
/// impl<T> adc::ErrorType for MyWaitingAdc<T> {
/// impl<T> adc::ErrorType for MyWaitingVoltmeter<T> {
/// type Error = adc::ErrorKind;
/// }
///
/// impl<T: Wait> AdcChannel for MyWaitingAdc<T> {
/// impl<T: Wait> Voltmeter for MyWaitingVoltmeter<T> {
/// async fn measure_nv(&mut self) -> Result<i64, Self::Error> {
/// Ok(self.measure_mv().await? as i64 * 1_000_000)
/// }
///
/// async fn measure_mv(&mut self) -> Result<i32, Self::Error> {
/// async fn measure_mv(&mut self) -> Result<i16, Self::Error> {
/// match self.ready_pin.wait_for_high().await {
/// Ok(()) => (),
/// Err(err) => return Err(match err.kind() {
Expand All @@ -82,28 +81,43 @@ pub use embedded_hal::adc::{Error, ErrorKind, ErrorType};
/// })
/// }
///
/// Ok(self.data() as i32)
/// Ok(self.data() as i16)
/// }
/// }
/// ```
pub trait AdcChannel: ErrorType {
/// Take a measurement in nV (nanovolts).
pub trait Voltmeter: ErrorType {
/// Measures voltage in nV (nanovolts).
///
/// This can measure between -9223372036.854775808V and 9223372036.854775807V.
async fn measure_nv(&mut self) -> Result<i64, Self::Error>;

/// Take a measurement in mV (microvolts).
/// Measures voltage in mV (microvolts).
///
/// This can measure between -2147.483648V and 2147.483647V.
/// If you need to measure a larger range, use [`measure_nv`](Voltmeter::measure_nv) instead.
///
/// When overriding the default implementation, ensure that the measured voltage is clamped
/// between [`i32::MIN`] and [`i32::MAX`].
async fn measure_uv(&mut self) -> Result<i32, Self::Error> {
Ok((self.measure_nv().await? / 1_000) as i32)
Ok((self.measure_nv().await? / 1_000).clamp(i32::MIN.into(), i32::MAX.into()) as i32)
}

/// Take a measurement in mV (millivolts).
async fn measure_mv(&mut self) -> Result<i32, Self::Error> {
Ok(self.measure_uv().await? / 1_000)
/// Measures voltage in mV (millivolts).
///
/// This can measure between between -32.768V and 32.767V.
/// If you need to measure a larger range,
/// use [`measure_uv`](Voltmeter::measure_uv) or [`measure_nv`](Voltmeter::measure_nv) instead.
///
/// When overriding the default implementation, ensure that the measured voltage is clamped
/// between [`i16::MIN`] and [`i16::MAX`].
async fn measure_mv(&mut self) -> Result<i16, Self::Error> {
Ok((self.measure_uv().await? / 1_000).clamp(i16::MIN.into(), i16::MAX.into()) as i16)
}
}

impl<T> AdcChannel for &mut T
impl<T> Voltmeter for &mut T
where
T: AdcChannel + ?Sized,
T: Voltmeter + ?Sized,
{
#[inline]
async fn measure_nv(&mut self) -> Result<i64, Self::Error> {
Expand All @@ -116,7 +130,58 @@ where
}

#[inline]
async fn measure_mv(&mut self) -> Result<i32, Self::Error> {
async fn measure_mv(&mut self) -> Result<i16, Self::Error> {
(*self).measure_mv().await
}
}

/// Asynchronous ammeter (ampere meter) for measuring current.
pub trait Ammeter: ErrorType {
/// Measures current in nA (nanoampere).
///
/// This can measure between -9223372036.854775808A and 9223372036.854775807A.
async fn measure_na(&mut self) -> Result<i64, Self::Error>;

/// Measures current in uA (microampere).
///
/// This can measure between -2147.483648A and 2147.483647A.
/// If you need to measure a larger range, use [`measure_na`](Ammeter::measure_na) instead.
///
/// When overriding the default implementation, ensure that the measured current is clamped
/// between [`i32::MIN`] and [`i32::MAX`].
async fn measure_ua(&mut self) -> Result<i32, Self::Error> {
Ok((self.measure_na().await? / 1_000).clamp(i32::MIN.into(), i32::MAX.into()) as i32)
}

/// Measures current in mA (milliampere).
///
/// This can measure between between -32.768A and 32.767A.
/// If you need to measure a larger range,
/// use [`measure_ua`](Ammeter::measure_ua) or [`measure_na`](Ammeter::measure_na) instead.
///
/// When overriding the default implementation, ensure that the measured voltage is clamped
/// between [`i16::MIN`] and [`i16::MAX`].
async fn measure_ma(&mut self) -> Result<i16, Self::Error> {
Ok((self.measure_ua().await? / 1_000).clamp(i16::MIN.into(), i16::MAX.into()) as i16)
}
}

impl<T> Ammeter for &mut T
where
T: Ammeter + ?Sized,
{
#[inline]
async fn measure_na(&mut self) -> Result<i64, Self::Error> {
(*self).measure_na().await
}

#[inline]
async fn measure_ua(&mut self) -> Result<i32, Self::Error> {
(*self).measure_ua().await
}

#[inline]
async fn measure_ma(&mut self) -> Result<i16, Self::Error> {
(*self).measure_ma().await
}
}
104 changes: 85 additions & 19 deletions embedded-hal/src/adc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,23 @@ use core::fmt::{Debug, Display};
#[cfg(feature = "defmt-03")]
use crate::defmt;

/// Read data from an ADC.
/// Blocking voltmeter for measuring voltage.
///
/// # Note for Implementers
///
/// This should wait until data is ready and then read it.
///
/// # Examples
///
/// In the first naive example, [`AdcChannel`] is implemented
/// In the first naive example, [`Voltmeter`] is implemented
/// using a spin loop and only returns once data is ready.
///
/// ```
/// use embedded_hal::adc::{AdcChannel, ErrorKind, ErrorType, Error};
/// use embedded_hal::adc::{ErrorKind, ErrorType, Error, Voltmeter};
///
/// struct MySpinningAdc;
/// struct MySpinningVoltmeter;
///
/// impl MySpinningAdc {
/// impl MySpinningVoltmeter {
/// pub fn is_ready(&mut self) -> bool {
/// // Just pretend this returns `false` the first few times.
/// true
Expand All @@ -32,42 +32,57 @@ use crate::defmt;
/// }
/// }
///
/// impl ErrorType for MySpinningAdc {
/// impl ErrorType for MySpinningVoltmeter {
/// type Error = ErrorKind;
/// }
///
/// impl AdcChannel for MySpinningAdc {
/// impl Voltmeter for MySpinningVoltmeter {
/// fn measure_nv(&mut self) -> Result<i64, Self::Error> {
/// Ok(self.measure_mv()? as i64 * 1_000_000)
/// }
///
/// fn measure_mv(&mut self) -> Result<i32, Self::Error> {
/// fn measure_mv(&mut self) -> Result<i16, Self::Error> {
/// while !self.is_ready() {
/// core::hint::spin_loop();
/// }
///
/// Ok(self.data() as i32)
/// Ok(self.data() as i16)
/// }
/// }
/// ```
pub trait AdcChannel: ErrorType {
/// Take a measurement in nV (nanovolts).
pub trait Voltmeter: ErrorType {
/// Measures voltage in nV (nanovolts).
///
/// This can measure between -9223372036.854775808V and 9223372036.854775807V.
fn measure_nv(&mut self) -> Result<i64, Self::Error>;

/// Take a measurement in mV (microvolts).
/// Measures voltage in mV (microvolts).
///
/// This can measure between -2147.483648V and 2147.483647V.
/// If you need to measure a larger range, use [`measure_nv`](Voltmeter::measure_nv) instead.
///
/// When overriding the default implementation, ensure that the measured voltage is clamped
/// between [`i32::MIN`] and [`i32::MAX`].
fn measure_uv(&mut self) -> Result<i32, Self::Error> {
Ok((self.measure_nv()? / 1_000) as i32)
Ok((self.measure_nv()? / 1_000).clamp(i32::MIN.into(), i32::MAX.into()) as i32)
}

/// Take a measurement in mV (millivolts).
fn measure_mv(&mut self) -> Result<i32, Self::Error> {
Ok(self.measure_uv()? / 1_000)
/// Measures voltage in mV (millivolts).
///
/// This can measure between between -32.768V and 32.767V.
/// If you need to measure a larger range,
/// use [`measure_uv`](Voltmeter::measure_uv) or [`measure_mv`](Voltmeter::measure_mv) instead.
///
/// When overriding the default implementation, ensure that the measured voltage is clamped
/// between [`i16::MIN`] and [`i16::MAX`].
fn measure_mv(&mut self) -> Result<i16, Self::Error> {
Ok((self.measure_uv()? / 1_000).clamp(i16::MIN.into(), i16::MAX.into()) as i16)
}
}

impl<T> AdcChannel for &mut T
impl<T> Voltmeter for &mut T
where
T: AdcChannel + ?Sized,
T: Voltmeter + ?Sized,
{
#[inline]
fn measure_nv(&mut self) -> Result<i64, Self::Error> {
Expand All @@ -80,11 +95,62 @@ where
}

#[inline]
fn measure_mv(&mut self) -> Result<i32, Self::Error> {
fn measure_mv(&mut self) -> Result<i16, Self::Error> {
(*self).measure_mv()
}
}

/// Blocking ammeter (ampere meter) for measuring current.
pub trait Ammeter: ErrorType {
/// Measures current in nA (nanoampere).
///
/// This can measure between -9223372036.854775808A and 9223372036.854775807A.
fn measure_na(&mut self) -> Result<i64, Self::Error>;

/// Measures current in uA (microampere).
///
/// This can measure between -2147.483648A and 2147.483647A.
/// If you need to measure a larger range, use [`measure_na`](Ammeter::measure_na) instead.
///
/// When overriding the default implementation, ensure that the measured current is clamped
/// between [`i32::MIN`] and [`i32::MAX`].
fn measure_ua(&mut self) -> Result<i32, Self::Error> {
Ok((self.measure_na()? / 1_000).clamp(i32::MIN.into(), i32::MAX.into()) as i32)
}

/// Measures current in mA (milliampere).
///
/// This can measure between between -32.768A and 32.767A.
/// If you need to measure a larger range,
/// use [`measure_ua`](Ammeter::measure_ua) or [`measure_na`](Ammeter::measure_na) instead.
///
/// When overriding the default implementation, ensure that the measured voltage is clamped
/// between [`i16::MIN`] and [`i16::MAX`].
fn measure_ma(&mut self) -> Result<i16, Self::Error> {
Ok((self.measure_ua()? / 1_000).clamp(i16::MIN.into(), i16::MAX.into()) as i16)
}
}

impl<T> Ammeter for &mut T
where
T: Ammeter + ?Sized,
{
#[inline]
fn measure_na(&mut self) -> Result<i64, Self::Error> {
(*self).measure_na()
}

#[inline]
fn measure_ua(&mut self) -> Result<i32, Self::Error> {
(*self).measure_ua()
}

#[inline]
fn measure_ma(&mut self) -> Result<i16, Self::Error> {
(*self).measure_ma()
}
}

/// ADC error.
pub trait Error: Debug {
/// Convert error to a generic ADC error kind.
Expand Down

0 comments on commit c3b96f0

Please sign in to comment.