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 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);