diff --git a/embassy-nrf/src/lib.rs b/embassy-nrf/src/lib.rs index 0c5dd059d..398bfed48 100644 --- a/embassy-nrf/src/lib.rs +++ b/embassy-nrf/src/lib.rs @@ -1039,3 +1039,27 @@ pub fn init(config: config::Config) -> Peripherals { peripherals } + +/// Operating modes for peripherals. +pub mod mode { + trait SealedMode {} + + /// Operating mode for a peripheral. + #[allow(private_bounds)] + pub trait Mode: SealedMode {} + + macro_rules! impl_mode { + ($name:ident) => { + impl SealedMode for $name {} + impl Mode for $name {} + }; + } + + /// Blocking mode. + pub struct Blocking; + /// Async mode. + pub struct Async; + + impl_mode!(Blocking); + impl_mode!(Async); +} diff --git a/embassy-nrf/src/rng.rs b/embassy-nrf/src/rng.rs index 7e42dc938..9d3130e6e 100644 --- a/embassy-nrf/src/rng.rs +++ b/embassy-nrf/src/rng.rs @@ -14,6 +14,7 @@ use embassy_hal_internal::{Peri, PeripheralType}; use embassy_sync::waitqueue::WakerRegistration; use crate::interrupt::typelevel::Interrupt; +use crate::mode::{Async, Blocking, Mode}; use crate::{interrupt, pac}; /// Interrupt handler. @@ -55,11 +56,31 @@ impl interrupt::typelevel::Handler for InterruptHandl /// A wrapper around an nRF RNG peripheral. /// /// It has a non-blocking API, and a blocking api through `rand`. -pub struct Rng<'d, T: Instance> { +pub struct Rng<'d, T: Instance, M: Mode> { _peri: Peri<'d, T>, + _phantom: PhantomData, } -impl<'d, T: Instance> Rng<'d, T> { +impl<'d, T: Instance> Rng<'d, T, Blocking> { + /// Creates a new RNG driver from the `RNG` peripheral and interrupt. + /// + /// SAFETY: The future returned from `fill_bytes` must not have its lifetime end without running its destructor, + /// e.g. using `mem::forget`. + /// + /// The synchronous API is safe. + pub fn new_blocking(rng: Peri<'d, T>) -> Self { + let this = Self { + _peri: rng, + _phantom: PhantomData, + }; + + this.stop(); + + this + } +} + +impl<'d, T: Instance> Rng<'d, T, Async> { /// Creates a new RNG driver from the `RNG` peripheral and interrupt. /// /// SAFETY: The future returned from `fill_bytes` must not have its lifetime end without running its destructor, @@ -70,7 +91,10 @@ impl<'d, T: Instance> Rng<'d, T> { rng: Peri<'d, T>, _irq: impl interrupt::typelevel::Binding> + 'd, ) -> Self { - let this = Self { _peri: rng }; + let this = Self { + _peri: rng, + _phantom: PhantomData, + }; this.stop(); this.disable_irq(); @@ -81,14 +105,6 @@ impl<'d, T: Instance> Rng<'d, T> { this } - fn stop(&self) { - T::regs().tasks_stop().write_value(1) - } - - fn start(&self) { - T::regs().tasks_start().write_value(1) - } - fn enable_irq(&self) { T::regs().intenset().write(|w| w.set_valrdy(true)); } @@ -97,16 +113,6 @@ impl<'d, T: Instance> Rng<'d, T> { T::regs().intenclr().write(|w| w.set_valrdy(true)); } - /// Enable or disable the RNG's bias correction. - /// - /// Bias correction removes any bias towards a '1' or a '0' in the bits generated. - /// However, this makes the generation of numbers slower. - /// - /// Defaults to disabled. - pub fn set_bias_correction(&self, enable: bool) { - T::regs().config().write(|w| w.set_dercen(enable)) - } - /// Fill the buffer with random bytes. pub async fn fill_bytes(&mut self, dest: &mut [u8]) { if dest.is_empty() { @@ -153,6 +159,26 @@ impl<'d, T: Instance> Rng<'d, T> { // Trigger the teardown drop(on_drop); } +} + +impl<'d, T: Instance, M: Mode> Rng<'d, T, M> { + fn stop(&self) { + T::regs().tasks_stop().write_value(1) + } + + fn start(&self) { + T::regs().tasks_start().write_value(1) + } + + /// Enable or disable the RNG's bias correction. + /// + /// Bias correction removes any bias towards a '1' or a '0' in the bits generated. + /// However, this makes the generation of numbers slower. + /// + /// Defaults to disabled. + pub fn set_bias_correction(&self, enable: bool) { + T::regs().config().write(|w| w.set_dercen(enable)) + } /// Fill the buffer with random bytes, blocking version. pub fn blocking_fill_bytes(&mut self, dest: &mut [u8]) { @@ -184,7 +210,7 @@ impl<'d, T: Instance> Rng<'d, T> { } } -impl<'d, T: Instance> Drop for Rng<'d, T> { +impl<'d, T: Instance, M: Mode> Drop for Rng<'d, T, M> { fn drop(&mut self) { self.stop(); critical_section::with(|cs| { @@ -195,7 +221,7 @@ impl<'d, T: Instance> Drop for Rng<'d, T> { } } -impl<'d, T: Instance> rand_core_06::RngCore for Rng<'d, T> { +impl<'d, T: Instance, M: Mode> rand_core_06::RngCore for Rng<'d, T, M> { fn fill_bytes(&mut self, dest: &mut [u8]) { self.blocking_fill_bytes(dest); } @@ -211,9 +237,9 @@ impl<'d, T: Instance> rand_core_06::RngCore for Rng<'d, T> { } } -impl<'d, T: Instance> rand_core_06::CryptoRng for Rng<'d, T> {} +impl<'d, T: Instance, M: Mode> rand_core_06::CryptoRng for Rng<'d, T, M> {} -impl<'d, T: Instance> rand_core_09::RngCore for Rng<'d, T> { +impl<'d, T: Instance, M: Mode> rand_core_09::RngCore for Rng<'d, T, M> { fn fill_bytes(&mut self, dest: &mut [u8]) { self.blocking_fill_bytes(dest); } @@ -225,7 +251,7 @@ impl<'d, T: Instance> rand_core_09::RngCore for Rng<'d, T> { } } -impl<'d, T: Instance> rand_core_09::CryptoRng for Rng<'d, T> {} +impl<'d, T: Instance, M: Mode> rand_core_09::CryptoRng for Rng<'d, T, M> {} /// Peripheral static state pub(crate) struct State {