#![cfg_attr(not(test), no_std)]
#![deny(
clippy::missing_safety_doc,
clippy::undocumented_unsafe_blocks,
unsafe_op_in_unsafe_fn
)]
#[cfg(feature = "chrono")]
mod chrono;
use core::ptr::{addr_of, addr_of_mut};
#[derive(Default)]
#[repr(C, align(4))]
struct Registers {
dr: u32,
mr: u32,
lr: u32,
cr: u8,
_reserved0: [u8; 3],
imsc: u8,
_reserved1: [u8; 3],
ris: u8,
_reserved2: [u8; 3],
mis: u8,
_reserved3: [u8; 3],
icr: u8,
_reserved4: [u8; 3],
}
pub struct Rtc {
registers: *mut Registers,
}
impl Rtc {
pub unsafe fn new(base_address: *mut u32) -> Self {
Rtc {
registers: base_address as _,
}
}
pub fn get_unix_timestamp(&self) -> u32 {
unsafe { addr_of!((*self.registers).dr).read_volatile() }
}
pub fn set_unix_timestamp(&mut self, unix_time: u32) {
unsafe { addr_of_mut!((*self.registers).lr).write_volatile(unix_time) }
}
pub fn set_match_timestamp(&mut self, match_timestamp: u32) {
unsafe { addr_of_mut!((*self.registers).mr).write_volatile(match_timestamp) }
}
pub fn matched(&self) -> bool {
let ris = unsafe { addr_of!((*self.registers).ris).read_volatile() };
(ris & 0x01) != 0
}
pub fn interrupt_pending(&self) -> bool {
let ris = unsafe { addr_of!((*self.registers).mis).read_volatile() };
(ris & 0x01) != 0
}
pub fn enable_interrupt(&mut self, mask: bool) {
let imsc = if mask { 0x01 } else { 0x00 };
unsafe { addr_of_mut!((*self.registers).imsc).write_volatile(imsc) }
}
pub fn clear_interrupt(&mut self) {
unsafe { addr_of_mut!((*self.registers).icr).write_volatile(0x01) }
}
}
unsafe impl Send for Rtc {}
unsafe impl Sync for Rtc {}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_get_timestamp() {
let mut registers = Registers {
dr: 12345678,
..Registers::default()
};
let rtc = unsafe { Rtc::new(&mut registers as *mut Registers as _) };
assert_eq!(rtc.get_unix_timestamp(), 12345678);
}
#[test]
fn test_set_timestamp() {
let mut registers = Registers::default();
let mut rtc = unsafe { Rtc::new(&mut registers as *mut Registers as _) };
rtc.set_unix_timestamp(424242);
drop(rtc);
assert_eq!(registers.lr, 424242);
}
}