use crate::{formatter::ByteMutWriter, log::LoggableClockData};
use core::fmt::{Debug, Write};
#[derive(Debug, Copy, Clone, Default)]
pub struct ClockData {
pub hundredths: u8,
pub seconds: u8,
pub minutes: u8,
pub hours: u8,
pub weekday: u8,
pub date: u8,
pub month: u8,
pub year: u8,
}
impl ClockData {
#[must_use]
pub fn new() -> ClockData {
ClockData {
..Default::default()
}
}
#[must_use]
pub fn hundredths(&self) -> u8 {
self.hundredths
}
#[must_use]
pub fn seconds(&self) -> u8 {
self.seconds
}
#[must_use]
pub fn minutes(&self) -> u8 {
self.minutes
}
#[must_use]
pub fn hours(&self) -> u8 {
self.hours
}
#[must_use]
pub fn weekday(&self) -> u8 {
self.weekday
}
#[must_use]
pub fn date(&self) -> u8 {
self.date
}
#[must_use]
pub fn month(&self) -> u8 {
self.month
}
#[must_use]
pub fn year(&self) -> u8 {
self.year
}
pub fn set(&mut self, value: &ClockData) {
*self = *value;
}
fn _set(&mut self, value: (u8, u8, u8, Weekday, u8, Month, CurrentYear)) {
let (hours, minutes, seconds, weekday, day, month, year) = value;
self.hundredths = 0;
self.hours = hours;
self.minutes = minutes;
self.seconds = seconds;
self.weekday = weekday as u8;
self.date = day;
self.month = month as u8;
self.year = year.0;
}
}
#[derive(Debug, Default)]
pub struct CurrentYear(u8);
impl CurrentYear {
pub fn new(value: u16) -> Self {
if value < 1970 {
panic!("Year must be greater than 1970");
}
if value < 2000 {
Self((value - 1900) as u8)
} else {
Self((value - 2000) as u8)
}
}
}
impl defmt::Format for LoggableClockData {
fn format(&self, fmt: defmt::Formatter) {
let data = self.data();
let mut buf = [0u8; 2];
let mut buf = ByteMutWriter::new(&mut buf[..]);
let hours = left_pad(&mut buf, data.hours);
let mut buf = [0u8; 2];
let mut buf = ByteMutWriter::new(&mut buf[..]);
let minutes = left_pad(&mut buf, data.minutes);
let mut buf = [0u8; 2];
let mut buf = ByteMutWriter::new(&mut buf[..]);
let seconds = left_pad(&mut buf, data.seconds);
let mut buf = [0u8; 2];
let mut buf = ByteMutWriter::new(&mut buf[..]);
let day = left_pad(&mut buf, data.date);
let month = Month::from(data.month);
let weekday = Weekday::from(data.weekday);
let mut buf = [0u8; 4];
let mut buf = ByteMutWriter::new(&mut buf[..]);
let year = pad_year(&mut buf, data.year, self.century());
defmt::write!(
fmt,
"{}:{}:{}, {}, {} {} {}",
hours,
minutes,
seconds,
weekday,
day,
month,
year,
);
}
}
#[derive(Debug, Default)]
#[allow(dead_code)]
pub enum Weekday {
#[default]
Sunday = 1,
Monday = 2,
Tuesday = 4,
Wednesday = 8,
Thursday = 16,
Friday = 32,
Saturday = 64,
}
#[allow(dead_code)]
#[allow(clippy::match_same_arms)]
impl Weekday {
#[must_use]
pub fn from(val: u8) -> Self {
match val {
1 => Self::Sunday,
2 => Self::Monday,
4 => Self::Tuesday,
8 => Self::Wednesday,
16 => Self::Thursday,
32 => Self::Friday,
64 => Self::Saturday,
_ => Self::Sunday,
}
}
}
impl defmt::Format for Weekday {
fn format(&self, fmt: defmt::Formatter) {
defmt::write!(
fmt,
"{}",
match self {
Self::Sunday => "Sunday",
Self::Monday => "Monday",
Self::Tuesday => "Tuesday",
Self::Wednesday => "Wednesday",
Self::Thursday => "Thursday",
Self::Friday => "Friday",
Self::Saturday => "Saturday",
}
);
}
}
#[allow(dead_code)]
#[derive(Debug, Default)]
pub enum Month {
#[default]
January = 1,
February = 2,
March = 3,
April = 4,
May = 5,
June = 6,
July = 7,
August = 8,
September = 9,
October = 10,
November = 11,
December = 12,
}
#[allow(dead_code)]
#[allow(clippy::match_same_arms)]
impl Month {
#[must_use]
pub fn from(val: u8) -> Self {
match val {
1 => Self::January,
2 => Self::February,
3 => Self::March,
4 => Self::April,
5 => Self::May,
6 => Self::June,
7 => Self::July,
8 => Self::August,
9 => Self::September,
10 => Self::October,
11 => Self::November,
12 => Self::December,
_ => Self::January,
}
}
}
impl defmt::Format for Month {
fn format(&self, fmt: defmt::Formatter) {
defmt::write!(
fmt,
"{}",
match self {
Self::January => "January",
Self::February => "February",
Self::March => "March",
Self::April => "April",
Self::May => "May",
Self::June => "June",
Self::July => "July",
Self::August => "August",
Self::September => "September",
Self::October => "October",
Self::November => "November",
Self::December => "December",
}
);
}
}
#[derive(Debug, Copy, Clone)]
#[allow(dead_code)]
pub enum Year {
TwentiethCentury(u8),
TwentyFirstCentury(u8),
}
impl Default for Year {
fn default() -> Self {
Self::TwentyFirstCentury(20)
}
}
#[derive(Debug, Default)]
pub struct DateTimeBuilder {
hours: u8,
minutes: u8,
seconds: u8,
date: u8,
weekday: Weekday,
month: Month,
year: CurrentYear,
}
impl DateTimeBuilder {
#[must_use]
pub fn new() -> Self {
Self {
hours: 0,
minutes: 0,
seconds: 0,
date: 1,
weekday: Weekday::Thursday,
month: Month::January,
year: CurrentYear::new(1970),
}
}
#[must_use]
pub fn hours(mut self, value: u8) -> Self {
self.hours = value;
self
}
#[must_use]
pub fn minutes(mut self, value: u8) -> Self {
self.minutes = value;
self
}
#[must_use]
pub fn seconds(mut self, value: u8) -> Self {
self.seconds = value;
self
}
#[must_use]
pub fn date(mut self, value: u8) -> Self {
self.date = value;
self
}
#[must_use]
pub fn weekday(mut self, value: Weekday) -> Self {
self.weekday = value;
self
}
#[must_use]
pub fn month(mut self, value: Month) -> Self {
self.month = value;
self
}
#[must_use]
pub fn year(mut self, value: CurrentYear) -> Self {
self.year = value;
self
}
#[must_use]
pub fn build(self) -> ClockData {
let mut data = ClockData::new();
data._set((
self.hours,
self.minutes,
self.seconds,
self.weekday,
self.date,
self.month,
self.year,
));
data
}
}
fn left_pad<'a>(buf: &'a mut ByteMutWriter<'_>, value: u8) -> &'a str {
buf.clear();
write!(buf, "{}{}", common_padding(value), value).unwrap();
buf.as_str()
}
fn pad_year<'a>(buf: &'a mut ByteMutWriter<'_>, value: u8, century: Year) -> &'a str {
buf.clear();
match century {
Year::TwentiethCentury(_) => write!(buf, "19{}{}", common_padding(value), value).unwrap(),
Year::TwentyFirstCentury(_) => write!(buf, "20{}{}", common_padding(value), value).unwrap(),
}
buf.as_str()
}
fn common_padding<'a>(value: u8) -> &'a str {
if value < 10 {
"0"
} else {
""
}
}
#[allow(dead_code)]
pub mod misc {
pub fn bcd_to_dec(value: u8) -> u8 {
((value / 0x10) * 10) + (value % 0x10)
}
pub fn dec_to_bcd(value: u8) -> u8 {
((value / 10) * 0x10) + (value % 10)
}
}