1#![no_std]
2use core::sync::atomic::{AtomicBool, Ordering};
50use embedded_hal::{
51 blocking::{self, i2c},
52 spi,
53};
54
55pub type SharedBus<T> = &'static CommonBus<T>;
57
58pub struct CommonBus<BUS> {
59 bus: core::cell::UnsafeCell<BUS>,
60 busy: AtomicBool,
61}
62
63impl<BUS> CommonBus<BUS> {
64 pub fn new(bus: BUS) -> Self {
65 CommonBus {
66 bus: core::cell::UnsafeCell::new(bus),
67 busy: AtomicBool::from(false),
68 }
69 }
70
71 fn lock<R, F: FnOnce(&mut BUS) -> R>(&self, f: F) -> R {
72 let compare =
73 atomic::compare_exchange(&self.busy, false, true, Ordering::SeqCst, Ordering::SeqCst)
74 .is_err();
75 if compare {
76 panic!("Bus conflict");
77 }
78
79 let result = f(unsafe { &mut *self.bus.get() });
80
81 self.busy.store(false, Ordering::SeqCst);
82
83 result
84 }
85
86 pub fn acquire(&self) -> &Self {
87 self
88 }
89}
90
91unsafe impl<BUS> Sync for CommonBus<BUS> {}
92
93impl<BUS: i2c::Read> i2c::Read for &CommonBus<BUS> {
94 type Error = BUS::Error;
95
96 fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Self::Error> {
97 self.lock(|bus| bus.read(address, buffer))
98 }
99}
100
101impl<BUS: i2c::Write> i2c::Write for &CommonBus<BUS> {
102 type Error = BUS::Error;
103
104 fn write(&mut self, address: u8, buffer: &[u8]) -> Result<(), Self::Error> {
105 self.lock(|bus| bus.write(address, buffer))
106 }
107}
108
109impl<BUS: i2c::WriteRead> i2c::WriteRead for &CommonBus<BUS> {
110 type Error = BUS::Error;
111
112 fn write_read(
113 &mut self,
114 address: u8,
115 bytes: &[u8],
116 buffer: &mut [u8],
117 ) -> Result<(), Self::Error> {
118 self.lock(|bus| bus.write_read(address, bytes, buffer))
119 }
120}
121
122macro_rules! spi {
123 ($($T:ty),*) => {
124 $(
125 impl<BUS: blocking::spi::Write<$T>> blocking::spi::Write<$T> for &CommonBus<BUS> {
126 type Error = BUS::Error;
127
128 fn write(&mut self, words: &[$T]) -> Result<(), Self::Error> {
129 self.lock(|bus| bus.write(words))
130 }
131 }
132
133 impl<BUS: blocking::spi::Transfer<$T>> blocking::spi::Transfer<$T> for &CommonBus<BUS> {
134 type Error = BUS::Error;
135
136 fn transfer<'w>(&mut self, words: &'w mut [$T]) -> Result<&'w [$T], Self::Error> {
137 self.lock(move |bus| bus.transfer(words))
138 }
139 }
140
141 impl<BUS: spi::FullDuplex<$T>> spi::FullDuplex<$T> for &CommonBus<BUS> {
142 type Error = BUS::Error;
143
144 fn read(&mut self) -> nb::Result<$T, Self::Error> {
145 self.lock(|bus| bus.read())
146 }
147
148 fn send(&mut self, word: $T) -> nb::Result<(), Self::Error> {
149 self.lock(|bus| bus.send(word))
150 }
151 }
152 )*
153 }
154}
155
156spi!(u8, u16, u32, u64);
157
158#[cfg(feature = "thumbv6")]
159mod atomic {
160 use core::sync::atomic::{AtomicBool, Ordering};
161
162 #[inline(always)]
163 pub fn compare_exchange(
164 atomic: &AtomicBool,
165 current: bool,
166 new: bool,
167 _success: Ordering,
168 _failure: Ordering,
169 ) -> Result<bool, bool> {
170 cortex_m::interrupt::free(|_cs| {
171 let prev = atomic.load(Ordering::Acquire);
172 if prev == current {
173 atomic.store(new, Ordering::Release);
174 Ok(prev)
175 } else {
176 Err(false)
177 }
178 })
179 }
180}
181
182#[cfg(not(feature = "thumbv6"))]
183mod atomic {
184 use core::sync::atomic::{AtomicBool, Ordering};
185
186 #[inline(always)]
187 pub fn compare_exchange(
188 atomic: &AtomicBool,
189 current: bool,
190 new: bool,
191 success: Ordering,
192 failure: Ordering,
193 ) -> Result<bool, bool> {
194 atomic.compare_exchange(current, new, success, failure)
195 }
196}
197
198#[macro_export]
212macro_rules! new {
213 ($bus:ident, $T:ty) => {
214 unsafe {
215 static mut _MANAGER: core::mem::MaybeUninit<shared_bus_rtic::CommonBus<$T>> =
216 core::mem::MaybeUninit::uninit();
217 _MANAGER = core::mem::MaybeUninit::new(shared_bus_rtic::CommonBus::new($bus));
218 &*_MANAGER.as_ptr()
219 };
220 };
221}