Coverage Report

Created: 2023-05-19 06:16

/src/ntp-dev/ntpd/refclock_datum.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
** refclock_datum - clock driver for the Datum Programmable Time Server
3
**
4
** Important note: This driver assumes that you have termios. If you have
5
** a system that does not have termios, you will have to modify this driver.
6
**
7
** Sorry, I have only tested this driver on SUN and HP platforms.
8
*/
9
10
#ifdef HAVE_CONFIG_H
11
# include <config.h>
12
#endif
13
14
#include "ntp_types.h"
15
16
#if defined(REFCLOCK) && defined(CLOCK_DATUM)
17
18
/*
19
** Include Files
20
*/
21
22
#include "ntpd.h"
23
#include "ntp_io.h"
24
#include "ntp_tty.h"
25
#include "ntp_refclock.h"
26
#include "timevalops.h"
27
#include "ntp_stdlib.h"
28
29
#include <stdio.h>
30
#include <ctype.h>
31
32
#if defined(STREAM)
33
#include <stropts.h>
34
#endif /* STREAM */
35
36
#include "ntp_stdlib.h"
37
38
/*
39
** This driver supports the Datum Programmable Time System (PTS) clock.
40
** The clock works in very straight forward manner. When it receives a
41
** time code request (e.g., the ascii string "//k/mn"), it responds with
42
** a seven byte BCD time code. This clock only responds with a
43
** time code after it first receives the "//k/mn" message. It does not
44
** periodically send time codes back at some rate once it is started.
45
** the returned time code can be broken down into the following fields.
46
**
47
**            _______________________________
48
** Bit Index | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
49
**            ===============================
50
** byte 0:   | -   -   -   - |      H D      |
51
**            ===============================
52
** byte 1:   |      T D      |      U D      |
53
**            ===============================
54
** byte 2:   | -   - |  T H  |      U H      |
55
**            ===============================
56
** byte 3:   | - |    T M    |      U M      |
57
**            ===============================
58
** byte 4:   | - |    T S    |      U S      |
59
**            ===============================
60
** byte 5:   |      t S      |      h S      |
61
**            ===============================
62
** byte 6:   |      m S      | -   -   -   - |
63
**            ===============================
64
**
65
** In the table above:
66
**
67
**  "-" means don't care
68
**  "H D", "T D", and "U D" means Hundreds, Tens, and Units of Days
69
**  "T H", and "UH" means Tens and Units of Hours
70
**  "T M", and "U M" means Tens and Units of Minutes
71
**  "T S", and "U S" means Tens and Units of Seconds
72
**  "t S", "h S", and "m S" means tenths, hundredths, and thousandths
73
**        of seconds
74
**
75
** The Datum PTS communicates throught the RS232 port on your machine.
76
** Right now, it assumes that you have termios. This driver has been tested
77
** on SUN and HP workstations. The Datum PTS supports various IRIG and
78
** NASA input codes. This driver assumes that the name of the device is
79
** /dev/datum. You will need to make a soft link to your RS232 device or
80
** create a new driver to use this refclock.
81
*/
82
83
/*
84
** Datum PTS defines
85
*/
86
87
/*
88
** Note that if GMT is defined, then the Datum PTS must use Greenwich
89
** time. Otherwise, this driver allows the Datum PTS to use the current
90
** wall clock for its time. It determines the time zone offset by minimizing
91
** the error after trying several time zone offsets. If the Datum PTS
92
** time is Greenwich time and GMT is not defined, everything should still
93
** work since the time zone will be found to be 0. What this really means
94
** is that your system time (at least to start with) must be within the
95
** correct time by less than +- 30 minutes. The default is for GMT to not
96
** defined. If you really want to force GMT without the funny +- 30 minute
97
** stuff then you must define (uncomment) GMT below.
98
*/
99
100
/*
101
#define GMT
102
#define DEBUG_DATUM_PTC
103
#define LOG_TIME_ERRORS
104
*/
105
106
107
#define PRECISION (-10)   /* precision assumed 1/1024 ms */
108
#define REFID "DATM"      /* reference id */
109
#define DATUM_DISPERSION 0    /* fixed dispersion = 0 ms */
110
0
#define DATUM_MAX_ERROR 0.100    /* limits on sigma squared */
111
0
#define DATUM_DEV "/dev/datum"  /* device name */
112
113
0
#define DATUM_MAX_ERROR2 (DATUM_MAX_ERROR*DATUM_MAX_ERROR)
114
115
/*
116
** The Datum PTS structure
117
*/
118
119
/*
120
** I don't use a fixed array of MAXUNITS like everyone else just because
121
** I don't like to program that way. Sorry if this bothers anyone. I assume
122
** that you can use any id for your unit and I will search for it in a
123
** dynamic array of units until I find it. I was worried that users might
124
** enter a bad id in their configuration file (larger than MAXUNITS) and
125
** besides, it is just cleaner not to have to assume that you have a fixed
126
** number of anything in a program.
127
*/
128
129
struct datum_pts_unit {
130
  struct peer *peer;    /* peer used by ntp */
131
  int PTS_fd;     /* file descriptor for PTS */
132
  u_int unit;     /* id for unit */
133
  u_long timestarted;   /* time started */
134
  l_fp lastrec;     /* time tag for the receive time (system) */
135
  l_fp lastref;     /* reference time (Datum time) */
136
  u_long yearstart;   /* the year that this clock started */
137
  int coderecv;     /* number of time codes received */
138
  int day;      /* day */
139
  int hour;     /* hour */
140
  int minute;     /* minutes */
141
  int second;     /* seconds */
142
  int msec;     /* miliseconds */
143
  int usec;     /* miliseconds */
144
  u_char leap;      /* funny leap character code */
145
  char retbuf[8];   /* returned time from the datum pts */
146
  char nbytes;      /* number of bytes received from datum pts */ 
147
  double sigma2;    /* average squared error (roughly) */
148
  int tzoff;      /* time zone offest from GMT */
149
};
150
151
/*
152
** PTS static constant variables for internal use
153
*/
154
155
static char TIME_REQUEST[6];  /* request message sent to datum for time */
156
static int nunits;    /* number of active units */
157
158
/*
159
** Callback function prototypes that ntpd needs to know about.
160
*/
161
162
static  int datum_pts_start   (int, struct peer *);
163
static  void  datum_pts_shutdown  (int, struct peer *);
164
static  void  datum_pts_poll    (int, struct peer *);
165
static  void  datum_pts_control (int, const struct refclockstat *,
166
           struct refclockstat *, struct peer *);
