diff --git a/embassy-hal-common/src/peripheral.rs b/embassy-hal-common/src/peripheral.rs index 46c6ebee..dcf9d3a2 100644 --- a/embassy-hal-common/src/peripheral.rs +++ b/embassy-hal-common/src/peripheral.rs @@ -50,19 +50,23 @@ pub(crate) fn can_be_preempted(irq: &impl Interrupt) -> bool { } impl<'a, S: PeripheralState> PeripheralMutex<'a, S> { - /// Create a new `PeripheralMutex` wrapping `irq`, with the initial state `state`. + /// Create a new `PeripheralMutex` wrapping `irq`, with `init` initializing the initial state. /// - /// self requires `state` to live for `'static`, because if the `PeripheralMutex` is leaked, the + /// self requires `S` to live for `'static`, because if the `PeripheralMutex` is leaked, the /// interrupt won't be disabled, which may try accessing the state at any time. To use non-`'static` /// state, see [`Self::new_unchecked`]. /// /// Registers `on_interrupt` as the `irq`'s handler, and enables it. - pub fn new(storage: &'a mut StateStorage, state: S, irq: S::Interrupt) -> Self + pub fn new( + irq: S::Interrupt, + storage: &'a mut StateStorage, + init: impl FnOnce() -> S, + ) -> Self where 'a: 'static, { // safety: safe because state is `'static`. - unsafe { Self::new_unchecked(storage, state, irq) } + unsafe { Self::new_unchecked(irq, storage, init) } } /// Create a `PeripheralMutex` without requiring the state is `'static`. @@ -72,9 +76,9 @@ impl<'a, S: PeripheralState> PeripheralMutex<'a, S> { /// # Safety /// The created instance must not be leaked (its `drop` must run). pub unsafe fn new_unchecked( - storage: &'a mut StateStorage, - state: S, irq: S::Interrupt, + storage: &'a mut StateStorage, + init: impl FnOnce() -> S, ) -> Self { if can_be_preempted(&irq) { panic!("`PeripheralMutex` cannot be created in an interrupt with higher priority than the interrupt it wraps"); @@ -84,7 +88,7 @@ impl<'a, S: PeripheralState> PeripheralMutex<'a, S> { // Safety: The pointer is valid and not used by anyone else // because we have the `&mut StateStorage`. - state_ptr.write(state); + state_ptr.write(init()); irq.disable(); irq.set_handler(|p| { diff --git a/embassy-hal-common/src/usb/mod.rs b/embassy-hal-common/src/usb/mod.rs index ae9f2607..70a74bd5 100644 --- a/embassy-hal-common/src/usb/mod.rs +++ b/embassy-hal-common/src/usb/mod.rs @@ -67,12 +67,11 @@ where class_set: S, irq: I, ) -> Self { - let initial_state = StateInner { + let mutex = PeripheralMutex::new_unchecked(irq, &mut state.0, || StateInner { device, classes: class_set.into_class_set(), _interrupt: PhantomData, - }; - let mutex = PeripheralMutex::new_unchecked(&mut state.0, initial_state, irq); + }); Self { inner: RefCell::new(mutex), } diff --git a/embassy-nrf/src/buffered_uarte.rs b/embassy-nrf/src/buffered_uarte.rs index 642c3018..048c36d3 100644 --- a/embassy-nrf/src/buffered_uarte.rs +++ b/embassy-nrf/src/buffered_uarte.rs @@ -155,23 +155,21 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> { ppi_ch2.set_task(Task::from_reg(&r.tasks_stoprx)); ppi_ch2.enable(); - let initial_state = StateInner { - phantom: PhantomData, - timer, - _ppi_ch1: ppi_ch1, - _ppi_ch2: ppi_ch2, - - rx: RingBuffer::new(rx_buffer), - rx_state: RxState::Idle, - rx_waker: WakerRegistration::new(), - - tx: RingBuffer::new(tx_buffer), - tx_state: TxState::Idle, - tx_waker: WakerRegistration::new(), - }; - Self { - inner: PeripheralMutex::new_unchecked(&mut state.0, initial_state, irq), + inner: PeripheralMutex::new_unchecked(irq, &mut state.0, move || StateInner { + phantom: PhantomData, + timer, + _ppi_ch1: ppi_ch1, + _ppi_ch2: ppi_ch2, + + rx: RingBuffer::new(rx_buffer), + rx_state: RxState::Idle, + rx_waker: WakerRegistration::new(), + + tx: RingBuffer::new(tx_buffer), + tx_state: TxState::Idle, + tx_waker: WakerRegistration::new(), + }), } } diff --git a/embassy-stm32/src/eth/v2/mod.rs b/embassy-stm32/src/eth/v2/mod.rs index cfb461ab..c1956aa1 100644 --- a/embassy-stm32/src/eth/v2/mod.rs +++ b/embassy-stm32/src/eth/v2/mod.rs @@ -78,10 +78,8 @@ impl<'d, P: PHY, const TX: usize, const RX: usize> Ethernet<'d, P, TX, RX> { tx_d1.configure(); tx_en.configure(); - let inner = Inner::new(peri); - // NOTE(unsafe) We are ourselves not leak-safe. - let state = PeripheralMutex::new_unchecked(&mut state.0, inner, interrupt); + let state = PeripheralMutex::new_unchecked(interrupt, &mut state.0, || Inner::new(peri)); // NOTE(unsafe) We have exclusive access to the registers let dma = ETH.ethernet_dma();