zodiac 0.3.0

Rust OS framework that offers safe interfaces for kernel development
Documentation
use time::PrimitiveDateTime;
use time::{Date, Month, Time};
use x86_64::instructions::port::Port;

#[derive(Debug)]
pub struct RtcDateTime {
    second: u8,
    minute: u8,
    hour: u8,
    day: u8,
    month: u8,
    year: u8,
}

impl Default for RtcDateTime {
    fn default() -> Self {
        let mut time = Self {
            second: Self::read_rtc(0x00),
            minute: Self::read_rtc(0x02),
            hour: Self::read_rtc(0x04),
            day: Self::read_rtc(0x07),
            month: Self::read_rtc(0x08),
            year: Self::read_rtc(0x09),
        };

        let format = Self::read_rtc(0x0b);
        let is_24_hour = format & (1 << 1) != 0;
        let is_binary = format & (1 << 2) != 0;

        if !is_binary {
            time.second = Self::bcd_to_bin(time.second);
            time.minute = Self::bcd_to_bin(time.minute);
            time.hour = Self::bcd_to_bin(time.hour);
            time.day = Self::bcd_to_bin(time.day);
            time.month = Self::bcd_to_bin(time.month);
            time.year = Self::bcd_to_bin(time.year);
        }

        if !is_24_hour {
            let is_pm = time.hour & 0x80 != 0;
            time.hour = (time.hour & 0x7F) % 12 + 12 * is_pm as u8;
        }

        time
    }
}

impl RtcDateTime {
    fn read_rtc(idx: u8) -> u8 {
        unsafe {
            Port::new(0x70).write(idx);
            Port::new(0x71).read()
        }
    }

    fn bcd_to_bin(bcd: u8) -> u8 {
        let msb = bcd & 0x80;
        let value = bcd & 0x7F;
        ((value / 16 * 10) + (value % 16)) | msb
    }

    pub fn unix_timestamp(&self) -> i64 {
        let month = Month::try_from(self.month).unwrap();
        let date = Date::from_calendar_date(2000 + self.year as i32, month, self.day).unwrap();
        let time = Time::from_hms(self.hour, self.minute, self.second).unwrap();
        PrimitiveDateTime::new(date, time)
            .assume_utc()
            .unix_timestamp()
    }
}