From af5562e9b9829c991a9e4c996db625569c9483ce Mon Sep 17 00:00:00 2001 From: Andres Vahter Date: Tue, 28 Nov 2023 14:38:40 +0200 Subject: [PATCH 1/4] embedded_hal_async support + update embedded_hal --- Cargo.toml | 7 +- src/configuration.rs | 214 ++++++++++++++++++++++++++++++++++++++++++- src/lib.rs | 7 +- src/reading.rs | 103 ++++++++++++++++++++- 4 files changed, 324 insertions(+), 7 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index d724c22..16726fa 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,8 +20,13 @@ include = [ "/LICENSE-APACHE", ] +[features] +default = [] +async = ["dep:embedded-hal-async"] + [dependencies] -embedded-hal = "0.2" +embedded-hal = "1.0.0-rc.1" +embedded-hal-async = { version = "=1.0.0-rc.1", optional = true } [dev-dependencies] linux-embedded-hal = "0.3" diff --git a/src/configuration.rs b/src/configuration.rs index c2fb469..292a2a0 100644 --- a/src/configuration.rs +++ b/src/configuration.rs @@ -1,68 +1,145 @@ use crate::{ BitFlags, Error, Register, RgbCGain, RgbCInterruptPersistence, Tcs3400, DEVICE_ADDRESS, }; -use embedded_hal::blocking::i2c; +#[cfg(not(feature = "async"))] +use embedded_hal::i2c::I2c; +#[cfg(feature = "async")] +use embedded_hal_async::i2c::I2c; impl Tcs3400 where - I2C: i2c::Write, + I2C: I2c, { /// Enable the device (Power ON). /// /// The device goes to idle state. + #[cfg(not(feature = "async"))] pub fn enable(&mut self) -> Result<(), Error> { let enable = self.enable; self.write_enable(enable | BitFlags::POWER_ON) } + /// Enable the device (Power ON). + /// + /// The device goes to idle state. + #[cfg(feature = "async")] + pub async fn enable(&mut self) -> Result<(), Error> { + let enable = self.enable; + self.write_enable(enable | BitFlags::POWER_ON).await + } + /// Disable the device (sleep). + #[cfg(not(feature = "async"))] pub fn disable(&mut self) -> Result<(), Error> { let enable = self.enable; self.write_enable(enable & !BitFlags::POWER_ON) } + /// Disable the device (sleep). + #[cfg(feature = "async")] + pub async fn disable(&mut self) -> Result<(), Error> { + let enable = self.enable; + self.write_enable(enable & !BitFlags::POWER_ON).await + } + /// Enable the RGB converter. + #[cfg(not(feature = "async"))] pub fn enable_rgbc(&mut self) -> Result<(), Error> { let enable = self.enable; self.write_enable(enable | BitFlags::RGBC_EN) } + /// Enable the RGB converter. + #[cfg(feature = "async")] + pub async fn enable_rgbc(&mut self) -> Result<(), Error> { + let enable = self.enable; + self.write_enable(enable | BitFlags::RGBC_EN).await + } + /// Disable the RGB converter. + #[cfg(not(feature = "async"))] pub fn disable_rgbc(&mut self) -> Result<(), Error> { let enable = self.enable; self.write_enable(enable & !BitFlags::RGBC_EN) } + /// Disable the RGB converter. + #[cfg(feature = "async")] + pub async fn disable_rgbc(&mut self) -> Result<(), Error> { + let enable = self.enable; + self.write_enable(enable & !BitFlags::RGBC_EN).await + } + /// Enable the RGB converter interrupt generation. + #[cfg(not(feature = "async"))] pub fn enable_rgbc_interrupts(&mut self) -> Result<(), Error> { let enable = self.enable; self.write_enable(enable | BitFlags::RGBC_INT_EN) } + /// Enable the RGB converter interrupt generation. + #[cfg(feature = "async")] + pub async fn enable_rgbc_interrupts(&mut self) -> Result<(), Error> { + let enable = self.enable; + self.write_enable(enable | BitFlags::RGBC_INT_EN).await + } + /// Disable the RGB converter interrupt generation. + #[cfg(not(feature = "async"))] pub fn disable_rgbc_interrupts(&mut self) -> Result<(), Error> { let enable = self.enable; self.write_enable(enable & !BitFlags::RGBC_INT_EN) } + /// Disable the RGB converter interrupt generation. + #[cfg(feature = "async")] + pub async fn disable_rgbc_interrupts(&mut self) -> Result<(), Error> { + let enable = self.enable; + self.write_enable(enable & !BitFlags::RGBC_INT_EN).await + } + /// Enable the wait feature (wait timer). + #[cfg(not(feature = "async"))] pub fn enable_wait(&mut self) -> Result<(), Error> { let enable = self.enable; self.write_enable(enable | BitFlags::WAIT_EN) } + /// Enable the wait feature (wait timer). + #[cfg(feature = "async")] + pub async fn enable_wait(&mut self) -> Result<(), Error> { + let enable = self.enable; + self.write_enable(enable | BitFlags::WAIT_EN).await + } + /// Disable the wait feature (wait timer). + #[cfg(not(feature = "async"))] pub fn disable_wait(&mut self) -> Result<(), Error> { let enable = self.enable; self.write_enable(enable & !BitFlags::WAIT_EN) } + /// Disable the wait feature (wait timer). + #[cfg(feature = "async")] + pub async fn disable_wait(&mut self) -> Result<(), Error> { + let enable = self.enable; + self.write_enable(enable & !BitFlags::WAIT_EN).await + } + + #[cfg(not(feature = "async"))] fn write_enable(&mut self, enable: u8) -> Result<(), Error> { self.write_register(Register::ENABLE, enable)?; self.enable = enable; Ok(()) } + #[cfg(feature = "async")] + async fn write_enable(&mut self, enable: u8) -> Result<(), Error> { + self.write_register(Register::ENABLE, enable).await?; + self.enable = enable; + Ok(()) + } + /// Set the number of wait time cycles (1-256). /// /// The actual wait time depends on the "*wait long*" setting. @@ -73,6 +150,7 @@ where /// `number_of_cycles * 0.03s`. /// See [`enable_wait_long()`](#method.enable_wait_long) and /// [`disable_wait_long()`](#method.disable_wait_long). + #[cfg(not(feature = "async"))] pub fn set_wait_cycles(&mut self, cycles: u16) -> Result<(), Error> { if cycles > 256 || cycles == 0 { return Err(Error::InvalidInputData); @@ -81,23 +159,64 @@ where self.write_register(Register::WTIME, (256 - cycles as u16) as u8) } + /// Set the number of wait time cycles (1-256). + /// + /// The actual wait time depends on the "*wait long*" setting. + /// - If *wait long* is disabled, then the wait time corresponds to: + /// `number_of_cycles * 2.78ms`. + /// - If *wait long* is enabled, then the wait time is increased by a + /// factor of 12 and therefore corresponds to aproximately: + /// `number_of_cycles * 0.03s`. + /// See [`enable_wait_long()`](#method.enable_wait_long) and + /// [`disable_wait_long()`](#method.disable_wait_long). + #[cfg(feature = "async")] + pub async fn set_wait_cycles(&mut self, cycles: u16) -> Result<(), Error> { + if cycles > 256 || cycles == 0 { + return Err(Error::InvalidInputData); + } + // the value is stored as a two's complement + self.write_register(Register::WTIME, (256 - cycles as u16) as u8) + .await + } + /// Enable the *wait long* setting. /// /// The wait time configured with `set_wait_cycles()` is increased by a /// factor of 12. See [`set_wait_cycles()`](#method.set_wait_cycles). + #[cfg(not(feature = "async"))] pub fn enable_wait_long(&mut self) -> Result<(), Error> { self.write_register(Register::CONFIG, BitFlags::WLONG) } + /// Enable the *wait long* setting. + /// + /// The wait time configured with `set_wait_cycles()` is increased by a + /// factor of 12. See [`set_wait_cycles()`](#method.set_wait_cycles). + #[cfg(feature = "async")] + pub async fn enable_wait_long(&mut self) -> Result<(), Error> { + self.write_register(Register::CONFIG, BitFlags::WLONG).await + } + /// Disable the *wait long* setting. /// /// The wait time configured with `set_wait_cycles()` is used without /// multiplication factor. See [`set_wait_cycles()`](#method.set_wait_cycles). + #[cfg(not(feature = "async"))] pub fn disable_wait_long(&mut self) -> Result<(), Error> { self.write_register(Register::CONFIG, 0) } + /// Disable the *wait long* setting. + /// + /// The wait time configured with `set_wait_cycles()` is used without + /// multiplication factor. See [`set_wait_cycles()`](#method.set_wait_cycles). + #[cfg(feature = "async")] + pub async fn disable_wait_long(&mut self) -> Result<(), Error> { + self.write_register(Register::CONFIG, 0).await + } + /// Set the RGB converter gain. + #[cfg(not(feature = "async"))] pub fn set_rgbc_gain(&mut self, gain: RgbCGain) -> Result<(), Error> { // Register field: AGAIN match gain { @@ -108,9 +227,22 @@ where } } + /// Set the RGB converter gain. + #[cfg(feature = "async")] + pub async fn set_rgbc_gain(&mut self, gain: RgbCGain) -> Result<(), Error> { + // Register field: AGAIN + match gain { + RgbCGain::_1x => self.write_register(Register::CONTROL, 0).await, + RgbCGain::_4x => self.write_register(Register::CONTROL, 1).await, + RgbCGain::_16x => self.write_register(Register::CONTROL, 2).await, + RgbCGain::_60x => self.write_register(Register::CONTROL, 3).await, + } + } + /// Set the number of integration cycles (1-256). /// /// The actual integration time corresponds to: `number_of_cycles * 2.78ms`. + #[cfg(not(feature = "async"))] pub fn set_integration_cycles(&mut self, cycles: u16) -> Result<(), Error> { if cycles > 256 || cycles == 0 { return Err(Error::InvalidInputData); @@ -119,21 +251,61 @@ where self.write_register(Register::ATIME, (256 - cycles as u16) as u8) } + /// Set the number of integration cycles (1-256). + /// + /// The actual integration time corresponds to: `number_of_cycles * 2.78ms`. + #[cfg(feature = "async")] + pub async fn set_integration_cycles(&mut self, cycles: u16) -> Result<(), Error> { + if cycles > 256 || cycles == 0 { + return Err(Error::InvalidInputData); + } + // the value is stored as a two's complement + self.write_register(Register::ATIME, (256 - cycles as u16) as u8) + .await + } + /// Set the RGB converter interrupt clear channel low threshold. + #[cfg(not(feature = "async"))] pub fn set_rgbc_interrupt_low_threshold(&mut self, threshold: u16) -> Result<(), Error> { self.write_register(Register::AILTL, threshold as u8)?; self.write_register(Register::AILTH, (threshold >> 8) as u8) } + /// Set the RGB converter interrupt clear channel low threshold. + #[cfg(feature = "async")] + pub async fn set_rgbc_interrupt_low_threshold( + &mut self, + threshold: u16, + ) -> Result<(), Error> { + self.write_register(Register::AILTL, threshold as u8) + .await?; + self.write_register(Register::AILTH, (threshold >> 8) as u8) + .await + } + /// Set the RGB converter interrupt clear channel high threshold. + #[cfg(not(feature = "async"))] pub fn set_rgbc_interrupt_high_threshold(&mut self, threshold: u16) -> Result<(), Error> { self.write_register(Register::AIHTL, threshold as u8)?; self.write_register(Register::AIHTH, (threshold >> 8) as u8) } + /// Set the RGB converter interrupt clear channel high threshold. + #[cfg(feature = "async")] + pub async fn set_rgbc_interrupt_high_threshold( + &mut self, + threshold: u16, + ) -> Result<(), Error> { + self.write_register(Register::AIHTL, threshold as u8) + .await?; + self.write_register(Register::AIHTH, (threshold >> 8) as u8) + .await + } + /// Set the RGB converter interrupt persistence. /// /// This controls the RGB converter interrupt generation rate. + #[cfg(not(feature = "async"))] pub fn set_rgbc_interrupt_persistence( &mut self, persistence: RgbCInterruptPersistence, @@ -159,9 +331,47 @@ where } } + /// Set the RGB converter interrupt persistence. + /// + /// This controls the RGB converter interrupt generation rate. + #[cfg(feature = "async")] + pub async fn set_rgbc_interrupt_persistence( + &mut self, + persistence: RgbCInterruptPersistence, + ) -> Result<(), Error> { + use crate::RgbCInterruptPersistence as IP; + match persistence { + IP::Every => self.write_register(Register::APERS, 0).await, + IP::Any => self.write_register(Register::APERS, 1).await, + IP::_2 => self.write_register(Register::APERS, 2).await, + IP::_3 => self.write_register(Register::APERS, 3).await, + IP::_5 => self.write_register(Register::APERS, 4).await, + IP::_10 => self.write_register(Register::APERS, 5).await, + IP::_15 => self.write_register(Register::APERS, 6).await, + IP::_20 => self.write_register(Register::APERS, 7).await, + IP::_25 => self.write_register(Register::APERS, 8).await, + IP::_30 => self.write_register(Register::APERS, 9).await, + IP::_35 => self.write_register(Register::APERS, 10).await, + IP::_40 => self.write_register(Register::APERS, 11).await, + IP::_45 => self.write_register(Register::APERS, 12).await, + IP::_50 => self.write_register(Register::APERS, 13).await, + IP::_55 => self.write_register(Register::APERS, 14).await, + IP::_60 => self.write_register(Register::APERS, 15).await, + } + } + + #[cfg(not(feature = "async"))] fn write_register(&mut self, register: u8, value: u8) -> Result<(), Error> { self.i2c .write(DEVICE_ADDRESS, &[register, value]) .map_err(Error::I2C) } + + #[cfg(feature = "async")] + async fn write_register(&mut self, register: u8, value: u8) -> Result<(), Error> { + self.i2c + .write(DEVICE_ADDRESS, &[register, value]) + .await + .map_err(Error::I2C) + } } diff --git a/src/lib.rs b/src/lib.rs index ebc285a..9d91195 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -148,7 +148,10 @@ #![deny(unsafe_code, missing_docs)] #![no_std] -use embedded_hal::blocking::i2c; +#[cfg(not(feature = "async"))] +use embedded_hal::i2c::I2c; +#[cfg(feature = "async")] +use embedded_hal_async::i2c::I2c; mod configuration; mod interface; @@ -168,7 +171,7 @@ pub struct Tcs3400 { impl Tcs3400 where - I2C: i2c::Write, + I2C: I2c, { /// Create new instance of the TCS3400 device. pub fn new(i2c: I2C) -> Self { diff --git a/src/reading.rs b/src/reading.rs index 9273a46..f9f9b9d 100644 --- a/src/reading.rs +++ b/src/reading.rs @@ -1,46 +1,97 @@ use crate::{AllChannelMeasurement, BitFlags, Error, Register, Tcs3400, DEVICE_ADDRESS}; -use embedded_hal::blocking::i2c; +#[cfg(not(feature = "async"))] +use embedded_hal::i2c::I2c; +#[cfg(feature = "async")] +use embedded_hal_async::i2c::I2c; impl Tcs3400 where - I2C: i2c::WriteRead, + I2C: I2c, { /// Check whether the RGB converter status is valid. /// /// Indicates that the RGBC channels have completed an integration cycle. #[allow(clippy::wrong_self_convention)] + #[cfg(not(feature = "async"))] pub fn is_rgbc_status_valid(&mut self) -> Result> { let status = self.read_register(Register::STATUS)?; Ok((status & BitFlags::RGBC_VALID) != 0) } + /// Check whether the RGB converter status is valid. + /// + /// Indicates that the RGBC channels have completed an integration cycle. + #[allow(clippy::wrong_self_convention)] + #[cfg(feature = "async")] + pub async fn is_rgbc_status_valid(&mut self) -> Result> { + let status = self.read_register(Register::STATUS).await?; + Ok((status & BitFlags::RGBC_VALID) != 0) + } + /// Read the clear (unfiltered) channel measurement data. + #[cfg(not(feature = "async"))] pub fn read_clear_channel(&mut self) -> Result> { self.read_channel(Register::CDATAL) } + /// Read the clear (unfiltered) channel measurement data. + #[cfg(feature = "async")] + pub async fn read_clear_channel(&mut self) -> Result> { + self.read_channel(Register::CDATAL).await + } + /// Read the red channel measurement data. + #[cfg(not(feature = "async"))] pub fn read_red_channel(&mut self) -> Result> { self.read_channel(Register::RDATAL) } + /// Read the red channel measurement data. + #[cfg(feature = "async")] + pub async fn read_red_channel(&mut self) -> Result> { + self.read_channel(Register::RDATAL).await + } + /// Read the green channel measurement data. + #[cfg(not(feature = "async"))] pub fn read_green_channel(&mut self) -> Result> { self.read_channel(Register::GDATAL) } + /// Read the green channel measurement data. + #[cfg(feature = "async")] + pub async fn read_green_channel(&mut self) -> Result> { + self.read_channel(Register::GDATAL).await + } + /// Read the blue channel measurement data. + #[cfg(not(feature = "async"))] pub fn read_blue_channel(&mut self) -> Result> { self.read_channel(Register::BDATAL) } + /// Read the blue channel measurement data. + #[cfg(feature = "async")] + pub async fn read_blue_channel(&mut self) -> Result> { + self.read_channel(Register::BDATAL).await + } + + #[cfg(not(feature = "async"))] fn read_channel(&mut self, first_register: u8) -> Result> { let mut cdata = [0; 2]; self.read_registers(first_register, &mut cdata)?; Ok((u16::from(cdata[1])) << 8 | u16::from(cdata[0])) } + #[cfg(feature = "async")] + async fn read_channel(&mut self, first_register: u8) -> Result> { + let mut cdata = [0; 2]; + self.read_registers(first_register, &mut cdata).await?; + Ok((u16::from(cdata[1])) << 8 | u16::from(cdata[0])) + } + /// Read the measurement data of all channels at once. + #[cfg(not(feature = "async"))] pub fn read_all_channels(&mut self) -> Result> { let mut data = [0; 8]; self.read_registers(Register::CDATAL, &mut data)?; @@ -52,15 +103,40 @@ where }) } + /// Read the measurement data of all channels at once. + #[cfg(feature = "async")] + pub async fn read_all_channels(&mut self) -> Result> { + let mut data = [0; 8]; + self.read_registers(Register::CDATAL, &mut data).await?; + Ok(AllChannelMeasurement { + clear: u16::from(data[1]) << 8 | u16::from(data[0]), + red: u16::from(data[3]) << 8 | u16::from(data[2]), + green: u16::from(data[5]) << 8 | u16::from(data[4]), + blue: u16::from(data[7]) << 8 | u16::from(data[6]), + }) + } + /// Read the device ID. /// /// The value returned corresponds to the part number identification: /// - `0x90` => `TCS34001 & TCS34005` /// - `0x93` => `TCS34003 & TCS34007` + #[cfg(not(feature = "async"))] pub fn read_device_id(&mut self) -> Result> { self.read_register(Register::ID) } + /// Read the device ID. + /// + /// The value returned corresponds to the part number identification: + /// - `0x90` => `TCS34001 & TCS34005` + /// - `0x93` => `TCS34003 & TCS34007` + #[cfg(feature = "async")] + pub async fn read_device_id(&mut self) -> Result> { + self.read_register(Register::ID).await + } + + #[cfg(not(feature = "async"))] fn read_register(&mut self, register: u8) -> Result> { let mut data = [0]; self.i2c @@ -69,9 +145,32 @@ where Ok(data[0]) } + #[cfg(feature = "async")] + async fn read_register(&mut self, register: u8) -> Result> { + let mut data = [0]; + self.i2c + .write_read(DEVICE_ADDRESS, &[register], &mut data) + .await + .map_err(Error::I2C)?; + Ok(data[0]) + } + + #[cfg(not(feature = "async"))] fn read_registers(&mut self, first_register: u8, mut data: &mut [u8]) -> Result<(), Error> { self.i2c .write_read(DEVICE_ADDRESS, &[first_register], &mut data) .map_err(Error::I2C) } + + #[cfg(feature = "async")] + async fn read_registers( + &mut self, + first_register: u8, + mut data: &mut [u8], + ) -> Result<(), Error> { + self.i2c + .write_read(DEVICE_ADDRESS, &[first_register], &mut data) + .await + .map_err(Error::I2C) + } } From 991ef13b377621ba3f33e712d80d2ea14b6e6720 Mon Sep 17 00:00:00 2001 From: Andres Vahter Date: Tue, 28 Nov 2023 14:55:25 +0200 Subject: [PATCH 2/4] changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bc1b18b..69fc609 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ## [Unreleased] -... +* Added `embedded_hal_async` support. ## 0.1.0 - 2022-11-16 From b2cf9cf522ec73e66618f9510e7503510f3ebe00 Mon Sep 17 00:00:00 2001 From: Andres Vahter Date: Fri, 5 Jan 2024 14:59:41 +0200 Subject: [PATCH 3/4] update to embedded-hal = "1.0.0-rc.3" --- Cargo.toml | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 16726fa..936b6be 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,12 +25,11 @@ default = [] async = ["dep:embedded-hal-async"] [dependencies] -embedded-hal = "1.0.0-rc.1" -embedded-hal-async = { version = "=1.0.0-rc.1", optional = true } +embedded-hal = "1.0.0-rc.3" +embedded-hal-async = { version = "=1.0.0-rc.3", optional = true } [dev-dependencies] -linux-embedded-hal = "0.3" -embedded-hal-mock = "0.7" +linux-embedded-hal = "0.4.0-alpha.4" [profile.release] lto = true From dcafb4cb8fe0c95ed51aae7bee9c1bb507981352 Mon Sep 17 00:00:00 2001 From: Andres Vahter Date: Wed, 10 Jan 2024 12:23:10 +0200 Subject: [PATCH 4/4] embedded-hal = "1.0" --- Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 936b6be..d3316cb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,8 +25,8 @@ default = [] async = ["dep:embedded-hal-async"] [dependencies] -embedded-hal = "1.0.0-rc.3" -embedded-hal-async = { version = "=1.0.0-rc.3", optional = true } +embedded-hal = "1.0" +embedded-hal-async = { version = "1.0", optional = true } [dev-dependencies] linux-embedded-hal = "0.4.0-alpha.4"