use core::cell::Cell;
use kernel::hil::time::{self, Alarm, Ticks, Time};
use kernel::utilities::cells::OptionalCell;
use kernel::utilities::registers::interfaces::{Readable, Writeable};
use kernel::utilities::registers::{register_bitfields, ReadOnly, ReadWrite, WriteOnly};
use kernel::utilities::StaticRef;
use kernel::ErrorCode;
const RTC1_BASE: StaticRef<RtcRegisters> =
unsafe { StaticRef::new(0x40011000 as *const RtcRegisters) };
#[repr(C)]
struct RtcRegisters {
tasks_start: WriteOnly<u32, Task::Register>,
tasks_stop: WriteOnly<u32, Task::Register>,
tasks_clear: WriteOnly<u32, Task::Register>,
tasks_trigovrflw: WriteOnly<u32, Task::Register>,
_reserved0: [u8; 240],
events_tick: ReadWrite<u32, Event::Register>,
events_ovrflw: ReadWrite<u32, Event::Register>,
_reserved1: [u8; 56],
events_compare: [ReadWrite<u32, Event::Register>; 4],
_reserved2: [u8; 436],
intenset: ReadWrite<u32, Inte::Register>,
intenclr: ReadWrite<u32, Inte::Register>,
_reserved3: [u8; 52],
evten: ReadWrite<u32, Inte::Register>,
evtenset: ReadWrite<u32, Inte::Register>,
evtenclr: ReadWrite<u32, Inte::Register>,
_reserved4: [u8; 440],
counter: ReadOnly<u32, Counter::Register>,
prescaler: ReadWrite<u32, Prescaler::Register>,
_reserved5: [u8; 52],
cc: [ReadWrite<u32, Counter::Register>; 4],
_reserved6: [u8; 2732],
power: ReadWrite<u32>,
}
register_bitfields![u32,
Inte [
TICK 0,
OVRFLW 1,
COMPARE0 16,
COMPARE1 17,
COMPARE2 18,
COMPARE3 19
],
Prescaler [
PRESCALER OFFSET(0) NUMBITS(12)
],
Task [
ENABLE 0
],
Event [
READY 0
],
Counter [
VALUE OFFSET(0) NUMBITS(24)
]
];
pub struct Rtc<'a> {
registers: StaticRef<RtcRegisters>,
overflow_client: OptionalCell<&'a dyn time::OverflowClient>,
alarm_client: OptionalCell<&'a dyn time::AlarmClient>,
enabled: Cell<bool>,
}
impl Rtc<'_> {
pub const fn new() -> Self {
Self {
registers: RTC1_BASE,
overflow_client: OptionalCell::empty(),
alarm_client: OptionalCell::empty(),
enabled: Cell::new(false),
}
}
pub fn handle_interrupt(&self) {
if self.registers.events_ovrflw.is_set(Event::READY) {
self.registers.events_ovrflw.write(Event::READY::CLEAR);
self.overflow_client.map(|client| client.overflow());
}
if self.registers.events_compare[0].is_set(Event::READY) {
self.registers.intenclr.write(Inte::COMPARE0::SET);
self.registers.events_compare[0].write(Event::READY::CLEAR);
self.alarm_client.map(|client| {
client.alarm();
});
}
}
}
impl Time for Rtc<'_> {
type Frequency = time::Freq32KHz;
type Ticks = time::Ticks24;
fn now(&self) -> Self::Ticks {
Self::Ticks::from(self.registers.counter.read(Counter::VALUE))
}
}
impl<'a> time::Counter<'a> for Rtc<'a> {
fn set_overflow_client(&self, client: &'a dyn time::OverflowClient) {
self.overflow_client.set(client);
self.registers.intenset.write(Inte::OVRFLW::SET);
}
fn start(&self) -> Result<(), ErrorCode> {
self.registers.prescaler.write(Prescaler::PRESCALER.val(0));
self.registers.tasks_start.write(Task::ENABLE::SET);
self.enabled.set(true);
Ok(())
}
fn stop(&self) -> Result<(), ErrorCode> {
self.registers.tasks_stop.write(Task::ENABLE::SET);
self.enabled.set(false);
Ok(())
}
fn reset(&self) -> Result<(), ErrorCode> {
self.registers.tasks_clear.write(Task::ENABLE::SET);
Ok(())
}
fn is_running(&self) -> bool {
self.enabled.get()
}
}
impl<'a> Alarm<'a> for Rtc<'a> {
fn set_alarm_client(&self, client: &'a dyn time::AlarmClient) {
self.alarm_client.set(client);
}
fn set_alarm(&self, reference: Self::Ticks, dt: Self::Ticks) {
const SYNC_TICS: u32 = 2;
let regs = &*self.registers;
let mut expire = reference.wrapping_add(dt);
let now = self.now();
let earliest_possible = now.wrapping_add(Self::Ticks::from(SYNC_TICS));
if !now.within_range(reference, expire) || expire.wrapping_sub(now).into_u32() <= SYNC_TICS
{
expire = earliest_possible;
}
regs.cc[0].write(Counter::VALUE.val(expire.into_u32()));
regs.events_compare[0].write(Event::READY::CLEAR);
regs.intenset.write(Inte::COMPARE0::SET);
}
fn get_alarm(&self) -> Self::Ticks {
Self::Ticks::from(self.registers.cc[0].read(Counter::VALUE))
}
fn disarm(&self) -> Result<(), ErrorCode> {
let regs = &*self.registers;
regs.intenclr.write(Inte::COMPARE0::SET);
regs.events_compare[0].write(Event::READY::CLEAR);
Ok(())
}
fn is_armed(&self) -> bool {
self.registers.evten.is_set(Inte::COMPARE0)
}
fn minimum_dt(&self) -> Self::Ticks {
Self::Ticks::from(10)
}
}