aboutsummaryrefslogtreecommitdiff
path: root/rtic-sync/src/arbiter/i2c.rs
blob: 40cefce2ca52441d0c9d9125357d31fd1d9fc305 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
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<ArbiterDevice<'static, I2c<'static, I2C1>>>,
//!     }
//!
//!     #[init(local = [
//!         i2c_arbiter: MaybeUninit<Arbiter<I2c<'static, I2C1>>> = 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<I2c<'static, I2C1>>) {
//!         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<BUS>,
}

impl<'a, BUS> ArbiterDevice<'a, BUS> {
    /// Create a new [`ArbiterDevice`] for I2C.
    pub fn new(bus: &'a Arbiter<BUS>) -> Self {
        Self { bus }
    }
}

impl<BUS> ErrorType for ArbiterDevice<'_, BUS>
where
    BUS: ErrorType,
{
    type Error = BUS::Error;
}

impl<BUS, A> AsyncI2c<A> for ArbiterDevice<'_, BUS>
where
    BUS: AsyncI2c<A>,
    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<BUS>,
}

impl<'a, BUS> BlockingArbiterDevice<'a, BUS> {
    /// Create a new [`BlockingArbiterDevice`] for I2C.
    pub fn new(bus: &'a Arbiter<BUS>) -> 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<A> for BlockingArbiterDevice<'a, BUS>
where
    BUS: BlockingI2c<A>,
    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)
    }
}