#![macro_use]
use core::cell::{RefCell, RefMut};
use core::future::poll_fn;
use core::marker::PhantomData;
use core::ptr;
use core::task::Poll;
use critical_section::{CriticalSection, Mutex};
#[cfg(feature = "_nrf5340-app")]
use embassy_futures::{select::select, yield_now};
use embassy_hal_internal::drop::OnDrop;
use embassy_hal_internal::{Peri, PeripheralType};
use embassy_sync::waitqueue::WakerRegistration;
use crate::interrupt::typelevel::Interrupt;
use crate::mode::{Async, Blocking, Mode};
use crate::{interrupt, pac};
pub struct InterruptHandler<T: Instance> {
_phantom: PhantomData<T>,
}
impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
unsafe fn on_interrupt() {
let r = T::regs();
r.rng_icr().write(|w| w.set_ehr_valid_clear(true));
pac::CC_HOST_RGF.icr().write(|w| w.set_rng_clear(true));
critical_section::with(|cs| {
let mut state = T::state().borrow_mut(cs);
if !state.ptr.is_null() && state.ptr != state.end {
for i in 0..6 {
let bytes = r.ehr_data(i).read().to_ne_bytes();
for b in bytes {
unsafe {
*state.ptr = b;
state.ptr = state.ptr.add(1);
}
if state.ptr == state.end {
state.waker.wake();
return;
}
}
}
}
});
}
}
pub struct CcRng<'d, M: Mode> {
r: pac::cc_rng::CcRng,
state: &'static State,
_phantom: PhantomData<(&'d (), M)>,
}
impl<'d> CcRng<'d, Blocking> {
pub fn new_blocking<T: Instance>(_rng: Peri<'d, T>) -> Self {
let this = Self {
r: T::regs(),
state: T::state(),
_phantom: PhantomData,
};
this.stop();
this
}
}
impl<'d> CcRng<'d, Async> {
pub fn new<T: Instance>(
_rng: Peri<'d, T>,
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
) -> Self {
let this = Self {
r: T::regs(),
state: T::state(),
_phantom: PhantomData,
};
this.disable_irq();
this.stop();
T::Interrupt::unpend();
unsafe { T::Interrupt::enable() };
this
}
fn enable_irq(&self) {
pac::CC_HOST_RGF
.imr()
.modify(|w| w.set_rng_mask(pac::cc_host_rgf::vals::RngMask::IRQENABLE));
self.r
.rng_imr()
.modify(|w| w.set_ehr_valid_mask(pac::cc_rng::vals::EhrValidMask::IRQENABLE));
}
fn disable_irq(&self) {
self.r.rng_icr().write(|w| w.set_ehr_valid_clear(true));
pac::CC_HOST_RGF.icr().write(|w| w.set_rng_clear(true));
self.r
.rng_imr()
.modify(|w| w.set_ehr_valid_mask(pac::cc_rng::vals::EhrValidMask::IRQDISABLE));
pac::CC_HOST_RGF
.imr()
.modify(|w| w.set_rng_mask(pac::cc_host_rgf::vals::RngMask::IRQDISABLE));
}
pub async fn fill_bytes(&mut self, dest: &mut [u8]) {
if dest.is_empty() {
return; }
let range = dest.as_mut_ptr_range();
let state = self.state;
critical_section::with(|cs| {
let mut state = state.borrow_mut(cs);
state.ptr = range.start;
state.end = range.end;
});
self.start();
self.enable_irq();
let on_drop = OnDrop::new(|| {
self.disable_irq();
self.stop();
critical_section::with(|cs| {
let mut state = state.borrow_mut(cs);
state.ptr = ptr::null_mut();
state.end = ptr::null_mut();
});
});
let fill_future = poll_fn(|cx| {
critical_section::with(|cs| {
let mut s = state.borrow_mut(cs);
s.waker.register(cx.waker());
if s.ptr == s.end {
Poll::Ready(())
} else {
Poll::Pending
}
})
});
#[cfg(feature = "_nrf5340-app")]
let _ = select(fill_future, async {
loop {
let _ = pac::CRYPTOCELL.enable().read().enable();
yield_now().await;
}
})
.await;
#[cfg(not(feature = "_nrf5340-app"))]
fill_future.await;
drop(on_drop);
}
}
impl<'d, M: Mode> CcRng<'d, M> {
fn start(&self) {
if !pac::CRYPTOCELL.enable().read().enable() {
pac::CRYPTOCELL.enable().write(|w| w.set_enable(true));
}
self.r.rng_clk().write(|w| w.set_enable(true));
self.r.rng_sw_reset().write(|w| w.set_reset(true));
loop {
self.r.rng_clk().write(|w| w.set_enable(true));
self.r.sample_cnt().write_value(pac::FICR.trng90b().rosc1().read());
if self.r.sample_cnt().read() == pac::FICR.trng90b().rosc1().read() {
break;
};
}
self.r
.trng_config()
.modify(|w| w.set_rosc_len(pac::cc_rng::vals::TrngConfigRoscLen::ROSC1));
self.r.noise_source().modify(|w| w.set_enable(true));
}
fn stop(&self) {
self.r.noise_source().modify(|w| w.set_enable(false));
self.r.rng_clk().write(|w| w.set_enable(false));
}
pub fn blocking_fill_bytes(&mut self, dest: &mut [u8]) {
self.start();
self.inner_fill_bytes(dest);
self.stop();
}
fn inner_fill_bytes(&mut self, dest: &mut [u8]) {
let mut index = 0;
while index < dest.len() {
while !self.r.rng_isr().read().ehr_valid_int() {}
self.r.rng_icr().write(|w| w.set_ehr_valid_clear(true));
for i in 0..6 {
let bytes = self.r.ehr_data(i).read().to_ne_bytes();
for b in bytes {
dest[index] = b;
index += 1;
if index >= dest.len() {
return;
}
}
}
}
}
pub fn blocking_next_u32(&mut self) -> u32 {
let mut bytes = [0; 4];
self.blocking_fill_bytes(&mut bytes);
u32::from_ne_bytes(bytes)
}
pub fn blocking_next_u64(&mut self) -> u64 {
let mut bytes = [0; 8];
self.blocking_fill_bytes(&mut bytes);
u64::from_ne_bytes(bytes)
}
}
impl<'d, M: Mode> Drop for CcRng<'d, M> {
fn drop(&mut self) {
self.stop();
critical_section::with(|cs| {
let mut state = self.state.borrow_mut(cs);
state.ptr = ptr::null_mut();
state.end = ptr::null_mut();
});
}
}
impl<'d, M: Mode> rand_core_06::RngCore for CcRng<'d, M> {
fn fill_bytes(&mut self, dest: &mut [u8]) {
self.blocking_fill_bytes(dest);
}
fn next_u32(&mut self) -> u32 {
self.blocking_next_u32()
}
fn next_u64(&mut self) -> u64 {
self.blocking_next_u64()
}
fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand_core_06::Error> {
self.blocking_fill_bytes(dest);
Ok(())
}
}
impl<'d, M: Mode> rand_core_06::CryptoRng for CcRng<'d, M> {}
impl<'d, M: Mode> rand_core_09::RngCore for CcRng<'d, M> {
fn fill_bytes(&mut self, dest: &mut [u8]) {
self.blocking_fill_bytes(dest);
}
fn next_u32(&mut self) -> u32 {
self.blocking_next_u32()
}
fn next_u64(&mut self) -> u64 {
self.blocking_next_u64()
}
}
impl<'d, M: Mode> rand_core_09::CryptoRng for CcRng<'d, M> {}
pub(crate) struct State {
inner: Mutex<RefCell<InnerState>>,
}
struct InnerState {
ptr: *mut u8,
end: *mut u8,
waker: WakerRegistration,
}
unsafe impl Send for InnerState {}
impl State {
pub(crate) const fn new() -> Self {
Self {
inner: Mutex::new(RefCell::new(InnerState::new())),
}
}
fn borrow_mut<'cs>(&'cs self, cs: CriticalSection<'cs>) -> RefMut<'cs, InnerState> {
self.inner.borrow(cs).borrow_mut()
}
}
impl InnerState {
const fn new() -> Self {
Self {
ptr: ptr::null_mut(),
end: ptr::null_mut(),
waker: WakerRegistration::new(),
}
}
}
pub(crate) trait SealedInstance {
fn regs() -> pac::cc_rng::CcRng;
fn state() -> &'static State;
}
#[allow(private_bounds)]
pub trait Instance: SealedInstance + PeripheralType + 'static + Send {
type Interrupt: interrupt::typelevel::Interrupt;
}
macro_rules! impl_ccrng {
($type:ident, $pac_type:ident, $irq:ident) => {
impl crate::cryptocell_rng::SealedInstance for peripherals::$type {
fn regs() -> pac::cc_rng::CcRng {
pac::$pac_type
}
fn state() -> &'static crate::cryptocell_rng::State {
static STATE: crate::cryptocell_rng::State = crate::cryptocell_rng::State::new();
&STATE
}
}
impl crate::cryptocell_rng::Instance for peripherals::$type {
type Interrupt = crate::interrupt::typelevel::$irq;
}
};
}