From 11e4ce0610b61bbbef74d7c86e8ec689275fdcd0 Mon Sep 17 00:00:00 2001 From: mrhgit Date: Sun, 13 Feb 2022 16:20:50 -0500 Subject: [PATCH 1/2] Adding in add_1024_weeks functionality, which is meant to substitute for usage of the library. Benefits are speed, size, and avoidance of 2038 bug (although it introduces a ~2080 bug). --- Navi_Clock_Fix.X/add1024weeks.c | 49 ++++++++++++++++++++++ Navi_Clock_Fix.X/add1024weeks.h | 8 ++++ Navi_Clock_Fix.X/main.c | 27 +++++------- Navi_Clock_Fix.X/test/test_add1024.c | 61 ++++++++++++++++++++++++++++ 4 files changed, 128 insertions(+), 17 deletions(-) create mode 100644 Navi_Clock_Fix.X/add1024weeks.c create mode 100644 Navi_Clock_Fix.X/add1024weeks.h create mode 100644 Navi_Clock_Fix.X/test/test_add1024.c diff --git a/Navi_Clock_Fix.X/add1024weeks.c b/Navi_Clock_Fix.X/add1024weeks.c new file mode 100644 index 0000000..0336031 --- /dev/null +++ b/Navi_Clock_Fix.X/add1024weeks.c @@ -0,0 +1,49 @@ +#include +#include +#include "add1024weeks.h" + +inline uint8_t is_leap_year(uint8_t years_since_2000) { + return (years_since_2000 & 0x3) ? 0 : 1; // works for 2000 <= year < 2100 +} + +void add_1024_weeks(uint8_t *year, uint8_t *month, uint8_t *day) { + // year is years since 2000, month is 1-indexed, day is 1-indexed + // note that 1024 weeks is 19 365-day years + 233 days (leap days adjusted later) + // there are either 4 or 5 leap days in any set of 19 years (between 2000 and 2099) + + uint8_t i; + const uint16_t cumul_days_in_month[12] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334}; + uint16_t day_of_year; + + day_of_year = cumul_days_in_month[*month - 1] + *day; + if (is_leap_year(*year) && *month >= 3) day_of_year++; // Add 1 for leap day if in March (1-index) + + // advance 19 years, keeping track of leap days passed + *year += 19; + day_of_year += 233 - 5 + is_leap_year(*year); + + // check if we've rolled over into new year + if (day_of_year > 365 + is_leap_year(*year)) { + day_of_year -= 365 + is_leap_year((*year)++); + } + + // Temporarily remove extra day if leap day exists and past feb 28th + // this is relatively the same as increasing cumulative days in the table + bool hide_extra_day = (is_leap_year(*year) && day_of_year > cumul_days_in_month[2]); + if (hide_extra_day) day_of_year--; + + // Convert day of year to (month, day) + *month = 0; + while (day_of_year > cumul_days_in_month[++(*month)]) { + // this loop left intentionally blank + } + day_of_year -= cumul_days_in_month[*month-1]; + + // Add extra "hidden" day back in, if in the month of February (1-index) + if (hide_extra_day && (*month)==2) day_of_year++; + + *day = day_of_year; // store day + + return; +} + diff --git a/Navi_Clock_Fix.X/add1024weeks.h b/Navi_Clock_Fix.X/add1024weeks.h new file mode 100644 index 0000000..4994fb6 --- /dev/null +++ b/Navi_Clock_Fix.X/add1024weeks.h @@ -0,0 +1,8 @@ +#ifndef ADD1024WEEKS_H +#define ADD1024WEEKS_H + +uint8_t is_leap_year(uint8_t years_since_2000); +void add_1024_weeks(uint8_t *year, uint8_t *month, uint8_t *day); + +#endif + diff --git a/Navi_Clock_Fix.X/main.c b/Navi_Clock_Fix.X/main.c index e8df6b3..6fad97e 100644 --- a/Navi_Clock_Fix.X/main.c +++ b/Navi_Clock_Fix.X/main.c @@ -6,8 +6,7 @@ * incorrect) default year when the GPS unit is powered up. * * This PIC16 code receives binary data from the Furuno GN80 and outputs the - * corrected (+1024 week) date. This uses a signed 32-bit time_t with - * functions, so this will suffer from the 2038 date problem. + * corrected (+1024 week) date. * * The binary protocol looks to be a clone of Trimble TSIP, with Furuno's own * packet structures. @@ -37,10 +36,10 @@ #include #include #include -#include #include "system.h" #include "eusart.h" +#include "add1024weeks.h" //convert BCD to decimal @@ -69,14 +68,10 @@ void main(void) { uint8_t rx_data, tmp_tx, check_xor=0, byte10=0, pktcnt=0; uint8_t pktid=0x03; //packet ID of 0x03 should be invalid (end of packet), so use for unknown ID - struct tm *date; - time_t conv_date=0; + uint8_t year, month, day; SYSTEM_Initialize(); - //initialize date values - date=gmtime(&conv_date); - while(1) { CLRWDT(); //poke watchdog @@ -113,7 +108,7 @@ void main(void) if (!byte10) //if 0x10 data, only want to do this once (check XOR doesn't include both 0x10s) { check_xor^=rx_data; //will remove this byte from check byte - date->tm_year=bcd_to_dec(rx_data)+100; //year since 1900 + year=bcd_to_dec(rx_data); //year since 2000 } } else if ((pktcnt==21)||(pktcnt==27)) //month (21=current, 27=last fix) @@ -121,7 +116,7 @@ void main(void) if (!byte10) //if 0x10 data, only want to do this once (check XOR doesn't include both 0x10s) { check_xor^=rx_data; //will remove this byte from check byte - date->tm_mon=bcd_to_dec(rx_data)-1; //months since January (0-11) + month=bcd_to_dec(rx_data); //months, 1-indexed } } else if ((pktcnt==22)||(pktcnt==28)) //day (22=current, 28=last fix) @@ -129,27 +124,25 @@ void main(void) if (!byte10) //if 0x10 data, only want to do this once (check XOR doesn't include both 0x10s, and don't want to send twice) { check_xor^=rx_data; //will remove this byte from check byte - date->tm_mday=bcd_to_dec(rx_data); //day of the month (1-31) + day=bcd_to_dec(rx_data); //day of the month (1-31) //fix the date - conv_date=mktime(date); //convert tm to time_t - conv_date+=((uint32_t)1024*7*24*60*60); //add 1024 weeks (in seconds) - date=gmtime(&conv_date); //convert time_t back to tm + add_1024_weeks(&year, &month, &day); // Uh //send replacement bytes (duplicating 0x10 if necessary) - tmp_tx=dec_to_bcd((uint8_t)date->tm_year-100); //year + tmp_tx=dec_to_bcd(year); //year send_byte(tmp_tx); if (tmp_tx==0x10) send_byte(tmp_tx); check_xor^=tmp_tx; //XOR replacement byte - tmp_tx=dec_to_bcd((uint8_t)date->tm_mon+1); //month + tmp_tx=dec_to_bcd(month); //month send_byte(tmp_tx); if (tmp_tx==0x10) send_byte(tmp_tx); check_xor^=tmp_tx; //XOR replacement byte - tmp_tx=dec_to_bcd((uint8_t)date->tm_mday); //day + tmp_tx=dec_to_bcd(day); //day send_byte(tmp_tx); if (tmp_tx==0x10) send_byte(tmp_tx); diff --git a/Navi_Clock_Fix.X/test/test_add1024.c b/Navi_Clock_Fix.X/test/test_add1024.c new file mode 100644 index 0000000..775f8a5 --- /dev/null +++ b/Navi_Clock_Fix.X/test/test_add1024.c @@ -0,0 +1,61 @@ +#include +#include +#include +#include +#include +#include "add1024weeks.h" + +void test_with_mktime(uint8_t *year, uint8_t *month, uint8_t *day) { + struct tm *date; + time_t conv_date = 0; + + date = gmtime(&conv_date); + date->tm_year = *year + 100; + date->tm_mon = *month - 1; + date->tm_mday = *day; + + conv_date = mktime(date); + conv_date += ((uint32_t)1024*7*24*60*60); // 1024 weeks in seconds + date = gmtime(&conv_date); + + *year = date->tm_year - 100; + *month = date->tm_mon + 1; + *day = date->tm_mday; + + return; +} + +int main(int argc, char* argv[]) { + uint8_t orig_year; // years since 2000 + uint8_t orig_month; // 1-indexed month + uint8_t orig_day; // 1-indexed day + uint8_t year_mk, month_mk, day_mk; + uint8_t year_add, month_add, day_add; + const uint8_t days_in_month[12] = {31,28,31,30,31,30,31,31,30,31,30,31}; + bool errors = false; + + for (orig_year = 0; orig_year < 80; orig_year++) { + for (orig_month = 1; orig_month < 13; orig_month++) { + for (orig_day = 1; orig_day < days_in_month[orig_month] + is_leap_year(orig_year); orig_day++) { + + year_mk = orig_year; month_mk = orig_month; day_mk = orig_day; + test_with_mktime(&year_mk, &month_mk, &day_mk); + + year_add = orig_year; month_add = orig_month; day_add = orig_day; + add_1024_weeks(&year_add, &month_add, &day_add); + + if ((year_mk != year_add || month_mk != month_add || day_mk != day_add)) { + printf("Original Year=%" PRIu16 " Month=%" PRIu8 " Day=%" PRIu8 "\n", ((uint16_t)orig_year + 2000), orig_month, orig_day); + printf("mktime Year=%" PRIu16 " Month=%" PRIu8 " Day=%" PRIu8 "\n", ((uint16_t)year_mk + 2000), month_mk, day_mk); + printf("add1024 Year=%" PRIu16 " Month=%" PRIu8 " Day=%" PRIu8 "\n", ((uint16_t)year_add + 2000), month_add, day_add); + printf("\n"); + errors = true; + } + } + } + } + + return (errors) ? 1 : 0; + +} + From c74983dbdbcae9cd9364c7ba38dfc9df6b60fa81 Mon Sep 17 00:00:00 2001 From: mrhgit Date: Sun, 13 Feb 2022 16:24:25 -0500 Subject: [PATCH 2/2] Fix README to clarify that the 2038 problem no longer exists --- Navi_Clock_Fix.X/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Navi_Clock_Fix.X/README.md b/Navi_Clock_Fix.X/README.md index a016cdc..f5595b4 100644 --- a/Navi_Clock_Fix.X/README.md +++ b/Navi_Clock_Fix.X/README.md @@ -7,8 +7,8 @@ navigation software, presumably ignoring 2002 since that's the (obviously incorrect) default year when the GPS unit is powered up. This PIC16F1825 code receives binary data from the Furuno GN80 and outputs the -corrected (+1024 week) date. This uses a signed 32-bit time_t with -functions, so this will suffer from the 2038 date problem. +corrected (+1024 week) date. The adjustment assumes the starting year is between 2000 and 2080 +(i.e. it only checks for the year being divisible by four and does not account for the year 2100). The GPS receiver is soldered to the navigation unit motherboard, and needs to be removed in order to use this, as the PIC needs to intercept and modify the serial data. I @@ -56,4 +56,4 @@ As compiled using the free version of the compiler with -o2 optimization, this u Including the functions ate up almost all of the flash, but greatly simplified my code. Alternatively, u-blox has an application note (UBX-19016936) with example code, which could likely be implemented with a much smaller flash footprint. -The precompiled .hex file is also included. \ No newline at end of file +The precompiled .hex file is also included.