167
static  void  datum_pts_init    (void);
168
static  void  datum_pts_buginfo (int, struct refclockbug *, struct peer *);
169
170
/*
171
** This is the call back function structure that ntpd actually uses for
172
** this refclock.
173
*/
174
175
struct  refclock refclock_datum = {
176
  datum_pts_start,    /* start up a new Datum refclock */
177
  datum_pts_shutdown,   /* shutdown a Datum refclock */
178
  datum_pts_poll,   /* sends out the time request */
179
  datum_pts_control,    /* not used */
180
  datum_pts_init,   /* initialization (called first) */
181
  datum_pts_buginfo,    /* not used */
182
  NOFLAGS     /* we are not setting any special flags */
183
};
184
185
/*
186
** The datum_pts_receive callback function is handled differently from the
187
** rest. It is passed to the ntpd io data structure. Basically, every
188
** 64 seconds, the datum_pts_poll() routine is called. It sends out the time
189
** request message to the Datum Programmable Time System. Then, ntpd
190
** waits on a select() call to receive data back. The datum_pts_receive()
191
** function is called as data comes back. We expect a seven byte time
192
** code to be returned but the datum_pts_receive() function may only get
193
** a few bytes passed to it at a time. In other words, this routine may
194
** get called by the io stuff in ntpd a few times before we get all seven
195
** bytes. Once the last byte is received, we process it and then pass the
196
** new time measurement to ntpd for updating the system time. For now,
197
** there is no 3 state filtering done on the time measurements. The
198
** jitter may be a little high but at least for its current use, it is not
199
** a problem. We have tried to keep things as simple as possible. This
200
** clock should not jitter more than 1 or 2 mseconds at the most once
201
** things settle down. It is important to get the right drift calibrated
202
** in the ntpd.drift file as well as getting the right tick set up right
203
** using tickadj for SUNs. Tickadj is not used for the HP but you need to
204
** remember to bring up the adjtime daemon because HP does not support
205
** the adjtime() call.
206
*/
207
208
static  void  datum_pts_receive (struct recvbuf *);
209
210
/*......................................................................*/
211
/*  datum_pts_start - start up the datum PTS. This means open the */
212
/*  RS232 device and set up the data structure for my unit.   */
213
/*......................................................................*/
214
215
static int
216
datum_pts_start(
217
  int unit,
218
  struct peer *peer
219
  )
