diff --git a/embedded-hal-async/Cargo.toml b/embedded-hal-async/Cargo.toml index 93e322c4..4d267933 100644 --- a/embedded-hal-async/Cargo.toml +++ b/embedded-hal-async/Cargo.toml @@ -20,4 +20,3 @@ defmt-03 = ["dep:defmt-03", "embedded-hal/defmt-03"] [dependencies] embedded-hal = { version = "1.0.0", path = "../embedded-hal" } defmt-03 = { package = "defmt", version = "0.3", optional = true } -tokio = { version = "1", features = ["rt", "macros"] } diff --git a/embedded-hal-async/src/adc.rs b/embedded-hal-async/src/adc.rs index 81165923..1863fdfe 100644 --- a/embedded-hal-async/src/adc.rs +++ b/embedded-hal-async/src/adc.rs @@ -4,9 +4,13 @@ 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. +/// /// # Examples /// -/// In the first naive example, [`read`](crate::adc::AdcChannel::read) is implemented +/// In the first naive example, [`AdcChannel`] is implemented /// using a spin loop and only returns once data is ready. /// /// ``` @@ -20,8 +24,8 @@ pub use embedded_hal::adc::{Error, ErrorKind, ErrorType}; /// true /// } /// -/// pub fn data(&mut self) -> u32 { -/// 42 +/// pub fn data(&mut self) -> u16 { +/// 3300 /// } /// } /// @@ -30,12 +34,16 @@ pub use embedded_hal::adc::{Error, ErrorKind, ErrorType}; /// } /// /// impl AdcChannel for MySpinningAdc { -/// async fn read(&mut self) -> Result { +/// async fn measure_nv(&mut self) -> Result { +/// Ok(self.measure_mv().await? as i64 * 1_000_000) +/// } +/// +/// async fn measure_mv(&mut self) -> Result { /// while !self.is_ready() { /// core::hint::spin_loop(); /// } /// -/// Ok(self.data()) +/// Ok(self.data() as i32) /// } /// } /// ``` @@ -51,8 +59,8 @@ pub use embedded_hal::adc::{Error, ErrorKind, ErrorType}; /// }; /// /// impl MyWaitingAdc { -/// pub fn data(&mut self) -> u32 { -/// 42 +/// pub fn data(&mut self) -> u16 { +/// 3300 /// } /// } /// @@ -61,7 +69,11 @@ pub use embedded_hal::adc::{Error, ErrorKind, ErrorType}; /// } /// /// impl AdcChannel for MyWaitingAdc { -/// async fn read(&mut self) -> Result { +/// async fn measure_nv(&mut self) -> Result { +/// Ok(self.measure_mv().await? as i64 * 1_000_000) +/// } +/// +/// async fn measure_mv(&mut self) -> Result { /// match self.ready_pin.wait_for_high().await { /// Ok(()) => (), /// Err(err) => return Err(match err.kind() { @@ -70,18 +82,23 @@ pub use embedded_hal::adc::{Error, ErrorKind, ErrorType}; /// }) /// } /// -/// Ok(self.data()) +/// Ok(self.data() as i32) /// } /// } /// ``` pub trait AdcChannel: ErrorType { - /// Reads data from the ADC. - /// - /// # Note for Implementers - /// - /// This should wait until data is ready and then read it. - /// If the ADC's precision is less than 32 bits, the value must be scaled accordingly. - async fn read(&mut self) -> Result; + /// Take a measurement in nV (nanovolts). + async fn measure_nv(&mut self) -> Result; + + /// Take a measurement in mV (microvolts). + async fn measure_uv(&mut self) -> Result { + Ok((self.measure_nv().await? / 1_000) as i32) + } + + /// Take a measurement in mV (millivolts). + async fn measure_mv(&mut self) -> Result { + Ok(self.measure_uv().await? / 1_000) + } } impl AdcChannel for &mut T @@ -89,96 +106,17 @@ where T: AdcChannel + ?Sized, { #[inline] - async fn read(&mut self) -> Result { - (*self).read().await - } -} - -#[cfg(test)] -mod test { - use super::*; - - /// Scale an integer containing `bits` bits to 32 bits. - fn scale_bits(raw_data: u32, bits: u32) -> u32 { - let mut scaled_data: u32 = 0; - - let mut remaining_bits = u32::BITS; - while remaining_bits > 0 { - let shl = bits.min(remaining_bits); - scaled_data = (scaled_data.wrapping_shl(shl)) | (raw_data.wrapping_shr(bits - shl)); - remaining_bits -= shl; - } - - scaled_data - } - - #[test] - fn scale_bits_i8_to_i32() { - let raw_data = u32::from(i8::MIN as u8); - let scaled_data = scale_bits(raw_data, 8); - assert!(i32::MIN <= (scaled_data as i32) && (scaled_data as i32) <= (i32::MIN + 1 << 8)); + async fn measure_nv(&mut self) -> Result { + (*self).measure_nv().await } - macro_rules! impl_adc { - ($Adc:ident, $bits:literal, $uint:ty) => { - struct $Adc($uint); - - impl $Adc { - const MAX: $uint = !(<$uint>::MAX.wrapping_shl($bits - 1).wrapping_shl(1)); - - pub fn data(&mut self) -> $uint { - self.0 - } - } - - impl ErrorType for $Adc { - type Error = core::convert::Infallible; - } - - impl AdcChannel for $Adc { - async fn read(&mut self) -> Result { - Ok(scale_bits(u32::from(self.data()), $bits)) - } - } - }; - } - - macro_rules! test_adc { - ($Adc:ident, $bits:literal, $uint:ty) => {{ - impl_adc!($Adc, $bits, $uint); - - // 0 should always be scaled to 0. - let mut adc_0 = $Adc(0); - assert_eq!(adc_0.read().await, Ok(0)); - - // `$Adc::MAX` should always be scaled to `u32::MAX`. - let mut adc_max = $Adc($Adc::MAX); - assert_eq!(adc_max.read().await, Ok(u32::MAX)); - }}; - } - - #[tokio::test] - async fn test_8_bit() { - test_adc!(Adc8, 8, u8); - } - - #[tokio::test] - async fn test_12_bit() { - test_adc!(Adc12, 12, u16); - } - - #[tokio::test] - async fn test_16_bit() { - test_adc!(Adc16, 16, u16); - } - - #[tokio::test] - async fn test_24_bit() { - test_adc!(Adc24, 24, u32); + #[inline] + async fn measure_uv(&mut self) -> Result { + (*self).measure_uv().await } - #[tokio::test] - async fn test_32_bit() { - test_adc!(Adc32, 32, u32); + #[inline] + async fn measure_mv(&mut self) -> Result { + (*self).measure_mv().await } } diff --git a/embedded-hal/src/adc.rs b/embedded-hal/src/adc.rs index fb22b943..7a6c4c09 100644 --- a/embedded-hal/src/adc.rs +++ b/embedded-hal/src/adc.rs @@ -7,9 +7,13 @@ use crate::defmt; /// Read data from an ADC. /// +/// # Note for Implementers +/// +/// This should wait until data is ready and then read it. +/// /// # Examples /// -/// In the first naive example, [`read`](crate::adc::AdcChannel::read) is implemented +/// In the first naive example, [`AdcChannel`] is implemented /// using a spin loop and only returns once data is ready. /// /// ``` @@ -23,8 +27,8 @@ use crate::defmt; /// true /// } /// -/// pub fn data(&mut self) -> u32 { -/// 42 +/// pub fn data(&mut self) -> u16 { +/// 3300 /// } /// } /// @@ -33,23 +37,32 @@ use crate::defmt; /// } /// /// impl AdcChannel for MySpinningAdc { -/// fn read(&mut self) -> Result { +/// fn measure_nv(&mut self) -> Result { +/// Ok(self.measure_mv()? as i64 * 1_000_000) +/// } +/// +/// fn measure_mv(&mut self) -> Result { /// while !self.is_ready() { /// core::hint::spin_loop(); /// } /// -/// Ok(self.data()) +/// Ok(self.data() as i32) /// } /// } /// ``` pub trait AdcChannel: ErrorType { - /// Reads data from the ADC. - /// - /// # Note for Implementers - /// - /// This should wait until data is ready and then read it. - /// If the ADC's precision is less than 32 bits, the value must be scaled accordingly. - fn read(&mut self) -> Result; + /// Take a measurement in nV (nanovolts). + fn measure_nv(&mut self) -> Result; + + /// Take a measurement in mV (microvolts). + fn measure_uv(&mut self) -> Result { + Ok((self.measure_nv()? / 1_000) as i32) + } + + /// Take a measurement in mV (millivolts). + fn measure_mv(&mut self) -> Result { + Ok(self.measure_uv()? / 1_000) + } } impl AdcChannel for &mut T @@ -57,8 +70,18 @@ where T: AdcChannel + ?Sized, { #[inline] - fn read(&mut self) -> Result { - (*self).read() + fn measure_nv(&mut self) -> Result { + (*self).measure_nv() + } + + #[inline] + fn measure_uv(&mut self) -> Result { + (*self).measure_uv() + } + + #[inline] + fn measure_mv(&mut self) -> Result { + (*self).measure_mv() } }