PPS-Client  1.4.0
Client for synchronizing the system clock to a GPS PPS source
pps-files.cpp
Go to the documentation of this file.
1 
22 #include "../client/pps-client.h"
23 extern struct G g;
24 
25 const char *last_distrib_file = "/var/local/pps-error-distrib";
26 const char *distrib_file = "/var/local/pps-error-distrib-forming";
27 const char *last_jitter_distrib_file = "/var/local/pps-jitter-distrib";
28 const char *jitter_distrib_file = "/var/local/pps-jitter-distrib-forming";
29 const char *log_file = "/var/log/pps-client.log";
30 const char *old_log_file = "/var/log/pps-client.old.log";
31 const char *last_intrpt_distrib_file = "/var/local/pps-intrpt-distrib";
32 const char *intrpt_distrib_file = "/var/local/pps-intrpt-distrib-forming";
33 const char *sysDelay_distrib_file = "/var/local/pps-sysDelay-distrib-forming";
34 const char *last_sysDelay_distrib_file = "/var/local/pps-sysDelay-distrib";
35 const char *pidFilename = "/var/run/pps-client.pid";
36 
37 const char *config_file = "/etc/pps-client.conf";
38 const char *ntp_config_file = "/etc/ntp.conf";
39 const char *ntp_config_bac = "/etc/ntp.conf.bac";
40 const char *ntp_config_part = "/etc/ntp.conf.part";
41 
42 const char *sysDelay_file = "/run/shm/pps-sysDelay";
43 const char *assert_file = "/run/shm/pps-assert";
44 const char *displayParams_file = "/run/shm/pps-display-params";
45 const char *arrayData_file = "/run/shm/pps-save-data";
46 
47 const char *space = " ";
48 const char *num = "0123456789.";
49 
50 extern const char *version;
51 
55 static struct ppsFilesVars {
56  struct stat configFileStat;
57  time_t modifyTime;
58  int lastJitterFileno;
59  int lastSysDelayFileno;
60  int lastErrorFileno;
61  int lastIntrptFileno;
62  int lastIntrptJitterFileno;
63 } f;
64 
69 const char *valid_config[] = {
70  "error-distrib",
71  "alert-pps-lost",
72  "jitter-distrib",
73  "calibrate",
74  "interrupt-distrib",
75  "sysdelay-distrib",
76  "exit-lost-pps",
77  "pps-gpio",
78  "output-gpio",
79  "intrpt-gpio",
80  "sntp",
81  "serial",
82  "serialPort"
83 };
84 
85 void initFileLocalData(void){
86  memset(&f, 0, sizeof(struct ppsFilesVars));
87 }
88 
89 int sysCommand(const char *cmd){
90  int rv = system(cmd);
91  if (rv == -1 || WIFEXITED(rv) == false){
92  sprintf(g.logbuf, "System command failed: %s\n", cmd);
93  writeToLog(g.logbuf);
94  return -1;
95  }
96  return 0;
97 }
98 
108 char *getString(int key){
109  int i = round(log2(key));
110 
111  if (g.config_select & key){
112  return g.configVals[i];
113  }
114  return NULL;
115 }
116 
137 bool hasString(int key, const char *string){
138  int i = round(log2(key));
139 
140  if (g.config_select & key){
141  char *val = strstr(g.configVals[i], string);
142  if (val != NULL){
143  return true;
144  }
145  }
146  return false;
147 }
148 
159 bool isEnabled(int key){
160  return hasString(key, "enable");
161 }
162 
173 bool isDisabled(int key){
174  return hasString(key, "disable");
175 }
176 
181 struct saveFileData arrayData[] = {
182  {"rawError", g.rawErrorDistrib, "/var/local/pps-raw-error-distrib", ERROR_DISTRIB_LEN, 2, RAW_ERROR_ZERO},
183  {"intrptError", g.intrptErrorDistrib, "/var/local/pps-intrpt-error-distrib", ERROR_DISTRIB_LEN, 2, RAW_ERROR_ZERO},
184  {"frequency-vars", NULL, "/var/local/pps-frequency-vars", 0, 3, 0},
185  {"pps-offsets", NULL, "/var/local/pps-offsets", 0, 4, 0}
186 };
187 
191 void couldNotOpenMsgTo(char *logbuf, const char *filename){
192  strcpy(logbuf, "ERROR: could not open \"");
193  strcat(logbuf, filename);
194  strcat(logbuf, "\": ");
195  strcat(logbuf, strerror(errno));
196  strcat(logbuf, "\n");
197 }
198 
202 void errorReadingMsgTo(char *logbuf, const char *filename){
203  strcpy(logbuf, "ERROR: reading \"");
204  strcat(logbuf, filename);
205  strcat(logbuf, "\" was interrupted: ");
206  strcat(logbuf, strerror(errno));
207  strcat(logbuf, "\n");
208 }
209 
215 void writeToLogNoTimestamp(char *logbuf){
216  struct stat info;
217 
218  bufferStatusMsg(logbuf);
219 
220  stat(log_file, &info);
221  if (info.st_size > 100000){ // Prevent unbounded log file growth
222  remove(old_log_file);
223  rename(log_file, old_log_file);
224  }
225 
226  mode_t mode = S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH;
227  int fd = open(log_file, O_CREAT | O_WRONLY | O_APPEND, mode);
228  if (fd == -1){
229  couldNotOpenMsgTo(logbuf, log_file);
230  printf("%s", logbuf);
231  return;
232  }
233 
234  int rv = write(fd, logbuf, strlen(logbuf));
235  if (rv == -1){
236  ;
237  }
238  close(fd);
239 }
240 
241 
247 void writeToLog(char *logbuf){
248  struct stat info;
249 
250  bufferStatusMsg(logbuf);
251 
252  stat(log_file, &info);
253  if (info.st_size > 100000){ // Prevent unbounded log file growth
254  remove(old_log_file);
255  rename(log_file, old_log_file);
256  }
257 
258  mode_t mode = S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH;
259  int fd = open(log_file, O_CREAT | O_WRONLY | O_APPEND, mode);
260  if (fd == -1){
261  couldNotOpenMsgTo(logbuf, log_file);
262  printf("%s", logbuf);
263  return;
264  }
265 
266  time_t t = time(NULL);
267  struct tm *tmp = localtime(&t);
268  strftime(g.strbuf, STRBUF_SZ, "%F %H:%M:%S ", tmp);
269  int rv = write(fd, g.strbuf, strlen(g.strbuf));
270  if (rv == -1){
271  ;
272  }
273 
274  rv = write(fd, logbuf, strlen(logbuf));
275  if (rv == -1){
276  ;
277  }
278  close(fd);
279 }
280 
290 void bufferStatusMsg(const char *msg){
291 
292  if (g.isVerbose){
293  fprintf(stdout, "%s", msg);
294  }
295 
296  int msglen = strlen(g.savebuf);
297  int parmslen = strlen(msg);
298 
299  if (msglen + parmslen > MSGBUF_SZ){
300  return;
301  }
302 
303  strcat(g.savebuf, msg);
304 }
305 
317 
318  int fSize = strlen(g.savebuf);
319 
320  remove(displayParams_file);
321  int fd = open_logerr(displayParams_file, O_CREAT | O_WRONLY);
322  if (fd == -1){
323  return -1;
324  }
325  int rv = write(fd, g.savebuf, fSize);
326  close(fd);
327  if (rv == -1){
328  sprintf(g.logbuf, "writeStatusStrings() Could not write to %s. Error: %s\n", displayParams_file, strerror(errno));
329  writeToLog(g.logbuf);
330  return -1;
331  }
332 
333  g.savebuf[0] = '\0';
334  return 0;
335 }
336 
347 int read_logerr(int fd, char *buf, int sz, const char *filename){
348  int rv = read(fd, buf, sz);
349  if (rv == -1){
350  errorReadingMsgTo(g.logbuf, filename);
351  writeToLog(g.logbuf);
352  return rv;
353  }
354  return rv;
355 }
356 
366 int open_logerr(const char* filename, int flags){
367  int mode = S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH;
368  int fd;
369  if ((flags & O_CREAT) == O_CREAT){
370  fd = open(filename, flags, mode);
371  }
372  else {
373  fd = open(filename, flags);
374  }
375  if (fd == -1){
376  couldNotOpenMsgTo(g.logbuf, filename);
377  writeToLog(g.logbuf);
378  return -1;
379  }
380  return fd;
381 }
382 
393 int writeFileMsgToLogbuf(const char *filename, char *logbuf){
394  struct stat stat_buf;
395  int rv;
396 
397  int fd = open(filename, O_RDONLY);
398  if (fd == -1){
399  couldNotOpenMsgTo(logbuf, filename);
400  printf("%s", logbuf);
401  return -1;
402  }
403  fstat(fd, &stat_buf);
404  int sz = stat_buf.st_size;
405 
406  if (sz >= LOGBUF_SZ-1){
407  rv = read(fd, logbuf, LOGBUF_SZ-1);
408  if (rv == -1){
409  errorReadingMsgTo(logbuf, filename);
410  printf("%s", logbuf);
411  return rv;
412  }
413  logbuf[LOGBUF_SZ-1] = '\0';
414  }
415  else {
416  rv = read(fd, logbuf, sz);
417  if (rv == -1){
418  errorReadingMsgTo(logbuf, filename);
419  printf("%s", logbuf);
420  return rv;
421  }
422  logbuf[sz] = '\0';
423  }
424  close(fd);
425  remove(filename);
426 
427  return 0;
428 }
429 
437 int writeFileMsgToLog(const char *filename){
438  return writeFileMsgToLogbuf(filename, g.logbuf);
439 }
440 
447 pid_t getChildPID(void){
448  pid_t pid = 0;
449  const char *filename = "/var/run/pps-client.pid";
450 
451  memset(g.strbuf, 0, STRBUF_SZ);
452 
453  int pfd = open_logerr(filename, O_RDONLY);
454  if (pfd == -1){
455  return -1;
456  }
457  if (read_logerr(pfd, g.strbuf, 19, filename) == -1){
458  close(pfd);
459  return -1;
460  }
461  sscanf(g.strbuf, "%d\n", &pid);
462  close(pfd);
463  if (pid > 0){
464  return pid;
465  }
466  return -1;
467 }
468 
475 bool ppsIsRunning(void){
476  char buf[50];
477  const char *filename = "/run/shm/pps-msg";
478 
479  int rv = sysCommand("pidof pps-client > /run/shm/pps-msg");
480  if (rv == -1){
481  return false;
482  }
483 
484  int fd = open(filename, O_RDONLY);
485  if (fd == -1){
486  sprintf(g.logbuf, "ppsIsRunning() Failed. Could not open %s. Error: %s\n", filename, strerror(errno));
487  writeToLog(g.logbuf);
488  return false;
489  }
490  memset(buf, 0, 50);
491  rv = read(fd, buf, 50);
492  if (rv == -1){
493  sprintf(g.logbuf, "ppsIsRunning() Failed. Could not read %s. Error: %s\n", filename, strerror(errno));
494  writeToLog(g.logbuf);
495  return false;
496  }
497 
498  int callerPID = 0, daemonPID = 0; // If running both of these exist
499  sscanf(buf, "%d %d\n", &callerPID, &daemonPID);
500 
501  close(fd);
502  remove(filename);
503 
504  if (daemonPID == 0){ // Otherwise only the first exists.
505  return false;
506  }
507  return true;
508 }
509 
515 int createPIDfile(void){
516 
517  int pfd = open_logerr(pidFilename, O_RDWR | O_CREAT | O_EXCL);
518  if (pfd == -1){
519  return -1;
520  }
521 
522  pid_t ppid = getpid();
523 
524  sprintf(g.strbuf, "%d\n", ppid);
525  if (write(pfd, g.strbuf, strlen(g.strbuf)) == -1) // Try to write the PID
526  {
527  close(pfd);
528  sprintf(g.logbuf, "createPIDfile() Could not write a PID file. Error: %s\n", strerror(errno));
529  writeToLog(g.logbuf);
530  return -1; // Write failed.
531  }
532  close(pfd);
533 
534  return ppid;
535 }
536 
550 bool configHasValue(int config_val, void *value){
551  int i = round(log2(config_val));
552  if (g.config_select & config_val){
553  char *val = strpbrk(g.configVals[i], num);
554  if (strpbrk(val, ".") != NULL){
555  sscanf(val, "%lf", (double *)value);
556  }
557  else {
558  sscanf(val, "%d", (int *)value);
559  }
560  return true;
561  }
562  return false;
563 }
564 
576 
577  int value;
578  int rv = 0;
579 
580  rv = readConfigFile();
581  if (rv == -1){
582  goto err_end;
583  }
584 
585  if (configHasValue(PPS_GPIO, &value)){
586  g.ppsGPIO = value;
587  }
588  else {
589  goto err_end;
590  }
591 
592  if (configHasValue(OUTPUT_GPIO, &value)){
593  g.outputGPIO = value;
594  }
595  else {
596  goto err_end;
597  }
598 
599  if (configHasValue(INTRPT_GPIO, &value)){
600  g.intrptGPIO = value;
601  }
602  else {
603  goto err_end;
604  }
605 
606  return rv;
607 
608 err_end:
609  return -1;
610 }
611 
626 int readConfigFile(void){
627 
628  struct stat stat_buf;
629 
630  int rvs = stat(config_file, &f.configFileStat);
631  if (rvs == -1){
632  sprintf(g.logbuf, "readConfigFile(): Config file not found.\n");
633  writeToLog(g.logbuf);
634  return -1; // No config file
635  }
636 
637  timespec t = f.configFileStat.st_mtim;
638 
639  if (g.configWasRead && g.seq_num > 0 && f.modifyTime == t.tv_sec){
640  return 0; // Config file unchanged from last read
641  }
642 
643  f.modifyTime = t.tv_sec;
644 
645  int fd = open_logerr(config_file, O_RDONLY);
646  if (fd == -1){
647  return -1;
648  }
649 
650  fstat(fd, &stat_buf);
651  int sz = stat_buf.st_size;
652 
653  if (sz >= CONFIG_FILE_SZ){
654  sprintf(g.logbuf, "readConfigFile(): not enough space allocated for config file.\n");
655  writeToLog(g.logbuf);
656  return -1;
657  }
658 
659  int rv = read_logerr(fd, g.configBuf, sz, config_file);
660  if (rv == -1 || sz != rv){
661  return -1;
662  }
663  close(fd);
664 
665  g.configBuf[sz] = '\0';
666 
667  int nCfgStrs = 0;
668  int i;
669 
670  char *pToken = strtok(g.configBuf, "\n"); // Separate tokens at "\n".
671 
672  while (pToken != NULL){
673  if (strlen(pToken) != 0){ // If not a blank line.
674  for (int j = 0; j < 10; j++){ // Skip leading spaces.
675  if (pToken[0] == ' '){
676  pToken += 1;
677  }
678  else {
679  break; // Break on first non-space character.
680  }
681  }
682 
683  if (pToken[0] != '#'){ // Ignore comment lines.
684  g.configVals[nCfgStrs] = pToken;
685  nCfgStrs += 1;
686  }
687  }
688  pToken = strtok(NULL, "\n"); // Get the next token.
689  }
690 
691  if (nCfgStrs == 0){
692  return 0;
693  }
694 
695  for (i = 0; i < nCfgStrs; i++){ // Compact g.configBuf to remove string terminators inserted by
696  if (i == 0){ // strtok() so that g.configBuf can be searched as a single string.
697  strcpy(g.configBuf, g.configVals[i]);
698  }
699  else {
700  strcat(g.configBuf, g.configVals[i]);
701  }
702  strcat(g.configBuf, "\n");
703  }
704 
705  int nValidCnfgs = sizeof(valid_config) / sizeof(char *);
706 
707  char **configVal = g.configVals; // Use g.configVals to return pointers to value strings
708  char *value;
709 
710  for (i = 0; i < nValidCnfgs; i++){
711 
712  char *found = strstr(g.configBuf, valid_config[i]);
713  if (found != NULL){
714  g.config_select |= 1 << i; // Set a bit in config_select
715 
716  value = strpbrk(found, "="); // Get the value string following '='.
717  value += 1;
718 
719  configVal[i] = value; // Point to g.configVals[i] value string in g.configBuf
720  }
721  else {
722  g.config_select &= ~(1 << i); // Clear a bit in config_select
723  configVal[i] = NULL;
724  }
725  }
726 
727  for (i = 0; i < nValidCnfgs; i++){ // Replace the "\n" at the end of each value
728  if (configVal[i] != NULL){ // string with a string terminator.
729  value = strpbrk(configVal[i], "\n");
730  if (value != NULL){
731  *value = 0;
732  }
733  }
734  }
735 
736  if (g.seq_num > 0){
737  g.configWasRead = true; // Insures that config file read at least once.
738  }
739 
740  return 0;
741 }
742 
759 void writeDistribution(int distrib[], int len, int scaleZero, int count,
760  int *last_epoch, const char *distrib_file, const char *last_distrib_file){
761  int rv = 0;
762  remove(distrib_file);
763  int fd = open_logerr(distrib_file, O_CREAT | O_WRONLY | O_APPEND);
764  if (fd == -1){
765  return;
766  }
767  for (int i = 0; i < len; i++){
768  sprintf(g.strbuf, "%d %d\n", i-scaleZero, distrib[i]);
769  rv = write(fd, g.strbuf, strlen(g.strbuf));
770  if (rv == -1){
771  sprintf(g.logbuf, "writeDistribution() Unable to write to %s. Error: %s\n", distrib_file, strerror(errno));
772  writeToLog(g.logbuf);
773  close(fd);
774  return;
775  }
776  }
777  close(fd);
778 
779  int epoch = count / SECS_PER_DAY;
780  if (epoch != *last_epoch ){
781  *last_epoch = epoch;
782  remove(last_distrib_file);
784  memset(distrib, 0, len * sizeof(int));
785  }
786 }
787 
810 void writeMultipleDistrib(int label[], int distrib[][INTRPT_DISTRIB_LEN], int len, int scaleZero, int count,
811  int *last_epoch, const char *distrib_file, const char *last_distrib_file){
812  int rv;
813 
814  remove(distrib_file);
815  int fd = open_logerr(distrib_file, O_CREAT | O_WRONLY | O_APPEND);
816  if (fd == -1){
817  return;
818  }
819 
820  int totals[NUM_PARAMS] = {0};
821  for (int i = 0; i < INTRPT_DISTRIB_LEN; i++){
822  for (int j = 0; j < NUM_PARAMS; j++){
823  totals[j] += distrib[j][i];
824  }
825  }
826 
827  sprintf(g.strbuf, "%s %d %d %d %d %d\n", "sysDelay:", label[0], label[1], label[2], label[3], label[4]);
828  rv = write(fd, g.strbuf, strlen(g.strbuf));
829  if (rv == -1){
830  sprintf(g.logbuf, "writeMultipleDistrib() Unable to write to %s. Error: %s\n", distrib_file, strerror(errno));
831  writeToLog(g.logbuf);
832  close(fd);
833  return;
834  }
835 
836  sprintf(g.strbuf, "%s %d %d %d %d %d\n", "totals:", totals[0], totals[1], totals[2], totals[3], totals[4]);
837  rv = write(fd, g.strbuf, strlen(g.strbuf));
838  if (rv == -1){
839  sprintf(g.logbuf, "writeMultipleDistrib() Unable to write to %s. Error: %s\n", distrib_file, strerror(errno));
840  writeToLog(g.logbuf);
841  close(fd);
842  return;
843  }
844 
845  for (int i = 0; i < len; i++){
846  sprintf(g.strbuf, "%d %d %d %d %d %d\n", i-scaleZero, distrib[0][i], distrib[1][i], distrib[2][i], distrib[3][i], distrib[4][i]);
847  rv = write(fd, g.strbuf, strlen(g.strbuf));
848  if (rv == -1){
849  sprintf(g.logbuf, "writeMultipleDistrib() Unable to write to %s. Error: %s\n", distrib_file, strerror(errno));
850  writeToLog(g.logbuf);
851  close(fd);
852  return;
853  }
854  }
855  close(fd);
856 
857  int epoch = count / SECS_PER_DAY;
858  if (epoch != *last_epoch ){
859  *last_epoch = epoch;
860  remove(last_distrib_file);
862  for (int i = 0; i < NUM_PARAMS; i++){
863  memset(distrib[i], 0, len * sizeof(int));
864  }
865 
866  }
867 }
868 
879  if (g.interruptCount % SECS_PER_MINUTE == 0 && g.seq_num > SETTLE_TIME){
880  writeMultipleDistrib(g.delayLabel, g.intrptDistrib, INTRPT_DISTRIB_LEN, 0, g.interruptCount,
881  &f.lastIntrptFileno, intrpt_distrib_file, last_intrpt_distrib_file);
882  }
883 }
884 
891  if (g.sysDelayCount % SECS_PER_MINUTE == 0 && g.seq_num > SETTLE_TIME && g.hardLimit == HARD_LIMIT_1){
892  writeDistribution(g.sysDelayDistrib, INTRPT_DISTRIB_LEN, 0, g.sysDelayCount,
893  &f.lastSysDelayFileno, sysDelay_distrib_file, last_sysDelay_distrib_file);
894  }
895 }
896 
904  if (g.jitterCount % SECS_PER_MINUTE == 0 && g.seq_num > SETTLE_TIME){
905  int scaleZero = JITTER_DISTRIB_LEN / 6;
906  writeDistribution(g.jitterDistrib, JITTER_DISTRIB_LEN, scaleZero, g.jitterCount,
907  &f.lastJitterFileno, jitter_distrib_file, last_jitter_distrib_file);
908  }
909 }
910 
918  if (g.errorCount % SECS_PER_MINUTE == 0 && g.seq_num > SETTLE_TIME){
919  int scaleZero = ERROR_DISTRIB_LEN / 6;
920  writeDistribution(g.errorDistrib, ERROR_DISTRIB_LEN, scaleZero,
921  g.errorCount, &f.lastErrorFileno, distrib_file, last_distrib_file);
922  }
923 }
924 
931 void writeOffsets(const char *filename){
932  int fd = open_logerr(filename, O_CREAT | O_WRONLY | O_TRUNC);
933  if (fd == -1){
934  return;
935  }
936  for (int i = 0; i < SECS_PER_10_MIN; i++){
937  int j = g.recIndex2 + i;
938  if (j >= SECS_PER_10_MIN){
939  j -= SECS_PER_10_MIN;
940  }
941  sprintf(g.strbuf, "%d %d %lf\n", g.seq_numRec[j], g.offsetRec[j], g.freqOffsetRec2[j]);
942  int rv = write(fd, g.strbuf, strlen(g.strbuf));
943  if (rv == -1){
944  sprintf(g.logbuf, "writeOffsets() Unable to write to %s. Error: %s\n", filename, strerror(errno));
945  writeToLog(g.logbuf);
946  }
947  }
948  close(fd);
949 }
950 
958 void writeFrequencyVars(const char *filename){
959  int fd = open_logerr(filename, O_CREAT | O_WRONLY | O_TRUNC);
960  if (fd == -1){
961  return;
962  }
963  for (int i = 0; i < NUM_5_MIN_INTERVALS; i++){
964  int j = g.recIndex + i; // Read the circular buffers relative to g.recIndx.
965  if (j >= NUM_5_MIN_INTERVALS){
966  j -= NUM_5_MIN_INTERVALS;
967  }
968  sprintf(g.strbuf, "%ld %lf %lf\n", g.timestampRec[j], g.freqOffsetRec[j], g.freqAllanDev[j]);
969  int rv = write(fd, g.strbuf, strlen(g.strbuf));
970  if (rv == -1){
971  sprintf(g.logbuf, "writeFrequencyVars() Write to %s failed with error: %s\n", filename, strerror(errno));
972  writeToLog(g.logbuf);
973  close(fd);
974  return;
975  }
976  }
977  close(fd);
978 }
979 
980 
991 int saveDoubleArray(double distrib[], const char *filename, int len, int arrayZero){
992 
993  int fd = open_logerr(filename, O_CREAT | O_WRONLY | O_TRUNC);
994  if (fd == -1){
995  return -1;
996  }
997 
998  int fileMaxLen = len * MAX_LINE_LEN * sizeof(char);
999  char *filebuf = new char[fileMaxLen];
1000  int fileLen = 0;
1001 
1002  filebuf[0] = '\0';
1003  for (int i = 0; i < len; i++){
1004  sprintf(g.strbuf, "%d %7.2lf\n", i - arrayZero, distrib[i]);
1005  fileLen += strlen(g.strbuf);
1006  strcat(filebuf, g.strbuf);
1007  }
1008 
1009  int rv = write(fd, filebuf, fileLen + 1);
1010  if (rv == -1){
1011  sprintf(g.logbuf, "saveDoubleArray() Write to %s failed with error: %s\n", filename, strerror(errno));
1012  writeToLog(g.logbuf);
1013  return -1;
1014  }
1015 
1016  fsync(fd);
1017 
1018  delete[] filebuf;
1019  close(fd);
1020  return 0;
1021 }
1022 
1034  struct stat buf;
1035 
1036  int rv = stat(arrayData_file, &buf); // stat() used only to check that there is an arrayData_file
1037  if (rv == -1){
1038  return 0;
1039  }
1040 
1041  int fd = open(arrayData_file, O_RDONLY);
1042  if (fd == -1){
1043  sprintf(g.logbuf, "processWriteRequest() Unable to open %s. Error: %s\n", arrayData_file, strerror(errno));
1044  writeToLog(g.logbuf);
1045  return -1;
1046  }
1047 
1048  char requestStr[25];
1049  char filename[225];
1050 
1051  filename[0] = '\0';
1052  rv = read(fd, g.strbuf, STRBUF_SZ);
1053  sscanf(g.strbuf, "%s %s", requestStr, filename);
1054 
1055  close(fd);
1056  remove(arrayData_file);
1057 
1058  int arrayLen = sizeof(arrayData) / sizeof(struct saveFileData);
1059  for (int i = 0; i < arrayLen; i++){
1060  if (strcmp(requestStr, arrayData[i].label) == 0){
1061  if (strlen(filename) == 0){
1062  strcpy(filename, arrayData[i].filename);
1063  }
1064  if (arrayData[i].arrayType == 2){
1065  saveDoubleArray((double *)arrayData[i].array, filename, arrayData[i].arrayLen, arrayData[i].arrayZero);
1066  break;
1067  }
1068  if (arrayData[i].arrayType == 3){
1069  writeFrequencyVars(filename);
1070  break;
1071  }
1072  if (arrayData[i].arrayType == 4){
1073  writeOffsets(filename);
1074  break;
1075  }
1076 
1077  }
1078  }
1079  return 0;
1080 }
1081 
1086 int processFiles(void){
1087 
1088  int rv = readConfigFile();
1089  if (rv == -1){
1090  return rv;
1091  }
1092 
1093  if (isEnabled(ERROR_DISTRIB)){
1095  }
1096 
1097  if (isEnabled(JITTER_DISTRIB)){
1099  }
1100 
1101  if (isEnabled(CALIBRATE)){
1102  g.doCalibration = true;
1103  }
1104  else if (isDisabled(CALIBRATE)){
1105  g.doCalibration = false;
1106  }
1107 
1108  if (isEnabled(EXIT_LOST_PPS)){
1109  g.exitOnLostPPS = true;
1110  }
1111  else if (isDisabled(EXIT_LOST_PPS)){
1112  g.exitOnLostPPS = false;
1113  }
1114 
1115  if (g.doCalibration && isEnabled(INTERRUPT_DISTRIB)){
1117  }
1118 
1119  if (g.doCalibration && isEnabled(SYSDELAY_DISTRIB)){
1121  }
1122 
1123  if (isEnabled(SNTP)){
1124  g.doNTPsettime = true;
1125  }
1126  else if (isDisabled(SNTP)){
1127  g.doNTPsettime = false;
1128  }
1129 
1130  if (isEnabled(SERIAL)){
1131  g.doNTPsettime = false;
1132  g.doSerialsettime = true;
1133  }
1134  else if (isDisabled(SERIAL)){
1135  g.doSerialsettime = false;
1136  }
1137 
1138  char *sp = getString(SERIAL_PORT);
1139  if (sp != NULL){
1140  strcpy(g.serialPort, sp);
1141  }
1142 
1143  rv = processWriteRequest();
1144  if (rv == -1){
1145  return rv;
1146  }
1147 
1148  return 0;
1149 }
1150 
1157 void writeSysDelay(void){
1158  memset(g.strbuf, 0, STRBUF_SZ);
1159  sprintf(g.strbuf, "%d#%d\n", g.sysDelay + g.sysDelayShift, g.seq_num);
1160  remove(sysDelay_file);
1161  int pfd = open_logerr(sysDelay_file, O_CREAT | O_WRONLY);
1162  if (pfd == -1){
1163  return;
1164  }
1165  int rv = write(pfd, g.strbuf, strlen(g.strbuf) + 1); // Write PPS sysDelay to sysDelay_file
1166  if (rv == -1){
1167  sprintf(g.logbuf, "writeSysDelay() Write to memory file failed with error: %s\n", strerror(errno));
1168  writeToLog(g.logbuf);
1169  }
1170  close(pfd);
1171 }
1172 
1179 void writeTimestamp(double timestamp){
1180  memset(g.strbuf, 0, STRBUF_SZ);
1181 
1182  sprintf(g.strbuf, "%lf#%d\n", timestamp, g.seq_num);
1183  remove(assert_file);
1184 
1185  int pfd = open_logerr(assert_file, O_CREAT | O_WRONLY);
1186  if (pfd == -1){
1187  return;
1188  }
1189  int rv = write(pfd, g.strbuf, strlen(g.strbuf) + 1); // Write PPS timestamp to assert_file
1190  if (rv == -1){
1191  sprintf(g.logbuf, "writeTimestamp() write to assert_file failed with error: %s\n", strerror(errno));
1192  writeToLog(g.logbuf);
1193  }
1194  close(pfd);
1195 }
1196 
1211 int alignNumbersAfter(const char *token, char *buf, int len){
1212  int pos = 0;
1213 
1214  char *str = strstr(buf, token);
1215  if (str == NULL){
1216  sprintf(g.logbuf, "alignNumbersAfter(): token not found. Exiting.\n");
1217  writeToLog(g.logbuf);
1218  return -1;
1219  }
1220  str += strlen(token);
1221 
1222  pos = str - buf;
1223  if (buf[pos] != '-'){
1224  memmove(str + 1, str, len - pos);
1225  buf[pos] = ' ';
1226  len += 1;
1227  }
1228  return len;
1229 }
1230 
1252 int alignTokens(const char *refToken, int offset, const char *token, char *buf, int len){
1253 
1254  int pos1, pos2;
1255 
1256  char *str = strstr(buf, refToken);
1257  if (str == NULL){
1258  sprintf(g.logbuf, "alignTokens(): refToken not found. Exiting.\n");
1259  writeToLog(g.logbuf);
1260  return -1;
1261  }
1262  str += strlen(refToken);
1263  pos1 = str - buf;
1264 
1265  str = strstr(buf, token);
1266  if (str == NULL){
1267  sprintf(g.logbuf, "alignTokens(): token not found. Exiting.\n");
1268  writeToLog(g.logbuf);
1269  return -1;
1270  }
1271  pos2 = str - buf;
1272 
1273  while (pos2 < pos1 + offset){
1274  memmove(str + 1, str, len - pos2);
1275  buf[pos2] = ' ';
1276  pos2 += 1;
1277  str += 1;
1278  len += 1;
1279  }
1280  return len;
1281 }
1282 
1292 
1293  if (g.interruptLossCount == 0) {
1294  const char *timefmt = "%F %H:%M:%S";
1295  char timeStr[30];
1296  char printStr[150];
1297 
1298  strftime(timeStr, 30, timefmt, localtime(&g.pps_t_sec));
1299 
1300  char *printfmt = g.strbuf;
1301 
1302  if (g.sysDelayShift == 0){
1303  strcpy(printfmt, "%s.%06d %d jitter: ");
1304  }
1305  else {
1306  strcpy(printfmt, "%s.%06d %d *jitter: ");
1307  }
1308 
1309  strcat(printfmt, "%d freqOffset: %f avgCorrection: %f clamp: %d\n");
1310 
1311  sprintf(printStr, printfmt, timeStr, g.pps_t_usec, g.seq_num,
1312  g.jitter, g.freqOffset, g.avgCorrection, g.hardLimit);
1313 
1314  int len = strlen(printStr) + 1; // strlen + '\0'
1315  len = alignNumbersAfter("jitter: ", printStr, len);
1316  if (len == -1){
1317  return -1;
1318  }
1319  len = alignTokens("jitter:", 6, "freqOffset:", printStr, len);
1320  if (len == -1){
1321  return -1;
1322  }
1323  len = alignNumbersAfter("freqOffset:", printStr, len);
1324  if (len == -1){
1325  return -1;
1326  }
1327  len = alignTokens("freqOffset:", 12, "avgCorrection:", printStr, len);
1328  if (len == -1){
1329  return -1;
1330  }
1331  len = alignNumbersAfter("avgCorrection: ", printStr, len);
1332  if (len == -1){
1333  return -1;
1334  }
1335  len = alignTokens("avgCorrection:", 12, "clamp:", printStr, len);
1336  if (len == -1){
1337  return -1;
1338  }
1339 
1340  bufferStatusMsg(printStr);
1341  }
1342  return 0;
1343 }
1344 
1350 int restartNTP(void){
1351  sprintf(g.logbuf, "Restarting NTP\n");
1352  writeToLog(g.logbuf);
1353 
1354  int rv = sysCommand("service ntp restart > /run/shm/ntp-restart-msg");
1355  writeFileMsgToLog("/run/shm/ntp-restart-msg");
1356  return rv;
1357 }
1358 
1369 int replaceNTPConfig(const char *fbuf){
1370  int fd = open_logerr(ntp_config_part, O_CREAT | O_RDWR | O_TRUNC);
1371  if (fd == -1){
1372  return -1;
1373  }
1374  int fSize = strlen(fbuf);
1375 
1376  int wr = write(fd, fbuf, fSize);
1377  if (wr != fSize){
1378  close(fd);
1379  remove(ntp_config_part);
1380  sprintf(g.logbuf, "ERROR: Write of new \"/etc/ntp.conf\" failed. Original unchanged.\n");
1381  writeToLog(g.logbuf);
1382  return -1;
1383  }
1384  fsync(fd);
1385  close(fd);
1386 
1387  int fdb = open(ntp_config_bac, O_RDONLY);
1388  if (fdb == -1){
1389  if (errno == ENOENT){
1391  }
1392  else {
1394  printf("%s", g.logbuf);
1395  }
1396  }
1397  else {
1398  close(fdb);
1399  remove(ntp_config_file);
1400  }
1402 
1403  return 0;
1404 }
1405 
1413 void removeConfigKeys(const char *key1, const char *key2, char *fbuf){
1414 
1415  char *pHead = NULL, *pTail = NULL, *pNxt = NULL;
1416  char *pLine = NULL;
1417 
1418  pLine = fbuf;
1419 
1420  while (strlen(pLine) > 0){
1421  // Search for key1 followed by key2
1422  while (pLine != NULL){ // If this is the next line
1423 
1424  pNxt = pLine;
1425  while (pNxt[0] == ' ' || pNxt[0] == '\t'){
1426  pNxt += 1;
1427  }
1428 
1429  if (strncmp(pNxt, key1, strlen(key1)) == 0){
1430  pHead = pNxt;
1431  pNxt += strlen(key1);
1432 
1433  while (pNxt[0] == ' ' || pNxt[0] == '\t'){
1434  pNxt += 1;
1435  }
1436 
1437  if (strncmp(pNxt, key2, strlen(key2)) == 0){
1438  pNxt += strlen(key2);
1439 
1440  while (pNxt[0] == ' ' || pNxt[0] == '\t' || pNxt[0] == '\n'){
1441  pNxt += 1;
1442  }
1443  pTail = pNxt;
1444 
1445  memmove(pHead, pTail, strlen(pTail)+1);
1446  pLine = pHead; // Point pLine to any remaining
1447  break; // tail of the file for removal
1448  } // of any more lines containing
1449  } // "key1 key2".
1450  pLine = strchr(pLine, '\n') + 1;
1451  }
1452  }
1453 }
1454 
1462 int disableNTP(void){
1463  struct stat stat_buf;
1464  int fd;
1465 
1466  if (g.doNTPsettime){
1467  fd = open_logerr(ntp_config_file, O_RDONLY);
1468  if (fd == -1){
1469  sprintf(g.logbuf, "disableNTP() Did not find NTP config file. Is NTP installed?\n");
1470  writeToLog(g.logbuf);
1471  return -1;
1472  }
1473  }
1474  else {
1475  fd = open(ntp_config_file, O_RDONLY);
1476  if (fd == -1){ // No NTP file so can't use SNTP
1477  sysCommand("timedatectl set-ntp false"); // Try timedatectl
1478  return -1;
1479  }
1480  }
1481 
1482  fstat(fd, &stat_buf);
1483  int sz = stat_buf.st_size;
1484 
1485  int fbufSz = sz + strlen("\ndisable ntp\n") + 10;
1486 
1487  char *fbuf = new char[fbufSz];
1488  memset(fbuf, 0, fbufSz);
1489 
1490  int rv = read_logerr(fd, fbuf, sz, ntp_config_file); // Read ntp.conf into fbuf
1491  if (rv == -1 || rv != sz){
1492  delete[] fbuf;
1493  close(fd);
1494  return -1;
1495  }
1496  close(fd);
1497 
1498  sz = strlen(fbuf);
1499  if (fbuf[sz-1] == '\n'){
1500  strcat(fbuf, "disable ntp\n");
1501  }
1502  else {
1503  strcat(fbuf, "\ndisable ntp\n");
1504  }
1505 
1506  sprintf(g.logbuf, "Wrote 'disable ntp' to ntp.conf.\n");
1507  writeToLog(g.logbuf);
1508 
1509  rv = replaceNTPConfig(fbuf);
1510  delete[] fbuf;
1511 
1512  if (rv == -1){
1513  return rv;
1514  }
1515 
1516  rv = restartNTP();
1517  return rv;
1518 }
1519 
1527 int enableNTP(void){
1528  int rv = 0;
1529  struct stat stat_buf;
1530  int fd = 0;
1531 
1532  if (g.doNTPsettime){
1533  fd = open_logerr(ntp_config_file, O_RDONLY);
1534  }
1535  else {
1536  fd = open(ntp_config_file, O_RDONLY);
1537  }
1538  if (fd == -1){ // No NTP file so can't use NTP
1539  sysCommand("timedatectl set-ntp true"); // Try timedatectl
1540  return -1;
1541  }
1542 
1543  fstat(fd, &stat_buf);
1544 
1545  int sz = stat_buf.st_size;
1546  char *fbuf = new char[sz+1];
1547 
1548  rv = read_logerr(fd, fbuf, sz, ntp_config_file);
1549  if (rv == -1 || rv != sz){
1550  delete[] fbuf;
1551  close(fd);
1552  return -1;
1553  }
1554  close(fd);
1555  fbuf[sz] = 0;
1556 
1557  removeConfigKeys("disable", "ntp", fbuf);
1558 
1559  rv = replaceNTPConfig(fbuf);
1560  delete[] fbuf;
1561 
1562  if (rv == -1){
1563  return rv;
1564  }
1565 
1566  rv = restartNTP();
1567  return rv;
1568 }
1569 
1583 char *copyMajorTo(char *majorPos){
1584 
1585  struct stat stat_buf;
1586 
1587  const char *filename = "/run/shm/proc_devices";
1588 
1589  int rv = sysCommand("cat /proc/devices > /run/shm/proc_devices"); // "/proc/devices" can't be handled like
1590  if (rv == -1){ // a normal file so it is copied to a memory
1591  return NULL; // file where its is contents can be read.
1592  }
1593 
1594  int fd = open_logerr(filename, O_RDONLY);
1595  if (fd == -1){
1596  return NULL;
1597  }
1598 
1599  fstat(fd, &stat_buf);
1600  int sz = stat_buf.st_size;
1601 
1602  char *fbuf = new char[sz+1];
1603 
1604  rv = read_logerr(fd, fbuf, sz, filename);
1605  if (rv == -1){
1606  close(fd);
1607  remove(filename);
1608  delete[] fbuf;
1609  return NULL;
1610  }
1611  close(fd);
1612  remove(filename);
1613 
1614  fbuf[sz] = '\0';
1615 
1616  char *pos = strstr(fbuf, "gps-pps-io");
1617  if (pos == NULL){
1618  sprintf(g.logbuf, "Can't find gps-pps-io in \"/run/shm/proc_devices\"\n");
1619  writeToLog(g.logbuf);
1620  delete[] fbuf;
1621  return NULL;
1622  }
1623  char *end = pos - 1;
1624  *end = 0;
1625 
1626  pos -= 2;
1627  char *pos2 = pos;
1628  while (pos2 == pos){
1629  pos -= 1;
1630  pos2 = strpbrk(pos, num);
1631  }
1632  strcpy(majorPos, pos2);
1633 
1634  delete[] fbuf;
1635  return majorPos;
1636 }
1637 
1638 char *getLinuxVersion(void){
1639  int rv;
1640  char fbuf[20];
1641  rv = sysCommand("uname -r > /run/shm/linuxVersion");
1642  if (rv == -1){
1643  return NULL;
1644  }
1645 
1646  int fd = open("/run/shm/linuxVersion", O_RDONLY);
1647  rv = read(fd, fbuf, 20);
1648  if (rv == -1){
1649  sprintf(g.logbuf, "getLinuxVersion() Unable to read Linux version from /run/shm/linuxVersion\n");
1650  writeToLog(g.logbuf);
1651  return NULL;
1652  }
1653  sscanf(fbuf, "%s\n", g.linuxVersion);
1654  return g.linuxVersion;
1655 }
1656 
1668 int driver_load(int ppsGPIO, int outputGPIO, int intrptGPIO){
1669  char driverFile[100];
1670 
1671  strcpy(driverFile, "/lib/modules/");
1672  strcat(driverFile, getLinuxVersion());
1673  strcat(driverFile, "/kernel/drivers/misc/gps-pps-io.ko");
1674 
1675  int fd = open(driverFile, O_RDONLY);
1676  if (fd < 0){
1677  if (errno == ENOENT){
1678  sprintf(g.logbuf, "Linux version changed. Requires\n");
1679  printf("%s", g.logbuf);
1680  writeToLog(g.logbuf);
1681  sprintf(g.logbuf, "reinstall of version-matching pps-client.\n");
1682  printf("%s", g.logbuf);
1683  writeToLog(g.logbuf);
1684  }
1685  return -1;
1686  }
1687  close(fd);
1688 
1689  char *insmod = g.strbuf;
1690  strcpy(insmod, "/sbin/insmod ");
1691  strcat(insmod, driverFile);
1692  sprintf(insmod + strlen(insmod), " PPS_GPIO=%d OUTPUT_GPIO=%d INTRPT_GPIO=%d", ppsGPIO, outputGPIO, intrptGPIO);
1693 
1694  sysCommand("rm -f /dev/gps-pps-io"); // Clean up any old device files.
1695 
1696  int rv = sysCommand(insmod); // Issue the insmod command
1697  if (rv == -1){
1698  return -1;
1699  }
1700 
1701  char *mknod = g.strbuf;
1702  strcpy(mknod, "mknod /dev/gps-pps-io c ");
1703  char *major = copyMajorTo(mknod + strlen(mknod));
1704  if (major == NULL){ // No major found! insmod failed.
1705  sprintf(g.logbuf, "driver_load() error: No major found!\n");
1706  writeToLog(g.logbuf);
1707  sysCommand("/sbin/rmmod gps-pps-io");
1708  return -1;
1709  }
1710  strcat(mknod, " 0");
1711 
1712  rv = sysCommand(mknod); // Issue the mknod command
1713  if (rv == -1){
1714  return -1;
1715  }
1716 
1717  rv = sysCommand("chgrp root /dev/gps-pps-io");
1718  if (rv == -1){
1719  return -1;
1720  }
1721 
1722  rv = sysCommand("chmod 664 /dev/gps-pps-io");
1723  if (rv == -1){
1724  return -1;
1725  }
1726 
1727  return 0;
1728 }
1729 
1734  sleep(5); // Make sure the system has actually closed the driver before we unload it.
1735  sysCommand("/sbin/rmmod gps_pps_io");
1736  sysCommand("rm -f /dev/gps-pps-io");
1737 }
1738 
1747 int getSeqNum(const char *pbuf){
1748 
1749  char *pSpc, *pNum;
1750  int seqNum = 0;
1751 
1752  pSpc = strpbrk((char *)pbuf, space);
1753 
1754  pNum = strpbrk(pSpc, num);
1755  pSpc = strpbrk(pNum, space);
1756  pNum = strpbrk(pSpc, num);
1757 
1758  sscanf(pNum, "%d ", &seqNum);
1759  return seqNum;
1760 }
1761 
1768  struct timeval tv1;
1769  struct timespec ts2;
1770  char paramsBuf[MSGBUF_SZ];
1771  struct stat stat_buf;
1772  int seqNum, lastSeqNum = -1;
1773 
1774  int dispTime = 500000; // Display at half second
1775 
1776  gettimeofday(&tv1, NULL);
1777  ts2 = setSyncDelay(dispTime, tv1.tv_usec);
1778 
1779  for (;;){
1780 
1781  if (g.exit_loop){
1782  break;
1783  }
1784  nanosleep(&ts2, NULL);
1785 
1786  int fd = open(displayParams_file, O_RDONLY);
1787  if (fd == -1){
1788  printf("showStatusEachSecond(): Could not open ");
1789  printf("%s", displayParams_file);
1790  printf("\n");
1791  }
1792  else {
1793  fstat(fd, &stat_buf);
1794  int sz = stat_buf.st_size;
1795 
1796  if (sz >= MSGBUF_SZ){
1797  printf("showStatusEachSecond() buffer too small. sz: %d\n", sz);
1798  close(fd);
1799  break;
1800  }
1801 
1802  int rv = read(fd, paramsBuf, sz);
1803  close(fd);
1804  if (rv == -1){
1805  printf("showStatusEachSecond() Read paramsBuf failed with error: %s\n", strerror(errno));
1806  break;
1807  }
1808 
1809  if (sz > 0){
1810 
1811  paramsBuf[sz]= '\0';
1812 
1813  int clen = strcspn(paramsBuf, "0123456789");
1814  if (clen > 0){ // Is an info message line.
1815  printf("%s", paramsBuf);
1816  }
1817  else { // Is a standard status line.
1818  seqNum = getSeqNum(paramsBuf);
1819 
1820  if (seqNum != lastSeqNum){
1821  printf("%s", paramsBuf);
1822  }
1823  lastSeqNum = seqNum;
1824  }
1825  }
1826  }
1827 
1828  gettimeofday(&tv1, NULL);
1829 
1830  ts2 = setSyncDelay(dispTime, tv1.tv_usec);
1831  }
1832  printf("Exiting PPS-Client status display\n");
1833 }
1834 
1842 void INThandler(int sig){
1843  g.exit_loop = true;
1844 }
1845 
1857 bool missingArg(int argc, char *argv[], int i){
1858  if (i == argc - 1 || argv[i+1][0] == '-'){
1859  printf("Error: Missing argument for %s.\n", argv[i]);
1860  return true;
1861  }
1862  return false;
1863 }
1864 
1874 int daemonSaveArray(const char *requestStr, const char *filename){
1875  char buf[200];
1876 
1877  int fd = open_logerr(arrayData_file, O_CREAT | O_WRONLY | O_TRUNC);
1878  if (fd == -1){
1879  printf("daemonSaveArray() Open arrayData_file failed\n");
1880  return -1;
1881  }
1882 
1883  strcpy(buf, requestStr);
1884 
1885  if (filename != NULL){
1886  strcat(buf, " ");
1887  strcat(buf, filename);
1888  }
1889 
1890  int rv = write(fd, buf, strlen(buf) + 1);
1891  close(fd);
1892  if (rv == -1){
1893  sprintf(g.logbuf, "daemonSaveArray() Write to tmpfs memory file failed\n");
1894  writeToLog(g.logbuf);
1895  return -1;
1896  }
1897  return 0;
1898 }
1899 
1905  printf("Accepts any of these:\n");
1906  int arrayLen = sizeof(arrayData) / sizeof(struct saveFileData);
1907  for (int i = 0; i < arrayLen; i++){
1908  printf("%s\n", arrayData[i].label);
1909  }
1910 }
1911 
1923 int parseSaveDataRequest(int argc, char *argv[], const char *requestStr){
1924 
1925  int arrayLen = sizeof(arrayData) / sizeof(struct saveFileData);
1926 
1927  int i;
1928  for (i = 0; i < arrayLen; i++){
1929  if (strcmp(requestStr, arrayData[i].label) == 0){
1930  break;
1931  }
1932  }
1933  if (i == arrayLen){
1934  printf("Arg \"%s\" not recognized\n", argv[i+1]);
1936  return -1;
1937  }
1938 
1939  char *filename = NULL;
1940  for (int j = 1; j < argc; j++){
1941  if (strcmp(argv[j], "-f") == 0){
1942  if (missingArg(argc, argv, j)){
1943  printf("Requires a filename.\n");
1944  return -1;
1945  }
1946  strncpy(g.strbuf, argv[j+1], STRBUF_SZ);
1947  g.strbuf[strlen(argv[j+1])] = '\0';
1948  filename = g.strbuf;
1949  break;
1950  }
1951  }
1952 
1953  if (filename != NULL){
1954  printf("Writing to file: %s\n", filename);
1955  }
1956  else {
1957  for (i = 0; i < arrayLen; i++){
1958  if (strcmp(requestStr, arrayData[i].label) == 0){
1959  printf("Writing to default file: %s\n", arrayData[i].filename);
1960  }
1961  }
1962  }
1963 
1964  if (daemonSaveArray(requestStr, filename) == -1){
1965  return -1;
1966  }
1967  return 0;
1968 }
1969 
1989 int accessDaemon(int argc, char *argv[]){
1990  bool verbose = false;
1991 
1992  if (! ppsIsRunning()){ // If not running,
1993  remove(pidFilename); // remove a zombie PID filename if found.
1994  return -1;
1995  }
1996 
1997  signal(SIGINT, INThandler); // Set handler to enable exiting with ctrl-c.
1998 
1999  printf("PPS-Client v%s is running.\n", version);
2000 
2001  if (argc > 1){
2002 
2003  for (int i = 1; i < argc; i++){
2004  if (strcmp(argv[i], "-v") == 0){
2005  verbose = true;
2006  }
2007  }
2008  for (int i = 1; i < argc; i++){
2009  if (strcmp(argv[i], "-s") == 0){ // This is a save data request.
2010  if (missingArg(argc, argv, i)){
2012  return -2;
2013  }
2014 
2015  if (parseSaveDataRequest(argc, argv, argv[i+1]) == -1){
2016  return -2;
2017  }
2018  break;
2019  }
2020  }
2021  }
2022 
2023  if (verbose){
2024  printf("Displaying second-by-second state params (ctrl-c to quit):\n");
2026  }
2027 
2028  return 0;
2029 }
2030 
2043 void buildErrorDistrib(int timeCorrection){
2044  int len = ERROR_DISTRIB_LEN - 1;
2045  int idx = timeCorrection + len / 6;
2046 
2047  if (idx < 0){
2048  idx = 0;
2049  }
2050  else if (idx > len){
2051  idx = len;
2052  }
2053  g.errorDistrib[idx] += 1;
2054 
2055  g.errorCount += 1;
2056 }
2057 
2067 void buildJitterDistrib(int rawError){
2068  int len = JITTER_DISTRIB_LEN - 1;
2069  int idx = rawError + len / 6;
2070 
2071  if (idx < 0){
2072  idx = 0;
2073  }
2074  else if (idx > len){
2075  idx = len;
2076  }
2077  g.jitterDistrib[idx] += 1;
2078 
2079  g.jitterCount += 1;
2080 }
2081 
2088 void TERMhandler(int sig){
2089  signal(SIGTERM, SIG_IGN);
2090  sprintf(g.logbuf,"Recieved SIGTERM\n");
2091  writeToLog(g.logbuf);
2092  g.exit_requested = true;
2093  signal(SIGTERM, TERMhandler);
2094 }
2095 
2101 void HUPhandler(int sig){
2102  signal(SIGHUP, SIG_IGN);
2103 }
2104 
2114 int getDelayIndex(int sysDelay){
2115  int i = 0;
2116  for (i = 0; i < NUM_PARAMS; i++){
2117  if (g.delayLabel[i] != 0){
2118  if (sysDelay == g.delayLabel[i]){
2119  break;
2120  }
2121  }
2122  else {
2123  g.delayLabel[i] = sysDelay;
2124  break;
2125  }
2126  }
2127  return i;
2128 }
2129 
2137 void buildInterruptDistrib(int intrptDelay){
2138  int len = INTRPT_DISTRIB_LEN - 1;
2139  int idx = intrptDelay;
2140 
2141  if (idx > len){
2142  idx = len;
2143  }
2144  if (idx < 0){
2145  idx = 0;
2146  }
2147 
2148  int j = getDelayIndex(g.sysDelay);
2149  g.intrptDistrib[j][idx] += 1;
2150 
2151  g.interruptCount += 1;
2152 }
2153 
2161 void buildSysDelayDistrib(int sysDelay){
2162  int len = INTRPT_DISTRIB_LEN - 1;
2163  int idx = sysDelay;
2164 
2165  if (idx > len){
2166  idx = len;
2167  }
2168  g.sysDelayDistrib[idx] += 1;
2169 
2170  g.sysDelayCount += 1;
2171 }
2172 
2186  timeval t;
2187  g.freqOffsetSum += g.freqOffset;
2188 
2189  g.freqOffsetDiff[g.intervalCount] = g.freqOffset - g.lastFreqOffset;
2190 
2191  g.lastFreqOffset = g.freqOffset;
2192  g.intervalCount += 1;
2193 
2194  if (g.intervalCount >= FIVE_MINUTES){
2195  gettimeofday(&t, NULL);
2196 
2197  double norm = 1.0 / (double)FREQDIFF_INTRVL;
2198 
2199  double diffSum = 0.0;
2200  for (int i = 0; i < FREQDIFF_INTRVL; i++){
2201  diffSum += g.freqOffsetDiff[i] * g.freqOffsetDiff[i];
2202  }
2203  g.freqAllanDev[g.recIndex] = sqrt(diffSum * norm * 0.5);
2204 
2205  g.timestampRec[g.recIndex] = t.tv_sec;
2206 
2207  g.freqOffsetRec[g.recIndex] = g.freqOffsetSum * norm;
2208 
2209  g.recIndex += 1;
2210  if (g.recIndex == NUM_5_MIN_INTERVALS){
2211  g.recIndex = 0;
2212  }
2213 
2214  g.intervalCount = 0;
2215  g.freqOffsetSum = 0.0;
2216  }
2217 }
2218 
2231 void recordOffsets(int timeCorrection){
2232 
2233  g.seq_numRec[g.recIndex2] = g.seq_num;
2234  g.offsetRec[g.recIndex2] = timeCorrection;
2235  g.freqOffsetRec2[g.recIndex2] = g.freqOffset;
2236 
2237  g.recIndex2 += 1;
2238  if (g.recIndex2 >= SECS_PER_10_MIN){
2239  g.recIndex2 = 0;
2240  }
2241 }
2242 
void writeToLog(char *logbuf)
Definition: pps-files.cpp:247
#define SERIAL
Definition: pps-client.h:121
void buildInterruptDistrib(int intrptDelay)
Definition: pps-files.cpp:2137
int replaceNTPConfig(const char *fbuf)
Definition: pps-files.cpp:1369
const char * log_file
Stores activity and errors.
Definition: pps-files.cpp:29
int alignTokens(const char *refToken, int offset, const char *token, char *buf, int len)
Definition: pps-files.cpp:1252
void recordOffsets(int timeCorrection)
Definition: pps-files.cpp:2231
char * copyMajorTo(char *majorPos)
Definition: pps-files.cpp:1583
void showStatusEachSecond(void)
Definition: pps-files.cpp:1767
#define JITTER_DISTRIB
Definition: pps-client.h:112
void recordFrequencyVars(void)
Definition: pps-files.cpp:2185
const char * distrib_file
Stores a forming distribution of offset corrections.
Definition: pps-files.cpp:26
double freqOffset
System clock frequency correction calculated as G.integralTimeCorrection * G.integralGain.
Definition: pps-client.h:226
const char * last_sysDelay_distrib_file
Stores a distribution of sysDelay.
Definition: pps-files.cpp:34
#define MSGBUF_SZ
Definition: pps-client.h:90
void writeJitterDistribFile(void)
Definition: pps-files.cpp:903
#define INTRPT_DISTRIB_LEN
Definition: pps-client.h:97
#define EXIT_LOST_PPS
Definition: pps-client.h:116
#define SECS_PER_10_MIN
Definition: pps-client.h:45
void printAcceptedArgs(void)
Definition: pps-files.cpp:1904
bool ppsIsRunning(void)
Definition: pps-files.cpp:475
int saveDoubleArray(double distrib[], const char *filename, int len, int arrayZero)
Definition: pps-files.cpp:991
#define OUTPUT_GPIO
Definition: pps-client.h:118
const char * valid_config[]
Definition: pps-files.cpp:69
void writeTimestamp(double timestamp)
Definition: pps-files.cpp:1179
struct G g
Declares the global variables defined in pps-client.h.
Definition: pps-client.cpp:53
const char * jitter_distrib_file
Stores a forming distribution of offset corrections.
Definition: pps-files.cpp:28
bool configHasValue(int config_val, void *value)
Definition: pps-files.cpp:550
#define JITTER_DISTRIB_LEN
Definition: pps-client.h:96
int daemonSaveArray(const char *requestStr, const char *filename)
Definition: pps-files.cpp:1874
bool isEnabled(int key)
Definition: pps-files.cpp:159
char linuxVersion[20]
Array for recording the Linux version.
Definition: pps-client.h:230
pid_t getChildPID(void)
Definition: pps-files.cpp:447
#define SERIAL_PORT
Definition: pps-client.h:122
const char * sysDelay_file
The current sysDelay value updated each second.
Definition: pps-files.cpp:42
int alignNumbersAfter(const char *token, char *buf, int len)
Definition: pps-files.cpp:1211
#define SYSDELAY_DISTRIB
Definition: pps-client.h:115
const char * intrpt_distrib_file
Stores a forming distribution of offset corrections.
Definition: pps-files.cpp:32
#define FIVE_MINUTES
Definition: pps-client.h:49
int disableNTP(void)
Definition: pps-files.cpp:1462
int getSeqNum(const char *pbuf)
Definition: pps-files.cpp:1747
int sysCommand(const char *cmd)
Definition: pps-files.cpp:89
int read_logerr(int fd, char *buf, int sz, const char *filename)
Definition: pps-files.cpp:347
#define RAW_ERROR_ZERO
Index corresponding to rawError == 0 in detectDelayPeak().
Definition: pps-client.h:67
void buildSysDelayDistrib(int sysDelay)
Definition: pps-files.cpp:2161
double avgCorrection
A one-minute rolling average of G.timeCorrection values generated by getAverageCorrection().
Definition: pps-client.h:213
const char * space
Definition: pps-files.cpp:47
int writeFileMsgToLogbuf(const char *filename, char *logbuf)
Definition: pps-files.cpp:393
const char * ntp_config_bac
Backup of the NTP configuration file.
Definition: pps-files.cpp:39
#define PPS_GPIO
Definition: pps-client.h:117
#define CALIBRATE
Definition: pps-client.h:113
const char * assert_file
The timestamps of the time corrections each second.
Definition: pps-files.cpp:43
#define SNTP
Definition: pps-client.h:120
const char * displayParams_file
Temporary file storing params for the status display.
Definition: pps-files.cpp:44
void writeSysDelay(void)
Definition: pps-files.cpp:1157
const char * last_distrib_file
Stores the completed distribution of offset corrections.
Definition: pps-files.cpp:25
void writeFrequencyVars(const char *filename)
Definition: pps-files.cpp:958
char * getLinuxVersion(void)
Definition: pps-files.cpp:1638
void HUPhandler(int sig)
Definition: pps-files.cpp:2101
void couldNotOpenMsgTo(char *logbuf, const char *filename)
Definition: pps-files.cpp:191
void INThandler(int sig)
Definition: pps-files.cpp:1842
char * getString(int key)
Definition: pps-files.cpp:108
int processFiles(void)
Definition: pps-files.cpp:1086
int accessDaemon(int argc, char *argv[])
Definition: pps-files.cpp:1989
#define CONFIG_FILE_SZ
Definition: pps-client.h:92
bool configWasRead
True if pps-client.conf was read at least once.
Definition: pps-client.h:153
const char * old_log_file
Stores activity and errors.
Definition: pps-files.cpp:30
void TERMhandler(int sig)
Definition: pps-files.cpp:2088
void errorReadingMsgTo(char *logbuf, const char *filename)
Definition: pps-files.cpp:202
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:759
bool isVerbose
Enables continuous printing of PPS-Client status params when "true".
Definition: pps-client.h:151
const char * last_intrpt_distrib_file
Stores the completed distribution of offset corrections.
Definition: pps-files.cpp:31
#define LOGBUF_SZ
Definition: pps-client.h:89
struct saveFileData arrayData[]
Definition: pps-files.cpp:181
bool missingArg(int argc, char *argv[], int i)
Definition: pps-files.cpp:1857
#define NUM_PARAMS
Definition: pps-client.h:94
void writeSysdelayDistribFile(void)
Definition: pps-files.cpp:890
void buildErrorDistrib(int timeCorrection)
Definition: pps-files.cpp:2043
const char * ntp_config_file
The NTP configuration file.
Definition: pps-files.cpp:38
int getDriverGPIOvals(void)
Definition: pps-files.cpp:575
const char * pidFilename
Stores the PID of PPS-Client.
Definition: pps-files.cpp:35
int getDelayIndex(int sysDelay)
Definition: pps-files.cpp:2114
void writeOffsets(const char *filename)
Definition: pps-files.cpp:931
void writeIntrptDistribFile(void)
Definition: pps-files.cpp:878
bool hasString(int key, const char *string)
Definition: pps-files.cpp:137
#define STRBUF_SZ
Definition: pps-client.h:88
#define ERROR_DISTRIB_LEN
Definition: pps-client.h:95
#define NUM_5_MIN_INTERVALS
Number of five minute intervals in 24 hours.
Definition: pps-client.h:48
const char * ntp_config_part
Temporary filename for an NTP config file during copy.
Definition: pps-files.cpp:40
#define SECS_PER_MINUTE
Definition: pps-client.h:43
int readConfigFile(void)
Definition: pps-files.cpp:626
int sysDelayShift
Assigned from G.delayShift and subtracted from G.rawError in correctDelayPeak() when a delay shift oc...
Definition: pps-client.h:185
int processWriteRequest(void)
Definition: pps-files.cpp:1033
int bufferStateParams(void)
Definition: pps-files.cpp:1291
int enableNTP(void)
Definition: pps-files.cpp:1527
unsigned int seq_num
Advancing count of the number of PPS interrupt timings that have been received.
Definition: pps-client.h:155
int writeFileMsgToLog(const char *filename)
Definition: pps-files.cpp:437
double rawErrorDistrib[ERROR_DISTRIB_LEN]
The distribution used to detect a delay shift in detectDelayPeak().
Definition: pps-client.h:192
#define MAX_LINE_LEN
Definition: pps-client.h:87
void writeMultipleDistrib(int label[], int distrib[][INTRPT_DISTRIB_LEN], int len, int scaleZero, int count, int *last_epoch, const char *distrib_file, const char *last_distrib_file)
Definition: pps-files.cpp:810
int sysDelay
Definition: pps-client.h:179
#define INTRPT_GPIO
Definition: pps-client.h:119
#define SETTLE_TIME
The PPS-Client up time required before saving performance data.
Definition: pps-client.h:51
#define SECS_PER_DAY
Definition: pps-client.h:47
const char * arrayData_file
Stores a request sent to the PPS-Client daemon.
Definition: pps-files.cpp:45
Struct for program-wide global variables showing those important to the controller.
Definition: pps-client.h:146
const char * sysDelay_distrib_file
Stores a forming distribution of sysDelay values.
Definition: pps-files.cpp:33
void driver_unload()
Definition: pps-files.cpp:1733
bool isDisabled(int key)
Definition: pps-files.cpp:173
int outputGPIO
The calibrate GPIO output number read from pps-client.conf and passed to the driver.
Definition: pps-client.h:148
void writeToLogNoTimestamp(char *logbuf)
Definition: pps-files.cpp:215
void removeConfigKeys(const char *key1, const char *key2, char *fbuf)
Definition: pps-files.cpp:1413
#define HARD_LIMIT_1
Definition: pps-client.h:102
int open_logerr(const char *filename, int flags)
Definition: pps-files.cpp:366
int createPIDfile(void)
Definition: pps-files.cpp:515
int interruptLossCount
Records the number of consecutive lost PPS interrupt times.
Definition: pps-client.h:162
#define INTERRUPT_DISTRIB
Definition: pps-client.h:114
const char * config_file
The PPS-Client configuration file.
Definition: pps-files.cpp:37
int hardLimit
An adaptive limit value determined by setHardLimit() and applied to G.rawError by clampJitter() as th...
Definition: pps-client.h:208
void buildJitterDistrib(int rawError)
Definition: pps-files.cpp:2067
#define FREQDIFF_INTRVL
The number of minutes between Allan deviation samples of system clock frequency correction.
Definition: pps-client.h:57
struct timespec setSyncDelay(int timeAt, int fracSec)
Definition: pps-client.cpp:937
int writeStatusStrings(void)
Definition: pps-files.cpp:316
int restartNTP(void)
Definition: pps-files.cpp:1350
int parseSaveDataRequest(int argc, char *argv[], const char *requestStr)
Definition: pps-files.cpp:1923
int intrptGPIO
The calibrate GPIO interrupt number read from pps-client.conf and passed to the driver.
Definition: pps-client.h:149
int driver_load(int ppsGPIO, int outputGPIO, int intrptGPIO)
Definition: pps-files.cpp:1668
void writeErrorDistribFile(void)
Definition: pps-files.cpp:917
int ppsGPIO
The PPS GPIO interrupt number read from pps-client.conf and passed to the driver. ...
Definition: pps-client.h:147
const char * version
Program version 1.4.0 created on 17 Dec 2017.
Definition: pps-client.cpp:51
void bufferStatusMsg(const char *msg)
Definition: pps-files.cpp:290
#define ERROR_DISTRIB
Definition: pps-client.h:110
void initFileLocalData(void)
Definition: pps-files.cpp:85
const char * num
Definition: pps-files.cpp:48
const char * last_jitter_distrib_file
Stores the completed distribution of offset corrections.
Definition: pps-files.cpp:27