1
+ // Note: Code taken from stm32h7xx-hal
2
+ //! Random Number Generator
3
+ //!
4
+ //! # Examples
5
+ //!
6
+ //! - [Random Blinky](https://github.com/stm32-rs/stm32h7xx-hal/blob/master/examples/blinky_random.rs)
7
+
8
+ use core:: cmp;
9
+ use core:: mem;
10
+
11
+ use crate :: rcc:: { rec, rec:: RngClkSel } ;
12
+ use crate :: rcc:: { CoreClocks , ResetEnable } ;
13
+ use crate :: stm32:: RNG ;
14
+ use crate :: time:: Hertz ;
15
+
16
+ #[ derive( Debug ) ]
17
+ #[ cfg_attr( feature = "defmt" , derive( defmt:: Format ) ) ]
18
+ pub enum ErrorKind {
19
+ ClockError = 0 ,
20
+ SeedError = 1 ,
21
+ }
22
+
23
+ pub trait KerClk {
24
+ /// Return the kernel clock for the Random Number Generator
25
+ ///
26
+ /// # Panics
27
+ ///
28
+ /// Panics if the kernel clock is not running
29
+ fn kernel_clk_unwrap ( prec : rec:: Rng , clocks : & CoreClocks ) -> Hertz ;
30
+ }
31
+
32
+ impl KerClk for RNG {
33
+ fn kernel_clk_unwrap ( prec : rec:: Rng , clocks : & CoreClocks ) -> Hertz {
34
+ match prec. get_kernel_clk_mux ( ) {
35
+ //RngClkSel::Hsi48 => {
36
+ RngClkSel :: Hsi48Ker => {
37
+ clocks. hsi48_ck ( ) . expect ( "RNG: HSI48 must be enabled" )
38
+ }
39
+ RngClkSel :: Pll1Q => {
40
+ clocks. pll1_q_ck ( ) . expect ( "RNG: PLL1_Q must be enabled" )
41
+ }
42
+ RngClkSel :: Lse => unimplemented ! ( ) ,
43
+ RngClkSel :: Lsi => {
44
+ clocks. lsi_ck ( ) . expect ( "RNG: LSI must be enabled" )
45
+ }
46
+ }
47
+ }
48
+ }
49
+
50
+ pub trait RngExt {
51
+ fn constrain ( self , prec : rec:: Rng , clocks : & CoreClocks ) -> Rng ;
52
+ }
53
+
54
+ impl RngExt for RNG {
55
+ fn constrain ( self , prec : rec:: Rng , clocks : & CoreClocks ) -> Rng {
56
+ let prec = prec. enable ( ) . reset ( ) ;
57
+
58
+ let hclk = clocks. hclk ( ) ;
59
+ let rng_clk = Self :: kernel_clk_unwrap ( prec, clocks) ;
60
+
61
+ // Otherwise clock checker will always flag an error
62
+ // See RM0433 Rev 6 Section 33.3.6
63
+ assert ! ( rng_clk > hclk / 32 , "RNG: Clock too slow" ) ;
64
+
65
+ self . cr ( ) . modify ( |_, w| w. ced ( ) . clear_bit ( ) . rngen ( ) . set_bit ( ) ) ;
66
+
67
+ Rng { rb : self }
68
+ }
69
+ }
70
+
71
+ pub trait RngCore < W > {
72
+ fn gen ( & mut self ) -> Result < W , ErrorKind > ;
73
+ fn fill ( & mut self , dest : & mut [ W ] ) -> Result < ( ) , ErrorKind > ;
74
+ }
75
+
76
+ pub struct Rng {
77
+ rb : RNG ,
78
+ }
79
+
80
+ impl Rng {
81
+ /// Returns 32 bits of randomness, or error
82
+ pub fn value ( & mut self ) -> Result < u32 , ErrorKind > {
83
+ loop {
84
+ let status = self . rb . sr ( ) . read ( ) ;
85
+ if status. cecs ( ) . bit ( ) {
86
+ return Err ( ErrorKind :: ClockError ) ;
87
+ }
88
+ if status. secs ( ) . bit ( ) {
89
+ return Err ( ErrorKind :: SeedError ) ;
90
+ }
91
+ if status. drdy ( ) . bit ( ) {
92
+ return Ok ( self . rb . dr ( ) . read ( ) . rndata ( ) . bits ( ) ) ;
93
+ }
94
+ }
95
+ }
96
+
97
+ pub fn release ( self ) -> RNG {
98
+ self . rb
99
+ }
100
+
101
+ /// Returns a reference to the inner peripheral
102
+ pub fn inner ( & self ) -> & RNG {
103
+ & self . rb
104
+ }
105
+
106
+ /// Returns a mutable reference to the inner peripheral
107
+ pub fn inner_mut ( & mut self ) -> & mut RNG {
108
+ & mut self . rb
109
+ }
110
+ }
111
+
112
+ impl core:: iter:: Iterator for Rng {
113
+ type Item = u32 ;
114
+
115
+ fn next ( & mut self ) -> Option < u32 > {
116
+ self . value ( ) . ok ( )
117
+ }
118
+ }
119
+
120
+ macro_rules! rng_core {
121
+ ( $( $type: ty) ,+) => {
122
+ $(
123
+ impl RngCore <$type> for Rng {
124
+ /// Returns a single element with random value, or error
125
+ fn gen ( & mut self ) -> Result <$type, ErrorKind > {
126
+ let val = self . value( ) ?;
127
+ Ok ( val as $type)
128
+ }
129
+
130
+ /// Fills buffer with random values, or return error
131
+ fn fill( & mut self , buffer: & mut [ $type] ) -> Result <( ) , ErrorKind > {
132
+ const BATCH_SIZE : usize = 4 / mem:: size_of:: <$type>( ) ;
133
+ let mut i = 0_usize ;
134
+ while i < buffer. len( ) {
135
+ let random_word = self . value( ) ?;
136
+
137
+ // using to_ne_bytes does not work for u8 and would make the macro
138
+ // implementation more complicated
139
+ #[ allow( clippy:: transmute_num_to_bytes) ]
140
+ let bytes: [ $type; BATCH_SIZE ] = unsafe { mem:: transmute( random_word) } ;
141
+ let n = cmp:: min( BATCH_SIZE , buffer. len( ) - i) ;
142
+ buffer[ i..i + n] . copy_from_slice( & bytes[ ..n] ) ;
143
+ i += n;
144
+ }
145
+ Ok ( ( ) )
146
+ }
147
+ }
148
+ ) +
149
+ } ;
150
+ }
151
+
152
+ // Only for types larger than 32 bits
153
+ macro_rules! rng_core_large {
154
+ ( $( $type: ty) ,+) => {
155
+ $(
156
+ impl RngCore <$type> for Rng {
157
+ fn gen ( & mut self ) -> Result <$type, ErrorKind > {
158
+ const WORDS : usize = mem:: size_of:: <$type>( ) / mem:: size_of:: <u32 >( ) ;
159
+ let mut res: $type = 0 ;
160
+
161
+ for i in 0 ..WORDS {
162
+ res |= ( self . value( ) ? as $type) << ( i * ( mem:: size_of:: <u32 >( ) * 8 ) )
163
+ }
164
+
165
+ Ok ( res)
166
+ }
167
+
168
+ fn fill( & mut self , dest: & mut [ $type] ) -> Result <( ) , ErrorKind > {
169
+ let len = dest. len( ) * ( mem:: size_of:: <$type>( ) / mem:: size_of:: <u32 >( ) ) ;
170
+ let ptr = dest. as_mut_ptr( ) as * mut u32 ;
171
+ let slice_u32 = unsafe { core:: slice:: from_raw_parts_mut( ptr, len) } ;
172
+ self . fill( slice_u32)
173
+ }
174
+ }
175
+ ) +
176
+ } ;
177
+ }
178
+
179
+ macro_rules! rng_core_transmute {
180
+ ( $( $type: ty = $from: ty) ,+) => {
181
+ $(
182
+ impl RngCore <$type> for Rng {
183
+ fn gen ( & mut self ) -> Result <$type, ErrorKind > {
184
+ let num = <Self as RngCore <$from>>:: gen ( self ) ?;
185
+ Ok ( unsafe { mem:: transmute:: <$from, $type>( num) } )
186
+ }
187
+
188
+ fn fill( & mut self , dest: & mut [ $type] ) -> Result <( ) , ErrorKind > {
189
+ let unsigned_slice = unsafe { mem:: transmute:: <& mut [ $type] , & mut [ $from] >( dest) } ;
190
+ <Self as RngCore <$from>>:: fill( self , unsigned_slice)
191
+ }
192
+ }
193
+ ) +
194
+ } ;
195
+ }
196
+
197
+ rng_core ! ( u8 , u16 , u32 ) ;
198
+
199
+ // Alignment of these types must be a multiple of mem::align_of::<32>()
200
+ rng_core_large ! ( u64 , u128 ) ;
201
+
202
+ // A and B must have the same alignment
203
+ // rng_core_transmute!(A = B)
204
+ // assert!(mem::align_of::<A>() == mem::align_of::<B>())
205
+ rng_core_transmute ! (
206
+ i8 = u8 ,
207
+ i16 = u16 ,
208
+ i32 = u32 ,
209
+ i64 = u64 ,
210
+ i128 = u128 ,
211
+ isize = usize
212
+ ) ;
213
+
214
+ // If usize is 32 bits, use the rng_core! impl
215
+ #[ cfg( target_pointer_width = "32" ) ]
216
+ rng_core ! ( usize ) ;
217
+
218
+ // If usize is 64 bits, use the rng_core_large! impl
219
+ #[ cfg( target_pointer_width = "64" ) ]
220
+ rng_core_large ! ( usize ) ;
221
+
222
+ // rand_core
223
+ #[ cfg( feature = "rand" ) ]
224
+ #[ cfg_attr( docsrs, doc( cfg( feature = "rand" ) ) ) ]
225
+ impl rand_core:: RngCore for Rng {
226
+ /// Generate a random u32
227
+ /// Panics if RNG fails.
228
+ fn next_u32 ( & mut self ) -> u32 {
229
+ self . gen ( ) . unwrap ( )
230
+ }
231
+
232
+ /// Generate a random u64
233
+ /// Panics if RNG fails.
234
+ fn next_u64 ( & mut self ) -> u64 {
235
+ self . gen ( ) . unwrap ( )
236
+ }
237
+
238
+ /// Fill a slice with random data.
239
+ /// Panics if RNG fails.
240
+ fn fill_bytes ( & mut self , dest : & mut [ u8 ] ) {
241
+ self . fill ( dest) . unwrap ( )
242
+ }
243
+
244
+ /// Try to fill a slice with random data. Return an error if RNG fails.
245
+ fn try_fill_bytes (
246
+ & mut self ,
247
+ dest : & mut [ u8 ] ,
248
+ ) -> Result < ( ) , rand_core:: Error > {
249
+ self . fill ( dest) . map_err ( |e| {
250
+ core:: num:: NonZeroU32 :: new (
251
+ rand_core:: Error :: CUSTOM_START + e as u32 ,
252
+ )
253
+ // This should never fail as long as no enum variant is equal to 0
254
+ . expect ( "Internal hal error" )
255
+ . into ( )
256
+ } )
257
+ }
258
+ }
259
+
260
+ #[ cfg( feature = "rand" ) ]
261
+ #[ cfg_attr( docsrs, doc( cfg( feature = "rand" ) ) ) ]
262
+ impl rand_core:: CryptoRng for Rng { }
0 commit comments