220
0
{
221
0
  struct refclockproc *pp;
222
0
  struct datum_pts_unit *datum_pts;
223
0
  int fd;
224
0
#ifdef HAVE_TERMIOS
225
0
  int rc;
226
0
  struct termios arg;
227
0
#endif
228
229
#ifdef DEBUG_DATUM_PTC
230
  if (debug)
231
      printf("Starting Datum PTS unit %d\n", unit);
232
#endif
233
234
  /*
235
  ** Open the Datum PTS device
236
  */
237
0
  fd = open(DATUM_DEV, O_RDWR);
238
239
0
  if (fd < 0) {
240
0
    msyslog(LOG_ERR, "Datum_PTS: open(\"%s\", O_RDWR) failed: %m", DATUM_DEV);
241
0
    return 0;
242
0
  }
243
244
  /*
245
  ** Create the memory for the new unit
246
  */
247
0
  datum_pts = emalloc_zero(sizeof(*datum_pts));
248
0
  datum_pts->unit = unit; /* set my unit id */
249
0
  datum_pts->yearstart = 0; /* initialize the yearstart to 0 */
250
0
  datum_pts->sigma2 = 0.0;  /* initialize the sigma2 to 0 */
251
252
0
  datum_pts->PTS_fd = fd;
253
254
0
  if (-1 == fcntl(datum_pts->PTS_fd, F_SETFL, 0)) /* clear the descriptor flags */
255
0
    msyslog(LOG_ERR, "MSF_ARCRON(%d): fcntl(F_SETFL, 0): %m.",
256
0
      unit);
257
258
#ifdef DEBUG_DATUM_PTC
259
  if (debug)
260
      printf("Opening RS232 port with file descriptor %d\n",
261
       datum_pts->PTS_fd);
262
#endif
263
264
  /*
265
  ** Set up the RS232 terminal device information. Note that we assume that
266
  ** we have termios. This code has only been tested on SUNs and HPs. If your
267
  ** machine does not have termios this driver cannot be initialized. You can change this
268
  ** if you want by editing this source. Please give the changes back to the
269
  ** ntp folks so that it can become part of their regular distribution.
270
  */
271
272
0
  memset(&arg, 0, sizeof(arg));
273
274
0
  arg.c_iflag = IGNBRK;
275
0
  arg.c_oflag = 0;
276
0
  arg.c_cflag = B9600 | CS8 | CREAD | PARENB | CLOCAL;
277
0
  arg.c_lflag = 0;
278
0
  arg.c_cc[VMIN] = 0;   /* start timeout timer right away (not used) */
279
0
  arg.c_cc[VTIME] = 30;   /* 3 second timout on reads (not used) */
280
281
0
  rc = tcsetattr(datum_pts->PTS_fd, TCSANOW, &arg);
282
0
  if (rc < 0) {
283
0
    msyslog(LOG_ERR, "Datum_PTS: tcsetattr(\"%s\") failed: %m", DATUM_DEV);
284
0
    close(datum_pts->PTS_fd);
285
0
    free(datum_pts);
286
0
    return 0;
287
0
  }
288
289
  /*
290
  ** Initialize the ntpd IO structure
291
  */
292
293
0
  datum_pts->peer = peer;
294
0
  pp = peer->procptr;
295
0
  pp->io.clock_recv = datum_pts_receive;
296
0
  pp->io.srcclock = peer;
297
0
  pp->io.datalen = 0;
298
0
  pp->io.fd = datum_pts->PTS_fd;
299
300
0
  if (!io_addclock(&pp->io)) {
301
0
    pp->io.fd = -1;
302
#ifdef DEBUG_DATUM_PTC
303
    if (debug)
304
        printf("Problem adding clock\n");
305
#endif
306
307
0
    msyslog(LOG_ERR, "Datum_PTS: Problem adding clock");
308
0
    close(datum_pts->PTS_fd);
309
0
    free(datum_pts);
310
311
0
    return 0;
312
0
  }
313
0
  peer->procptr->unitptr = datum_pts;
314
315
  /*
316
  ** Now add one to the number of units and return a successful code
317
  */
318
319
0
  nunits++;
320
0
  return 1;
321
322
0
}
323
324
325
/*......................................................................*/
326
/*  datum_pts_shutdown - this routine shuts doen the device and */
327
/*  removes the memory for the unit.        */
328
/*......................................................................*/
329
330
static void
331
datum_pts_shutdown(
332
  int unit,
333
  struct peer *peer
334
  )
