Andrew Boyson / clock

Dependents:   oldheating gps motorhome heating

Committer:
andrewboyson
Date:
Mon Jul 03 07:07:48 2017 +0000
Revision:
2:55f070f05a43
Parent:
1:f3746f3cc345
Child:
3:92cfc43d493a
Pulled out state module which is now expected to be found in the application

Who changed what in which revision?

UserRevisionLine numberNew contents of line
andrewboyson 0:33686e88f09a 1 #include "mbed.h"
andrewboyson 0:33686e88f09a 2 #include "log.h"
andrewboyson 0:33686e88f09a 3 #include "tick.h"
andrewboyson 0:33686e88f09a 4 #include "rtc.h"
andrewboyson 0:33686e88f09a 5 #include "time.h"
andrewboyson 0:33686e88f09a 6 #include "state.h"
andrewboyson 0:33686e88f09a 7
andrewboyson 0:33686e88f09a 8 #define ONE_BILLION 1000000000
andrewboyson 0:33686e88f09a 9 #define ONE_MILLION 1000000
andrewboyson 0:33686e88f09a 10
andrewboyson 0:33686e88f09a 11 #define SLEW_DIVISOR 10
andrewboyson 0:33686e88f09a 12 #define SLEW_MAX_MS 20
andrewboyson 0:33686e88f09a 13
andrewboyson 0:33686e88f09a 14 #define PPB_DIVISOR 1000
andrewboyson 0:33686e88f09a 15 #define PPB_CHANGE_MAX 10000000
andrewboyson 0:33686e88f09a 16
andrewboyson 0:33686e88f09a 17 #define MAX_PERIOD_DIFFERENCE 1000000
andrewboyson 0:33686e88f09a 18
andrewboyson 0:33686e88f09a 19 #define SYNCED_LIMIT_NS 100000
andrewboyson 0:33686e88f09a 20 #define SYNCED_LIMIT_PPB 100000
andrewboyson 0:33686e88f09a 21
andrewboyson 0:33686e88f09a 22 #define MAX_OFFSET_SECS 3
andrewboyson 0:33686e88f09a 23
andrewboyson 2:55f070f05a43 24 #define DEBUG true
andrewboyson 2:55f070f05a43 25
andrewboyson 0:33686e88f09a 26 bool SyncedTime = false;
andrewboyson 0:33686e88f09a 27 bool SyncedRate = false;
andrewboyson 0:33686e88f09a 28
andrewboyson 0:33686e88f09a 29 static void setSlew(int64_t diff)
andrewboyson 0:33686e88f09a 30 {
andrewboyson 0:33686e88f09a 31 int64_t absDiff = llabs(diff);
andrewboyson 0:33686e88f09a 32 int64_t hysterisis = SYNCED_LIMIT_NS >> 3;
andrewboyson 0:33686e88f09a 33
andrewboyson 0:33686e88f09a 34 if (absDiff < SYNCED_LIMIT_NS - hysterisis) SyncedTime = true;
andrewboyson 0:33686e88f09a 35 if (absDiff > SYNCED_LIMIT_NS + hysterisis) SyncedTime = false;
andrewboyson 0:33686e88f09a 36
andrewboyson 0:33686e88f09a 37 int64_t slew = -diff / SLEW_DIVISOR;
andrewboyson 0:33686e88f09a 38 int32_t slewMaxNs = SLEW_MAX_MS * ONE_MILLION;
andrewboyson 0:33686e88f09a 39
andrewboyson 0:33686e88f09a 40 if (slew > slewMaxNs) slew = slewMaxNs;
andrewboyson 0:33686e88f09a 41 if (slew < -slewMaxNs) slew = -slewMaxNs;
andrewboyson 0:33686e88f09a 42
andrewboyson 0:33686e88f09a 43 TickSlew = slew;
andrewboyson 0:33686e88f09a 44 }
andrewboyson 0:33686e88f09a 45 static void setPpb(int64_t diff)
andrewboyson 2:55f070f05a43 46 {
andrewboyson 2:55f070f05a43 47 if (DEBUG) LogTimeF("Sync setPpb diff %lld against TickPpb %ld\r\n", diff, TickPpb);
andrewboyson 2:55f070f05a43 48
andrewboyson 0:33686e88f09a 49 int64_t absDiff = llabs(diff);
andrewboyson 0:33686e88f09a 50 int64_t hysterisis = SYNCED_LIMIT_PPB >> 6;
andrewboyson 0:33686e88f09a 51
andrewboyson 0:33686e88f09a 52 if (absDiff < SYNCED_LIMIT_PPB - hysterisis) SyncedRate = true;
andrewboyson 0:33686e88f09a 53 if (absDiff > SYNCED_LIMIT_PPB + hysterisis) SyncedRate = false;
andrewboyson 0:33686e88f09a 54
andrewboyson 0:33686e88f09a 55 int64_t toAdd = diff / PPB_DIVISOR;
andrewboyson 0:33686e88f09a 56
andrewboyson 0:33686e88f09a 57 if (toAdd > PPB_CHANGE_MAX) toAdd = PPB_CHANGE_MAX;
andrewboyson 0:33686e88f09a 58 if (toAdd < -PPB_CHANGE_MAX) toAdd = -PPB_CHANGE_MAX;
andrewboyson 2:55f070f05a43 59
andrewboyson 0:33686e88f09a 60 TickPpb -= toAdd;
andrewboyson 2:55f070f05a43 61
andrewboyson 2:55f070f05a43 62 if (DEBUG) LogTimeF("Sync setPpb toAdd %lld gives TickPpb %ld\r\n", toAdd, TickPpb);
andrewboyson 2:55f070f05a43 63
andrewboyson 0:33686e88f09a 64 StateSavePpb(TickPpb);
andrewboyson 0:33686e88f09a 65 }
andrewboyson 0:33686e88f09a 66
andrewboyson 0:33686e88f09a 67
andrewboyson 0:33686e88f09a 68 void SyncPpsI()
andrewboyson 0:33686e88f09a 69 {
andrewboyson 0:33686e88f09a 70 TickSaveSnapshotI();
andrewboyson 0:33686e88f09a 71 }
andrewboyson 0:33686e88f09a 72
andrewboyson 0:33686e88f09a 73 void SyncPpsN(time_t t)
andrewboyson 2:55f070f05a43 74 {
andrewboyson 2:55f070f05a43 75 int64_t thisExtClock = t * (int64_t)ONE_BILLION; //Make sure one of the RHS is cast to 64 bit
andrewboyson 0:33686e88f09a 76 static int64_t lastIntClock = 0;
andrewboyson 0:33686e88f09a 77 static int64_t lastExtClock = 0;
andrewboyson 0:33686e88f09a 78
andrewboyson 0:33686e88f09a 79 if (!TickIsSet) //Cold start - only ever true if the RTC was not set.
andrewboyson 0:33686e88f09a 80 {
andrewboyson 0:33686e88f09a 81 LogTimeF("Cold start of clock\r\n");
andrewboyson 0:33686e88f09a 82 TickSet(thisExtClock);
andrewboyson 0:33686e88f09a 83 lastIntClock = 0;
andrewboyson 0:33686e88f09a 84 lastExtClock = 0;
andrewboyson 0:33686e88f09a 85 return;
andrewboyson 0:33686e88f09a 86 }
andrewboyson 0:33686e88f09a 87
andrewboyson 0:33686e88f09a 88 //Get the time at the time of the interrupt
andrewboyson 0:33686e88f09a 89 int64_t thisIntClock;
andrewboyson 0:33686e88f09a 90 int64_t thisAbsClock;
andrewboyson 0:33686e88f09a 91 TickRetrieveSnapshot(&thisIntClock, &thisAbsClock);
andrewboyson 0:33686e88f09a 92
andrewboyson 0:33686e88f09a 93 //Calulate the time error
andrewboyson 0:33686e88f09a 94 int64_t absDiff = thisAbsClock - thisExtClock;
andrewboyson 0:33686e88f09a 95 if (abs(absDiff) > MAX_OFFSET_SECS * (int64_t)ONE_BILLION)
andrewboyson 0:33686e88f09a 96 {
andrewboyson 0:33686e88f09a 97 TickSet(thisExtClock);
andrewboyson 0:33686e88f09a 98 lastIntClock = 0;
andrewboyson 0:33686e88f09a 99 lastExtClock = 0;
andrewboyson 0:33686e88f09a 100 return;
andrewboyson 0:33686e88f09a 101 }
andrewboyson 0:33686e88f09a 102 setSlew(absDiff);
andrewboyson 0:33686e88f09a 103
andrewboyson 0:33686e88f09a 104 //Calculate the rate error
andrewboyson 0:33686e88f09a 105 if (lastExtClock)
andrewboyson 0:33686e88f09a 106 {
andrewboyson 0:33686e88f09a 107 int64_t extPeriod = thisExtClock - lastExtClock;
andrewboyson 0:33686e88f09a 108
andrewboyson 0:33686e88f09a 109 int64_t intPeriod = thisIntClock - lastIntClock;
andrewboyson 0:33686e88f09a 110 int64_t periodDiff = intPeriod - extPeriod;
andrewboyson 0:33686e88f09a 111 if (extPeriod < ONE_BILLION + MAX_PERIOD_DIFFERENCE &&
andrewboyson 0:33686e88f09a 112 extPeriod > ONE_BILLION - MAX_PERIOD_DIFFERENCE)
andrewboyson 0:33686e88f09a 113 {
andrewboyson 0:33686e88f09a 114 setPpb(periodDiff);
andrewboyson 0:33686e88f09a 115 }
andrewboyson 0:33686e88f09a 116 }
andrewboyson 0:33686e88f09a 117
andrewboyson 0:33686e88f09a 118 //Save the time in the RTC
andrewboyson 0:33686e88f09a 119 struct tm tm;
andrewboyson 0:33686e88f09a 120 TimeToTmUtc(t, &tm);
andrewboyson 0:33686e88f09a 121 RtcSetTm(&tm);
andrewboyson 0:33686e88f09a 122
andrewboyson 0:33686e88f09a 123 //Save last values
andrewboyson 0:33686e88f09a 124 lastIntClock = thisIntClock;
andrewboyson 0:33686e88f09a 125 lastExtClock = thisExtClock;
andrewboyson 0:33686e88f09a 126
andrewboyson 0:33686e88f09a 127 }
andrewboyson 1:f3746f3cc345 128 void SyncNs(int64_t ns)
andrewboyson 1:f3746f3cc345 129 {
andrewboyson 2:55f070f05a43 130 int64_t thisExtClock = ns;
andrewboyson 2:55f070f05a43 131 static int64_t lastIntClock = 0;
andrewboyson 2:55f070f05a43 132 static int64_t lastExtClock = 0;
andrewboyson 2:55f070f05a43 133
andrewboyson 2:55f070f05a43 134 if (!TickIsSet) //Cold start - only ever true if the RTC was not set.
andrewboyson 2:55f070f05a43 135 {
andrewboyson 2:55f070f05a43 136 LogTimeF("Cold start of clock\r\n");
andrewboyson 2:55f070f05a43 137 TickSet(thisExtClock);
andrewboyson 2:55f070f05a43 138 lastIntClock = 0;
andrewboyson 2:55f070f05a43 139 lastExtClock = 0;
andrewboyson 2:55f070f05a43 140 return;
andrewboyson 2:55f070f05a43 141 }
andrewboyson 2:55f070f05a43 142
andrewboyson 2:55f070f05a43 143 //Get the time at the time of the interrupt
andrewboyson 2:55f070f05a43 144 TickSaveSnapshotI();
andrewboyson 2:55f070f05a43 145 int64_t thisIntClock;
andrewboyson 2:55f070f05a43 146 int64_t thisAbsClock;
andrewboyson 2:55f070f05a43 147 TickRetrieveSnapshot(&thisIntClock, &thisAbsClock);
andrewboyson 2:55f070f05a43 148
andrewboyson 2:55f070f05a43 149 //Calulate the time error
andrewboyson 2:55f070f05a43 150 int64_t absDiff = thisAbsClock - thisExtClock;
andrewboyson 2:55f070f05a43 151 if (abs(absDiff) > MAX_OFFSET_SECS * (int64_t)ONE_BILLION)
andrewboyson 2:55f070f05a43 152 {
andrewboyson 2:55f070f05a43 153 if (DEBUG) LogTimeF("Sync - offset is greater than %d seconds so resetting Tick time and rate\r\n", MAX_OFFSET_SECS);
andrewboyson 2:55f070f05a43 154 TickSet(thisExtClock);
andrewboyson 2:55f070f05a43 155 TickPpb = 0;
andrewboyson 2:55f070f05a43 156 lastIntClock = 0;
andrewboyson 2:55f070f05a43 157 lastExtClock = 0;
andrewboyson 2:55f070f05a43 158 return;
andrewboyson 2:55f070f05a43 159 }
andrewboyson 2:55f070f05a43 160 setSlew(absDiff);
andrewboyson 2:55f070f05a43 161
andrewboyson 2:55f070f05a43 162 //Calculate the rate error
andrewboyson 2:55f070f05a43 163 if (lastExtClock)
andrewboyson 2:55f070f05a43 164 {
andrewboyson 2:55f070f05a43 165 int64_t extPeriod = thisExtClock - lastExtClock;
andrewboyson 2:55f070f05a43 166
andrewboyson 2:55f070f05a43 167 int64_t intPeriod = thisIntClock - lastIntClock;
andrewboyson 2:55f070f05a43 168 int64_t periodDiff = intPeriod - extPeriod;
andrewboyson 2:55f070f05a43 169
andrewboyson 2:55f070f05a43 170 int64_t ppb = periodDiff * ONE_BILLION / extPeriod;
andrewboyson 2:55f070f05a43 171 setPpb(ppb);
andrewboyson 2:55f070f05a43 172 }
andrewboyson 2:55f070f05a43 173
andrewboyson 2:55f070f05a43 174 //Save the time in the RTC
andrewboyson 2:55f070f05a43 175 time_t t = ns / ONE_BILLION;
andrewboyson 2:55f070f05a43 176 struct tm tm;
andrewboyson 2:55f070f05a43 177 TimeToTmUtc(t, &tm);
andrewboyson 2:55f070f05a43 178 RtcSetTm(&tm);
andrewboyson 2:55f070f05a43 179
andrewboyson 2:55f070f05a43 180 //Save last values
andrewboyson 2:55f070f05a43 181 lastIntClock = thisIntClock;
andrewboyson 2:55f070f05a43 182 lastExtClock = thisExtClock;
andrewboyson 2:55f070f05a43 183
andrewboyson 1:f3746f3cc345 184 }