mirror of
https://github.com/Polprzewodnikowy/SummerCart64.git
synced 2024-11-22 05:59:15 +01:00
[SC64][SW] Added support for 400 leap years for the RTC
This commit is contained in:
parent
903efe5353
commit
a571fe16f5
@ -329,17 +329,17 @@ _This command does not require arguments or data._
|
|||||||
|
|
||||||
#### `response` (time)
|
#### `response` (time)
|
||||||
| offset | type | description |
|
| offset | type | description |
|
||||||
| ------ | ------- | ----------------------------------------- |
|
| ------ | ------- | --------------------------------------- |
|
||||||
| `0` | uint8_t | Weekday (1 - 7), 1 represents Monday |
|
| `0` | uint8_t | Weekday (1 - 7), 1 represents Monday |
|
||||||
| `1` | uint8_t | Hours (0 - 23) |
|
| `1` | uint8_t | Hours (0 - 23) |
|
||||||
| `2` | uint8_t | Minutes (0 - 59) |
|
| `2` | uint8_t | Minutes (0 - 59) |
|
||||||
| `3` | uint8_t | Seconds (0 - 59) |
|
| `3` | uint8_t | Seconds (0 - 59) |
|
||||||
| `4` | uint8_t | Century (0 - 255), 0 represents year 1900 |
|
| `4` | uint8_t | Century (0 - 7), 0 represents year 1900 |
|
||||||
| `5` | uint8_t | Year (0 - 99) |
|
| `5` | uint8_t | Year (0 - 99) |
|
||||||
| `6` | uint8_t | Month (1 - 12) |
|
| `6` | uint8_t | Month (1 - 12) |
|
||||||
| `7` | uint8_t | Day (1 - 31) |
|
| `7` | uint8_t | Day (1 - 31) |
|
||||||
|
|
||||||
Date/time values use the [BCD](https://en.wikipedia.org/wiki/Binary-coded_decimal) format, except for the century field.
|
Date/time values use the [BCD](https://en.wikipedia.org/wiki/Binary-coded_decimal) format.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@ -357,15 +357,15 @@ Date/time values use the [BCD](https://en.wikipedia.org/wiki/Binary-coded_decima
|
|||||||
|
|
||||||
#### `arg1` (time_1)
|
#### `arg1` (time_1)
|
||||||
| bits | description |
|
| bits | description |
|
||||||
| --------- | ----------------------------------------- |
|
| --------- | --------------------------------------- |
|
||||||
| `[31:24]` | Century (0 - 255), 0 represents year 1900 |
|
| `[31:24]` | Century (0 - 7), 0 represents year 1900 |
|
||||||
| `[23:16]` | Year (0 - 99) |
|
| `[23:16]` | Year (0 - 99) |
|
||||||
| `[15:8]` | Month (1 - 12) |
|
| `[15:8]` | Month (1 - 12) |
|
||||||
| `[7:0]` | Day (1 - 31) |
|
| `[7:0]` | Day (1 - 31) |
|
||||||
|
|
||||||
_This command does not send response data._
|
_This command does not send response data._
|
||||||
|
|
||||||
Date/time values use the [BCD](https://en.wikipedia.org/wiki/Binary-coded_decimal) format, except for the century field.
|
Date/time values use the [BCD](https://en.wikipedia.org/wiki/Binary-coded_decimal) format.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
@ -435,14 +435,14 @@ save_type_t cfg_get_save_type (void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void cfg_get_time (uint32_t *args) {
|
void cfg_get_time (uint32_t *args) {
|
||||||
rtc_time_t t;
|
rtc_real_time_t t;
|
||||||
rtc_get_time(&t);
|
rtc_get_time(&t);
|
||||||
args[0] = ((t.weekday << 24) | (t.hour << 16) | (t.minute << 8) | t.second);
|
args[0] = ((t.weekday << 24) | (t.hour << 16) | (t.minute << 8) | t.second);
|
||||||
args[1] = ((t.century << 24) | (t.year << 16) | (t.month << 8) | t.day);
|
args[1] = ((t.century << 24) | (t.year << 16) | (t.month << 8) | t.day);
|
||||||
}
|
}
|
||||||
|
|
||||||
void cfg_set_time (uint32_t *args) {
|
void cfg_set_time (uint32_t *args) {
|
||||||
rtc_time_t t;
|
rtc_real_time_t t;
|
||||||
t.second = (args[0] & 0xFF);
|
t.second = (args[0] & 0xFF);
|
||||||
t.minute = ((args[0] >> 8) & 0xFF);
|
t.minute = ((args[0] >> 8) & 0xFF);
|
||||||
t.hour = ((args[0] >> 16) & 0xFF);
|
t.hour = ((args[0] >> 16) & 0xFF);
|
||||||
|
@ -71,7 +71,7 @@ typedef struct {
|
|||||||
|
|
||||||
struct process {
|
struct process {
|
||||||
enum state state;
|
enum state state;
|
||||||
rtc_time_t time;
|
rtc_real_time_t time;
|
||||||
bool disk_spinning;
|
bool disk_spinning;
|
||||||
bool cmd_response_delayed;
|
bool cmd_response_delayed;
|
||||||
bool bm_running;
|
bool bm_running;
|
||||||
|
@ -14,14 +14,12 @@
|
|||||||
#define RTC_ADDRESS_RTCDATE (0x04)
|
#define RTC_ADDRESS_RTCDATE (0x04)
|
||||||
#define RTC_ADDRESS_RTCMTH (0x05)
|
#define RTC_ADDRESS_RTCMTH (0x05)
|
||||||
#define RTC_ADDRESS_RTCYEAR (0x06)
|
#define RTC_ADDRESS_RTCYEAR (0x06)
|
||||||
#define RTC_ADDRESS_CONTROL (0x07)
|
|
||||||
#define RTC_ADDRESS_OSCTRIM (0x08)
|
#define RTC_ADDRESS_OSCTRIM (0x08)
|
||||||
#define RTC_ADDRESS_SRAM_MAGIC (0x20)
|
#define RTC_ADDRESS_SRAM_MAGIC (0x20)
|
||||||
#define RTC_ADDRESS_SRAM_REGION (0x24)
|
#define RTC_ADDRESS_SRAM_REGION (0x24)
|
||||||
|
#define RTC_ADDRESS_SRAM_CENTURY (0x25)
|
||||||
#define RTC_ADDRESS_SRAM_VERSION (0x28)
|
#define RTC_ADDRESS_SRAM_VERSION (0x28)
|
||||||
#define RTC_ADDRESS_SRAM_SETTINGS (0x2C)
|
#define RTC_ADDRESS_SRAM_SETTINGS (0x2C)
|
||||||
#define RTC_ADDRESS_SRAM_CENTURY (0x40)
|
|
||||||
#define RTC_ADDRESS_SRAM_LAST_YEAR (0x41)
|
|
||||||
|
|
||||||
#define RTC_RTCSEC_ST (1 << 7)
|
#define RTC_RTCSEC_ST (1 << 7)
|
||||||
|
|
||||||
@ -32,8 +30,28 @@
|
|||||||
|
|
||||||
#define RTC_TIME_REFRESH_PERIOD_MS (500)
|
#define RTC_TIME_REFRESH_PERIOD_MS (500)
|
||||||
|
|
||||||
|
#define RTC_FROM_BCD(x) ((((((x) >> 4) & 0xF) % 10) * 10) + (((x) & 0xF) % 10))
|
||||||
|
#define RTC_TO_BCD(x) (((((x) / 10) % 10) << 4) | ((x) % 10))
|
||||||
|
|
||||||
static rtc_time_t rtc_time = {
|
|
||||||
|
typedef struct {
|
||||||
|
struct {
|
||||||
|
uint8_t second;
|
||||||
|
uint8_t minute;
|
||||||
|
uint8_t hour;
|
||||||
|
uint8_t weekday;
|
||||||
|
uint8_t day;
|
||||||
|
uint8_t month;
|
||||||
|
uint8_t year;
|
||||||
|
} time;
|
||||||
|
struct {
|
||||||
|
uint8_t value;
|
||||||
|
uint8_t last_year;
|
||||||
|
} century;
|
||||||
|
} rtc_raw_time_t;
|
||||||
|
|
||||||
|
|
||||||
|
static rtc_real_time_t rtc_time = {
|
||||||
.second = 0x00,
|
.second = 0x00,
|
||||||
.minute = 0x00,
|
.minute = 0x00,
|
||||||
.hour = 0x12,
|
.hour = 0x12,
|
||||||
@ -43,25 +61,10 @@ static rtc_time_t rtc_time = {
|
|||||||
.year = 0x24,
|
.year = 0x24,
|
||||||
.century = 0x01,
|
.century = 0x01,
|
||||||
};
|
};
|
||||||
static bool rtc_time_pending = false;
|
|
||||||
|
|
||||||
static uint8_t rtc_region = 0xFF;
|
static uint8_t rtc_region = 0xFF;
|
||||||
static bool rtc_region_pending = false;
|
|
||||||
|
|
||||||
static rtc_settings_t rtc_settings = {
|
static rtc_settings_t rtc_settings = {
|
||||||
.led_enabled = true,
|
.led_enabled = true,
|
||||||
};
|
};
|
||||||
static bool rtc_settings_pending = false;
|
|
||||||
|
|
||||||
static const uint8_t rtc_regs_bit_mask[7] = {
|
|
||||||
0b01111111,
|
|
||||||
0b01111111,
|
|
||||||
0b00111111,
|
|
||||||
0b00000111,
|
|
||||||
0b00111111,
|
|
||||||
0b00011111,
|
|
||||||
0b11111111
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
static bool rtc_read (uint8_t address, uint8_t *data, uint8_t length) {
|
static bool rtc_read (uint8_t address, uint8_t *data, uint8_t length) {
|
||||||
@ -89,86 +92,209 @@ static bool rtc_write (uint8_t address, uint8_t *data, uint8_t length) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rtc_sanitize_time (uint8_t *regs) {
|
|
||||||
for (int i = 0; i < 7; i++) {
|
|
||||||
regs[i] &= rtc_regs_bit_mask[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void rtc_osc_stop (void) {
|
static void rtc_osc_stop (void) {
|
||||||
uint8_t tmp = 0x00;
|
uint8_t tmp;
|
||||||
|
|
||||||
rtc_write(RTC_ADDRESS_RTCSEC, &tmp, 1);
|
rtc_read(RTC_ADDRESS_RTCSEC, &tmp, sizeof(tmp));
|
||||||
|
|
||||||
|
tmp &= ~(RTC_RTCSEC_ST);
|
||||||
|
|
||||||
|
rtc_write(RTC_ADDRESS_RTCSEC, &tmp, sizeof(tmp));
|
||||||
|
|
||||||
while ((!rtc_read(RTC_ADDRESS_RTCWKDAY, &tmp, 1)) && (tmp & RTC_RTCWKDAY_OSCRUN));
|
while ((!rtc_read(RTC_ADDRESS_RTCWKDAY, &tmp, 1)) && (tmp & RTC_RTCWKDAY_OSCRUN));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void rtc_sanitize_raw_time (rtc_raw_time_t *raw) {
|
||||||
|
raw->time.second &= 0b01111111;
|
||||||
|
raw->time.minute &= 0b01111111;
|
||||||
|
raw->time.hour &= 0b00111111;
|
||||||
|
raw->time.weekday &= 0b00000111;
|
||||||
|
raw->time.day &= 0b00111111;
|
||||||
|
raw->time.month &= 0b00011111;
|
||||||
|
if (raw->time.weekday == 0) {
|
||||||
|
raw->time.weekday = 7;
|
||||||
|
}
|
||||||
|
raw->century.value &= 0b00000111;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int8_t rtc_calculate_raw_day_offset (uint8_t century, uint8_t year, uint8_t month, uint8_t day, bool adjust_forward) {
|
||||||
|
int8_t raw_day_offset = ((century + 2) / 4);
|
||||||
|
if (((century % 4) == 1) && ((year > 0x00) || (month > 0x02) || ((month == 0x02) && (day >= (0x29 - raw_day_offset))))) {
|
||||||
|
raw_day_offset += 1;
|
||||||
|
}
|
||||||
|
return adjust_forward ? raw_day_offset : (-raw_day_offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8_t rtc_get_days_in_month (uint8_t century, uint8_t year, uint8_t month) {
|
||||||
|
const uint8_t DAYS_IN_MONTH[12] = {
|
||||||
|
31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
|
||||||
|
};
|
||||||
|
|
||||||
|
if (month < 1 || month > 12) {
|
||||||
|
month = (((month - 1) % 12) + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t days = DAYS_IN_MONTH[month - 1];
|
||||||
|
|
||||||
|
if (month == 2) {
|
||||||
|
if (((century % 4) == 1) || ((year > 0) && ((year % 4) == 0))) {
|
||||||
|
days += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return days;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rtc_adjust_date (uint8_t *century, uint8_t *year, uint8_t *month, uint8_t *day, int8_t day_offset) {
|
||||||
|
if (day_offset == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int8_t dec_century = RTC_FROM_BCD(*century);
|
||||||
|
int8_t dec_year = RTC_FROM_BCD(*year);
|
||||||
|
int8_t dec_month = RTC_FROM_BCD(*month);
|
||||||
|
int8_t dec_day = RTC_FROM_BCD(*day);
|
||||||
|
|
||||||
|
int8_t century_offset = 0;
|
||||||
|
int8_t year_offset = 0;
|
||||||
|
int8_t month_offset = 0;
|
||||||
|
|
||||||
|
uint8_t current_month_days = rtc_get_days_in_month(dec_century, dec_year, dec_month);
|
||||||
|
|
||||||
|
dec_day += day_offset;
|
||||||
|
if (dec_day < 1) {
|
||||||
|
month_offset = -1;
|
||||||
|
} else if (dec_day > current_month_days) {
|
||||||
|
dec_day %= current_month_days;
|
||||||
|
month_offset = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
dec_month += month_offset;
|
||||||
|
if (dec_month < 1) {
|
||||||
|
dec_month = 12;
|
||||||
|
year_offset = -1;
|
||||||
|
} else if (dec_month > 12) {
|
||||||
|
dec_month = 1;
|
||||||
|
year_offset = 1;
|
||||||
|
}
|
||||||
|
*month = RTC_TO_BCD(dec_month);
|
||||||
|
|
||||||
|
dec_year += year_offset;
|
||||||
|
if (dec_year < 0) {
|
||||||
|
dec_year = 99;
|
||||||
|
century_offset = -1;
|
||||||
|
} else if (dec_year > 99) {
|
||||||
|
dec_year = 0;
|
||||||
|
century_offset = 1;
|
||||||
|
}
|
||||||
|
*year = RTC_TO_BCD(dec_year);
|
||||||
|
|
||||||
|
dec_century += century_offset;
|
||||||
|
if (dec_century < 0) {
|
||||||
|
dec_century = 7;
|
||||||
|
} else if (dec_century > 7) {
|
||||||
|
dec_century = 0;
|
||||||
|
}
|
||||||
|
*century = RTC_TO_BCD(dec_century);
|
||||||
|
|
||||||
|
if (dec_day <= 0) {
|
||||||
|
dec_day = rtc_get_days_in_month(dec_century, dec_year, dec_month) + dec_day;
|
||||||
|
}
|
||||||
|
*day = RTC_TO_BCD(dec_day);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rtc_raw_to_real (rtc_raw_time_t *raw, rtc_real_time_t *real) {
|
||||||
|
real->century = raw->century.value;
|
||||||
|
real->year = raw->time.year;
|
||||||
|
real->month = raw->time.month;
|
||||||
|
real->day = raw->time.day;
|
||||||
|
real->weekday = raw->time.weekday;
|
||||||
|
real->hour = raw->time.hour;
|
||||||
|
real->minute = raw->time.minute;
|
||||||
|
real->second = raw->time.second;
|
||||||
|
|
||||||
|
int8_t day_offset = rtc_calculate_raw_day_offset(real->century, real->year, real->month, real->day, false);
|
||||||
|
|
||||||
|
rtc_adjust_date(&real->century, &real->year, &real->month, &real->day, day_offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rtc_real_to_raw (rtc_raw_time_t *raw, rtc_real_time_t *real) {
|
||||||
|
raw->century.value = real->century;
|
||||||
|
raw->time.year = real->year;
|
||||||
|
raw->time.month = real->month;
|
||||||
|
raw->time.day = real->day;
|
||||||
|
raw->time.weekday = real->weekday;
|
||||||
|
raw->time.hour = real->hour;
|
||||||
|
raw->time.minute = real->minute;
|
||||||
|
raw->time.second = real->second;
|
||||||
|
|
||||||
|
int8_t day_offset = rtc_calculate_raw_day_offset(raw->century.value, raw->time.year, raw->time.month, raw->time.day, true);
|
||||||
|
|
||||||
|
rtc_adjust_date(&raw->century.value, &raw->time.year, &raw->time.month, &raw->time.day, day_offset);
|
||||||
|
}
|
||||||
|
|
||||||
static void rtc_read_time (void) {
|
static void rtc_read_time (void) {
|
||||||
uint8_t regs[7];
|
rtc_raw_time_t raw;
|
||||||
uint8_t last_year;
|
bool update_raw_century = false;
|
||||||
|
|
||||||
if (rtc_read(RTC_ADDRESS_RTCSEC, regs, 7)) {
|
if (rtc_read(RTC_ADDRESS_RTCSEC, (uint8_t *) (&raw.time), sizeof(raw.time))) {
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (rtc_read(RTC_ADDRESS_SRAM_CENTURY, &rtc_time.century, 1)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (rtc_read(RTC_ADDRESS_SRAM_LAST_YEAR, &last_year, 1)) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
rtc_sanitize_time(regs);
|
if (rtc_read(RTC_ADDRESS_SRAM_CENTURY, (uint8_t *) (&raw.century), sizeof(raw.century))) {
|
||||||
|
return;
|
||||||
rtc_time.second = regs[0];
|
|
||||||
rtc_time.minute = regs[1];
|
|
||||||
rtc_time.hour = regs[2];
|
|
||||||
rtc_time.weekday = regs[3];
|
|
||||||
rtc_time.day = regs[4];
|
|
||||||
rtc_time.month = regs[5];
|
|
||||||
rtc_time.year = regs[6];
|
|
||||||
|
|
||||||
if (rtc_time.year < last_year) {
|
|
||||||
rtc_time.century += 1;
|
|
||||||
rtc_write(RTC_ADDRESS_SRAM_CENTURY, &rtc_time.century, 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rtc_time.year != last_year) {
|
rtc_sanitize_raw_time(&raw);
|
||||||
rtc_write(RTC_ADDRESS_SRAM_LAST_YEAR, &rtc_time.year, 1);
|
|
||||||
|
if (raw.time.year < raw.century.last_year) {
|
||||||
|
raw.century.value += 1;
|
||||||
|
update_raw_century = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (raw.time.year != raw.century.last_year) {
|
||||||
|
raw.century.last_year = raw.time.year;
|
||||||
|
update_raw_century = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (update_raw_century) {
|
||||||
|
rtc_write(RTC_ADDRESS_SRAM_CENTURY, (uint8_t *) (&raw.century), sizeof(raw.century));
|
||||||
|
}
|
||||||
|
|
||||||
|
rtc_raw_to_real(&raw, &rtc_time);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rtc_write_time (void) {
|
static void rtc_write_time (void) {
|
||||||
uint8_t regs[7];
|
rtc_raw_time_t raw;
|
||||||
|
uint8_t raw_regs[7];
|
||||||
|
|
||||||
|
rtc_real_to_raw(&raw, &rtc_time);
|
||||||
|
|
||||||
|
rtc_sanitize_raw_time(&raw);
|
||||||
|
|
||||||
|
raw_regs[0] = (raw.time.second | RTC_RTCSEC_ST);
|
||||||
|
raw_regs[1] = raw.time.minute;
|
||||||
|
raw_regs[2] = raw.time.hour;
|
||||||
|
raw_regs[3] = (raw.time.weekday | RTC_RTCWKDAY_VBATEN);
|
||||||
|
raw_regs[4] = raw.time.day;
|
||||||
|
raw_regs[5] = raw.time.month;
|
||||||
|
raw_regs[6] = raw.time.year;
|
||||||
|
|
||||||
|
raw.century.last_year = raw.time.year;
|
||||||
|
|
||||||
rtc_osc_stop();
|
rtc_osc_stop();
|
||||||
|
|
||||||
regs[0] = rtc_time.second;
|
rtc_write(RTC_ADDRESS_SRAM_CENTURY, (uint8_t *) (&raw.century), sizeof(raw.century));
|
||||||
regs[1] = rtc_time.minute;
|
rtc_write(RTC_ADDRESS_RTCMIN, &raw_regs[1], sizeof(raw_regs) - sizeof(raw_regs[0]));
|
||||||
regs[2] = rtc_time.hour;
|
rtc_write(RTC_ADDRESS_RTCSEC, &raw_regs[0], sizeof(raw_regs[0]));
|
||||||
regs[3] = rtc_time.weekday;
|
|
||||||
regs[4] = rtc_time.day;
|
|
||||||
regs[5] = rtc_time.month;
|
|
||||||
regs[6] = rtc_time.year;
|
|
||||||
|
|
||||||
rtc_sanitize_time(regs);
|
|
||||||
|
|
||||||
regs[0] |= RTC_RTCSEC_ST;
|
|
||||||
regs[3] |= RTC_RTCWKDAY_VBATEN;
|
|
||||||
|
|
||||||
rtc_write(RTC_ADDRESS_SRAM_CENTURY, &rtc_time.century, 1);
|
|
||||||
rtc_write(RTC_ADDRESS_SRAM_LAST_YEAR, &rtc_time.year, 1);
|
|
||||||
rtc_write(RTC_ADDRESS_RTCMIN, ®s[1], 6);
|
|
||||||
rtc_write(RTC_ADDRESS_RTCSEC, ®s[0], 1);
|
|
||||||
|
|
||||||
rtc_read_time();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rtc_read_region (void) {
|
static void rtc_read_region (void) {
|
||||||
rtc_read(RTC_ADDRESS_SRAM_REGION, &rtc_region, 1);
|
rtc_read(RTC_ADDRESS_SRAM_REGION, &rtc_region, sizeof(rtc_region));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rtc_write_region (void) {
|
static void rtc_write_region (void) {
|
||||||
rtc_write(RTC_ADDRESS_SRAM_REGION, &rtc_region, 1);
|
rtc_write(RTC_ADDRESS_SRAM_REGION, &rtc_region, sizeof(rtc_region));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rtc_read_settings (void) {
|
static void rtc_read_settings (void) {
|
||||||
@ -179,8 +305,41 @@ static void rtc_write_settings (void) {
|
|||||||
rtc_write(RTC_ADDRESS_SRAM_SETTINGS, (uint8_t *) (&rtc_settings), sizeof(rtc_settings));
|
rtc_write(RTC_ADDRESS_SRAM_SETTINGS, (uint8_t *) (&rtc_settings), sizeof(rtc_settings));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void rtc_read_joybus_time (void) {
|
||||||
|
uint32_t time[2];
|
||||||
|
|
||||||
void rtc_get_time (rtc_time_t *time) {
|
time[0] = fpga_reg_get(REG_RTC_TIME_0);
|
||||||
|
time[1] = fpga_reg_get(REG_RTC_TIME_1);
|
||||||
|
|
||||||
|
rtc_time.weekday = ((time[0] >> 24) & 0xFF) + 1;
|
||||||
|
rtc_time.hour = ((time[0] >> 16) & 0xFF);
|
||||||
|
rtc_time.minute = ((time[0] >> 8) & 0xFF);
|
||||||
|
rtc_time.second = ((time[0] >> 0) & 0xFF);
|
||||||
|
rtc_time.century = ((time[1] >> 24) & 0xFF);
|
||||||
|
rtc_time.year = ((time[1] >> 16) & 0xFF);
|
||||||
|
rtc_time.month = ((time[1] >> 8) & 0xFF);
|
||||||
|
rtc_time.day = ((time[1] >> 0) & 0xFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rtc_write_joybus_time (void) {
|
||||||
|
uint32_t time[2] = {(
|
||||||
|
((rtc_time.weekday - 1) << 24) |
|
||||||
|
(rtc_time.hour << 16) |
|
||||||
|
(rtc_time.minute << 8) |
|
||||||
|
(rtc_time.second << 0)
|
||||||
|
), (
|
||||||
|
(rtc_time.century << 24) |
|
||||||
|
(rtc_time.year << 16) |
|
||||||
|
(rtc_time.month << 8) |
|
||||||
|
(rtc_time.day << 0)
|
||||||
|
)};
|
||||||
|
|
||||||
|
fpga_reg_set(REG_RTC_TIME_0, time[0]);
|
||||||
|
fpga_reg_set(REG_RTC_TIME_1, time[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void rtc_get_time (rtc_real_time_t *time) {
|
||||||
time->second = rtc_time.second;
|
time->second = rtc_time.second;
|
||||||
time->minute = rtc_time.minute;
|
time->minute = rtc_time.minute;
|
||||||
time->hour = rtc_time.hour;
|
time->hour = rtc_time.hour;
|
||||||
@ -191,7 +350,7 @@ void rtc_get_time (rtc_time_t *time) {
|
|||||||
time->century = rtc_time.century;
|
time->century = rtc_time.century;
|
||||||
}
|
}
|
||||||
|
|
||||||
void rtc_set_time (rtc_time_t *time) {
|
void rtc_set_time (rtc_real_time_t *time) {
|
||||||
rtc_time.second = time->second;
|
rtc_time.second = time->second;
|
||||||
rtc_time.minute = time->minute;
|
rtc_time.minute = time->minute;
|
||||||
rtc_time.hour = time->hour;
|
rtc_time.hour = time->hour;
|
||||||
@ -200,7 +359,8 @@ void rtc_set_time (rtc_time_t *time) {
|
|||||||
rtc_time.month = time->month;
|
rtc_time.month = time->month;
|
||||||
rtc_time.year = time->year;
|
rtc_time.year = time->year;
|
||||||
rtc_time.century = time->century;
|
rtc_time.century = time->century;
|
||||||
rtc_time_pending = true;
|
rtc_write_time();
|
||||||
|
rtc_read_time();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -210,7 +370,7 @@ uint8_t rtc_get_region (void) {
|
|||||||
|
|
||||||
void rtc_set_region (uint8_t region) {
|
void rtc_set_region (uint8_t region) {
|
||||||
rtc_region = region;
|
rtc_region = region;
|
||||||
rtc_region_pending = true;
|
rtc_write_region();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -219,23 +379,25 @@ rtc_settings_t *rtc_get_settings (void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void rtc_save_settings (void) {
|
void rtc_save_settings (void) {
|
||||||
rtc_settings_pending = true;
|
rtc_write_settings();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void rtc_init (void) {
|
void rtc_init (void) {
|
||||||
bool uninitialized = false;
|
bool uninitialized = false;
|
||||||
const char *magic = "SC64";
|
const char *magic = "RTC1";
|
||||||
uint8_t buffer[4];
|
uint8_t buffer[sizeof(magic)];
|
||||||
|
uint8_t osc_trim = 0;
|
||||||
uint32_t settings_version;
|
uint32_t settings_version;
|
||||||
|
|
||||||
for (int i = 0; i < 4; i++) {
|
for (int i = 0; i < sizeof(buffer) / sizeof(buffer[0]); i++) {
|
||||||
buffer[i] = 0;
|
buffer[i] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
rtc_read(RTC_ADDRESS_SRAM_MAGIC, buffer, 4);
|
rtc_read(RTC_ADDRESS_SRAM_MAGIC, buffer, sizeof(buffer));
|
||||||
|
rtc_read(RTC_ADDRESS_SRAM_VERSION, (uint8_t *) (&settings_version), sizeof(settings_version));
|
||||||
|
|
||||||
for (int i = 0; i < 4; i++) {
|
for (int i = 0; i < sizeof(magic); i++) {
|
||||||
if (buffer[i] != magic[i]) {
|
if (buffer[i] != magic[i]) {
|
||||||
uninitialized = true;
|
uninitialized = true;
|
||||||
break;
|
break;
|
||||||
@ -243,19 +405,16 @@ void rtc_init (void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (uninitialized) {
|
if (uninitialized) {
|
||||||
buffer[0] = 0;
|
rtc_write(RTC_ADDRESS_OSCTRIM, &osc_trim, sizeof(osc_trim));
|
||||||
rtc_write(RTC_ADDRESS_SRAM_MAGIC, (uint8_t *) (magic), 4);
|
|
||||||
rtc_write(RTC_ADDRESS_OSCTRIM, buffer, 1);
|
|
||||||
rtc_write_time();
|
rtc_write_time();
|
||||||
rtc_write_region();
|
rtc_write_region();
|
||||||
|
rtc_write(RTC_ADDRESS_SRAM_MAGIC, (uint8_t *) (magic), sizeof(magic));
|
||||||
}
|
}
|
||||||
|
|
||||||
rtc_read(RTC_ADDRESS_SRAM_VERSION, (uint8_t *) (&settings_version), 4);
|
|
||||||
|
|
||||||
if (uninitialized || (settings_version != RTC_SETTINGS_VERSION)) {
|
if (uninitialized || (settings_version != RTC_SETTINGS_VERSION)) {
|
||||||
settings_version = RTC_SETTINGS_VERSION;
|
settings_version = RTC_SETTINGS_VERSION;
|
||||||
rtc_write(RTC_ADDRESS_SRAM_VERSION, (uint8_t *) (&settings_version), 4);
|
|
||||||
rtc_write_settings();
|
rtc_write_settings();
|
||||||
|
rtc_write(RTC_ADDRESS_SRAM_VERSION, (uint8_t *) (&settings_version), sizeof(settings_version));
|
||||||
}
|
}
|
||||||
|
|
||||||
rtc_read_time();
|
rtc_read_time();
|
||||||
@ -270,62 +429,16 @@ void rtc_process (void) {
|
|||||||
uint32_t scr = fpga_reg_get(REG_RTC_SCR);
|
uint32_t scr = fpga_reg_get(REG_RTC_SCR);
|
||||||
|
|
||||||
if ((scr & RTC_SCR_PENDING) && ((scr & RTC_SCR_MAGIC_MASK) == RTC_SCR_MAGIC)) {
|
if ((scr & RTC_SCR_PENDING) && ((scr & RTC_SCR_MAGIC_MASK) == RTC_SCR_MAGIC)) {
|
||||||
uint32_t data[2];
|
rtc_read_joybus_time();
|
||||||
|
|
||||||
data[0] = fpga_reg_get(REG_RTC_TIME_0);
|
|
||||||
data[1] = fpga_reg_get(REG_RTC_TIME_1);
|
|
||||||
|
|
||||||
rtc_time.weekday = ((data[0] >> 24) & 0xFF) + 1;
|
|
||||||
rtc_time.hour = ((data[0] >> 16) & 0xFF);
|
|
||||||
rtc_time.minute = ((data[0] >> 8) & 0xFF);
|
|
||||||
rtc_time.second = ((data[0] >> 0) & 0xFF);
|
|
||||||
rtc_time.century = ((data[1] >> 24) & 0xFF);
|
|
||||||
rtc_time.year = ((data[1] >> 16) & 0xFF);
|
|
||||||
rtc_time.month = ((data[1] >> 8) & 0xFF);
|
|
||||||
rtc_time.day = ((data[1] >> 0) & 0xFF);
|
|
||||||
rtc_time_pending = true;
|
|
||||||
|
|
||||||
fpga_reg_set(REG_RTC_TIME_0, data[0]);
|
|
||||||
fpga_reg_set(REG_RTC_TIME_1, data[1]);
|
|
||||||
fpga_reg_set(REG_RTC_SCR, RTC_SCR_DONE);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rtc_time_pending) {
|
|
||||||
rtc_time_pending = false;
|
|
||||||
rtc_write_time();
|
rtc_write_time();
|
||||||
}
|
rtc_read_time();
|
||||||
|
rtc_write_joybus_time();
|
||||||
if (rtc_region_pending) {
|
fpga_reg_set(REG_RTC_SCR, RTC_SCR_DONE);
|
||||||
rtc_region_pending = false;
|
|
||||||
rtc_write_region();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rtc_settings_pending) {
|
|
||||||
rtc_settings_pending = false;
|
|
||||||
rtc_write_settings();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (timer_countdown_elapsed(TIMER_ID_RTC)) {
|
if (timer_countdown_elapsed(TIMER_ID_RTC)) {
|
||||||
timer_countdown_start(TIMER_ID_RTC, RTC_TIME_REFRESH_PERIOD_MS);
|
timer_countdown_start(TIMER_ID_RTC, RTC_TIME_REFRESH_PERIOD_MS);
|
||||||
|
|
||||||
rtc_read_time();
|
rtc_read_time();
|
||||||
|
rtc_write_joybus_time();
|
||||||
uint32_t data[2];
|
|
||||||
|
|
||||||
data[0] = (
|
|
||||||
((rtc_time.weekday - 1) << 24) |
|
|
||||||
(rtc_time.hour << 16) |
|
|
||||||
(rtc_time.minute << 8) |
|
|
||||||
(rtc_time.second << 0)
|
|
||||||
);
|
|
||||||
data[1] = (
|
|
||||||
(rtc_time.century << 24) |
|
|
||||||
(rtc_time.year << 16) |
|
|
||||||
(rtc_time.month << 8) |
|
|
||||||
(rtc_time.day << 0)
|
|
||||||
);
|
|
||||||
|
|
||||||
fpga_reg_set(REG_RTC_TIME_0, data[0]);
|
|
||||||
fpga_reg_set(REG_RTC_TIME_1, data[1]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,15 +15,15 @@ typedef struct {
|
|||||||
uint8_t month;
|
uint8_t month;
|
||||||
uint8_t year;
|
uint8_t year;
|
||||||
uint8_t century;
|
uint8_t century;
|
||||||
} rtc_time_t;
|
} rtc_real_time_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
bool led_enabled;
|
bool led_enabled;
|
||||||
} rtc_settings_t;
|
} rtc_settings_t;
|
||||||
|
|
||||||
|
|
||||||
void rtc_get_time (rtc_time_t *time);
|
void rtc_get_time (rtc_real_time_t *time);
|
||||||
void rtc_set_time (rtc_time_t *time);
|
void rtc_set_time (rtc_real_time_t *time);
|
||||||
|
|
||||||
uint8_t rtc_get_region (void);
|
uint8_t rtc_get_region (void);
|
||||||
void rtc_set_region (uint8_t region);
|
void rtc_set_region (uint8_t region);
|
||||||
|
@ -15,12 +15,14 @@ pub fn convert_to_datetime(data: &[u8; 8]) -> Result<NaiveDateTime, Error> {
|
|||||||
let hour = u8_from_bcd(data[1]);
|
let hour = u8_from_bcd(data[1]);
|
||||||
let day = u8_from_bcd(data[7]);
|
let day = u8_from_bcd(data[7]);
|
||||||
let month = u8_from_bcd(data[6]);
|
let month = u8_from_bcd(data[6]);
|
||||||
let year = 1900u32 + (data[4] as u32 * 100) + u8_from_bcd(data[5]) as u32;
|
let year = 1900u32 + (u8_from_bcd(data[4]) as u32 * 100) + u8_from_bcd(data[5]) as u32;
|
||||||
NaiveDateTime::parse_from_str(
|
NaiveDateTime::parse_from_str(
|
||||||
&format!("{year:4}-{month:02}-{day:02}T{hour:02}:{minute:02}:{second:02}"),
|
&format!("{year:4}-{month:02}-{day:02}T{hour:02}:{minute:02}:{second:02}"),
|
||||||
"%Y-%m-%dT%H:%M:%S",
|
"%Y-%m-%dT%H:%M:%S",
|
||||||
)
|
)
|
||||||
.map_err(|_| Error::new("Couldn't convert from bytes to NaiveDateTime"))
|
.map_err(|e| {
|
||||||
|
Error::new(format!("Couldn't convert time from bytes to NaiveDateTime: {e}").as_str())
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn convert_from_datetime(datetime: NaiveDateTime) -> [u32; 2] {
|
pub fn convert_from_datetime(datetime: NaiveDateTime) -> [u32; 2] {
|
||||||
@ -31,7 +33,7 @@ pub fn convert_from_datetime(datetime: NaiveDateTime) -> [u32; 2] {
|
|||||||
let day = bcd_from_u8(datetime.day() as u8);
|
let day = bcd_from_u8(datetime.day() as u8);
|
||||||
let month = bcd_from_u8(datetime.month() as u8);
|
let month = bcd_from_u8(datetime.month() as u8);
|
||||||
let year = bcd_from_u8((datetime.year() % 100) as u8);
|
let year = bcd_from_u8((datetime.year() % 100) as u8);
|
||||||
let century = ((datetime.year() - 1900) / 100) as u8;
|
let century = bcd_from_u8(((datetime.year() - 1900) / 100) as u8);
|
||||||
[
|
[
|
||||||
u32::from_be_bytes([weekday, hour, minute, second]),
|
u32::from_be_bytes([weekday, hour, minute, second]),
|
||||||
u32::from_be_bytes([century, year, month, day]),
|
u32::from_be_bytes([century, year, month, day]),
|
||||||
|
Loading…
Reference in New Issue
Block a user