shared_bus/
macros.rs

1/// Macro for creating a `std`-based bus manager with `'static` lifetime.
2///
3/// This macro is a convenience helper for creating a bus manager that lives for the `'static`
4/// lifetime an thus can be safely shared across threads.
5///
6/// This macro is only available with the `std` feature.
7///
8/// # Syntax
9/// ```ignore
10/// let bus = shared_bus::new_std!(<Full Bus Type Signature> = <bus>).unwrap();
11/// ```
12///
13/// The macro returns an Option which will be `Some(&'static bus_manager)` on the first run and
14/// `None` afterwards.  This is necessary to uphold safety around the inner `static` variable.
15///
16/// # Example
17/// ```
18/// # struct MyDevice<T>(T);
19/// # impl<T> MyDevice<T> {
20/// #     pub fn new(t: T) -> Self { MyDevice(t) }
21/// #     pub fn do_something_on_the_bus(&mut self) { }
22/// # }
23/// #
24/// # struct SomeI2cBus;
25/// # let i2c = SomeI2cBus;
26/// // For example:
27/// // let i2c = I2c::i2c1(dp.I2C1, (scl, sda), 90.khz(), clocks, &mut rcc.apb1);
28///
29/// // The bus is a 'static reference -> it lives forever and references can be
30/// // shared with other threads.
31/// let bus: &'static _ = shared_bus::new_std!(SomeI2cBus = i2c).unwrap();
32///
33/// let mut proxy1 = bus.acquire_i2c();
34/// let mut my_device = MyDevice::new(bus.acquire_i2c());
35///
36/// // We can easily move a proxy to another thread:
37/// # let t =
38/// std::thread::spawn(move || {
39///     my_device.do_something_on_the_bus();
40/// });
41/// # t.join().unwrap();
42/// ```
43#[cfg(feature = "std")]
44#[macro_export]
45macro_rules! new_std {
46    ($bus_type:ty = $bus:expr) => {{
47        use $crate::once_cell::sync::OnceCell;
48
49        static MANAGER: OnceCell<$crate::BusManagerStd<$bus_type>> = OnceCell::new();
50
51        let m = $crate::BusManagerStd::new($bus);
52        match MANAGER.set(m) {
53            Ok(_) => MANAGER.get(),
54            Err(_) => None,
55        }
56    }};
57}
58
59/// Macro for creating a Cortex-M bus manager with `'static` lifetime.
60///
61/// This macro is a convenience helper for creating a bus manager that lives for the `'static`
62/// lifetime an thus can be safely shared across tasks/execution contexts (like interrupts).
63///
64/// This macro is only available with the `cortex-m` feature.
65///
66/// # Syntax
67/// ```ignore
68/// let bus = shared_bus::new_cortexm!(<Full Bus Type Signature> = <bus>).unwrap();
69/// ```
70///
71/// The macro returns an Option which will be `Some(&'static bus_manager)` on the first run and
72/// `None` afterwards.  This is necessary to uphold safety around the inner `static` variable.
73///
74/// # Example
75/// ```no_run
76/// # use embedded_hal::blocking::i2c::Write;
77/// # struct MyDevice<T>(T);
78/// # impl<T> MyDevice<T> {
79/// #     pub fn new(t: T) -> Self { MyDevice(t) }
80/// #     pub fn do_something_on_the_bus(&mut self) { }
81/// # }
82/// #
83/// # struct SomeI2cBus;
84/// # impl Write for SomeI2cBus {
85/// #     type Error = ();
86/// #     fn write(&mut self, addr: u8, buffer: &[u8]) -> Result<(), Self::Error> { Ok(()) }
87/// # }
88/// static mut SHARED_DEVICE:
89///     Option<MyDevice<shared_bus::I2cProxy<shared_bus::CortexMMutex<SomeI2cBus>>>>
90///     = None;
91///
92/// fn main() -> ! {
93/// #   let i2c = SomeI2cBus;
94///     // For example:
95///     // let i2c = I2c::i2c1(dp.I2C1, (scl, sda), 90.khz(), clocks, &mut rcc.apb1);
96///
97///     // The bus is a 'static reference -> it lives forever and references can be
98///     // shared with other tasks.
99///     let bus: &'static _ = shared_bus::new_cortexm!(SomeI2cBus = i2c).unwrap();
100///
101///     let mut proxy1 = bus.acquire_i2c();
102///     let my_device = MyDevice::new(bus.acquire_i2c());
103///
104///     unsafe {
105///         SHARED_DEVICE = Some(my_device);
106///     }
107///
108///     cortex_m::asm::dmb();
109///
110///     // enable the interrupt
111///
112///     loop {
113///         proxy1.write(0x39, &[0xaa]);
114///     }
115/// }
116///
117/// fn INTERRUPT() {
118///     let dev = unsafe {SHARED_DEVICE.as_mut().unwrap()};
119///
120///     dev.do_something_on_the_bus();
121/// }
122/// ```
123#[cfg(feature = "cortex-m")]
124#[macro_export]
125macro_rules! new_cortexm {
126    ($bus_type:ty = $bus:expr) => {{
127        let m: Option<&'static mut _> = $crate::cortex_m::singleton!(
128            : $crate::BusManagerCortexM<$bus_type> =
129                $crate::BusManagerCortexM::new($bus)
130        );
131
132        m
133    }};
134}
135
136/// Macro for creating a Xtensa-lx6 bus manager with `'static` lifetime.
137///
138/// This macro is a convenience helper for creating a bus manager that lives for the `'static`
139/// lifetime an thus can be safely shared across tasks/execution contexts (like interrupts).
140///
141/// This macro is only available with the `xtensa` feature.
142///
143/// # Syntax
144/// ```ignore
145/// let bus = shared_bus::new_xtensa!(<Full Bus Type Signature> = <bus>).unwrap();
146/// ```
147///
148/// The macro returns an Option which will be `Some(&'static bus_manager)` on the first run and
149/// `None` afterwards.  This is necessary to uphold safety around the inner `static` variable.
150#[cfg(feature = "xtensa")]
151#[macro_export]
152macro_rules! new_xtensa {
153    ($bus_type:ty = $bus:expr) => {{
154        let m: Option<&'static mut _> = $crate::xtensa_lx::singleton!(
155            : $crate::BusManagerXtensa<$bus_type> =
156                $crate::BusManagerXtensa::new($bus)
157        );
158
159        m
160    }};
161}
162
163/// Construct a statically allocated bus manager.
164#[cfg(feature = "cortex-m")]
165#[macro_export]
166macro_rules! new_atomic_check {
167    ($bus_type:ty = $bus:expr) => {{
168        let m: Option<&'static mut _> = $crate::cortex_m::singleton!(
169            : $crate::BusManagerAtomicCheck<$bus_type> =
170                $crate::BusManagerAtomicCheck::new($bus)
171        );
172
173        m
174    }};
175}