use core::cell::Cell;
use kernel::deferred_call::{DeferredCall, DeferredCallClient};
use kernel::hil::date_time;
use kernel::hil::date_time::{DateTimeClient, DateTimeValues, DayOfWeek, Month};
use kernel::platform::chip::ClockInterface;
use kernel::utilities::cells::OptionalCell;
use kernel::utilities::registers::interfaces::{ReadWriteable, Readable};
use kernel::utilities::registers::{register_bitfields, ReadWrite};
use kernel::utilities::StaticRef;
use kernel::ErrorCode;
use stm32f4xx::clocks::{phclk, Stm32f4Clocks};
#[repr(C)]
pub struct RtcRegisters {
rtc_tr: ReadWrite<u32, RTC_TR::Register>,
rtc_dr: ReadWrite<u32, RTC_DR::Register>,
rtc_cr: ReadWrite<u32, RTC_CR::Register>,
rtc_isr: ReadWrite<u32, RTC_ISR::Register>,
rtc_prer: ReadWrite<u32, RTC_PRER::Register>,
rtc_wutr: ReadWrite<u32, RTC_WUTR::Register>,
rtc_calibr: ReadWrite<u32, RTC_CALIBR::Register>,
rtc_alrmar: ReadWrite<u32, RTC_ALRMAR::Register>,
rtc_alrmbr: ReadWrite<u32, RTC_ALRMBR::Register>,
rtc_wpr: ReadWrite<u32, RTC_WPR::Register>,
rtc_ssr: ReadWrite<u32, RTC_SSR::Register>,
rtc_shiftr: ReadWrite<u32, RTC_SHIFTR::Register>,
rtc_tstr: ReadWrite<u32, RTC_TSTR::Register>,
rtc_tsdr: ReadWrite<u32, RTC_TSDR::Register>,
rtc_tsssr: ReadWrite<u32, RTC_TSSSR::Register>,
rtc_calr: ReadWrite<u32, RTC_CALR::Register>,
rtc_tafcr: ReadWrite<u32, RTC_TAFCR::Register>,
rtc_alrmassr: ReadWrite<u32, RTC_ALRMASSR::Register>,
rtc_alrmbssr: ReadWrite<u32, RTC_ALRMBSSR::Register>,
rtc_bkpxr: [ReadWrite<u32, RTC_BKPXR::Register>; 19],
}
register_bitfields![u32,
RTC_TR[
PM OFFSET(22) NUMBITS(1) [],
HT OFFSET(20) NUMBITS(2) [],
HU OFFSET(16) NUMBITS(4) [],
MNT OFFSET(12) NUMBITS(3) [],
MNU OFFSET(8) NUMBITS(4) [],
ST OFFSET(4) NUMBITS(3) [],
SU OFFSET(0) NUMBITS(4) [],
],
RTC_DR[
YT OFFSET(20) NUMBITS(4) [],
YU OFFSET(16) NUMBITS(4) [],
WDU OFFSET(13) NUMBITS(3) [],
MT OFFSET(12) NUMBITS(1) [],
MU OFFSET(8) NUMBITS(4) [],
DT OFFSET(4) NUMBITS(2) [],
DU OFFSET(0) NUMBITS(4) [],
],
RTC_CR[
COE OFFSET(23) NUMBITS(1) [],
OSEL OFFSET(21) NUMBITS(2) [],
POL OFFSET(20) NUMBITS(1) [],
COSEL OFFSET(19) NUMBITS(1) [],
BKP OFFSET(18) NUMBITS(1) [],
SUB1H OFFSET(17) NUMBITS(1) [],
ADD1H OFFSET(16) NUMBITS(1) [],
TSIE OFFSET(15) NUMBITS(1) [],
WUTIE OFFSET(14) NUMBITS(1) [],
ALRBIE OFFSET(13) NUMBITS(1) [],
ALRAIE OFFSET(12) NUMBITS(1) [],
TSE OFFSET(11) NUMBITS(1) [],
WUTE OFFSET(10) NUMBITS(1) [],
ALRBE OFFSET(9) NUMBITS(1) [],
ALRAE OFFSET(8) NUMBITS(1) [],
DCE OFFSET(7) NUMBITS(1) [],
FMT OFFSET(6) NUMBITS(1) [],
BYPSHAD OFFSET(5) NUMBITS(1) [],
REFCKON OFFSET(4) NUMBITS(1) [],
TSEDGE OFFSET(3) NUMBITS(1) [],
WUCKSEL OFFSET(0) NUMBITS(3) [],
],
RTC_ISR[
RECALPF OFFSET(16) NUMBITS(1) [],
TAMP2F OFFSET(14) NUMBITS(1) [],
TAMP1F OFFSET(13) NUMBITS(1) [],
TSOVF OFFSET(12) NUMBITS(1) [],
TSF OFFSET(11) NUMBITS(1) [],
WUTF OFFSET(10) NUMBITS(1) [],
ALRBF OFFSET(9) NUMBITS(1) [],
ALRAF OFFSET(8) NUMBITS(1) [],
INIT OFFSET(7) NUMBITS(1) [],
INITF OFFSET(6) NUMBITS(1) [],
RSF OFFSET(5) NUMBITS(1) [],
INITS OFFSET(4) NUMBITS(1) [],
SHPF OFFSET(3) NUMBITS(1) [],
WUTWF OFFSET(2) NUMBITS(1) [],
ALRBWF OFFSET(1) NUMBITS(1) [],
ALRAWF OFFSET(0) NUMBITS(1) [],
],
RTC_PRER[
PREDIV_A OFFSET(16) NUMBITS(7) [],
PREDIV_S OFFSET(0) NUMBITS(15) [],
],
RTC_WUTR[
WUT OFFSET(0) NUMBITS(16) [],
],
RTC_CALIBR[
DCS OFFSET(7) NUMBITS(1) [],
DC OFFSET(0) NUMBITS(5) [],
],
RTC_ALRMAR[
MSK4 OFFSET(31) NUMBITS(1) [],
WDSEL OFFSET(30) NUMBITS(1) [],
DT OFFSET(28) NUMBITS(2) [],
DU OFFSET(24) NUMBITS(4) [],
MSK3 OFFSET(23) NUMBITS(1) [],
PM OFFSET(22) NUMBITS(1) [],
HT OFFSET(20) NUMBITS(2) [],
HU OFFSET(16) NUMBITS(4) [],
MSK2 OFFSET(15) NUMBITS(1) [],
MNT OFFSET(12) NUMBITS(3) [],
MNU OFFSET(8) NUMBITS(4) [],
MSK1 OFFSET(7) NUMBITS(1) [],
ST OFFSET(4) NUMBITS(3) [],
SU OFFSET(0) NUMBITS(4) [],
],
RTC_ALRMBR[
MSK4 OFFSET(31) NUMBITS(1) [],
WDSEL OFFSET(30) NUMBITS(1) [],
DT OFFSET(28) NUMBITS(2) [],
DU OFFSET(24) NUMBITS(4) [],
MSK3 OFFSET(23) NUMBITS(1) [],
PM OFFSET(22) NUMBITS(1) [],
HT OFFSET(20) NUMBITS(2) [],
HU OFFSET(16) NUMBITS(4) [],
MSK2 OFFSET(15) NUMBITS(1) [],
MNT OFFSET(12) NUMBITS(3) [],
MNU OFFSET(8) NUMBITS(4) [],
MSK1 OFFSET(7) NUMBITS(1) [],
ST OFFSET(4) NUMBITS(3) [],
SU OFFSET(0) NUMBITS(4) [],
],
RTC_WPR[
KEY OFFSET(0) NUMBITS(8) [],
],
RTC_SSR[
SS OFFSET(0) NUMBITS(16) [],
],
RTC_SHIFTR[
ADD1S OFFSET(31) NUMBITS(1) [],
SUBFS OFFSET(0) NUMBITS(15) [],
],
RTC_TSTR[
PM OFFSET(22) NUMBITS(1) [],
HT OFFSET(20) NUMBITS(2) [],
HU OFFSET(16) NUMBITS(4) [],
MNT OFFSET(12) NUMBITS(3) [],
MNU OFFSET(8) NUMBITS(4) [],
ST OFFSET(4) NUMBITS(3) [],
STU OFFSET(0) NUMBITS(4) [],
],
RTC_TSDR[
WDU OFFSET(13) NUMBITS(3) [],
MT OFFSET(12) NUMBITS(1) [],
MU OFFSET(8) NUMBITS(4) [],
DT OFFSET(4) NUMBITS(2) [],
DU OFFSET(0) NUMBITS(4) [],
],
RTC_TSSSR[
SS OFFSET(0) NUMBITS(16) [],
],
RTC_CALR[
CALP OFFSET(15) NUMBITS(1) [],
CALW8 OFFSET(14) NUMBITS(1) [],
CALW16 OFFSET(13) NUMBITS(1) [],
CALM OFFSET(0) NUMBITS(9) [],
],
RTC_TAFCR[
ALARMOUTTYPE OFFSET(18) NUMBITS(1) [],
TSINSEL OFFSET(17) NUMBITS(1) [],
TAMP1INSEL OFFSET(16) NUMBITS(1) [],
TAMPPUDIS OFFSET(15) NUMBITS(1) [],
TAMPPRCH OFFSET(13) NUMBITS(2) [],
TAMPFLT OFFSET(11) NUMBITS(2) [],
TAMPFREQ OFFSET(8) NUMBITS(3) [],
TAMPTS OFFSET(7) NUMBITS(1) [],
TAMP2TRG OFFSET(4) NUMBITS(1) [],
TAMP2E OFFSET(3) NUMBITS(1) [],
TAMPIE OFFSET(2) NUMBITS(1) [],
TAMP1TRG OFFSET(1) NUMBITS(1) [],
TAMP1E OFFSET(0) NUMBITS(1) [],
],
RTC_ALRMASSR[
MASKSS OFFSET(24) NUMBITS(4) [],
SS OFFSET(0) NUMBITS(15) [],
],
RTC_ALRMBSSR[
MASKSS OFFSET(24) NUMBITS(4) [],
SS OFFSET(0) NUMBITS(15) [],
],
RTC_BKPXR[
BKP OFFSET(0) NUMBITS(32) [],
],
];
pub struct Rtc<'a> {
registers: StaticRef<RtcRegisters>,
client: OptionalCell<&'a dyn date_time::DateTimeClient>,
pub clock: phclk::PeripheralClock<'a>,
pub pwr_clock: phclk::PeripheralClock<'a>,
time: Cell<DateTimeValues>,
deferred_call: DeferredCall,
deferred_call_task: OptionalCell<DeferredCallTask>,
}
#[derive(Clone, Copy)]
enum DeferredCallTask {
Get,
Set,
}
impl DeferredCallClient for Rtc<'_> {
fn handle_deferred_call(&self) {
self.deferred_call_task.take().map(|value| match value {
DeferredCallTask::Get => self
.client
.map(|client| client.get_date_time_done(Ok(self.time.get()))),
DeferredCallTask::Set => self.client.map(|client| client.set_date_time_done(Ok(()))),
});
}
fn register(&'static self) {
self.deferred_call.register(self);
}
}
const RTC_BASE: StaticRef<RtcRegisters> =
unsafe { StaticRef::new(0x40002800 as *const RtcRegisters) };
impl<'a> Rtc<'a> {
pub fn new(clocks: &'a dyn Stm32f4Clocks) -> Rtc<'a> {
Rtc {
registers: RTC_BASE,
client: OptionalCell::empty(),
clock: phclk::PeripheralClock::new(phclk::PeripheralClockType::RTC, clocks),
pwr_clock: phclk::PeripheralClock::new(phclk::PeripheralClockType::PWR, clocks),
time: Cell::new(DateTimeValues {
year: 0,
month: Month::January,
day: 1,
day_of_week: DayOfWeek::Sunday,
hour: 0,
minute: 0,
seconds: 0,
}),
deferred_call: DeferredCall::new(),
deferred_call_task: OptionalCell::empty(),
}
}
fn dotw_try_from_u32(dotw: u32) -> Result<DayOfWeek, ErrorCode> {
match dotw {
1 => Ok(DayOfWeek::Monday),
2 => Ok(DayOfWeek::Tuesday),
3 => Ok(DayOfWeek::Wednesday),
4 => Ok(DayOfWeek::Thursday),
5 => Ok(DayOfWeek::Friday),
6 => Ok(DayOfWeek::Saturday),
7 => Ok(DayOfWeek::Sunday),
_ => Err(ErrorCode::INVAL),
}
}
fn dotw_into_u32(dotw: DayOfWeek) -> u32 {
match dotw {
DayOfWeek::Monday => 1,
DayOfWeek::Tuesday => 2,
DayOfWeek::Wednesday => 3,
DayOfWeek::Thursday => 4,
DayOfWeek::Friday => 5,
DayOfWeek::Saturday => 6,
DayOfWeek::Sunday => 7,
}
}
fn month_try_from_u32(month_num: u32) -> Result<Month, ErrorCode> {
match month_num {
1 => Ok(Month::January),
2 => Ok(Month::February),
3 => Ok(Month::March),
4 => Ok(Month::April),
5 => Ok(Month::May),
6 => Ok(Month::June),
7 => Ok(Month::July),
8 => Ok(Month::August),
9 => Ok(Month::September),
10 => Ok(Month::October),
11 => Ok(Month::November),
12 => Ok(Month::December),
_ => Err(ErrorCode::INVAL),
}
}
fn month_into_u32(month: Month) -> u32 {
match month {
Month::January => 1,
Month::February => 2,
Month::March => 3,
Month::April => 4,
Month::May => 5,
Month::June => 6,
Month::July => 7,
Month::August => 8,
Month::September => 9,
Month::October => 10,
Month::November => 11,
Month::December => 12,
}
}
#[inline(never)]
fn bypass_write_protection(&self) {
self.registers.rtc_wpr.modify(RTC_WPR::KEY.val(0xCA)); self.registers.rtc_wpr.modify(RTC_WPR::KEY.val(0x53)); }
#[inline(never)]
fn enable_write_protection(&self) {
self.registers.rtc_wpr.modify(RTC_WPR::KEY.val(0x42)); }
fn date_time_setup(&self, datetime: date_time::DateTimeValues) -> Result<(), ErrorCode> {
let month_num = Rtc::month_into_u32(datetime.month);
let dotw_num = Rtc::dotw_into_u32(datetime.day_of_week);
if !(datetime.day >= 1 && datetime.day <= 31) {
return Err(ErrorCode::INVAL);
}
if !(datetime.hour <= 23) {
return Err(ErrorCode::INVAL);
}
if !(datetime.minute <= 59) {
return Err(ErrorCode::INVAL);
}
if !(datetime.seconds <= 59) {
return Err(ErrorCode::INVAL);
}
self.registers.rtc_dr.modify(
RTC_DR::YT.val((datetime.year % 100) as u32 / 10)
+ RTC_DR::YU.val((datetime.year % 100) as u32 % 10)
+ RTC_DR::MT.val(month_num / 10)
+ RTC_DR::MU.val(month_num % 10)
+ RTC_DR::DT.val(datetime.day as u32 / 10)
+ RTC_DR::DU.val(datetime.day as u32 % 10)
+ RTC_DR::WDU.val(dotw_num),
);
self.registers.rtc_tr.modify(
RTC_TR::HT.val(datetime.hour as u32 / 10)
+ RTC_TR::HU.val(datetime.hour as u32 % 10)
+ RTC_TR::MNT.val(datetime.minute as u32 / 10)
+ RTC_TR::MNU.val(datetime.minute as u32 % 10)
+ RTC_TR::ST.val(datetime.seconds as u32 / 10)
+ RTC_TR::SU.val(datetime.seconds as u32 % 10),
);
Ok(())
}
pub fn enter_init_mode(&self) -> Result<(), ErrorCode> {
self.bypass_write_protection();
self.registers.rtc_isr.modify(RTC_ISR::INIT::SET);
let mut cycle_counter = 100000;
while cycle_counter > 0 && !self.registers.rtc_isr.is_set(RTC_ISR::INITF) {
cycle_counter -= 1;
}
if cycle_counter <= 0 {
return Err(ErrorCode::FAIL);
}
Ok(())
}
pub fn exit_init_mode(&self) -> Result<(), ErrorCode> {
self.registers.rtc_isr.modify(RTC_ISR::INIT::CLEAR);
let mut cycle_counter = 100000;
while cycle_counter > 0 && !self.registers.rtc_isr.is_set(RTC_ISR::RSF) {
cycle_counter -= 1;
}
if cycle_counter <= 0 {
return Err(ErrorCode::FAIL);
}
self.enable_write_protection();
Ok(())
}
pub fn rtc_init(&self) -> Result<(), ErrorCode> {
self.enter_init_mode()?;
self.registers
.rtc_prer
.modify(RTC_PRER::PREDIV_A.val(128 - 1));
self.registers
.rtc_prer
.modify(RTC_PRER::PREDIV_S.val(256 - 1));
self.registers.rtc_cr.modify(RTC_CR::FMT.val(0));
let datetime = date_time::DateTimeValues {
year: 0,
month: Month::January,
day: 1,
day_of_week: DayOfWeek::Monday,
hour: 0,
minute: 0,
seconds: 0,
};
self.date_time_setup(datetime)?;
self.exit_init_mode()?;
Ok(())
}
pub fn enable_clock(&self) {
self.pwr_clock.enable();
match crate::pwr::enable_backup_access() {
Err(e) => panic!("{:?}", e),
_ => (),
}
self.clock.enable();
}
}
impl<'a> date_time::DateTime<'a> for Rtc<'a> {
fn get_date_time(&self) -> Result<(), ErrorCode> {
match self.deferred_call_task.take() {
Some(DeferredCallTask::Set) => {
self.deferred_call_task.insert(Some(DeferredCallTask::Set));
return Err(ErrorCode::BUSY);
}
Some(DeferredCallTask::Get) => {
self.deferred_call_task.insert(Some(DeferredCallTask::Get));
return Err(ErrorCode::ALREADY);
}
_ => (),
}
let month_num =
self.registers.rtc_dr.read(RTC_DR::MT) * 10 + self.registers.rtc_dr.read(RTC_DR::MU);
let month_name = Rtc::month_try_from_u32(month_num)?;
let dotw_num = self.registers.rtc_dr.read(RTC_DR::WDU);
let dotw_name = Rtc::dotw_try_from_u32(dotw_num)?;
let datetime = date_time::DateTimeValues {
hour: (self.registers.rtc_tr.read(RTC_TR::HT) * 10
+ self.registers.rtc_tr.read(RTC_TR::HU)) as u8,
minute: (self.registers.rtc_tr.read(RTC_TR::MNT) * 10
+ self.registers.rtc_tr.read(RTC_TR::MNU)) as u8,
seconds: (self.registers.rtc_tr.read(RTC_TR::ST) * 10
+ self.registers.rtc_tr.read(RTC_TR::SU)) as u8,
year: (self.registers.rtc_dr.read(RTC_DR::YT) * 10
+ self.registers.rtc_dr.read(RTC_DR::YU)) as u16,
month: month_name,
day: (self.registers.rtc_dr.read(RTC_DR::DT) * 10
+ self.registers.rtc_dr.read(RTC_DR::DU)) as u8,
day_of_week: dotw_name,
};
self.time.replace(datetime);
self.deferred_call_task.insert(Some(DeferredCallTask::Get));
self.deferred_call.set();
Ok(())
}
fn set_date_time(&self, date_time: date_time::DateTimeValues) -> Result<(), ErrorCode> {
match self.deferred_call_task.take() {
Some(DeferredCallTask::Set) => {
self.deferred_call_task.insert(Some(DeferredCallTask::Set));
return Err(ErrorCode::ALREADY);
}
Some(DeferredCallTask::Get) => {
self.deferred_call_task.insert(Some(DeferredCallTask::Get));
return Err(ErrorCode::BUSY);
}
_ => (),
}
self.enter_init_mode()?;
self.date_time_setup(date_time)?;
self.exit_init_mode()?;
self.deferred_call_task.insert(Some(DeferredCallTask::Set));
self.deferred_call.set();
Ok(())
}
fn set_client(&self, client: &'a dyn DateTimeClient) {
self.client.set(client);
}
}