Andrew Boyson / clock

Dependents:   oldheating gps motorhome heating

Files at this revision

API Documentation at this revision

Comitter:
andrewboyson
Date:
Sat Dec 29 19:00:39 2018 +0000
Parent:
43:45b11d2c5490
Child:
45:1d8d5b312f72
Commit message:
Made TAI with conversion to UTC as required

Changed in this revision

clock/clkstate.c Show annotated file Show diff for this revision Revisions of this file
clock/clkstate.h Show annotated file Show diff for this revision Revisions of this file
clock/clkutc.c Show annotated file Show diff for this revision Revisions of this file
clock/clkutc.h Show annotated file Show diff for this revision Revisions of this file
tm/tm.c Show annotated file Show diff for this revision Revisions of this file
tm/tm.h Show annotated file Show diff for this revision Revisions of this file
--- a/clock/clkstate.c	Wed Dec 05 11:35:16 2018 +0000
+++ b/clock/clkstate.c	Sat Dec 29 19:00:39 2018 +0000
@@ -1,13 +1,84 @@
 #include <stdint.h>
 
+#include "clktime.h"
+#include      "tm.h"
+
 #define GPREG0 (*((volatile unsigned *) 0x40024044))
+#define GPREG1 (*((volatile unsigned *) 0x40024048))
 
+//Sync states
 volatile int32_t ClockSlew = 0; //ns     - up to +/- 2.147s of slew
 volatile int32_t ClockPpb  = 0; //This gets set to the last recorded ppb in TickInit
 
 void ClockSetPpb (int32_t value) { ClockPpb  = value; GPREG0 = ClockPpb; }
 void ClockAddPpb (int32_t value) { ClockPpb += value; GPREG0 = ClockPpb; }
 
+/*
++----+----+----+----+----+----+----+----+
+|Flgs|  Leap months |     Leap count    |
+|UUDE|    12 bits   |      16 bits      |
++----+----+----+----+----+----+----+----+
+
+Leap months: 12 bits will hold 4096 months or 341 years
+
+Leap count: 16 bits will hold enough leaps seconds for 60,000 years
+
+Flgs
+U = unused
+D = direction: 1 to subtract; 0 to add
+E = Enable: 1 if leap to take into account at the start of the leap month; 0 if already taken or to be ignored
+*/
+
+//Leap seconds
+int     ClockLeapSecondCount   = 0; //12 bits holds enough leap seconds for at least 300 years.
+int64_t ClockLeapSecondCount64 = 0;
+static void makeLeapSecondCount64() { ClockLeapSecondCount64 = ((int64_t)ClockLeapSecondCount) << CLK_TIME_ONE_SECOND_SHIFT; }
+void ClockSetLeapSecondCount(int value)
+{
+    ClockLeapSecondCount = value;
+    makeLeapSecondCount64();
+    GPREG1 = GPREG1 & 0xFFFF0000 | value & 0x0000FFFF;
+}
+void ClockAddLeapSecondCount(int value)
+{
+    ClockSetLeapSecondCount(ClockLeapSecondCount + value);
+}
+
+//Next leap second
+int     ClockNextLeapMonth1970 = 0;
+int64_t ClockNextLeapSecondUtc = 0;
+static void makeNextLeapSecondUtc()
+{
+    int year  = ClockNextLeapMonth1970 / 12 + 1970;
+    int month = ClockNextLeapMonth1970 % 12 + 1;
+    struct tm tm;
+    TmFromInteger(year, month, 1, 0, 0, 0, &tm);
+    time_t t = TmUtcToTimeT(&tm);
+    ClockNextLeapSecondUtc = (int64_t)t << CLK_TIME_ONE_SECOND_SHIFT;
+}
+void ClockSetNextLeapMonth1970(int value)
+{
+    ClockNextLeapMonth1970 = value;
+    makeNextLeapSecondUtc();
+    GPREG1 = GPREG1 & 0xF000FFFF | (uint32_t)value << 16 & 0x0FFF0000; //Precedence order: shifts then ands then ors.
+}
+
+bool ClockNextLeapEnable   = false;
+bool ClockNextLeapBackward = false;
+void ClockSetNextLeapEnable(bool value)
+{
+    ClockNextLeapEnable = value;
+    if (value) GPREG1 |= 0x10000000;
+    else       GPREG1 &= 0xEFFFFFFF;
+}
+void ClockSetNextLeapBackward(bool value)
+{
+    ClockNextLeapBackward = value;
+    if (value) GPREG1 |= 0x20000000;
+    else       GPREG1 &= 0xDFFFFFFF;
+}
+
+//Clock limits
 int ClockSlewDivisor       = 10;
 int ClockSlewMaxMs         = 10;
 int ClockPpbDivisor        = 10;
