From 51b02e523ddf8470ab2a10163345264210a66d3c Mon Sep 17 00:00:00 2001 From: Hauke Jung Date: Thu, 18 Jan 2024 06:19:34 +0100 Subject: [PATCH] Update to embedded hal v.1.0.0 --- Cargo.toml | 22 ++++++------ bin/main.rs | 17 +++++---- examples/linux.rs | 8 ++--- src/error.rs | 17 --------- src/lib.rs | 4 --- src/scd4x.rs | 89 +++++++++++++++++++++++------------------------ 6 files changed, 67 insertions(+), 90 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 42f14f9..07f9dde 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "scd4x" -version = "0.2.2" +version = "0.3.0" authors = ["Hauke Jung "] documentation = "https://docs.rs/scd4x" repository = "https://github.com/hauju/scd4x-rs.git" @@ -18,22 +18,22 @@ util = [ "structopt", "simplelog", "humantime", "linux-embedded-hal", "anyhow" ] default = [ "util" ] [dependencies] -sensirion-i2c = "0.1" -embedded-hal = "0.2" +sensirion-i2c = "0.2" +embedded-hal = "1.0" -log = { version = "0.4.16", default_features = false } -defmt = { version = "0.3.0", optional = true } -anyhow = { version = "1.0.56", optional=true, default_features = false } +log = { version = "0.4.20", default_features = false } +defmt = { version = "0.3.5", optional = true } +anyhow = { version = "1.0.79", optional=true, default_features = false } structopt = { version = "0.3.26", optional = true } -linux-embedded-hal = { version = "0.3.2", optional = true } -simplelog = { version = "0.12.0", optional = true } +linux-embedded-hal = { version = "0.4", optional = true } +simplelog = { version = "0.12.1", optional = true } humantime = { version = "2.1.0", optional = true } - [dev-dependencies] -linux-embedded-hal = "0.3" -embedded-hal-mock = "0.8" +linux-embedded-hal = "0.4" +embedded-hal-mock = "0.10" + [[bin]] name = "scd4x-util" diff --git a/bin/main.rs b/bin/main.rs index 56c9a40..98f03ef 100644 --- a/bin/main.rs +++ b/bin/main.rs @@ -1,6 +1,6 @@ -use embedded_hal::blocking::delay::DelayMs; -use hal::{Delay, I2cdev, i2cdev::linux::LinuxI2CError}; -use linux_embedded_hal as hal; + +use embedded_hal::delay::DelayNs; +use linux_embedded_hal::{Delay, I2cdev, i2cdev::linux::LinuxI2CError}; use log::{debug, info, error}; @@ -35,7 +35,6 @@ pub struct Options { fn main() -> Result<(), Error> { - // Load options let opts = Options::from_args(); @@ -62,19 +61,19 @@ fn main() -> Result<(), Error> { #[cfg(feature = "scd41")] sensor.wake_up(); - sensor.stop_periodic_measurement()?; - sensor.reinit()?; + sensor.stop_periodic_measurement().unwrap(); + sensor.reinit().unwrap(); - let serial = sensor.serial_number()?; + let serial = sensor.serial_number().unwrap(); info!("Serial: {:#04x}", serial); debug!("Starting periodic measurement"); - sensor.start_periodic_measurement()?; + sensor.start_periodic_measurement().unwrap(); debug!("Waiting for first measurement... (5 sec)"); loop { - hal::Delay.delay_ms(5000u16); + Delay.delay_ms(5000); debug!("Waiting for data ready"); loop { diff --git a/examples/linux.rs b/examples/linux.rs index 295ae39..3884051 100644 --- a/examples/linux.rs +++ b/examples/linux.rs @@ -1,6 +1,6 @@ -use embedded_hal::blocking::delay::DelayMs; -use hal::{Delay, I2cdev}; -use linux_embedded_hal as hal; + +use embedded_hal::delay::DelayNs; +use linux_embedded_hal::{Delay, I2cdev}; use scd4x::Scd4x; @@ -19,7 +19,7 @@ fn main() { sensor.start_periodic_measurement().unwrap(); println!("Waiting for first measurement... (5 sec)"); loop { - hal::Delay.delay_ms(5000u16); + Delay.delay_ms(5000); let data = sensor.measurement().unwrap(); diff --git a/src/error.rs b/src/error.rs index 48bdd4c..52fb6e5 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,6 +1,3 @@ -use embedded_hal as hal; -use hal::blocking::i2c::{Read, Write}; -use sensirion_i2c::i2c; /// SCD4X errors #[derive(Debug, PartialEq)] @@ -22,17 +19,3 @@ pub enum Error { /// Internal fail Internal } - -impl From> for Error -where - I2cWrite: Write, - I2cRead: Read, -{ - fn from(err: i2c::Error) -> Self { - match err { - i2c::Error::Crc => Error::Crc, - i2c::Error::I2cWrite(e) => Error::I2c(e), - i2c::Error::I2cRead(e) => Error::I2c(e), - } - } -} diff --git a/src/lib.rs b/src/lib.rs index 0171e10..6fd625a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -8,10 +8,6 @@ /// Log functions for internal use, use `crate::log::*` mod log { - // Default to logging with log - #[cfg(not(feature = "defmt"))] - pub use log::{trace, debug, info, warn, error}; - // Replace with defmt if enabled #[cfg(feature = "defmt")] pub use defmt::{trace, debug, info, warn, error}; diff --git a/src/scd4x.rs b/src/scd4x.rs index ea998b2..1d032ba 100644 --- a/src/scd4x.rs +++ b/src/scd4x.rs @@ -1,11 +1,10 @@ -use embedded_hal as hal; -use hal::blocking::delay::DelayMs; -use hal::blocking::i2c::{Read, Write, WriteRead}; use crate::commands::Command; use crate::error::Error; use crate::types::{RawSensorData, SensorData}; -use sensirion_i2c::{crc8, i2c}; +use sensirion_i2c::crc8; +use embedded_hal::delay::DelayNs; +use embedded_hal::i2c::I2c; const SCD4X_I2C_ADDRESS: u8 = 0x62; @@ -17,10 +16,10 @@ pub struct Scd4x { is_running: bool, } -impl Scd4x +impl Scd4x where - I2C: Read + Write + WriteRead, - D: DelayMs, + I2C: I2c, + D: DelayNs, { pub fn new(i2c: I2C, delay: D) -> Self { Scd4x { @@ -32,7 +31,7 @@ where /// Start periodic measurement, signal update interval is 5 seconds. /// This command is only available in idle mode. - pub fn start_periodic_measurement(&mut self) -> Result<(), Error> { + pub fn start_periodic_measurement(&mut self) -> Result<(), Error> { self.write_command(Command::StartPeriodicMeasurement)?; self.is_running = true; Ok(()) @@ -40,14 +39,14 @@ where /// Stop periodic measurement and return to idle mode for sensor configuration or to safe energy. /// This command is only available in measurement mode. - pub fn stop_periodic_measurement(&mut self) -> Result<(), Error> { + pub fn stop_periodic_measurement(&mut self) -> Result<(), Error> { self.write_command(Command::StopPeriodicMeasurement)?; self.is_running = false; Ok(()) } /// Read raw sensor data - pub fn sensor_output(&mut self) -> Result> { + pub fn sensor_output(&mut self) -> Result> { let mut buf = [0; 9]; self.delayed_read_cmd(Command::ReadMeasurement, &mut buf)?; @@ -63,7 +62,7 @@ where } /// Read converted sensor data - pub fn measurement(&mut self) -> Result> { + pub fn measurement(&mut self) -> Result> { let mut buf = [0; 9]; self.delayed_read_cmd(Command::ReadMeasurement, &mut buf)?; @@ -80,7 +79,7 @@ where } /// Get sensor temperature offset - pub fn temperature_offset(&mut self) -> Result> { + pub fn temperature_offset(&mut self) -> Result> { let mut buf = [0; 3]; self.delayed_read_cmd(Command::GetTemperatureOffset, &mut buf)?; @@ -90,14 +89,14 @@ where } /// Set sensor temperature offset - pub fn set_temperature_offset(&mut self, offset: f32) -> Result<(), Error> { + pub fn set_temperature_offset(&mut self, offset: f32) -> Result<(), Error> { let t_offset = (offset * 65536.0 / 175.0) as i16; self.write_command_with_data(Command::SetTemperatureOffset, t_offset as u16)?; Ok(()) } /// Get sensor altitude in meters above sea level. - pub fn altitude(&mut self) -> Result> { + pub fn altitude(&mut self) -> Result> { let mut buf = [0; 3]; self.delayed_read_cmd(Command::GetSensorAltitude, &mut buf)?; let altitude = u16::from_be_bytes([buf[0], buf[1]]); @@ -105,19 +104,19 @@ where } /// Set sensor altitude in meters above sea level. - pub fn set_altitude(&mut self, altitude: u16) -> Result<(), Error> { + pub fn set_altitude(&mut self, altitude: u16) -> Result<(), Error> { self.write_command_with_data(Command::SetSensorAltitude, altitude)?; Ok(()) } /// Set ambient pressure to enable continious pressure compensation - pub fn set_ambient_pressure(&mut self, pressure_hpa: u16) -> Result<(), Error> { + pub fn set_ambient_pressure(&mut self, pressure_hpa: u16) -> Result<(), Error> { self.write_command_with_data(Command::SetAmbientPressure, pressure_hpa)?; Ok(()) } /// Perform forced recalibration - pub fn forced_recalibration(&mut self, target_co2_concentration: u16) -> Result> { + pub fn forced_recalibration(&mut self, target_co2_concentration: u16) -> Result> { let frc_correction = self.delayed_read_cmd_with_data( Command::PerformForcedRecalibration, target_co2_concentration, @@ -132,7 +131,7 @@ where } /// Get the status of automatic self-calibration - pub fn automatic_self_calibration(&mut self) -> Result> { + pub fn automatic_self_calibration(&mut self) -> Result> { let mut buf = [0; 3]; self.delayed_read_cmd(Command::GetAutomaticSelfCalibrationEnabled, &mut buf)?; let status = u16::from_be_bytes([buf[0], buf[1]]) != 0; @@ -140,19 +139,19 @@ where } /// Enable or disable automatic self-calibration - pub fn set_automatic_self_calibration(&mut self, enabled: bool) -> Result<(), Error> { + pub fn set_automatic_self_calibration(&mut self, enabled: bool) -> Result<(), Error> { self.write_command_with_data(Command::SetAutomaticSelfCalibrationEnabled, enabled as u16)?; Ok(()) } /// Start low power periodic measurements - pub fn start_low_power_periodic_measurements(&mut self) -> Result<(), Error> { + pub fn start_low_power_periodic_measurements(&mut self) -> Result<(), Error> { self.write_command(Command::StartLowPowerPeriodicMeasurement)?; Ok(()) } /// Check whether new measurement data is available for read-out. - pub fn data_ready_status(&mut self) -> Result> { + pub fn data_ready_status(&mut self) -> Result> { let mut buf = [0; 3]; self.delayed_read_cmd(Command::GetDataReadyStatus, &mut buf)?; let status = u16::from_be_bytes([buf[0], buf[1]]); @@ -163,14 +162,14 @@ where } /// Save settings to non-volatile memory - pub fn persist_settings(&mut self) -> Result<(), Error> { + pub fn persist_settings(&mut self) -> Result<(), Error> { self.write_command(Command::PersistSettings)?; Ok(()) } /// Get 48-bit serial number - pub fn serial_number(&mut self) -> Result> { - let mut buf = [0; 9]; + pub fn serial_number(&mut self) -> Result> { + let mut buf: [u8; 9] = [0; 9]; self.delayed_read_cmd(Command::GetSerialNumber, &mut buf)?; let serial = u64::from(buf[0]) << 40 | u64::from(buf[1]) << 32 @@ -183,7 +182,7 @@ where } /// End-of-line test to confirm sensor functionality. - pub fn self_test_is_ok(&mut self) -> Result> { + pub fn self_test_is_ok(&mut self) -> Result> { let mut buf = [0; 3]; self.delayed_read_cmd(Command::PerformSelfTest, &mut buf)?; @@ -192,13 +191,13 @@ where } /// Initiates the reset of all configurations stored in the EEPROM and erases the FRC and ASC algorithm history. - pub fn factory_reset(&mut self) -> Result<(), Error> { + pub fn factory_reset(&mut self) -> Result<(), Error> { self.write_command(Command::PerformFactoryReset)?; Ok(()) } /// The reinit command reinitializes the sensor by reloading user settings from EEPROM. - pub fn reinit(&mut self) -> Result<(), Error> { + pub fn reinit(&mut self) -> Result<(), Error> { self.write_command(Command::Reinit)?; Ok(()) } @@ -207,7 +206,7 @@ where /// The sensor output is read with the measurement method. /// Takes around 5 seconds to complete #[cfg(feature = "scd41")] - pub fn measure_single_shot(&mut self) -> Result<(), Error> { + pub fn measure_single_shot(&mut self) -> Result<(), Error> { self.write_command(Command::MeasureSingleShot)?; Ok(()) } @@ -216,21 +215,21 @@ where /// The sensor output is read with the measurement method. /// Completes immediately, but the measurement can only be read after 5 seconds. #[cfg(feature = "scd41")] - pub fn measure_single_shot_non_blocking(&mut self) -> Result<(), Error> { + pub fn measure_single_shot_non_blocking(&mut self) -> Result<(), Error> { self.write_command(Command::MeasureSingleShotNonBlocking)?; Ok(()) } /// On-demand measurement of relative humidity and temperature only. #[cfg(feature = "scd41")] - pub fn measure_single_shot_rht(&mut self) -> Result<(), Error> { + pub fn measure_single_shot_rht(&mut self) -> Result<(), Error> { self.write_command(Command::MeasureSingleShotRhtOnly)?; Ok(()) } /// Put the sensor from idle to sleep mode to reduce current consumption. #[cfg(feature = "scd41")] - pub fn power_down(&mut self) -> Result<(), Error> { + pub fn power_down(&mut self) -> Result<(), Error> { self.write_command(Command::PowerDown)?; Ok(()) } @@ -243,34 +242,34 @@ where } /// Command for reading values from the sensor - fn delayed_read_cmd(&mut self, cmd: Command, data: &mut [u8]) -> Result<(), Error> { + fn delayed_read_cmd(&mut self, cmd: Command, data: &mut [u8]) -> Result<(), Error> { self.write_command(cmd)?; - i2c::read_words_with_crc(&mut self.i2c, SCD4X_I2C_ADDRESS, data)?; + self.i2c.read(SCD4X_I2C_ADDRESS, data).map_err(Error::I2c)?; Ok(()) } /// Send command with parameter, takes response - fn delayed_read_cmd_with_data(&mut self, cmd: Command, data: u16) -> Result> { + fn delayed_read_cmd_with_data(&mut self, cmd: Command, data: u16) -> Result> { self.write_command_with_data(cmd, data)?; let mut buf = [0; 3]; - i2c::read_words_with_crc(&mut self.i2c, SCD4X_I2C_ADDRESS, &mut buf)?; - + self.i2c.read(SCD4X_I2C_ADDRESS, &mut buf).map_err(Error::I2c)?; Ok(u16::from_be_bytes([buf[0], buf[1]])) } /// Writes commands without additional arguments. - fn write_command(&mut self, cmd: Command) -> Result<(), Error> { + fn write_command(&mut self, cmd: Command) -> Result<(), Error> { let (command, delay, allowed_if_running) = cmd.as_tuple(); if !allowed_if_running && self.is_running { return Err(Error::NotAllowed); } - i2c::write_command(&mut self.i2c, SCD4X_I2C_ADDRESS, command).map_err(Error::I2c)?; + let cmd = command.to_be_bytes(); + self.i2c.write(SCD4X_I2C_ADDRESS, &cmd).map_err(Error::I2c)?; self.delay.delay_ms(delay); Ok(()) } /// Sets sensor internal parameter - fn write_command_with_data(&mut self, cmd: Command, data: u16) -> Result<(), Error> { + fn write_command_with_data(&mut self, cmd: Command, data: u16) -> Result<(), Error> { let (command, delay, allowed_if_running) = cmd.as_tuple(); if !allowed_if_running && self.is_running { return Err(Error::NotAllowed); @@ -283,9 +282,7 @@ where buf[2..4].copy_from_slice(&d); buf[4] = crc8::calculate(&d); - self.i2c - .write(SCD4X_I2C_ADDRESS, &buf) - .map_err(Error::I2c)?; + self.i2c.write(SCD4X_I2C_ADDRESS, &buf).map_err(Error::I2c)?; self.delay.delay_ms(delay); Ok(()) } @@ -293,10 +290,10 @@ where #[cfg(test)] mod tests { - use embedded_hal_mock as hal; + use embedded_hal_mock::eh1::i2c::Transaction; + use embedded_hal_mock::eh1::delay::NoopDelay as DelayMock; + use embedded_hal_mock::eh1::i2c::Mock as I2cMock; - use self::hal::delay::MockNoop as DelayMock; - use self::hal::i2c::{Mock as I2cMock, Transaction}; use super::*; /// Test the get_serial_number function @@ -317,6 +314,7 @@ mod tests { let serial = sensor.serial_number().unwrap(); // Assert assert_eq!(serial, 0xbeefbeefbeef); + sensor.i2c.done(); } /// Test the measurement function @@ -339,5 +337,6 @@ mod tests { assert_eq!(data.co2, 1000_u16); assert_eq!(data.temperature, 22.000198_f32); assert_eq!(data.humidity, 50_f32); + sensor.i2c.done(); } }