diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2c64145a..752e0c66 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -23,7 +23,7 @@ jobs: - stm32h7b0 - stm32h735 env: # Peripheral Feature flags - FLAGS: rt,xspi,sdmmc,fmc,usb_hs,rtc,ethernet,ltdc,crc + FLAGS: rt,xspi,sdmmc,sdmmc-fatfs,fmc,usb_hs,rtc,ethernet,ltdc,crc,rand steps: - uses: actions/checkout@v2 diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 42a86bc9..dddbed3e 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -19,7 +19,7 @@ jobs: - log-semihost - log-rtt env: # Peripheral Feature flags - FLAGS: rt,xspi,sdmmc,fmc,usb_hs,rtc,ethernet,ltdc,crc + FLAGS: rt,xspi,sdmmc,sdmmc-fatfs,fmc,usb_hs,rtc,ethernet,ltdc,crc,rand steps: - uses: actions/checkout@v2 diff --git a/Cargo.toml b/Cargo.toml index b16cab0e..4952e0a0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -51,6 +51,11 @@ version = "0.4" default-features = false optional = true +[dependencies.rand_core] +version = "0.6" +default-features = false +optional = true + [dev-dependencies] cortex-m-rt = ">=0.6.15,<0.8" cortex-m-rtic = { version = "0.5.8", default-features = false, features = ["cortex-m-7"] } @@ -93,6 +98,7 @@ sdmmc-fatfs = ["embedded-sdmmc", "sdmmc"] ethernet = ["smoltcp"] rtc = ["chrono"] crc = [] +rand = ["rand_core"] rt = ["stm32h7/rt"] usb_hs = ["synopsys-usb-otg", "synopsys-usb-otg/hs"] stm32h742 = ["stm32h7/stm32h743", "device-selected", "rm0433"] diff --git a/src/lib.rs b/src/lib.rs index a0098ab9..6b99f5be 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -31,7 +31,7 @@ //! External Memory //! //! * [Flexible Memory Controller (FMC)](crate::fmc) Feature gate `fmc` -//! * [SD Card (SDMMC)](crate::sdmmc) Feature gate `sdmmc` +//! * [SD Card (SDMMC)](crate::sdmmc) Feature gate `sdmmc` (FAT16/32 driver is available under the `sdmmc-fatfs` feature gate) //! //! Timing functions //! @@ -44,7 +44,7 @@ //! Others //! //! * [Cyclic Redundancy Check (CRC)](crate::crc) Feature gate `crc` -//! * [Random Number Generator](crate::rng) +//! * [Random Number Generator](crate::rng) ([rand_core::RngCore](rand_core::RngCore) is implemented under the`rand` feature gate) //! * [System Window Watchdog](crate::watchdog) #![cfg_attr(not(test), no_std)] diff --git a/src/rng.rs b/src/rng.rs index c4a48b9d..708dbe3c 100644 --- a/src/rng.rs +++ b/src/rng.rs @@ -15,8 +15,8 @@ use crate::time::Hertz; #[derive(Debug)] pub enum ErrorKind { - ClockError, - SeedError, + ClockError = 0, + SeedError = 1, } trait KerClk { @@ -131,8 +131,112 @@ macro_rules! rng_core { }; } -rng_core!(u32, u16, u8); +// Only for types larger than 32 bits +macro_rules! rng_core_large { + ($($type:ty),+) => { + $( + impl RngCore<$type> for Rng { + fn gen(&mut self) -> Result<$type, ErrorKind> { + const WORDS: usize = mem::size_of::<$type>() / mem::size_of::(); + let mut res: $type = 0; + + for i in 0..WORDS { + res |= (self.value()? as $type) << (i * (mem::size_of::() * 8)) + } + + Ok(res) + } + + fn fill(&mut self, dest: &mut [$type]) -> Result<(), ErrorKind> { + let len = dest.len() * (mem::size_of::<$type>() / mem::size_of::()); + let ptr = dest.as_mut_ptr() as *mut u32; + let slice_u32 = unsafe { core::slice::from_raw_parts_mut(ptr, len) }; + self.fill(slice_u32) + } + } + )+ + }; +} + +macro_rules! rng_core_transmute { + ($($type:ty = $from:ty),+) => { + $( + impl RngCore<$type> for Rng { + fn gen(&mut self) -> Result<$type, ErrorKind> { + let num = >::gen(self)?; + Ok(unsafe { mem::transmute::<$from, $type>(num) }) + } -// Test host may have > 32-bit types, which we don't consider. + fn fill(&mut self, dest: &mut [$type]) -> Result<(), ErrorKind> { + let unsigned_slice = unsafe { mem::transmute::<&mut [$type], &mut [$from]>(dest) }; + >::fill(self, unsigned_slice) + } + } + )+ + }; +} + +rng_core!(u8, u16, u32); + +// Alignment of these types must be a multiple of mem::align_of::<32>() +rng_core_large!(u64, u128); + +// A and B must have the same alignment +// rng_core_transmute!(A = B) +// assert!(mem::align_of::() == mem::align_of::()) +rng_core_transmute!( + i8 = u8, + i16 = u16, + i32 = u32, + i64 = u64, + i128 = u128, + isize = usize +); + +// If usize is 32 bits, use the rng_core! impl #[cfg(target_pointer_width = "32")] rng_core!(usize); + +// If usize is 64 bits, use the rng_core_large! impl +#[cfg(target_pointer_width = "64")] +rng_core_large!(usize); + +// rand_core +#[cfg(feature = "rand")] +impl rand_core::RngCore for Rng { + /// Generate a random u32 + /// Panics if RNG fails. + fn next_u32(&mut self) -> u32 { + self.gen().unwrap() + } + + /// Generate a random u64 + /// Panics if RNG fails. + fn next_u64(&mut self) -> u64 { + self.gen().unwrap() + } + + /// Fill a slice with random data. + /// Panics if RNG fails. + fn fill_bytes(&mut self, dest: &mut [u8]) { + self.fill(dest).unwrap() + } + + /// Try to fill a slice with random data. Return an error if RNG fails. + fn try_fill_bytes( + &mut self, + dest: &mut [u8], + ) -> Result<(), rand_core::Error> { + self.fill(dest).map_err(|e| { + core::num::NonZeroU32::new( + rand_core::Error::CUSTOM_START + e as u32, + ) + // This should never fail as long as no enum variant is equal to 0 + .expect("Internal hal error") + .into() + }) + } +} + +#[cfg(feature = "rand")] +impl rand_core::CryptoRng for Rng {}