shared_bus/
proxies.rs

1#[cfg(feature = "eh-alpha")]
2use embedded_hal_alpha::i2c as i2c_alpha;
3
4use embedded_hal::adc;
5use embedded_hal::blocking::i2c;
6use embedded_hal::blocking::spi;
7
8/// Proxy type for I2C bus sharing.
9///
10/// The `I2cProxy` implements all (blocking) I2C traits so it can be passed to drivers instead of
11/// the bus instance.  Internally, it holds reference to the bus via a mutex, ensuring that all
12/// accesses are strictly synchronized.
13///
14/// An `I2cProxy` is created by calling [`BusManager::acquire_i2c()`][acquire_i2c].
15///
16/// [acquire_i2c]: ./struct.BusManager.html#method.acquire_i2c
17#[derive(Debug)]
18pub struct I2cProxy<'a, M> {
19    pub(crate) mutex: &'a M,
20}
21
22impl<'a, M: crate::BusMutex> Clone for I2cProxy<'a, M> {
23    fn clone(&self) -> Self {
24        Self { mutex: &self.mutex }
25    }
26}
27
28impl<'a, M: crate::BusMutex> i2c::Write for I2cProxy<'a, M>
29where
30    M::Bus: i2c::Write,
31{
32    type Error = <M::Bus as i2c::Write>::Error;
33
34    fn write(&mut self, addr: u8, buffer: &[u8]) -> Result<(), Self::Error> {
35        self.mutex.lock(|bus| bus.write(addr, buffer))
36    }
37}
38
39impl<'a, M: crate::BusMutex> i2c::Read for I2cProxy<'a, M>
40where
41    M::Bus: i2c::Read,
42{
43    type Error = <M::Bus as i2c::Read>::Error;
44
45    fn read(&mut self, addr: u8, buffer: &mut [u8]) -> Result<(), Self::Error> {
46        self.mutex.lock(|bus| bus.read(addr, buffer))
47    }
48}
49
50impl<'a, M: crate::BusMutex> i2c::WriteRead for I2cProxy<'a, M>
51where
52    M::Bus: i2c::WriteRead,
53{
54    type Error = <M::Bus as i2c::WriteRead>::Error;
55
56    fn write_read(
57        &mut self,
58        addr: u8,
59        buffer_in: &[u8],
60        buffer_out: &mut [u8],
61    ) -> Result<(), Self::Error> {
62        self.mutex
63            .lock(|bus| bus.write_read(addr, buffer_in, buffer_out))
64    }
65}
66
67impl<'a, M: crate::BusMutex> i2c::WriteIterRead for I2cProxy<'a, M>
68where
69    M::Bus: i2c::WriteIterRead,
70{
71    type Error = <M::Bus as i2c::WriteIterRead>::Error;
72
73    fn write_iter_read<B>(
74        &mut self,
75        address: u8,
76        bytes: B,
77        buffer: &mut [u8],
78    ) -> Result<(), Self::Error>
79    where
80        B: IntoIterator<Item = u8>,
81    {
82        self.mutex
83            .lock(|bus| bus.write_iter_read(address, bytes, buffer))
84    }
85}
86
87impl<'a, M: crate::BusMutex> i2c::WriteIter for I2cProxy<'a, M>
88where
89    M::Bus: i2c::WriteIter,
90{
91    type Error = <M::Bus as i2c::WriteIter>::Error;
92
93    fn write<B>(&mut self, address: u8, bytes: B) -> Result<(), Self::Error>
94    where
95        B: IntoIterator<Item = u8>,
96    {
97        self.mutex.lock(|bus| bus.write(address, bytes))
98    }
99}
100
101// Implementations for the embedded_hal alpha
102
103#[cfg(feature = "eh-alpha")]
104impl<'a, M: crate::BusMutex> i2c_alpha::ErrorType for I2cProxy<'a, M>
105where
106    M::Bus: i2c_alpha::ErrorType,
107{
108    type Error = <M::Bus as i2c_alpha::ErrorType>::Error;
109}
110
111#[cfg(feature = "eh-alpha")]
112impl<'a, M: crate::BusMutex> i2c_alpha::I2c for I2cProxy<'a, M>
113where
114    M::Bus: i2c_alpha::I2c,
115{
116    fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Self::Error> {
117        self.mutex.lock(|bus| bus.read(address, buffer))
118    }
119
120    fn write(&mut self, address: u8, bytes: &[u8]) -> Result<(), Self::Error> {
121        self.mutex.lock(|bus| bus.write(address, bytes))
122    }
123
124    fn write_iter<B>(&mut self, address: u8, bytes: B) -> Result<(), Self::Error>
125    where
126        B: IntoIterator<Item = u8>,
127    {
128        self.mutex.lock(|bus| bus.write_iter(address, bytes))
129    }
130
131    fn write_read(
132        &mut self,
133        address: u8,
134        bytes: &[u8],
135        buffer: &mut [u8],
136    ) -> Result<(), Self::Error> {
137        self.mutex
138            .lock(|bus| bus.write_read(address, bytes, buffer))
139    }
140
141    fn write_iter_read<B>(
142        &mut self,
143        address: u8,
144        bytes: B,
145        buffer: &mut [u8],
146    ) -> Result<(), Self::Error>
147    where
148        B: IntoIterator<Item = u8>,
149    {
150        self.mutex
151            .lock(|bus| bus.write_iter_read(address, bytes, buffer))
152    }
153
154    fn transaction<'b>(
155        &mut self,
156        address: u8,
157        operations: &mut [i2c_alpha::Operation<'b>],
158    ) -> Result<(), Self::Error> {
159        self.mutex.lock(|bus| bus.transaction(address, operations))
160    }
161
162    fn transaction_iter<'b, O>(&mut self, address: u8, operations: O) -> Result<(), Self::Error>
163    where
164        O: IntoIterator<Item = i2c_alpha::Operation<'b>>,
165    {
166        self.mutex
167            .lock(|bus| bus.transaction_iter(address, operations))
168    }
169}
170
171/// Proxy type for SPI bus sharing.
172///
173/// The `SpiProxy` implements all (blocking) SPI traits so it can be passed to drivers instead of
174/// the bus instance.  An `SpiProxy` is created by calling [`BusManager::acquire_spi()`][acquire_spi].
175///
176/// **Note**: The `SpiProxy` can only be used for sharing **withing a single task/thread**.  This
177/// is due to drivers usually managing the chip-select pin manually which would be inherently racy
178/// in a concurrent environment (because the mutex is locked only after asserting CS).  To ensure
179/// safe usage, a `SpiProxy` can only be created when using [`BusManagerSimple`] and is `!Send`.
180///
181/// [acquire_spi]: ./struct.BusManager.html#method.acquire_spi
182/// [`BusManagerSimple`]: ./type.BusManagerSimple.html
183#[derive(Debug)]
184pub struct SpiProxy<'a, M> {
185    pub(crate) mutex: &'a M,
186    pub(crate) _u: core::marker::PhantomData<*mut ()>,
187}
188
189impl<'a, M: crate::BusMutex> Clone for SpiProxy<'a, M> {
190    fn clone(&self) -> Self {
191        Self {
192            mutex: &self.mutex,
193            _u: core::marker::PhantomData,
194        }
195    }
196}
197
198impl<'a, M: crate::BusMutex> spi::Transfer<u8> for SpiProxy<'a, M>
199where
200    M::Bus: spi::Transfer<u8>,
201{
202    type Error = <M::Bus as spi::Transfer<u8>>::Error;
203
204    fn transfer<'w>(&mut self, words: &'w mut [u8]) -> Result<&'w [u8], Self::Error> {
205        self.mutex.lock(move |bus| bus.transfer(words))
206    }
207}
208
209impl<'a, M: crate::BusMutex> spi::Write<u8> for SpiProxy<'a, M>
210where
211    M::Bus: spi::Write<u8>,
212{
213    type Error = <M::Bus as spi::Write<u8>>::Error;
214
215    fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> {
216        self.mutex.lock(|bus| bus.write(words))
217    }
218}
219
220/// Proxy type for ADC sharing.
221///
222/// The `AdcProxy` implements OneShot trait so it can be passed to drivers instead of
223/// ADC instance. Internally, it holds reference to the bus via a mutex, ensuring
224/// that all accesses are strictly synchronized.
225///
226/// An `AdcProxy` is created by calling [`BusManager::acquire_adc()`][acquire_adc].
227///
228/// **Note**: The [`adc::OneShot`] trait proxied by this type describes a
229/// non-blocking contract for ADC read operation.  However access to a shared ADC
230/// unit can not be arbitrated in a completely non-blocking and concurrency safe way.
231/// Any reading from a channel shall be completed before `shared-bus` can allow the
232/// next read from the same or another channel. So the current implementation breaks
233/// the non-blocking contract of the trait and just busy-spins until a sample is
234/// returned.
235///
236/// [acquire_adc]: ./struct.BusManager.html#method.acquire_adc
237#[derive(Debug)]
238pub struct AdcProxy<'a, M> {
239    pub(crate) mutex: &'a M,
240}
241
242impl<'a, M: crate::BusMutex> Clone for AdcProxy<'a, M> {
243    fn clone(&self) -> Self {
244        Self { mutex: &self.mutex }
245    }
246}
247
248impl<'a, M: crate::BusMutex, ADC, Word, Pin> adc::OneShot<ADC, Word, Pin> for AdcProxy<'a, M>
249where
250    Pin: adc::Channel<ADC>,
251    M::Bus: adc::OneShot<ADC, Word, Pin>,
252{
253    type Error = <M::Bus as adc::OneShot<ADC, Word, Pin>>::Error;
254
255    fn read(&mut self, pin: &mut Pin) -> nb::Result<Word, Self::Error> {
256        self.mutex
257            .lock(|bus| nb::block!(bus.read(pin)).map_err(nb::Error::Other))
258    }
259}