From 38c364473c83f7a6214046d157ea5fe92e758732 Mon Sep 17 00:00:00 2001 From: Emil Fresk Date: Sun, 23 Jun 2024 10:33:02 +0200 Subject: Add blocking version of `rtic_sync::arbiter::{i2c,spi}::ArbiterDevice` --- rtic-sync/src/arbiter/i2c.rs | 168 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 168 insertions(+) create mode 100644 rtic-sync/src/arbiter/i2c.rs (limited to 'rtic-sync/src/arbiter/i2c.rs') diff --git a/rtic-sync/src/arbiter/i2c.rs b/rtic-sync/src/arbiter/i2c.rs new file mode 100644 index 0000000..40cefce --- /dev/null +++ b/rtic-sync/src/arbiter/i2c.rs @@ -0,0 +1,168 @@ +//! I2C bus sharing using [`Arbiter`] +//! +//! An Example how to use it in RTIC application: +//! ```text +//! #[app(device = some_hal, peripherals = true, dispatchers = [TIM16])] +//! mod app { +//! use core::mem::MaybeUninit; +//! use rtic_sync::{arbiter::{i2c::ArbiterDevice, Arbiter}, +//! +//! #[shared] +//! struct Shared {} +//! +//! #[local] +//! struct Local { +//! ens160: Ens160>>, +//! } +//! +//! #[init(local = [ +//! i2c_arbiter: MaybeUninit>> = MaybeUninit::uninit(), +//! ])] +//! fn init(cx: init::Context) -> (Shared, Local) { +//! let i2c = I2c::new(cx.device.I2C1); +//! let i2c_arbiter = cx.local.i2c_arbiter.write(Arbiter::new(i2c)); +//! let ens160 = Ens160::new(ArbiterDevice::new(i2c_arbiter), 0x52); +//! +//! i2c_sensors::spawn(i2c_arbiter).ok(); +//! +//! (Shared {}, Local { ens160 }) +//! } +//! +//! #[task(local = [ens160])] +//! async fn i2c_sensors(cx: i2c_sensors::Context, i2c: &'static Arbiter>) { +//! use sensor::Asensor; +//! +//! loop { +//! // Use scope to make sure I2C access is dropped. +//! { +//! // Read from sensor driver that wants to use I2C directly. +//! let mut i2c = i2c.access().await; +//! let status = Asensor::status(&mut i2c).await; +//! } +//! +//! // Read ENS160 sensor. +//! let eco2 = cx.local.ens160.eco2().await; +//! } +//! } +//! } +//! ``` + +use super::Arbiter; +use embedded_hal::i2c::{AddressMode, ErrorType, I2c as BlockingI2c, Operation}; +use embedded_hal_async::i2c::I2c as AsyncI2c; + +/// [`Arbiter`]-based shared bus implementation for I2C. +pub struct ArbiterDevice<'a, BUS> { + bus: &'a Arbiter, +} + +impl<'a, BUS> ArbiterDevice<'a, BUS> { + /// Create a new [`ArbiterDevice`] for I2C. + pub fn new(bus: &'a Arbiter) -> Self { + Self { bus } + } +} + +impl ErrorType for ArbiterDevice<'_, BUS> +where + BUS: ErrorType, +{ + type Error = BUS::Error; +} + +impl AsyncI2c for ArbiterDevice<'_, BUS> +where + BUS: AsyncI2c, + A: AddressMode, +{ + async fn read(&mut self, address: A, read: &mut [u8]) -> Result<(), Self::Error> { + let mut bus = self.bus.access().await; + bus.read(address, read).await + } + + async fn write(&mut self, address: A, write: &[u8]) -> Result<(), Self::Error> { + let mut bus = self.bus.access().await; + bus.write(address, write).await + } + + async fn write_read( + &mut self, + address: A, + write: &[u8], + read: &mut [u8], + ) -> Result<(), Self::Error> { + let mut bus = self.bus.access().await; + bus.write_read(address, write, read).await + } + + async fn transaction( + &mut self, + address: A, + operations: &mut [Operation<'_>], + ) -> Result<(), Self::Error> { + let mut bus = self.bus.access().await; + bus.transaction(address, operations).await + } +} + +/// [`Arbiter`]-based shared bus implementation for I2C. +pub struct BlockingArbiterDevice<'a, BUS> { + bus: &'a Arbiter, +} + +impl<'a, BUS> BlockingArbiterDevice<'a, BUS> { + /// Create a new [`BlockingArbiterDevice`] for I2C. + pub fn new(bus: &'a Arbiter) -> Self { + Self { bus } + } + + /// Create an `ArbiterDevice` from an `BlockingArbiterDevice`. + pub fn into_non_blocking(self) -> ArbiterDevice<'a, BUS> + where + BUS: AsyncI2c, + { + ArbiterDevice { bus: self.bus } + } +} + +impl<'a, BUS> ErrorType for BlockingArbiterDevice<'a, BUS> +where + BUS: ErrorType, +{ + type Error = BUS::Error; +} + +impl<'a, BUS, A> AsyncI2c for BlockingArbiterDevice<'a, BUS> +where + BUS: BlockingI2c, + A: AddressMode, +{ + async fn read(&mut self, address: A, read: &mut [u8]) -> Result<(), Self::Error> { + let mut bus = self.bus.access().await; + bus.read(address, read) + } + + async fn write(&mut self, address: A, write: &[u8]) -> Result<(), Self::Error> { + let mut bus = self.bus.access().await; + bus.write(address, write) + } + + async fn write_read( + &mut self, + address: A, + write: &[u8], + read: &mut [u8], + ) -> Result<(), Self::Error> { + let mut bus = self.bus.access().await; + bus.write_read(address, write, read) + } + + async fn transaction( + &mut self, + address: A, + operations: &mut [Operation<'_>], + ) -> Result<(), Self::Error> { + let mut bus = self.bus.access().await; + bus.transaction(address, operations) + } +} -- cgit v1.2.3