335
0
{
336
0
  struct refclockproc *pp;
337
0
  struct datum_pts_unit *datum_pts;
338
339
#ifdef DEBUG_DATUM_PTC
340
  if (debug)
341
      printf("Shutdown Datum PTS\n");
342
#endif
343
344
0
  msyslog(LOG_ERR, "Datum_PTS: Shutdown Datum PTS");
345
346
  /*
347
  ** We found the unit so close the file descriptor and free up the memory used
348
  ** by the structure.
349
  */
350
0
  pp = peer->procptr;
351
0
  datum_pts = pp->unitptr;
352
0
  if (NULL != datum_pts) {
353
0
    io_closeclock(&pp->io);
354
0
    free(datum_pts);
355
0
  }
356
0
}
357
358
359
/*......................................................................*/
360
/*  datum_pts_poll - this routine sends out the time request to the */
361
/*  Datum PTS device. The time will be passed back in the     */
362
/*  datum_pts_receive() routine.          */
363
/*......................................................................*/
364
365
static void
366
datum_pts_poll(
367
  int unit,
368
  struct peer *peer
369
  )
370
0
{
371
0
  int error_code;
372
0
  struct datum_pts_unit *datum_pts;
373
374
0
  datum_pts = peer->procptr->unitptr;
375
376
#ifdef DEBUG_DATUM_PTC
377
  if (debug)
378
      printf("Poll Datum PTS\n");
379
#endif
380
381
  /*
382
  ** Find the right unit and send out a time request once it is found.
383
  */
384
0
  error_code = write(datum_pts->PTS_fd, TIME_REQUEST, 6);
385
0
  if (error_code != 6)
386
0
    perror("TIME_REQUEST");
387
0
  datum_pts->nbytes = 0;
388
0
}
389
390
391
/*......................................................................*/
392
/*  datum_pts_control - not used          */
393
/*......................................................................*/
394
395
static void
396
datum_pts_control(
397
  int unit,
398
  const struct refclockstat *in,
399
  struct refclockstat *out,
400
  struct peer *peer
401
  )
402
0
{
403
404
#ifdef DEBUG_DATUM_PTC
405
  if (debug)
406
      printf("Control Datum PTS\n");
407
#endif
408
409
0
}
410
411
412
/*......................................................................*/
413
/*  datum_pts_init - initializes things for all possible Datum  */
414
/*  time code generators that might be used. In practice, this is */
415
/*  only called once at the beginning before anything else is */
416
/*  called.               */
417
/*......................................................................*/
418
419
static void
420
datum_pts_init(void)
421
0
{
422
423
  /*                  */
424
  /*...... open up the log file if we are debugging ......................*/
425
  /*                  */
426
427
  /*
428
  ** Open up the log file if we are debugging. For now, send data out to the
429
  ** screen (stdout).
430
  */
431
432
#ifdef DEBUG_DATUM_PTC
433
  if (debug)
434
      printf("Init Datum PTS\n");
435
#endif
436
437
  /*
438
  ** Initialize the time request command string. This is the only message
439
  ** that we ever have to send to the Datum PTS (although others are defined).
440
  */
441
442
0
  memcpy(TIME_REQUEST, "//k/mn",6);
443
444
  /*
445
  ** Initialize the number of units to 0 and set the dynamic array of units to
446
  ** NULL since there are no units defined yet.
447
  */
448
449
0
  nunits = 0;
450
451
0
}
452
453
454
/*......................................................................*/
455
/*  datum_pts_buginfo - not used          */
456
/*......................................................................*/
457
458
static void
459
datum_pts_buginfo(
460
  int unit,
461
  register struct refclockbug *bug,
462
  register struct peer *peer
463
  )
