Andrew Boyson / clock

Dependents:   oldheating gps motorhome heating

sync.c

Committer:
andrewboyson
Date:
2018-01-19
Revision:
22:df0b906bda26
Parent:
18:207dd1474cd9
Child:
26:0421132e6eaf

File content as of revision 22:df0b906bda26:

#include <stdlib.h>
#include <stdbool.h>

#include   "log.h"
#include  "tick.h"
#include  "time.h"
#include "clock.h"

#define ONE_BILLION 1000000000LL //Make sure ONE_BILLION is 64 bit by putting LL on the end
#define ONE_MILLION    1000000

bool SyncTrace = false;

bool SyncedTime = false;
bool SyncedRate = false;
static void setSyncedTime(int64_t diff)
{
    int64_t absDiff = llabs(diff);
    int64_t limit      = ClockSyncedLimitNs;
    int64_t hysterisis = ClockSyncedHysterisNs;
    
    if (absDiff < limit - hysterisis) SyncedTime = true;
    if (absDiff > limit + hysterisis) SyncedTime = false;
}
static void setSyncedRate(int64_t diff)
{
    
    int64_t absDiff = llabs(diff);
    int64_t limit      = ClockSyncedLimitPpb;
    int64_t hysterisis = ClockSyncedHysterisPpb;
    
    if (absDiff < limit - hysterisis) SyncedRate = true;
    if (absDiff > limit + hysterisis) SyncedRate = false;
}

static void setSlew(int64_t diff)
{
    int64_t slew = -diff / ClockSlewDivisor;
    int32_t slewMaxNs = ClockSlewMaxMs * ONE_MILLION;
    
    if (slew >  slewMaxNs) slew =  slewMaxNs;
    if (slew < -slewMaxNs) slew = -slewMaxNs;
    
    TickSetSlew(slew);
    
    if (SyncTrace) LogTimeF("Sync setSlew diff %lld gives slew %lld gives TickSlew %ld\r\n", diff, slew, TickGetSlew());
}
static void adjustPpb(int64_t diff)
{    
    int64_t toAdd = diff / ClockPpbDivisor;
    int32_t maxAdd = ClockPpbChangeMax;

    if (toAdd >  maxAdd) toAdd =  maxAdd;
    if (toAdd < -maxAdd) toAdd = -maxAdd;
            
    TickAddPpb(-toAdd);
    
    if (SyncTrace) LogTimeF("Sync setPpb diff %lld gives toAdd %lld gives TickPpb %ld\r\n", diff, toAdd, TickGetPpb());
}

static int64_t lastIntClock = -1; //-1 indicates invalid value. 0 is a valid value.
static int64_t lastExtClock = -1;
static void reset(int64_t thisExtClock)
{
    TickSet(thisExtClock);
    TickSetPpb(0);
    lastIntClock = 0;
    lastExtClock = 0;
}

static void sync(int64_t thisExtClock)
{
    
    if (!TickIsSet()) //Cold start - only ever true if the RTC was not set.
    {
        LogTimeF("Sync - cold start of clock so resetting\r\n");
        reset(thisExtClock);
        return;
    }

    //Get the time at the time of the interrupt
    int64_t thisIntClock;
    int64_t thisAbsClock;
    TickGetTimesFromSnapshot(&thisIntClock, &thisAbsClock);

    //Calulate the time error
    int64_t absDiff = thisAbsClock - thisExtClock;
    if (llabs(absDiff) > ClockMaxOffsetSecs * ONE_BILLION)
    {
        LogTimeF("Sync - offset is greater than %d seconds so resetting\r\n", ClockMaxOffsetSecs);
        reset(thisExtClock);
        return;
    } 
    setSlew(absDiff);
    setSyncedTime(absDiff);
    
    //Calculate the rate error
    if (lastExtClock > -1)
    {
        int64_t extPeriod = thisExtClock - lastExtClock;
        
        int64_t intPeriod = thisIntClock - lastIntClock;
        int64_t periodDiff =   intPeriod -    extPeriod;
        
        int64_t ppb;
        if (extPeriod == ONE_BILLION) ppb = periodDiff; //This saves a 64bit multiplication and division for PPS
        else                          ppb = periodDiff * ONE_BILLION / extPeriod;
        
        adjustPpb(ppb);
        setSyncedRate(ppb);
    }

    //Save last values
    lastIntClock = thisIntClock;
    lastExtClock = thisExtClock;
}
void SyncPpsI(          ) { TickSaveSnapshot(); }
void SyncPpsN(time_t t  ) { int64_t ns = t * ONE_BILLION; sync(ns); }
void SyncNs  (int64_t ns) { TickSaveSnapshot();           sync(ns); }