mirror of
https://github.com/Ninjdai1/pokeemerald.git
synced 2025-01-07 18:13:21 +01:00
1f4c88c952
* Copy Berry Fix MB dism from FR
347 lines
7.6 KiB
C
347 lines
7.6 KiB
C
#include "gba/gba.h"
|
|
#include "siirtc.h"
|
|
#include "global.h"
|
|
#include "main.h"
|
|
|
|
struct Time gTimeSinceBerryUpdate;
|
|
struct Time gRtcUTCTime;
|
|
|
|
static u16 sRtcProbeStatus;
|
|
static struct SiiRtcInfo sRtcInfoBuffer;
|
|
static u8 sRtcProbeCode;
|
|
static u16 sImeBak;
|
|
static struct SiiRtcInfo sRtcInfoWork;
|
|
|
|
const struct SiiRtcInfo sDefaultRTC = {
|
|
.year = 0, // 2000
|
|
.month = 1, // January
|
|
.day = 1, // 01
|
|
.dayOfWeek = 0,
|
|
.hour = 0,
|
|
.minute = 0,
|
|
.second = 0,
|
|
.status = 0,
|
|
.alarmHour = 0,
|
|
.alarmMinute = 0
|
|
};
|
|
const s32 sDaysPerMonth[] = {
|
|
31,
|
|
28,
|
|
31,
|
|
30,
|
|
31,
|
|
30,
|
|
31,
|
|
31,
|
|
30,
|
|
31,
|
|
30,
|
|
31
|
|
};
|
|
|
|
void rtc_get_status_and_datetime(struct SiiRtcInfo *);
|
|
u16 rtc_validate_datetime(struct SiiRtcInfo *);
|
|
|
|
|
|
void rtc_intr_disable(void)
|
|
{
|
|
sImeBak = REG_IME;
|
|
REG_IME = 0;
|
|
}
|
|
|
|
void rtc_intr_enable(void)
|
|
{
|
|
REG_IME = sImeBak;
|
|
}
|
|
|
|
s32 bcd_to_hex(u8 a0)
|
|
{
|
|
if (a0 >= 0xa0 || (a0 & 0xF) >= 10)
|
|
return 0xFF;
|
|
return ((a0 >> 4) & 0xF) * 10 + (a0 & 0xF);
|
|
}
|
|
|
|
bool8 is_leap_year(u8 year)
|
|
{
|
|
if ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0)
|
|
return TRUE;
|
|
return FALSE;
|
|
}
|
|
|
|
u16 rtc_count_days_parameterized(u8 year, u8 month, u8 day)
|
|
{
|
|
u16 numDays = 0;
|
|
s32 i;
|
|
for (i = year - 1; i > 0; i--)
|
|
{
|
|
numDays += 365;
|
|
if (is_leap_year(i) == TRUE)
|
|
numDays++;
|
|
}
|
|
for (i = 0; i < month - 1; i++)
|
|
numDays += sDaysPerMonth[i];
|
|
if (month > MONTH_FEB && is_leap_year(year) == TRUE)
|
|
numDays++;
|
|
numDays += day;
|
|
return numDays;
|
|
}
|
|
|
|
u16 rtc_count_days_from_info(struct SiiRtcInfo *info)
|
|
{
|
|
return rtc_count_days_parameterized(bcd_to_hex(info->year), bcd_to_hex(info->month), bcd_to_hex(info->day));
|
|
}
|
|
|
|
static void rtc_probe_status(void)
|
|
{
|
|
sRtcProbeStatus = 0;
|
|
rtc_intr_disable();
|
|
SiiRtcUnprotect();
|
|
sRtcProbeCode = SiiRtcProbe();
|
|
rtc_intr_enable();
|
|
if ((sRtcProbeCode & 0xF) != 1)
|
|
sRtcProbeStatus = 1;
|
|
else
|
|
{
|
|
if (sRtcProbeCode & 0xF0)
|
|
sRtcProbeStatus = 2;
|
|
else
|
|
sRtcProbeStatus = 0;
|
|
rtc_get_status_and_datetime(&sRtcInfoBuffer);
|
|
sRtcProbeStatus = rtc_validate_datetime(&sRtcInfoBuffer);
|
|
}
|
|
}
|
|
|
|
u16 rtc_get_probe_status(void)
|
|
{
|
|
return sRtcProbeStatus;
|
|
}
|
|
|
|
void sub_020106EC(struct SiiRtcInfo * info)
|
|
{
|
|
if (sRtcProbeStatus & 0xFF0)
|
|
*info = sDefaultRTC;
|
|
else
|
|
rtc_get_status_and_datetime(info);
|
|
}
|
|
|
|
void rtc_get_datetime(struct SiiRtcInfo * info)
|
|
{
|
|
rtc_intr_disable();
|
|
SiiRtcGetDateTime(info);
|
|
rtc_intr_enable();
|
|
}
|
|
|
|
void rtc_get_status(struct SiiRtcInfo * info)
|
|
{
|
|
rtc_intr_disable();
|
|
SiiRtcGetStatus(info);
|
|
rtc_intr_enable();
|
|
}
|
|
|
|
void rtc_get_status_and_datetime(struct SiiRtcInfo * info)
|
|
{
|
|
rtc_get_status(info);
|
|
rtc_get_datetime(info);
|
|
}
|
|
|
|
u16 rtc_validate_datetime(struct SiiRtcInfo * info)
|
|
{
|
|
s32 year, month, day;
|
|
u16 r4 = (info->status & SIIRTCINFO_POWER) ? 0x20 : 0;
|
|
if (!(info->status & SIIRTCINFO_24HOUR))
|
|
r4 |= 0x10;
|
|
year = bcd_to_hex(info->year);
|
|
if (year == 0xFF)
|
|
r4 |= 0x40;
|
|
month = bcd_to_hex(info->month);
|
|
if (month == 0xFF || month == 0 || month > 12)
|
|
r4 |= 0x80;
|
|
day = bcd_to_hex(info->day);
|
|
if (day == 0xFF)
|
|
r4 |= 0x100;
|
|
if (month == MONTH_FEB)
|
|
{
|
|
if (day > is_leap_year(year) + sDaysPerMonth[1])
|
|
r4 |= 0x100;
|
|
}
|
|
else
|
|
{
|
|
if (day > sDaysPerMonth[month - 1])
|
|
r4 |= 0x100;
|
|
}
|
|
day = bcd_to_hex(info->hour);
|
|
if (day > 24)
|
|
r4 |= 0x200;
|
|
day = bcd_to_hex(info->minute);
|
|
if (day > 60)
|
|
r4 |= 0x400;
|
|
day = bcd_to_hex(info->second);
|
|
if (day > 60)
|
|
r4 |= 0x800;
|
|
return r4;
|
|
}
|
|
|
|
void rtc_reset(void)
|
|
{
|
|
rtc_intr_disable();
|
|
SiiRtcReset();
|
|
rtc_intr_enable();
|
|
}
|
|
|
|
void rtc_sub_time_from_datetime(struct SiiRtcInfo * datetime, struct Time * dest, struct Time * timediff)
|
|
{
|
|
u16 r4 = rtc_count_days_from_info(datetime);
|
|
dest->seconds = bcd_to_hex(datetime->second) - timediff->seconds;
|
|
dest->minutes = bcd_to_hex(datetime->minute) - timediff->minutes;
|
|
dest->hours = bcd_to_hex(datetime->hour) - timediff->hours;
|
|
dest->days = r4 - timediff->days;
|
|
if (dest->seconds < 0)
|
|
{
|
|
dest->seconds += 60;
|
|
dest->minutes--;
|
|
}
|
|
if (dest->minutes < 0)
|
|
{
|
|
dest->minutes += 60;
|
|
dest->hours--;
|
|
}
|
|
if (dest->hours < 0)
|
|
{
|
|
dest->hours += 24;
|
|
dest->days--;
|
|
}
|
|
}
|
|
|
|
void rtc_sub_time_from_time(struct Time * dest, struct Time * diff, struct Time * src)
|
|
{
|
|
dest->seconds = src->seconds - diff->seconds;
|
|
dest->minutes = src->minutes - diff->minutes;
|
|
dest->hours = src->hours - diff->hours;
|
|
dest->days = src->days - diff->days;
|
|
if (dest->seconds < 0)
|
|
{
|
|
dest->seconds += 60;
|
|
dest->minutes--;
|
|
}
|
|
if (dest->minutes < 0)
|
|
{
|
|
dest->minutes += 60;
|
|
dest->hours--;
|
|
}
|
|
if (dest->hours < 0)
|
|
{
|
|
dest->hours += 24;
|
|
dest->days--;
|
|
}
|
|
}
|
|
|
|
bool32 rtc_maincb_is_rtc_working(void)
|
|
{
|
|
rtc_probe_status();
|
|
if (rtc_get_probe_status() & 0xFF0)
|
|
return FALSE;
|
|
return TRUE;
|
|
}
|
|
|
|
void rtc_set_datetime(struct SiiRtcInfo * info)
|
|
{
|
|
vu16 imeBak = REG_IME;
|
|
REG_IME = 0;
|
|
SiiRtcSetDateTime(info);
|
|
REG_IME = imeBak;
|
|
}
|
|
|
|
bool32 rtc_maincb_is_time_since_last_berry_update_positive(u8 * a0)
|
|
{
|
|
rtc_get_status_and_datetime(&sRtcInfoWork);
|
|
*a0 = bcd_to_hex(sRtcInfoWork.year);
|
|
rtc_sub_time_from_datetime(&sRtcInfoWork, &gRtcUTCTime, LocalTimeOffset);
|
|
rtc_sub_time_from_time(&gTimeSinceBerryUpdate, LastBerryTreeUpdate, &gRtcUTCTime);
|
|
if (gTimeSinceBerryUpdate.days * 1440 + gTimeSinceBerryUpdate.hours * 60 + gTimeSinceBerryUpdate.minutes >= 0)
|
|
return TRUE;
|
|
return FALSE;
|
|
}
|
|
|
|
u32 hex_to_bcd(u8 a0)
|
|
{
|
|
u32 r4;
|
|
if (a0 > 99)
|
|
return 0xFF;
|
|
r4 = Div(a0, 10) << 4;
|
|
r4 |= Mod(a0, 10);
|
|
return r4;
|
|
}
|
|
|
|
void sii_rtc_inc(u8 * a0)
|
|
{
|
|
*a0 = hex_to_bcd(bcd_to_hex(*a0) + 1);
|
|
}
|
|
|
|
void sii_rtc_inc_month(struct SiiRtcInfo * a0)
|
|
{
|
|
sii_rtc_inc(&a0->month);
|
|
if (bcd_to_hex(a0->month) > 12)
|
|
{
|
|
sii_rtc_inc(&a0->year);
|
|
a0->month = MONTH_JAN;
|
|
}
|
|
}
|
|
|
|
void sii_rtc_inc_day(struct SiiRtcInfo * a0)
|
|
{
|
|
sii_rtc_inc(&a0->day);
|
|
if (bcd_to_hex(a0->day) > sDaysPerMonth[bcd_to_hex(a0->month) - 1])
|
|
{
|
|
if (!is_leap_year(bcd_to_hex(a0->year)) || bcd_to_hex(a0->month) != MONTH_FEB || bcd_to_hex(a0->day) != 29)
|
|
{
|
|
a0->day = 1;
|
|
sii_rtc_inc_month(a0);
|
|
}
|
|
}
|
|
}
|
|
|
|
bool32 rtc_is_past_feb_28_2000(struct SiiRtcInfo * a0)
|
|
{
|
|
if (bcd_to_hex(a0->year) == 0)
|
|
{
|
|
if (bcd_to_hex(a0->month) == MONTH_JAN)
|
|
return FALSE;
|
|
if (bcd_to_hex(a0->month) > MONTH_FEB)
|
|
return TRUE;
|
|
if (bcd_to_hex(a0->day) == 29)
|
|
return TRUE;
|
|
return FALSE;
|
|
}
|
|
if (bcd_to_hex(a0->year) == 1)
|
|
return TRUE;
|
|
return FALSE;
|
|
}
|
|
|
|
void rtc_maincb_fix_date(void)
|
|
{
|
|
rtc_get_status_and_datetime(&sRtcInfoWork);
|
|
if (bcd_to_hex(sRtcInfoWork.year) == 0 || bcd_to_hex(sRtcInfoWork.year) == 1)
|
|
{
|
|
if (bcd_to_hex(sRtcInfoWork.year) == 1)
|
|
{
|
|
sRtcInfoWork.year = 2;
|
|
sRtcInfoWork.month = MONTH_JAN;
|
|
sRtcInfoWork.day = 2;
|
|
rtc_set_datetime(&sRtcInfoWork);
|
|
}
|
|
else
|
|
{
|
|
if (rtc_is_past_feb_28_2000(&sRtcInfoWork) == TRUE)
|
|
{
|
|
sii_rtc_inc_day(&sRtcInfoWork);
|
|
sii_rtc_inc(&sRtcInfoWork.year);
|
|
}
|
|
else
|
|
{
|
|
sii_rtc_inc(&sRtcInfoWork.year);
|
|
}
|
|
rtc_set_datetime(&sRtcInfoWork);
|
|
}
|
|
}
|
|
}
|