stm32g0xx_hal/
rng.rs

1use core::cmp;
2use core::mem;
3
4use crate::hal::blocking::rng;
5use crate::rcc::{Enable, Rcc, Reset};
6use crate::stm32::RNG;
7
8#[derive(Clone, Copy)]
9pub enum RngClkSource {
10    HSI = 1,
11    SysClock = 2,
12    PLLQ = 3,
13}
14
15#[derive(Clone, Copy)]
16pub enum RngClkDivider {
17    NotDivided = 0,
18    Div2 = 1,
19    Div4 = 2,
20    Div8 = 3,
21}
22
23pub struct Config {
24    clk_src: RngClkSource,
25    clk_div: RngClkDivider,
26}
27
28impl Config {
29    pub fn new(clk_src: RngClkSource) -> Self {
30        Config::default().clock_src(clk_src)
31    }
32
33    pub fn clock_src(mut self, clk_src: RngClkSource) -> Self {
34        self.clk_src = clk_src;
35        self
36    }
37
38    pub fn clock_div(mut self, clk_div: RngClkDivider) -> Self {
39        self.clk_div = clk_div;
40        self
41    }
42}
43
44impl Default for Config {
45    fn default() -> Config {
46        Config {
47            clk_src: RngClkSource::HSI,
48            clk_div: RngClkDivider::NotDivided,
49        }
50    }
51}
52
53#[derive(Debug)]
54pub enum ErrorKind {
55    ClockError,
56    SeedError,
57}
58
59pub trait RngExt {
60    fn constrain(self, cfg: Config, rcc: &mut Rcc) -> Rng;
61}
62
63impl RngExt for RNG {
64    fn constrain(self, cfg: Config, rcc: &mut Rcc) -> Rng {
65        RNG::enable(rcc);
66        RNG::reset(rcc);
67        rcc.ccipr
68            .modify(|_, w| unsafe { w.rngsel().bits(cfg.clk_src as u8) });
69        rcc.ccipr
70            .modify(|_, w| unsafe { w.rngdiv().bits(cfg.clk_div as u8) });
71        self.cr.modify(|_, w| w.rngen().set_bit());
72        Rng { rb: self }
73    }
74}
75
76pub trait RngCore<W> {
77    fn gen(&mut self) -> Result<W, ErrorKind>;
78    fn gen_range(&mut self, low: W, high: W) -> Result<W, ErrorKind>;
79    fn fill(&mut self, dest: &mut [W]) -> Result<(), ErrorKind>;
80}
81
82pub struct Rng {
83    rb: RNG,
84}
85
86impl Rng {
87    pub fn gen(&mut self) -> Result<u32, ErrorKind> {
88        loop {
89            let status = self.rb.sr.read();
90            if status.drdy().bit() {
91                return Ok(self.rb.dr.read().rndata().bits());
92            }
93            if status.cecs().bit() {
94                return Err(ErrorKind::ClockError);
95            }
96            if status.secs().bit() {
97                return Err(ErrorKind::SeedError);
98            }
99        }
100    }
101
102    pub fn release(self) -> RNG {
103        self.rb
104    }
105
106    pub fn gen_bool(&mut self) -> Result<bool, ErrorKind> {
107        let val = self.gen()?;
108        Ok(val & 1 == 1)
109    }
110
111    pub fn gen_ratio(&mut self, numerator: u32, denominator: u32) -> Result<bool, ErrorKind> {
112        assert!(denominator > 0 || denominator > numerator);
113        let val = self.gen_range(0, denominator)?;
114        Ok(numerator > val)
115    }
116
117    pub fn choose<'a, T>(&mut self, values: &'a [T]) -> Result<&'a T, ErrorKind> {
118        let val = self.gen_range(0, values.len())?;
119        Ok(&values[val])
120    }
121
122    pub fn choose_mut<'a, T>(&mut self, values: &'a mut [T]) -> Result<&'a mut T, ErrorKind> {
123        let val = self.gen_range(0, values.len())?;
124        Ok(&mut values[val])
125    }
126
127    pub fn shuffle<T>(&mut self, values: &mut [T]) -> Result<(), ErrorKind> {
128        for i in (1..values.len()).rev() {
129            values.swap(i, self.gen_range(0, i + 1)?);
130        }
131        Ok(())
132    }
133}
134
135impl core::iter::Iterator for Rng {
136    type Item = u32;
137
138    fn next(&mut self) -> Option<u32> {
139        self.gen().ok()
140    }
141}
142
143impl rng::Read for Rng {
144    type Error = ErrorKind;
145
146    fn read(&mut self, buffer: &mut [u8]) -> Result<(), Self::Error> {
147        self.fill(buffer)
148    }
149}
150
151macro_rules! rng_core {
152    ($($type:ty),+) => {
153        $(
154            impl RngCore<$type> for Rng {
155                fn gen(&mut self) -> Result<$type, ErrorKind> {
156                    let val = self.gen()?;
157                    Ok(val as $type)
158                }
159
160                // TODO: fix modulo bias
161                fn gen_range(&mut self, low: $type, high: $type) -> Result<$type, ErrorKind> {
162                    assert!(high > low);
163                    let range = high - low;
164                    let val: $type = self.gen()? as $type;
165                    Ok(low + val % range)
166                }
167
168                fn fill(&mut self, buffer: &mut [$type]) -> Result<(), ErrorKind> {
169                    const BATCH_SIZE: usize = 4 / mem::size_of::<$type>();
170                    let mut i = 0_usize;
171                    while i < buffer.len() {
172                        let random_word = self.gen()?;
173
174                        #[allow(clippy::transmute_num_to_bytes)]
175                        let bytes: [$type; BATCH_SIZE] = unsafe { mem::transmute(random_word) };
176                        let n = cmp::min(BATCH_SIZE, buffer.len() - i);
177                        buffer[i..i + n].copy_from_slice(&bytes[..n]);
178                        i += n;
179                    }
180                    Ok(())
181                }
182            }
183        )+
184    };
185}
186
187rng_core!(usize, u32, u16, u8);