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