aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--embassy-nrf/src/util/peripheral.rs72
1 files changed, 57 insertions, 15 deletions
diff --git a/embassy-nrf/src/util/peripheral.rs b/embassy-nrf/src/util/peripheral.rs
index bf78d7760..b23699d24 100644
--- a/embassy-nrf/src/util/peripheral.rs
+++ b/embassy-nrf/src/util/peripheral.rs
@@ -1,9 +1,11 @@
1use core::array::IntoIter;
1use core::cell::UnsafeCell; 2use core::cell::UnsafeCell;
2use core::marker::{PhantomData, PhantomPinned}; 3use core::marker::{PhantomData, PhantomPinned};
4use core::mem::MaybeUninit;
3use core::pin::Pin; 5use core::pin::Pin;
4use core::sync::atomic::{compiler_fence, Ordering}; 6use core::sync::atomic::{compiler_fence, Ordering};
5 7
6use crate::fmt::*; 8use crate::fmt::{assert, *};
7use crate::interrupt::Interrupt; 9use crate::interrupt::Interrupt;
8 10
9pub trait PeripheralState { 11pub trait PeripheralState {
@@ -11,8 +13,19 @@ pub trait PeripheralState {
11 fn on_interrupt(&mut self); 13 fn on_interrupt(&mut self);
12} 14}
13 15
16#[derive(Clone, Copy, PartialEq, Eq, Debug)]
17enum Life {
18 Ready,
19 Created,
20 Freed,
21}
22
14pub struct PeripheralMutex<S: PeripheralState> { 23pub struct PeripheralMutex<S: PeripheralState> {
15 inner: Option<(UnsafeCell<S>, S::Interrupt)>, 24 life: Life,
25
26 state: MaybeUninit<UnsafeCell<S>>, // Init if life != Freed
27 irq: MaybeUninit<S::Interrupt>, // Init if life != Freed
28
16 _not_send: PhantomData<*mut ()>, 29 _not_send: PhantomData<*mut ()>,
17 _pinned: PhantomPinned, 30 _pinned: PhantomPinned,
18} 31}
@@ -20,16 +33,19 @@ pub struct PeripheralMutex<S: PeripheralState> {
20impl<S: PeripheralState> PeripheralMutex<S> { 33impl<S: PeripheralState> PeripheralMutex<S> {
21 pub fn new(state: S, irq: S::Interrupt) -> Self { 34 pub fn new(state: S, irq: S::Interrupt) -> Self {
22 Self { 35 Self {
23 inner: Some((UnsafeCell::new(state), irq)), 36 life: Life::Created,
37 state: MaybeUninit::new(UnsafeCell::new(state)),
38 irq: MaybeUninit::new(irq),
24 _not_send: PhantomData, 39 _not_send: PhantomData,
25 _pinned: PhantomPinned, 40 _pinned: PhantomPinned,
26 } 41 }
27 } 42 }
28 43
29 pub fn with<R>(self: Pin<&mut Self>, f: impl FnOnce(&mut S, &mut S::Interrupt) -> R) -> R { 44 /// safety: self must be pinned.
30 let this = unsafe { self.get_unchecked_mut() }; 45 unsafe fn setup(&mut self) {
31 let (state, irq) = unwrap!(this.inner.as_mut()); 46 assert!(self.life == Life::Created);
32 47
48 let irq = &mut *self.irq.as_mut_ptr();
33 irq.disable(); 49 irq.disable();
34 compiler_fence(Ordering::SeqCst); 50 compiler_fence(Ordering::SeqCst);
35 51
@@ -37,13 +53,30 @@ impl<S: PeripheralState> PeripheralMutex<S> {
37 // Safety: it's OK to get a &mut to the state, since 53 // Safety: it's OK to get a &mut to the state, since
38 // - We're in the IRQ, no one else can't preempt us 54 // - We're in the IRQ, no one else can't preempt us
39 // - We can't have preempted a with() call because the irq is disabled during it. 55 // - We can't have preempted a with() call because the irq is disabled during it.
40 let state = unsafe { &mut *(p as *mut S) }; 56 let state = &mut *(p as *mut S);
41 state.on_interrupt(); 57 state.on_interrupt();
42 }); 58 });
43 irq.set_handler_context(state.get() as *mut ()); 59 irq.set_handler_context(self.state.as_mut_ptr() as *mut ());
60
61 compiler_fence(Ordering::SeqCst);
62 irq.enable();
63
64 self.life = Life::Ready;
65 }
66
67 pub fn with<R>(self: Pin<&mut Self>, f: impl FnOnce(&mut S, &mut S::Interrupt) -> R) -> R {
68 let this = unsafe { self.get_unchecked_mut() };
69 if this.life != Life::Ready {
70 unsafe { this.setup() }
71 }
72
73 let irq = unsafe { &mut *this.irq.as_mut_ptr() };
74
75 irq.disable();
76 compiler_fence(Ordering::SeqCst);
44 77
45 // Safety: it's OK to get a &mut to the state, since the irq is disabled. 78 // Safety: it's OK to get a &mut to the state, since the irq is disabled.
46 let state = unsafe { &mut *state.get() }; 79 let state = unsafe { &mut *(*this.state.as_ptr()).get() };
47 80
48 let r = f(state, irq); 81 let r = f(state, irq);
49 82
@@ -55,11 +88,19 @@ impl<S: PeripheralState> PeripheralMutex<S> {
55 88
56 pub fn try_free(self: Pin<&mut Self>) -> Option<(S, S::Interrupt)> { 89 pub fn try_free(self: Pin<&mut Self>) -> Option<(S, S::Interrupt)> {
57 let this = unsafe { self.get_unchecked_mut() }; 90 let this = unsafe { self.get_unchecked_mut() };
58 this.inner.take().map(|(state, irq)| { 91
59 irq.disable(); 92 if this.life != Life::Freed {
60 irq.remove_handler(); 93 return None;
61 (state.into_inner(), irq) 94 }
62 }) 95
96 unsafe { &mut *this.irq.as_mut_ptr() }.disable();
97 compiler_fence(Ordering::SeqCst);
98
99 this.life = Life::Freed;
100
101 let state = unsafe { this.state.as_ptr().read().into_inner() };
102 let irq = unsafe { this.irq.as_ptr().read() };
103 Some((state, irq))
63 } 104 }
64 105
65 pub fn free(self: Pin<&mut Self>) -> (S, S::Interrupt) { 106 pub fn free(self: Pin<&mut Self>) -> (S, S::Interrupt) {
@@ -69,7 +110,8 @@ impl<S: PeripheralState> PeripheralMutex<S> {
69 110
70impl<S: PeripheralState> Drop for PeripheralMutex<S> { 111impl<S: PeripheralState> Drop for PeripheralMutex<S> {
71 fn drop(&mut self) { 112 fn drop(&mut self) {
72 if let Some((_state, irq)) = &mut self.inner { 113 if self.life != Life::Freed {
114 let irq = unsafe { &mut *self.irq.as_mut_ptr() };
73 irq.disable(); 115 irq.disable();
74 irq.remove_handler(); 116 irq.remove_handler();
75 } 117 }