stm32l4xx_hal/
rng.rs

1extern crate core;
2#[cfg(feature = "unproven")]
3use core::cmp;
4
5use crate::rcc::{Clocks, Enable, AHB2};
6use crate::stm32::RNG;
7pub use rand_core::{CryptoRng, RngCore};
8
9/// Extension trait to activate the RNG
10pub trait RngExt {
11    /// Enables the RNG
12    fn enable(self, ahb2: &mut AHB2, clocks: Clocks) -> Rng;
13}
14
15impl RngExt for RNG {
16    fn enable(self, ahb2: &mut AHB2, clocks: Clocks) -> Rng {
17        // crrcr.crrcr().modify(|_, w| w.hsi48on().set_bit()); // p. 180 in ref-manual
18        // ...this is now supposed to be done in RCC configuration before freezing
19
20        // hsi48 should be turned on previously or msi at 48mhz
21        let msi = match clocks.msi() {
22            Some(msi) => msi == crate::rcc::MsiFreq::RANGE48M,
23            None => false,
24        };
25        let hsi = clocks.hsi48();
26        assert!(msi || hsi);
27
28        <RNG as Enable>::enable(ahb2);
29        // if we don't do this... we can be "too fast", and
30        // the following setting of rng.cr.rngen has no effect!!
31        while !RNG::is_enabled() {}
32
33        self.cr.modify(|_, w| w.rngen().set_bit());
34
35        Rng { rng: self }
36    }
37}
38
39/// Constrained RNG peripheral
40pub struct Rng {
41    rng: RNG,
42}
43
44impl Rng {
45    // cf. https://github.com/nrf-rs/nrf51-hal/blob/master/src/rng.rs#L31
46    pub fn free(self) -> RNG {
47        // maybe disable the RNG?
48        self.rng
49    }
50
51    // various methods that are not in the blessed embedded_hal
52    // trait list, but may be helpful nonetheless
53    // Q: should these be prefixed by underscores?
54
55    pub fn get_random_data(&self) -> u32 {
56        while !self.is_data_ready() {}
57        self.possibly_invalid_random_data()
58        // NB: no need to clear bit here
59    }
60
61    // RNG_CR
62    /* missing in stm32l4...
63    pub fn is_clock_error_detection_enabled(&self) -> bool {
64        self.rng.cr.read().ced().bit()
65    }
66    */
67
68    pub fn is_interrupt_enabled(&self) -> bool {
69        self.rng.cr.read().ie().bit()
70    }
71
72    pub fn is_enabled(&self) -> bool {
73        self.rng.cr.read().rngen().bit()
74    }
75
76    // RNG_SR
77    pub fn is_clock_error(&self) -> bool {
78        self.rng.sr.read().cecs().bit()
79    }
80
81    pub fn is_seed_error(&self) -> bool {
82        self.rng.sr.read().secs().bit()
83    }
84
85    pub fn is_data_ready(&self) -> bool {
86        self.rng.sr.read().drdy().bit()
87    }
88
89    // RNG_DR
90    pub fn possibly_invalid_random_data(&self) -> u32 {
91        self.rng.dr.read().rndata().bits()
92    }
93}
94
95impl RngCore for Rng {
96    fn next_u32(&mut self) -> u32 {
97        self.get_random_data()
98    }
99
100    fn next_u64(&mut self) -> u64 {
101        rand_core::impls::next_u64_via_u32(self)
102    }
103
104    fn fill_bytes(&mut self, dest: &mut [u8]) {
105        rand_core::impls::fill_bytes_via_next(self, dest)
106    }
107
108    fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand_core::Error> {
109        Ok(self.fill_bytes(dest))
110    }
111}
112
113impl CryptoRng for Rng {}
114
115#[derive(Debug)]
116pub enum Error {}
117
118#[cfg(feature = "unproven")]
119impl crate::hal::blocking::rng::Read for Rng {
120    // TODO: this error seems pretty useless if it
121    // doesn't flag non-enabled RNG or non-started HSI48,
122    // but that would be a runtime cost :/
123    type Error = Error;
124
125    fn read(&mut self, buffer: &mut [u8]) -> Result<(), Self::Error> {
126        let mut i = 0usize;
127        while i < buffer.len() {
128            let random_word: u32 = self.get_random_data();
129            let bytes: [u8; 4] = random_word.to_ne_bytes();
130            let n = cmp::min(4, buffer.len() - i);
131            buffer[i..i + n].copy_from_slice(&bytes[..n]);
132            i += n;
133        }
134
135        Ok(())
136    }
137}