From a571fe16f5bb7e93beaa8886489d2f23fef6f0ed Mon Sep 17 00:00:00 2001 From: Mateusz Faderewski Date: Fri, 14 Jun 2024 21:47:10 +0200 Subject: [PATCH] [SC64][SW] Added support for 400 leap years for the RTC --- docs/03_usb_interface.md | 36 ++-- sw/controller/src/cfg.c | 4 +- sw/controller/src/dd.c | 2 +- sw/controller/src/rtc.c | 393 ++++++++++++++++++++++------------- sw/controller/src/rtc.h | 6 +- sw/deployer/src/sc64/time.rs | 8 +- 6 files changed, 282 insertions(+), 167 deletions(-) diff --git a/docs/03_usb_interface.md b/docs/03_usb_interface.md index c8f6eff..9b8cc7e 100644 --- a/docs/03_usb_interface.md +++ b/docs/03_usb_interface.md @@ -328,18 +328,18 @@ Use this command to set value of persistent setting option. Available persistent _This command does not require arguments or data._ #### `response` (time) -| offset | type | description | -| ------ | ------- | ----------------------------------------- | -| `0` | uint8_t | Weekday (1 - 7), 1 represents Monday | -| `1` | uint8_t | Hours (0 - 23) | -| `2` | uint8_t | Minutes (0 - 59) | -| `3` | uint8_t | Seconds (0 - 59) | -| `4` | uint8_t | Century (0 - 255), 0 represents year 1900 | -| `5` | uint8_t | Year (0 - 99) | -| `6` | uint8_t | Month (1 - 12) | -| `7` | uint8_t | Day (1 - 31) | +| offset | type | description | +| ------ | ------- | --------------------------------------- | +| `0` | uint8_t | Weekday (1 - 7), 1 represents Monday | +| `1` | uint8_t | Hours (0 - 23) | +| `2` | uint8_t | Minutes (0 - 59) | +| `3` | uint8_t | Seconds (0 - 59) | +| `4` | uint8_t | Century (0 - 7), 0 represents year 1900 | +| `5` | uint8_t | Year (0 - 99) | +| `6` | uint8_t | Month (1 - 12) | +| `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. --- @@ -356,16 +356,16 @@ Date/time values use the [BCD](https://en.wikipedia.org/wiki/Binary-coded_decima | `[7:0]` | Seconds (0 - 59) | #### `arg1` (time_1) -| bits | description | -| --------- | ----------------------------------------- | -| `[31:24]` | Century (0 - 255), 0 represents year 1900 | -| `[23:16]` | Year (0 - 99) | -| `[15:8]` | Month (1 - 12) | -| `[7:0]` | Day (1 - 31) | +| bits | description | +| --------- | --------------------------------------- | +| `[31:24]` | Century (0 - 7), 0 represents year 1900 | +| `[23:16]` | Year (0 - 99) | +| `[15:8]` | Month (1 - 12) | +| `[7:0]` | Day (1 - 31) | _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. --- diff --git a/sw/controller/src/cfg.c b/sw/controller/src/cfg.c index 47e056a..557f0a0 100644 --- a/sw/controller/src/cfg.c +++ b/sw/controller/src/cfg.c @@ -435,14 +435,14 @@ save_type_t cfg_get_save_type (void) { } void cfg_get_time (uint32_t *args) { - rtc_time_t t; + rtc_real_time_t t; rtc_get_time(&t); 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); } void cfg_set_time (uint32_t *args) { - rtc_time_t t; + rtc_real_time_t t; t.second = (args[0] & 0xFF); t.minute = ((args[0] >> 8) & 0xFF); t.hour = ((args[0] >> 16) & 0xFF); diff --git a/sw/controller/src/dd.c b/sw/controller/src/dd.c index e7d609d..aad3ae9 100644 --- a/sw/controller/src/dd.c +++ b/sw/controller/src/dd.c @@ -71,7 +71,7 @@ typedef struct { struct process { enum state state; - rtc_time_t time; + rtc_real_time_t time; bool disk_spinning; bool cmd_response_delayed; bool bm_running; diff --git a/sw/controller/src/rtc.c b/sw/controller/src/rtc.c index a731ba2..522a751 100644 --- a/sw/controller/src/rtc.c +++ b/sw/controller/src/rtc.c @@ -14,14 +14,12 @@ #define RTC_ADDRESS_RTCDATE (0x04) #define RTC_ADDRESS_RTCMTH (0x05) #define RTC_ADDRESS_RTCYEAR (0x06) -#define RTC_ADDRESS_CONTROL (0x07) #define RTC_ADDRESS_OSCTRIM (0x08) #define RTC_ADDRESS_SRAM_MAGIC (0x20) #define RTC_ADDRESS_SRAM_REGION (0x24) +#define RTC_ADDRESS_SRAM_CENTURY (0x25) #define RTC_ADDRESS_SRAM_VERSION (0x28) #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) @@ -32,8 +30,28 @@ #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, .minute = 0x00, .hour = 0x12, @@ -43,25 +61,10 @@ static rtc_time_t rtc_time = { .year = 0x24, .century = 0x01, }; -static bool rtc_time_pending = false; - static uint8_t rtc_region = 0xFF; -static bool rtc_region_pending = false; - static rtc_settings_t rtc_settings = { .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) { @@ -89,86 +92,209 @@ static bool rtc_write (uint8_t address, uint8_t *data, uint8_t length) { 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) { - 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)); } +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) { - uint8_t regs[7]; - uint8_t last_year; + rtc_raw_time_t raw; + bool update_raw_century = false; - if (rtc_read(RTC_ADDRESS_RTCSEC, regs, 7)) { - return; - } - if (rtc_read(RTC_ADDRESS_SRAM_CENTURY, &rtc_time.century, 1)) { - return; - } - if (rtc_read(RTC_ADDRESS_SRAM_LAST_YEAR, &last_year, 1)) { + if (rtc_read(RTC_ADDRESS_RTCSEC, (uint8_t *) (&raw.time), sizeof(raw.time))) { return; } - rtc_sanitize_time(regs); - - 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_read(RTC_ADDRESS_SRAM_CENTURY, (uint8_t *) (&raw.century), sizeof(raw.century))) { + return; } - if (rtc_time.year != last_year) { - rtc_write(RTC_ADDRESS_SRAM_LAST_YEAR, &rtc_time.year, 1); + rtc_sanitize_raw_time(&raw); + + 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) { - 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(); - regs[0] = rtc_time.second; - regs[1] = rtc_time.minute; - regs[2] = rtc_time.hour; - 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(); + rtc_write(RTC_ADDRESS_SRAM_CENTURY, (uint8_t *) (&raw.century), sizeof(raw.century)); + rtc_write(RTC_ADDRESS_RTCMIN, &raw_regs[1], sizeof(raw_regs) - sizeof(raw_regs[0])); + rtc_write(RTC_ADDRESS_RTCSEC, &raw_regs[0], sizeof(raw_regs[0])); } 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) { - 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) { @@ -179,8 +305,41 @@ static void rtc_write_settings (void) { 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->minute = rtc_time.minute; time->hour = rtc_time.hour; @@ -191,7 +350,7 @@ void rtc_get_time (rtc_time_t *time) { 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.minute = time->minute; rtc_time.hour = time->hour; @@ -200,7 +359,8 @@ void rtc_set_time (rtc_time_t *time) { rtc_time.month = time->month; rtc_time.year = time->year; 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) { 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) { - rtc_settings_pending = true; + rtc_write_settings(); } void rtc_init (void) { bool uninitialized = false; - const char *magic = "SC64"; - uint8_t buffer[4]; + const char *magic = "RTC1"; + uint8_t buffer[sizeof(magic)]; + uint8_t osc_trim = 0; 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; } - 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]) { uninitialized = true; break; @@ -243,19 +405,16 @@ void rtc_init (void) { } if (uninitialized) { - buffer[0] = 0; - rtc_write(RTC_ADDRESS_SRAM_MAGIC, (uint8_t *) (magic), 4); - rtc_write(RTC_ADDRESS_OSCTRIM, buffer, 1); + rtc_write(RTC_ADDRESS_OSCTRIM, &osc_trim, sizeof(osc_trim)); rtc_write_time(); 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)) { settings_version = RTC_SETTINGS_VERSION; - rtc_write(RTC_ADDRESS_SRAM_VERSION, (uint8_t *) (&settings_version), 4); rtc_write_settings(); + rtc_write(RTC_ADDRESS_SRAM_VERSION, (uint8_t *) (&settings_version), sizeof(settings_version)); } rtc_read_time(); @@ -270,62 +429,16 @@ void rtc_process (void) { uint32_t scr = fpga_reg_get(REG_RTC_SCR); if ((scr & RTC_SCR_PENDING) && ((scr & RTC_SCR_MAGIC_MASK) == RTC_SCR_MAGIC)) { - uint32_t data[2]; - - 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_read_joybus_time(); rtc_write_time(); - } - - if (rtc_region_pending) { - rtc_region_pending = false; - rtc_write_region(); - } - - if (rtc_settings_pending) { - rtc_settings_pending = false; - rtc_write_settings(); + rtc_read_time(); + rtc_write_joybus_time(); + fpga_reg_set(REG_RTC_SCR, RTC_SCR_DONE); } if (timer_countdown_elapsed(TIMER_ID_RTC)) { timer_countdown_start(TIMER_ID_RTC, RTC_TIME_REFRESH_PERIOD_MS); - rtc_read_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]); + rtc_write_joybus_time(); } } diff --git a/sw/controller/src/rtc.h b/sw/controller/src/rtc.h index 6a53a3f..8b84e65 100644 --- a/sw/controller/src/rtc.h +++ b/sw/controller/src/rtc.h @@ -15,15 +15,15 @@ typedef struct { uint8_t month; uint8_t year; uint8_t century; -} rtc_time_t; +} rtc_real_time_t; typedef struct { bool led_enabled; } rtc_settings_t; -void rtc_get_time (rtc_time_t *time); -void rtc_set_time (rtc_time_t *time); +void rtc_get_time (rtc_real_time_t *time); +void rtc_set_time (rtc_real_time_t *time); uint8_t rtc_get_region (void); void rtc_set_region (uint8_t region); diff --git a/sw/deployer/src/sc64/time.rs b/sw/deployer/src/sc64/time.rs index 871adc0..2effb07 100644 --- a/sw/deployer/src/sc64/time.rs +++ b/sw/deployer/src/sc64/time.rs @@ -15,12 +15,14 @@ pub fn convert_to_datetime(data: &[u8; 8]) -> Result { let hour = u8_from_bcd(data[1]); let day = u8_from_bcd(data[7]); 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( &format!("{year:4}-{month:02}-{day:02}T{hour:02}:{minute:02}:{second:02}"), "%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] { @@ -31,7 +33,7 @@ pub fn convert_from_datetime(datetime: NaiveDateTime) -> [u32; 2] { let day = bcd_from_u8(datetime.day() as u8); let month = bcd_from_u8(datetime.month() 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([century, year, month, day]),