rtic_sync/arbiter/
i2c.rs

1//! I2C bus sharing using [`Arbiter`]
2//!
3//! An Example how to use it in RTIC application:
4//! ```text
5//! #[app(device = some_hal, peripherals = true, dispatchers = [TIM16])]
6//! mod app {
7//!     use core::mem::MaybeUninit;
8//!     use rtic_sync::{arbiter::{i2c::ArbiterDevice, Arbiter},
9//!
10//!     #[shared]
11//!     struct Shared {}
12//!
13//!     #[local]
14//!     struct Local {
15//!         ens160: Ens160<ArbiterDevice<'static, I2c<'static, I2C1>>>,
16//!     }
17//!
18//!     #[init(local = [
19//!         i2c_arbiter: MaybeUninit<Arbiter<I2c<'static, I2C1>>> = MaybeUninit::uninit(),
20//!     ])]
21//!     fn init(cx: init::Context) -> (Shared, Local) {
22//!         let i2c = I2c::new(cx.device.I2C1);
23//!         let i2c_arbiter = cx.local.i2c_arbiter.write(Arbiter::new(i2c));
24//!         let ens160 = Ens160::new(ArbiterDevice::new(i2c_arbiter), 0x52);
25//!
26//!         i2c_sensors::spawn(i2c_arbiter).ok();
27//!
28//!         (Shared {}, Local { ens160 })
29//!     }
30//!
31//!     #[task(local = [ens160])]
32//!     async fn i2c_sensors(cx: i2c_sensors::Context, i2c: &'static Arbiter<I2c<'static, I2C1>>) {
33//!         use sensor::Asensor;
34//!
35//!         loop {
36//!             // Use scope to make sure I2C access is dropped.
37//!             {
38//!                 // Read from sensor driver that wants to use I2C directly.
39//!                 let mut i2c = i2c.access().await;
40//!                 let status = Asensor::status(&mut i2c).await;
41//!             }
42//!
43//!             // Read ENS160 sensor.
44//!             let eco2 = cx.local.ens160.eco2().await;
45//!         }
46//!     }
47//! }
48//! ```
49
50use super::Arbiter;
51use embedded_hal::i2c::{AddressMode, ErrorType, I2c as BlockingI2c, Operation};
52use embedded_hal_async::i2c::I2c as AsyncI2c;
53
54/// [`Arbiter`]-based shared bus implementation for I2C.
55pub struct ArbiterDevice<'a, BUS> {
56    bus: &'a Arbiter<BUS>,
57}
58
59impl<'a, BUS> ArbiterDevice<'a, BUS> {
60    /// Create a new [`ArbiterDevice`] for I2C.
61    pub fn new(bus: &'a Arbiter<BUS>) -> Self {
62        Self { bus }
63    }
64}
65
66impl<BUS> ErrorType for ArbiterDevice<'_, BUS>
67where
68    BUS: ErrorType,
69{
70    type Error = BUS::Error;
71}
72
73impl<BUS, A> AsyncI2c<A> for ArbiterDevice<'_, BUS>
74where
75    BUS: AsyncI2c<A>,
76    A: AddressMode,
77{
78    async fn read(&mut self, address: A, read: &mut [u8]) -> Result<(), Self::Error> {
79        let mut bus = self.bus.access().await;
80        bus.read(address, read).await
81    }
82
83    async fn write(&mut self, address: A, write: &[u8]) -> Result<(), Self::Error> {
84        let mut bus = self.bus.access().await;
85        bus.write(address, write).await
86    }
87
88    async fn write_read(
89        &mut self,
90        address: A,
91        write: &[u8],
92        read: &mut [u8],
93    ) -> Result<(), Self::Error> {
94        let mut bus = self.bus.access().await;
95        bus.write_read(address, write, read).await
96    }
97
98    async fn transaction(
99        &mut self,
100        address: A,
101        operations: &mut [Operation<'_>],
102    ) -> Result<(), Self::Error> {
103        let mut bus = self.bus.access().await;
104        bus.transaction(address, operations).await
105    }
106}
107
108/// [`Arbiter`]-based shared bus implementation for I2C.
109pub struct BlockingArbiterDevice<'a, BUS> {
110    bus: &'a Arbiter<BUS>,
111}
112
113impl<'a, BUS> BlockingArbiterDevice<'a, BUS> {
114    /// Create a new [`BlockingArbiterDevice`] for I2C.
115    pub fn new(bus: &'a Arbiter<BUS>) -> Self {
116        Self { bus }
117    }
118
119    /// Create an `ArbiterDevice` from an `BlockingArbiterDevice`.
120    pub fn into_non_blocking(self) -> ArbiterDevice<'a, BUS>
121    where
122        BUS: AsyncI2c,
123    {
124        ArbiterDevice { bus: self.bus }
125    }
126}
127
128impl<'a, BUS> ErrorType for BlockingArbiterDevice<'a, BUS>
129where
130    BUS: ErrorType,
131{
132    type Error = BUS::Error;
133}
134
135impl<'a, BUS, A> AsyncI2c<A> for BlockingArbiterDevice<'a, BUS>
136where
137    BUS: BlockingI2c<A>,
138    A: AddressMode,
139{
140    async fn read(&mut self, address: A, read: &mut [u8]) -> Result<(), Self::Error> {
141        let mut bus = self.bus.access().await;
142        bus.read(address, read)
143    }
144
145    async fn write(&mut self, address: A, write: &[u8]) -> Result<(), Self::Error> {
146        let mut bus = self.bus.access().await;
147        bus.write(address, write)
148    }
149
150    async fn write_read(
151        &mut self,
152        address: A,
153        write: &[u8],
154        read: &mut [u8],
155    ) -> Result<(), Self::Error> {
156        let mut bus = self.bus.access().await;
157        bus.write_read(address, write, read)
158    }
159
160    async fn transaction(
161        &mut self,
162        address: A,
163        operations: &mut [Operation<'_>],
164    ) -> Result<(), Self::Error> {
165        let mut bus = self.bus.access().await;
166        bus.transaction(address, operations)
167    }
168}