embassy_nrf/
rng.rs

1//! Random Number Generator (RNG) driver.
2
3#![macro_use]
4
5use core::cell::{RefCell, RefMut};
6use core::future::poll_fn;
7use core::marker::PhantomData;
8use core::ptr;
9use core::task::Poll;
10
11use critical_section::{CriticalSection, Mutex};
12use embassy_hal_internal::drop::OnDrop;
13use embassy_hal_internal::{Peri, PeripheralType};
14use embassy_sync::waitqueue::WakerRegistration;
15
16use crate::interrupt::typelevel::Interrupt;
17use crate::mode::{Async, Blocking, Mode};
18use crate::{interrupt, pac};
19
20/// Interrupt handler.
21pub struct InterruptHandler<T: Instance> {
22    _phantom: PhantomData<T>,
23}
24
25impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
26    unsafe fn on_interrupt() {
27        let r = T::regs();
28
29        // Clear the event.
30        r.events_valrdy().write_value(0);
31
32        // Mutate the slice within a critical section,
33        // so that the future isn't dropped in between us loading the pointer and actually dereferencing it.
34        critical_section::with(|cs| {
35            let mut state = T::state().borrow_mut(cs);
36            // We need to make sure we haven't already filled the whole slice,
37            // in case the interrupt fired again before the executor got back to the future.
38            if !state.ptr.is_null() && state.ptr != state.end {
39                // If the future was dropped, the pointer would have been set to null,
40                // so we're still good to mutate the slice.
41                // The safety contract of `Rng::new` means that the future can't have been dropped
42                // without calling its destructor.
43                unsafe {
44                    *state.ptr = r.value().read().value();
45                    state.ptr = state.ptr.add(1);
46                }
47
48                if state.ptr == state.end {
49                    state.waker.wake();
50                }
51            }
52        });
53    }
54}
55
56/// A wrapper around an nRF RNG peripheral.
57///
58/// It has a non-blocking API, and a blocking api through `rand`.
59pub struct Rng<'d, T: Instance, M: Mode> {
60    _peri: Peri<'d, T>,
61    _phantom: PhantomData<M>,
62}
63
64impl<'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
83impl<'d, T: Instance> Rng<'d, T, Async> {
84    /// Creates a new RNG driver from the `RNG` peripheral and interrupt.
85    ///
86    /// SAFETY: The future returned from `fill_bytes` must not have its lifetime end without running its destructor,
87    /// e.g. using `mem::forget`.
88    ///
89    /// The synchronous API is safe.
90    pub fn new(
91        rng: Peri<'d, T>,
92        _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
93    ) -> Self {
94        let this = Self {
95            _peri: rng,
96            _phantom: PhantomData,
97        };
98
99        this.stop();
100        this.disable_irq();
101
102        T::Interrupt::unpend();
103        unsafe { T::Interrupt::enable() };
104
105        this
106    }
107
108    fn enable_irq(&self) {
109        T::regs().intenset().write(|w| w.set_valrdy(true));
110    }
111
112    fn disable_irq(&self) {
113        T::regs().intenclr().write(|w| w.set_valrdy(true));
114    }
115
116    /// Fill the buffer with random bytes.
117    pub async fn fill_bytes(&mut self, dest: &mut [u8]) {
118        if dest.is_empty() {
119            return; // Nothing to fill
120        }
121
122        let range = dest.as_mut_ptr_range();
123        // Even if we've preempted the interrupt, it can't preempt us again,
124        // so we don't need to worry about the order we write these in.
125        critical_section::with(|cs| {
126            let mut state = T::state().borrow_mut(cs);
127            state.ptr = range.start;
128            state.end = range.end;
129        });
130
131        self.enable_irq();
132        self.start();
133
134        let on_drop = OnDrop::new(|| {
135            self.stop();
136            self.disable_irq();
137
138            critical_section::with(|cs| {
139                let mut state = T::state().borrow_mut(cs);
140                state.ptr = ptr::null_mut();
141                state.end = ptr::null_mut();
142            });
143        });
144
145        poll_fn(|cx| {
146            critical_section::with(|cs| {
147                let mut s = T::state().borrow_mut(cs);
148                s.waker.register(cx.waker());
149                if s.ptr == s.end {
150                    // We're done.
151                    Poll::Ready(())
152                } else {
153                    Poll::Pending
154                }
155            })
156        })
157        .await;
158
159        // Trigger the teardown
160        drop(on_drop);
161    }
162}
163
164impl<'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    }
182
183    /// Fill the buffer with random bytes, blocking version.
184    pub fn blocking_fill_bytes(&mut self, dest: &mut [u8]) {
185        self.start();
186
187        for byte in dest.iter_mut() {
188            let regs = T::regs();
189            while regs.events_valrdy().read() == 0 {}
190            regs.events_valrdy().write_value(0);
191            *byte = regs.value().read().value();
192        }
193
194        self.stop();
195    }
196
197    /// Generate a random u32
198    pub fn blocking_next_u32(&mut self) -> u32 {
199        let mut bytes = [0; 4];
200        self.blocking_fill_bytes(&mut bytes);
201        // We don't care about the endianness, so just use the native one.
202        u32::from_ne_bytes(bytes)
203    }
204
205    /// Generate a random u64
206    pub fn blocking_next_u64(&mut self) -> u64 {
207        let mut bytes = [0; 8];
208        self.blocking_fill_bytes(&mut bytes);
209        u64::from_ne_bytes(bytes)
210    }
211}
212
213impl<'d, T: Instance, M: Mode> Drop for Rng<'d, T, M> {
214    fn drop(&mut self) {
215        self.stop();
216        critical_section::with(|cs| {
217            let mut state = T::state().borrow_mut(cs);
218            state.ptr = ptr::null_mut();
219            state.end = ptr::null_mut();
220        });
221    }
222}
223
224impl<'d, T: Instance, M: Mode> rand_core_06::RngCore for Rng<'d, T, M> {
225    fn fill_bytes(&mut self, dest: &mut [u8]) {
226        self.blocking_fill_bytes(dest);
227    }
228    fn next_u32(&mut self) -> u32 {
229        self.blocking_next_u32()
230    }
231    fn next_u64(&mut self) -> u64 {
232        self.blocking_next_u64()
233    }
234    fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand_core_06::Error> {
235        self.blocking_fill_bytes(dest);
236        Ok(())
237    }
238}
239
240impl<'d, T: Instance, M: Mode> rand_core_06::CryptoRng for Rng<'d, T, M> {}
241
242impl<'d, T: Instance, M: Mode> rand_core_09::RngCore for Rng<'d, T, M> {
243    fn fill_bytes(&mut self, dest: &mut [u8]) {
244        self.blocking_fill_bytes(dest);
245    }
246    fn next_u32(&mut self) -> u32 {
247        self.blocking_next_u32()
248    }
249    fn next_u64(&mut self) -> u64 {
250        self.blocking_next_u64()
251    }
252}
253
254impl<'d, T: Instance, M: Mode> rand_core_09::CryptoRng for Rng<'d, T, M> {}
255
256/// Peripheral static state
257pub(crate) struct State {
258    inner: Mutex<RefCell<InnerState>>,
259}
260
261struct InnerState {
262    ptr: *mut u8,
263    end: *mut u8,
264    waker: WakerRegistration,
265}
266
267unsafe impl Send for InnerState {}
268
269impl State {
270    pub(crate) const fn new() -> Self {
271        Self {
272            inner: Mutex::new(RefCell::new(InnerState::new())),
273        }
274    }
275
276    fn borrow_mut<'cs>(&'cs self, cs: CriticalSection<'cs>) -> RefMut<'cs, InnerState> {
277        self.inner.borrow(cs).borrow_mut()
278    }
279}
280
281impl InnerState {
282    const fn new() -> Self {
283        Self {
284            ptr: ptr::null_mut(),
285            end: ptr::null_mut(),
286            waker: WakerRegistration::new(),
287        }
288    }
289}
290
291pub(crate) trait SealedInstance {
292    fn regs() -> pac::rng::Rng;
293    fn state() -> &'static State;
294}
295
296/// RNG peripheral instance.
297#[allow(private_bounds)]
298pub trait Instance: SealedInstance + PeripheralType + 'static + Send {
299    /// Interrupt for this peripheral.
300    type Interrupt: interrupt::typelevel::Interrupt;
301}
302
303macro_rules! impl_rng {
304    ($type:ident, $pac_type:ident, $irq:ident) => {
305        impl crate::rng::SealedInstance for peripherals::$type {
306            fn regs() -> crate::pac::rng::Rng {
307                pac::$pac_type
308            }
309            fn state() -> &'static crate::rng::State {
310                static STATE: crate::rng::State = crate::rng::State::new();
311                &STATE
312            }
313        }
314        impl crate::rng::Instance for peripherals::$type {
315            type Interrupt = crate::interrupt::typelevel::$irq;
316        }
317    };
318}