Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions Navi_Clock_Fix.X/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 <time.h>
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
Expand Down Expand Up @@ -56,4 +56,4 @@ As compiled using the free version of the compiler with -o2 optimization, this u
Including the <time.h> 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.
The precompiled .hex file is also included.
49 changes: 49 additions & 0 deletions Navi_Clock_Fix.X/add1024weeks.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#include <stdint.h>
#include <stdbool.h>
#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;
}

8 changes: 8 additions & 0 deletions Navi_Clock_Fix.X/add1024weeks.h
Original file line number Diff line number Diff line change
@@ -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

27 changes: 10 additions & 17 deletions Navi_Clock_Fix.X/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 <time.h>
* 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.
Expand Down Expand Up @@ -37,10 +36,10 @@
#include <xc.h>
#include <stdint.h>
#include <stdbool.h>
#include <time.h>

#include "system.h"
#include "eusart.h"
#include "add1024weeks.h"


//convert BCD to decimal
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -113,43 +108,41 @@ 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)
{
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)
{
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);
Expand Down
61 changes: 61 additions & 0 deletions Navi_Clock_Fix.X/test/test_add1024.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
#include <stdio.h>
#include <time.h>
#include <stdint.h>
#include <stdbool.h>
#include <inttypes.h>
#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;

}