@@ -20,5 +91,11 @@
 
 void ClockStateInit(void)
 {
-    ClockPpb = GPREG0; //This is saved each time Tickppb is updated
+    ClockPpb               =  GPREG0;
+    ClockLeapSecondCount   =  GPREG1 & 0x0000FFFF;
+    makeLeapSecondCount64();
+    ClockNextLeapMonth1970 = (GPREG1 & 0x0FFF0000) >> 16;
+    makeNextLeapSecondUtc();
+    ClockNextLeapEnable    =  GPREG1 & 0x10000000;
+    ClockNextLeapBackward  =  GPREG1 & 0x20000000;
 }
\ No newline at end of file
--- a/clock/clkstate.h	Wed Dec 05 11:35:16 2018 +0000
+++ b/clock/clkstate.h	Sat Dec 29 19:00:39 2018 +0000
@@ -6,6 +6,20 @@
 extern void ClockSetPpb(int32_t value);
 extern void ClockAddPpb(int32_t value);
 
+extern int     ClockLeapSecondCount;
+extern int64_t ClockLeapSecondCount64;
+extern void    ClockSetLeapSecondCount(int value);
+extern void    ClockAddLeapSecondCount(int value);
+
+extern int     ClockNextLeapMonth1970; //Months since 1970 
+extern int64_t ClockNextLeapSecondUtc;
+extern void    ClockSetNextLeapMonth1970(int value);
+
+extern bool ClockNextLeapEnable;
+extern bool ClockNextLeapBackward;
+extern void ClockSetNextLeapEnable  (bool value);
+extern void ClockSetNextLeapBackward(bool value);
+
 extern int ClockSlewDivisor      ;
 extern int ClockSlewMaxMs        ;
 extern int ClockPpbDivisor       ;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/clock/clkutc.c	Sat Dec 29 19:00:39 2018 +0000
@@ -0,0 +1,14 @@
+#include <stdint.h>
+#include "clktime.h"
+#include "clkstate.h"
+
+void ClkUtcHandleLeapSecond(int64_t tai)
+{
+    if (ClockNextLeapSecondUtc && tai >= ClockNextLeapSecondUtc + ClockLeapSecondCount64)
+    {
+        ClockAddLeapSecondCount(1);
+        ClockSetNextLeapMonth1970(0); //This resets ClockNextLeapSecondUtc
+    }
+}
+int64_t ClkUtcFromTai(int64_t tai) { return tai - ClockLeapSecondCount64; }
+int64_t ClkUtcToTai  (int64_t utc) { return utc + ClockLeapSecondCount64; }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/clock/clkutc.h	Sat Dec 29 19:00:39 2018 +0000
@@ -0,0 +1,4 @@
+#include <stdint.h>
+
+extern  int64_t ClkUtcGet(uint32_t * pLeaps);
+extern     void ClkUtcSet(int64_t utc, uint32_t leaps);
--- a/tm/tm.c	Wed Dec 05 11:35:16 2018 +0000
+++ b/tm/tm.c	Sat Dec 29 19:00:39 2018 +0000
@@ -279,6 +279,16 @@
     //Fill the day of week and the day of year part of the tm structure
     calculateDayOfYearAndWeek(ptm->tm_year, ptm->tm_mon, ptm->tm_mday, &ptm->tm_yday, &ptm->tm_wday);
 }
+void TmFromInteger(int year, int month, int mday, int hour, int min, int sec, struct tm* ptm)
+{
+    ptm->tm_year = year - 1900;
+    ptm->tm_mon = month - 1;
+    ptm->tm_mday = mday;
+    calculateDayOfYearAndWeek(ptm->tm_year, ptm->tm_mon, ptm->tm_mday, &ptm->tm_yday, &ptm->tm_wday);
+    ptm->tm_hour = hour;
+    ptm->tm_min  = min;
+    ptm->tm_sec  = sec;
+}
 void TmIncrement(struct tm* ptm)
 {
     ptm->tm_sec++;
--- a/tm/tm.h	Wed Dec 05 11:35:16 2018 +0000
+++ b/tm/tm.h	Sat Dec 29 19:00:39 2018 +0000
@@ -6,5 +6,6 @@
 
 extern void   TmUtcToLocal(struct tm* ptm);
 extern void   TmFromAsciiDateTime(const char* pDate, const char* pTime, struct tm* ptm);
+extern void   TmFromInteger(int year, int month, int mday, int hour, int min, int sec, struct tm* ptm);
 extern int    TmSecondsBetween(struct tm* ptmLater, struct tm* ptmEarlier);
 extern void   TmIncrement(struct tm* ptm);
\ No newline at end of file