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, M: Mode> {
60    r: pac::rng::Rng,
61    state: &'static State,
62    _phantom: PhantomData<(&'d (), M)>,
63}
64
65impl<'d> Rng<'d, Blocking> {
66    /// Creates a new RNG driver from the `RNG` peripheral and interrupt.
67    ///
68    /// SAFETY: The future returned from `fill_bytes` must not have its lifetime end without running its destructor,
69    /// e.g. using `mem::forget`.
70    ///
71    /// The synchronous API is safe.
72    pub fn new_blocking<T: Instance>(_rng: Peri<'d, T>) -> Self {
73        let this = Self {
74            r: T::regs(),
75            state: T::state(),
76            _phantom: PhantomData,
77        };
78
79        this.stop();
80
81        this
82    }
83}
84
85impl<'d> Rng<'d, Async> {
86    /// Creates a new RNG driver from the `RNG` peripheral and interrupt.
87    ///
88    /// SAFETY: The future returned from `fill_bytes` must not have its lifetime end without running its destructor,
89    /// e.g. using `mem::forget`.
90    ///
91    /// The synchronous API is safe.
92    pub fn new<T: Instance>(
93        _rng: Peri<'d, T>,
94        _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
95    ) -> Self {
96        let this = Self {
97            r: T::regs(),
98            state: T::state(),
99            _phantom: PhantomData,
100        };
101
102        this.stop();
103        this.disable_irq();
104
105        T::Interrupt::unpend();
106        unsafe { T::Interrupt::enable() };
107
108        this
109    }
110
111    fn enable_irq(&self) {
112        self.r.intenset().write(|w| w.set_valrdy(true));
113    }
114
115    fn disable_irq(&self) {
116        self.r.intenclr().write(|w| w.set_valrdy(true));
117    }
118
119    /// Fill the buffer with random bytes.
120    pub async fn fill_bytes(&mut self, dest: &mut [u8]) {
121        if dest.is_empty() {
122            return; // Nothing to fill
123        }
124
125        let range = dest.as_mut_ptr_range();
126        let state = self.state;
127        // Even if we've preempted the interrupt, it can't preempt us again,
128        // so we don't need to worry about the order we write these in.
129        critical_section::with(|cs| {
130            let mut state = state.borrow_mut(cs);
131            state.ptr = range.start;
132            state.end = range.end;
133        });
134
135        self.enable_irq();
136        self.start();
137
138        let on_drop = OnDrop::new(|| {
139            self.stop();
140            self.disable_irq();
141
142            critical_section::with(|cs| {
143                let mut state = state.borrow_mut(cs);
144                state.ptr = ptr::null_mut();
145                state.end = ptr::null_mut();
146            });
147        });
148
149        poll_fn(|cx| {
150            critical_section::with(|cs| {
151                let mut s = state.borrow_mut(cs);
152                s.waker.register(cx.waker());
153                if s.ptr == s.end {
154                    // We're done.
155                    Poll::Ready(())
156                } else {
157                    Poll::Pending
158                }
159            })
160        })
161        .await;
162
163        // Trigger the teardown
164        drop(on_drop);
165    }
166}
167
168impl<'d, M: Mode> Rng<'d, M> {
169    fn stop(&self) {
170        self.r.tasks_stop().write_value(1)
171    }
172
173    fn start(&self) {
174        self.r.tasks_start().write_value(1)
175    }
176
177    /// Enable or disable the RNG's bias correction.
178    ///
179    /// Bias correction removes any bias towards a '1' or a '0' in the bits generated.
180    /// However, this makes the generation of numbers slower.
181    ///
182    /// Defaults to disabled.
183    pub fn set_bias_correction(&self, enable: bool) {
184        self.r.config().write(|w| w.set_dercen(enable))
185    }
186
187    /// Fill the buffer with random bytes, blocking version.
188    pub fn blocking_fill_bytes(&mut self, dest: &mut [u8]) {
189        self.start();
190
191        for byte in dest.iter_mut() {
192            let regs = self.r;
193            while regs.events_valrdy().read() == 0 {}
194            regs.events_valrdy().write_value(0);
195            *byte = regs.value().read().value();
196        }
197
198        self.stop();
199    }
200
201    /// Generate a random u32
202    pub fn blocking_next_u32(&mut self) -> u32 {
203        let mut bytes = [0; 4];
204        self.blocking_fill_bytes(&mut bytes);
205        // We don't care about the endianness, so just use the native one.
206        u32::from_ne_bytes(bytes)
207    }
208
209    /// Generate a random u64
210    pub fn blocking_next_u64(&mut self) -> u64 {
211        let mut bytes = [0; 8];
212        self.blocking_fill_bytes(&mut bytes);
213        u64::from_ne_bytes(bytes)
214    }
215}
216
217impl<'d, M: Mode> Drop for Rng<'d, M> {
218    fn drop(&mut self) {
219        self.stop();
220        critical_section::with(|cs| {
221            let mut state = self.state.borrow_mut(cs);
222            state.ptr = ptr::null_mut();
223            state.end = ptr::null_mut();
224        });
225    }
226}
227
228impl<'d, M: Mode> rand_core_06::RngCore for Rng<'d, M> {
229    fn fill_bytes(&mut self, dest: &mut [u8]) {
230        self.blocking_fill_bytes(dest);
231    }
232    fn next_u32(&mut self) -> u32 {
233        self.blocking_next_u32()
234    }
235    fn next_u64(&mut self) -> u64 {
236        self.blocking_next_u64()
237    }
238    fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand_core_06::Error> {
239        self.blocking_fill_bytes(dest);
240        Ok(())
241    }
242}
243
244impl<'d, M: Mode> rand_core_06::CryptoRng for Rng<'d, M> {}
245
246impl<'d, M: Mode> rand_core_09::RngCore for Rng<'d, M> {
247    fn fill_bytes(&mut self, dest: &mut [u8]) {
248        self.blocking_fill_bytes(dest);
249    }
250    fn next_u32(&mut self) -> u32 {
251        self.blocking_next_u32()
252    }
253    fn next_u64(&mut self) -> u64 {
254        self.blocking_next_u64()
255    }
256}
257
258impl<'d, M: Mode> rand_core_09::CryptoRng for Rng<'d, M> {}
259
260/// Peripheral static state
261pub(crate) struct State {
262    inner: Mutex<RefCell<InnerState>>,
263}
264
265struct InnerState {
266    ptr: *mut u8,
267    end: *mut u8,
268    waker: WakerRegistration,
269}
270
271unsafe impl Send for InnerState {}
272
273impl State {
274    pub(crate) const fn new() -> Self {
275        Self {
276            inner: Mutex::new(RefCell::new(InnerState::new())),
277        }
278    }
279
280    fn borrow_mut<'cs>(&'cs self, cs: CriticalSection<'cs>) -> RefMut<'cs, InnerState> {
281        self.inner.borrow(cs).borrow_mut()
282    }
283}
284
285impl InnerState {
286    const fn new() -> Self {
287        Self {
288            ptr: ptr::null_mut(),
289            end: ptr::null_mut(),
290            waker: WakerRegistration::new(),
291        }
292    }
293}
294
295pub(crate) trait SealedInstance {
296    fn regs() -> pac::rng::Rng;
297    fn state() -> &'static State;
298}
299
300/// RNG peripheral instance.
301#[allow(private_bounds)]
302pub trait Instance: SealedInstance + PeripheralType + 'static + Send {
303    /// Interrupt for this peripheral.
304    type Interrupt: interrupt::typelevel::Interrupt;
305}
306
307macro_rules! impl_rng {
308    ($type:ident, $pac_type:ident, $irq:ident) => {
309        impl crate::rng::SealedInstance for peripherals::$type {
310            fn regs() -> crate::pac::rng::Rng {
311                pac::$pac_type
312            }
313            fn state() -> &'static crate::rng::State {
314                static STATE: crate::rng::State = crate::rng::State::new();
315                &STATE
316            }
317        }
318        impl crate::rng::Instance for peripherals::$type {
319            type Interrupt = crate::interrupt::typelevel::$irq;
320        }
321    };
322}