44 #include "../client/pps-client.h" 49 extern int adjtimex (
struct timex *timex);
73 memset(&
g, 0,
sizeof(
struct G));
81 g.exitOnLostPPS =
true;
82 g.doCalibration =
true;
83 g.doNTPsettime =
true;
85 g.
t3.modes = ADJ_FREQUENCY;
313 bool isReady =
false;
397 int rv = write(pps_fd, msg, 2 *
sizeof(
int));
399 sprintf(
g.logbuf,
"setClockToNTPtime() write to driver failed with msg: %s\n", strerror(errno));
423 sprintf(
g.logbuf,
"setClockToSerialTime() Corrected time by %d seconds\n",
g.serialTimeError);
428 msg[1] =
g.serialTimeError;
429 int rv = write(pps_fd, msg, 2 *
sizeof(
int));
431 sprintf(
g.logbuf,
"setClockToSerialTime() write to driver failed with msg: %s\n", strerror(errno));
437 g.serialTimeError = 0;
462 sprintf(
g.logbuf,
"setClockFractionalSecond() Made correction: %d\n", correction);
469 int rv = write(pps_fd, msg, 2 *
sizeof(
int));
471 sprintf(
g.logbuf,
"setClockFractionalSecond() write to driver failed with msg: %s\n", strerror(errno));
500 if (*count > 600 && *count % 60 == 0){
502 for (
int i = 0; i < len; i++){
506 errorDistrib[idx] += 1.0;
590 g.pps_t_sec =
t.tv_sec;
628 struct timespec t_mono;
629 struct timeval t_now;
631 clock_gettime(CLOCK_MONOTONIC, &t_mono);
632 g.
t_mono_now = (double)t_mono.tv_sec + 1e-9 * (
double)t_mono.tv_nsec;
638 gettimeofday(&t_now, NULL);
639 g.
t_now = (int)t_now.tv_sec;
646 int iDiff = round(diff);
649 sprintf(
g.logbuf,
"increaseMonotonicCount() lost a cycle. diff: %lf\n", diff);
656 if (
g.blockDetectClockChange > 0){
657 g.blockDetectClockChange -= 1;
673 double accFrac = 0.9;
690 bool clockChanged =
false;
696 sprintf(
g.logbuf,
"detectExteralSystemClockChange() Got error g.t_now: %d g.t_count: %d\n",
g.
t_now,
g.
t_count);
734 if (
g.doSerialsettime &&
g.serialTimeError != 0){
741 if (
g.blockDetectClockChange == 0 &&
766 g.
t3.modes = ADJ_OFFSET_SINGLESHOT;
782 g.
t3.modes = ADJ_FREQUENCY;
814 if (
g.
seq_num > 0 &&
g.exit_requested ==
false){
819 sprintf(
g.logbuf,
"WARNING: PPS interrupt lost\n");
824 rv = write(pps_fd, &output,
sizeof(
int));
826 sprintf(
g.logbuf,
"checkPPSInterrupt() write to driver failed with msg: %s\n", strerror(errno));
833 sprintf(
g.logbuf,
"ERROR: Lost PPS for one hour.");
840 sprintf(
g.logbuf,
"PPS interrupt resumed\n");
845 rv = write(pps_fd, &output,
sizeof(
int));
847 sprintf(
g.logbuf,
"checkPPSInterrupt() write to driver failed with msg: %s\n", strerror(errno));
875 bool isDelaySpike =
false;
884 isDelaySpike =
false;
888 isDelaySpike =
false;
947 else if (timerVal < 0){
953 ts2.tv_nsec = timerVal * 1000;
981 rv = write(pps_fd, &out,
sizeof(
int));
983 sprintf(
g.logbuf,
"getInterruptDelay() write to driver failed with msg: %s\n", strerror(errno));
988 rv = read(pps_fd, (
void *)
g.
tm, 6 *
sizeof(
int));
1011 sprintf(
g.msgbuf,
"Interrupt delay: %d usec, Delay median: %lf usec sysDelay: %d usec\n",
1017 sprintf(
g.logbuf,
"getInterruptDelay() Device driver read returned: %d Error: %s\n", rv, strerror(errno));
1023 rv = write(pps_fd, &out,
sizeof(
int));
1025 sprintf(
g.logbuf,
"getInterruptDelay() write to driver failed with msg: %s\n", strerror(errno));
1067 ssize_t rv = read(pps_fd, (
void *)
g.
tm, 2 *
sizeof(
int));
1073 if (rv == 0 && !
g.exit_requested){
1074 time_t t = time(NULL);
1075 struct tm *tmp = localtime(&t);
1076 strftime(
g.strbuf,
STRBUF_SZ,
"%F %H:%M:%S ", tmp);
1077 strcat(
g.strbuf,
"Read PPS interrupt failed\n");
1081 sprintf(
g.logbuf,
"gps-pps-io PPS read() returned: %d Error: %s\n", rv, strerror(errno));
1087 g.
t.tv_sec =
g.
tm[0];
1089 g.
t.tv_usec =
g.
tm[1];
1098 sprintf(
g.logbuf,
"pps-client is restarting...\n");
1145 struct timespec ts2;
1156 if (
g.doNTPsettime){
1162 if (
g.doSerialsettime){
1164 strcpy(cmd,
"stty -F ");
1166 printf(
"g.serialPort: %s\n",
g.serialPort);
1168 strcat(cmd,
g.serialPort);
1169 strcat(cmd,
" raw 9600 cs8 clocal -cstopb");
1181 sprintf(
g.logbuf,
"PPS-Client v%s is starting ...\n",
version);
1187 gettimeofday(&tv1, NULL);
1193 if (
g.exit_requested){
1194 sprintf(
g.logbuf,
"PPS-Client stopped.\n");
1199 nanosleep(&ts2, NULL);
1210 sprintf(
g.logbuf,
"Lost PPS or system error. pps-client is exiting.\n");
1219 if (
g.doNTPsettime){
1224 if (
g.doSerialsettime){
1245 gettimeofday(&tv1, NULL);
1250 if (
g.doNTPsettime){
1253 if (
g.doSerialsettime){
1283 bool verbose =
false;
1286 if (strcmp(argv[1],
"-v") == 0){
1292 if (prStat == 0 || prStat == -2){
1296 if (geteuid() != 0){
1297 printf(
"pps-client is not running. \"sudo pps-client\" to start.\n");
1309 sprintf(
g.logbuf,
"Fork in main() failed: %s\n", strerror(errno));
1315 struct sched_param param;
1316 mlockall(MCL_CURRENT | MCL_FUTURE);
1325 if (
g.doNTPsettime && rv != 0){
1329 param.sched_priority = 99;
1330 sched_setscheduler(0, SCHED_FIFO, ¶m);
1333 sprintf(
g.logbuf,
"Could not get GPIO vals for driver. Exiting.\n");
1334 fprintf(stderr,
"%s",
g.logbuf);
1340 sprintf(
g.logbuf,
"Could not load PPS-Client driver. Exiting.\n");
1341 fprintf(stderr,
"%s",
g.logbuf);
1359 sprintf(
g.msgbuf,
"Process PID: %d\n", ppid);
1366 sprintf(
g.logbuf,
"PPS-Client closed driver\n");
1377 sprintf(
g.logbuf,
"PPS-Client unloaded driver.\n");
#define SLEW_LEN
The slew accumulator (slewAccum) update interval.
void writeToLog(char *logbuf)
double slewAccum
Accumulates G.rawError in getTimeSlew() and is used to determine G.avgSlew.
void buildInterruptDistrib(int intrptDelay)
bool detectIntrptDelaySpike(int intrptError)
void recordOffsets(int timeCorrection)
bool isControlling
Set "true" by getAcquireState() when the control loop can begin to control the system clock frequency...
#define INV_DELAY_SAMPLES_PER_MIN
Constant for calculating G.sysDelay.
void recordFrequencyVars(void)
int tm[6]
Returns the interrupt calibration reception and response times from the PPS-Client device driver...
struct timex t3
Passes G.timeCorrection to the system function adjtimex() in makeTimeCorrection().
double freqOffset
System clock frequency correction calculated as G.integralTimeCorrection * G.integralGain.
#define SHOW_INTRPT_DATA_INTVL
The number of seconds between displays of interrupt delay in the PPS-Client status line...
int makeTimeCorrection(struct timeval pps_t, int pps_fd)
double integral[NUM_INTEGRALS]
Array of integrals constructed by makeAverageIntegral().
int removeNoise(int rawError)
double t_mono_now
Current monotonic count of passing seconds.
void setHardLimit(double avgCorrection)
void writeTimestamp(double timestamp)
double integralTimeCorrection
Integral or average integral of G.timeCorrection returned by getIntegral();.
unsigned int ppsCount
Advancing count of G.rawErrorDistrib[] entries made by detectDelayPeak().
int getFractionalSeconds(timeval pps_t)
int rawError
Set equal to G.interruptTime - G.sysDelay in makeTimeCorrection().
void freeSNTPThreads(timeCheckParams *tcp)
bool integralIsReady(void)
#define INTEGRAL_GAIN
Controller integral gain constant in active controller operation.
bool interruptLost
Set "true" when a PPS interrupt time fails to be received.
int adjtimex(struct timex *timex)
int zeroError
The controller error resulting from removing jitter noise from G.rawError in removeNoise().
void getTimeSlew(int rawError)
unsigned int activeCount
Advancing count of controller cycles once G.isControlling is "true".
void makeSNTPTimeQuery(timeCheckParams *tcp)
void makeAverageIntegral(double avgCorrection)
int integralCount
Counts the integrals formed over the last 10 controller cycles and signals when all integrals in G...
double getAverageCorrection(int timeCorrection)
int correctionAccum
Accumulates G.timeCorrection values from G.correctionFifo in getAverageCorrection() in order to gener...
double avgSlew
Average slew value determined by getTimeSlew() from the average of G.slewAccum each time G...
int checkPPSInterrupt(int pps_fd)
void increaseMonotonicCount(void)
int sysCommand(const char *cmd)
#define RAW_ERROR_DECAY
Decay rate for G.rawError samples (1 hour half life)
#define RAW_ERROR_ZERO
Index corresponding to rawError == 0 in detectDelayPeak().
void buildSysDelayDistrib(int sysDelay)
double avgCorrection
A one-minute rolling average of G.timeCorrection values generated by getAverageCorrection().
unsigned int intrptCount
Advancing count of intrptErrorDistrib[] entries made by detectDelayPeak().
const char * version
Program version 1.4.0 created on 17 Dec 2017.
void initialize(bool verbose)
#define BLOCK_FOR_10
Blocks detection of external system clock changes for 10 seconds.
#define PER_MINUTE
Inverse seconds per minute.
int consensusTimeError
Consensus value of whole-second time corrections for DST or leap seconds from Internet SNTP servers...
int timeCorrection
Time correction value constructed in makeTimeCorrection() by dividing G.zeroError by G...
#define NUM_INTEGRALS
Number of integrals used by makeAverageIntegral() to calculate the one minute clock frequency correct...
int accessDaemon(int argc, char *argv[])
int allocInitializeSerialThread(timeCheckParams *tcp)
double avgIntegral
One-minute average of the integrals in G.integral[].
int correctionFifo[OFFSETFIFO_LEN]
Contains the G.timeCorrection values from over the previous 60 seconds.
double delayMedian
Median of G.intrptDelay values calculated in getInterruptDelay().
void TERMhandler(int sig)
bool isVerbose
Enables continuous printing of PPS-Client status params when "true".
void buildErrorDistrib(int timeCorrection)
#define INV_GAIN_0
Controller inverse proportional gain constant at startup.
bool slewIsLow
Set to "true" in getAcquireState() when G.avgSlew is less than SLEW_MAX. This is a precondition for g...
int getDriverGPIOvals(void)
int clampJitter(int rawError)
int setClockFractionalSecond(int correction, int pps_fd)
int removeIntrptNoise(int intrptError)
int correctionFifo_idx
Advances G.correctionFifo on each controller cycle in integralIsReady() which returns "true" every 60...
void freeSerialThread(timeCheckParams *tcp)
int setClockToNTPtime(int pps_fd)
#define ERROR_DISTRIB_LEN
int slewAccum_cnt
Count of the number of times G.rawError has been summed into G.slewAccum.
int sysDelayShift
Assigned from G.delayShift and subtracted from G.rawError in correctDelayPeak() when a delay shift oc...
int noiseLevel
PPS time delay value beyond which a delay is defined to be a delay spike.
int bufferStateParams(void)
bool isDelaySpike
Set "true" by detectDelaySpike() when G.rawError exceeds G.noiseLevel.
unsigned int seq_num
Advancing count of the number of PPS interrupt timings that have been received.
int t_count
Whole seconds counted at the time of G.t_now.
#define SLEW_MAX
Jitter slew value below which the controller will begin to frequency lock.
double rawErrorDistrib[ERROR_DISTRIB_LEN]
The distribution used to detect a delay shift in detectDelayPeak().
#define INTERRUPT_LOST
Number of consecutive lost interrupts at which a warning starts.
#define MAX_SPIKES
Maximum microseconds to suppress a burst of continuous positive jitter.
void setDelayTrackers(void)
int getInterruptDelay(int pps_fd)
Struct for passing arguments to and from threads querying SNTP time servers or GPS receivers...
int intrptDelay
Value of the interrupt delay calibration measurement received from the PPS-Client device driver...
void buildRawErrorDistrib(int rawError, double errorDistrib[], unsigned int *count)
#define SETTLE_TIME
The PPS-Client up time required before saving performance data.
int invProportionalGain
Controller proportional gain configured inversely to use as an int divisor.
int nDelaySpikes
Current count of continuous delay spikes made by detectDelaySpike().
Struct for program-wide global variables showing those important to the controller.
int outputGPIO
The calibrate GPIO output number read from pps-client.conf and passed to the driver.
#define NOISE_LEVEL_MIN
The minimum level at which interrupt delays are delay spikes.
int t_now
Whole seconds of current time reported by gettimeofday().
int intrptError
Set equal to "intrptDelay - sysDelay" in getInterruptDelay().
int allocInitializeSNTPThreads(timeCheckParams *tcp)
bool getAcquireState(void)
double t_mono_last
Last recorded monotonic count used to determine a lost PPS update.
bool detectDelaySpike(int rawError)
int open_logerr(const char *filename, int flags)
int makeSerialTimeQuery(timeCheckParams *tcp)
bool detectExteralSystemClockChange(void)
int interruptLossCount
Records the number of consecutive lost PPS interrupt times.
#define INTERRUPT_LATENCY
Default interrupt latency assigned to sysDelay (microseconds).
#define INTERRUPT_DISTRIB
int setClockToSerialTime(int pps_fd)
bool isNearZero(double val)
int readPPS_SetTime(bool verbose, int pps_fd)
#define NOISE_FACTOR
Adjusts G.noiseLevel to track G.sysDelay.
struct timeval t
Time of system response to the PPS interrupt. Received from the PPS-Client device driver...
int main(int argc, char *argv[])
int hardLimit
An adaptive limit value determined by setHardLimit() and applied to G.rawError by clampJitter() as th...
void buildJitterDistrib(int rawError)
struct timespec setSyncDelay(int timeAt, int fracSec)
int writeStatusStrings(void)
int correctionFifoCount
Signals that G.correctionFifo contains a full count of G.timeCorrection values.
int intrptGPIO
The calibrate GPIO interrupt number read from pps-client.conf and passed to the driver.
int driver_load(int ppsGPIO, int outputGPIO, int intrptGPIO)
int ppsGPIO
The PPS GPIO interrupt number read from pps-client.conf and passed to the driver. ...
#define ADJTIMEX_SCALE
Frequency scaling required by adjtimex().
#define INV_GAIN_1
Controller inverse proportional gain constant during active controller operation. ...
double zeroAccum
Accumulator to test nearness to zero in isNearZero()
bool interruptReceived
Set "true" when makeTimeCorrection() processes an interrupt time from the PPS-Client device driver...
void getPPStime(timeval t, int timeCorrection)
void bufferStatusMsg(const char *msg)
int interruptTime
Fractional second part of G.t received from PPS-Client device driver.
double integralGain
Current controller integral gain.
#define PER_NUM_INTEGRALS
Inverse of NUM_INTEGRALS.
void initFileLocalData(void)
struct G g
Declares the global variables defined in pps-client.h.
void waitForPPS(bool verbose, int pps_fd)