cmake_cpputest_template/inc/extralibs/rtc_helper.h
2025-12-23 14:33:54 -08:00

127 lines
No EOL
2.9 KiB
C

// MIT License
// Copyright (c) 2025 UniTheCat
#define RTC_TICKS_PER_SECOND 32768
#define SECONDS_PER_MINUTE 60
#define SECONDS_PER_HOUR 3600
#define SECONDS_PER_DAY 86400
#define IS_LEAP_YEAR(year) ((((year) % 4 == 0) && ((year) % 100 != 0)) || ((year) % 400 == 0))
// Array of days in each month (non-leap year)
const u8 DAYS_IN_MONTH[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
typedef struct {
u16 year;
u8 month;
u8 day;
} rtc_date_t;
typedef struct {
u8 hr;
u8 min;
u8 sec;
u16 ms;
} rtc_time_t;
typedef struct {
rtc_date_t date;
rtc_time_t time;
} rtc_datetime_t;
// calculate days of the current year. eg. 2020-02-05 is 36 day
u32 RTC_days_of_year(u16 year, u8 month, u8 day) {
u32 day_of_year = 0;
// Add days from January to month-1
for (u8 m = 0; m < month - 1; m++) {
day_of_year += DAYS_IN_MONTH[m];
}
// Add extra day for February (full month) if it's a leap year
if (month > 2 && IS_LEAP_YEAR(year)) {
day_of_year += 1;
}
// Add days in the current month
day_of_year += day;
return day_of_year;
}
u32 RTC_get_seconds(u16 year, u8 month, u8 day, u8 hr, u8 min, u8 sec) {
//# Validate input
if (month < 1 || month > 12 || day < 1 || day > 31 ||
hr > 23 || min > 59 || sec > 59 || year < 1970) { return 0; }
// calculate days of the current year, -1 for 0-based days
u32 days = RTC_days_of_year(year, month, day) - 1;
// add the days count excluding the current year
// (start from epoch time 1970-01-01 00:00:00)
for (int y=1970; y < year; y++) {
days += IS_LEAP_YEAR(y) ? 366 : 365;
}
// calculate total seconds
return days * SECONDS_PER_DAY +
hr * SECONDS_PER_HOUR +
min * SECONDS_PER_MINUTE + sec;
}
rtc_time_t RTC_get_time(u32 total_seconds, u32 ms) {
u32 minutes = total_seconds / 60;
return (rtc_time_t) {
.sec = total_seconds % 60,
.min = minutes % 60,
.hr = (minutes / 60) % 24,
.ms = ms
};
}
rtc_date_t RTC_get_date(u32 total_seconds, u16 year_base) {
rtc_date_t output = {
.year = year_base,
.month = 1,
.day = 1
};
// Days since epoch
u32 days_remaining = total_seconds / SECONDS_PER_DAY;
// Find the year
while(1) {
u32 days_in_year = IS_LEAP_YEAR(output.year) ? 366 : 365;
if (days_remaining < days_in_year) break;
days_remaining -= days_in_year;
output.year++;
}
// find the month
for (u8 m = 0; m < 12; m++) {
u8 days_in_month = DAYS_IN_MONTH[m];
if (m == 1 && IS_LEAP_YEAR(output.year)) days_in_month = 29;
if (days_remaining < days_in_month) break;
days_remaining -= days_in_month;
output.month++;
}
// add 1 because days_remaining is 0-based
output.day = days_remaining + 1;
return output;
}
void RTC_print_date(rtc_date_t date, char *delimiter) {
printf("%04d", date.year);
printf("%s%02d", delimiter, date.month);
printf("%s%02d", delimiter, date.day);
}
void RTC_print_time(rtc_time_t time) {
printf("%02d:%02d:%02d.%03d",
time.hr, time.min, time.sec, time.ms);
}