aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDario Nieuwenhuis <[email protected]>2022-01-13 23:10:24 +0100
committerDario Nieuwenhuis <[email protected]>2022-01-13 23:56:39 +0100
commit6eec3d8acca1a4c6a853d0b65e43ec0a0f5c5c27 (patch)
treed49ecce9b03d6f7c5e2dc2c4419e798a69453ec9
parentdf00c83984b99c5c87a1e90d042147eae7c75631 (diff)
nrf/rng: expose all functionality as inherent methods.
-rw-r--r--embassy-nrf/src/rng.rs115
-rw-r--r--examples/nrf/src/bin/rng.rs6
2 files changed, 53 insertions, 68 deletions
diff --git a/embassy-nrf/src/rng.rs b/embassy-nrf/src/rng.rs
index 6b36cbb88..98833c52b 100644
--- a/embassy-nrf/src/rng.rs
+++ b/embassy-nrf/src/rng.rs
@@ -1,5 +1,3 @@
1use core::convert::Infallible;
2use core::future::Future;
3use core::marker::PhantomData; 1use core::marker::PhantomData;
4use core::ptr; 2use core::ptr;
5use core::sync::atomic::AtomicPtr; 3use core::sync::atomic::AtomicPtr;
@@ -7,13 +5,11 @@ use core::sync::atomic::Ordering;
7use core::task::Poll; 5use core::task::Poll;
8 6
9use embassy::interrupt::InterruptExt; 7use embassy::interrupt::InterruptExt;
10use embassy::traits;
11use embassy::util::Unborrow; 8use embassy::util::Unborrow;
12use embassy::waitqueue::AtomicWaker; 9use embassy::waitqueue::AtomicWaker;
13use embassy_hal_common::drop::OnDrop; 10use embassy_hal_common::drop::OnDrop;
14use embassy_hal_common::unborrow; 11use embassy_hal_common::unborrow;
15use futures::future::poll_fn; 12use futures::future::poll_fn;
16use rand_core::RngCore;
17 13
18use crate::interrupt; 14use crate::interrupt;
19use crate::pac; 15use crate::pac;
@@ -39,7 +35,7 @@ struct State {
39 35
40/// A wrapper around an nRF RNG peripheral. 36/// A wrapper around an nRF RNG peripheral.
41/// 37///
42/// It has a non-blocking API, through `embassy::traits::Rng`, and a blocking api through `rand`. 38/// It has a non-blocking API, and a blocking api through `rand`.
43pub struct Rng<'d> { 39pub struct Rng<'d> {
44 irq: interrupt::RNG, 40 irq: interrupt::RNG,
45 phantom: PhantomData<(&'d mut RNG, &'d mut interrupt::RNG)>, 41 phantom: PhantomData<(&'d mut RNG, &'d mut interrupt::RNG)>,
@@ -146,72 +142,51 @@ impl<'d> Rng<'d> {
146 pub fn bias_correction(&self, enable: bool) { 142 pub fn bias_correction(&self, enable: bool) {
147 RNG::regs().config.write(|w| w.dercen().bit(enable)) 143 RNG::regs().config.write(|w| w.dercen().bit(enable))
148 } 144 }
149}
150
151impl<'d> Drop for Rng<'d> {
152 fn drop(&mut self) {
153 self.irq.disable()
154 }
155}
156
157impl<'d> traits::rng::Rng for Rng<'d> {
158 type Error = Infallible;
159 145
160 type RngFuture<'a> 146 pub async fn fill_bytes(&mut self, dest: &mut [u8]) {
161 where 147 if dest.len() == 0 {
162 'd: 'a, 148 return; // Nothing to fill
163 = impl Future<Output = Result<(), Self::Error>> + 'a; 149 }
164
165 fn fill_bytes<'a>(&'a mut self, dest: &'a mut [u8]) -> Self::RngFuture<'a> {
166 async move {
167 if dest.len() == 0 {
168 return Ok(()); // Nothing to fill
169 }
170
171 let range = dest.as_mut_ptr_range();
172 // Even if we've preempted the interrupt, it can't preempt us again,
173 // so we don't need to worry about the order we write these in.
174 STATE.ptr.store(range.start, Ordering::Relaxed);
175 STATE.end.store(range.end, Ordering::Relaxed);
176 150
177 self.enable_irq(); 151 let range = dest.as_mut_ptr_range();
178 self.start(); 152 // Even if we've preempted the interrupt, it can't preempt us again,
153 // so we don't need to worry about the order we write these in.
154 STATE.ptr.store(range.start, Ordering::Relaxed);
155 STATE.end.store(range.end, Ordering::Relaxed);
179 156
180 let on_drop = OnDrop::new(|| { 157 self.enable_irq();
181 self.stop(); 158 self.start();
182 self.disable_irq();
183 159
184 // The interrupt is now disabled and can't preempt us anymore, so the order doesn't matter here. 160 let on_drop = OnDrop::new(|| {
185 STATE.ptr.store(ptr::null_mut(), Ordering::Relaxed); 161 self.stop();
186 STATE.end.store(ptr::null_mut(), Ordering::Relaxed); 162 self.disable_irq();
187 });
188 163
189 poll_fn(|cx| { 164 // The interrupt is now disabled and can't preempt us anymore, so the order doesn't matter here.
190 STATE.waker.register(cx.waker()); 165 STATE.ptr.store(ptr::null_mut(), Ordering::Relaxed);
166 STATE.end.store(ptr::null_mut(), Ordering::Relaxed);
167 });
191 168
192 // The interrupt will never modify `end`, so load it first and then get the most up-to-date `ptr`. 169 poll_fn(|cx| {
193 let end = STATE.end.load(Ordering::Relaxed); 170 STATE.waker.register(cx.waker());
194 let ptr = STATE.ptr.load(Ordering::Relaxed);
195 171
196 if ptr == end { 172 // The interrupt will never modify `end`, so load it first and then get the most up-to-date `ptr`.
197 // We're done. 173 let end = STATE.end.load(Ordering::Relaxed);
198 Poll::Ready(()) 174 let ptr = STATE.ptr.load(Ordering::Relaxed);
199 } else {
200 Poll::Pending
201 }
202 })
203 .await;
204 175
205 // Trigger the teardown 176 if ptr == end {
206 drop(on_drop); 177 // We're done.
178 Poll::Ready(())
179 } else {
180 Poll::Pending
181 }
182 })
183 .await;
207 184
208 Ok(()) 185 // Trigger the teardown
209 } 186 drop(on_drop);
210 } 187 }
211}
212 188
213impl<'d> RngCore for Rng<'d> { 189 pub fn blocking_fill_bytes(&mut self, dest: &mut [u8]) {
214 fn fill_bytes(&mut self, dest: &mut [u8]) {
215 self.start(); 190 self.start();
216 191
217 for byte in dest.iter_mut() { 192 for byte in dest.iter_mut() {
@@ -223,24 +198,36 @@ impl<'d> RngCore for Rng<'d> {
223 198
224 self.stop(); 199 self.stop();
225 } 200 }
201}
202
203impl<'d> Drop for Rng<'d> {
204 fn drop(&mut self) {
205 self.irq.disable()
206 }
207}
208
209impl<'d> rand_core::RngCore for Rng<'d> {
210 fn fill_bytes(&mut self, dest: &mut [u8]) {
211 self.blocking_fill_bytes(dest);
212 }
226 213
227 fn next_u32(&mut self) -> u32 { 214 fn next_u32(&mut self) -> u32 {
228 let mut bytes = [0; 4]; 215 let mut bytes = [0; 4];
229 self.fill_bytes(&mut bytes); 216 self.blocking_fill_bytes(&mut bytes);
230 // We don't care about the endianness, so just use the native one. 217 // We don't care about the endianness, so just use the native one.
231 u32::from_ne_bytes(bytes) 218 u32::from_ne_bytes(bytes)
232 } 219 }
233 220
234 fn next_u64(&mut self) -> u64 { 221 fn next_u64(&mut self) -> u64 {
235 let mut bytes = [0; 8]; 222 let mut bytes = [0; 8];
236 self.fill_bytes(&mut bytes); 223 self.blocking_fill_bytes(&mut bytes);
237 u64::from_ne_bytes(bytes) 224 u64::from_ne_bytes(bytes)
238 } 225 }
239 226
240 fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand_core::Error> { 227 fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand_core::Error> {
241 self.fill_bytes(dest); 228 self.blocking_fill_bytes(dest);
242 Ok(()) 229 Ok(())
243 } 230 }
244} 231}
245 232
246// TODO: Should `Rng` implement `CryptoRng`? It's 'suitable for cryptographic purposes' according to the specification. 233impl<'d> rand_core::CryptoRng for Rng<'d> {}
diff --git a/examples/nrf/src/bin/rng.rs b/examples/nrf/src/bin/rng.rs
index 2f1a26993..a35a9fa85 100644
--- a/examples/nrf/src/bin/rng.rs
+++ b/examples/nrf/src/bin/rng.rs
@@ -5,9 +5,7 @@
5#[path = "../example_common.rs"] 5#[path = "../example_common.rs"]
6mod example_common; 6mod example_common;
7 7
8use defmt::unwrap;
9use embassy::executor::Spawner; 8use embassy::executor::Spawner;
10use embassy::traits::rng::Rng as _;
11use embassy_nrf::interrupt; 9use embassy_nrf::interrupt;
12use embassy_nrf::rng::Rng; 10use embassy_nrf::rng::Rng;
13use embassy_nrf::Peripherals; 11use embassy_nrf::Peripherals;
@@ -19,14 +17,14 @@ async fn main(_spawner: Spawner, p: Peripherals) {
19 17
20 // Async API 18 // Async API
21 let mut bytes = [0; 4]; 19 let mut bytes = [0; 4];
22 unwrap!(rng.fill_bytes(&mut bytes).await); // nRF RNG is infallible 20 rng.fill_bytes(&mut bytes).await;
23 defmt::info!("Some random bytes: {:?}", bytes); 21 defmt::info!("Some random bytes: {:?}", bytes);
24 22
25 // Sync API with `rand` 23 // Sync API with `rand`
26 defmt::info!("A random number from 1 to 10: {:?}", rng.gen_range(1..=10)); 24 defmt::info!("A random number from 1 to 10: {:?}", rng.gen_range(1..=10));
27 25
28 let mut bytes = [0; 1024]; 26 let mut bytes = [0; 1024];
29 unwrap!(rng.fill_bytes(&mut bytes).await); 27 rng.fill_bytes(&mut bytes).await;
30 let zero_count: u32 = bytes.iter().fold(0, |acc, val| acc + val.count_zeros()); 28 let zero_count: u32 = bytes.iter().fold(0, |acc, val| acc + val.count_zeros());
31 let one_count: u32 = bytes.iter().fold(0, |acc, val| acc + val.count_ones()); 29 let one_count: u32 = bytes.iter().fold(0, |acc, val| acc + val.count_ones());
32 defmt::info!( 30 defmt::info!(