1#![cfg_attr(not(feature = "std"), no_std)]
2
3#[cfg(not(feature = "std"))]
4extern crate alloc;
5
6#[cfg(not(feature = "std"))]
7use alloc::{boxed::Box, format};
8use core::any::{Any, TypeId};
9use cu29::prelude::*;
10use embedded_hal as eh1;
11use embedded_io::{Read, Write};
12use spin::Mutex;
13
14type Entry = Box<dyn Any + Send>;
15
16struct TypedSlot {
17 type_id: TypeId,
18 entry: Entry,
19}
20
21macro_rules! define_registry {
22 ($name:ident) => {
23 struct $name {
24 entries: [Option<TypedSlot>; 8],
25 }
26
27 impl $name {
28 const fn new() -> Self {
29 Self {
30 entries: [None, None, None, None, None, None, None, None],
31 }
32 }
33 }
34 };
35}
36
37define_registry!(SerialSlots);
38define_registry!(SpiSlots);
39define_registry!(CsSlots);
40define_registry!(DelaySlots);
41
42static SERIAL_SLOTS: Mutex<SerialSlots> = Mutex::new(SerialSlots::new());
43static SPI_SLOTS: Mutex<SpiSlots> = Mutex::new(SpiSlots::new());
44static CS_SLOTS: Mutex<CsSlots> = Mutex::new(CsSlots::new());
45static DELAY_SLOTS: Mutex<DelaySlots> = Mutex::new(DelaySlots::new());
46
47pub const MAX_SERIAL_SLOTS: usize = 8;
48pub const MAX_SPI_SLOTS: usize = 8;
49pub const MAX_CS_SLOTS: usize = 8;
50pub const MAX_DELAY_SLOTS: usize = 8;
51
52fn register_inner<T>(
53 slots: &mut [Option<TypedSlot>],
54 max: usize,
55 slot: usize,
56 value: T,
57) -> CuResult<()>
58where
59 T: Any + Send + 'static,
60{
61 if slot >= max {
62 return Err(CuError::from(format!(
63 "Registry slot {slot} out of range (max {max})"
64 )));
65 }
66 slots[slot] = Some(TypedSlot {
67 type_id: TypeId::of::<T>(),
68 entry: Box::new(value),
69 });
70 Ok(())
71}
72
73fn take_inner<T>(slots: &mut [Option<TypedSlot>], max: usize, slot: usize) -> Option<T>
74where
75 T: Any + Send + 'static,
76{
77 if slot >= max {
78 return None;
79 }
80 let record = slots[slot].take()?;
81 if record.type_id != TypeId::of::<T>() {
82 slots[slot] = Some(record);
83 return None;
84 }
85 record.entry.downcast::<T>().map(|boxed| *boxed).ok()
86}
87
88fn status_inner(slots: &[Option<TypedSlot>], max: usize) -> [bool; 8] {
89 let mut status = [false; 8];
90 let slice = &slots[..max.min(8)];
91 for (i, slot) in slice.iter().enumerate() {
92 status[i] = slot.is_some();
93 }
94 status
95}
96
97pub fn register<S, E>(slot: usize, serial: S) -> CuResult<()>
101where
102 S: Write<Error = E> + Read<Error = E> + Send + 'static,
103{
104 let mut slots = SERIAL_SLOTS.lock();
105 register_inner(&mut slots.entries, MAX_SERIAL_SLOTS, slot, serial)
106}
107
108pub fn take<S, E>(slot: usize) -> Option<S>
113where
114 S: Write<Error = E> + Read<Error = E> + Send + 'static,
115{
116 let mut slots = SERIAL_SLOTS.lock();
117 take_inner(&mut slots.entries, MAX_SERIAL_SLOTS, slot)
118}
119
120pub fn slot_status() -> [bool; 8] {
122 let slots = SERIAL_SLOTS.lock();
123 status_inner(&slots.entries, MAX_SERIAL_SLOTS)
124}
125
126pub fn register_spi<S>(slot: usize, spi: S) -> CuResult<()>
128where
129 S: eh1::spi::SpiBus<u8> + Send + 'static,
130 S::Error: Send + 'static,
131{
132 let mut slots = SPI_SLOTS.lock();
133 register_inner(&mut slots.entries, MAX_SPI_SLOTS, slot, spi)
134}
135
136pub fn take_spi<S>(slot: usize) -> Option<S>
138where
139 S: eh1::spi::SpiBus<u8> + Send + 'static,
140 S::Error: Send + 'static,
141{
142 let mut slots = SPI_SLOTS.lock();
143 take_inner(&mut slots.entries, MAX_SPI_SLOTS, slot)
144}
145
146pub fn register_cs<P>(slot: usize, pin: P) -> CuResult<()>
148where
149 P: eh1::digital::OutputPin + Send + 'static,
150 P::Error: Send + 'static,
151{
152 let mut slots = CS_SLOTS.lock();
153 register_inner(&mut slots.entries, MAX_CS_SLOTS, slot, pin)
154}
155
156pub fn take_cs<P>(slot: usize) -> Option<P>
158where
159 P: eh1::digital::OutputPin + Send + 'static,
160 P::Error: Send + 'static,
161{
162 let mut slots = CS_SLOTS.lock();
163 take_inner(&mut slots.entries, MAX_CS_SLOTS, slot)
164}
165
166pub fn register_delay<D>(slot: usize, delay: D) -> CuResult<()>
168where
169 D: eh1::delay::DelayNs + Send + 'static,
170{
171 let mut slots = DELAY_SLOTS.lock();
172 register_inner(&mut slots.entries, MAX_DELAY_SLOTS, slot, delay)
173}
174
175pub fn take_delay<D>(slot: usize) -> Option<D>
177where
178 D: eh1::delay::DelayNs + Send + 'static,
179{
180 let mut slots = DELAY_SLOTS.lock();
181 take_inner(&mut slots.entries, MAX_DELAY_SLOTS, slot)
182}
183
184pub fn spi_slot_status() -> [bool; 8] {
186 let slots = SPI_SLOTS.lock();
187 status_inner(&slots.entries, MAX_SPI_SLOTS)
188}
189
190pub fn cs_slot_status() -> [bool; 8] {
192 let slots = CS_SLOTS.lock();
193 status_inner(&slots.entries, MAX_CS_SLOTS)
194}
195
196pub fn delay_slot_status() -> [bool; 8] {
198 let slots = DELAY_SLOTS.lock();
199 status_inner(&slots.entries, MAX_DELAY_SLOTS)
200}
201
202#[cfg(test)]
204pub fn clear_all() {
205 {
206 let mut slots = SERIAL_SLOTS.lock();
207 for slot in &mut slots.entries {
208 *slot = None;
209 }
210 }
211 {
212 let mut slots = SPI_SLOTS.lock();
213 for slot in &mut slots.entries {
214 *slot = None;
215 }
216 }
217 {
218 let mut slots = CS_SLOTS.lock();
219 for slot in &mut slots.entries {
220 *slot = None;
221 }
222 }
223 {
224 let mut slots = DELAY_SLOTS.lock();
225 for slot in &mut slots.entries {
226 *slot = None;
227 }
228 }
229}
230
231#[cfg(test)]
232mod tests {
233 use super::*;
234 use embedded_io::{ErrorKind, ErrorType};
235
236 #[derive(Debug, Clone, Copy)]
237 struct TestError;
238
239 impl embedded_io::Error for TestError {
240 fn kind(&self) -> ErrorKind {
241 ErrorKind::Other
242 }
243 }
244
245 struct MockSerial;
246
247 impl ErrorType for MockSerial {
248 type Error = TestError;
249 }
250
251 impl embedded_io::Write for MockSerial {
252 fn write(&mut self, _buf: &[u8]) -> Result<usize, Self::Error> {
253 Ok(0)
254 }
255
256 fn flush(&mut self) -> Result<(), Self::Error> {
257 Ok(())
258 }
259 }
260
261 impl embedded_io::Read for MockSerial {
262 fn read(&mut self, _buf: &mut [u8]) -> Result<usize, Self::Error> {
263 Ok(0)
264 }
265 }
266
267 #[derive(Debug, Clone, Copy)]
268 struct MockHalError;
269
270 impl eh1::spi::Error for MockHalError {
271 fn kind(&self) -> eh1::spi::ErrorKind {
272 eh1::spi::ErrorKind::Other
273 }
274 }
275
276 impl eh1::digital::Error for MockHalError {
277 fn kind(&self) -> eh1::digital::ErrorKind {
278 eh1::digital::ErrorKind::Other
279 }
280 }
281
282 struct MockSpi;
283
284 impl eh1::spi::ErrorType for MockSpi {
285 type Error = MockHalError;
286 }
287
288 impl eh1::spi::SpiBus<u8> for MockSpi {
289 fn read(&mut self, _words: &mut [u8]) -> Result<(), Self::Error> {
290 Ok(())
291 }
292
293 fn write(&mut self, _words: &[u8]) -> Result<(), Self::Error> {
294 Ok(())
295 }
296
297 fn transfer(&mut self, _read: &mut [u8], _write: &[u8]) -> Result<(), Self::Error> {
298 Ok(())
299 }
300
301 fn transfer_in_place(&mut self, _words: &mut [u8]) -> Result<(), Self::Error> {
302 Ok(())
303 }
304
305 fn flush(&mut self) -> Result<(), Self::Error> {
306 Ok(())
307 }
308 }
309
310 struct OtherSpi;
311
312 impl eh1::spi::ErrorType for OtherSpi {
313 type Error = MockHalError;
314 }
315
316 impl eh1::spi::SpiBus<u8> for OtherSpi {
317 fn read(&mut self, _words: &mut [u8]) -> Result<(), Self::Error> {
318 Ok(())
319 }
320
321 fn write(&mut self, _words: &[u8]) -> Result<(), Self::Error> {
322 Ok(())
323 }
324
325 fn transfer(&mut self, _read: &mut [u8], _write: &[u8]) -> Result<(), Self::Error> {
326 Ok(())
327 }
328
329 fn transfer_in_place(&mut self, _words: &mut [u8]) -> Result<(), Self::Error> {
330 Ok(())
331 }
332
333 fn flush(&mut self) -> Result<(), Self::Error> {
334 Ok(())
335 }
336 }
337
338 struct MockCs;
339
340 impl eh1::digital::ErrorType for MockCs {
341 type Error = MockHalError;
342 }
343
344 impl eh1::digital::OutputPin for MockCs {
345 fn set_low(&mut self) -> Result<(), Self::Error> {
346 Ok(())
347 }
348
349 fn set_high(&mut self) -> Result<(), Self::Error> {
350 Ok(())
351 }
352 }
353
354 struct OtherCs;
355
356 impl eh1::digital::ErrorType for OtherCs {
357 type Error = MockHalError;
358 }
359
360 impl eh1::digital::OutputPin for OtherCs {
361 fn set_low(&mut self) -> Result<(), Self::Error> {
362 Ok(())
363 }
364
365 fn set_high(&mut self) -> Result<(), Self::Error> {
366 Ok(())
367 }
368 }
369
370 struct MockDelay;
371
372 impl eh1::delay::DelayNs for MockDelay {
373 fn delay_ns(&mut self, _ns: u32) {}
374 }
375
376 struct OtherDelay;
377
378 impl eh1::delay::DelayNs for OtherDelay {
379 fn delay_ns(&mut self, _ns: u32) {}
380 }
381
382 #[test]
383 fn test_register_and_take_serial() {
384 clear_all();
385
386 let serial = MockSerial;
387 assert!(register(0, serial).is_ok());
388
389 let status = slot_status();
390 assert!(status[0]);
391 assert!(!status[1]);
392
393 let recovered: Option<MockSerial> = take(0);
394 assert!(recovered.is_some());
395
396 let status = slot_status();
397 assert!(!status[0]);
398 }
399
400 #[test]
401 fn test_register_and_take_spi() {
402 clear_all();
403 assert!(register_spi(0, MockSpi).is_ok());
404 assert!(spi_slot_status()[0]);
405 assert!(take_spi::<MockSpi>(0).is_some());
406 assert!(!spi_slot_status()[0]);
407
408 assert!(register_spi(1, MockSpi).is_ok());
410 assert!(take_spi::<OtherSpi>(1).is_none());
411 assert!(spi_slot_status()[1]);
412 }
413
414 #[test]
415 fn test_register_and_take_cs() {
416 clear_all();
417 assert!(register_cs(0, MockCs).is_ok());
418 assert!(cs_slot_status()[0]);
419 assert!(take_cs::<MockCs>(0).is_some());
420 assert!(!cs_slot_status()[0]);
421
422 assert!(register_cs(1, MockCs).is_ok());
423 assert!(take_cs::<OtherCs>(1).is_none());
424 assert!(cs_slot_status()[1]);
425 }
426
427 #[test]
428 fn test_register_and_take_delay() {
429 clear_all();
430 assert!(register_delay(0, MockDelay).is_ok());
431 assert!(delay_slot_status()[0]);
432 assert!(take_delay::<MockDelay>(0).is_some());
433 assert!(!delay_slot_status()[0]);
434
435 assert!(register_delay(1, MockDelay).is_ok());
436 assert!(take_delay::<OtherDelay>(1).is_none());
437 assert!(delay_slot_status()[1]);
438 }
439
440 #[test]
441 fn test_slot_bounds() {
442 clear_all();
443 let serial = MockSerial;
444 assert!(register(MAX_SERIAL_SLOTS, serial).is_err());
445
446 let recovered: Option<MockSerial> = take(MAX_SERIAL_SLOTS);
447 assert!(recovered.is_none());
448
449 assert!(register_spi(MAX_SPI_SLOTS, MockSpi).is_err());
450 assert!(take_spi::<MockSpi>(MAX_SPI_SLOTS).is_none());
451
452 assert!(register_cs(MAX_CS_SLOTS, MockCs).is_err());
453 assert!(take_cs::<MockCs>(MAX_CS_SLOTS).is_none());
454
455 assert!(register_delay(MAX_DELAY_SLOTS, MockDelay).is_err());
456 assert!(take_delay::<MockDelay>(MAX_DELAY_SLOTS).is_none());
457 }
458}