diff options
| author | Dario Nieuwenhuis <[email protected]> | 2025-05-19 16:38:34 +0200 |
|---|---|---|
| committer | Dario Nieuwenhuis <[email protected]> | 2025-05-21 12:39:52 +0200 |
| commit | 0e47478f01335c735f8f27fa3a935776736e9afa (patch) | |
| tree | 89e9184d44b567a8a4c8de871cc1645090c11e9f | |
| parent | 7cbc9058bc726900571a7858c581f60cd8cb0266 (diff) | |
nrf/rng: add Blocking/Async Mode param.
This allows avoiding creating the irq handler if you're only going
to use it in blocking mode.
| -rw-r--r-- | embassy-nrf/src/lib.rs | 24 | ||||
| -rw-r--r-- | embassy-nrf/src/rng.rs | 78 |
2 files changed, 76 insertions, 26 deletions
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 { | |||
| 1039 | 1039 | ||
| 1040 | peripherals | 1040 | peripherals |
| 1041 | } | 1041 | } |
| 1042 | |||
| 1043 | /// Operating modes for peripherals. | ||
| 1044 | pub mod mode { | ||
| 1045 | trait SealedMode {} | ||
| 1046 | |||
| 1047 | /// Operating mode for a peripheral. | ||
| 1048 | #[allow(private_bounds)] | ||
| 1049 | pub trait Mode: SealedMode {} | ||
| 1050 | |||
| 1051 | macro_rules! impl_mode { | ||
| 1052 | ($name:ident) => { | ||
| 1053 | impl SealedMode for $name {} | ||
| 1054 | impl Mode for $name {} | ||
| 1055 | }; | ||
| 1056 | } | ||
| 1057 | |||
| 1058 | /// Blocking mode. | ||
| 1059 | pub struct Blocking; | ||
| 1060 | /// Async mode. | ||
| 1061 | pub struct Async; | ||
| 1062 | |||
| 1063 | impl_mode!(Blocking); | ||
| 1064 | impl_mode!(Async); | ||
| 1065 | } | ||
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}; | |||
| 14 | use embassy_sync::waitqueue::WakerRegistration; | 14 | use embassy_sync::waitqueue::WakerRegistration; |
| 15 | 15 | ||
| 16 | use crate::interrupt::typelevel::Interrupt; | 16 | use crate::interrupt::typelevel::Interrupt; |
| 17 | use crate::mode::{Async, Blocking, Mode}; | ||
| 17 | use crate::{interrupt, pac}; | 18 | use crate::{interrupt, pac}; |
| 18 | 19 | ||
| 19 | /// Interrupt handler. | 20 | /// Interrupt handler. |
| @@ -55,11 +56,31 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl | |||
| 55 | /// A wrapper around an nRF RNG peripheral. | 56 | /// A wrapper around an nRF RNG peripheral. |
| 56 | /// | 57 | /// |
| 57 | /// It has a non-blocking API, and a blocking api through `rand`. | 58 | /// It has a non-blocking API, and a blocking api through `rand`. |
| 58 | pub struct Rng<'d, T: Instance> { | 59 | pub struct Rng<'d, T: Instance, M: Mode> { |
| 59 | _peri: Peri<'d, T>, | 60 | _peri: Peri<'d, T>, |
| 61 | _phantom: PhantomData<M>, | ||
| 60 | } | 62 | } |
| 61 | 63 | ||
| 62 | impl<'d, T: Instance> Rng<'d, T> { | 64 | impl<'d, T: Instance> Rng<'d, T, Blocking> { |
| 65 | /// Creates a new RNG driver from the `RNG` peripheral and interrupt. | ||
| 66 | /// | ||
| 67 | /// SAFETY: The future returned from `fill_bytes` must not have its lifetime end without running its destructor, | ||
| 68 | /// e.g. using `mem::forget`. | ||
| 69 | /// | ||
| 70 | /// The synchronous API is safe. | ||
| 71 | pub fn new_blocking(rng: Peri<'d, T>) -> Self { | ||
| 72 | let this = Self { | ||
| 73 | _peri: rng, | ||
| 74 | _phantom: PhantomData, | ||
| 75 | }; | ||
| 76 | |||
| 77 | this.stop(); | ||
| 78 | |||
| 79 | this | ||
| 80 | } | ||
| 81 | } | ||
| 82 | |||
| 83 | impl<'d, T: Instance> Rng<'d, T, Async> { | ||
| 63 | /// Creates a new RNG driver from the `RNG` peripheral and interrupt. | 84 | /// Creates a new RNG driver from the `RNG` peripheral and interrupt. |
| 64 | /// | 85 | /// |
| 65 | /// SAFETY: The future returned from `fill_bytes` must not have its lifetime end without running its destructor, | 86 | /// 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> { | |||
| 70 | rng: Peri<'d, T>, | 91 | rng: Peri<'d, T>, |
| 71 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, | 92 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, |
| 72 | ) -> Self { | 93 | ) -> Self { |
| 73 | let this = Self { _peri: rng }; | 94 | let this = Self { |
| 95 | _peri: rng, | ||
| 96 | _phantom: PhantomData, | ||
| 97 | }; | ||
| 74 | 98 | ||
| 75 | this.stop(); | 99 | this.stop(); |
| 76 | this.disable_irq(); | 100 | this.disable_irq(); |
| @@ -81,14 +105,6 @@ impl<'d, T: Instance> Rng<'d, T> { | |||
| 81 | this | 105 | this |
| 82 | } | 106 | } |
| 83 | 107 | ||
| 84 | fn stop(&self) { | ||
| 85 | T::regs().tasks_stop().write_value(1) | ||
| 86 | } | ||
| 87 | |||
| 88 | fn start(&self) { | ||
| 89 | T::regs().tasks_start().write_value(1) | ||
| 90 | } | ||
| 91 | |||
| 92 | fn enable_irq(&self) { | 108 | fn enable_irq(&self) { |
| 93 | T::regs().intenset().write(|w| w.set_valrdy(true)); | 109 | T::regs().intenset().write(|w| w.set_valrdy(true)); |
| 94 | } | 110 | } |
| @@ -97,16 +113,6 @@ impl<'d, T: Instance> Rng<'d, T> { | |||
| 97 | T::regs().intenclr().write(|w| w.set_valrdy(true)); | 113 | T::regs().intenclr().write(|w| w.set_valrdy(true)); |
| 98 | } | 114 | } |
| 99 | 115 | ||
| 100 | /// Enable or disable the RNG's bias correction. | ||
| 101 | /// | ||
| 102 | /// Bias correction removes any bias towards a '1' or a '0' in the bits generated. | ||
| 103 | /// However, this makes the generation of numbers slower. | ||
| 104 | /// | ||
| 105 | /// Defaults to disabled. | ||
| 106 | pub fn set_bias_correction(&self, enable: bool) { | ||
| 107 | T::regs().config().write(|w| w.set_dercen(enable)) | ||
| 108 | } | ||
| 109 | |||
| 110 | /// Fill the buffer with random bytes. | 116 | /// Fill the buffer with random bytes. |
| 111 | pub async fn fill_bytes(&mut self, dest: &mut [u8]) { | 117 | pub async fn fill_bytes(&mut self, dest: &mut [u8]) { |
| 112 | if dest.is_empty() { | 118 | if dest.is_empty() { |
| @@ -153,6 +159,26 @@ impl<'d, T: Instance> Rng<'d, T> { | |||
| 153 | // Trigger the teardown | 159 | // Trigger the teardown |
| 154 | drop(on_drop); | 160 | drop(on_drop); |
| 155 | } | 161 | } |
| 162 | } | ||
| 163 | |||
| 164 | impl<'d, T: Instance, M: Mode> Rng<'d, T, M> { | ||
| 165 | fn stop(&self) { | ||
| 166 | T::regs().tasks_stop().write_value(1) | ||
| 167 | } | ||
| 168 | |||
| 169 | fn start(&self) { | ||
| 170 | T::regs().tasks_start().write_value(1) | ||
| 171 | } | ||
| 172 | |||
| 173 | /// Enable or disable the RNG's bias correction. | ||
| 174 | /// | ||
| 175 | /// Bias correction removes any bias towards a '1' or a '0' in the bits generated. | ||
| 176 | /// However, this makes the generation of numbers slower. | ||
| 177 | /// | ||
| 178 | /// Defaults to disabled. | ||
| 179 | pub fn set_bias_correction(&self, enable: bool) { | ||
| 180 | T::regs().config().write(|w| w.set_dercen(enable)) | ||
| 181 | } | ||
| 156 | 182 | ||
| 157 | /// Fill the buffer with random bytes, blocking version. | 183 | /// Fill the buffer with random bytes, blocking version. |
| 158 | pub fn blocking_fill_bytes(&mut self, dest: &mut [u8]) { | 184 | pub fn blocking_fill_bytes(&mut self, dest: &mut [u8]) { |
| @@ -184,7 +210,7 @@ impl<'d, T: Instance> Rng<'d, T> { | |||
| 184 | } | 210 | } |
| 185 | } | 211 | } |
| 186 | 212 | ||
| 187 | impl<'d, T: Instance> Drop for Rng<'d, T> { | 213 | impl<'d, T: Instance, M: Mode> Drop for Rng<'d, T, M> { |
| 188 | fn drop(&mut self) { | 214 | fn drop(&mut self) { |
| 189 | self.stop(); | 215 | self.stop(); |
| 190 | critical_section::with(|cs| { | 216 | critical_section::with(|cs| { |
| @@ -195,7 +221,7 @@ impl<'d, T: Instance> Drop for Rng<'d, T> { | |||
| 195 | } | 221 | } |
| 196 | } | 222 | } |
| 197 | 223 | ||
| 198 | impl<'d, T: Instance> rand_core_06::RngCore for Rng<'d, T> { | 224 | impl<'d, T: Instance, M: Mode> rand_core_06::RngCore for Rng<'d, T, M> { |
| 199 | fn fill_bytes(&mut self, dest: &mut [u8]) { | 225 | fn fill_bytes(&mut self, dest: &mut [u8]) { |
| 200 | self.blocking_fill_bytes(dest); | 226 | self.blocking_fill_bytes(dest); |
| 201 | } | 227 | } |
| @@ -211,9 +237,9 @@ impl<'d, T: Instance> rand_core_06::RngCore for Rng<'d, T> { | |||
| 211 | } | 237 | } |
| 212 | } | 238 | } |
| 213 | 239 | ||
| 214 | impl<'d, T: Instance> rand_core_06::CryptoRng for Rng<'d, T> {} | 240 | impl<'d, T: Instance, M: Mode> rand_core_06::CryptoRng for Rng<'d, T, M> {} |
| 215 | 241 | ||
| 216 | impl<'d, T: Instance> rand_core_09::RngCore for Rng<'d, T> { | 242 | impl<'d, T: Instance, M: Mode> rand_core_09::RngCore for Rng<'d, T, M> { |
| 217 | fn fill_bytes(&mut self, dest: &mut [u8]) { | 243 | fn fill_bytes(&mut self, dest: &mut [u8]) { |
| 218 | self.blocking_fill_bytes(dest); | 244 | self.blocking_fill_bytes(dest); |
| 219 | } | 245 | } |
| @@ -225,7 +251,7 @@ impl<'d, T: Instance> rand_core_09::RngCore for Rng<'d, T> { | |||
| 225 | } | 251 | } |
| 226 | } | 252 | } |
| 227 | 253 | ||
| 228 | impl<'d, T: Instance> rand_core_09::CryptoRng for Rng<'d, T> {} | 254 | impl<'d, T: Instance, M: Mode> rand_core_09::CryptoRng for Rng<'d, T, M> {} |
| 229 | 255 | ||
| 230 | /// Peripheral static state | 256 | /// Peripheral static state |
| 231 | pub(crate) struct State { | 257 | pub(crate) struct State { |