464
0
{
465
466
#ifdef DEBUG_DATUM_PTC
467
  if (debug)
468
      printf("Buginfo Datum PTS\n");
469
#endif
470
471
0
}
472
473
474
/*......................................................................*/
475
/*  datum_pts_receive - receive the time buffer that was read in  */
476
/*  by the ntpd io handling routines. When 7 bytes have been  */
477
/*  received (it may take several tries before all 7 bytes are  */
478
/*  received), then the time code must be unpacked and sent to  */
479
/*  the ntpd clock_receive() routine which causes the systems */
480
/*  clock to be updated (several layers down).      */
481
/*......................................................................*/
482
483
static void
484
datum_pts_receive(
485
  struct recvbuf *rbufp
486
  )
487
0
{
488
0
  int i;
489
0
  size_t nb;
490
0
  l_fp tstmp;
491
0
  struct peer *p;
492
0
  struct datum_pts_unit *datum_pts;
493
0
  char *dpt;
494
0
  int dpend;
495
0
  int tzoff;
496
0
  int timerr;
497
0
  double ftimerr, abserr;
498
#ifdef DEBUG_DATUM_PTC
499
  double dispersion;
500
#endif
501
0
  int goodtime;
502
      /*double doffset;*/
503
504
  /*
505
  ** Get the time code (maybe partial) message out of the rbufp buffer.
506
  */
507
508
0
  p = rbufp->recv_peer;
509
0
  datum_pts = p->procptr->unitptr;
510
0
  dpt = (char *)&rbufp->recv_space;
511
0
  dpend = rbufp->recv_length;
512
513
#ifdef DEBUG_DATUM_PTC
514
  if (debug)
515
    printf("Receive Datum PTS: %d bytes\n", dpend);
516
#endif
517
518
  /*                  */
519
  /*...... save the ntp system time when the first byte is received ......*/
520
  /*                  */
521
522
  /*
523
  ** Save the ntp system time when the first byte is received. Note that
524
  ** because it may take several calls to this routine before all seven
525
  ** bytes of our return message are finally received by the io handlers in
526
  ** ntpd, we really do want to use the time tag when the first byte is
527
  ** received to reduce the jitter.
528
  */
529
530
0
  nb = datum_pts->nbytes;
531
0
  if (nb == 0) {
532
0
    datum_pts->lastrec = rbufp->recv_time;
533
0
  }
534
535
  /*
536
  ** Increment our count to the number of bytes received so far. Return if we
537
  ** haven't gotten all seven bytes yet.
538
  ** [Sec 3388] make sure we do not overrun the buffer.
539
  ** TODO: what to do with excessive bytes, if we ever get them?
540
  */
541
0
  for (i=0; (i < dpend) && (nb < sizeof(datum_pts->retbuf)); i++, nb++) {
542
0
    datum_pts->retbuf[nb] = dpt[i];
543
0
  }
544
0
  datum_pts->nbytes = nb;
545
  
546
0
  if (nb < 7) {
547
0
    return;
548
0
  }
549
550
  /*
551
  ** Convert the seven bytes received in our time buffer to day, hour, minute,
552
  ** second, and msecond values. The usec value is not used for anything
553
  ** currently. It is just the fractional part of the time stored in units
554
  ** of microseconds.
555
  */
556
557
0
  datum_pts->day =  100*(datum_pts->retbuf[0] & 0x0f) +
558
0
    10*((datum_pts->retbuf[1] & 0xf0)>>4) +
559
0
    (datum_pts->retbuf[1] & 0x0f);
560
561
0
  datum_pts->hour = 10*((datum_pts->retbuf[2] & 0x30)>>4) +
562
0
    (datum_pts->retbuf[2] & 0x0f);
563
564
0
  datum_pts->minute = 10*((datum_pts->retbuf[3] & 0x70)>>4) +
565
0
    (datum_pts->retbuf[3] & 0x0f);
566
567
0
  datum_pts->second = 10*((datum_pts->retbuf[4] & 0x70)>>4) +
568
0
    (datum_pts->retbuf[4] & 0x0f);
569
570
0
  datum_pts->msec = 100*((datum_pts->retbuf[5] & 0xf0) >> 4) + 
571
0
    10*(datum_pts->retbuf[5] & 0x0f) +
572
0
    ((datum_pts->retbuf[6] & 0xf0)>>4);
573
574
0
  datum_pts->usec = 1000*datum_pts->msec;
575
576
#ifdef DEBUG_DATUM_PTC
577
  if (debug)
578
      printf("day %d, hour %d, minute %d, second %d, msec %d\n",
579
       datum_pts->day,
580
       datum_pts->hour,
581
       datum_pts->minute,
582
       datum_pts->second,
583
       datum_pts->msec);
584
#endif
585
586
  /*
587
  ** Get the GMT time zone offset. Note that GMT should be zero if the Datum
588
  ** reference time is using GMT as its time base. Otherwise we have to
589
  ** determine the offset if the Datum PTS is using time of day as its time
590
  ** base.
591
  */
592
593
0
  goodtime = 0;   /* We are not sure about the time and offset yet */
594
595
0
#ifdef GMT
596
597
  /*
598
  ** This is the case where the Datum PTS is using GMT so there is no time
599
  ** zone offset.
600
  */
601
602
0
  tzoff = 0;    /* set time zone offset to 0 */
603
604
#else
605
606
  /*
607
  ** This is the case where the Datum PTS is using regular time of day for its
608
  ** time so we must compute the time zone offset. The way we do it is kind of
609
  ** funny but it works. We loop through different time zones (0 to 24) and
610
  ** pick the one that gives the smallest error (+- one half hour). The time
611
  ** zone offset is stored in the datum_pts structure for future use. Normally,
612
  ** the clocktime() routine is only called once (unless the time zone offset
613
  ** changes due to daylight savings) since the goodtime flag is set when a
614
  ** good time is found (with a good offset). Note that even if the Datum
615
  ** PTS is using GMT, this mechanism will still work since it should come up
616
  ** with a value for tzoff = 0 (assuming that your system clock is within
617
  ** a half hour of the Datum time (even with time zone differences).
618
  */
619
620
  for (tzoff=0; tzoff<24; tzoff++) {
621
    if (clocktime( datum_pts->day,
622
             datum_pts->hour,
623
             datum_pts->minute,
624
             datum_pts->second,
625
             (tzoff + datum_pts->tzoff) % 24,
626
             datum_pts->lastrec.l_ui,
627
             &datum_pts->yearstart,
628
             &datum_pts->lastref.l_ui) ) {
629
630
      datum_pts->lastref.l_uf = 0;
631
      error = datum_pts->lastref.l_ui - datum_pts->lastrec.l_ui;
632
633
#ifdef DEBUG_DATUM_PTC
634
      printf("Time Zone (clocktime method) = %d, error = %d\n", tzoff, error);
635
#endif
636
637
      if ((error < 1799) && (error > -1799)) {
638
        tzoff = (tzoff + datum_pts->tzoff) % 24;
639
        datum_pts->tzoff = tzoff;
640
        goodtime = 1;
641
642
#ifdef DEBUG_DATUM_PTC
643
        printf("Time Zone found (clocktime method) = %d\n",tzoff);
644
#endif
645
646
        break;
647
      }
648
649
    }
650
  }
651
652
#endif
653
654
  /*
655
  ** Make sure that we have a good time from the Datum PTS. Clocktime() also
656
  ** sets yearstart and lastref.l_ui. We will have to set astref.l_uf (i.e.,
657
  ** the fraction of a second) stuff later.
658
  */
659
660
0
  if (!goodtime) {
661
662
0
    if (!clocktime( datum_pts->day,
663
0
        datum_pts->hour,
664
0
        datum_pts->minute,
665
0
        datum_pts->second,
666
0
        tzoff,
667
0
        datum_pts->lastrec.l_ui,
668
0
        &datum_pts->yearstart,
669
0
        &datum_pts->lastref.l_ui) ) {
670
671
#ifdef DEBUG_DATUM_PTC
672
      if (debug)
673
      {
674
        printf("Error: bad clocktime\n");
675
        printf("GMT %d, lastrec %d, yearstart %d, lastref %d\n",
676
               tzoff,
677
               datum_pts->lastrec.l_ui,
678
               datum_pts->yearstart,
679
               datum_pts->lastref.l_ui);
680
      }
681
#endif
682
683
0
      msyslog(LOG_ERR, "Datum_PTS: Bad clocktime");
684
685
0
      return;
686
687
0
    }else{
688
689
#ifdef DEBUG_DATUM_PTC
690
      if (debug)
691
          printf("Good clocktime\n");
692
#endif
693
694
0
    }
695
696
0
  }
697
698
  /*
699
  ** We have datum_pts->lastref.l_ui set (which is the integer part of the
700
  ** time. Now set the microseconds field.
701
  */
702
703
0
  TVUTOTSF(datum_pts->usec, datum_pts->lastref.l_uf);
704
705
  /*
706
  ** Compute the time correction as the difference between the reference
707
  ** time (i.e., the Datum time) minus the receive time (system time).
708
  */
709
710
0
  tstmp = datum_pts->lastref;   /* tstmp is the datum ntp time */
711
0
  L_SUB(&tstmp, &datum_pts->lastrec);  /* tstmp is now the correction */
712
0
  datum_pts->coderecv++;    /* increment a counter */
713
714
#ifdef DEBUG_DATUM_PTC
715
  dispersion = DATUM_DISPERSION;  /* set the dispersion to 0 */
716
  ftimerr = dispersion;
717
  ftimerr /= (1024.0 * 64.0);
718
  if (debug)
719
      printf("dispersion = %d, %f\n", dispersion, ftimerr);
720
#endif
721
722
  /*
723
  ** Pass the new time to ntpd through the refclock_receive function. Note
724
  ** that we are not trying to make any corrections due to the time it takes
725
  ** for the Datum PTS to send the message back. I am (erroneously) assuming
726
  ** that the time for the Datum PTS to send the time back to us is negligable.
727
  ** I suspect that this time delay may be as much as 15 ms or so (but probably
728
  ** less). For our needs at JPL, this kind of error is ok so it is not
729
  ** necessary to use fudge factors in the ntp.conf file. Maybe later we will.
730
  */
731
      /*LFPTOD(&tstmp, doffset);*/
732
0
  datum_pts->lastref = datum_pts->lastrec;
733
0
  refclock_receive(datum_pts->peer);
734
735
  /*
736
  ** Compute sigma squared (not used currently). Maybe later, this could be
737
  ** used for the dispersion estimate. The problem is that ntpd does not link
738
  ** in the math library so sqrt() is not available. Anyway, this is useful
739
  ** for debugging. Maybe later I will just use absolute values for the time
740
  ** error to come up with my dispersion estimate. Anyway, for now my dispersion
741
  ** is set to 0.
742
  */
743
744
0
  timerr = tstmp.l_ui<<20;
745
0
  timerr |= (tstmp.l_uf>>12) & 0x000fffff;
746
0
  ftimerr = timerr;
747
0
  ftimerr /= 1024*1024;
748
0
  abserr = ftimerr;
749
0
  if (ftimerr < 0.0) abserr = -ftimerr;
750
751
0
  if (datum_pts->sigma2 == 0.0) {
752
0
    if (abserr < DATUM_MAX_ERROR) {
753
0
      datum_pts->sigma2 = abserr*abserr;
754
0
    }else{
755
0
      datum_pts->sigma2 = DATUM_MAX_ERROR2;
756
0
    }
757
0
  }else{
758
0
    if (abserr < DATUM_MAX_ERROR) {
759
0
      datum_pts->sigma2 = 0.95*datum_pts->sigma2 + 0.05*abserr*abserr;
760
0
    }else{
761
0
      datum_pts->sigma2 = 0.95*datum_pts->sigma2 + 0.05*DATUM_MAX_ERROR2;
762
0
    }
763
0
  }
764
765
#ifdef DEBUG_DATUM_PTC
766
  if (debug)
767
      printf("Time error = %f seconds\n", ftimerr);
768
#endif
769
770
#if defined(DEBUG_DATUM_PTC) || defined(LOG_TIME_ERRORS)
771
  if (debug)
772
      printf("PTS: day %d, hour %d, minute %d, second %d, msec %d, Time Error %f\n",
773
       datum_pts->day,
774
       datum_pts->hour,
775
       datum_pts->minute,
776
       datum_pts->second,
777
       datum_pts->msec,
778
       ftimerr);
779
#endif
780
781
0
}
782
#else
783
NONEMPTY_TRANSLATION_UNIT
784
#endif /* REFCLOCK */