PPS-Client  2.0.0
Client for synchronizing the system clock to a GPS PPS source
pps-files.cpp
Go to the documentation of this file.
1 
5 /*
6  * Copyright (C) 2016-2020 Raymond S. Connell
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License along
19  * with this program; if not, write to the Free Software Foundation, Inc.,
20  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21  */
22 
23 #include "../client/pps-client.h"
24 
25 extern struct G g;
26 
27 const char *config_file = "/XXXX/pps-client.conf";
28 const char *last_distrib_file = "/pps-error-distrib";
29 const char *distrib_file = "/pps-error-distrib-forming";
30 const char *last_jitter_distrib_file = "/pps-jitter-distrib";
31 const char *jitter_distrib_file = "/pps-jitter-distrib-forming";
32 const char *log_file = "/pps-client.log";
33 const char *old_log_file = "/pps-client.old.log";
34 const char *pidFilename = "/pps-client.pid";
35 const char *assert_file = "/pps-assert";
36 const char *displayParams_file = "/pps-display-params";
37 const char *arrayData_file = "/pps-save-data";
38 const char *pps_msg_file = "/pps-msg";
39 const char *linuxVersion_file = "/linuxVersion";
40 const char *gmtTime_file = "/gmtTime";
41 const char *nistTime_file = "/nist_out";
42 const char *integral_state_file = "/.pps-last-state";
43 const char *home_file = "/Home";
44 const char *cpuinfo_file = "/cpuinfo";
45 
46 const char *space = " ";
47 const char *num = "0123456789.";
48 
49 extern const char *version;
50 
51 static struct stat configFileStat;
52 static time_t modifyTime = 0;
53 static int lastJitterFileno = 0;
54 static int lastErrorFileno = 0;
55 static struct timespec offset_assert = {0, 0};
56 
57 bool writeJitterDistrib = false;
58 bool writeErrorDistrib = false;
59 
63 struct ppsFiles f;
64 
74 const char *valid_config[] = {
75  "error-distrib",
76  "alert-pps-lost",
77  "jitter-distrib",
78  "exit-lost-pps",
79  "pps-gpio",
80  "output-gpio",
81  "intrpt-gpio",
82  "nist",
83  "serial",
84  "serialPort",
85  "execdir",
86  "servicedir",
87  "configdir",
88  "docdir",
89  "rundir",
90  "shmdir",
91  "tstdir",
92  "logdir",
93  "zeroOffset",
94  "moduledir",
95  "ppsdevice",
96  "ppsphase",
97  "procdir",
98  "segregate"
99 };
100 
110 int List::binaryInsert(int val){
111  if (count == size){
112  return size;
113  }
114 
115  count += 1;
116 
117  int high = ln - 1;
118  if (ln == 0 || val > lst[high].val){
119  insert(ln, val);
120  return ln;
121  }
122  if (ln == 1){
123  if (val < lst[0].val){
124  insert(0, val);
125  return 0;
126  }
127  if (val > lst[0].val){
128  insert(ln, val);
129  return ln;
130  }
131  lst[0].nVals += 1;
132  return 0;
133  }
134  int low = -1;
135  int j = 0;
136  while ((high - low) > 1){
137  j = (high + low) / 2;
138  if (val <= lst[j].val){
139  high = j;
140  }
141  else {
142  low = j;
143  }
144  }
145  if (lst[high].val == val){
146  lst[high].nVals += 1;
147  return high;
148  }
149  insert(high, val);
150  return high;
151 }
152 
153 
164 double List::averageBelow(int maxVal){
165 
166  int sum = 0;
167  int n = 0;
168  double average;
169 
170  if (ln == 0){
171  return 0;
172  }
173 
174  for (int i = 0; i < ln; i++){
175  sum += lst[i].nVals * lst[i].val;
176  n += lst[i].nVals;
177 
178  if (i < ln-1){
179  if (lst[i+1].val - lst[i].val >= maxVal){
180  break;
181  }
182  }
183  }
184 
185  average = (double)sum / (double)n;
186 
187  return average;
188 }
189 
193 int sysCommand(const char *cmd){
194  int rv = system(cmd);
195  if (rv == -1 || WIFEXITED(rv) == false){
196  sprintf(g.logbuf, "System command failed: %s\n", cmd);
197  writeToLog(g.logbuf, "sysCommand()");
198  return -1;
199  }
200  return 0;
201 }
202 
212 char *getString(int key){
213  char *str;
214  int len;
215  int i = round(log2(key));
216 
217  if (g.config_select & key){
218 
219  str = g.configVals[i];
220 
221  len = strlen(str);
222 
223  while (str[len-1] == ' '){
224  str[len-1] = '\0';
225  len -= 1;
226  }
227 
228  return str;
229  }
230  return NULL;
231 }
232 
253 bool hasString(int key, const char *string){
254  int i = round(log2(key));
255 
256  if (g.config_select & key){
257  char *val = strstr(g.configVals[i], string);
258  if (val != NULL){
259  return true;
260  }
261  }
262  return false;
263 }
264 
275 bool isEnabled(int key){
276  return hasString(key, "enable");
277 }
278 
289 bool isDisabled(int key){
290  return hasString(key, "disable");
291 }
292 
297 struct saveFileData arrayData[] = {
298  {"rawError", g.rawErrorDistrib, "/var/local/pps-raw-error-distrib", ERROR_DISTRIB_LEN, 2, RAW_ERROR_ZERO},
299  {"frequency-vars", NULL, "/var/local/pps-frequency-vars", 0, 3, 0},
300  {"pps-offsets", NULL, "/var/local/pps-offsets", 0, 4, 0}
301 };
302 
306 void couldNotOpenMsgTo(char *logbuf, const char *filename, const char* location){
307  strcpy(logbuf, "ERROR: could not open \"");
308  strcat(logbuf, filename);
309  strcat(logbuf, "\": ");
310  strcat(logbuf, strerror(errno));
311  strcat(logbuf, " ");
312  strcat(logbuf, location);
313  strcat(logbuf, "\n");
314 }
315 
319 void errorReadingMsgTo(char *logbuf, const char *filename){
320  strcpy(logbuf, "ERROR: reading \"");
321  strcat(logbuf, filename);
322  strcat(logbuf, "\" was interrupted: ");
323  strcat(logbuf, strerror(errno));
324  strcat(logbuf, "\n");
325 }
326 
332 void writeToLogNoTimestamp(char *logbuf){
333  struct stat info;
334 
335  bufferStatusMsg(logbuf);
336 
337  stat(f.log_file, &info);
338  if (info.st_size > 100000){ // Prevent unbounded log file growth
339  remove(f.old_log_file);
340  rename(f.log_file, f.old_log_file);
341  }
342 
343  mode_t mode = S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH;
344  int fd = open(f.log_file, O_CREAT | O_WRONLY | O_APPEND, mode);
345  if (fd == -1){
346  couldNotOpenMsgTo(logbuf, f.log_file, "writeToLogNoTimestamp()");
347  printf("%s", logbuf);
348  return;
349  }
350 
351  int rv = write(fd, logbuf, strlen(logbuf));
352  if (rv == -1){
353  ;
354  }
355  close(fd);
356 }
357 
358 
364 void writeToLog(char *logbuf, const char *location){
365  struct stat info;
366 
367  bufferStatusMsg(logbuf);
368 
369  stat(f.log_file, &info);
370  if (info.st_size > 100000){ // Prevent unbounded log file growth
371  remove(f.old_log_file);
372  rename(f.log_file, f.old_log_file);
373  }
374 
375  mode_t mode = S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH;
376  int fd = open(f.log_file, O_CREAT | O_WRONLY | O_APPEND, mode);
377  if (fd == -1){
378  couldNotOpenMsgTo(logbuf, f.log_file, location);
379  printf("%s", logbuf);
380  return;
381  }
382 
383  time_t t = time(NULL);
384  struct tm *tmp = localtime(&t);
385  strftime(g.strbuf, STRBUF_SZ-1, "%F %H:%M:%S ", tmp);
386  int rv = write(fd, g.strbuf, strlen(g.strbuf));
387  if (rv == -1){
388  ;
389  }
390 
391  rv = write(fd, logbuf, strlen(logbuf));
392  if (rv == -1){
393  ;
394  }
395  close(fd);
396 }
397 
407 void bufferStatusMsg(const char *msg){
408 
409  if (g.isVerbose){
410  fprintf(stdout, "%s", msg);
411  }
412 
413  int msglen = strlen(g.savebuf) + 10;
414  int parmslen = strlen(msg);
415 
416  if (msglen + parmslen > MSGBUF_SZ){
417  return;
418  }
419 
420  strcat(g.savebuf, msg);
421 
422  return;
423 }
424 
436 
437  int fSize = strlen(g.savebuf);
438 
439  remove(f.displayParams_file);
440  int fd = open_logerr(f.displayParams_file, O_CREAT | O_WRONLY, "writeStatusStrings() 1");
441  if (fd == -1){
442  return -1;
443  }
444  int rv = write(fd, g.savebuf, fSize);
445  close(fd);
446  if (rv == -1){
447  sprintf(g.logbuf, "writeStatusStrings() Could not write to %s. Error: %s\n", f.displayParams_file, strerror(errno));
448  writeToLog(g.logbuf, "writeStatusStrings() 2");
449  return -1;
450  }
451 
452  g.savebuf[0] = '\0';
453  return 0;
454 }
455 
466 int read_logerr(int fd, char *buf, int sz, const char *filename){
467  int rv = read(fd, buf, sz);
468  if (rv == -1){
469  errorReadingMsgTo(g.logbuf, filename);
470  writeToLog(g.logbuf, "read_logerr()");
471  return rv;
472  }
473  return rv;
474 }
475 
486 int open_logerr(const char* filename, int flags, const char *location){
487  int mode = S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH;
488  int fd;
489  if ((flags & O_CREAT) == O_CREAT){
490  fd = open(filename, flags, mode);
491  }
492  else {
493  fd = open(filename, flags);
494  }
495  if (fd == -1){
496  couldNotOpenMsgTo(g.logbuf, filename, location);
497  writeToLog(g.logbuf, location);
498  return -1;
499  }
500  return fd;
501 }
502 
509 int saveLastState(void){
510  char buf[500];
511 
512  int fd = open_logerr(f.integral_state_file, O_CREAT | O_WRONLY, "saveLastState()");
513  if (fd == -1){
514  return -1;
515  }
516 
517  memset(buf, 0, 500 * sizeof(char));
518  char *pbuf;
519  pbuf = buf;
520  for (int i = 0; i < NUM_INTEGRALS; i++){
521  sprintf(pbuf, "%lf\n", g.integral[i]);
522  while (*pbuf != '\0'){
523  pbuf += 1;
524  }
525  }
526 
527  sprintf(pbuf, "%d\n", g.slewIsLow);
528  while (*pbuf != '\0'){
529  pbuf += 1;
530  }
531 
532  sprintf(pbuf, "%lf\n", g.avgIntegral);
533  while (*pbuf != '\0'){
534  pbuf += 1;
535  }
536 
537  sprintf(pbuf, "%d\n", g.integralCount);
538  while (*pbuf != '\0'){
539  pbuf += 1;
540  }
541 
542  sprintf(pbuf, "%d\n", g.correctionFifo_idx);
543  while (*pbuf != '\0'){
544  pbuf += 1;
545  }
546 
547  sprintf(pbuf, "%lf\n", g.integralTimeCorrection);
548  while (*pbuf != '\0'){
549  pbuf += 1;
550  }
551 
552  for (int i = 0; i < OFFSETFIFO_LEN; i++){
553  sprintf(pbuf, "%d\n", g.correctionFifo[i]);
554  while (*pbuf != '\0'){
555  pbuf += 1;
556  }
557  }
558 
559  sprintf(pbuf, "%d\n", g.correctionFifoCount);
560  while (*pbuf != '\0'){
561  pbuf += 1;
562  }
563 
564  sprintf(pbuf, "%d\n", g.correctionAccum);
565  while (*pbuf != '\0'){
566  pbuf += 1;
567  }
568 
569  sprintf(pbuf, "%lf\n", g.freqOffset);
570  while (*pbuf != '\0'){
571  pbuf += 1;
572  }
573 
574  sprintf(pbuf, "%d\n", g.activeCount);
575  while (*pbuf != '\0'){
576  pbuf += 1;
577  }
578 
579  sprintf(pbuf, "%d\n", g.seq_num);
580  while (*pbuf != '\0'){
581  pbuf += 1;
582  }
583 
584  sprintf(pbuf, "%d\n", (int)g.isControlling);
585  while (*pbuf != '\0'){
586  pbuf += 1;
587  }
588 
589  sprintf(pbuf, "%d\n", g.hardLimit);
590  while (*pbuf != '\0'){
591  pbuf += 1;
592  }
593 
594  int rv = write(fd, buf, strlen(buf) + 1);
595 
596  close(fd);
597 
598  if (rv == -1){
599  sprintf(g.logbuf, "saveLastState() Write to %s failed\n", integral_state_file);
600  writeToLog(g.logbuf, "daemonSaveArray()");
601  return -1;
602  }
603  return 0;
604 }
605 
610 int loadLastState(void){
611  char buf[500];
612 
613  int fd = open(f.integral_state_file, O_RDONLY);
614  if (fd == -1){
615  return 1;
616  }
617 
618  int rv = read_logerr(fd, buf, 499, integral_state_file);
619  if (rv == -1){
620  return -1;
621  }
622  close(fd);
623 
624  char *pbuf = buf;
625 
626  for (int i = 0; i < NUM_INTEGRALS; i++){
627  sscanf(pbuf, "%lf\n", &g.integral[i]);
628 
629  while (*pbuf != '\n'){
630  pbuf += 1;
631  }
632  pbuf += 1;
633  }
634 
635  int b;
636  sscanf(pbuf, "%d\n", &b);
637  g.slewIsLow = false;
638  if (b > 0){
639  g.slewIsLow = true;
640  }
641 
642  while (*pbuf != '\n'){
643  pbuf += 1;
644  }
645  pbuf += 1;
646 
647  sscanf(pbuf, "%lf\n", &g.avgIntegral);
648  while (*pbuf != '\n'){
649  pbuf += 1;
650  }
651  pbuf += 1;
652 
653  sscanf(pbuf, "%d\n", &g.integralCount);
654  while (*pbuf != '\n'){
655  pbuf += 1;
656  }
657  pbuf += 1;
658 
659  sscanf(pbuf, "%d\n", &g.correctionFifo_idx);
660  while (*pbuf != '\n'){
661  pbuf += 1;
662  }
663  pbuf += 1;
664 
665  sscanf(pbuf, "%lf\n", &g.integralTimeCorrection);
666  while (*pbuf != '\n'){
667  pbuf += 1;
668  }
669  pbuf += 1;
670 
671  for (int i = 0; i < OFFSETFIFO_LEN; i++){
672  sscanf(pbuf, "%d\n", &g.correctionFifo[i]);
673 
674  while (*pbuf != '\n'){
675  pbuf += 1;
676  }
677  pbuf += 1;
678  }
679 
680  sscanf(pbuf, "%d\n", &g.correctionFifoCount);
681  while (*pbuf != '\n'){
682  pbuf += 1;
683  }
684  pbuf += 1;
685 
686  sscanf(pbuf, "%d\n", &g.correctionAccum);
687  while (*pbuf != '\n'){
688  pbuf += 1;
689  }
690  pbuf += 1;
691 
692  sscanf(pbuf, "%lf\n", &g.freqOffset);
693  while (*pbuf != '\n'){
694  pbuf += 1;
695  }
696  pbuf += 1;
697 
698  sscanf(pbuf, "%d\n", &g.activeCount);
699  while (*pbuf != '\n'){
700  pbuf += 1;
701  }
702  pbuf += 1;
703 
704  sscanf(pbuf, "%d\n", &g.seq_num);
705  while (*pbuf != '\n'){
706  pbuf += 1;
707  }
708  pbuf += 1;
709 
710  int t_f;
711  sscanf(pbuf, "%d\n", &t_f);
712  if (t_f == 0){
713  g.isControlling = false;
714  }
715  else {
716  g.isControlling = true;
717  }
718  while (*pbuf != '\n'){
719  pbuf += 1;
720  }
721  pbuf += 1;
722 
723  sscanf(pbuf, "%d\n", &g.hardLimit);
724  while (*pbuf != '\n'){
725  pbuf += 1;
726  }
727  pbuf += 1;
728 
729  g.startingFromRestore = SECS_PER_MINUTE;
730 
732 
733  g.t3.modes = ADJ_FREQUENCY;
734  g.t3.freq = (long)round(ADJTIMEX_SCALE * g.freqOffset);
735  adjtimex(&g.t3); // Adjust the system clock frequency.
736 
737  return 0;
738 }
739 
750 int writeFileMsgToLogbuf(const char *filename, char *logbuf){
751  struct stat stat_buf;
752  int rv;
753 
754  int fd = open(filename, O_RDONLY);
755  if (fd == -1){
756  couldNotOpenMsgTo(logbuf, filename, "writeFileMsgToLogbuf()");
757  printf("%s", logbuf);
758  return -1;
759  }
760  fstat(fd, &stat_buf);
761  int sz = stat_buf.st_size;
762 
763  if (sz >= LOGBUF_SZ-1){
764  rv = read(fd, logbuf, LOGBUF_SZ-1);
765  if (rv == -1){
766  errorReadingMsgTo(logbuf, filename);
767  printf("%s", logbuf);
768  return rv;
769  }
770  logbuf[LOGBUF_SZ-1] = '\0';
771  }
772  else {
773  rv = read(fd, logbuf, sz);
774  if (rv == -1){
775  errorReadingMsgTo(logbuf, filename);
776  printf("%s", logbuf);
777  return rv;
778  }
779  logbuf[sz] = '\0';
780  }
781  close(fd);
782  remove(filename);
783 
784  return 0;
785 }
786 
794 int writeFileMsgToLog(const char *filename){
795  return writeFileMsgToLogbuf(filename, g.logbuf);
796 }
797 
804 pid_t getChildPID(void){
805  pid_t pid = 0;
806 
807  memset(g.strbuf, 0, STRBUF_SZ-1);
808 
809  int pfd = open_logerr(f.pidFilename, O_RDONLY, "getChildPID()");
810  if (pfd == -1){
811  return -1;
812  }
813  if (read_logerr(pfd, g.strbuf, 19, f.pidFilename) == -1){
814  close(pfd);
815  return -1;
816  }
817  sscanf(g.strbuf, "%d\n", &pid);
818  close(pfd);
819  if (pid > 0){
820  return pid;
821  }
822  return -1;
823 }
824 
831 bool ppsIsRunning(void){
832  char buf[50];
833  char cmdbuf[100];
834 
835  memset(cmdbuf, 0, 100 * sizeof(char));
836  strcpy(cmdbuf, "pidof pps-client > ");
837  strcat(cmdbuf, f.pps_msg_file);
838 
839  int rv = sysCommand(cmdbuf);
840  if (rv == -1){
841  return false;
842  }
843 
844  int fd = open(f.pps_msg_file, O_RDONLY);
845  if (fd == -1){
846  sprintf(g.logbuf, "ppsIsRunning() Failed. Could not open %s. Error: %s\n", f.pps_msg_file, strerror(errno));
847  writeToLog(g.logbuf, "ppsIsRunning()");
848  return false;
849  }
850  memset(buf, 0, 50 * sizeof(char));
851  rv = read(fd, buf, 50);
852  if (rv == -1){
853  sprintf(g.logbuf, "ppsIsRunning() Failed. Could not read %s. Error: %s\n", f.pps_msg_file, strerror(errno));
854  writeToLog(g.logbuf, "ppsIsRunning()");
855  return false;
856  }
857 
858  int callerPID = 0, daemonPID = 0; // If running both of these exist
859  sscanf(buf, "%d %d\n", &callerPID, &daemonPID);
860 
861  close(fd);
862  remove(f.pps_msg_file);
863 
864  if (daemonPID == 0){ // Otherwise only the first exists.
865  return false;
866  }
867  return true;
868 }
869 
875 int createPIDfile(void){
876 
877  struct stat buf;
878  int rv = stat(f.pidFilename, &buf);
879  if (rv == 0){ // If the PID file exists from previously,
880  rv = remove(f.pidFilename); // then remove it.
881  if (rv != 0){
882  return -1;
883  }
884  }
885 
886  int pfd = open_logerr(f.pidFilename, O_RDWR | O_CREAT | O_EXCL, "createPIDfile()");
887  if (pfd == -1){
888  return -1;
889  }
890 
891  pid_t ppid = getpid();
892 
893  sprintf(g.strbuf, "%d\n", ppid);
894  if (write(pfd, g.strbuf, strlen(g.strbuf)) == -1) // Try to write the PID
895  {
896  close(pfd);
897  sprintf(g.logbuf, "createPIDfile() Could not write a PID file. Error: %s\n", strerror(errno));
898  writeToLog(g.logbuf, "createPIDfile()");
899  return -1; // Write failed.
900  }
901  close(pfd);
902 
903  return ppid;
904 }
905 
922 int readConfigFile(const char *fconfig){
923 
924  struct stat stat_buf;
925 
926  int rvs = stat(fconfig, &configFileStat);
927  if (rvs == -1){
928  sprintf(g.logbuf, "readConfigFile(): Config file not found.\n");
929  writeToLog(g.logbuf, "readConfigFile()");
930  return -1; // No config file
931  }
932 
933  timespec t = configFileStat.st_mtim;
934 
935  if (g.configWasRead && g.seq_num > 0 && modifyTime == t.tv_sec){
936  return 1; // Config file unchanged from last read
937  }
938 
939  modifyTime = t.tv_sec;
940 
941  int fd = open_logerr(fconfig, O_RDONLY, "readConfigFile()");
942  if (fd == -1){
943  return -1;
944  }
945 
946  fstat(fd, &stat_buf);
947  int sz = stat_buf.st_size;
948 
949  if (sz >= CONFIG_FILE_SZ){
950  sprintf(g.logbuf, "readConfigFile(): not enough space allocated for config file.\n");
951  writeToLog(g.logbuf, "readConfigFile()");
952  return -1;
953  }
954 
955  int rv = read_logerr(fd, g.configBuf, sz, fconfig);
956  if (rv == -1 || sz != rv){
957  return -1;
958  }
959  close(fd);
960 
961  g.configBuf[sz] = '\0';
962 
963  int nCfgStrs = 0;
964  int i;
965 
966  char *pToken = strtok(g.configBuf, "\n"); // Separate tokens at "\n".
967 
968  while (pToken != NULL){
969  if (strlen(pToken) != 0){ // If not a blank line.
970  for (int j = 0; j < 10; j++){ // Skip leading spaces.
971  if (pToken[0] == ' '){
972  pToken += 1;
973  }
974  else {
975  break; // Break on first non-space character.
976  }
977  }
978 
979  if (pToken[0] != '#'){ // Ignore comment lines.
980  g.configVals[nCfgStrs] = pToken;
981  nCfgStrs += 1;
982  }
983  }
984  pToken = strtok(NULL, "\n"); // Get the next token.
985  }
986 
987  if (nCfgStrs == 0){
988  return 0;
989  }
990 
991  for (i = 0; i < nCfgStrs; i++){ // Compact g.configBuf to remove string terminators inserted by
992  if (i == 0){ // strtok() so that g.configBuf can be searched as a single string.
993  strcpy(g.configBuf, g.configVals[i]);
994  }
995  else {
996  strcat(g.configBuf, g.configVals[i]);
997  }
998  strcat(g.configBuf, "\n");
999  }
1000 
1001  int nValidCnfgs = sizeof(valid_config) / sizeof(char *);
1002 
1003  char **configVal = g.configVals; // Use g.configVals to return pointers to value strings
1004  char *value;
1005 
1006  for (i = 0; i < nValidCnfgs; i++){
1007 
1008  char *found = strstr(g.configBuf, valid_config[i]);
1009  if (found != NULL){
1010  g.config_select |= 1 << i; // Set a bit in g.config_select
1011 
1012  value = strpbrk(found, "="); // Get the value string following '='.
1013  value += 1;
1014 
1015  configVal[i] = value; // Point to g.configVals[i] value string in g.configBuf
1016  }
1017  else {
1018  g.config_select &= ~(1 << i); // Clear a bit in config_select
1019  configVal[i] = NULL;
1020  }
1021  }
1022 
1023  for (i = 0; i < nValidCnfgs; i++){ // Replace the "\n" at the end of each value
1024  if (configVal[i] != NULL){ // string with a string terminator.
1025  value = strpbrk(configVal[i], "\n");
1026  if (value != NULL){
1027  *value = 0;
1028  }
1029  }
1030  }
1031 
1032  if (g.seq_num > 0){
1033  g.configWasRead = true; // Insures that config file read at least once.
1034  }
1035 
1036  return 0;
1037 }
1038 
1055 void writeDistribution(int distrib[], int len, int scaleZero, int count,
1056  int *last_epoch, const char *distrib_file, const char *last_distrib_file){
1057  int rv = 0;
1058  remove(distrib_file);
1059  int fd = open_logerr(distrib_file, O_CREAT | O_WRONLY | O_APPEND, "writeDistribution()");
1060  if (fd == -1){
1061  return;
1062  }
1063  for (int i = 0; i < len; i++){
1064  sprintf(g.strbuf, "%d %d\n", i-scaleZero, distrib[i]);
1065  rv = write(fd, g.strbuf, strlen(g.strbuf));
1066  if (rv == -1){
1067  sprintf(g.logbuf, "writeDistribution() Unable to write to %s. Error: %s\n", distrib_file, strerror(errno));
1068  writeToLog(g.logbuf, "writeDistribution()");
1069  close(fd);
1070  return;
1071  }
1072  }
1073  close(fd);
1074 
1075  int epoch = count / SECS_PER_DAY;
1076  if (epoch != *last_epoch ){
1077  *last_epoch = epoch;
1078  remove(last_distrib_file);
1080  memset(distrib, 0, len * sizeof(int));
1081  }
1082 }
1083 
1091  if (g.jitterCount % SECS_PER_MINUTE == 0 && g.seq_num > SETTLE_TIME){
1092  int scaleZero = JITTER_DISTRIB_LEN / 3;
1093  writeDistribution(g.jitterDistrib, JITTER_DISTRIB_LEN, scaleZero, g.jitterCount,
1094  &lastJitterFileno, f.jitter_distrib_file, f.last_jitter_distrib_file);
1095  }
1096 }
1097 
1105  if (g.errorCount % SECS_PER_MINUTE == 0 && g.seq_num > SETTLE_TIME){
1106  int scaleZero = ERROR_DISTRIB_LEN / 6;
1107  writeDistribution(g.errorDistrib, ERROR_DISTRIB_LEN, scaleZero,
1108  g.errorCount, &lastErrorFileno, f.distrib_file, f.last_distrib_file);
1109  }
1110 }
1111 
1118 void writeOffsets(const char *filename){
1119  int fd = open_logerr(filename, O_CREAT | O_WRONLY | O_TRUNC, "writeOffsets()");
1120  if (fd == -1){
1121  return;
1122  }
1123  for (int i = 0; i < SECS_PER_10_MIN; i++){
1124  int j = g.recIndex2 + i;
1125  if (j >= SECS_PER_10_MIN){
1126  j -= SECS_PER_10_MIN;
1127  }
1128  sprintf(g.strbuf, "%d %d %lf\n", g.seq_numRec[j], g.offsetRec[j], g.freqOffsetRec2[j]);
1129  int rv = write(fd, g.strbuf, strlen(g.strbuf));
1130  if (rv == -1){
1131  sprintf(g.logbuf, "writeOffsets() Unable to write to %s. Error: %s\n", filename, strerror(errno));
1132  writeToLog(g.logbuf, "writeOffsets()");
1133  }
1134  }
1135  close(fd);
1136 }
1137 
1145 void writeFrequencyVars(const char *filename){
1146  int fd = open_logerr(filename, O_CREAT | O_WRONLY | O_TRUNC, "writeFrequencyVars()");
1147  if (fd == -1){
1148  return;
1149  }
1150  for (int i = 0; i < NUM_5_MIN_INTERVALS; i++){
1151  int j = g.recIndex + i; // Read the circular buffers relative to g.recIndx.
1152  if (j >= NUM_5_MIN_INTERVALS){
1153  j -= NUM_5_MIN_INTERVALS;
1154  }
1155  sprintf(g.strbuf, "%ld %lf %lf\n", g.timestampRec[j], g.freqOffsetRec[j], g.freqAllanDev[j]);
1156  int rv = write(fd, g.strbuf, strlen(g.strbuf));
1157  if (rv == -1){
1158  sprintf(g.logbuf, "writeFrequencyVars() Write to %s failed with error: %s\n", filename, strerror(errno));
1159  writeToLog(g.logbuf, "writeFrequencyVars");
1160  close(fd);
1161  return;
1162  }
1163  }
1164  close(fd);
1165 }
1166 
1177 int saveDoubleArray(double distrib[], const char *filename, int len, int arrayZero){
1178 
1179  int fd = open_logerr(filename, O_CREAT | O_WRONLY | O_TRUNC, "saveDoubleArray()");
1180  if (fd == -1){
1181  return -1;
1182  }
1183 
1184  int fileMaxLen = len * MAX_LINE_LEN * sizeof(char);
1185  char *filebuf = new char[fileMaxLen];
1186  int fileLen = 0;
1187 
1188  filebuf[0] = '\0';
1189  for (int i = 0; i < len; i++){
1190  sprintf(g.strbuf, "%d %7.2lf\n", i - arrayZero, distrib[i]);
1191  fileLen += strlen(g.strbuf);
1192  strcat(filebuf, g.strbuf);
1193  }
1194 
1195  int rv = write(fd, filebuf, fileLen + 1);
1196  if (rv == -1){
1197  sprintf(g.logbuf, "saveDoubleArray() Write to %s failed with error: %s\n", filename, strerror(errno));
1198  writeToLog(g.logbuf, "saveDoubleArray()");
1199  return -1;
1200  }
1201 
1202  fsync(fd);
1203 
1204  delete[] filebuf;
1205  close(fd);
1206  return 0;
1207 }
1208 
1220  struct stat buf;
1221 
1222  int rv = stat(f.arrayData_file, &buf); // stat() used only to check that there is an arrayData_file
1223  if (rv == -1){
1224  return 0;
1225  }
1226 
1227  int fd = open(f.arrayData_file, O_RDONLY);
1228  if (fd == -1){
1229  sprintf(g.logbuf, "processWriteRequest() Unable to open %s. Error: %s\n", f.arrayData_file, strerror(errno));
1230  writeToLog(g.logbuf, "processWriteRequest()");
1231  return -1;
1232  }
1233 
1234  char requestStr[25];
1235  char filename[225];
1236 
1237  filename[0] = '\0';
1238  rv = read(fd, g.strbuf, STRBUF_SZ-1);
1239  sscanf(g.strbuf, "%s %s", requestStr, filename);
1240 
1241  close(fd);
1242  remove(f.arrayData_file);
1243 
1244  int arrayLen = sizeof(arrayData) / sizeof(struct saveFileData);
1245  for (int i = 0; i < arrayLen; i++){
1246  if (strcmp(requestStr, arrayData[i].label) == 0){
1247  if (strlen(filename) == 0){
1248  strcpy(filename, arrayData[i].filename);
1249  }
1250  if (arrayData[i].arrayType == 2){
1251  saveDoubleArray((double *)arrayData[i].array, filename, arrayData[i].arrayLen, arrayData[i].arrayZero);
1252  break;
1253  }
1254  if (arrayData[i].arrayType == 3){
1255  writeFrequencyVars(filename);
1256  break;
1257  }
1258  if (arrayData[i].arrayType == 4){
1259  writeOffsets(filename);
1260  break;
1261  }
1262 
1263  }
1264  }
1265  return 0;
1266 }
1267 
1274 
1275  int rv = readConfigFile(config_file);
1276  if (rv == -1){
1277  return rv;
1278  }
1279 
1280  char *sp;
1281 
1282  sp = getString(RUNDIR);
1283  if (sp != NULL){
1284  strcpy(f.pidFilename, sp);
1285  strcat(f.pidFilename, pidFilename);
1286  }
1287 
1288  sp = getString(SHMDIR);
1289  if (sp != NULL){
1290  strcpy(f.assert_file, sp);
1291  strcat(f.assert_file, assert_file);
1292 
1293  strcpy(f.displayParams_file, sp);
1294  strcat(f.displayParams_file, displayParams_file);
1295 
1296  strcpy(f.arrayData_file, sp);
1297  strcat(f.arrayData_file, arrayData_file);
1298 
1299  strcpy(f.pps_msg_file, sp);
1300  strcat(f.pps_msg_file, pps_msg_file);
1301  }
1302 
1303  sp = getString(TSTDIR);
1304  if (sp != NULL){
1305  strcpy(f.last_distrib_file, sp);
1306  strcat(f.last_distrib_file, last_distrib_file);
1307 
1308  strcpy(f.distrib_file, sp);
1309  strcat(f.distrib_file, distrib_file);
1310 
1311  strcpy(f.last_jitter_distrib_file, sp);
1312  strcat(f.last_jitter_distrib_file, last_jitter_distrib_file);
1313 
1314  strcpy(f.home_file, sp);
1315  strcat(f.home_file, home_file);
1316  }
1317 
1318  sp = getString(LOGDIR);
1319  if (sp != NULL){
1320  strcpy(f.log_file, sp);
1321  strcat(f.log_file, log_file);
1322 
1323  strcpy(f.old_log_file, sp);
1324  strcat(f.old_log_file, old_log_file);
1325  }
1326 
1327  g.doNISTsettime = true;
1328 
1329  if (isEnabled(SERIAL)){
1330  g.doNISTsettime = false;
1331  g.doSerialsettime = true;
1332  }
1333  else if (isDisabled(SERIAL)){
1334  g.doSerialsettime = false;
1335  }
1336 
1337  sp = getString(SERIAL_PORT);
1338  if (sp != NULL){
1339  strcpy(g.serialPort, sp);
1340  }
1341 
1342  if (isEnabled(NIST)){
1343  g.doNISTsettime = true;
1344  }
1345  else if (isDisabled(NIST)){
1346  g.doNISTsettime = false;
1347  }
1348 
1349  return 0;
1350 }
1351 
1356 int getConfigs(void){
1357 
1358  // Activities that are checked each second ******************
1359 
1360  if (isEnabled(ERROR_DISTRIB)){
1361  if (writeErrorDistrib == false){
1362  memset(g.errorDistrib, 0, ERROR_DISTRIB_LEN * sizeof(int));
1363  g.errorCount = 0;
1364  writeErrorDistrib = true;
1365  }
1366  }
1367  else {
1368  writeErrorDistrib = false;
1369  }
1370 
1371  if (writeErrorDistrib){
1373  }
1374 
1375  if (isEnabled(JITTER_DISTRIB)){
1376  if (writeJitterDistrib == false){
1377  memset(g.jitterDistrib, 0, JITTER_DISTRIB_LEN * sizeof(int));
1378  g.jitterCount = 0;
1379  writeJitterDistrib = true;
1380  }
1381  }
1382  else {
1383  writeJitterDistrib = false;
1384  }
1385 
1386  if (writeJitterDistrib){
1388  }
1389 
1390  int rv = processWriteRequest();
1391  if (rv == -1){
1392  return rv;
1393  }
1394 
1395  //****************************************************************
1396 
1398  if (rv == -1){
1399  return rv;
1400  }
1401  if (rv == 1){ // Skip reading again if rv == 1
1402  return 0;
1403  }
1404 
1405  char *sp;
1406  struct stat dirStat;
1407 
1408  sp = getString(RUNDIR);
1409  if (sp != NULL){
1410 
1411  rv = stat(sp, &dirStat);
1412  if (rv == -1){
1413  printf("Invalid path for rundir. %s: %s\n", strerror(errno), sp);
1414  return rv;
1415  }
1416 
1417  strcpy(f.pidFilename, sp);
1418  strcat(f.pidFilename, pidFilename);
1419  }
1420 
1421  sp = getString(SHMDIR);
1422  if (sp != NULL){
1423 
1424  rv = stat(sp, &dirStat);
1425  if (rv == -1){
1426  printf("Invalid path for shmdir in pps-client.conf. %s: %s\n", strerror(errno), sp);
1427  return rv;
1428  }
1429 
1430  strcpy(f.assert_file, sp);
1431  strcat(f.assert_file, assert_file);
1432 
1433  strcpy(f.displayParams_file, sp);
1434  strcat(f.displayParams_file, displayParams_file);
1435 
1436  strcpy(f.arrayData_file, sp);
1437  strcat(f.arrayData_file, arrayData_file);
1438 
1439  strcpy(f.pps_msg_file, sp);
1440  strcat(f.pps_msg_file, pps_msg_file);
1441 
1442  strcpy(f.linuxVersion_file, sp);
1443  strcat(f.linuxVersion_file, linuxVersion_file);
1444 
1445  strcpy(f.gmtTime_file, sp);
1446  strcat(f.gmtTime_file, gmtTime_file);
1447 
1448  strcpy(f.nistTime_file, sp);
1449  strcat(f.nistTime_file, nistTime_file);
1450  }
1451 
1452  sp = getString(TSTDIR);
1453  if (sp != NULL){
1454 
1455  rv = stat(sp, &dirStat);
1456  if (rv == -1){
1457  printf("Invalid path for tstdir in pps-client.conf. %s: %s\n", strerror(errno), sp);
1458  return rv;
1459  }
1460 
1461  strcpy(f.last_distrib_file, sp);
1462  strcat(f.last_distrib_file, last_distrib_file);
1463 
1464  strcpy(f.distrib_file, sp);
1465  strcat(f.distrib_file, distrib_file);
1466 
1467  strcpy(f.last_jitter_distrib_file, sp);
1468  strcat(f.last_jitter_distrib_file, last_jitter_distrib_file);
1469 
1470  strcpy(f.jitter_distrib_file, sp);
1471  strcat(f.jitter_distrib_file, jitter_distrib_file);
1472 
1473  strcpy(f.home_file, sp);
1474  strcat(f.home_file, home_file);
1475  }
1476 
1477  sp = getString(LOGDIR);
1478  if (sp != NULL){
1479 
1480  rv = stat(sp, &dirStat);
1481  if (rv == -1){
1482  printf("Invalid path for logdir in pps-client.conf. %s: %s\n", strerror(errno), sp);
1483  return rv;
1484  }
1485 
1486  strcpy(f.log_file, sp);
1487  strcat(f.log_file, log_file);
1488 
1489  strcpy(f.old_log_file, sp);
1490  strcat(f.old_log_file, old_log_file);
1491  }
1492 
1493  sp = getString(PPSDEVICE);
1494  if (sp != NULL){
1495 
1496  rv = stat(sp, &dirStat);
1497  if (rv == -1){
1498  printf("Invalid path for ppsdevice in pps-client.conf. %s: %s\n", strerror(errno), sp);
1499  return rv;
1500  }
1501 
1502  strcpy(f.pps_device, sp);
1503  }
1504 
1505  sp = getString(PPSDELAY);
1506  if (sp != NULL){
1507  char *ptr;
1508  g.zeroOffset = (int)strtol(sp, &ptr, 10);
1509  }
1510 
1511  sp = getString(SEGREGATE);
1512  if (sp != NULL){
1513  rv = sscanf(sp, "%d/%d", &g.useCore, &g.nCores);
1514  if (rv != 2 || g.useCore >= g.nCores){
1515  printf("Invalid value for segregate in pps-client.conf\n");
1516  return -1;
1517  }
1518  }
1519 
1520  sp = getString(PPSPHASE);
1521  if (sp != NULL){
1522  char *ptr;
1523  g.ppsPhase = (int)strtol(sp, &ptr, 10);
1524  if(g.ppsPhase > 1){
1525  printf("Invalid value for ppsphase in pps-client.conf. Must be 0 or 1.\n");
1526  return -1;
1527  }
1528  }
1529 
1530  sp = getString(PROCDIR);
1531  if (sp != NULL){
1532 
1533  rv = stat(sp, &dirStat);
1534  if (rv == -1){
1535  printf("Invalid path for procdir in pps-client.conf. %s: %s\n", strerror(errno), sp);
1536  return rv;
1537  }
1538 
1539  strcpy(f.cpuinfo_file, sp);
1540  strcat(f.cpuinfo_file, cpuinfo_file);
1541  }
1542 
1543  g.doNISTsettime = true;
1544 
1545  if (isEnabled(NIST)){
1546  g.doNISTsettime = true;
1547  }
1548  else if (isDisabled(NIST)){
1549  g.doNISTsettime = false;
1550  }
1551 
1552  if (isEnabled(SERIAL)){
1553  g.doNISTsettime = false;
1554  g.doSerialsettime = true;
1555  }
1556  else if (isDisabled(SERIAL)){
1557  g.doSerialsettime = false;
1558  }
1559 
1560  sp = getString(SERIAL_PORT);
1561  if (sp != NULL){
1562  strcpy(g.serialPort, sp);
1563  }
1564 
1565  if (isEnabled(EXIT_LOST_PPS)){
1566  g.exitOnLostPPS = true;
1567  }
1568  else if (isDisabled(EXIT_LOST_PPS)){
1569  g.exitOnLostPPS = false;
1570  }
1571 
1572  return 0;
1573 }
1574 
1581 void writeTimestamp(double timestamp){
1582  memset(g.strbuf, 0, STRBUF_SZ-1);
1583 
1584  sprintf(g.strbuf, "%lf#%d\n", timestamp, g.seq_num);
1585  remove(f.assert_file);
1586 
1587  int pfd = open_logerr(f.assert_file, O_CREAT | O_WRONLY, "writeTimestamp() 1");
1588  if (pfd == -1){
1589  return;
1590  }
1591  int rv = write(pfd, g.strbuf, strlen(g.strbuf) + 1); // Write PPS timestamp to f.assert_file
1592  if (rv == -1){
1593  sprintf(g.logbuf, "writeTimestamp() write to assert_file failed with error: %s\n", strerror(errno));
1594  writeToLog(g.logbuf, "writeTimestamp() 2");
1595  }
1596  close(pfd);
1597 }
1598 
1613 int alignNumbersAfter(const char *token, char *buf, int len){
1614  int pos = 0;
1615 
1616  char *str = strstr(buf, token);
1617  if (str == NULL){
1618  sprintf(g.logbuf, "alignNumbersAfter(): token not found. Exiting.\n");
1619  writeToLog(g.logbuf, "alignNumbersAfter()");
1620  return -1;
1621  }
1622  str += strlen(token);
1623 
1624  pos = str - buf;
1625  if (buf[pos] != '-'){
1626  memmove(str + 1, str, len - pos);
1627  buf[pos] = ' ';
1628  len += 1;
1629  }
1630  return len;
1631 }
1632 
1654 int alignTokens(const char *refToken, int offset, const char *token, char *buf, int len){
1655 
1656  int pos1, pos2;
1657 
1658  char *str = strstr(buf, refToken);
1659  if (str == NULL){
1660  sprintf(g.logbuf, "alignTokens(): refToken not found. Exiting.\n");
1661  writeToLog(g.logbuf, "alignTokens()");
1662  return -1;
1663  }
1664  str += strlen(refToken);
1665  pos1 = str - buf;
1666 
1667  str = strstr(buf, token);
1668  if (str == NULL){
1669  sprintf(g.logbuf, "alignTokens(): token not found. Exiting.\n");
1670  writeToLog(g.logbuf, "alignTokens()");
1671  return -1;
1672  }
1673  pos2 = str - buf;
1674 
1675  while (pos2 < pos1 + offset){
1676  memmove(str + 1, str, len - pos2);
1677  buf[pos2] = ' ';
1678  pos2 += 1;
1679  str += 1;
1680  len += 1;
1681  }
1682  return len;
1683 }
1684 
1694 
1695  if (g.interruptLossCount == 0) {
1696  const char *timefmt = "%F %H:%M:%S";
1697  char timeStr[50];
1698  char printStr[200];
1699 
1700  memset(timeStr, 0, 50 * sizeof(char));
1701  strftime(timeStr, 50, timefmt, localtime(&g.pps_t_sec));
1702 
1703  char *printfmt = g.strbuf;
1704 
1705  strcpy(printfmt, "%s.%06d %d jitter: ");
1706 
1707  if (g.clampAbsolute){
1708  strcat(printfmt, "%d freqOffset: %f avgCorrection: %f clamp: %d\n");
1709  }
1710  else {
1711  strcat(printfmt, "%d freqOffset: %f avgCorrection: %f clamp: %d*\n");
1712  }
1713 
1714  sprintf(printStr, printfmt, timeStr, g.pps_t_usec, g.seq_num,
1715  g.jitter, g.freqOffset, g.avgCorrection, g.hardLimit);
1716 
1717  int len = strlen(printStr) + 1; // strlen + '\0'
1718  len = alignNumbersAfter("jitter: ", printStr, len);
1719  if (len == -1){
1720  return -1;
1721  }
1722  len = alignTokens("jitter:", 6, "freqOffset:", printStr, len);
1723  if (len == -1){
1724  return -1;
1725  }
1726  len = alignNumbersAfter("freqOffset:", printStr, len);
1727  if (len == -1){
1728  return -1;
1729  }
1730  len = alignTokens("freqOffset:", 12, "avgCorrection:", printStr, len);
1731  if (len == -1){
1732  return -1;
1733  }
1734  len = alignNumbersAfter("avgCorrection: ", printStr, len);
1735  if (len == -1){
1736  return -1;
1737  }
1738  len = alignTokens("avgCorrection:", 12, "clamp:", printStr, len);
1739  if (len == -1){
1740  return -1;
1741  }
1742 
1743  bufferStatusMsg(printStr);
1744  }
1745  return 0;
1746 }
1747 
1755 void removeConfigKeys(const char *key1, const char *key2, char *fbuf){
1756 
1757  char *pHead = NULL, *pTail = NULL, *pNxt = NULL;
1758  char *pLine = NULL;
1759 
1760  pLine = fbuf;
1761 
1762  while (strlen(pLine) > 0){
1763  // Search for key1 followed by key2
1764  while (pLine != NULL){ // If this is the next line
1765 
1766  pNxt = pLine;
1767  while (pNxt[0] == ' ' || pNxt[0] == '\t'){
1768  pNxt += 1;
1769  }
1770 
1771  if (strncmp(pNxt, key1, strlen(key1)) == 0){
1772  pHead = pNxt;
1773  pNxt += strlen(key1);
1774 
1775  while (pNxt[0] == ' ' || pNxt[0] == '\t'){
1776  pNxt += 1;
1777  }
1778 
1779  if (strncmp(pNxt, key2, strlen(key2)) == 0){
1780  pNxt += strlen(key2);
1781 
1782  while (pNxt[0] == ' ' || pNxt[0] == '\t' || pNxt[0] == '\n'){
1783  pNxt += 1;
1784  }
1785  pTail = pNxt;
1786 
1787  memmove(pHead, pTail, strlen(pTail)+1);
1788  pLine = pHead; // Point pLine to any remaining
1789  break; // tail of the file for removal
1790  } // of any more lines containing
1791  } // "key1 key2".
1792  pLine = strchr(pLine, '\n') + 1;
1793  }
1794  }
1795 }
1796 
1801 char *getLinuxVersion(void){
1802  int rv;
1803  char fbuf[20];
1804  char cmdbuf[100];
1805 
1806  memset(cmdbuf, 0, 100 * sizeof(char));
1807  strcpy(cmdbuf, "uname -r > ");
1808  strcat(cmdbuf, f.linuxVersion_file);
1809 
1810  rv = sysCommand(cmdbuf);
1811  if (rv == -1){
1812  return NULL;
1813  }
1814 
1815  int fd = open(f.linuxVersion_file, O_RDONLY);
1816  rv = read(fd, fbuf, 20);
1817  if (rv == -1){
1818  sprintf(g.logbuf, "getLinuxVersion(): Unable to read Linux version from %s\n", f.linuxVersion_file);
1819  writeToLog(g.logbuf, "getLinuxVersion()");
1820  return NULL;
1821  }
1822  sscanf(fbuf, "%s\n", g.linuxVersion);
1823  return g.linuxVersion;
1824 }
1825 
1826 
1834 int getRPiCPU(void){
1835  int rv;
1836 
1837  int fd = open_logerr(f.cpuinfo_file, O_RDONLY, "getRPiCPU()");
1838  if (fd == -1){
1839  printf("getRPiCPU() Open f.cpuinfo_file failed\n");
1840  return -1;
1841  }
1842 
1843  char *filebuf = new char[CONFIG_FILE_SZ];
1844  memset(filebuf, 0, CONFIG_FILE_SZ * sizeof(char));
1845 
1846  rv = read(fd, filebuf, CONFIG_FILE_SZ-1);
1847  if (rv == -1){
1848  sprintf(g.logbuf, "getRPiCPU(): Unable to read from %s\n", f.cpuinfo_file);
1849  writeToLog(g.logbuf, "getRPiCPU()");
1850  delete filebuf;
1851  return -1;
1852  }
1853 
1854  rv = 0;
1855 
1856  char *pstr = strstr(filebuf, "Raspberry Pi");
1857  if (pstr != NULL){
1858  if (strncmp(pstr, "Raspberry Pi 3", 14) == 0){
1859  rv = 3;
1860  }
1861  else if (strncmp(pstr, "Raspberry Pi 4", 14) == 0){
1862  rv = 4;
1863  }
1864  }
1865  delete filebuf;
1866  return rv;
1867 }
1868 
1878  int rv;
1879  char cmdstr[100];
1880  char cmd[100];
1881  int bitmask = 0;
1882  struct stat stat_buf;
1883 
1884  sprintf(cmdstr, "printf 'Assigned PPS-Client to processor %d\n'", g.useCore);
1885  sysCommand(cmdstr);
1886 
1887  for (int i = g.nCores - 1; i >= 0; i--){ // Create bitmask of cores to be used
1888  bitmask = bitmask << 1; // by all processes except PPS-Client
1889  if (g.useCore != i){
1890  bitmask |= 1;
1891  }
1892  }
1893 
1894  memset(cmd, 0, 100);
1895  sprintf(cmd,"taskset -p %d ", bitmask);
1896 
1897  const char *end = " > /dev/null 2>&1"; // "> /dev/null 2>&1" suppresses all messages
1898 
1899  rv = sysCommand("ps --no-headers -eo pid > /dev/shm/pid.txt"); // Save PIDs only of all running processes
1900  if (rv == -1){
1901  return rv;
1902  }
1903 
1904 
1905  int fd = open("/dev/shm/pid.txt", O_RDONLY); // Open the PID file
1906  if (fd == -1){
1907  return fd;
1908  }
1909 
1910  fstat(fd, &stat_buf);
1911  int sz = stat_buf.st_size;
1912 
1913  char *fbuf = new char[sz+1];
1914 
1915  rv = read(fd, fbuf, sz); // Read PID file into fbuf
1916 
1917  close(fd);
1918 
1919  if (rv == -1){
1920  delete fbuf;
1921  return rv;
1922  }
1923 
1924  char *pbuf = strtok(fbuf, "\n"); // Locate the first CR
1925 
1926  pbuf = strtok(NULL, "\n\0");
1927  memset(cmdstr, 0, 100);
1928  strcpy(cmdstr, cmd);
1929  strcat(cmdstr, fbuf);
1930  strcat(cmdstr, end);
1931 
1932  rv = sysCommand(cmdstr);
1933  if (rv == -1){
1934  delete fbuf;
1935  return rv;
1936  }
1937 
1938  while (pbuf != NULL){
1939  pbuf = strtok(NULL, "\n\0");
1940  if (pbuf != NULL){
1941 
1942  memset(cmdstr, 0, 100);
1943  strcpy(cmdstr, cmd);
1944  strcat(cmdstr, pbuf);
1945  strcat(cmdstr, end);
1946 
1947  rv = sysCommand(cmdstr); // Attempt to put each running processes on other cores
1948  if (rv == -1){
1949  delete fbuf;
1950  return rv;
1951  }
1952 
1953  }
1954  }
1955 
1956  bitmask = 0;
1957 
1958  for (int i = g.nCores - 1; i >= 0; i--){ // Create bitmask of core to be used
1959  bitmask = bitmask << 1; // by PPS-Client
1960  if (g.useCore == i){
1961  bitmask |= 1;
1962  }
1963  }
1964 
1965  memset(cmdstr, 0, 100);
1966  sprintf(cmdstr,"taskset -p %d `pidof pps-client` > /dev/null 2>&1", bitmask);
1967  sysCommand(cmdstr);
1968 
1969 // printf("\n");
1970 
1971  delete fbuf;
1972  return 0;
1973 }
1974 
1975 
1984 int getSeqNum(const char *pbuf){
1985 
1986  char *pSpc, *pNum;
1987  int seqNum = 0;
1988 
1989  pSpc = strpbrk((char *)pbuf, space);
1990 
1991  pNum = strpbrk(pSpc, num);
1992  pSpc = strpbrk(pNum, space);
1993  pNum = strpbrk(pSpc, num);
1994 
1995  sscanf(pNum, "%d ", &seqNum);
1996  return seqNum;
1997 }
1998 
2005  struct timeval tv1;
2006  struct timespec ts2;
2007  char paramsBuf[MSGBUF_SZ];
2008  struct stat stat_buf;
2009  int seqNum = 0, lastSeqNum = -1;
2010 
2011  if (g.doSerialsettime == true){
2012  printf("\nSerial port, %s, is providing time of day from GPS Satellites\n\n", g.serialPort);
2013  }
2014  else if (g.doNISTsettime == true){
2015  printf("\nNIST UDP time servers are providing time of day over the Internet\n\n");
2016  }
2017 
2018  int dispTime = 500000; // Display at half second
2019 
2020  gettimeofday(&tv1, NULL);
2021  ts2 = setSyncDelay(dispTime, tv1.tv_usec);
2022 
2023  for (;;){
2024 
2025  if (g.exit_loop){
2026  break;
2027  }
2028  nanosleep(&ts2, NULL);
2029 
2030  int fd = open(f.displayParams_file, O_RDONLY);
2031  if (fd == -1){
2032  printf("showStatusEachSecond(): Could not open f.displayParams_file");
2033  printf("%s", f.displayParams_file);
2034  printf("\n");
2035  }
2036  else {
2037  fstat(fd, &stat_buf);
2038  int sz = stat_buf.st_size;
2039 
2040  if (sz >= MSGBUF_SZ){
2041  printf("showStatusEachSecond() buffer too small. sz: %d\n", sz);
2042  close(fd);
2043  break;
2044  }
2045 
2046  int rv = read(fd, paramsBuf, sz);
2047  close(fd);
2048  if (rv == -1){
2049  printf("showStatusEachSecond() Read paramsBuf failed with error: %s\n", strerror(errno));
2050  break;
2051 
2052  }
2053 
2054  if (sz > 0){
2055 
2056  paramsBuf[sz]= '\0';
2057 
2058  char *sv = strstr(paramsBuf, "jitter");
2059  if (sv != NULL){ // Is a standard status line containing "jitter".
2060  seqNum = getSeqNum(paramsBuf);
2061 
2062  if (seqNum != lastSeqNum){
2063  printf("%s", paramsBuf);
2064  }
2065  }
2066  else { // Is informational or error message
2067  seqNum += 1;
2068 
2069  if (seqNum != lastSeqNum){
2070  printf("%s", paramsBuf);
2071  }
2072  }
2073  lastSeqNum = seqNum;
2074  }
2075  }
2076 
2077  gettimeofday(&tv1, NULL);
2078 
2079  ts2 = setSyncDelay(dispTime, tv1.tv_usec);
2080  }
2081  printf(" Exiting PPS-Client status display\n");
2082 }
2083 
2091 void INThandler(int sig){
2092  g.exit_loop = true;
2093 }
2094 
2106 bool missingArg(int argc, char *argv[], int i){
2107  if (i == argc - 1 || argv[i+1][0] == '-'){
2108  printf("Error: Missing argument for %s.\n", argv[i]);
2109  return true;
2110  }
2111  return false;
2112 }
2113 
2123 int daemonSaveArray(const char *requestStr, const char *filename){
2124  char buf[200];
2125 
2126  int fd = open_logerr(f.arrayData_file, O_CREAT | O_WRONLY | O_TRUNC, "daemonSaveArray()");
2127  if (fd == -1){
2128  printf("daemonSaveArray() Open f.arrayData_file failed\n");
2129  return -1;
2130  }
2131 
2132  strcpy(buf, requestStr);
2133 
2134  if (filename != NULL){
2135  strcat(buf, " ");
2136  strcat(buf, filename);
2137  }
2138 
2139  int rv = write(fd, buf, strlen(buf) + 1);
2140  close(fd);
2141  if (rv == -1){
2142  sprintf(g.logbuf, "daemonSaveArray() Write to tmpfs memory file failed\n");
2143  writeToLog(g.logbuf, "daemonSaveArray()");
2144  return -1;
2145  }
2146  return 0;
2147 }
2148 
2154  printf("Accepts any of these:\n");
2155  int arrayLen = sizeof(arrayData) / sizeof(struct saveFileData);
2156  for (int i = 0; i < arrayLen; i++){
2157  printf("%s\n", arrayData[i].label);
2158  }
2159 }
2160 
2172 int parseSaveDataRequest(int argc, char *argv[], const char *requestStr){
2173 
2174  int arrayLen = sizeof(arrayData) / sizeof(struct saveFileData);
2175 
2176  int i;
2177  for (i = 0; i < arrayLen; i++){
2178  if (strcmp(requestStr, arrayData[i].label) == 0){
2179  break;
2180  }
2181  }
2182  if (i == arrayLen){
2183  printf("Arg \"%s\" not recognized\n", argv[i+1]);
2185  return -1;
2186  }
2187 
2188  char *filename = NULL;
2189  for (int j = 1; j < argc; j++){
2190  if (strcmp(argv[j], "-f") == 0){
2191  if (missingArg(argc, argv, j)){
2192  printf("Requires a filename.\n");
2193  return -1;
2194  }
2195  strncpy(g.strbuf, argv[j+1], STRBUF_SZ-1);
2196  g.strbuf[strlen(argv[j+1])] = '\0';
2197  filename = g.strbuf;
2198  break;
2199  }
2200  }
2201 
2202  if (filename != NULL){
2203  printf("Writing to file: %s\n", filename);
2204  }
2205  else {
2206  for (i = 0; i < arrayLen; i++){
2207  if (strcmp(requestStr, arrayData[i].label) == 0){
2208  printf("Writing to default file: %s\n", arrayData[i].filename);
2209  }
2210  }
2211  }
2212 
2213  if (daemonSaveArray(requestStr, filename) == -1){
2214  return -1;
2215  }
2216  return 0;
2217 }
2218 
2238 int accessDaemon(int argc, char *argv[]){
2239  bool verbose = false;
2240 
2241  getSharedConfigs();
2242 
2243  if (! ppsIsRunning()){ // If not running,
2244  remove(f.pidFilename); // remove a zombie PID filename if one is found.
2245  return 1;
2246  }
2247 
2248  signal(SIGINT, INThandler); // Set handler to enable exiting with ctrl-c.
2249 
2250  printf("\nPPS-Client v%s is running.\n", version);
2251 
2252  if (argc > 1){
2253 
2254  for (int i = 1; i < argc; i++){
2255  if (strcmp(argv[i], "-v") == 0){
2256  verbose = true;
2257  }
2258  }
2259  for (int i = 1; i < argc; i++){
2260  if (strcmp(argv[i], "-s") == 0){ // This is a save data request.
2261  if (missingArg(argc, argv, i)){
2263  return -1;
2264  }
2265 
2266  if (parseSaveDataRequest(argc, argv, argv[i+1]) == -1){
2267  return -1;
2268  }
2269  break;
2270  }
2271  }
2272  }
2273 
2274  if (verbose){
2275  printf("Displaying second-by-second state params (ctrl-c to quit):\n");
2277  }
2278 
2279  return 0;
2280 }
2281 
2294 void buildErrorDistrib(int timeCorrection){
2295  int len = ERROR_DISTRIB_LEN - 1;
2296  int idx = timeCorrection + len / 6;
2297 
2298  if (idx < 0){
2299  idx = 0;
2300  }
2301  else if (idx > len){
2302  idx = len;
2303  }
2304  g.errorDistrib[idx] += 1;
2305 
2306  g.errorCount += 1;
2307 }
2308 
2316 void buildJitterDistrib(int rawError){
2317  int len = JITTER_DISTRIB_LEN - 1;
2318  int idx = rawError + len / 3;
2319 
2320  if (idx < 0){
2321  idx = 0;
2322  }
2323  else if (idx > len){
2324  idx = len;
2325  }
2326  g.jitterDistrib[idx] += 1;
2327 
2328  g.jitterCount += 1;
2329 }
2330 
2337 void TERMhandler(int sig){
2338  signal(SIGTERM, SIG_IGN);
2339  sprintf(g.logbuf,"Recieved SIGTERM\n");
2340  writeToLog(g.logbuf, "TERMhandler()");
2341  g.exit_requested = true;
2342  signal(SIGTERM, TERMhandler);
2343 }
2344 
2350 void HUPhandler(int sig){
2351  signal(SIGHUP, SIG_IGN);
2352 }
2353 
2367  timeval t;
2368  g.freqOffsetSum += g.freqOffset;
2369 
2370  g.freqOffsetDiff[g.intervalCount] = g.freqOffset - g.lastFreqOffset;
2371 
2372  g.lastFreqOffset = g.freqOffset;
2373  g.intervalCount += 1;
2374 
2375  if (g.intervalCount >= FIVE_MINUTES){
2376  gettimeofday(&t, NULL);
2377 
2378  double norm = 1.0 / (double)FREQDIFF_INTRVL;
2379 
2380  double diffSum = 0.0;
2381  for (int i = 0; i < FREQDIFF_INTRVL; i++){
2382  diffSum += g.freqOffsetDiff[i] * g.freqOffsetDiff[i];
2383  }
2384  g.freqAllanDev[g.recIndex] = sqrt(diffSum * norm * 0.5);
2385 
2386  g.timestampRec[g.recIndex] = t.tv_sec;
2387 
2388  g.freqOffsetRec[g.recIndex] = g.freqOffsetSum * norm;
2389 
2390  g.recIndex += 1;
2391  if (g.recIndex == NUM_5_MIN_INTERVALS){
2392  g.recIndex = 0;
2393  }
2394 
2395  g.intervalCount = 0;
2396  g.freqOffsetSum = 0.0;
2397  }
2398 }
2399 
2412 void recordOffsets(int timeCorrection){
2413 
2414  g.seq_numRec[g.recIndex2] = g.seq_num;
2415  g.offsetRec[g.recIndex2] = timeCorrection;
2416  g.freqOffsetRec2[g.recIndex2] = g.freqOffset;
2417 
2418  g.recIndex2 += 1;
2419  if (g.recIndex2 >= SECS_PER_10_MIN){
2420  g.recIndex2 = 0;
2421  }
2422 }
2423 
2433 int find_source(const char *path, pps_handle_t *handle, int *avail_mode)
2434 {
2435  pps_params_t params;
2436  int ret;
2437 
2438  /* Try to find the source by using the supplied "path" name */
2439  ret = open(path, O_RDWR);
2440 
2441  if (ret < 0) {
2442  sprintf(g.logbuf, "Unable to open device \"%s\" (%m)\n", path);
2443  fprintf(stderr, "%s", g.logbuf);
2444  writeToLog(g.logbuf, "find_source()");
2445  sprintf(g.logbuf, "Is the PPS driver enabled?\n");
2446  fprintf(stderr, "%s", g.logbuf);
2447  writeToLog(g.logbuf, "find_source()");
2448  return ret;
2449  }
2450 
2451  /* Open the PPS source (and check the file descriptor) */
2452  ret = time_pps_create(ret, handle);
2453  if (ret < 0) {
2454  sprintf(g.logbuf, "cannot create a PPS source from device "
2455  "\"%s\" (%m)\n", path);
2456  writeToLog(g.logbuf, "find_source()");
2457  return -1;
2458  }
2459 
2460  /* Find out what features are supported */
2461  ret = time_pps_getcap(*handle, avail_mode);
2462  if (ret < 0) {
2463  sprintf(g.logbuf, "cannot get capabilities (%m)\n");
2464  writeToLog(g.logbuf, "find_source()");
2465  return -1;
2466  }
2467  if ((*avail_mode & PPS_CAPTUREASSERT) == 0) {
2468  sprintf(g.logbuf, "cannot CAPTUREASSERT\n");
2469  writeToLog(g.logbuf, "find_source()");
2470  return -1;
2471  }
2472 
2473  /* Capture assert timestamps */
2474  ret = time_pps_getparams(*handle, &params);
2475  if (ret < 0) {
2476  sprintf(g.logbuf, "cannot get parameters (%m)\n");
2477  writeToLog(g.logbuf, "find_source()");
2478  return -1;
2479  }
2480  params.mode |= PPS_CAPTUREASSERT;
2481  /* Override any previous offset if possible */
2482  if ((*avail_mode & PPS_OFFSETASSERT) != 0) {
2483  params.mode |= PPS_OFFSETASSERT;
2484  params.assert_offset = offset_assert;
2485  }
2486  ret = time_pps_setparams(*handle, &params);
2487  if (ret < 0) {
2488  sprintf(g.logbuf, "cannot set parameters (%m)\n");
2489  writeToLog(g.logbuf, "find_source()");
2490  return -1;
2491  }
2492 
2493  return 0;
2494 }
2495 
2505 int readPPSTimestamp(pps_handle_t *handle, int *avail_mode, int *tm)
2506 {
2507  struct timespec timeout;
2508  pps_info_t infobuf;
2509  int ret;
2510 
2511  /* create a zero-valued timeout */
2512  timeout.tv_sec = 3;
2513  timeout.tv_nsec = 0;
2514 
2515 retry:
2516  if (*avail_mode & PPS_CANWAIT){ /* waits for the next event */
2517  ret = time_pps_fetch(*handle, PPS_TSFMT_TSPEC, &infobuf, &timeout);
2518  }
2519  else {
2520  sleep(1);
2521  ret = time_pps_fetch(*handle, PPS_TSFMT_TSPEC, &infobuf, &timeout);
2522  }
2523  if (ret < 0) {
2524  if (ret == -EINTR) {
2525  sprintf(g.logbuf, "readPPSTimestamp(): time_pps_fetch() got a signal!\n");
2526  writeToLog(g.logbuf, "readPPSTimestamp");
2527  goto retry;
2528  }
2529 
2530  return -1;
2531  }
2532 
2533  if (g.ppsPhase == 0){
2534  tm[0] = (int)infobuf.assert_timestamp.tv_sec;
2535  tm[1] = (int)(infobuf.assert_timestamp.tv_nsec / 1000);
2536  }
2537  else {
2538  tm[0] = (int)infobuf.clear_timestamp.tv_sec;
2539  tm[1] = (int)(infobuf.clear_timestamp.tv_nsec / 1000);
2540  }
2541 
2542  return 0;
2543 }
2544 
2545 int getRootHome(void){
2546  char buf[100];
2547  char cmdStr[100];
2548 
2549  memset(cmdStr, 0, 100);
2550  strcpy(cmdStr, "echo $HOME > ");
2551  strcat(cmdStr, f.home_file);
2552 
2553  sysCommand(cmdStr);
2554 
2555  int fd = open(f.home_file, O_RDONLY);
2556  if (fd == -1){
2557  sprintf(g.logbuf, "getRootHome(): Unable to open file %s\n", "./Home");
2558  writeToLog(g.logbuf, "getRootHome()");
2559  return -1;
2560  }
2561 
2562  memset(buf, 0, 100);
2563 
2564  int rv = read(fd, buf, 99);
2565  if (rv == -1){
2566  close(fd);
2567  return -1;
2568  }
2569  close(fd);
2570 
2571  char *pbuf = buf;
2572  while (*pbuf != '/'){
2573  pbuf += 1;
2574  }
2575 
2576  char *pbufEnd = pbuf;
2577  while(*pbufEnd != '\n'){
2578  pbufEnd += 1;
2579  }
2580  *pbufEnd = '\0';
2581 
2582  strcpy(f.integral_state_file, pbuf);
2583  strcat(f.integral_state_file, integral_state_file);
2584 
2585  remove(f.home_file);
2586 
2587  return 0;
2588 }
f
struct ppsFiles f
PPS-Client internal files.
Definition: pps-files.cpp:63
G::slewIsLow
bool slewIsLow
Set to "true" in getAcquireState() when G.avgSlew is less than SLEW_MAX. This is a precondition for g...
Definition: pps-client.h:214
writeJitterDistribFile
void writeJitterDistribFile(void)
Definition: pps-files.cpp:1090
G::rawErrorDistrib
double rawErrorDistrib[ERROR_DISTRIB_LEN]
The distribution of rawError values accumulated in buildRawErrorDistrib().
Definition: pps-client.h:203
G::integral
double integral[NUM_INTEGRALS]
Array of integrals constructed by makeAverageIntegral().
Definition: pps-client.h:229
OFFSETFIFO_LEN
#define OFFSETFIFO_LEN
Length of G.correctionFifo which contains the data used to generate G.avgCorrection.
Definition: pps-client.h:67
G::correctionAccum
int correctionAccum
Accumulates G.timeCorrection values from G.correctionFifo in getMovingAverage() in order to generate ...
Definition: pps-client.h:227
pps_params
Definition: timepps.h:53
writeJitterDistrib
bool writeJitterDistrib
Definition: pps-files.cpp:57
FIVE_MINUTES
#define FIVE_MINUTES
Definition: pps-client.h:54
HUPhandler
void HUPhandler(int sig)
Definition: pps-files.cpp:2350
couldNotOpenMsgTo
void couldNotOpenMsgTo(char *logbuf, const char *filename, const char *location)
Definition: pps-files.cpp:306
G::hardLimit
int hardLimit
An adaptive limit value determined by setHardLimit() and applied to G.rawError by clampJitter() as th...
Definition: pps-client.h:217
cpuinfo_file
const char * cpuinfo_file
Definition: pps-files.cpp:44
accessDaemon
int accessDaemon(int argc, char *argv[])
Definition: pps-files.cpp:2238
G::activeCount
unsigned int activeCount
Advancing count of active (not skipped) controller cycles once G.isControlling is "true".
Definition: pps-client.h:181
removeConfigKeys
void removeConfigKeys(const char *key1, const char *key2, char *fbuf)
Definition: pps-files.cpp:1755
recordFrequencyVars
void recordFrequencyVars(void)
Definition: pps-files.cpp:2366
isEnabled
bool isEnabled(int key)
Definition: pps-files.cpp:275
G::correctionFifoCount
int correctionFifoCount
Signals that G.correctionFifo contains a full count of G.timeCorrection values.
Definition: pps-client.h:226
ERROR_DISTRIB
#define ERROR_DISTRIB
Definition: pps-client.h:116
processWriteRequest
int processWriteRequest(void)
Definition: pps-files.cpp:1219
G::freqOffset
double freqOffset
System clock frequency correction calculated as G.integralTimeCorrection * G.integralGain.
Definition: pps-client.h:236
G::doNISTsettime
bool doNISTsettime
Definition: pps-client.h:238
NUM_INTEGRALS
#define NUM_INTEGRALS
Number of integrals used by makeAverageIntegral() to calculate the one minute clock frequency correct...
Definition: pps-client.h:68
SHMDIR
#define SHMDIR
Definition: pps-client.h:131
getSeqNum
int getSeqNum(const char *pbuf)
Definition: pps-files.cpp:1984
sysCommand
int sysCommand(const char *cmd)
Definition: pps-files.cpp:193
read_logerr
int read_logerr(int fd, char *buf, int sz, const char *filename)
Definition: pps-files.cpp:466
writeDistribution
void writeDistribution(int distrib[], int len, int scaleZero, int count, int *last_epoch, const char *distrib_file, const char *last_distrib_file)
Definition: pps-files.cpp:1055
writeToLog
void writeToLog(char *logbuf, const char *location)
Definition: pps-files.cpp:364
writeTimestamp
void writeTimestamp(double timestamp)
Definition: pps-files.cpp:1581
SETTLE_TIME
#define SETTLE_TIME
The PPS-Client up time required before saving performance data.
Definition: pps-client.h:56
G::interruptLossCount
int interruptLossCount
Records the number of consecutive lost PPS interrupt times.
Definition: pps-client.h:185
G::seq_num
unsigned int seq_num
Advancing count of the number of PPS interrupt timings that have been received.
Definition: pps-client.h:176
writeErrorDistribFile
void writeErrorDistribFile(void)
Definition: pps-files.cpp:1104
version
const char * version
Program v2.0.0 updated on 9 Jul 2020.
Definition: pps-client.cpp:53
find_source
int find_source(const char *path, pps_handle_t *handle, int *avail_mode)
Definition: pps-files.cpp:2433
displayParams_file
const char * displayParams_file
Temporary file storing params for the status display.
Definition: pps-files.cpp:36
pps_info
Definition: timepps.h:45
space
const char * space
Definition: pps-files.cpp:46
ADJTIMEX_SCALE
#define ADJTIMEX_SCALE
Frequency scaling required by adjtimex().
Definition: pps-client.h:71
G::ppsPhase
int ppsPhase
Accounts for a possible hardware inversion of the PPS signal.
Definition: pps-client.h:199
getString
char * getString(int key)
Definition: pps-files.cpp:212
G::integralTimeCorrection
double integralTimeCorrection
Integral or average integral of G.timeCorrection returned by getIntegral();.
Definition: pps-client.h:235
writeFrequencyVars
void writeFrequencyVars(const char *filename)
Definition: pps-files.cpp:1145
gmtTime_file
const char * gmtTime_file
Definition: pps-files.cpp:40
buildJitterDistrib
void buildJitterDistrib(int rawError)
Definition: pps-files.cpp:2316
getChildPID
pid_t getChildPID(void)
Definition: pps-files.cpp:804
num
const char * num
Definition: pps-files.cpp:47
assignProcessorAffinity
int assignProcessorAffinity(void)
Definition: pps-files.cpp:1877
G::correctionFifo_idx
int correctionFifo_idx
Advances G.correctionFifo on each controller cycle in integralIsReady() which returns "true" every 60...
Definition: pps-client.h:232
adjtimex
int adjtimex(struct timex *timex)
G::clampAbsolute
bool clampAbsolute
Hard limit relative to zero if true else relative to average G.rawError.
Definition: pps-client.h:218
ERROR_DISTRIB_LEN
#define ERROR_DISTRIB_LEN
Definition: pps-client.h:102
PPSDELAY
#define PPSDELAY
Definition: pps-client.h:134
arrayData
struct saveFileData arrayData[]
Definition: pps-files.cpp:297
writeFileMsgToLogbuf
int writeFileMsgToLogbuf(const char *filename, char *logbuf)
Definition: pps-files.cpp:750
G::integralCount
int integralCount
Counts the integrals formed over the last 10 controller cycles and signals when all integrals in G....
Definition: pps-client.h:231
errorReadingMsgTo
void errorReadingMsgTo(char *logbuf, const char *filename)
Definition: pps-files.cpp:319
distrib_file
const char * distrib_file
Stores a forming distribution of offset corrections.
Definition: pps-files.cpp:29
readPPSTimestamp
int readPPSTimestamp(pps_handle_t *handle, int *avail_mode, int *tm)
Definition: pps-files.cpp:2505
writeFileMsgToLog
int writeFileMsgToLog(const char *filename)
Definition: pps-files.cpp:794
getRPiCPU
int getRPiCPU(void)
Definition: pps-files.cpp:1834
pps_msg_file
const char * pps_msg_file
Definition: pps-files.cpp:38
getLinuxVersion
char * getLinuxVersion(void)
Definition: pps-files.cpp:1801
writeOffsets
void writeOffsets(const char *filename)
Definition: pps-files.cpp:1118
RAW_ERROR_ZERO
#define RAW_ERROR_ZERO
Index corresponding to rawError == 0 in buildRawErrorDistrib().
Definition: pps-client.h:73
g
struct G g
Declares the global variables defined in pps-client.h.
Definition: pps-client.cpp:55
jitter_distrib_file
const char * jitter_distrib_file
Stores a forming distribution of offset corrections.
Definition: pps-files.cpp:31
bufferStatusMsg
void bufferStatusMsg(const char *msg)
Definition: pps-files.cpp:407
arrayData_file
const char * arrayData_file
Stores a request sent to the PPS-Client daemon.
Definition: pps-files.cpp:37
createPIDfile
int createPIDfile(void)
Definition: pps-files.cpp:875
G::doSerialsettime
bool doSerialsettime
Definition: pps-client.h:242
FREQDIFF_INTRVL
#define FREQDIFF_INTRVL
The number of minutes between Allan deviation samples of system clock frequency correction.
Definition: pps-client.h:60
ppsIsRunning
bool ppsIsRunning(void)
Definition: pps-files.cpp:831
G::linuxVersion
char linuxVersion[20]
Array for recording the Linux version.
Definition: pps-client.h:246
valid_config
const char * valid_config[]
Definition: pps-files.cpp:74
last_jitter_distrib_file
const char * last_jitter_distrib_file
Stores the completed distribution of offset corrections.
Definition: pps-files.cpp:30
EXIT_LOST_PPS
#define EXIT_LOST_PPS
Definition: pps-client.h:119
isDisabled
bool isDisabled(int key)
Definition: pps-files.cpp:289
NUM_5_MIN_INTERVALS
#define NUM_5_MIN_INTERVALS
Number of five minute intervals in 24 hours.
Definition: pps-client.h:53
alignTokens
int alignTokens(const char *refToken, int offset, const char *token, char *buf, int len)
Definition: pps-files.cpp:1654
getRootHome
int getRootHome(void)
Definition: pps-files.cpp:2545
LOGBUF_SZ
#define LOGBUF_SZ
Definition: pps-client.h:96
STRBUF_SZ
#define STRBUF_SZ
Definition: pps-client.h:95
pps_handle_t
int pps_handle_t
Definition: timepps.h:60
JITTER_DISTRIB
#define JITTER_DISTRIB
Definition: pps-client.h:118
MAX_LINE_LEN
#define MAX_LINE_LEN
Definition: pps-client.h:94
G::t3
struct timex t3
Passes G.timeCorrection to the system function adjtimex() in makeTimeCorrection().
Definition: pps-client.h:222
G::zeroOffset
int zeroOffset
Definition: pps-client.h:196
alignNumbersAfter
int alignNumbersAfter(const char *token, char *buf, int len)
Definition: pps-files.cpp:1613
PPSPHASE
#define PPSPHASE
Definition: pps-client.h:137
SERIAL_PORT
#define SERIAL_PORT
Definition: pps-client.h:125
PROCDIR
#define PROCDIR
Definition: pps-client.h:138
getConfigs
int getConfigs(void)
Definition: pps-files.cpp:1356
missingArg
bool missingArg(int argc, char *argv[], int i)
Definition: pps-files.cpp:2106
LOGDIR
#define LOGDIR
Definition: pps-client.h:133
daemonSaveArray
int daemonSaveArray(const char *requestStr, const char *filename)
Definition: pps-files.cpp:2123
SECS_PER_10_MIN
#define SECS_PER_10_MIN
Definition: pps-client.h:50
MSGBUF_SZ
#define MSGBUF_SZ
Definition: pps-client.h:97
G::nCores
int nCores
If PPS-Client is segregated, identifies the number of processor cores.
Definition: pps-client.h:168
parseSaveDataRequest
int parseSaveDataRequest(int argc, char *argv[], const char *requestStr)
Definition: pps-files.cpp:2172
PPSDEVICE
#define PPSDEVICE
Definition: pps-client.h:136
TSTDIR
#define TSTDIR
Definition: pps-client.h:132
nistTime_file
const char * nistTime_file
Definition: pps-files.cpp:41
setSyncDelay
struct timespec setSyncDelay(int timeAt, int fracSec)
Definition: pps-client.cpp:1086
G::avgCorrection
double avgCorrection
A one-minute rolling average of G.timeCorrection values generated by getMovingAverage().
Definition: pps-client.h:224
JITTER_DISTRIB_LEN
#define JITTER_DISTRIB_LEN
Definition: pps-client.h:103
open_logerr
int open_logerr(const char *filename, int flags, const char *location)
Definition: pps-files.cpp:486
integral_state_file
const char * integral_state_file
Definition: pps-files.cpp:42
log_file
const char * log_file
Stores activity and errors.
Definition: pps-files.cpp:32
bufferStateParams
int bufferStateParams(void)
Definition: pps-files.cpp:1693
TERMhandler
void TERMhandler(int sig)
Definition: pps-files.cpp:2337
INThandler
void INThandler(int sig)
Definition: pps-files.cpp:2091
printAcceptedArgs
void printAcceptedArgs(void)
Definition: pps-files.cpp:2153
G::integralGain
double integralGain
Current controller integral gain.
Definition: pps-client.h:234
NIST
#define NIST
Definition: pps-client.h:123
recordOffsets
void recordOffsets(int timeCorrection)
Definition: pps-files.cpp:2412
SEGREGATE
#define SEGREGATE
Definition: pps-client.h:139
config_file
const char * config_file
The PPS-Client configuration file.
Definition: pps-files.cpp:27
pps_params::mode
int mode
Definition: timepps.h:55
writeErrorDistrib
bool writeErrorDistrib
Definition: pps-files.cpp:58
loadLastState
int loadLastState(void)
Definition: pps-files.cpp:610
G::configWasRead
bool configWasRead
True if pps-client.conf was read at least once.
Definition: pps-client.h:174
writeStatusStrings
int writeStatusStrings(void)
Definition: pps-files.cpp:435
buildErrorDistrib
void buildErrorDistrib(int timeCorrection)
Definition: pps-files.cpp:2294
hasString
bool hasString(int key, const char *string)
Definition: pps-files.cpp:253
assert_file
const char * assert_file
The timestamps of the time corrections each second.
Definition: pps-files.cpp:35
writeToLogNoTimestamp
void writeToLogNoTimestamp(char *logbuf)
Definition: pps-files.cpp:332
getSharedConfigs
int getSharedConfigs(void)
Definition: pps-files.cpp:1273
pidFilename
const char * pidFilename
Stores the PID of PPS-Client.
Definition: pps-files.cpp:34
saveDoubleArray
int saveDoubleArray(double distrib[], const char *filename, int len, int arrayZero)
Definition: pps-files.cpp:1177
CONFIG_FILE_SZ
#define CONFIG_FILE_SZ
Definition: pps-client.h:99
SERIAL
#define SERIAL
Definition: pps-client.h:124
G
Struct for program-wide global variables showing those important to the controller.
Definition: pps-client.h:167
RUNDIR
#define RUNDIR
Definition: pps-client.h:130
old_log_file
const char * old_log_file
Stores activity and errors.
Definition: pps-files.cpp:33
last_distrib_file
const char * last_distrib_file
Stores the completed distribution of offset corrections.
Definition: pps-files.cpp:28
SECS_PER_MINUTE
#define SECS_PER_MINUTE
Definition: pps-client.h:48
showStatusEachSecond
void showStatusEachSecond(void)
Definition: pps-files.cpp:2004
G::avgIntegral
double avgIntegral
One-minute average of the integrals in G.integral[].
Definition: pps-client.h:230
G::isControlling
bool isControlling
Set "true" by getAcquireState() when the control loop can begin to control the system clock frequency...
Definition: pps-client.h:180
G::correctionFifo
int correctionFifo[OFFSETFIFO_LEN]
Contains the G.timeCorrection values from over the previous 60 seconds.
Definition: pps-client.h:225
SECS_PER_DAY
#define SECS_PER_DAY
Definition: pps-client.h:52
saveLastState
int saveLastState(void)
Definition: pps-files.cpp:509
home_file
const char * home_file
Definition: pps-files.cpp:43
readConfigFile
int readConfigFile(const char *fconfig)
Definition: pps-files.cpp:922
G::isVerbose
bool isVerbose
Enables continuous printing of PPS-Client status params when "true".
Definition: pps-client.h:172
linuxVersion_file
const char * linuxVersion_file
Definition: pps-files.cpp:39
G::useCore
int useCore
If PPS-Client is segregated, the core on which it runs.
Definition: pps-client.h:169