use portable_atomic::{AtomicUsize, Ordering};
static TRNG_ENABLED: AtomicUsize = AtomicUsize::new(0);
static TRNG_USERS: AtomicUsize = AtomicUsize::new(0);
use super::Rng;
use crate::peripherals::{ADC1, RNG};
#[instability::unstable]
pub struct TrngSource<'d> {
_rng: RNG<'d>,
_adc: ADC1<'d>,
}
impl<'d> TrngSource<'d> {
#[instability::unstable]
pub fn new(_rng: RNG<'d>, _adc: ADC1<'d>) -> Self {
crate::soc::trng::ensure_randomness();
unsafe { Self::increase_entropy_source_counter() }
Self { _rng, _adc }
}
#[instability::unstable]
pub unsafe fn increase_entropy_source_counter() {
if TRNG_ENABLED.fetch_add(1, Ordering::Relaxed) == usize::MAX {
panic!("TrngSource enable overflowed");
}
}
#[instability::unstable]
pub fn decrease_entropy_source_counter(_private: crate::private::Internal) {
match TRNG_ENABLED.fetch_sub(1, Ordering::Relaxed) {
0 => panic!("TrngSource is not active"),
1 => assert!(
TRNG_USERS.load(Ordering::Acquire) == 0,
"TRNG cannot be disabled while it's in use"
),
_ => {}
}
}
#[instability::unstable]
pub fn is_enabled() -> bool {
TRNG_ENABLED.load(Ordering::Relaxed) > 0
}
#[instability::unstable]
pub fn try_disable(self) -> Result<(), Self> {
if TRNG_ENABLED
.fetch_update(Ordering::Relaxed, Ordering::Relaxed, |enabled| {
assert!(enabled > 0, "TrngSource is not active");
if TRNG_USERS.load(Ordering::Acquire) > 0 {
return None;
}
Some(enabled - 1)
})
.is_err()
{
return Err(self);
}
core::mem::forget(self);
Ok(())
}
}
impl Drop for TrngSource<'_> {
fn drop(&mut self) {
Self::decrease_entropy_source_counter(crate::private::Internal);
crate::soc::trng::revert_trng();
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[non_exhaustive]
#[instability::unstable]
pub enum TrngError {
TrngSourceNotEnabled,
}
#[cfg_attr(docsrs, procmacros::doc_replace(
"analog_pin" => {
cfg(esp32) => "GPIO32",
_ => "GPIO3"
}
))]
#[derive(Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[non_exhaustive]
#[instability::unstable]
pub struct Trng {
rng: Rng,
}
impl Clone for Trng {
#[inline]
fn clone(&self) -> Self {
TRNG_USERS.fetch_add(1, Ordering::Acquire);
Self { rng: self.rng }
}
}
impl Trng {
#[inline]
#[instability::unstable]
pub fn try_new() -> Result<Self, TrngError> {
TRNG_USERS.fetch_add(1, Ordering::Acquire);
let this = Self { rng: Rng::new() };
if TRNG_ENABLED.load(Ordering::Acquire) == 0 {
return Err(TrngError::TrngSourceNotEnabled);
}
Ok(this)
}
#[inline]
#[instability::unstable]
pub fn random(&self) -> u32 {
self.rng.random()
}
#[inline]
#[instability::unstable]
pub fn read(&self, buffer: &mut [u8]) {
self.rng.read(buffer);
}
#[inline]
#[instability::unstable]
pub fn downgrade(self) -> Rng {
Rng::new()
}
}
impl Drop for Trng {
fn drop(&mut self) {
TRNG_USERS.fetch_sub(1, Ordering::Release);
}
}
#[instability::unstable]
impl rand_core_06::RngCore for Trng {
fn next_u32(&mut self) -> u32 {
<Rng as rand_core_06::RngCore>::next_u32(&mut self.rng)
}
fn next_u64(&mut self) -> u64 {
<Rng as rand_core_06::RngCore>::next_u64(&mut self.rng)
}
fn fill_bytes(&mut self, dest: &mut [u8]) {
<Rng as rand_core_06::RngCore>::fill_bytes(&mut self.rng, dest)
}
fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand_core_06::Error> {
<Rng as rand_core_06::RngCore>::try_fill_bytes(&mut self.rng, dest)
}
}
#[instability::unstable]
impl rand_core_09::RngCore for Trng {
fn next_u32(&mut self) -> u32 {
<Rng as rand_core_09::RngCore>::next_u32(&mut self.rng)
}
fn next_u64(&mut self) -> u64 {
<Rng as rand_core_09::RngCore>::next_u64(&mut self.rng)
}
fn fill_bytes(&mut self, dest: &mut [u8]) {
<Rng as rand_core_09::RngCore>::fill_bytes(&mut self.rng, dest)
}
}
#[instability::unstable]
impl rand_core_06::CryptoRng for Trng {}
#[instability::unstable]
impl rand_core_09::CryptoRng for Trng {}
#[instability::unstable]
impl rand_core_010::TryRng for Trng {
type Error = core::convert::Infallible;
fn try_next_u32(&mut self) -> Result<u32, Self::Error> {
<Rng as rand_core_010::TryRng>::try_next_u32(&mut self.rng)
}
fn try_next_u64(&mut self) -> Result<u64, Self::Error> {
<Rng as rand_core_010::TryRng>::try_next_u64(&mut self.rng)
}
fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Self::Error> {
<Rng as rand_core_010::TryRng>::try_fill_bytes(&mut self.rng, dest)
}
}
#[instability::unstable]
impl rand_core_010::TryCryptoRng for Trng {}