PPS-Client
1.4.0
Client for synchronizing the system clock to a GPS PPS source
|
The pps-client.cpp file contains the principal PPS-Client controller functions and structures. More...
#include "../client/pps-client.h"
Go to the source code of this file.
Functions | |
int | adjtimex (struct timex *timex) |
void | setDelayTrackers (void) |
void | initialize (bool verbose) |
bool | getAcquireState (void) |
void | setHardLimit (double avgCorrection) |
bool | detectDelaySpike (int rawError) |
void | getTimeSlew (int rawError) |
int | clampJitter (int rawError) |
void | makeAverageIntegral (double avgCorrection) |
bool | integralIsReady (void) |
double | getAverageCorrection (int timeCorrection) |
int | setClockToNTPtime (int pps_fd) |
int | setClockToSerialTime (int pps_fd) |
int | setClockFractionalSecond (int correction, int pps_fd) |
void | buildRawErrorDistrib (int rawError, double errorDistrib[], unsigned int *count) |
int | removeNoise (int rawError) |
double | getIntegral (void) |
void | getPPStime (timeval t, int timeCorrection) |
int | getFractionalSeconds (timeval pps_t) |
void | increaseMonotonicCount (void) |
bool | isNearZero (double val) |
bool | detectExteralSystemClockChange (void) |
int | makeTimeCorrection (struct timeval pps_t, int pps_fd) |
int | checkPPSInterrupt (int pps_fd) |
bool | detectIntrptDelaySpike (int intrptError) |
int | removeIntrptNoise (int intrptError) |
struct timespec | setSyncDelay (int timeAt, int fracSec) |
int | getInterruptDelay (int pps_fd) |
int | readPPS_SetTime (bool verbose, int pps_fd) |
void | waitForPPS (bool verbose, int pps_fd) |
int | main (int argc, char *argv[]) |
Variables | |
const char * | version = "1.4.0" |
Program version 1.4.0 created on 17 Dec 2017. More... | |
struct G | g |
Declares the global variables defined in pps-client.h. More... | |
The pps-client.cpp file contains the principal PPS-Client controller functions and structures.
The PPS-Client daemon synchronizes the system clock to a Pulse-Per-Second (PPS) source to a resolution of one microsecond with an absolute accuracy of a few microseconds. To obtain this level of performance PPS-Client provides offset corrections every second and frequency corrections every minute. This and removal of jitter in the reported PPS time keeps the system clock continuously synchronized to the PPS source.
A wired GPIO connection is required from a PPS source. Synchronization is provided by the rising edge of that PPS source which is connected to GPIO 4.
The executable for this daemon is "/usr/sbin/pps-client"
The daemon script is "/etc/init.d/pps-client"
The configuration file is "/etc/pps-client.conf"
The kernel driver is "/lib/modules/`uname -r`/kernel/drivers/misc/gps-pps-io.ko"
Created on: Nov 17, 2015
Copyright (C) 2016-2018 Raymond S. Connell
This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Definition in file pps-client.cpp.
int adjtimex | ( | struct timex * | timex | ) |
System call
void buildRawErrorDistrib | ( | int | rawError, |
double | errorDistrib[], | ||
unsigned int * | count | ||
) |
Constructs an exponentially decaying distribution of rawError with a half life on individual samples of 1 hour.
[in] | rawError | The distribution values. |
[out] | errorDistrib | The distribution being constructed. |
[in,out] | count | The count of distribution samples. |
Definition at line 487 of file pps-client.cpp.
int checkPPSInterrupt | ( | int | pps_fd | ) |
Logs loss and resumption of the PPS interrupt and if so configured can set a hardware pin HIGH and LOW respectively. Can force exit if the interrupt is lost for more than one hour when "exit-lost-pps=enable" is set in the config file.
[in] | pps_fd | The gps-pps-io device driver file descriptor. |
Definition at line 810 of file pps-client.cpp.
int clampJitter | ( | int | rawError | ) |
Clamps rawError to an adaptive value determined at the current hardLimit value from the current value of G.avgCorrection.
Once the rawError values have been limited to values of +/- 1 microsecond and the control loop has settled, this clamping causes the controller to make the average number of positive and negative rawError values equal rather than making the sum of the positive and negative jitter values zero. This removes the bias that would otherwise be introduced by the rawError values which are largely random and consequently would introduce a constantly changing random offset. The result is also to move the average PPS interrupt delay to its median value.
[in] | rawError | The raw error value to be converted to a zero error. |
Definition at line 246 of file pps-client.cpp.
bool detectDelaySpike | ( | int | rawError | ) |
Removes jitter delay spikes by returning "true" as long as the jitter value remains beyond a threshold (G.noiseLevel). Is not active unless G.hardLimit is at HARD_LIMIT_4 or below.
[in] | rawError | The raw error vlue to be tested for a delay spike. |
Definition at line 183 of file pps-client.cpp.
bool detectExteralSystemClockChange | ( | void | ) |
Determines whether the system clock has been set externally.
Definition at line 689 of file pps-client.cpp.
bool detectIntrptDelaySpike | ( | int | intrptError | ) |
Removes jitter delay spikes by returning "true" as long as the jitter level remains above a threshold (G.noiseLevel). Is not active unless G.hardLimit is at HARD_LIMIT_4 or below.
[in] | intrptError | The raw interrupt error value to be tested for a delay spike. |
Definition at line 874 of file pps-client.cpp.
bool getAcquireState | ( | void | ) |
Returns true when the control loop can begin to control the system clock frequency. At program start only the time slew is adjusted because the drift can be too large for it to be practical to adjust the system clock frequency to correct for it. SLEW_MAX sets a reasonable limit below which frequency offset can also be adjusted to correct system time.
Consequently, once the drift is within SLEW_MAX microseconds of zero and the controller has been running for at least 60 seconds (time selected for convenience), this function returns "true" causing the controller to begin to also adjust the system clock frequency offset.
Definition at line 109 of file pps-client.cpp.
double getAverageCorrection | ( | int | timeCorrection | ) |
Maintains G.correctionFifo which contains second-by-second values of time corrections over the last minute, accumulates a rolling sum of these and returns the average correction over the last minute.
Since timeCorrection converges to a sequence of positive and negative values each of magnitude one, the average timeCorrection which is forced to be zero by the controller also corresponds to the time delay where the number of positive and negative corrections are equal and thus this time delay, although not directly measurable, is the median of the time delays causing the corrections.
[in] | timeCorrection | The time correction value to be accumulated. |
Definition at line 347 of file pps-client.cpp.
int getFractionalSeconds | ( | timeval | pps_t | ) |
Gets the fractional seconds part of interrupt time and if the value should be interpreted as negative then translates the value.
[in] | pps_t | The delayed time of the PPS rising edge returned by the system clock. |
Definition at line 611 of file pps-client.cpp.
double getIntegral | ( | void | ) |
if G.hardLimit == HARD_LIMIT_1, gets an integral time correction as a 10 second average of integrals of average time corrections over one minute. Otherwise gets the integral time correction as the single last integral of average time corrections over one minute.
Definition at line 560 of file pps-client.cpp.
int getInterruptDelay | ( | int | pps_fd | ) |
When CALIBRATE is enabled, calculates the time interval between a write to an I/O pin that generates a hardware interrupt and the recognition of that interrupt by the system.
Both the write time and the recognition time are read from the PPS-Client kernel driver approximately each second. The time interval is then calculated along with its median value. The median value, generated with one-minute weighting, is the approximate interrupt delay and is assigned to G.sysDelay.
[in] | pps_fd | The PPS-Client device driver file descriptor. |
Definition at line 977 of file pps-client.cpp.
void getPPStime | ( | timeval | t, |
int | timeCorrection | ||
) |
Gets the time of the PPS rising edge from the timeCorrection value and sets the corresponding timestamp.
[in] | t | The delayed time of the PPS rising edge returned by the system. |
[in] | timeCorrection | The correction to be applied to get the back dated time of the PPS rising edge. |
Definition at line 589 of file pps-client.cpp.
void getTimeSlew | ( | int | rawError | ) |
Gets the average time offset from zero over the interval SLEW_LEN and updates avgSlew with this value every SLEW_LEN seconds.
[in] | rawError | The raw error to be accumulated to determine average slew. |
Definition at line 215 of file pps-client.cpp.
void increaseMonotonicCount | ( | void | ) |
Advances a monotonic time count g.t_count second by second even when this function is not called every second. The g.t_count value is used to determine if the system time has been set externally in the detectExteralSystemClockChange() function.
Definition at line 627 of file pps-client.cpp.
void initialize | ( | bool | verbose | ) |
Sets global variables to initial values at startup or restart and sets system clock frequency offset to zero.
[in] | verbose | Enables printing of state status params when "true". |
Definition at line 72 of file pps-client.cpp.
bool integralIsReady | ( | void | ) |
Advances the G.correctionFifo index each second and returns "true" when 60 new time correction values have been accumulated in G.correctionAccum.
When a value of "true" is returned, new average time correction integrals have been generated by makeAverageIntegral() and are ready for use.
Definition at line 312 of file pps-client.cpp.
bool isNearZero | ( | double | val | ) |
Checks that arg val has been near zero for about the previous 20 or so values.
[in] | val | The arg to be checked for nearness to zero. |
Definition at line 672 of file pps-client.cpp.
int main | ( | int | argc, |
char * | argv[] | ||
) |
If not already running, creates a detached process that will run as a daemon. Accepts one command line arg: -v that causes the daemon to run in verbose mode which writes a status string and event messages to the console once per second. These messages continue until the console that started the pps-client daemon is closed.
Alternatively, if the daemon is already running, displays a statement to that effect and accepts the following optional command line args:
The -v flag starts the second-by-second display of a status string that will continue until ended by ctrl-c.
The -s flag requests that specified files be saved. If the -s flag is not followed by a file specifier, a list of the files that can be saved is printed.
Definition at line 1279 of file pps-client.cpp.
void makeAverageIntegral | ( | double | avgCorrection | ) |
Constructs, at each second over the last 10 seconds in each minute, 10 integrals of the average time correction over the last minute.
These integrals are then averaged to G.avgIntegral just before the minute rolls over. The use of this average of the last 10 integrals to correct the frequency offset of the system clock provides a modest improvement over using only the single last integral.
[in] | avgCorrection | The average correction to be integrated. |
Definition at line 274 of file pps-client.cpp.
int makeTimeCorrection | ( | struct timeval | pps_t, |
int | pps_fd | ||
) |
Makes time corrections each second, frequency corrections each minute and removes jitter from the PPS time reported by pps_t.
This function is called by readPPS_SetTime() from within the one-second delay loop in the waitForPPS() function.
[in] | pps_t | The delayed time of the PPS rising edge returned by the system clock. |
[in] | pps_fd | The gps-pps-io device driver file descriptor. |
Definition at line 723 of file pps-client.cpp.
int readPPS_SetTime | ( | bool | verbose, |
int | pps_fd | ||
) |
Requests a read of the reception time of the PPS hardware interrupt by the gps-pps-io driver and passes the value read to makeTimeCorrection(). The driver is accessed with the pps_fd file descriptor.
When read(pps_fd) is called, the driver puts pps-client to sleep until a PPS hardware interrupt has occurred. When it occurs, the driver wakes up pps-client, read(pps_fd) copies the time at which the interrupt was caught by the driver and the value is passed to makeTimeCorrection().
The first time pps-client runs, the time slew can be as large as hundreds of milliseconds. When this is the case, limits imposed by adjtimex() prevent changes in offset of more than about 500 microseconds each second. As a result, pps-client will make a partial correction each minute and will restart several times before the slew is small enough that getAcquireState() will set G.isControlling to "true". This looping will eventually converge but can take as long as 20 minutes.
[in] | verbose | If "true" then write pps-client state status messages to the console. Else not. |
[in] | pps_fd | The gps-pps-io device driver file descriptor. |
Definition at line 1064 of file pps-client.cpp.
int removeIntrptNoise | ( | int | intrptError | ) |
Removes delay peaks, spikes and jitter from intrptError and returns the resulting clamped zeroError.
[in] | intrptError | The raw interrupt error value to be processed. |
Definition at line 906 of file pps-client.cpp.
int removeNoise | ( | int | rawError | ) |
Removes spikes and jitter from rawError and returns the resulting clamped zeroError.
[in] | rawError | The raw error value to be processed. |
Definition at line 520 of file pps-client.cpp.
int setClockFractionalSecond | ( | int | correction, |
int | pps_fd | ||
) |
Corrects the system time whenever the system clock is set externally.
The external device that sets the clock may inject a non-zero fractional second along with the whole seconds. This is removed by effectively inverting the sign of any detected fractional second and immediately applying it as a clock correction.
[in] | correction | The fractional correction value in microseconds. |
[in] | pps_fd | The gps-pps-io device driver file descriptor. |
Definition at line 460 of file pps-client.cpp.
int setClockToNTPtime | ( | int | pps_fd | ) |
Sets the system time whenever there is an error relative to the whole seconds obtained from Internet SNTP servers by writing the whole second correction to the PPS kernel driver.
Errors are infrequent. But if one occurs the whole seconds of system clock are set following the CHECK_TIME interval to the correct time though the gps-pps-io device driver.
[in] | pps_fd | The gps-pps-io device driver file descriptor. |
Definition at line 389 of file pps-client.cpp.
int setClockToSerialTime | ( | int | pps_fd | ) |
Sets the system time whenever there is an error relative to the whole seconds obtained through the serial port by writing the whole second correction to the PPS kernel driver.
Errors are infrequent. But if one occurs the whole seconds of system clock are set following the CHECK_TIME interval to the correct time though the gps-pps-io device driver.
[in] | pps_fd | The gps-pps-io device driver file descriptor. |
Definition at line 422 of file pps-client.cpp.
void setDelayTrackers | ( | void | ) |
Sets G.noiseLevel to be proportional to G.sysDelay.
Definition at line 58 of file pps-client.cpp.
void setHardLimit | ( | double | avgCorrection | ) |
Uses G.avgSlew or avgCorrection and the curent hard limit, G.hardLimit, to determine the global G.hardLimit to set on zero error to convert error values to time corrections.
Because it is much more effective and does not introduce additional time delay, hard limiting is used instead of filtering to remove noise (jitter) from the reported time of PPS capture.
[in] | avgCorrection | Current average correction value. |
Definition at line 134 of file pps-client.cpp.
struct timespec setSyncDelay | ( | int | timeAt, |
int | fracSec | ||
) |
Sets a nanosleep() time delay equal to the time remaining in the second from the time recorded as fracSec plus an adjustment value of timeAt in microseconds. The purpose of the delay is to put the program to sleep until just before the time when a PPS interrupt timing will be delivered by the gps-pps-io device driver.
[in] | timeAt | The adjustment value. |
[in] | fracSec | The fractional second part of the system time. |
Definition at line 937 of file pps-client.cpp.
void waitForPPS | ( | bool | verbose, |
int | pps_fd | ||
) |
Runs the one-second wait loop that waits for the PPS hardware interrupt that returns the timestamp of the interrupt which is passed to makeTimeCorrection().
[in] | verbose | If "true" then write pps-client state status messages to the console. Else not. |
[in] | pps_fd | The gps-pps-io device driver file descriptor. |
Definition at line 1143 of file pps-client.cpp.
struct G g |
Declares the global variables defined in pps-client.h.
Definition at line 53 of file pps-client.cpp.
const char* version = "1.4.0" |
Program version 1.4.0 created on 17 Dec 2017.
Definition at line 51 of file pps-client.cpp.