use core::marker::PhantomData;
use cc2538_pac::{soc_adc, SocAdc};
use crate::radio::{Radio, RadioDriver, RadioOff, RadioOn, RxMode};
pub struct NotSeeded;
pub struct Seeded;
pub enum Operation {
Normal,
ClockOnce,
Stop,
}
pub struct RngDriver<'p, STATE> {
_rng: PhantomData<&'p mut SocAdc>,
_state: PhantomData<STATE>,
}
impl<STATE> RngDriver<'_, STATE> {
fn regs() -> &'static soc_adc::RegisterBlock {
unsafe { &*SocAdc::ptr() }
}
fn on(&self) {
unsafe { Self::regs().adccon1().modify(|_, w| w.rctrl().bits(0)) };
}
fn off(&self) {
unsafe { Self::regs().adccon1().modify(|_, w| w.rctrl().bits(1)) };
}
fn enable_in_low_power_mode() {
todo!()
}
}
impl<STATE> Drop for RngDriver<'_, STATE> {
fn drop(&mut self) {
self.off();
}
}
impl RngDriver<'_, Seeded> {
pub fn get_random(&self) -> u32 {
unsafe {
Self::regs()
.adccon1()
.write(|w| w.rctrl().bits(Operation::ClockOnce as u8))
};
Self::regs().rndl().read().bits() | (Self::regs().rndh().read().bits() << 8)
}
}
impl<'p> RngDriver<'p, NotSeeded> {
pub fn new_with_seed(_rng: &'p mut SocAdc, seed: u16) -> RngDriver<'p, Seeded> {
let this = Self {
_rng: PhantomData,
_state: PhantomData,
};
this.on();
unsafe {
Self::regs()
.rndl()
.write(|w| w.rndl().bits(((seed >> 8) & 0xff) as u8));
Self::regs()
.rndl()
.write(|w| w.rndl().bits((seed & 0xff) as u8));
}
RngDriver {
_rng: PhantomData,
_state: PhantomData,
}
}
pub fn new_with_radio_seed(_rng: &'p mut SocAdc, radio: &mut Radio) -> RngDriver<'p, Seeded> {
let this = Self {
_rng: PhantomData,
_state: PhantomData,
};
this.on();
let mut r = Radio::Undefined;
core::mem::swap(&mut r, radio);
let (mut r, enabled) = match r {
Radio::Off(r) => (r.enable(None), false),
Radio::On(r) => (r, true),
Radio::Undefined => unreachable!(),
};
r.set_rx_mode(RxMode::InfiniteReception);
while !r.is_rssi_valid() {}
let mut seed: u16 = 0;
while seed == 0x0000 || seed == 0x8003 {
for _ in 0..16 {
seed |= r.random_data() as u16;
seed <<= 1;
}
}
unsafe {
Self::regs()
.rndl()
.write(|w| w.rndl().bits(((seed >> 8) & 0xff) as u8));
Self::regs()
.rndl()
.write(|w| w.rndl().bits((seed & 0xff) as u8));
}
r.set_rx_mode(RxMode::Normal);
let mut r = if !enabled {
Radio::Off(r.disable())
} else {
Radio::On(r)
};
core::mem::swap(&mut r, radio);
RngDriver {
_rng: PhantomData,
_state: PhantomData,
}
}
}