diff options
author | YamaArashi <shadow962@live.com> | 2016-02-03 00:26:25 -0800 |
---|---|---|
committer | YamaArashi <shadow962@live.com> | 2016-02-03 00:26:25 -0800 |
commit | 5fd538d1802b2ae9e3e854140f68cb45fe50e97a (patch) | |
tree | a7d3cc4b70435a6cc4a94b4497307393d743f28d /src | |
parent | 6f965a9eca507c27049fbd90a57f620b63c92d6d (diff) |
RTC code/data
Diffstat (limited to 'src')
-rw-r--r-- | src/librtc.c | 174 | ||||
-rw-r--r-- | src/rtc_util.c | 335 | ||||
-rw-r--r-- | src/string_util.c | 7 |
3 files changed, 423 insertions, 93 deletions
diff --git a/src/librtc.c b/src/librtc.c index a64c5af89..b87862a8f 100644 --- a/src/librtc.c +++ b/src/librtc.c @@ -1,29 +1,22 @@ -#include "global.h" - -struct RtcInfo -{ - u8 year; - u8 month; - u8 dayOfMonth; - u8 dayOfWeek; - u8 hour; - u8 minute; - u8 second; - u8 control; - u8 unknown1; - u8 unknown2; -}; - -#define OFFSET_YEAR offsetof(struct RtcInfo, year) -#define OFFSET_MONTH offsetof(struct RtcInfo, month) -#define OFFSET_DAY_OF_MONTH offsetof(struct RtcInfo, dayOfMonth) -#define OFFSET_DAY_OF_WEEK offsetof(struct RtcInfo, dayOfWeek) -#define OFFSET_HOUR offsetof(struct RtcInfo, hour) -#define OFFSET_MINUTE offsetof(struct RtcInfo, minute) -#define OFFSET_SECOND offsetof(struct RtcInfo, second) -#define OFFSET_CONTROL offsetof(struct RtcInfo, control) -#define OFFSET_UNKNOWN1 offsetof(struct RtcInfo, unknown1) -#define OFFSET_UNKNOWN2 offsetof(struct RtcInfo, unknown2) +#include "gba/gba.h" +#include "rtc.h" + +#define RTC_CTRL_UNK1 0x02 // unknown +#define RTC_CTRL_IRQ_ENABLE 0x08 // per-minute IRQ enable +#define RTC_CTRL_UNK2 0x20 // unknown +#define RTC_CTRL_24HOUR 0x40 // 0: 12-hour mode, 1: 24-hour mode +#define RTC_CTRL_POWER_FAILURE 0x80 // power failure occurred + +#define OFFSET_YEAR offsetof(struct RtcInfo, year) +#define OFFSET_MONTH offsetof(struct RtcInfo, month) +#define OFFSET_DAY offsetof(struct RtcInfo, day) +#define OFFSET_DAY_OF_WEEK offsetof(struct RtcInfo, dayOfWeek) +#define OFFSET_HOUR offsetof(struct RtcInfo, hour) +#define OFFSET_MINUTE offsetof(struct RtcInfo, minute) +#define OFFSET_SECOND offsetof(struct RtcInfo, second) +#define OFFSET_CONTROL offsetof(struct RtcInfo, control) +#define OFFSET_UNKNOWN1 offsetof(struct RtcInfo, unknown1) +#define OFFSET_UNKNOWN2 offsetof(struct RtcInfo, unknown2) #define RTC_BUF(info, index) (*((u8 *)(info) + (index))) @@ -33,57 +26,56 @@ struct RtcInfo #define RTC_TIME_BUF(info, index) (*((u8 *)(info) + OFFSET_HOUR + (index))) #define RTC_TIME_BUF_LEN (OFFSET_SECOND - OFFSET_HOUR + 1) +#define RTC_CMD_RESET 0x60 +#define RTC_CMD_WR_CONTROL 0x62 +#define RTC_CMD_RD_CONTROL 0x63 +#define RTC_CMD_WR_DATETIME 0x64 +#define RTC_CMD_RD_DATETIME 0x65 +#define RTC_CMD_WR_TIME 0x66 +#define RTC_CMD_RD_TIME 0x67 +#define RTC_CMD_WR_UNKNOWN 0x68 + extern vu16 GPIOPortData; extern vu16 GPIOPortDirection; -extern vu16 GPIOPortReadWrite; +extern vu16 GPIOPortReadEnable; extern bool8 gRtcLocked; -void RTC_SetReadWrite(); -void RTC_SetReadOnly(); -u8 RTC_Init(); -bool8 RTC_Reset(); -bool8 RTC_GetControlReg(struct RtcInfo *rtc); -bool8 RTC_SetControlReg(struct RtcInfo *rtc); -bool8 RTC_GetDateTime(struct RtcInfo *rtc); -bool8 RTC_SetDateTime(struct RtcInfo *rtc); -bool8 RTC_GetTime(struct RtcInfo *rtc); -bool8 RTC_SetTime(struct RtcInfo *rtc); -bool8 RTC_SetUnknownData(struct RtcInfo *rtc); -s32 RTC_WriteByte(u8 value); -s32 RTC_WriteByteReversed(u8 value); -u8 RTC_ReadByte(); -void RTC_SetReadWriteInternal(); -void RTC_SetReadOnlyInternal(); - -void RTC_SetReadWrite() +s32 RTC_WriteCommand(u8 value); +s32 RTC_WriteData(u8 value); +u8 RTC_ReadData(); +void RTC_EnableGpioPortRead(); +void RTC_DisableGpioPortRead(); + +void RTC_Unprotect() { - RTC_SetReadWriteInternal(); + RTC_EnableGpioPortRead(); gRtcLocked = FALSE; } -void RTC_SetReadOnly() +void RTC_Protect() { - RTC_SetReadOnlyInternal(); + RTC_DisableGpioPortRead(); gRtcLocked = TRUE; } -u8 RTC_Init() +u8 RTC_Probe() { - u8 v2; + u8 errorCode; struct RtcInfo rtc; - if (!RTC_GetControlReg(&rtc)) + if (!RTC_GetControl(&rtc)) return 0; - v2 = 0; + errorCode = 0; - if ((rtc.control & 0xC0) == 0x80 || !(rtc.control & 0xC0)) + if ((rtc.control & (RTC_INFO_CTRL_POWER_FAILURE | RTC_INFO_CTRL_24HOUR)) == RTC_INFO_CTRL_POWER_FAILURE + || (rtc.control & (RTC_INFO_CTRL_POWER_FAILURE | RTC_INFO_CTRL_24HOUR)) == 0) { if (!RTC_Reset()) return 0; - v2++; + errorCode++; } RTC_GetTime(&rtc); @@ -91,12 +83,12 @@ u8 RTC_Init() if (rtc.second & 0x80) { if (!RTC_Reset()) - return (v2 << 4) & 0xF0; + return (errorCode << 4) & 0xF0; - v2++; + errorCode++; } - return (v2 << 4) | 1; + return (errorCode << 4) | 1; } bool8 RTC_Reset() @@ -114,21 +106,21 @@ bool8 RTC_Reset() GPIOPortDirection = 7; - RTC_WriteByte(0x60); + RTC_WriteCommand(RTC_CMD_RESET); GPIOPortData = 1; GPIOPortData = 1; gRtcLocked = FALSE; - rtc.control = 0x40; + rtc.control = RTC_INFO_CTRL_24HOUR; - result = RTC_SetControlReg(&rtc); + result = RTC_SetControl(&rtc); return result; } -bool8 RTC_GetControlReg(struct RtcInfo *rtc) +bool8 RTC_GetControl(struct RtcInfo *rtc) { u8 controlData; @@ -142,13 +134,16 @@ bool8 RTC_GetControlReg(struct RtcInfo *rtc) GPIOPortDirection = 7; - RTC_WriteByte(0x63); + RTC_WriteCommand(RTC_CMD_RD_CONTROL); GPIOPortDirection = 5; - controlData = RTC_ReadByte(); + controlData = RTC_ReadData(); - rtc->control = (controlData & 0xC0) | ((controlData & 0x20) >> 3) | ((controlData & 8) >> 2) | ((controlData & 2) >> 1); + rtc->control = (controlData & (RTC_CTRL_POWER_FAILURE | RTC_CTRL_24HOUR)) + | ((controlData & RTC_CTRL_UNK2) >> 3) + | ((controlData & RTC_CTRL_IRQ_ENABLE) >> 2) + | ((controlData & RTC_CTRL_UNK1) >> 1); GPIOPortData = 1; GPIOPortData = 1; @@ -158,7 +153,7 @@ bool8 RTC_GetControlReg(struct RtcInfo *rtc) return TRUE; } -bool8 RTC_SetControlReg(struct RtcInfo *rtc) +bool8 RTC_SetControl(struct RtcInfo *rtc) { u8 controlData; @@ -170,13 +165,16 @@ bool8 RTC_SetControlReg(struct RtcInfo *rtc) GPIOPortData = 1; GPIOPortData = 5; - controlData = ((rtc->control & 4) << 3) | (1 << 6) | ((rtc->control & 2) << 2) | ((rtc->control & 1) << 1); + controlData = RTC_CTRL_24HOUR + | ((rtc->control & RTC_INFO_CTRL_UNK2) << 3) + | ((rtc->control & RTC_INFO_CTRL_IRQ_ENABLE) << 2) + | ((rtc->control & RTC_INFO_CTRL_UNK1) << 1); GPIOPortDirection = 7; - RTC_WriteByte(0x62); + RTC_WriteCommand(RTC_CMD_WR_CONTROL); - RTC_WriteByteReversed(controlData); + RTC_WriteData(controlData); GPIOPortData = 1; GPIOPortData = 1; @@ -200,12 +198,12 @@ bool8 RTC_GetDateTime(struct RtcInfo *rtc) GPIOPortDirection = 7; - RTC_WriteByte(0x65); + RTC_WriteCommand(RTC_CMD_RD_DATETIME); GPIOPortDirection = 5; for (i = 0; i < RTC_DATETIME_BUF_LEN; i++) - RTC_DATETIME_BUF(rtc, i) = RTC_ReadByte(); + RTC_DATETIME_BUF(rtc, i) = RTC_ReadData(); RTC_BUF(rtc, OFFSET_HOUR) &= 0x7F; @@ -231,10 +229,10 @@ bool8 RTC_SetDateTime(struct RtcInfo *rtc) GPIOPortDirection = 7; - RTC_WriteByte(0x64); + RTC_WriteCommand(RTC_CMD_WR_DATETIME); for (i = 0; i < RTC_DATETIME_BUF_LEN; i++) - RTC_WriteByteReversed(RTC_DATETIME_BUF(rtc, i)); + RTC_WriteData(RTC_DATETIME_BUF(rtc, i)); GPIOPortData = 1; GPIOPortData = 1; @@ -258,12 +256,12 @@ bool8 RTC_GetTime(struct RtcInfo *rtc) GPIOPortDirection = 7; - RTC_WriteByte(0x67); + RTC_WriteCommand(RTC_CMD_RD_TIME); GPIOPortDirection = 5; for (i = 0; i < RTC_TIME_BUF_LEN; i++) - RTC_TIME_BUF(rtc, i) = RTC_ReadByte(); + RTC_TIME_BUF(rtc, i) = RTC_ReadData(); RTC_BUF(rtc, OFFSET_HOUR) &= 0x7F; @@ -289,10 +287,10 @@ bool8 RTC_SetTime(struct RtcInfo *rtc) GPIOPortDirection = 7; - RTC_WriteByte(0x66); + RTC_WriteCommand(RTC_CMD_WR_TIME); for (i = 0; i < RTC_TIME_BUF_LEN; i++) - RTC_WriteByteReversed(RTC_TIME_BUF(rtc, i)); + RTC_WriteData(RTC_TIME_BUF(rtc, i)); GPIOPortData = 1; GPIOPortData = 1; @@ -312,9 +310,13 @@ bool8 RTC_SetUnknownData(struct RtcInfo *rtc) gRtcLocked = TRUE; + // unknown1 appears to be a BCD number in the range 0-11, + // so it may be an hour in 12-hour format. + // Months are normally 1-12. + a[0] = ((rtc->unknown1 & 0xF) + 10 * ((rtc->unknown1 >> 4) & 0xF)); - if (a[0] <= 0xB) + if (a[0] < 12) a[0] = rtc->unknown1; else a[0] = rtc->unknown1 | 0x80; @@ -326,10 +328,10 @@ bool8 RTC_SetUnknownData(struct RtcInfo *rtc) GPIOPortDirection = 7; - RTC_WriteByte(0x68); + RTC_WriteCommand(RTC_CMD_WR_UNKNOWN); for (i = 0; i < 2; i++) - RTC_WriteByteReversed(a[i]); + RTC_WriteData(a[i]); GPIOPortData = 1; GPIOPortData = 1; @@ -339,7 +341,7 @@ bool8 RTC_SetUnknownData(struct RtcInfo *rtc) return TRUE; } -s32 RTC_WriteByte(u8 value) +s32 RTC_WriteCommand(u8 value) { u8 i; u8 temp; @@ -356,7 +358,7 @@ s32 RTC_WriteByte(u8 value) // control reaches end of non-void function } -s32 RTC_WriteByteReversed(u8 value) +s32 RTC_WriteData(u8 value) { u8 i; u8 temp; @@ -373,7 +375,7 @@ s32 RTC_WriteByteReversed(u8 value) // control reaches end of non-void function } -u8 RTC_ReadByte() +u8 RTC_ReadData() { u8 i; u8 temp; @@ -395,12 +397,12 @@ u8 RTC_ReadByte() return value; } -void RTC_SetReadWriteInternal() +void RTC_EnableGpioPortRead() { - GPIOPortReadWrite = 1; + GPIOPortReadEnable = 1; } -void RTC_SetReadOnlyInternal() +void RTC_DisableGpioPortRead() { - GPIOPortReadWrite = 0; + GPIOPortReadEnable = 0; } diff --git a/src/rtc_util.c b/src/rtc_util.c new file mode 100644 index 000000000..b279ec753 --- /dev/null +++ b/src/rtc_util.c @@ -0,0 +1,335 @@ +#include "global.h" +#include "rtc.h" +#include "rtc_util.h" +#include "string_util.h" + +extern const struct RtcInfo gDefaultRtcInfo; +extern const s32 gNumDaysInMonths[]; + +extern u16 gRtcErrorFlags; +extern struct RtcInfo gRtcInfo; +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 RtcInfo *rtc); +void RtcGetInfo(struct RtcInfo *rtc); +void RtcGetDateTime(struct RtcInfo *rtc); +void RtcGetControl(struct RtcInfo *rtc); +void RtcGetRawInfo(struct RtcInfo *rtc); +u16 RtcCheckInfo(struct RtcInfo *rtc); +void RtcCalcTimeDifference(struct RtcInfo *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; + + for (i = year - 1; i > 0; i--) + { + dayCount += 365; + + if (IsLeapYear(i) == TRUE) + dayCount++; + } + + 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 RtcInfo *rtc) +{ + u8 year = ConvertBcdToBinary(rtc->year); + u8 month = ConvertBcdToBinary(rtc->month); + u8 day = ConvertBcdToBinary(rtc->day); + return ConvertDateToDayCount(year, month, day); +} + +void RtcInit() +{ + gRtcErrorFlags = 0; + + RtcDisableInterrupts(); + RTC_Unprotect(); + gRtcProbeResult = RTC_Probe(); + RtcRestoreInterrupts(); + + if (!(gRtcProbeResult & 0xF)) + { + gRtcErrorFlags = 1; + return; + } + + if (gRtcProbeResult & 0xF0) + gRtcErrorFlags = 2; + else + gRtcErrorFlags = 0; + + RtcGetRawInfo(&gRtcInfo); + gRtcErrorFlags = RtcCheckInfo(&gRtcInfo); +} + +u16 RtcGetErrorFlags() +{ + return gRtcErrorFlags; +} + +void RtcGetInfo(struct RtcInfo *rtc) +{ + if (gRtcErrorFlags & 0xFF0) + *rtc = gDefaultRtcInfo; + else + RtcGetRawInfo(rtc); +} + +void RtcGetDateTime(struct RtcInfo *rtc) +{ + RtcDisableInterrupts(); + RTC_GetDateTime(rtc); + RtcRestoreInterrupts(); +} + +void RtcGetControl(struct RtcInfo *rtc) +{ + RtcDisableInterrupts(); + RTC_GetControl(rtc); + RtcRestoreInterrupts(); +} + +void RtcGetRawInfo(struct RtcInfo *rtc) +{ + RtcGetControl(rtc); + RtcGetDateTime(rtc); +} + +u16 RtcCheckInfo(struct RtcInfo *rtc) +{ + u16 errorFlags = 0; + s32 year; + s32 month; + s32 value; + + if (rtc->control & RTC_INFO_CTRL_POWER_FAILURE) + errorFlags |= 0x20; + + if (!(rtc->control & RTC_INFO_CTRL_24HOUR)) + errorFlags |= 0x10; + + year = ConvertBcdToBinary(rtc->year); + + if (year == 0xFF) + errorFlags |= 0x40; + + month = ConvertBcdToBinary(rtc->month); + + if (month == 0xFF || month == 0 || month > 12) + errorFlags |= 0x80; + + value = ConvertBcdToBinary(rtc->day); + + if (value == 0xFF) + errorFlags |= 0x100; + + if (month == MONTH_FEB) + { + if (value > IsLeapYear(year) + gNumDaysInMonths[month - 1]) + errorFlags |= 0x100; + } + else + { + if (value > gNumDaysInMonths[month - 1]) + errorFlags |= 0x100; + } + + value = ConvertBcdToBinary(rtc->hour); + + if (value > 24) + errorFlags |= 0x200; + + value = ConvertBcdToBinary(rtc->minute); + + if (value > 60) + errorFlags |= 0x400; + + value = ConvertBcdToBinary(rtc->second); + + if (value > 60) + errorFlags |= 0x800; + + return errorFlags; +} + +void RtcReset() +{ + RtcDisableInterrupts(); + RTC_Reset(); + 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, gRtcInfo.hour, gRtcInfo.minute, gRtcInfo.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 RtcInfo *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(&gRtcInfo); + RtcCalcTimeDifference(&gRtcInfo, &gLocalTime, &gSaveBlock2.localTimeOffset); +} + +void RtcInitLocalTimeOffset(s32 hours, s32 minutes) +{ + RtcCalcLocalTimeOffset(0, hours, minutes, 0); +} + +void RtcCalcLocalTimeOffset(s32 days, s32 hours, s32 minutes, s32 seconds) +{ + gLocalTime.days = days; + gLocalTime.hours = hours; + gLocalTime.minutes = minutes; + gLocalTime.seconds = seconds; + RtcGetInfo(&gRtcInfo); + RtcCalcTimeDifference(&gRtcInfo, &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(&gRtcInfo); + return (24 * 60) * RtcGetDayCount(&gRtcInfo) + 60 * gRtcInfo.hour + gRtcInfo.minute; +} diff --git a/src/string_util.c b/src/string_util.c index 221319ae3..a2d2d9cd2 100644 --- a/src/string_util.c +++ b/src/string_util.c @@ -1,13 +1,6 @@ #include "global.h" #include "string_util.h" -#define CHAR_SPACE 0x00 -#define CHAR_QUESTION_MARK 0xAC - -#define EXT_CTRL_CODE_BEGIN 0xFC // extended control code -#define PLACEHOLDER_BEGIN 0xFD // string placeholder -#define EOS 0xFF // end of string - #define MAX_PLACEHOLDER_ID 0xD typedef u8 *(*ExpandPlaceholderFunc)(); |