From 9edfc54fb8b3c2bc46f9730a0eaa80811cb156dd Mon Sep 17 00:00:00 2001 From: YamaArashi Date: Tue, 5 Apr 2016 21:03:12 -0700 Subject: rename RTC files --- Makefile | 2 +- asm/rom.s | 4 +- data/data2.s | 2 +- data/rtc.s | 33 +++++ data/rtc_util.s | 33 ----- include/rtc.h | 76 ++++------ include/rtc_util.h | 34 ----- include/siirtc.h | 54 +++++++ src/librtc.c | 427 ----------------------------------------------------- src/rtc.c | 349 +++++++++++++++++++++++++++++++++++++++++++ src/rtc_util.c | 349 ------------------------------------------- src/siirtc.c | 427 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 12 files changed, 895 insertions(+), 895 deletions(-) create mode 100644 data/rtc.s delete mode 100644 data/rtc_util.s delete mode 100644 include/rtc_util.h create mode 100644 include/siirtc.h delete mode 100644 src/librtc.c create mode 100644 src/rtc.c delete mode 100644 src/rtc_util.c create mode 100644 src/siirtc.c diff --git a/Makefile b/Makefile index 6175c5cd3..5117c2eb9 100644 --- a/Makefile +++ b/Makefile @@ -62,7 +62,7 @@ include tilesets.mk $(OBJS): $(CSRCS:src/%.c=genasm/%.s) -genasm/librtc.s: CFLAGS := -mthumb-interwork -Iinclude +genasm/siirtc.s: CFLAGS := -mthumb-interwork -Iinclude # TODO: fix this .syntax hack diff --git a/asm/rom.s b/asm/rom.s index 722e54745..7e5fa928d 100644 --- a/asm/rom.s +++ b/asm/rom.s @@ -18378,7 +18378,7 @@ _080090EC: .4byte 0x00000fbc _080090F0: .4byte 0x0000efff thumb_func_end sub_8009084 - .include "genasm/rtc_util.s" + .include "genasm/rtc.s" thumb_func_start sub_80096C4 sub_80096C4: ; 80096C4 @@ -676821,7 +676821,7 @@ _0814AE2C: .4byte gUnknown_0842F6C0 .include "asm/libgcnmultiboot.s" .include "asm/libmks4agb.s" .include "asm/libagbbackup.s" - .include "genasm/librtc.s" + .include "genasm/siirtc.s" .include "asm/libagbsyscall.s" .include "asm/libgcc.s" .include "data/data2.s" diff --git a/data/data2.s b/data/data2.s index 9f5b37cd8..a3c66a58a 100644 --- a/data/data2.s +++ b/data/data2.s @@ -364,7 +364,7 @@ gUnknown_081E75FC: ; 81E75FC .incbin "baserom.gba", 0x001e75fc, 0x14 ; 81E7610 - .include "data/rtc_util.s" + .include "data/rtc.s" gUnknown_081E764C: ; 81E764C .incbin "baserom.gba", 0x001e764c, 0x40 diff --git a/data/rtc.s b/data/rtc.s new file mode 100644 index 000000000..599f4e001 --- /dev/null +++ b/data/rtc.s @@ -0,0 +1,33 @@ + .align 2 + +; Dummy values used when the RTC is in an invalid state. +; 2000 Jan 1 00:00:00 +gRtcDummy: ; 81E7610 + .byte 0 + .byte 1 + .byte 1 + .byte 0 + .byte 0 + .byte 0 + .byte 0 + .byte 0 + .byte 0 + .byte 0 + .byte 0 + .byte 0 + + .align 2 + +gNumDaysInMonths: ; 81E761C + .4byte 31 + .4byte 28 + .4byte 31 + .4byte 30 + .4byte 31 + .4byte 30 + .4byte 31 + .4byte 31 + .4byte 30 + .4byte 31 + .4byte 30 + .4byte 31 diff --git a/data/rtc_util.s b/data/rtc_util.s deleted file mode 100644 index 599f4e001..000000000 --- a/data/rtc_util.s +++ /dev/null @@ -1,33 +0,0 @@ - .align 2 - -; Dummy values used when the RTC is in an invalid state. -; 2000 Jan 1 00:00:00 -gRtcDummy: ; 81E7610 - .byte 0 - .byte 1 - .byte 1 - .byte 0 - .byte 0 - .byte 0 - .byte 0 - .byte 0 - .byte 0 - .byte 0 - .byte 0 - .byte 0 - - .align 2 - -gNumDaysInMonths: ; 81E761C - .4byte 31 - .4byte 28 - .4byte 31 - .4byte 30 - .4byte 31 - .4byte 30 - .4byte 31 - .4byte 31 - .4byte 30 - .4byte 31 - .4byte 30 - .4byte 31 diff --git a/include/rtc.h b/include/rtc.h index 5864f95b8..96d7e716b 100644 --- a/include/rtc.h +++ b/include/rtc.h @@ -1,54 +1,34 @@ -#ifndef GUARD_RTC_H -#define GUARD_RTC_H +#ifndef GUARD_RTC_UTIL_H +#define GUARD_RTC_UTIL_H -#include "gba/gba.h" +#include "global.h" -#define SIIRTCINFO_INTFE 0x01 // frequency interrupt enable -#define SIIRTCINFO_INTME 0x02 // per-minute interrupt enable -#define SIIRTCINFO_INTAE 0x04 // alarm interrupt enable -#define SIIRTCINFO_24HOUR 0x40 // 0: 12-hour mode, 1: 24-hour mode -#define SIIRTCINFO_POWER 0x80 // power on or power failure occurred +#define RTC_INIT_ERROR 0x0001 +#define RTC_INIT_WARNING 0x0002 -enum -{ - MONTH_JAN = 1, - MONTH_FEB, - MONTH_MAR, - MONTH_APR, - MONTH_MAY, - MONTH_JUN, - MONTH_JUL, - MONTH_AUG, - MONTH_SEP, - MONTH_OCT, - MONTH_NOV, - MONTH_DEC -}; +#define RTC_ERR_12HOUR_CLOCK 0x0010 +#define RTC_ERR_POWER_FAILURE 0x0020 +#define RTC_ERR_INVALID_YEAR 0x0040 +#define RTC_ERR_INVALID_MONTH 0x0080 +#define RTC_ERR_INVALID_DAY 0x0100 +#define RTC_ERR_INVALID_HOUR 0x0200 +#define RTC_ERR_INVALID_MINUTE 0x0400 +#define RTC_ERR_INVALID_SECOND 0x0800 -struct SiiRtcInfo -{ - u8 year; - u8 month; - u8 day; - u8 dayOfWeek; - u8 hour; - u8 minute; - u8 second; - u8 status; - u8 alarmHour; - u8 alarmMinute; -}; +#define RTC_ERR_FLAG_MASK 0x0FF0 -void SiiRtcUnprotect(); -void SiiRtcProtect(); -u8 SiiRtcProbe(); -bool8 SiiRtcReset(); -bool8 SiiRtcGetStatus(struct SiiRtcInfo *rtc); -bool8 SiiRtcSetStatus(struct SiiRtcInfo *rtc); -bool8 SiiRtcGetDateTime(struct SiiRtcInfo *rtc); -bool8 SiiRtcSetDateTime(struct SiiRtcInfo *rtc); -bool8 SiiRtcGetTime(struct SiiRtcInfo *rtc); -bool8 SiiRtcSetTime(struct SiiRtcInfo *rtc); -bool8 SiiRtcSetAlarm(struct SiiRtcInfo *rtc); +void RtcInit(); +u16 RtcGetErrorStatus(); +void RtcReset(); +void FormatDecimalTime(u8 *dest, s32 hour, s32 minute, s32 second); +void FormatHexTime(u8 *dest, s32 hour, s32 minute, s32 second); +void FormatHexRtcTime(u8 *dest); +void FormatDecimalDate(u8 *dest, s32 year, s32 month, s32 day); +void FormatHexDate(u8 *dest, s32 year, s32 month, s32 day); +void RtcCalcLocalTime(); +void RtcInitLocalTimeOffset(s32 hour, s32 minute); +void RtcCalcLocalTimeOffset(s32 days, s32 hours, s32 minutes, s32 seconds); +void CalcTimeDifference(struct Time *result, struct Time *t1, struct Time *t2); +u32 RtcGetMinuteCount(); -#endif // GUARD_RTC_H +#endif // GUARD_RTC_UTIL_H diff --git a/include/rtc_util.h b/include/rtc_util.h deleted file mode 100644 index 96d7e716b..000000000 --- a/include/rtc_util.h +++ /dev/null @@ -1,34 +0,0 @@ -#ifndef GUARD_RTC_UTIL_H -#define GUARD_RTC_UTIL_H - -#include "global.h" - -#define RTC_INIT_ERROR 0x0001 -#define RTC_INIT_WARNING 0x0002 - -#define RTC_ERR_12HOUR_CLOCK 0x0010 -#define RTC_ERR_POWER_FAILURE 0x0020 -#define RTC_ERR_INVALID_YEAR 0x0040 -#define RTC_ERR_INVALID_MONTH 0x0080 -#define RTC_ERR_INVALID_DAY 0x0100 -#define RTC_ERR_INVALID_HOUR 0x0200 -#define RTC_ERR_INVALID_MINUTE 0x0400 -#define RTC_ERR_INVALID_SECOND 0x0800 - -#define RTC_ERR_FLAG_MASK 0x0FF0 - -void RtcInit(); -u16 RtcGetErrorStatus(); -void RtcReset(); -void FormatDecimalTime(u8 *dest, s32 hour, s32 minute, s32 second); -void FormatHexTime(u8 *dest, s32 hour, s32 minute, s32 second); -void FormatHexRtcTime(u8 *dest); -void FormatDecimalDate(u8 *dest, s32 year, s32 month, s32 day); -void FormatHexDate(u8 *dest, s32 year, s32 month, s32 day); -void RtcCalcLocalTime(); -void RtcInitLocalTimeOffset(s32 hour, s32 minute); -void RtcCalcLocalTimeOffset(s32 days, s32 hours, s32 minutes, s32 seconds); -void CalcTimeDifference(struct Time *result, struct Time *t1, struct Time *t2); -u32 RtcGetMinuteCount(); - -#endif // GUARD_RTC_UTIL_H diff --git a/include/siirtc.h b/include/siirtc.h new file mode 100644 index 000000000..5864f95b8 --- /dev/null +++ b/include/siirtc.h @@ -0,0 +1,54 @@ +#ifndef GUARD_RTC_H +#define GUARD_RTC_H + +#include "gba/gba.h" + +#define SIIRTCINFO_INTFE 0x01 // frequency interrupt enable +#define SIIRTCINFO_INTME 0x02 // per-minute interrupt enable +#define SIIRTCINFO_INTAE 0x04 // alarm interrupt enable +#define SIIRTCINFO_24HOUR 0x40 // 0: 12-hour mode, 1: 24-hour mode +#define SIIRTCINFO_POWER 0x80 // power on or power failure occurred + +enum +{ + MONTH_JAN = 1, + MONTH_FEB, + MONTH_MAR, + MONTH_APR, + MONTH_MAY, + MONTH_JUN, + MONTH_JUL, + MONTH_AUG, + MONTH_SEP, + MONTH_OCT, + MONTH_NOV, + MONTH_DEC +}; + +struct SiiRtcInfo +{ + u8 year; + u8 month; + u8 day; + u8 dayOfWeek; + u8 hour; + u8 minute; + u8 second; + u8 status; + u8 alarmHour; + u8 alarmMinute; +}; + +void SiiRtcUnprotect(); +void SiiRtcProtect(); +u8 SiiRtcProbe(); +bool8 SiiRtcReset(); +bool8 SiiRtcGetStatus(struct SiiRtcInfo *rtc); +bool8 SiiRtcSetStatus(struct SiiRtcInfo *rtc); +bool8 SiiRtcGetDateTime(struct SiiRtcInfo *rtc); +bool8 SiiRtcSetDateTime(struct SiiRtcInfo *rtc); +bool8 SiiRtcGetTime(struct SiiRtcInfo *rtc); +bool8 SiiRtcSetTime(struct SiiRtcInfo *rtc); +bool8 SiiRtcSetAlarm(struct SiiRtcInfo *rtc); + +#endif // GUARD_RTC_H diff --git a/src/librtc.c b/src/librtc.c deleted file mode 100644 index 8d748b06e..000000000 --- a/src/librtc.c +++ /dev/null @@ -1,427 +0,0 @@ -// Ruby/Sapphire/Emerald cartridges contain a Seiko Instruments Inc. (SII) -// S-3511A real-time clock (RTC). This library ("SIIRTC_V001") is for -// communicating with the RTC. - -#include "gba/gba.h" -#include "rtc.h" - -#define STATUS_INTFE 0x02 // frequency interrupt enable -#define STATUS_INTME 0x08 // per-minute interrupt enable -#define STATUS_INTAE 0x20 // alarm interrupt enable -#define STATUS_24HOUR 0x40 // 0: 12-hour mode, 1: 24-hour mode -#define STATUS_POWER 0x80 // power on or power failure occurred - -#define TEST_MODE 0x80 // flag in the "second" byte - -#define ALARM_AM 0x00 -#define ALARM_PM 0x80 - -#define OFFSET_YEAR offsetof(struct SiiRtcInfo, year) -#define OFFSET_MONTH offsetof(struct SiiRtcInfo, month) -#define OFFSET_DAY offsetof(struct SiiRtcInfo, day) -#define OFFSET_DAY_OF_WEEK offsetof(struct SiiRtcInfo, dayOfWeek) -#define OFFSET_HOUR offsetof(struct SiiRtcInfo, hour) -#define OFFSET_MINUTE offsetof(struct SiiRtcInfo, minute) -#define OFFSET_SECOND offsetof(struct SiiRtcInfo, second) -#define OFFSET_STATUS offsetof(struct SiiRtcInfo, status) -#define OFFSET_ALARM_HOUR offsetof(struct SiiRtcInfo, alarmHour) -#define OFFSET_ALARM_MINUTE offsetof(struct SiiRtcInfo, alarmMinute) - -#define INFO_BUF(info, index) (*((u8 *)(info) + (index))) - -#define DATETIME_BUF(info, index) INFO_BUF(info, OFFSET_YEAR + index) -#define DATETIME_BUF_LEN (OFFSET_SECOND - OFFSET_YEAR + 1) - -#define TIME_BUF(info, index) INFO_BUF(info, OFFSET_HOUR + index) -#define TIME_BUF_LEN (OFFSET_SECOND - OFFSET_HOUR + 1) - -#define WR 0 // command for writing data -#define RD 1 // command for reading data - -#define CMD(n) (0x60 | (n << 1)) - -#define CMD_RESET CMD(0) -#define CMD_STATUS CMD(1) -#define CMD_DATETIME CMD(2) -#define CMD_TIME CMD(3) -#define CMD_ALARM CMD(4) - -extern vu16 GPIOPortData; -extern vu16 GPIOPortDirection; -extern vu16 GPIOPortReadEnable; - -extern bool8 gSiiRtcLocked; - -static int WriteCommand(u8 value); -static int WriteData(u8 value); -static u8 ReadData(); -static void EnableGpioPortRead(); -static void DisableGpioPortRead(); - -void SiiRtcUnprotect() -{ - EnableGpioPortRead(); - gSiiRtcLocked = FALSE; -} - -void SiiRtcProtect() -{ - DisableGpioPortRead(); - gSiiRtcLocked = TRUE; -} - -u8 SiiRtcProbe() -{ - u8 errorCode; - struct SiiRtcInfo rtc; - - if (!SiiRtcGetStatus(&rtc)) - return 0; - - errorCode = 0; - - if ((rtc.status & (SIIRTCINFO_POWER | SIIRTCINFO_24HOUR)) == SIIRTCINFO_POWER - || (rtc.status & (SIIRTCINFO_POWER | SIIRTCINFO_24HOUR)) == 0) - { - // The RTC is in 12-hour mode. Reset it and switch to 24-hour mode. - - // Note that the conditions are redundant and equivalent to simply - // "(rtc.status & SIIRTCINFO_24HOUR) == 0". It's possible that this - // was also intended to handle resetting the clock after power failure - // but a mistake was made. - - if (!SiiRtcReset()) - return 0; - - errorCode++; - } - - SiiRtcGetTime(&rtc); - - if (rtc.second & TEST_MODE) - { - // The RTC is in test mode. Reset it to leave test mode. - - if (!SiiRtcReset()) - return (errorCode << 4) & 0xF0; - - errorCode++; - } - - return (errorCode << 4) | 1; -} - -bool8 SiiRtcReset() -{ - u8 result; - struct SiiRtcInfo rtc; - - if (gSiiRtcLocked == TRUE) - return FALSE; - - gSiiRtcLocked = TRUE; - - GPIOPortData = 1; - GPIOPortData = 5; - - GPIOPortDirection = 7; - - WriteCommand(CMD_RESET | WR); - - GPIOPortData = 1; - GPIOPortData = 1; - - gSiiRtcLocked = FALSE; - - rtc.status = SIIRTCINFO_24HOUR; - - result = SiiRtcSetStatus(&rtc); - - return result; -} - -bool8 SiiRtcGetStatus(struct SiiRtcInfo *rtc) -{ - u8 statusData; - - if (gSiiRtcLocked == TRUE) - return FALSE; - - gSiiRtcLocked = TRUE; - - GPIOPortData = 1; - GPIOPortData = 5; - - GPIOPortDirection = 7; - - WriteCommand(CMD_STATUS | RD); - - GPIOPortDirection = 5; - - statusData = ReadData(); - - rtc->status = (statusData & (STATUS_POWER | STATUS_24HOUR)) - | ((statusData & STATUS_INTAE) >> 3) - | ((statusData & STATUS_INTME) >> 2) - | ((statusData & STATUS_INTFE) >> 1); - - GPIOPortData = 1; - GPIOPortData = 1; - - gSiiRtcLocked = FALSE; - - return TRUE; -} - -bool8 SiiRtcSetStatus(struct SiiRtcInfo *rtc) -{ - u8 statusData; - - if (gSiiRtcLocked == TRUE) - return FALSE; - - gSiiRtcLocked = TRUE; - - GPIOPortData = 1; - GPIOPortData = 5; - - statusData = STATUS_24HOUR - | ((rtc->status & SIIRTCINFO_INTAE) << 3) - | ((rtc->status & SIIRTCINFO_INTME) << 2) - | ((rtc->status & SIIRTCINFO_INTFE) << 1); - - GPIOPortDirection = 7; - - WriteCommand(CMD_STATUS | WR); - - WriteData(statusData); - - GPIOPortData = 1; - GPIOPortData = 1; - - gSiiRtcLocked = FALSE; - - return TRUE; -} - -bool8 SiiRtcGetDateTime(struct SiiRtcInfo *rtc) -{ - u8 i; - - if (gSiiRtcLocked == TRUE) - return FALSE; - - gSiiRtcLocked = TRUE; - - GPIOPortData = 1; - GPIOPortData = 5; - - GPIOPortDirection = 7; - - WriteCommand(CMD_DATETIME | RD); - - GPIOPortDirection = 5; - - for (i = 0; i < DATETIME_BUF_LEN; i++) - DATETIME_BUF(rtc, i) = ReadData(); - - INFO_BUF(rtc, OFFSET_HOUR) &= 0x7F; - - GPIOPortData = 1; - GPIOPortData = 1; - - gSiiRtcLocked = FALSE; - - return TRUE; -} - -bool8 SiiRtcSetDateTime(struct SiiRtcInfo *rtc) -{ - u8 i; - - if (gSiiRtcLocked == TRUE) - return FALSE; - - gSiiRtcLocked = TRUE; - - GPIOPortData = 1; - GPIOPortData = 5; - - GPIOPortDirection = 7; - - WriteCommand(CMD_DATETIME | WR); - - for (i = 0; i < DATETIME_BUF_LEN; i++) - WriteData(DATETIME_BUF(rtc, i)); - - GPIOPortData = 1; - GPIOPortData = 1; - - gSiiRtcLocked = FALSE; - - return TRUE; -} - -bool8 SiiRtcGetTime(struct SiiRtcInfo *rtc) -{ - u8 i; - - if (gSiiRtcLocked == TRUE) - return FALSE; - - gSiiRtcLocked = TRUE; - - GPIOPortData = 1; - GPIOPortData = 5; - - GPIOPortDirection = 7; - - WriteCommand(CMD_TIME | RD); - - GPIOPortDirection = 5; - - for (i = 0; i < TIME_BUF_LEN; i++) - TIME_BUF(rtc, i) = ReadData(); - - INFO_BUF(rtc, OFFSET_HOUR) &= 0x7F; - - GPIOPortData = 1; - GPIOPortData = 1; - - gSiiRtcLocked = FALSE; - - return TRUE; -} - -bool8 SiiRtcSetTime(struct SiiRtcInfo *rtc) -{ - u8 i; - - if (gSiiRtcLocked == TRUE) - return FALSE; - - gSiiRtcLocked = TRUE; - - GPIOPortData = 1; - GPIOPortData = 5; - - GPIOPortDirection = 7; - - WriteCommand(CMD_TIME | WR); - - for (i = 0; i < TIME_BUF_LEN; i++) - WriteData(TIME_BUF(rtc, i)); - - GPIOPortData = 1; - GPIOPortData = 1; - - gSiiRtcLocked = FALSE; - - return TRUE; -} - -bool8 SiiRtcSetAlarm(struct SiiRtcInfo *rtc) -{ - u8 i; - u8 alarmData[2]; - - if (gSiiRtcLocked == TRUE) - return FALSE; - - gSiiRtcLocked = TRUE; - - // Decode BCD. - alarmData[0] = (rtc->alarmHour & 0xF) + 10 * ((rtc->alarmHour >> 4) & 0xF); - - // The AM/PM flag must be set correctly even in 24-hour mode. - - if (alarmData[0] < 12) - alarmData[0] = rtc->alarmHour | ALARM_AM; - else - alarmData[0] = rtc->alarmHour | ALARM_PM; - - alarmData[1] = rtc->alarmMinute; - - GPIOPortData = 1; - GPIOPortData = 5; - - GPIOPortDirection = 7; - - WriteCommand(CMD_ALARM | WR); - - for (i = 0; i < 2; i++) - WriteData(alarmData[i]); - - GPIOPortData = 1; - GPIOPortData = 1; - - gSiiRtcLocked = FALSE; - - return TRUE; -} - -static int WriteCommand(u8 value) -{ - u8 i; - u8 temp; - - for (i = 0; i < 8; i++) - { - temp = ((value >> (7 - i)) & 1); - GPIOPortData = (temp << 1) | 4; - GPIOPortData = (temp << 1) | 4; - GPIOPortData = (temp << 1) | 4; - GPIOPortData = (temp << 1) | 5; - } - - // control reaches end of non-void function -} - -static int WriteData(u8 value) -{ - u8 i; - u8 temp; - - for (i = 0; i < 8; i++) - { - temp = ((value >> i) & 1); - GPIOPortData = (temp << 1) | 4; - GPIOPortData = (temp << 1) | 4; - GPIOPortData = (temp << 1) | 4; - GPIOPortData = (temp << 1) | 5; - } - - // control reaches end of non-void function -} - -static u8 ReadData() -{ - u8 i; - u8 temp; - u8 value; - - for (i = 0; i < 8; i++) - { - GPIOPortData = 4; - GPIOPortData = 4; - GPIOPortData = 4; - GPIOPortData = 4; - GPIOPortData = 4; - GPIOPortData = 5; - - temp = ((GPIOPortData & 2) >> 1); - value = (value >> 1) | (temp << 7); // UB: accessing uninitialized var - } - - return value; -} - -static void EnableGpioPortRead() -{ - GPIOPortReadEnable = 1; -} - -static void DisableGpioPortRead() -{ - GPIOPortReadEnable = 0; -} diff --git a/src/rtc.c b/src/rtc.c new file mode 100644 index 000000000..6f164066b --- /dev/null +++ b/src/rtc.c @@ -0,0 +1,349 @@ +#include "global.h" +#include "siirtc.h" +#include "rtc.h" +#include "string_util.h" + +extern const struct SiiRtcInfo gRtcDummy; +extern const s32 gNumDaysInMonths[]; + +extern u16 gRtcErrorStatus; +extern struct SiiRtcInfo gRtc; +extern u8 gRtcProbeResult; +extern u16 gRtcSavedIme; + +extern struct Time gLocalTime; + +void RtcDisableInterrupts(); +void RtcRestoreInterrupts(); +u32 ConvertBcdToBinary(u8 bcd); +bool8 IsLeapYear(u8 year); +u16 ConvertDateToDayCount(u8 year, u8 month, u8 day); +u16 RtcGetDayCount(struct SiiRtcInfo *rtc); +void RtcGetInfo(struct SiiRtcInfo *rtc); +void RtcGetDateTime(struct SiiRtcInfo *rtc); +void RtcGetStatus(struct SiiRtcInfo *rtc); +void RtcGetRawInfo(struct SiiRtcInfo *rtc); +u16 RtcCheckInfo(struct SiiRtcInfo *rtc); +void RtcCalcTimeDifference(struct SiiRtcInfo *rtc, struct Time *result, struct Time *t); + +void RtcDisableInterrupts() +{ + gRtcSavedIme = REG_IME; + REG_IME = 0; +} + +void RtcRestoreInterrupts() +{ + REG_IME = gRtcSavedIme; +} + +u32 ConvertBcdToBinary(u8 bcd) +{ + if (bcd > 0x9F) + return 0xFF; + + if ((bcd & 0xF) <= 9) + return (10 * ((bcd >> 4) & 0xF)) + (bcd & 0xF); + else + return 0xFF; +} + +bool8 IsLeapYear(u8 year) +{ + if ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)) + return TRUE; + + return FALSE; +} + +u16 ConvertDateToDayCount(u8 year, u8 month, u8 day) +{ + s32 i; + u16 dayCount = 0; + +#if (REVISION < 2) + // Revisions 0 and 1 don't add days for the year 2000, + // causing the berry glitch. + for (i = year - 1; i > 0; i--) + { + dayCount += 365; + + if (IsLeapYear(i) == TRUE) + dayCount++; + } +#else + // Revision 2 has "i >= 0" as the condition instead of "i > 0", + // which fixes the issue. + for (i = year - 1; i >= 0; i--) + { + dayCount += 365; + + if (IsLeapYear(i) == TRUE) + dayCount++; + } +#endif + + for (i = 0; i < month - 1; i++) + dayCount += gNumDaysInMonths[i]; + + if (month > MONTH_FEB && IsLeapYear(year) == TRUE) + dayCount++; + + dayCount += day; + + return dayCount; +} + +u16 RtcGetDayCount(struct SiiRtcInfo *rtc) +{ + u8 year = ConvertBcdToBinary(rtc->year); + u8 month = ConvertBcdToBinary(rtc->month); + u8 day = ConvertBcdToBinary(rtc->day); + return ConvertDateToDayCount(year, month, day); +} + +void RtcInit() +{ + gRtcErrorStatus = 0; + + RtcDisableInterrupts(); + SiiRtcUnprotect(); + gRtcProbeResult = SiiRtcProbe(); + RtcRestoreInterrupts(); + + if (!(gRtcProbeResult & 0xF)) + { + gRtcErrorStatus = RTC_INIT_ERROR; + return; + } + + if (gRtcProbeResult & 0xF0) + gRtcErrorStatus = RTC_INIT_WARNING; + else + gRtcErrorStatus = 0; + + RtcGetRawInfo(&gRtc); + gRtcErrorStatus = RtcCheckInfo(&gRtc); +} + +u16 RtcGetErrorStatus() +{ + return gRtcErrorStatus; +} + +void RtcGetInfo(struct SiiRtcInfo *rtc) +{ + if (gRtcErrorStatus & RTC_ERR_FLAG_MASK) + *rtc = gRtcDummy; + else + RtcGetRawInfo(rtc); +} + +void RtcGetDateTime(struct SiiRtcInfo *rtc) +{ + RtcDisableInterrupts(); + SiiRtcGetDateTime(rtc); + RtcRestoreInterrupts(); +} + +void RtcGetStatus(struct SiiRtcInfo *rtc) +{ + RtcDisableInterrupts(); + SiiRtcGetStatus(rtc); + RtcRestoreInterrupts(); +} + +void RtcGetRawInfo(struct SiiRtcInfo *rtc) +{ + RtcGetStatus(rtc); + RtcGetDateTime(rtc); +} + +u16 RtcCheckInfo(struct SiiRtcInfo *rtc) +{ + u16 errorFlags = 0; + s32 year; + s32 month; + s32 value; + + if (rtc->status & SIIRTCINFO_POWER) + errorFlags |= RTC_ERR_POWER_FAILURE; + + if (!(rtc->status & SIIRTCINFO_24HOUR)) + errorFlags |= RTC_ERR_12HOUR_CLOCK; + + year = ConvertBcdToBinary(rtc->year); + + if (year == 0xFF) + errorFlags |= RTC_ERR_INVALID_YEAR; + + month = ConvertBcdToBinary(rtc->month); + + if (month == 0xFF || month == 0 || month > 12) + errorFlags |= RTC_ERR_INVALID_MONTH; + + value = ConvertBcdToBinary(rtc->day); + + if (value == 0xFF) + errorFlags |= RTC_ERR_INVALID_DAY; + + if (month == MONTH_FEB) + { + if (value > IsLeapYear(year) + gNumDaysInMonths[month - 1]) + errorFlags |= RTC_ERR_INVALID_DAY; + } + else + { + if (value > gNumDaysInMonths[month - 1]) + errorFlags |= RTC_ERR_INVALID_DAY; + } + + value = ConvertBcdToBinary(rtc->hour); + + if (value > 24) + errorFlags |= RTC_ERR_INVALID_HOUR; + + value = ConvertBcdToBinary(rtc->minute); + + if (value > 60) + errorFlags |= RTC_ERR_INVALID_MINUTE; + + value = ConvertBcdToBinary(rtc->second); + + if (value > 60) + errorFlags |= RTC_ERR_INVALID_SECOND; + + return errorFlags; +} + +void RtcReset() +{ + RtcDisableInterrupts(); + SiiRtcReset(); + RtcRestoreInterrupts(); +} + +void FormatDecimalTime(u8 *dest, s32 hour, s32 minute, s32 second) +{ + dest = ConvertIntToDecimalStringN(dest, hour, STR_CONV_MODE_LEADING_ZEROS, 2); + *dest++ = CHAR_COLON; + dest = ConvertIntToDecimalStringN(dest, minute, STR_CONV_MODE_LEADING_ZEROS, 2); + *dest++ = CHAR_COLON; + dest = ConvertIntToDecimalStringN(dest, second, STR_CONV_MODE_LEADING_ZEROS, 2); + *dest = EOS; +} + +void FormatHexTime(u8 *dest, s32 hour, s32 minute, s32 second) +{ + dest = ConvertIntToHexStringN(dest, hour, STR_CONV_MODE_LEADING_ZEROS, 2); + *dest++ = CHAR_COLON; + dest = ConvertIntToHexStringN(dest, minute, STR_CONV_MODE_LEADING_ZEROS, 2); + *dest++ = CHAR_COLON; + dest = ConvertIntToHexStringN(dest, second, STR_CONV_MODE_LEADING_ZEROS, 2); + *dest = EOS; +} + +void FormatHexRtcTime(u8 *dest) +{ + FormatHexTime(dest, gRtc.hour, gRtc.minute, gRtc.second); +} + +void FormatDecimalDate(u8 *dest, s32 year, s32 month, s32 day) +{ + dest = ConvertIntToDecimalStringN(dest, year, STR_CONV_MODE_LEADING_ZEROS, 4); + *dest++ = CHAR_HYPHEN; + dest = ConvertIntToDecimalStringN(dest, month, STR_CONV_MODE_LEADING_ZEROS, 2); + *dest++ = CHAR_HYPHEN; + dest = ConvertIntToDecimalStringN(dest, day, STR_CONV_MODE_LEADING_ZEROS, 2); + *dest = EOS; +} + +void FormatHexDate(u8 *dest, s32 year, s32 month, s32 day) +{ + dest = ConvertIntToHexStringN(dest, year, STR_CONV_MODE_LEADING_ZEROS, 4); + *dest++ = CHAR_HYPHEN; + dest = ConvertIntToHexStringN(dest, month, STR_CONV_MODE_LEADING_ZEROS, 2); + *dest++ = CHAR_HYPHEN; + dest = ConvertIntToHexStringN(dest, day, STR_CONV_MODE_LEADING_ZEROS, 2); + *dest = EOS; +} + +void RtcCalcTimeDifference(struct SiiRtcInfo *rtc, struct Time *result, struct Time *t) +{ + u16 days = RtcGetDayCount(rtc); + result->seconds = ConvertBcdToBinary(rtc->second) - t->seconds; + result->minutes = ConvertBcdToBinary(rtc->minute) - t->minutes; + result->hours = ConvertBcdToBinary(rtc->hour) - t->hours; + result->days = days - t->days; + + if (result->seconds < 0) + { + result->seconds += 60; + --result->minutes; + } + + if (result->minutes < 0) + { + result->minutes += 60; + --result->hours; + } + + if (result->hours < 0) + { + result->hours += 24; + --result->days; + } +} + +void RtcCalcLocalTime() +{ + RtcGetInfo(&gRtc); + RtcCalcTimeDifference(&gRtc, &gLocalTime, &gSaveBlock2.localTimeOffset); +} + +void RtcInitLocalTimeOffset(s32 hour, s32 minute) +{ + RtcCalcLocalTimeOffset(0, hour, minute, 0); +} + +void RtcCalcLocalTimeOffset(s32 days, s32 hours, s32 minutes, s32 seconds) +{ + gLocalTime.days = days; + gLocalTime.hours = hours; + gLocalTime.minutes = minutes; + gLocalTime.seconds = seconds; + RtcGetInfo(&gRtc); + RtcCalcTimeDifference(&gRtc, &gSaveBlock2.localTimeOffset, &gLocalTime); +} + +void CalcTimeDifference(struct Time *result, struct Time *t1, struct Time *t2) +{ + result->seconds = t2->seconds - t1->seconds; + result->minutes = t2->minutes - t1->minutes; + result->hours = t2->hours - t1->hours; + result->days = t2->days - t1->days; + + if (result->seconds < 0) + { + result->seconds += 60; + --result->minutes; + } + + if (result->minutes < 0) + { + result->minutes += 60; + --result->hours; + } + + if (result->hours < 0) + { + result->hours += 24; + --result->days; + } +} + +u32 RtcGetMinuteCount() +{ + RtcGetInfo(&gRtc); + return (24 * 60) * RtcGetDayCount(&gRtc) + 60 * gRtc.hour + gRtc.minute; +} diff --git a/src/rtc_util.c b/src/rtc_util.c deleted file mode 100644 index 876d4ab24..000000000 --- a/src/rtc_util.c +++ /dev/null @@ -1,349 +0,0 @@ -#include "global.h" -#include "rtc.h" -#include "rtc_util.h" -#include "string_util.h" - -extern const struct SiiRtcInfo gRtcDummy; -extern const s32 gNumDaysInMonths[]; - -extern u16 gRtcErrorStatus; -extern struct SiiRtcInfo gRtc; -extern u8 gRtcProbeResult; -extern u16 gRtcSavedIme; - -extern struct Time gLocalTime; - -void RtcDisableInterrupts(); -void RtcRestoreInterrupts(); -u32 ConvertBcdToBinary(u8 bcd); -bool8 IsLeapYear(u8 year); -u16 ConvertDateToDayCount(u8 year, u8 month, u8 day); -u16 RtcGetDayCount(struct SiiRtcInfo *rtc); -void RtcGetInfo(struct SiiRtcInfo *rtc); -void RtcGetDateTime(struct SiiRtcInfo *rtc); -void RtcGetStatus(struct SiiRtcInfo *rtc); -void RtcGetRawInfo(struct SiiRtcInfo *rtc); -u16 RtcCheckInfo(struct SiiRtcInfo *rtc); -void RtcCalcTimeDifference(struct SiiRtcInfo *rtc, struct Time *result, struct Time *t); - -void RtcDisableInterrupts() -{ - gRtcSavedIme = REG_IME; - REG_IME = 0; -} - -void RtcRestoreInterrupts() -{ - REG_IME = gRtcSavedIme; -} - -u32 ConvertBcdToBinary(u8 bcd) -{ - if (bcd > 0x9F) - return 0xFF; - - if ((bcd & 0xF) <= 9) - return (10 * ((bcd >> 4) & 0xF)) + (bcd & 0xF); - else - return 0xFF; -} - -bool8 IsLeapYear(u8 year) -{ - if ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)) - return TRUE; - - return FALSE; -} - -u16 ConvertDateToDayCount(u8 year, u8 month, u8 day) -{ - s32 i; - u16 dayCount = 0; - -#if (REVISION < 2) - // Revisions 0 and 1 don't add days for the year 2000, - // causing the berry glitch. - for (i = year - 1; i > 0; i--) - { - dayCount += 365; - - if (IsLeapYear(i) == TRUE) - dayCount++; - } -#else - // Revision 2 has "i >= 0" as the condition instead of "i > 0", - // which fixes the issue. - for (i = year - 1; i >= 0; i--) - { - dayCount += 365; - - if (IsLeapYear(i) == TRUE) - dayCount++; - } -#endif - - for (i = 0; i < month - 1; i++) - dayCount += gNumDaysInMonths[i]; - - if (month > MONTH_FEB && IsLeapYear(year) == TRUE) - dayCount++; - - dayCount += day; - - return dayCount; -} - -u16 RtcGetDayCount(struct SiiRtcInfo *rtc) -{ - u8 year = ConvertBcdToBinary(rtc->year); - u8 month = ConvertBcdToBinary(rtc->month); - u8 day = ConvertBcdToBinary(rtc->day); - return ConvertDateToDayCount(year, month, day); -} - -void RtcInit() -{ - gRtcErrorStatus = 0; - - RtcDisableInterrupts(); - SiiRtcUnprotect(); - gRtcProbeResult = SiiRtcProbe(); - RtcRestoreInterrupts(); - - if (!(gRtcProbeResult & 0xF)) - { - gRtcErrorStatus = RTC_INIT_ERROR; - return; - } - - if (gRtcProbeResult & 0xF0) - gRtcErrorStatus = RTC_INIT_WARNING; - else - gRtcErrorStatus = 0; - - RtcGetRawInfo(&gRtc); - gRtcErrorStatus = RtcCheckInfo(&gRtc); -} - -u16 RtcGetErrorStatus() -{ - return gRtcErrorStatus; -} - -void RtcGetInfo(struct SiiRtcInfo *rtc) -{ - if (gRtcErrorStatus & RTC_ERR_FLAG_MASK) - *rtc = gRtcDummy; - else - RtcGetRawInfo(rtc); -} - -void RtcGetDateTime(struct SiiRtcInfo *rtc) -{ - RtcDisableInterrupts(); - SiiRtcGetDateTime(rtc); - RtcRestoreInterrupts(); -} - -void RtcGetStatus(struct SiiRtcInfo *rtc) -{ - RtcDisableInterrupts(); - SiiRtcGetStatus(rtc); - RtcRestoreInterrupts(); -} - -void RtcGetRawInfo(struct SiiRtcInfo *rtc) -{ - RtcGetStatus(rtc); - RtcGetDateTime(rtc); -} - -u16 RtcCheckInfo(struct SiiRtcInfo *rtc) -{ - u16 errorFlags = 0; - s32 year; - s32 month; - s32 value; - - if (rtc->status & SIIRTCINFO_POWER) - errorFlags |= RTC_ERR_POWER_FAILURE; - - if (!(rtc->status & SIIRTCINFO_24HOUR)) - errorFlags |= RTC_ERR_12HOUR_CLOCK; - - year = ConvertBcdToBinary(rtc->year); - - if (year == 0xFF) - errorFlags |= RTC_ERR_INVALID_YEAR; - - month = ConvertBcdToBinary(rtc->month); - - if (month == 0xFF || month == 0 || month > 12) - errorFlags |= RTC_ERR_INVALID_MONTH; - - value = ConvertBcdToBinary(rtc->day); - - if (value == 0xFF) - errorFlags |= RTC_ERR_INVALID_DAY; - - if (month == MONTH_FEB) - { - if (value > IsLeapYear(year) + gNumDaysInMonths[month - 1]) - errorFlags |= RTC_ERR_INVALID_DAY; - } - else - { - if (value > gNumDaysInMonths[month - 1]) - errorFlags |= RTC_ERR_INVALID_DAY; - } - - value = ConvertBcdToBinary(rtc->hour); - - if (value > 24) - errorFlags |= RTC_ERR_INVALID_HOUR; - - value = ConvertBcdToBinary(rtc->minute); - - if (value > 60) - errorFlags |= RTC_ERR_INVALID_MINUTE; - - value = ConvertBcdToBinary(rtc->second); - - if (value > 60) - errorFlags |= RTC_ERR_INVALID_SECOND; - - return errorFlags; -} - -void RtcReset() -{ - RtcDisableInterrupts(); - SiiRtcReset(); - RtcRestoreInterrupts(); -} - -void FormatDecimalTime(u8 *dest, s32 hour, s32 minute, s32 second) -{ - dest = ConvertIntToDecimalStringN(dest, hour, STR_CONV_MODE_LEADING_ZEROS, 2); - *dest++ = CHAR_COLON; - dest = ConvertIntToDecimalStringN(dest, minute, STR_CONV_MODE_LEADING_ZEROS, 2); - *dest++ = CHAR_COLON; - dest = ConvertIntToDecimalStringN(dest, second, STR_CONV_MODE_LEADING_ZEROS, 2); - *dest = EOS; -} - -void FormatHexTime(u8 *dest, s32 hour, s32 minute, s32 second) -{ - dest = ConvertIntToHexStringN(dest, hour, STR_CONV_MODE_LEADING_ZEROS, 2); - *dest++ = CHAR_COLON; - dest = ConvertIntToHexStringN(dest, minute, STR_CONV_MODE_LEADING_ZEROS, 2); - *dest++ = CHAR_COLON; - dest = ConvertIntToHexStringN(dest, second, STR_CONV_MODE_LEADING_ZEROS, 2); - *dest = EOS; -} - -void FormatHexRtcTime(u8 *dest) -{ - FormatHexTime(dest, gRtc.hour, gRtc.minute, gRtc.second); -} - -void FormatDecimalDate(u8 *dest, s32 year, s32 month, s32 day) -{ - dest = ConvertIntToDecimalStringN(dest, year, STR_CONV_MODE_LEADING_ZEROS, 4); - *dest++ = CHAR_HYPHEN; - dest = ConvertIntToDecimalStringN(dest, month, STR_CONV_MODE_LEADING_ZEROS, 2); - *dest++ = CHAR_HYPHEN; - dest = ConvertIntToDecimalStringN(dest, day, STR_CONV_MODE_LEADING_ZEROS, 2); - *dest = EOS; -} - -void FormatHexDate(u8 *dest, s32 year, s32 month, s32 day) -{ - dest = ConvertIntToHexStringN(dest, year, STR_CONV_MODE_LEADING_ZEROS, 4); - *dest++ = CHAR_HYPHEN; - dest = ConvertIntToHexStringN(dest, month, STR_CONV_MODE_LEADING_ZEROS, 2); - *dest++ = CHAR_HYPHEN; - dest = ConvertIntToHexStringN(dest, day, STR_CONV_MODE_LEADING_ZEROS, 2); - *dest = EOS; -} - -void RtcCalcTimeDifference(struct SiiRtcInfo *rtc, struct Time *result, struct Time *t) -{ - u16 days = RtcGetDayCount(rtc); - result->seconds = ConvertBcdToBinary(rtc->second) - t->seconds; - result->minutes = ConvertBcdToBinary(rtc->minute) - t->minutes; - result->hours = ConvertBcdToBinary(rtc->hour) - t->hours; - result->days = days - t->days; - - if (result->seconds < 0) - { - result->seconds += 60; - --result->minutes; - } - - if (result->minutes < 0) - { - result->minutes += 60; - --result->hours; - } - - if (result->hours < 0) - { - result->hours += 24; - --result->days; - } -} - -void RtcCalcLocalTime() -{ - RtcGetInfo(&gRtc); - RtcCalcTimeDifference(&gRtc, &gLocalTime, &gSaveBlock2.localTimeOffset); -} - -void RtcInitLocalTimeOffset(s32 hour, s32 minute) -{ - RtcCalcLocalTimeOffset(0, hour, minute, 0); -} - -void RtcCalcLocalTimeOffset(s32 days, s32 hours, s32 minutes, s32 seconds) -{ - gLocalTime.days = days; - gLocalTime.hours = hours; - gLocalTime.minutes = minutes; - gLocalTime.seconds = seconds; - RtcGetInfo(&gRtc); - RtcCalcTimeDifference(&gRtc, &gSaveBlock2.localTimeOffset, &gLocalTime); -} - -void CalcTimeDifference(struct Time *result, struct Time *t1, struct Time *t2) -{ - result->seconds = t2->seconds - t1->seconds; - result->minutes = t2->minutes - t1->minutes; - result->hours = t2->hours - t1->hours; - result->days = t2->days - t1->days; - - if (result->seconds < 0) - { - result->seconds += 60; - --result->minutes; - } - - if (result->minutes < 0) - { - result->minutes += 60; - --result->hours; - } - - if (result->hours < 0) - { - result->hours += 24; - --result->days; - } -} - -u32 RtcGetMinuteCount() -{ - RtcGetInfo(&gRtc); - return (24 * 60) * RtcGetDayCount(&gRtc) + 60 * gRtc.hour + gRtc.minute; -} diff --git a/src/siirtc.c b/src/siirtc.c new file mode 100644 index 000000000..cb152abdf --- /dev/null +++ b/src/siirtc.c @@ -0,0 +1,427 @@ +// Ruby/Sapphire/Emerald cartridges contain a Seiko Instruments Inc. (SII) +// S-3511A real-time clock (RTC). This library ("SIIRTC_V001") is for +// communicating with the RTC. + +#include "gba/gba.h" +#include "siirtc.h" + +#define STATUS_INTFE 0x02 // frequency interrupt enable +#define STATUS_INTME 0x08 // per-minute interrupt enable +#define STATUS_INTAE 0x20 // alarm interrupt enable +#define STATUS_24HOUR 0x40 // 0: 12-hour mode, 1: 24-hour mode +#define STATUS_POWER 0x80 // power on or power failure occurred + +#define TEST_MODE 0x80 // flag in the "second" byte + +#define ALARM_AM 0x00 +#define ALARM_PM 0x80 + +#define OFFSET_YEAR offsetof(struct SiiRtcInfo, year) +#define OFFSET_MONTH offsetof(struct SiiRtcInfo, month) +#define OFFSET_DAY offsetof(struct SiiRtcInfo, day) +#define OFFSET_DAY_OF_WEEK offsetof(struct SiiRtcInfo, dayOfWeek) +#define OFFSET_HOUR offsetof(struct SiiRtcInfo, hour) +#define OFFSET_MINUTE offsetof(struct SiiRtcInfo, minute) +#define OFFSET_SECOND offsetof(struct SiiRtcInfo, second) +#define OFFSET_STATUS offsetof(struct SiiRtcInfo, status) +#define OFFSET_ALARM_HOUR offsetof(struct SiiRtcInfo, alarmHour) +#define OFFSET_ALARM_MINUTE offsetof(struct SiiRtcInfo, alarmMinute) + +#define INFO_BUF(info, index) (*((u8 *)(info) + (index))) + +#define DATETIME_BUF(info, index) INFO_BUF(info, OFFSET_YEAR + index) +#define DATETIME_BUF_LEN (OFFSET_SECOND - OFFSET_YEAR + 1) + +#define TIME_BUF(info, index) INFO_BUF(info, OFFSET_HOUR + index) +#define TIME_BUF_LEN (OFFSET_SECOND - OFFSET_HOUR + 1) + +#define WR 0 // command for writing data +#define RD 1 // command for reading data + +#define CMD(n) (0x60 | (n << 1)) + +#define CMD_RESET CMD(0) +#define CMD_STATUS CMD(1) +#define CMD_DATETIME CMD(2) +#define CMD_TIME CMD(3) +#define CMD_ALARM CMD(4) + +extern vu16 GPIOPortData; +extern vu16 GPIOPortDirection; +extern vu16 GPIOPortReadEnable; + +extern bool8 gSiiRtcLocked; + +static int WriteCommand(u8 value); +static int WriteData(u8 value); +static u8 ReadData(); +static void EnableGpioPortRead(); +static void DisableGpioPortRead(); + +void SiiRtcUnprotect() +{ + EnableGpioPortRead(); + gSiiRtcLocked = FALSE; +} + +void SiiRtcProtect() +{ + DisableGpioPortRead(); + gSiiRtcLocked = TRUE; +} + +u8 SiiRtcProbe() +{ + u8 errorCode; + struct SiiRtcInfo rtc; + + if (!SiiRtcGetStatus(&rtc)) + return 0; + + errorCode = 0; + + if ((rtc.status & (SIIRTCINFO_POWER | SIIRTCINFO_24HOUR)) == SIIRTCINFO_POWER + || (rtc.status & (SIIRTCINFO_POWER | SIIRTCINFO_24HOUR)) == 0) + { + // The RTC is in 12-hour mode. Reset it and switch to 24-hour mode. + + // Note that the conditions are redundant and equivalent to simply + // "(rtc.status & SIIRTCINFO_24HOUR) == 0". It's possible that this + // was also intended to handle resetting the clock after power failure + // but a mistake was made. + + if (!SiiRtcReset()) + return 0; + + errorCode++; + } + + SiiRtcGetTime(&rtc); + + if (rtc.second & TEST_MODE) + { + // The RTC is in test mode. Reset it to leave test mode. + + if (!SiiRtcReset()) + return (errorCode << 4) & 0xF0; + + errorCode++; + } + + return (errorCode << 4) | 1; +} + +bool8 SiiRtcReset() +{ + u8 result; + struct SiiRtcInfo rtc; + + if (gSiiRtcLocked == TRUE) + return FALSE; + + gSiiRtcLocked = TRUE; + + GPIOPortData = 1; + GPIOPortData = 5; + + GPIOPortDirection = 7; + + WriteCommand(CMD_RESET | WR); + + GPIOPortData = 1; + GPIOPortData = 1; + + gSiiRtcLocked = FALSE; + + rtc.status = SIIRTCINFO_24HOUR; + + result = SiiRtcSetStatus(&rtc); + + return result; +} + +bool8 SiiRtcGetStatus(struct SiiRtcInfo *rtc) +{ + u8 statusData; + + if (gSiiRtcLocked == TRUE) + return FALSE; + + gSiiRtcLocked = TRUE; + + GPIOPortData = 1; + GPIOPortData = 5; + + GPIOPortDirection = 7; + + WriteCommand(CMD_STATUS | RD); + + GPIOPortDirection = 5; + + statusData = ReadData(); + + rtc->status = (statusData & (STATUS_POWER | STATUS_24HOUR)) + | ((statusData & STATUS_INTAE) >> 3) + | ((statusData & STATUS_INTME) >> 2) + | ((statusData & STATUS_INTFE) >> 1); + + GPIOPortData = 1; + GPIOPortData = 1; + + gSiiRtcLocked = FALSE; + + return TRUE; +} + +bool8 SiiRtcSetStatus(struct SiiRtcInfo *rtc) +{ + u8 statusData; + + if (gSiiRtcLocked == TRUE) + return FALSE; + + gSiiRtcLocked = TRUE; + + GPIOPortData = 1; + GPIOPortData = 5; + + statusData = STATUS_24HOUR + | ((rtc->status & SIIRTCINFO_INTAE) << 3) + | ((rtc->status & SIIRTCINFO_INTME) << 2) + | ((rtc->status & SIIRTCINFO_INTFE) << 1); + + GPIOPortDirection = 7; + + WriteCommand(CMD_STATUS | WR); + + WriteData(statusData); + + GPIOPortData = 1; + GPIOPortData = 1; + + gSiiRtcLocked = FALSE; + + return TRUE; +} + +bool8 SiiRtcGetDateTime(struct SiiRtcInfo *rtc) +{ + u8 i; + + if (gSiiRtcLocked == TRUE) + return FALSE; + + gSiiRtcLocked = TRUE; + + GPIOPortData = 1; + GPIOPortData = 5; + + GPIOPortDirection = 7; + + WriteCommand(CMD_DATETIME | RD); + + GPIOPortDirection = 5; + + for (i = 0; i < DATETIME_BUF_LEN; i++) + DATETIME_BUF(rtc, i) = ReadData(); + + INFO_BUF(rtc, OFFSET_HOUR) &= 0x7F; + + GPIOPortData = 1; + GPIOPortData = 1; + + gSiiRtcLocked = FALSE; + + return TRUE; +} + +bool8 SiiRtcSetDateTime(struct SiiRtcInfo *rtc) +{ + u8 i; + + if (gSiiRtcLocked == TRUE) + return FALSE; + + gSiiRtcLocked = TRUE; + + GPIOPortData = 1; + GPIOPortData = 5; + + GPIOPortDirection = 7; + + WriteCommand(CMD_DATETIME | WR); + + for (i = 0; i < DATETIME_BUF_LEN; i++) + WriteData(DATETIME_BUF(rtc, i)); + + GPIOPortData = 1; + GPIOPortData = 1; + + gSiiRtcLocked = FALSE; + + return TRUE; +} + +bool8 SiiRtcGetTime(struct SiiRtcInfo *rtc) +{ + u8 i; + + if (gSiiRtcLocked == TRUE) + return FALSE; + + gSiiRtcLocked = TRUE; + + GPIOPortData = 1; + GPIOPortData = 5; + + GPIOPortDirection = 7; + + WriteCommand(CMD_TIME | RD); + + GPIOPortDirection = 5; + + for (i = 0; i < TIME_BUF_LEN; i++) + TIME_BUF(rtc, i) = ReadData(); + + INFO_BUF(rtc, OFFSET_HOUR) &= 0x7F; + + GPIOPortData = 1; + GPIOPortData = 1; + + gSiiRtcLocked = FALSE; + + return TRUE; +} + +bool8 SiiRtcSetTime(struct SiiRtcInfo *rtc) +{ + u8 i; + + if (gSiiRtcLocked == TRUE) + return FALSE; + + gSiiRtcLocked = TRUE; + + GPIOPortData = 1; + GPIOPortData = 5; + + GPIOPortDirection = 7; + + WriteCommand(CMD_TIME | WR); + + for (i = 0; i < TIME_BUF_LEN; i++) + WriteData(TIME_BUF(rtc, i)); + + GPIOPortData = 1; + GPIOPortData = 1; + + gSiiRtcLocked = FALSE; + + return TRUE; +} + +bool8 SiiRtcSetAlarm(struct SiiRtcInfo *rtc) +{ + u8 i; + u8 alarmData[2]; + + if (gSiiRtcLocked == TRUE) + return FALSE; + + gSiiRtcLocked = TRUE; + + // Decode BCD. + alarmData[0] = (rtc->alarmHour & 0xF) + 10 * ((rtc->alarmHour >> 4) & 0xF); + + // The AM/PM flag must be set correctly even in 24-hour mode. + + if (alarmData[0] < 12) + alarmData[0] = rtc->alarmHour | ALARM_AM; + else + alarmData[0] = rtc->alarmHour | ALARM_PM; + + alarmData[1] = rtc->alarmMinute; + + GPIOPortData = 1; + GPIOPortData = 5; + + GPIOPortDirection = 7; + + WriteCommand(CMD_ALARM | WR); + + for (i = 0; i < 2; i++) + WriteData(alarmData[i]); + + GPIOPortData = 1; + GPIOPortData = 1; + + gSiiRtcLocked = FALSE; + + return TRUE; +} + +static int WriteCommand(u8 value) +{ + u8 i; + u8 temp; + + for (i = 0; i < 8; i++) + { + temp = ((value >> (7 - i)) & 1); + GPIOPortData = (temp << 1) | 4; + GPIOPortData = (temp << 1) | 4; + GPIOPortData = (temp << 1) | 4; + GPIOPortData = (temp << 1) | 5; + } + + // control reaches end of non-void function +} + +static int WriteData(u8 value) +{ + u8 i; + u8 temp; + + for (i = 0; i < 8; i++) + { + temp = ((value >> i) & 1); + GPIOPortData = (temp << 1) | 4; + GPIOPortData = (temp << 1) | 4; + GPIOPortData = (temp << 1) | 4; + GPIOPortData = (temp << 1) | 5; + } + + // control reaches end of non-void function +} + +static u8 ReadData() +{ + u8 i; + u8 temp; + u8 value; + + for (i = 0; i < 8; i++) + { + GPIOPortData = 4; + GPIOPortData = 4; + GPIOPortData = 4; + GPIOPortData = 4; + GPIOPortData = 4; + GPIOPortData = 5; + + temp = ((GPIOPortData & 2) >> 1); + value = (value >> 1) | (temp << 7); // UB: accessing uninitialized var + } + + return value; +} + +static void EnableGpioPortRead() +{ + GPIOPortReadEnable = 1; +} + +static void DisableGpioPortRead() +{ + GPIOPortReadEnable = 0; +} -- cgit v1.2.3