Skip to content

Commit

Permalink
Update to embedded-hal 1.0.0-alpha.8 and add optional support for emb…
Browse files Browse the repository at this point in the history
…edded-hal-async (#23)

* Add optional support for embedded-hal-async

* Run cargo fmt
  • Loading branch information
quentinmit authored Jan 16, 2023
1 parent efd5a52 commit 051071f
Show file tree
Hide file tree
Showing 4 changed files with 429 additions and 124 deletions.
9 changes: 7 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,12 @@ edition = "2018"
name = "bme280"

[dependencies]
embedded-hal = "=1.0.0-alpha.7"
embedded-hal = "=1.0.0-alpha.8"
serde = { version = "1.0", optional = true, features = ["derive"] }
defmt = { version = "0.3.2", optional = true }
derive_more = { version = "0.99.17", optional = true}
embedded-hal-async = { version = "0.1.0-alpha.1", optional = true }
maybe-async-cfg = "0.2.3"

[dev-dependencies]
cortex-m-rtic = "1.0.0"
Expand All @@ -26,12 +28,15 @@ defmt-rtt = "0.3.0"
panic-semihosting = "0.6"

[dev-dependencies.stm32f4xx-hal]
version = "0.12.0"
version = "0.13.2"
features = ["stm32f411"]

[features]
default = ["sync"]
with_defmt = ["defmt"]
with_std = ["derive_more"]
sync = []
async = ["embedded-hal-async"]

[[example]]
name = "rtic"
162 changes: 139 additions & 23 deletions src/i2c.rs
Original file line number Diff line number Diff line change
@@ -1,25 +1,58 @@
//! BME280 driver for sensors attached via I2C.
#[cfg(feature = "async")]
use core::future::Future;
#[cfg(feature = "sync")]
use embedded_hal::delay::blocking::DelayUs;
use embedded_hal::i2c::{blocking::I2c, ErrorType};

#[cfg(feature = "sync")]
use embedded_hal::i2c::blocking::I2c;
use embedded_hal::i2c::ErrorType;
#[cfg(feature = "async")]
use embedded_hal_async::delay::DelayUs as AsyncDelayUs;
#[cfg(feature = "async")]
use embedded_hal_async::i2c::I2c as AsyncI2c;

#[cfg(feature = "async")]
use super::{AsyncBME280Common, AsyncInterface};
#[cfg(feature = "sync")]
use super::{BME280Common, Interface};
use super::{
BME280Common, Configuration, Error, IIRFilter, Interface, Measurements, Oversampling,
BME280_H_CALIB_DATA_LEN, BME280_P_T_CALIB_DATA_LEN, BME280_P_T_H_DATA_LEN,
Configuration, Error, IIRFilter, Measurements, Oversampling, BME280_H_CALIB_DATA_LEN,
BME280_P_T_CALIB_DATA_LEN, BME280_P_T_H_DATA_LEN,
};

const BME280_I2C_ADDR_PRIMARY: u8 = 0x76;
const BME280_I2C_ADDR_SECONDARY: u8 = 0x77;

/// Representation of a BME280
#[maybe_async_cfg::maybe(
sync(
feature = "sync",
self = "BME280",
idents(AsyncBME280Common(sync = "BME280Common"))
),
async(feature = "async", keep_self)
)]
#[derive(Debug, Default)]
pub struct BME280<I2C> {
common: BME280Common<I2CInterface<I2C>>,
pub struct AsyncBME280<I2C> {
common: AsyncBME280Common<I2CInterface<I2C>>,
}

impl<I2C> BME280<I2C>
#[maybe_async_cfg::maybe(
sync(
feature = "sync",
self = "BME280",
idents(
AsyncI2c(sync = "I2c"),
AsyncDelayUs(sync = "DelayUs"),
AsyncBME280Common(sync = "BME280Common"),
)
),
async(feature = "async", keep_self)
)]
impl<I2C> AsyncBME280<I2C>
where
I2C: I2c + ErrorType,
I2C: AsyncI2c + ErrorType,
{
/// Create a new BME280 struct using the primary I²C address `0x76`
pub fn new_primary(i2c: I2C) -> Self {
Expand All @@ -33,8 +66,8 @@ where

/// Create a new BME280 struct using a custom I²C address
pub fn new(i2c: I2C, address: u8) -> Self {
BME280 {
common: BME280Common {
Self {
common: AsyncBME280Common {
interface: I2CInterface { i2c, address },
calibration: None,
},
Expand All @@ -44,32 +77,34 @@ where
/// Initializes the BME280.
/// This configures 2x temperature oversampling, 16x pressure oversampling, and the IIR filter
/// coefficient 16.
pub fn init<D: DelayUs>(&mut self, delay: &mut D) -> Result<(), Error<I2C::Error>> {
self.common.init(
delay,
Configuration::default()
.with_humidity_oversampling(Oversampling::Oversampling1X)
.with_pressure_oversampling(Oversampling::Oversampling16X)
.with_temperature_oversampling(Oversampling::Oversampling2X)
.with_iir_filter(IIRFilter::Coefficient16),
)
pub async fn init<D: AsyncDelayUs>(&mut self, delay: &mut D) -> Result<(), Error<I2C::Error>> {
self.common
.init(
delay,
Configuration::default()
.with_humidity_oversampling(Oversampling::Oversampling1X)
.with_pressure_oversampling(Oversampling::Oversampling16X)
.with_temperature_oversampling(Oversampling::Oversampling2X)
.with_iir_filter(IIRFilter::Coefficient16),
)
.await
}

/// Initializes the BME280, applying the given configuration.
pub fn init_with_config<D: DelayUs>(
pub async fn init_with_config<D: AsyncDelayUs>(
&mut self,
delay: &mut D,
config: Configuration,
) -> Result<(), Error<I2C::Error>> {
self.common.init(delay, config)
self.common.init(delay, config).await
}

/// Captures and processes sensor data for temperature, pressure, and humidity
pub fn measure<D: DelayUs>(
pub async fn measure<D: AsyncDelayUs>(
&mut self,
delay: &mut D,
) -> Result<Measurements<I2C::Error>, Error<I2C::Error>> {
self.common.measure(delay)
self.common.measure(delay).await
}
}

Expand All @@ -82,6 +117,7 @@ struct I2CInterface<I2C> {
address: u8,
}

#[cfg(feature = "sync")]
impl<I2C> Interface for I2CInterface<I2C>
where
I2C: I2c + ErrorType,
Expand Down Expand Up @@ -135,3 +171,83 @@ where
.map_err(Error::Bus)
}
}

#[cfg(feature = "async")]
impl<I2C> AsyncInterface for I2CInterface<I2C>
where
I2C: AsyncI2c + ErrorType,
{
type Error = I2C::Error;

type ReadRegisterFuture<'a> = impl Future<Output = Result<u8, Error<Self::Error>>>
where
I2C: 'a;
fn read_register<'a>(&'a mut self, register: u8) -> Self::ReadRegisterFuture<'a> {
async move {
let mut data: [u8; 1] = [0];
self.i2c
.write_read(self.address, &[register], &mut data)
.await
.map_err(Error::Bus)?;
Ok(data[0])
}
}

type ReadDataFuture<'a> = impl Future<Output = Result<[u8; BME280_P_T_H_DATA_LEN], Error<Self::Error>>>
where
I2C: 'a;
fn read_data<'a>(&'a mut self, register: u8) -> Self::ReadDataFuture<'a> {
async move {
let mut data = [0; BME280_P_T_H_DATA_LEN];
self.i2c
.write_read(self.address, &[register], &mut data)
.await
.map_err(Error::Bus)?;
Ok(data)
}
}

type ReadPtCalibDataFuture<'a> = impl Future<Output = Result<[u8; BME280_P_T_CALIB_DATA_LEN], Error<Self::Error>>>
where
I2C: 'a;
fn read_pt_calib_data<'a>(&'a mut self, register: u8) -> Self::ReadPtCalibDataFuture<'a> {
async move {
let mut data = [0; BME280_P_T_CALIB_DATA_LEN];
self.i2c
.write_read(self.address, &[register], &mut data)
.await
.map_err(Error::Bus)?;
Ok(data)
}
}

type ReadHCalibDataFuture<'a> = impl Future<Output = Result<[u8; BME280_H_CALIB_DATA_LEN], Error<Self::Error>>>
where
I2C: 'a;
fn read_h_calib_data<'a>(&'a mut self, register: u8) -> Self::ReadHCalibDataFuture<'a> {
async move {
let mut data = [0; BME280_H_CALIB_DATA_LEN];
self.i2c
.write_read(self.address, &[register], &mut data)
.await
.map_err(Error::Bus)?;
Ok(data)
}
}

type WriteRegisterFuture<'a> = impl Future<Output = Result<(), Error<Self::Error>>>
where
I2C: 'a;
fn write_register<'a>(
&'a mut self,
register: u8,
payload: u8,
) -> Self::WriteRegisterFuture<'a> {
async move {
self.i2c
.write(self.address, &[register, payload])
.await
.map_err(Error::Bus)
}
}
}
Loading

0 comments on commit 051071f

Please sign in to comment.