summaryrefslogtreecommitdiff
path: root/src/code/lb_rtc.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/code/lb_rtc.c')
-rw-r--r--src/code/lb_rtc.c593
1 files changed, 593 insertions, 0 deletions
diff --git a/src/code/lb_rtc.c b/src/code/lb_rtc.c
new file mode 100644
index 0000000..8935435
--- /dev/null
+++ b/src/code/lb_rtc.c
@@ -0,0 +1,593 @@
+#include "lb_rtc.h"
+#include "m_common_data.h"
+#include "padmgr.h"
+#include "722970.h"
+#include "721EC0.h"
+#include "7220C0.h"
+#include "722310.h"
+#include "722AB0.h"
+#include "722880.h"
+#include "macros.h"
+#include "attributes.h"
+
+s32 l_lbRTC_isInitial = 1;
+s32 l_lbRTC_IsSampled = 0;
+
+s32 B_80145620_jp;
+lbRTC_time_c l_lbRTC_Time;
+
+s32 lbRTC_Initial() {
+ OSMesgQueue* mq;
+
+ if (l_lbRTC_isInitial == 1) {
+ mq = padmgr_LockSerialMesgQ();
+ l_lbRTC_isInitial = 0;
+ B_80145620_jp = func_800FECD0_jp(mq);
+ padmgr_UnlockSerialMesgQ(mq);
+ }
+ return B_80145620_jp;
+}
+
+s32 lbRTC_IsOki(lbRTC_time_c* ptr) {
+ s32 isInitial;
+ OSMesgQueue* mq;
+
+ isInitial = lbRTC_Initial();
+
+ if (isInitial == 0) {
+ mq = padmgr_LockSerialMesgQ();
+ isInitial = func_800FE220_jp(mq, ptr);
+ padmgr_UnlockSerialMesgQ(mq);
+ if (isInitial == 0) {
+ return isInitial;
+ }
+ }
+ l_lbRTC_isInitial = 1;
+ return isInitial;
+}
+
+s32 lbRTC_IsAbnormal() {
+ lbRTC_time_c time;
+ s32 temp UNUSED;
+ s32 res = lbRTC_IsOki(&time);
+
+ if ((res == 0) && (l_lbRTC_IsSampled == 1)) {
+ s32 baseTimer = (l_lbRTC_Time.sec + (l_lbRTC_Time.min * 60));
+
+ if ((time.sec + (time.min * 60)) != baseTimer) {
+ return res;
+ }
+ }
+ return res;
+}
+
+void lbRTC_Sampling() {
+ lbRTC_time_c time;
+
+ if ((lbRTC_IsOki(&time) == 0) && (!l_lbRTC_IsSampled)) {
+ l_lbRTC_Time.sec = time.sec;
+ l_lbRTC_Time.min = time.min;
+ l_lbRTC_IsSampled = 1;
+ }
+}
+
+void func_800D4F6C_jp(lbRTC_time_c* time) {
+ OSMesgQueue* mq;
+
+ if (lbRTC_Initial() == 0) {
+ mq = padmgr_LockSerialMesgQ();
+ func_800FEBE0_jp(mq, time);
+ padmgr_UnlockSerialMesgQ(mq);
+ }
+}
+
+void func_800D4FB8_jp(lbRTC_time_c* time) {
+ OSMesgQueue* mq;
+
+ if (lbRTC_Initial() == 0) {
+ mq = padmgr_LockSerialMesgQ();
+ func_800FE420_jp(mq, time);
+ padmgr_UnlockSerialMesgQ(mq);
+ }
+}
+
+void lbRTC_SetTime(lbRTC_time_c* time) {
+ OSMesgQueue* mq;
+
+ if (common_data.time.rtcEnabled == 1 && !common_data.time.rtcCrashed) {
+ time->weekday = lbRTC_Week(time->year, time->month, time->day);
+ mq = padmgr_LockSerialMesgQ();
+ func_800FE670_jp(mq, time);
+ padmgr_UnlockSerialMesgQ(mq);
+ } else {
+ lbRTC_TimeCopy(&common_data.time.rtcTime, time);
+ }
+}
+
+void lbRTC_GetTime(lbRTC_time_c* time) {
+ OSMesgQueue* mq;
+
+ if (common_data.time.rtcEnabled == 1 && !common_data.time.rtcCrashed) {
+ mq = padmgr_LockSerialMesgQ();
+ func_800FE220_jp(mq, time);
+ padmgr_UnlockSerialMesgQ(mq);
+ } else {
+ lbRTC_TimeCopy(time, &common_data.time.rtcTime);
+ }
+}
+
+const lbRTC_day_t days_month[2][lbRTC_MONTHS_MAX + 1] = {
+ // Regular year
+ { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
+
+ // Leap year
+ { 0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
+};
+
+lbRTC_day_t lbRTC_GetDaysByMonth(lbRTC_year_t year, lbRTC_month_t month) {
+ s32 leap = !(year & 3) ? 1 : 0;
+ s32 idx = leap == 1 ? 1 : 0;
+
+ return days_month[idx][month];
+}
+
+typedef union lbRTCYMD {
+ s32 raw;
+ lbRTC_ymd_t ymd;
+} lbRTCYMD;
+
+s32 lbRTC_IsEqualDate(lbRTC_year_t y0, lbRTC_month_t m0, lbRTC_day_t d0, lbRTC_year_t y1, lbRTC_month_t m1,
+ lbRTC_day_t d1) {
+ lbRTCYMD ymd0;
+ lbRTCYMD ymd1;
+ s32 res;
+
+ ymd0.ymd.year = y0;
+ ymd0.ymd.month = m0;
+ ymd0.ymd.day = d0;
+
+ ymd1.ymd.year = y1;
+ ymd1.ymd.month = m1;
+ ymd1.ymd.day = d1;
+
+ res = ymd0.raw - ymd1.raw;
+ if (res == 0) {
+ return lbRTC_EQUAL;
+ }
+
+ if (res < 0) {
+ return lbRTC_LESS;
+ }
+ return lbRTC_OVER;
+}
+
+s32 lbRTC_IsEqualTime(const lbRTC_time_c* t0, const lbRTC_time_c* t1, s32 flags) {
+ s32 equal = 0;
+
+ if (flags & lbRTC_CHECK_SECONDS) {
+ if (t0->sec == t1->sec) {
+ equal |= lbRTC_CHECK_SECONDS;
+ }
+ }
+
+ if (flags & lbRTC_CHECK_MINUTES) {
+ if (t0->min == t1->min) {
+ equal |= lbRTC_CHECK_MINUTES;
+ }
+ }
+
+ if (flags & lbRTC_CHECK_HOURS) {
+ if (t0->hour == t1->hour) {
+ equal |= lbRTC_CHECK_HOURS;
+ }
+ }
+
+ if (flags & lbRTC_CHECK_WEEKDAYS) {
+ if (t0->weekday == t1->weekday) {
+ equal |= lbRTC_CHECK_WEEKDAYS;
+ }
+ }
+
+ if (flags & lbRTC_CHECK_DAYS) {
+ if (t0->day == t1->day) {
+ equal |= lbRTC_CHECK_DAYS;
+ }
+ }
+
+ if (flags & lbRTC_CHECK_MONTHS) {
+ if (t0->month == t1->month) {
+ equal |= lbRTC_CHECK_MONTHS;
+ }
+ }
+
+ if (flags & lbRTC_CHECK_YEARS) {
+ if (t0->year == t1->year) {
+ equal |= lbRTC_CHECK_YEARS;
+ }
+ }
+
+ return flags == (equal & flags);
+}
+
+s32 lbRTC_IsOverTime(const lbRTC_time_c* t0, const lbRTC_time_c* t1) {
+
+ if (t1->year < t0->year) {
+ return lbRTC_LESS;
+ }
+
+ if (t1->year == t0->year) {
+ if (t1->month >= t0->month) {
+ if (t1->month == t0->month) {
+ if (t1->day >= t0->day) {
+ if (t1->day == t0->day) {
+ if (t1->hour >= t0->hour) {
+ if (t1->hour == t0->hour) {
+ if (t1->min >= t0->min) {
+ if (t1->min == t0->min) {
+ if (t1->sec < t0->sec) {
+ return lbRTC_LESS;
+ }
+ }
+ } else {
+ return lbRTC_LESS;
+ }
+ }
+ } else {
+ return lbRTC_LESS;
+ }
+ }
+ } else {
+ return lbRTC_LESS;
+ }
+ }
+ } else {
+ return lbRTC_LESS;
+ }
+ }
+
+ return lbRTC_OVER;
+}
+
+s32 lbRTC_IsJustAtRTC(const lbRTC_time_c* time, s32 flags) {
+ lbRTC_time_c rtcTime;
+
+ lbRTC_GetTime(&rtcTime);
+
+ return lbRTC_IsEqualTime(&rtcTime, time, flags);
+}
+
+s32 lbRTC_IsOverRTC(const lbRTC_time_c* time) {
+ lbRTC_time_c rtcTime;
+
+ lbRTC_GetTime(&rtcTime);
+
+ return lbRTC_IsOverTime(time, &rtcTime) == lbRTC_OVER;
+}
+
+s32 lbRTC_IsOverWeekRTC(const lbRTC_time_c* t0, lbRTC_weekday_t week) {
+ s32 curWeek;
+ lbRTC_time_c t1;
+
+ curWeek = week - t0->weekday;
+ t1 = *t0;
+
+ if (curWeek <= 0) {
+ curWeek += 7;
+ }
+
+ t1.hour = 0;
+ t1.min = 0;
+ t1.sec = 0;
+
+ lbRTC_Add_DD(&t1, curWeek);
+ lbRTC_IsOverRTC(&t1);
+}
+
+void func_800D5480_jp(lbRTC_time_c* t0, lbRTC_time_c* t1) {
+
+ lbRTC_time_c t2;
+ lbRTC_time_c t3;
+
+ t2 = *t0;
+ t3 = *t1;
+
+ func_800FF060_jp(&t3, &t2);
+}
+
+const int total_days[2][lbRTC_MONTHS_MAX + 1] = {
+ // Standard year
+ { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
+ // Leap year
+ { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
+};
+
+s32 lbRTC_GetIntervalDays(const lbRTC_time_c* t0, const lbRTC_time_c* t1) {
+ s32 leapPeriod = (t1->year - t0->year) / 4;
+ s32 years = (t1->year - t0->year) % 4;
+ s32 lessLeap = (t0->year % 4) == 0;
+ s32 overLeap = (t1->year % 4) == 0;
+ s32 leapAdd = ((4 - (t0->year % 4)) % 4) < years;
+
+ s32 days;
+
+ if (t0->year > t1->year) {
+ return 0;
+ } else {
+ if (t0->year == t1->year) {
+ if (t0->month > t1->month) {
+ return 0;
+ } else {
+ if (t0->month == t1->month) {
+ if (t0->day > t1->day) {
+ return 0;
+ } else {
+ if (t0->day == t1->day) {
+ if (t0->hour > t1->hour) {
+ return 0;
+ } else {
+ if (t0->hour == t1->hour) {
+ if (t0->min > t1->min) {
+ return 0;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ days = leapPeriod * 1461 + years * 365 + leapAdd;
+
+ days += t1->day - 1;
+ days += total_days[overLeap][t1->month - 1];
+
+ days -= t0->day - 1;
+ days -= total_days[lessLeap][t0->month - 1];
+
+ return days;
+}
+
+void lbRTC_Add_YY(lbRTC_time_c* time, s32 years) {
+ time->year += (u16)years;
+}
+
+void lbRTC_Add_MM(lbRTC_time_c* time, s32 month) {
+ s32 timeMonth = time->month;
+
+ timeMonth += month;
+
+ if (timeMonth > lbRTC_MONTHS_MAX) {
+ lbRTC_Add_YY(time, timeMonth / lbRTC_MONTHS_MAX);
+ timeMonth %= lbRTC_MONTHS_MAX;
+ }
+
+ time->month = (lbRTC_month_t)timeMonth;
+}
+
+void lbRTC_Add_DD(lbRTC_time_c* time, s32 day) {
+ s32 days = lbRTC_GetDaysByMonth(time->year, (lbRTC_month_t)time->month);
+ s32 timeDay = time->day;
+
+ timeDay += day;
+
+ if (timeDay > days) {
+ timeDay -= days;
+ lbRTC_Add_MM(time, 1);
+ }
+
+ time->day = (lbRTC_day_t)timeDay;
+}
+
+void lbRTC_Add_hh(lbRTC_time_c* time, s32 hour) {
+ s32 timeHour = time->hour;
+
+ timeHour += hour;
+ if (timeHour >= lbRTC_HOURS_PER_DAY) {
+ lbRTC_Add_DD(time, timeHour / lbRTC_HOURS_PER_DAY);
+ timeHour %= lbRTC_HOURS_PER_DAY;
+ }
+
+ time->hour = (lbRTC_hour_t)timeHour;
+}
+
+void lbRTC_Add_mm(lbRTC_time_c* time, s32 min) {
+ s32 timeSec = time->min;
+
+ timeSec += min;
+ if (timeSec >= lbRTC_MINUTES_PER_HOUR) {
+ lbRTC_Add_hh(time, timeSec / lbRTC_MINUTES_PER_HOUR);
+ timeSec %= lbRTC_MINUTES_PER_HOUR;
+ }
+
+ time->min = (lbRTC_min_t)timeSec;
+}
+
+void lbRTC_Add_ss(lbRTC_time_c* time, s32 sec) {
+ int timeSec = time->sec;
+
+ timeSec += sec;
+ if (timeSec >= lbRTC_SECONDS_PER_MINUTE) {
+ lbRTC_Add_mm(time, timeSec / lbRTC_SECONDS_PER_MINUTE);
+ timeSec %= lbRTC_SECONDS_PER_MINUTE;
+ }
+
+ time->sec = (lbRTC_sec_t)timeSec;
+}
+
+void lbRTC_Add_Date(lbRTC_time_c* time, const lbRTC_time_c* add_time) {
+ lbRTC_Add_ss(time, add_time->sec);
+ lbRTC_Add_mm(time, add_time->min);
+ lbRTC_Add_hh(time, add_time->hour);
+ lbRTC_Add_DD(time, add_time->day);
+ lbRTC_Add_MM(time, add_time->month);
+ lbRTC_Add_YY(time, add_time->year);
+}
+
+void lbRTC_Sub_YY(lbRTC_time_c* time, s32 year) {
+ time->year -= (lbRTC_year_t)year;
+}
+
+void lbRTC_Sub_MM(lbRTC_time_c* time, s32 month) {
+ s32 calcMonth = time->month - month;
+ if (calcMonth < 1) {
+ s32 temp = calcMonth;
+ s32 year;
+
+ if (calcMonth == 0) {
+ calcMonth = lbRTC_MONTHS_MAX;
+ year = 1;
+ } else {
+ temp = ABS(calcMonth);
+ year = temp / lbRTC_MONTHS_MAX + 1;
+ calcMonth = lbRTC_MONTHS_MAX - (temp % lbRTC_MONTHS_MAX);
+ }
+
+ lbRTC_Sub_YY(time, year);
+ }
+
+ time->month = (lbRTC_month_t)calcMonth;
+}
+
+void lbRTC_Sub_DD(lbRTC_time_c* time, s32 days) {
+ s32 currentDay = time->day;
+ s32 day;
+
+ if (time->month == lbRTC_JANUARY) {
+ day = lbRTC_GetDaysByMonth(time->year, lbRTC_MONTHS_MAX);
+ } else {
+ day = lbRTC_GetDaysByMonth(time->year, (time->month - 1));
+ }
+
+ currentDay -= days;
+
+ if (currentDay <= 0) {
+ if (currentDay == 0) {
+ currentDay = day;
+ } else {
+ currentDay += day;
+ }
+
+ lbRTC_Sub_MM(time, 1);
+ }
+
+ time->day = (lbRTC_day_t)currentDay;
+}
+
+void lbRTC_Sub_hh(lbRTC_time_c* time, s32 hour) {
+ s32 timeHour = time->hour;
+ timeHour -= hour;
+
+ if (timeHour < 0) {
+ s32 temp = timeHour;
+ s32 days;
+
+ temp = ABS(timeHour);
+ days = temp / lbRTC_HOURS_PER_DAY + 1;
+ timeHour = lbRTC_HOURS_PER_DAY - (temp % lbRTC_HOURS_PER_DAY);
+
+ if (timeHour == lbRTC_HOURS_PER_DAY) {
+ timeHour = 0;
+ days--;
+ }
+
+ lbRTC_Sub_DD(time, days);
+ }
+
+ time->hour = (lbRTC_hour_t)timeHour;
+}
+
+void lbRTC_Sub_mm(lbRTC_time_c* time, s32 min) {
+ s32 timeMin = time->min;
+ timeMin -= min;
+
+ if (timeMin < 0) {
+ s32 temp = timeMin;
+ s32 hours;
+
+ temp = ABS(timeMin);
+ hours = temp / lbRTC_MINUTES_PER_HOUR + 1;
+ timeMin = lbRTC_MINUTES_PER_HOUR - (temp % lbRTC_MINUTES_PER_HOUR);
+
+ if (timeMin == lbRTC_MINUTES_PER_HOUR) {
+ timeMin = 0;
+ hours--;
+ }
+
+ lbRTC_Sub_hh(time, hours);
+ }
+
+ time->min = (lbRTC_min_t)timeMin;
+}
+
+void lbRTC_Sub_ss(lbRTC_time_c* time, s32 sec) {
+ s32 timeSec = time->sec;
+ timeSec -= sec;
+
+ if (timeSec < 0) {
+ s32 temp = timeSec;
+ s32 mins;
+
+ temp = ABS(timeSec);
+ mins = temp / lbRTC_SECONDS_PER_MINUTE + 1;
+ timeSec = lbRTC_SECONDS_PER_MINUTE - (temp % lbRTC_SECONDS_PER_MINUTE);
+
+ if (timeSec == lbRTC_SECONDS_PER_MINUTE) {
+ timeSec = 0;
+ mins--;
+ }
+
+ lbRTC_Sub_mm(time, mins);
+ }
+
+ time->sec = (lbRTC_sec_t)timeSec;
+}
+
+void lbRTC_Sub_Date(lbRTC_time_c* time, const lbRTC_time_c* sub_time) {
+ lbRTC_Sub_ss(time, sub_time->sec);
+ lbRTC_Sub_mm(time, sub_time->min);
+ lbRTC_Sub_hh(time, sub_time->hour);
+ lbRTC_Sub_DD(time, sub_time->day);
+ lbRTC_Sub_MM(time, sub_time->month);
+ lbRTC_Sub_YY(time, sub_time->year);
+}
+
+const lbRTC_time_c a_time = { 0, 0, 0, 1, 0, 1, 1901 };
+
+lbRTC_weekday_t lbRTC_Week(lbRTC_year_t year, lbRTC_month_t month, lbRTC_day_t day) {
+
+ lbRTC_time_c b_time = { 0, 0, 0, 0, 0, 0, 0000 };
+
+ b_time.year = year;
+ b_time.month = month;
+ b_time.day = day;
+
+ return (lbRTC_weekday_t)((lbRTC_GetIntervalDays(&a_time, &b_time) + 2) % lbRTC_WEEKDAYS_MAX);
+}
+
+void lbRTC_TimeCopy(lbRTC_time_c* dst, const lbRTC_time_c* src) {
+ *dst = *src;
+}
+
+const lbRTC_day_t day_tbl[] = { 00, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
+
+s32 lbRTC_IsValidTime(const lbRTC_time_c* time) {
+ s32 res;
+
+ if ((time->year < lbRTC_YEAR_MIN || time->year > lbRTC_YEAR_MAX) || (time->month == lbRTC_MONTHS_BEGIN) ||
+ (time->month > lbRTC_MONTHS_MAX) || (time->day == 0) || (time->hour > lbRTC_HOURS_PER_DAY - 1) ||
+ (time->min > lbRTC_MINUTES_PER_HOUR - 1) || (time->sec > lbRTC_SECONDS_PER_MINUTE - 1)) {
+ res = 0;
+ } else {
+ if (time->day == 29 && time->month == lbRTC_FEBRUARY) {
+ res = !(time->year & 3) ? 1 : 0;
+ } else if (time->day > day_tbl[time->month]) {
+ res = 0;
+ } else {
+ res = 1;
+ }
+ }
+
+ return res;
+}