Coverage Report

Created: 2023-05-19 06:16

/src/ntp-dev/ntpd/refclock_arc.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * refclock_arc - clock driver for ARCRON MSF/DCF/WWVB receivers
3
 */
4
5
#ifdef HAVE_CONFIG_H
6
#include <config.h>
7
#endif
8
9
#include "ntp_types.h"
10
11
#if defined(REFCLOCK) && defined(CLOCK_ARCRON_MSF)
12
13
static const char arc_version[] = { "V1.3 2003/02/21" };
14
15
/* define PRE_NTP420 for compatibility to previous versions of NTP (at least
16
   to 4.1.0 */
17
#undef PRE_NTP420
18
19
#ifndef ARCRON_NOT_KEEN
20
#define ARCRON_KEEN 1 /* Be keen, and trusting of the clock, if defined. */
21
#endif
22
23
#ifndef ARCRON_NOT_MULTIPLE_SAMPLES
24
#define ARCRON_MULTIPLE_SAMPLES 1 /* Use all timestamp bytes as samples. */
25
#endif
26
27
#ifndef ARCRON_NOT_LEAPSECOND_KEEN
28
#ifndef ARCRON_LEAPSECOND_KEEN
29
#undef ARCRON_LEAPSECOND_KEEN /* Respond quickly to leap seconds: doesn't work yet. */
30
#endif
31
#endif
32
33
/*
34
Code by Derek Mulcahy, <derek@toybox.demon.co.uk>, 1997.
35
Modifications by Damon Hart-Davis, <d@hd.org>, 1997.
36
Modifications by Paul Alfille, <palfille@partners.org>, 2003.
37
Modifications by Christopher Price, <cprice@cs-home.com>, 2003.
38
Modifications by Nigel Roles <nigel@9fs.org>, 2003.
39
40
41
THIS CODE IS SUPPLIED AS IS, WITH NO WARRANTY OF ANY KIND.  USE AT
42
YOUR OWN RISK.
43
44
Orginally developed and used with ntp3-5.85 by Derek Mulcahy.
45
46
Built against ntp3-5.90 on Solaris 2.5 using gcc 2.7.2.
47
48
This code may be freely copied and used and incorporated in other
49
systems providing the disclaimer and notice of authorship are
50
reproduced.
51
52
-------------------------------------------------------------------------------
53
54
Nigel's notes:
55
56
1) Called tcgetattr() before modifying, so that fields correctly initialised
57
   for all operating systems
58
59
2) Altered parsing of timestamp line so that it copes with fields which are
60
   not always ASCII digits (e.g. status field when battery low)
61
62
-------------------------------------------------------------------------------
63
64
Christopher's notes:
65
66
MAJOR CHANGES SINCE V1.2 
67
========================
68
 1) Applied patch by Andrey Bray <abuse@madhouse.demon.co.uk>
69
    2001-02-17 comp.protocols.time.ntp
70
71
 2) Added WWVB support via clock mode command, localtime/UTC time configured
72
    via flag1=(0=UTC, 1=localtime)
73
74
 3) Added ignore resync request via flag2=(0=resync, 1=ignore resync)
75
76
 4) Added simplified conversion from localtime to UTC with dst/bst translation
77
78
 5) Added average signal quality poll
79
80
 6) Fixed a badformat error when no code is available due to stripping 
81
    \n & \r's 
82
83
 7) Fixed a badformat error when clearing lencode & memset a_lastcode in poll
84
    routine
85
86
 8) Lots of code cleanup, including standardized DEBUG macros and removal 
87
    of unused code 
88
89
-------------------------------------------------------------------------------
90
91
Author's original note:
92
93
I enclose my ntp driver for the Galleon Systems Arc MSF receiver.
94
95
It works (after a fashion) on both Solaris-1 and Solaris-2.
96
97
I am currently using ntp3-5.85.  I have been running the code for
98
about 7 months without any problems.  Even coped with the change to BST!
99
100
I had to do some funky things to read from the clock because it uses the
101
power from the receive lines to drive the transmit lines.  This makes the
102
code look a bit stupid but it works.  I also had to put in some delays to
103
allow for the turnaround time from receive to transmit.  These delays
104
are between characters when requesting a time stamp so that shouldn't affect
105
the results too drastically.
106
107
...
108
109
The bottom line is that it works but could easily be improved.  You are
110
free to do what you will with the code.  I haven't been able to determine
111
how good the clock is.  I think that this requires a known good clock
112
to compare it against.
113
114
-------------------------------------------------------------------------------
115
116
Damon's notes for adjustments:
117
118
MAJOR CHANGES SINCE V1.0
119
========================
120
 1) Removal of pollcnt variable that made the clock go permanently
121
    off-line once two time polls failed to gain responses.
122
123
 2) Avoiding (at least on Solaris-2) terminal becoming the controlling
124
    terminal of the process when we do a low-level open().
125
126
 3) Additional logic (conditional on ARCRON_LEAPSECOND_KEEN being
127
    defined) to try to resync quickly after a potential leap-second
128
    insertion or deletion.
129
130
 4) Code significantly slimmer at run-time than V1.0.
131
132
133
GENERAL
134
=======
135
136
 1) The C preprocessor symbol to have the clock built has been changed
137
    from ARC to ARCRON_MSF to CLOCK_ARCRON_MSF to minimise the
138
    possiblity of clashes with other symbols in the future.
139
140
 2) PRECISION should be -4/-5 (63ms/31ms) for the following reasons:
141
142
     a) The ARC documentation claims the internal clock is (only)
143
  accurate to about 20ms relative to Rugby (plus there must be
144
  noticable drift and delay in the ms range due to transmission
145
  delays and changing atmospheric effects).  This clock is not
146
  designed for ms accuracy as NTP has spoilt us all to expect.
147
148
     b) The clock oscillator looks like a simple uncompensated quartz
149
  crystal of the sort used in digital watches (ie 32768Hz) which
150
  can have large temperature coefficients and drifts; it is not
151
  clear if this oscillator is properly disciplined to the MSF
152
  transmission, but as the default is to resync only once per
153
  *day*, we can imagine that it is not, and is free-running.  We
154
  can minimise drift by resyncing more often (at the cost of
155
  reduced battery life), but drift/wander may still be
156
  significant.
157
158
     c) Note that the bit time of 3.3ms adds to the potential error in
159
  the the clock timestamp, since the bit clock of the serial link
160
  may effectively be free-running with respect to the host clock
161
  and the MSF clock.  Actually, the error is probably 1/16th of
162
  the above, since the input data is probably sampled at at least
163
  16x the bit rate.
164
165
    By keeping the clock marked as not very precise, it will have a
166
    fairly large dispersion, and thus will tend to be used as a
167
    `backup' time source and sanity checker, which this clock is
168
    probably ideal for.  For an isolated network without other time
169
    sources, this clock can probably be expected to provide *much*
170
    better than 1s accuracy, which will be fine.
171
172
    By default, PRECISION is set to -4, but experience, especially at a
173
    particular geographic location with a particular clock, may allow
174
    this to be altered to -5.  (Note that skews of +/- 10ms are to be
175
    expected from the clock from time-to-time.)  This improvement of
176
    reported precision can be instigated by setting flag3 to 1, though
177
    the PRECISION will revert to the normal value while the clock
178
    signal quality is unknown whatever the flag3 setting.
179
180
    IN ANY CASE, BE SURE TO SET AN APPROPRIATE FUDGE FACTOR TO REMOVE
181
    ANY RESIDUAL SKEW, eg:
182
183
  server 127.127.27.0 # ARCRON MSF radio clock unit 0.
184
  # Fudge timestamps by about 20ms.
185
  fudge 127.127.27.0 time1 0.020
186
187
    You will need to observe your system's behaviour, assuming you have
188
    some other NTP source to compare it with, to work out what the
189
    fudge factor should be.  For my Sun SS1 running SunOS 4.1.3_U1 with
190
    my MSF clock with my distance from the MSF transmitter, +20ms
191
    seemed about right, after some observation.
192
193
 3) REFID has been made "MSFa" to reflect the MSF time source and the
194
    ARCRON receiver.
195
196
 4) DEFAULT_RESYNC_TIME is the time in seconds (by default) before
197
    forcing a resync since the last attempt.  This is picked to give a
198
    little less than an hour between resyncs and to try to avoid
199
    clashing with any regular event at a regular time-past-the-hour
200
    which might cause systematic errors.
201
202
    The INITIAL_RESYNC_DELAY is to avoid bothering the clock and
203
    running down its batteries unnecesarily if ntpd is going to crash
204
    or be killed or reconfigured quickly.  If ARCRON_KEEN is defined
205
    then this period is long enough for (with normal polling rates)
206
    enough time samples to have been taken to allow ntpd to sync to
207
    the clock before the interruption for the clock to resync to MSF.
208
    This avoids ntpd syncing to another peer first and then
209
    almost immediately hopping to the MSF clock.
210
211
    The RETRY_RESYNC_TIME is used before rescheduling a resync after a
212
    resync failed to reveal a statisfatory signal quality (too low or
213
    unknown).
214
215
 5) The clock seems quite jittery, so I have increased the
216
    median-filter size from the typical (previous) value of 3.  I
217
    discard up to half the results in the filter.  It looks like maybe
218
    1 sample in 10 or so (maybe less) is a spike, so allow the median
219
    filter to discard at least 10% of its entries or 1 entry, whichever
220
    is greater.
221
222
 6) Sleeping *before* each character sent to the unit to allow required
223
    inter-character time but without introducting jitter and delay in
224
    handling the response if possible.
225
226
 7) If the flag ARCRON_KEEN is defined, take time samples whenever
227
    possible, even while resyncing, etc.  We rely, in this case, on the
228
    clock always giving us a reasonable time or else telling us in the
229
    status byte at the end of the timestamp that it failed to sync to
230
    MSF---thus we should never end up syncing to completely the wrong
231
    time.
232
233
 8) If the flag ARCRON_OWN_FILTER is defined, use own versions of
234
    refclock median-filter routines to get round small bug in 3-5.90
235
    code which does not return the median offset. XXX Removed this
236
    bit due NTP Version 4 upgrade - dlm.
237
238
 9) We would appear to have a year-2000 problem with this clock since
239
    it returns only the two least-significant digits of the year.  But
240
    ntpd ignores the year and uses the local-system year instead, so
241
    this is in fact not a problem.  Nevertheless, we attempt to do a
242
    sensible thing with the dates, wrapping them into a 100-year
243
    window.
244
245
 10)Logs stats information that can be used by Derek's Tcl/Tk utility
246
    to show the status of the clock.
247
248
 11)The clock documentation insists that the number of bits per
249
    character to be sent to the clock, and sent by it, is 11, including
250
    one start bit and two stop bits.  The data format is either 7+even
251
    or 8+none.
252
253
254
TO-DO LIST
255
==========
256
257
  * Eliminate use of scanf(), and maybe sprintf().
258
259
  * Allow user setting of resync interval to trade battery life for
260
    accuracy; maybe could be done via fudge factor or unit number.
261
262
  * Possibly note the time since the last resync of the MSF clock to
263
    MSF as the age of the last reference timestamp, ie trust the
264
    clock's oscillator not very much...
265
266
  * Add very slow auto-adjustment up to a value of +/- time2 to correct
267
    for long-term errors in the clock value (time2 defaults to 0 so the
268
    correction would be disabled by default).
269
270
  * Consider trying to use the tty_clk/ppsclock support.
271
272
  * Possibly use average or maximum signal quality reported during
273
    resync, rather than just the last one, which may be atypical.
274
275
*/
276
277
278
/* Notes for HKW Elektronik GmBH Radio clock driver */
279
/* Author Lyndon David, Sentinet Ltd, Feb 1997      */
280
/* These notes seem also to apply usefully to the ARCRON clock. */
281
282
/* The HKW clock module is a radio receiver tuned into the Rugby */
283
/* MSF time signal tranmitted on 60 kHz. The clock module connects */
284
/* to the computer via a serial line and transmits the time encoded */
285
/* in 15 bytes at 300 baud 7 bits two stop bits even parity */
286
287
/* Clock communications, from the datasheet */
288
/* All characters sent to the clock are echoed back to the controlling */
289
/* device. */
290
/* Transmit time/date information */
291
/* syntax ASCII o<cr> */
292
/* Character o may be replaced if neccesary by a character whose code */
293
/* contains the lowest four bits f(hex) eg */
294
/* syntax binary: xxxx1111 00001101 */
295
296
/* DHD note:
297
You have to wait for character echo + 10ms before sending next character.
298
*/
299
300
/* The clock replies to this command with a sequence of 15 characters */
301
/* which contain the complete time and a final <cr> making 16 characters */
302
/* in total. */
303
/* The RC computer clock will not reply immediately to this command because */
304
/* the start bit edge of the first reply character marks the beginning of */
305
/* the second. So the RC Computer Clock will reply to this command at the */
306
/* start of the next second */
307
/* The characters have the following meaning */
308
/* 1. hours tens   */
309
/* 2. hours units  */
310
/* 3. minutes tens */
311
/* 4. minutes units */
312
/* 5. seconds tens  */
313
/* 6. seconds units */
314
/* 7. day of week 1-monday 7-sunday */
315
/* 8. day of month tens */
316
/* 9. day of month units */
317
/* 10. month tens */
318
/* 11. month units */
319
/* 12. year tens */
320
/* 13. year units */
321
/* 14. BST/UTC status */
322
/*  bit 7 parity */
323
/*  bit 6 always 0 */
324
/*  bit 5 always 1 */
325
/*  bit 4 always 1 */
326
/*  bit 3 always 0 */
327
/*  bit 2 =1 if UTC is in effect, complementary to the BST bit */
328
/*  bit 1 =1 if BST is in effect, according to the BST bit     */
329
/*  bit 0 BST/UTC change impending bit=1 in case of change impending */
330
/* 15. status */
331
/*  bit 7 parity */
332
/*  bit 6 always 0 */
333
/*  bit 5 always 1 */
334
/*  bit 4 always 1 */
335
/*  bit 3 =1 if low battery is detected */
336
/*  bit 2 =1 if the very last reception attempt failed and a valid */
337
/*    time information already exists (bit0=1) */
338
/*    =0 if the last reception attempt was successful */
339
/*  bit 1 =1 if at least one reception since 2:30 am was successful */
340
/*    =0 if no reception attempt since 2:30 am was successful */
341
/*  bit 0 =1 if the RC Computer Clock contains valid time information */
342
/*    This bit is zero after reset and one after the first */
343
/*    successful reception attempt */
344
345
/* DHD note:
346
Also note g<cr> command which confirms that a resync is in progress, and
347
if so what signal quality (0--5) is available.
348
Also note h<cr> command which starts a resync to MSF signal.
349
*/
350
351
352
#include "ntpd.h"
353
#include "ntp_io.h"
354
#include "ntp_refclock.h"
355
#include "ntp_calendar.h"
356
#include "ntp_stdlib.h"
357
358
#include <stdio.h>
359
#include <ctype.h>
360
361
#if defined(HAVE_BSD_TTYS)
362
#include <sgtty.h>
363
#endif /* HAVE_BSD_TTYS */
364
365
#if defined(HAVE_SYSV_TTYS)
366
#include <termio.h>
367
#endif /* HAVE_SYSV_TTYS */
368
369
#if defined(HAVE_TERMIOS)
370
#include <termios.h>
371
#endif
372
373
/*
374
 * This driver supports the ARCRON MSF/DCF/WWVB Radio Controlled Clock
375
 */
376
377
/*
378
 * Interface definitions
379
 */
380
#define DEVICE    "/dev/arc%d"  /* Device name and unit. */
381
0
#define SPEED   B300    /* UART speed (300 baud) */
382
0
#define PRECISION (-4)    /* Precision  (~63 ms). */
383
0
#define HIGHPRECISION (-5)    /* If things are going well... */
384
0
#define REFID   "MSFa"    /* Reference ID. */
385
0
#define REFID_MSF "MSF"    /* Reference ID. */
386
0
#define REFID_DCF77 "DCF"    /* Reference ID. */
387
0
#define REFID_WWVB  "WWVB"    /* Reference ID. */
388
0
#define DESCRIPTION "ARCRON MSF/DCF/WWVB Receiver"
389
390
#ifdef PRE_NTP420
391
#define MODE ttlmax
392
#else
393
0
#define MODE ttl
394
#endif
395
396
0
#define LENARC    16    /* Format `o' timecode length. */
397
398
#define BITSPERCHAR 11    /* Bits per character. */
399
#define BITTIME   0x0DA740E /* Time for 1 bit at 300bps. */
400
#define CHARTIME10  0x8888888 /* Time for 10-bit char at 300bps. */
401
#define CHARTIME11  0x962FC96 /* Time for 11-bit char at 300bps. */
402
#define CHARTIME      /* Time for char at 300bps. */ \
403
( (BITSPERCHAR == 11) ? CHARTIME11 : ( (BITSPERCHAR == 10) ? CHARTIME10 : \
404
               (BITSPERCHAR * BITTIME) ) )
405
406
     /* Allow for UART to accept char half-way through final stop bit. */
407
#define INITIALOFFSET ((u_int32)(-BITTIME/2))
408
409
     /*
410
    charoffsets[x] is the time after the start of the second that byte
411
    x (with the first byte being byte 1) is received by the UART,
412
    assuming that the initial edge of the start bit of the first byte
413
    is on-time.  The values are represented as the fractional part of
414
    an l_fp.
415
416
    We store enough values to have the offset of each byte including
417
    the trailing \r, on the assumption that the bytes follow one
418
    another without gaps.
419
    */
420
     static const u_int32 charoffsets[LENARC+1] = {
421
#if BITSPERCHAR == 11 /* Usual case. */
422
       /* Offsets computed as accurately as possible... */
423
       0,
424
       INITIALOFFSET + 0x0962fc96, /*  1 chars,  11 bits */
425
       INITIALOFFSET + 0x12c5f92c, /*  2 chars,  22 bits */
426
       INITIALOFFSET + 0x1c28f5c3, /*  3 chars,  33 bits */
427
       INITIALOFFSET + 0x258bf259, /*  4 chars,  44 bits */
428
       INITIALOFFSET + 0x2eeeeeef, /*  5 chars,  55 bits */
429
       INITIALOFFSET + 0x3851eb85, /*  6 chars,  66 bits */
430
       INITIALOFFSET + 0x41b4e81b, /*  7 chars,  77 bits */
431
       INITIALOFFSET + 0x4b17e4b1, /*  8 chars,  88 bits */
432
       INITIALOFFSET + 0x547ae148, /*  9 chars,  99 bits */
433
       INITIALOFFSET + 0x5dddddde, /* 10 chars, 110 bits */
434
       INITIALOFFSET + 0x6740da74, /* 11 chars, 121 bits */
435
       INITIALOFFSET + 0x70a3d70a, /* 12 chars, 132 bits */
436
       INITIALOFFSET + 0x7a06d3a0, /* 13 chars, 143 bits */
437
       INITIALOFFSET + 0x8369d037, /* 14 chars, 154 bits */
438
       INITIALOFFSET + 0x8ccccccd, /* 15 chars, 165 bits */
439
       INITIALOFFSET + 0x962fc963  /* 16 chars, 176 bits */
440
#else
441
       /* Offsets computed with a small rounding error... */
442
       0,
443
       INITIALOFFSET +  1 * CHARTIME,
444
       INITIALOFFSET +  2 * CHARTIME,
445
       INITIALOFFSET +  3 * CHARTIME,
446
       INITIALOFFSET +  4 * CHARTIME,
447
       INITIALOFFSET +  5 * CHARTIME,
448
       INITIALOFFSET +  6 * CHARTIME,
449
       INITIALOFFSET +  7 * CHARTIME,
450
       INITIALOFFSET +  8 * CHARTIME,
451
       INITIALOFFSET +  9 * CHARTIME,
452
       INITIALOFFSET + 10 * CHARTIME,
453
       INITIALOFFSET + 11 * CHARTIME,
454
       INITIALOFFSET + 12 * CHARTIME,
455
       INITIALOFFSET + 13 * CHARTIME,
456
       INITIALOFFSET + 14 * CHARTIME,
457
       INITIALOFFSET + 15 * CHARTIME,
458
       INITIALOFFSET + 16 * CHARTIME
459
#endif
460
     };
461
462
0
#define DEFAULT_RESYNC_TIME  (57*60)  /* Gap between resync attempts (s). */
463
0
#define RETRY_RESYNC_TIME    (27*60)  /* Gap to emergency resync attempt. */
464
#ifdef ARCRON_KEEN
465
0
#define INITIAL_RESYNC_DELAY 500  /* Delay before first resync. */
466
#else
467
#define INITIAL_RESYNC_DELAY 50   /* Delay before first resync. */
468
#endif
469
470
     static const int moff[12] =
471
{ 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
472
/* Flags for a raw open() of the clock serial device. */
473
#ifdef O_NOCTTY /* Good, we can avoid tty becoming controlling tty. */
474
#define OPEN_FLAGS (O_RDWR | O_NOCTTY)
475
#else   /* Oh well, it may not matter... */
476
#define OPEN_FLAGS (O_RDWR)
477
#endif
478
479
480
/* Length of queue of command bytes to be sent. */
481
0
#define CMDQUEUELEN 4      /* Enough for two cmds + each \r. */
482
/* Queue tick time; interval in seconds between chars taken off queue. */
483
/* Must be >= 2 to allow o\r response to come back uninterrupted. */
484
0
#define QUEUETICK   2      /* Allow o\r reply to finish. */
485
486
/*
487
 * ARC unit control structure
488
 */
489
struct arcunit {
490
  l_fp lastrec;     /* Time tag for the receive time (system). */
491
  int status;     /* Clock status. */
492
493
  int quality;      /* Quality of reception 0--5 for unit. */
494
  /* We may also use the values -1 or 6 internally. */
495
  u_long quality_stamp; /* Next time to reset quality average. */
496
497
  u_long next_resync; /* Next resync time (s) compared to current_time. */
498
  int resyncing;      /* Resync in progress if true. */
499
500
  /* In the outgoing queue, cmdqueue[0] is next to be sent. */
501
  char cmdqueue[CMDQUEUELEN+1]; /* Queue of outgoing commands + \0. */
502
503
  u_long saved_flags; /* Saved fudge flags. */
504
};
505
506
#ifdef ARCRON_LEAPSECOND_KEEN
507
/* The flag `possible_leap' is set non-zero when any MSF unit
508
       thinks a leap-second may have happened.
509
510
       Set whenever we receive a valid time sample in the first hour of
511
       the first day of the first/seventh months.
512
513
       Outside the special hour this value is unconditionally set
514
       to zero by the receive routine.
515
516
       On finding itself in this timeslot, as long as the value is
517
       non-negative, the receive routine sets it to a positive value to
518
       indicate a resync to MSF should be performed.
519
520
       In the poll routine, if this value is positive and we are not
521
       already resyncing (eg from a sync that started just before
522
       midnight), start resyncing and set this value negative to
523
       indicate that a leap-triggered resync has been started.  Having
524
       set this negative prevents the receive routine setting it
525
       positive and thus prevents multiple resyncs during the witching
526
       hour.
527
     */
528
static int possible_leap = 0;       /* No resync required by default. */
529
#endif
530
531
#if 0
532
static void dummy_event_handler (struct peer *);
533
static void   arc_event_handler (struct peer *);
534
#endif /* 0 */
535
536
0
#define QUALITY_UNKNOWN     -1 /* Indicates unknown clock quality. */
537
#define MIN_CLOCK_QUALITY    0 /* Min quality clock will return. */
538
0
#define MIN_CLOCK_QUALITY_OK 3 /* Min quality for OK reception. */
539
0
#define MAX_CLOCK_QUALITY    5 /* Max quality clock will return. */
540
541
/*
542
 * Function prototypes
543
 */
544
static  int arc_start (int, struct peer *);
545
static  void  arc_shutdown  (int, struct peer *);
546
static  void  arc_receive (struct recvbuf *);
547
static  void  arc_poll  (int, struct peer *);
548
549
/*
550
 * Transfer vector
551
 */
552
struct  refclock refclock_arc = {
553
  arc_start,    /* start up driver */
554
  arc_shutdown,   /* shut down driver */
555
  arc_poll,   /* transmit poll message */
556
  noentry,    /* not used (old arc_control) */
557
  noentry,    /* initialize driver (not used) */
558
  noentry,    /* not used (old arc_buginfo) */
559
  NOFLAGS     /* not used */
560
};
561
562
/* Queue us up for the next tick. */
563
#define ENQUEUE(up) \
564
0
  do { \
565
0
       peer->procptr->nextaction = current_time + QUEUETICK; \
566
0
  } while(0)
567
568
/* Placeholder event handler---does nothing safely---soaks up loose tick. */
569
static void
570
dummy_event_handler(
571
  struct peer *peer
572
  )
573
0
{
574
0
#ifdef DEBUG
575
0
  if(debug) { printf("arc: dummy_event_handler() called.\n"); }
576
0
#endif
577
0
}
578
579
/*
580
Normal event handler.
581
582
Take first character off queue and send to clock if not a null.
583
584
Shift characters down and put a null on the end.
585
586
We assume that there is no parallelism so no race condition, but even
587
if there is nothing bad will happen except that we might send some bad
588
data to the clock once in a while.
589
*/
590
static void
591
arc_event_handler(
592
  struct peer *peer
593
  )
594
0
{
595
0
  struct refclockproc *pp = peer->procptr;
596
0
  register struct arcunit *up = pp->unitptr;
597
0
  int i;
598
0
  char c;
599
0
#ifdef DEBUG
600
0
  if(debug > 2) { printf("arc: arc_event_handler() called.\n"); }
601
0
#endif
602
603
0
  c = up->cmdqueue[0];       /* Next char to be sent. */
604
  /* Shift down characters, shifting trailing \0 in at end. */
605
0
  for(i = 0; i < CMDQUEUELEN; ++i)
606
0
  { up->cmdqueue[i] = up->cmdqueue[i+1]; }
607
608
  /* Don't send '\0' characters. */
609
0
  if(c != '\0') {
610
0
    if(write(pp->io.fd, &c, 1) != 1) {
611
0
      msyslog(LOG_NOTICE, "ARCRON: write to fd %d failed", pp->io.fd);
612
0
    }
613
0
#ifdef DEBUG
614
0
    else if(debug) { printf("arc: sent `%2.2x', fd %d.\n", c, pp->io.fd); }
615
0
#endif
616
0
  }
617
618
0
  ENQUEUE(up);
619
0
}
620
621
/*
622
 * arc_start - open the devices and initialize data for processing
623
 */
624
static int
625
arc_start(
626
  int unit,
627
  struct peer *peer
628
  )
629
0
{
630
0
  register struct arcunit *up;
631
0
  struct refclockproc *pp;
632
0
  int temp_fd;
633
0
  int fd;
634
0
  char device[20];
635
0
#ifdef HAVE_TERMIOS
636
0
  struct termios arg;
637
0
#endif
638
639
0
  msyslog(LOG_NOTICE, "MSF_ARCRON %s: opening unit %d",
640
0
    arc_version, unit);
641
0
  DPRINTF(1, ("arc: %s: attempt to open unit %d.\n", arc_version,
642
0
    unit));
643
644
  /*
645
   * Open serial port. Use CLK line discipline, if available.
646
   */
647
0
  snprintf(device, sizeof(device), DEVICE, unit);
648
0
  temp_fd = refclock_open(device, SPEED, LDISC_CLK);
649
0
  if (temp_fd <= 0)
650
0
    return 0;
651
0
  DPRINTF(1, ("arc: unit %d using tty_open().\n", unit));
652
0
  fd = tty_open(device, OPEN_FLAGS, 0777);
653
0
  if (fd < 0) {
654
0
    msyslog(LOG_ERR, "MSF_ARCRON(%d): failed second open(%s, 0777): %m.",
655
0
      unit, device);
656
0
    close(temp_fd);
657
0
    return 0;
658
0
  }
659
0
  close(temp_fd);
660
0
  temp_fd = -1;   /* not used after this, at *this* time. */
661
662
0
#ifndef SYS_WINNT
663
0
  if (-1 == fcntl(fd, F_SETFL, 0)) /* clear the descriptor flags */
664
0
    msyslog(LOG_ERR, "MSF_ARCRON(%d): fcntl(F_SETFL, 0): %m.",
665
0
      unit);
666
667
0
#endif
668
0
  DPRINTF(1, ("arc: opened RS232 port with file descriptor %d.\n", fd));
669
670
0
#ifdef HAVE_TERMIOS
671
672
0
  if (tcgetattr(fd, &arg) < 0) {
673
0
    msyslog(LOG_ERR, "MSF_ARCRON(%d): tcgetattr(%s): %m.",
674
0
      unit, device);
675
0
    close(fd);
676
0
    return 0;
677
0
  }
678
679
0
  arg.c_iflag = IGNBRK | ISTRIP;
680
0
  arg.c_oflag = 0;
681
0
  arg.c_cflag = B300 | CS8 | CREAD | CLOCAL | CSTOPB;
682
0
  arg.c_lflag = 0;
683
0
  arg.c_cc[VMIN] = 1;
684
0
  arg.c_cc[VTIME] = 0;
685
686
0
  if (tcsetattr(fd, TCSANOW, &arg) < 0) {
687
0
    msyslog(LOG_ERR, "MSF_ARCRON(%d): tcsetattr(%s): %m.",
688
0
      unit, device);
689
0
    close(fd);
690
0
    return 0;
691
0
  }
692
693
#else
694
695
  msyslog(LOG_ERR, "ARCRON: termios required by this driver");
696
  (void)close(fd);
697
698
  return 0;
699
700
#endif
701
702
  /* Set structure to all zeros... */
703
0
  up = emalloc_zero(sizeof(*up));
704
0
  pp = peer->procptr;
705
0
  pp->io.clock_recv = arc_receive;
706
0
  pp->io.srcclock = peer;
707
0
  pp->io.datalen = 0;
708
0
  pp->io.fd = fd;
709
0
  if (!io_addclock(&pp->io)) {
710
0
    close(fd);
711
0
    pp->io.fd = -1;
712
0
    free(up); 
713
0
    return(0); 
714
0
  }
715
0
  pp->unitptr = up;
716
717
  /*
718
   * Initialize miscellaneous variables
719
   */
720
0
  peer->precision = PRECISION;
721
0
  peer->stratum = 2;              /* Default to stratum 2 not 0. */
722
0
  pp->clockdesc = DESCRIPTION;
723
0
  if (peer->MODE > 3) {
724
0
    msyslog(LOG_NOTICE, "ARCRON: Invalid mode %d", peer->MODE);
725
0
    return 0;
726
0
  }
727
0
#ifdef DEBUG
728
0
  if(debug) { printf("arc: mode = %d.\n", peer->MODE); }
729
0
#endif
730
0
  switch (peer->MODE) {
731
0
      case 1:
732
0
    memcpy((char *)&pp->refid, REFID_MSF, 4);
733
0
    break;
734
0
      case 2:
735
0
    memcpy((char *)&pp->refid, REFID_DCF77, 4);
736
0
    break;
737
0
      case 3:
738
0
    memcpy((char *)&pp->refid, REFID_WWVB, 4);
739
0
    break;
740
0
      default:
741
0
    memcpy((char *)&pp->refid, REFID, 4);
742
0
    break;
743
0
  }
744
  /* Spread out resyncs so that they should remain separated. */
745
0
  up->next_resync = current_time + INITIAL_RESYNC_DELAY + (67*unit)%1009;
746
747
#if 0 /* Not needed because of zeroing of arcunit structure... */
748
  up->resyncing = 0;              /* Not resyncing yet. */
749
  up->saved_flags = 0;            /* Default is all flags off. */
750
  /* Clear send buffer out... */
751
  {
752
    int i;
753
    for(i = CMDQUEUELEN; i >= 0; --i) { up->cmdqueue[i] = '\0'; }
754
  }
755
#endif
756
757
0
#ifdef ARCRON_KEEN
758
0
  up->quality = QUALITY_UNKNOWN;  /* Trust the clock immediately. */
759
#else
760
  up->quality = MIN_CLOCK_QUALITY;/* Don't trust the clock yet. */
761
#endif
762
763
0
  peer->procptr->action = arc_event_handler;
764
765
0
  ENQUEUE(up);
766
767
0
  return(1);
768
0
}
769
770
771
/*
772
 * arc_shutdown - shut down the clock
773
 */
774
static void
775
arc_shutdown(
776
  int unit,
777
  struct peer *peer
778
  )
779
0
{
780
0
  register struct arcunit *up;
781
0
  struct refclockproc *pp;
782
783
0
  peer->procptr->action = dummy_event_handler;
784
785
0
  pp = peer->procptr;
786
0
  up = pp->unitptr;
787
0
  if (-1 != pp->io.fd)
788
0
    io_closeclock(&pp->io);
789
0
  if (NULL != up)
790
0
    free(up);
791
0
}
792
793
/*
794
Compute space left in output buffer.
795
*/
796
static int
797
space_left(
798
  register struct arcunit *up
799
  )
800
0
{
801
0
  int spaceleft;
802
803
  /* Compute space left in buffer after any pending output. */
804
0
  for(spaceleft = 0; spaceleft < CMDQUEUELEN; ++spaceleft)
805
0
  { if(up->cmdqueue[CMDQUEUELEN - 1 - spaceleft] != '\0') { break; } }
806
0
  return(spaceleft);
807
0
}
808
809
/*
810
Send command by copying into command buffer as far forward as possible,
811
after any pending output.
812
813
Indicate an error by returning 0 if there is not space for the command.
814
*/
815
static int
816
send_slow(
817
  register struct arcunit *up,
818
  int fd,
819
  const char *s
820
  )
821
0
{
822
0
  int sl = strlen(s);
823
0
  int spaceleft = space_left(up);
824
825
0
#ifdef DEBUG
826
0
  if(debug > 1) { printf("arc: spaceleft = %d.\n", spaceleft); }
827
0
#endif
828
0
  if(spaceleft < sl) { /* Should not normally happen... */
829
0
#ifdef DEBUG
830
0
    msyslog(LOG_NOTICE, "ARCRON: send-buffer overrun (%d/%d)",
831
0
      sl, spaceleft);
832
0
#endif
833
0
    return(0);      /* FAILED! */
834
0
  }
835
836
  /* Copy in the command to be sent. */
837
0
  while(*s && spaceleft > 0) { up->cmdqueue[CMDQUEUELEN - spaceleft--] = *s++; }
838
839
0
  return(1);
840
0
}
841
842
843
static int
844
get2(char *p, int *val)
845
0
{
846
0
  if (!isdigit((unsigned char)p[0]) || !isdigit((unsigned char)p[1])) return 0;
847
0
  *val = (p[0] - '0') * 10 + p[1] - '0';
848
0
  return 1;
849
0
}
850
851
static int
852
get1(char *p, int *val)
853
0
{
854
0
  if (!isdigit((unsigned char)p[0])) return 0;
855
0
  *val = p[0] - '0';
856
0
  return 1;
857
0
}
858
859
/* Macro indicating action we will take for different quality values. */
860
0
#define quality_action(q) \
861
0
(((q) == QUALITY_UNKNOWN) ?         "UNKNOWN, will use clock anyway" : \
862
0
 (((q) < MIN_CLOCK_QUALITY_OK) ? "TOO POOR, will not use clock" : \
863
0
  "OK, will use clock"))
864
865
/*
866
 * arc_receive - receive data from the serial interface
867
 */
868
static void
869
arc_receive(
870
  struct recvbuf *rbufp
871
  )
872
0
{
873
0
  register struct arcunit *up;
874
0
  struct refclockproc *pp;
875
0
  struct peer *peer;
876
0
  char c;
877
0
  int i, n, wday, month, flags, status;
878
0
  int arc_last_offset;
879
0
  static int quality_average = 0;
880
0
  static int quality_sum = 0;
881
0
  static int quality_polls = 0;
882
883
  /*
884
   * Initialize pointers and read the timecode and timestamp
885
   */
886
0
  peer = rbufp->recv_peer;
887
0
  pp = peer->procptr;
888
0
  up = pp->unitptr;
889
890
891
  /*
892
    If the command buffer is empty, and we are resyncing, insert a
893
    g\r quality request into it to poll for signal quality again.
894
  */
895
0
  if((up->resyncing) && (space_left(up) == CMDQUEUELEN)) {
896
0
#ifdef DEBUG
897
0
    if(debug > 1) { printf("arc: inserting signal-quality poll.\n"); }
898
0
#endif
899
0
    send_slow(up, pp->io.fd, "g\r");
900
0
  }
901
902
  /*
903
    The `arc_last_offset' is the offset in lastcode[] of the last byte
904
    received, and which we assume actually received the input
905
    timestamp.
906
907
    (When we get round to using tty_clk and it is available, we
908
    assume that we will receive the whole timecode with the
909
    trailing \r, and that that \r will be timestamped.  But this
910
    assumption also works if receive the characters one-by-one.)
911
  */
912
0
  arc_last_offset = pp->lencode+rbufp->recv_length - 1;
913
914
  /*
915
    We catch a timestamp iff:
916
917
    * The command code is `o' for a timestamp.
918
919
    * If ARCRON_MULTIPLE_SAMPLES is undefined then we must have
920
    exactly char in the buffer (the command code) so that we
921
    only sample the first character of the timecode as our
922
    `on-time' character.
923
924
    * The first character in the buffer is not the echoed `\r'
925
    from the `o` command (so if we are to timestamp an `\r' it
926
    must not be first in the receive buffer with lencode==1.
927
    (Even if we had other characters following it, we probably
928
    would have a premature timestamp on the '\r'.)
929
930
    * We have received at least one character (I cannot imagine
931
    how it could be otherwise, but anyway...).
932
  */
933
0
  c = rbufp->recv_buffer[0];
934
0
  if((pp->a_lastcode[0] == 'o') &&
935
#ifndef ARCRON_MULTIPLE_SAMPLES
936
     (pp->lencode == 1) &&
937
#endif
938
0
     ((pp->lencode != 1) || (c != '\r')) &&
939
0
     (arc_last_offset >= 1)) {
940
    /* Note that the timestamp should be corrected if >1 char rcvd. */
941
0
    l_fp timestamp;
942
0
    timestamp = rbufp->recv_time;
943
0
#ifdef DEBUG
944
0
    if(debug) { /* Show \r as `R', other non-printing char as `?'. */
945
0
      printf("arc: stamp -->%c<-- (%d chars rcvd)\n",
946
0
             ((c == '\r') ? 'R' : (isgraph((unsigned char)c) ? c : '?')),
947
0
             rbufp->recv_length);
948
0
    }
949
0
#endif
950
951
    /*
952
      Now correct timestamp by offset of last byte received---we
953
      subtract from the receive time the delay implied by the
954
      extra characters received.
955
956
      Reject the input if the resulting code is too long, but
957
      allow for the trailing \r, normally not used but a good
958
      handle for tty_clk or somesuch kernel timestamper.
959
    */
960
0
    if(arc_last_offset > LENARC) {
961
0
#ifdef DEBUG
962
0
      if(debug) {
963
0
        printf("arc: input code too long (%d cf %d); rejected.\n",
964
0
               arc_last_offset, LENARC);
965
0
      }
966
0
#endif
967
0
      pp->lencode = 0;
968
0
      refclock_report(peer, CEVNT_BADREPLY);
969
0
      return;
970
0
    }
971
972
0
    L_SUBUF(&timestamp, charoffsets[arc_last_offset]);
973
0
#ifdef DEBUG
974
0
    if(debug > 1) {
975
0
      printf(
976
0
        "arc: %s%d char(s) rcvd, the last for lastcode[%d]; -%sms offset applied.\n",
977
0
        ((rbufp->recv_length > 1) ? "*** " : ""),
978
0
        rbufp->recv_length,
979
0
        arc_last_offset,
980
0
        mfptoms((unsigned long)0,
981
0
          charoffsets[arc_last_offset],
982
0
          1));
983
0
    }
984
0
#endif
985
986
0
#ifdef ARCRON_MULTIPLE_SAMPLES
987
    /*
988
      If taking multiple samples, capture the current adjusted
989
      sample iff:
990
991
      * No timestamp has yet been captured (it is zero), OR
992
993
      * This adjusted timestamp is earlier than the one already
994
      captured, on the grounds that this one suffered less
995
      delay in being delivered to us and is more accurate.
996
997
    */
998
0
    if(L_ISZERO(&(up->lastrec)) ||
999
0
       L_ISGEQ(&(up->lastrec), &timestamp))
1000
0
#endif
1001
0
    {
1002
0
#ifdef DEBUG
1003
0
      if(debug > 1) {
1004
0
        printf("arc: system timestamp captured.\n");
1005
0
#ifdef ARCRON_MULTIPLE_SAMPLES
1006
0
        if(!L_ISZERO(&(up->lastrec))) {
1007
0
          l_fp diff;
1008
0
          diff = up->lastrec;
1009
0
          L_SUB(&diff, &timestamp);
1010
0
          printf("arc: adjusted timestamp by -%sms.\n",
1011
0
                 mfptoms(diff.l_ui, diff.l_uf, 3));
1012
0
        }
1013
0
#endif
1014
0
      }
1015
0
#endif
1016
0
      up->lastrec = timestamp;
1017
0
    }
1018
1019
0
  }
1020
1021
  /* Just in case we still have lots of rubbish in the buffer... */
1022
  /* ...and to avoid the same timestamp being reused by mistake, */
1023
  /* eg on receipt of the \r coming in on its own after the      */
1024
  /* timecode.                   */
1025
0
  if(pp->lencode >= LENARC) {
1026
0
#ifdef DEBUG
1027
0
    if(debug && (rbufp->recv_buffer[0] != '\r'))
1028
0
    { printf("arc: rubbish in pp->a_lastcode[].\n"); }
1029
0
#endif
1030
0
    pp->lencode = 0;
1031
0
    return;
1032
0
  }
1033
1034
  /* Append input to code buffer, avoiding overflow. */
1035
0
  for(i = 0; i < rbufp->recv_length; i++) {
1036
0
    if(pp->lencode >= LENARC) { break; } /* Avoid overflow... */
1037
0
    c = rbufp->recv_buffer[i];
1038
1039
    /* Drop trailing '\r's and drop `h' command echo totally. */
1040
0
    if(c != '\r' && c != 'h') { pp->a_lastcode[pp->lencode++] = c; }
1041
1042
    /*
1043
      If we've just put an `o' in the lastcode[0], clear the
1044
      timestamp in anticipation of a timecode arriving soon.
1045
1046
      We would expect to get to process this before any of the
1047
      timecode arrives.
1048
    */
1049
0
    if((c == 'o') && (pp->lencode == 1)) {
1050
0
      L_CLR(&(up->lastrec));
1051
0
#ifdef DEBUG
1052
0
      if(debug > 1) { printf("arc: clearing timestamp.\n"); }
1053
0
#endif
1054
0
    }
1055
0
  }
1056
0
  if (pp->lencode == 0) return;
1057
1058
  /* Handle a quality message. */
1059
0
  if(pp->a_lastcode[0] == 'g') {
1060
0
    int r, q;
1061
1062
0
    if(pp->lencode < 3) { return; } /* Need more data... */
1063
0
    r = (pp->a_lastcode[1] & 0x7f); /* Strip parity. */
1064
0
    q = (pp->a_lastcode[2] & 0x7f); /* Strip parity. */
1065
0
    if(((q & 0x70) != 0x30) || ((q & 0xf) > MAX_CLOCK_QUALITY) ||
1066
0
       ((r & 0x70) != 0x30)) {
1067
      /* Badly formatted response. */
1068
0
#ifdef DEBUG
1069
0
      if(debug) { printf("arc: bad `g' response %2x %2x.\n", r, q); }
1070
0
#endif
1071
0
      return;
1072
0
    }
1073
0
    if(r == '3') { /* Only use quality value whilst sync in progress. */
1074
0
      if (up->quality_stamp < current_time) {
1075
0
        struct calendar cal;
1076
0
        l_fp new_stamp;
1077
      
1078
0
        get_systime (&new_stamp);
1079
0
        caljulian (new_stamp.l_ui, &cal);
1080
0
        up->quality_stamp = 
1081
0
          current_time + 60 - cal.second + 5;
1082
0
        quality_sum = 0;
1083
0
        quality_polls = 0;
1084
0
      }
1085
0
      quality_sum += (q & 0xf);
1086
0
      quality_polls++;
1087
0
      quality_average = (quality_sum / quality_polls);
1088
0
#ifdef DEBUG
1089
0
      if(debug) { printf("arc: signal quality %d (%d).\n", quality_average, (q & 0xf)); }
1090
0
#endif
1091
0
    } else if( /* (r == '2') && */ up->resyncing) {
1092
0
      up->quality = quality_average;
1093
0
#ifdef DEBUG
1094
0
      if(debug)
1095
0
      {
1096
0
        printf("arc: sync finished, signal quality %d: %s\n",
1097
0
               up->quality,
1098
0
               quality_action(up->quality));
1099
0
      }
1100
0
#endif
1101
0
      msyslog(LOG_NOTICE,
1102
0
        "ARCRON: sync finished, signal quality %d: %s",
1103
0
        up->quality,
1104
0
        quality_action(up->quality));
1105
0
      up->resyncing = 0; /* Resync is over. */
1106
0
      quality_average = 0;
1107
0
      quality_sum = 0;
1108
0
      quality_polls = 0;
1109
1110
0
#ifdef ARCRON_KEEN
1111
      /* Clock quality dubious; resync earlier than usual. */
1112
0
      if((up->quality == QUALITY_UNKNOWN) ||
1113
0
         (up->quality < MIN_CLOCK_QUALITY_OK))
1114
0
      { up->next_resync = current_time + RETRY_RESYNC_TIME; }
1115
0
#endif
1116
0
    }
1117
0
    pp->lencode = 0;
1118
0
    return;
1119
0
  }
1120
1121
  /* Stop now if this is not a timecode message. */
1122
0
  if(pp->a_lastcode[0] != 'o') {
1123
0
    pp->lencode = 0;
1124
0
    refclock_report(peer, CEVNT_BADREPLY);
1125
0
    return;
1126
0
  }
1127
1128
  /* If we don't have enough data, wait for more... */
1129
0
  if(pp->lencode < LENARC) { return; }
1130
1131
1132
  /* WE HAVE NOW COLLECTED ONE TIMESTAMP (phew)... */
1133
0
#ifdef DEBUG
1134
0
  if(debug > 1) { printf("arc: NOW HAVE TIMESTAMP...\n"); }
1135
0
#endif
1136
1137
  /* But check that we actually captured a system timestamp on it. */
1138
0
  if(L_ISZERO(&(up->lastrec))) {
1139
0
#ifdef DEBUG
1140
0
    if(debug) { printf("arc: FAILED TO GET SYSTEM TIMESTAMP\n"); }
1141
0
#endif
1142
0
    pp->lencode = 0;
1143
0
    refclock_report(peer, CEVNT_BADREPLY);
1144
0
    return;
1145
0
  }
1146
  /*
1147
    Append a mark of the clock's received signal quality for the
1148
    benefit of Derek Mulcahy's Tcl/Tk utility (we map the `unknown'
1149
    quality value to `6' for his s/w) and terminate the string for
1150
    sure.  This should not go off the buffer end.
1151
  */
1152
0
  pp->a_lastcode[pp->lencode] = ((up->quality == QUALITY_UNKNOWN) ?
1153
0
               '6' : ('0' + up->quality));
1154
0
  pp->a_lastcode[pp->lencode + 1] = '\0'; /* Terminate for printf(). */
1155
1156
#ifdef PRE_NTP420
1157
  /* We don't use the micro-/milli- second part... */
1158
  pp->usec = 0;
1159
  pp->msec = 0;
1160
#else
1161
  /* We don't use the nano-second part... */
1162
0
  pp->nsec = 0;
1163
0
#endif  
1164
  /* Validate format and numbers. */
1165
0
  if (pp->a_lastcode[0] != 'o'
1166
0
    || !get2(pp->a_lastcode + 1, &pp->hour)
1167
0
    || !get2(pp->a_lastcode + 3, &pp->minute)
1168
0
    || !get2(pp->a_lastcode + 5, &pp->second)
1169
0
    || !get1(pp->a_lastcode + 7, &wday)
1170
0
    || !get2(pp->a_lastcode + 8, &pp->day)
1171
0
    || !get2(pp->a_lastcode + 10, &month)
1172
0
    || !get2(pp->a_lastcode + 12, &pp->year)) {
1173
0
#ifdef DEBUG
1174
    /* Would expect to have caught major problems already... */
1175
0
    if(debug) { printf("arc: badly formatted data.\n"); }
1176
0
#endif
1177
0
    pp->lencode = 0;
1178
0
    refclock_report(peer, CEVNT_BADREPLY);
1179
0
    return;
1180
0
  }
1181
0
  flags = pp->a_lastcode[14];
1182
0
  status = pp->a_lastcode[15];
1183
0
#ifdef DEBUG
1184
0
  if(debug) { printf("arc: status 0x%.2x flags 0x%.2x\n", flags, status); }
1185
0
#endif
1186
0
  n = 9;
1187
1188
  /*
1189
    Validate received values at least enough to prevent internal
1190
    array-bounds problems, etc.
1191
  */
1192
0
  if((pp->hour < 0) || (pp->hour > 23) ||
1193
0
     (pp->minute < 0) || (pp->minute > 59) ||
1194
0
     (pp->second < 0) || (pp->second > 60) /*Allow for leap seconds.*/ ||
1195
0
     (wday < 1) || (wday > 7) ||
1196
0
     (pp->day < 1) || (pp->day > 31) ||
1197
0
     (month < 1) || (month > 12) ||
1198
0
     (pp->year < 0) || (pp->year > 99)) {
1199
    /* Data out of range. */
1200
0
    pp->lencode = 0;
1201
0
    refclock_report(peer, CEVNT_BADREPLY);
1202
0
    return;
1203
0
  }
1204
1205
1206
0
  if(peer->MODE == 0) { /* compatiblity to original version */
1207
0
    int bst = flags;
1208
    /* Check that BST/UTC bits are the complement of one another. */
1209
0
    if(!(bst & 2) == !(bst & 4)) {
1210
0
      pp->lencode = 0;
1211
0
      refclock_report(peer, CEVNT_BADREPLY);
1212
0
      return;
1213
0
    }
1214
0
  }
1215
0
  if(status & 0x8) { msyslog(LOG_NOTICE, "ARCRON: battery low"); }
1216
1217
  /* Year-2000 alert! */
1218
  /* Attempt to wrap 2-digit date into sensible window. */
1219
0
  if(pp->year < YEAR_PIVOT) { pp->year += 100; }    /* Y2KFixes */
1220
0
  pp->year += 1900; /* use full four-digit year */  /* Y2KFixes */
1221
  /*
1222
    Attempt to do the right thing by screaming that the code will
1223
    soon break when we get to the end of its useful life.  What a
1224
    hero I am...  PLEASE FIX LEAP-YEAR AND WRAP CODE IN 209X!
1225
  */
1226
0
  if(pp->year >= YEAR_PIVOT+2000-2 ) {       /* Y2KFixes */
1227
    /*This should get attention B^> */
1228
0
    msyslog(LOG_NOTICE,
1229
0
      "ARCRON: fix me!  EITHER YOUR DATE IS BADLY WRONG or else I will break soon!");
1230
0
  }
1231
0
#ifdef DEBUG
1232
0
  if(debug) {
1233
0
    printf("arc: n=%d %02d:%02d:%02d %02d/%02d/%04d %1d %1d\n",
1234
0
           n,
1235
0
           pp->hour, pp->minute, pp->second,
1236
0
           pp->day, month, pp->year, flags, status);
1237
0
  }
1238
0
#endif
1239
1240
  /*
1241
    The status value tested for is not strictly supported by the
1242
    clock spec since the value of bit 2 (0x4) is claimed to be
1243
    undefined for MSF, yet does seem to indicate if the last resync
1244
    was successful or not.
1245
  */
1246
0
  pp->leap = LEAP_NOWARNING;
1247
0
  status &= 0x7;
1248
0
  if(status == 0x3) {
1249
0
    if(status != up->status)
1250
0
    { msyslog(LOG_NOTICE, "ARCRON: signal acquired"); }
1251
0
  } else {
1252
0
    if(status != up->status) {
1253
0
      msyslog(LOG_NOTICE, "ARCRON: signal lost");
1254
0
      pp->leap = LEAP_NOTINSYNC; /* MSF clock is free-running. */
1255
0
      up->status = status;
1256
0
      pp->lencode = 0;
1257
0
      refclock_report(peer, CEVNT_FAULT);
1258
0
      return;
1259
0
    }
1260
0
  }
1261
0
  up->status = status;
1262
1263
0
  if (peer->MODE == 0) { /* compatiblity to original version */
1264
0
    int bst = flags;
1265
1266
0
    pp->day += moff[month - 1];
1267
1268
0
    if(isleap_4(pp->year) && month > 2) { pp->day++; }/* Y2KFixes */
1269
1270
    /* Convert to UTC if required */
1271
0
    if(bst & 2) {
1272
0
      pp->hour--;
1273
0
      if (pp->hour < 0) {
1274
0
        pp->hour = 23;
1275
0
        pp->day--;
1276
        /* If we try to wrap round the year
1277
         * (BST on 1st Jan), reject.*/
1278
0
        if(pp->day < 0) {
1279
0
          pp->lencode = 0;
1280
0
          refclock_report(peer, CEVNT_BADTIME);
1281
0
          return;
1282
0
        }
1283
0
      }
1284
0
    }
1285
0
  }
1286
1287
0
  if(peer->MODE > 0) {
1288
0
    if(pp->sloppyclockflag & CLK_FLAG1) {
1289
0
      struct tm  local;
1290
0
      struct tm *gmtp;
1291
0
      time_t     unixtime;
1292
1293
      /*
1294
       * Convert to GMT for sites that distribute localtime.
1295
       * This means we have to do Y2K conversion on the
1296
       * 2-digit year; otherwise, we get the time wrong.
1297
       */
1298
1299
0
      memset(&local, 0, sizeof(local));
1300
1301
0
      local.tm_year  = pp->year-1900;
1302
0
      local.tm_mon   = month-1;
1303
0
      local.tm_mday  = pp->day;
1304
0
      local.tm_hour  = pp->hour;
1305
0
      local.tm_min   = pp->minute;
1306
0
      local.tm_sec   = pp->second;
1307
0
      switch (peer->MODE) {
1308
0
          case 1:
1309
0
        local.tm_isdst = (flags & 2);
1310
0
        break;
1311
0
          case 2:
1312
0
        local.tm_isdst = (flags & 2);
1313
0
        break;
1314
0
          case 3:
1315
0
        switch (flags & 3) {
1316
0
            case 0: /* It is unclear exactly when the 
1317
                 Arcron changes from DST->ST and 
1318
                 ST->DST. Testing has shown this
1319
                 to be irregular. For the time 
1320
                 being, let the OS decide. */
1321
0
          local.tm_isdst = 0;
1322
0
#ifdef DEBUG
1323
0
          if (debug)
1324
0
              printf ("arc: DST = 00 (0)\n"); 
1325
0
#endif
1326
0
          break;
1327
0
            case 1: /* dst->st time */
1328
0
          local.tm_isdst = -1;
1329
0
#ifdef DEBUG
1330
0
          if (debug) 
1331
0
              printf ("arc: DST = 01 (1)\n"); 
1332
0
#endif
1333
0
          break;
1334
0
            case 2: /* st->dst time */
1335
0
          local.tm_isdst = -1;
1336
0
#ifdef DEBUG
1337
0
          if (debug) 
1338
0
              printf ("arc: DST = 10 (2)\n"); 
1339
0
#endif
1340
0
          break;
1341
0
            case 3: /* dst time */
1342
0
                local.tm_isdst = 1;
1343
0
#ifdef DEBUG
1344
0
          if (debug) 
1345
0
              printf ("arc: DST = 11 (3)\n"); 
1346
0
#endif
1347
0
          break;
1348
0
        }
1349
0
        break;
1350
0
          default:
1351
0
        msyslog(LOG_NOTICE, "ARCRON: Invalid mode %d",
1352
0
          peer->MODE);
1353
0
        return;
1354
0
        break;
1355
0
      }
1356
0
      unixtime = mktime (&local);
1357
0
      if ((gmtp = gmtime (&unixtime)) == NULL)
1358
0
      {
1359
0
        pp->lencode = 0;
1360
0
        refclock_report (peer, CEVNT_FAULT);
1361
0
        return;
1362
0
      }
1363
0
      pp->year = gmtp->tm_year+1900;
1364
0
      month = gmtp->tm_mon+1;
1365
0
      pp->day = ymd2yd(pp->year,month,gmtp->tm_mday);
1366
      /* pp->day = gmtp->tm_yday; */
1367
0
      pp->hour = gmtp->tm_hour;
1368
0
      pp->minute = gmtp->tm_min;
1369
0
      pp->second = gmtp->tm_sec;
1370
0
#ifdef DEBUG
1371
0
      if (debug)
1372
0
      {
1373
0
        printf ("arc: time is %04d/%02d/%02d %02d:%02d:%02d UTC\n",
1374
0
          pp->year,month,gmtp->tm_mday,pp->hour,pp->minute,
1375
0
          pp->second);
1376
0
      }
1377
0
#endif
1378
0
    } else 
1379
0
    {
1380
      /*
1381
      * For more rational sites distributing UTC
1382
      */
1383
0
      pp->day    = ymd2yd(pp->year,month,pp->day);
1384
0
    }
1385
0
  }
1386
1387
0
  if (peer->MODE == 0) { /* compatiblity to original version */
1388
        /* If clock signal quality is 
1389
         * unknown, revert to default PRECISION...*/
1390
0
    if(up->quality == QUALITY_UNKNOWN) { 
1391
0
      peer->precision = PRECISION; 
1392
0
    } else { /* ...else improve precision if flag3 is set... */
1393
0
      peer->precision = ((pp->sloppyclockflag & CLK_FLAG3) ?
1394
0
             HIGHPRECISION : PRECISION);
1395
0
    }
1396
0
  } else {
1397
0
    if ((status == 0x3) && (pp->sloppyclockflag & CLK_FLAG2)) {
1398
0
      peer->precision = ((pp->sloppyclockflag & CLK_FLAG3) ?
1399
0
             HIGHPRECISION : PRECISION);
1400
0
    } else if (up->quality == QUALITY_UNKNOWN) {
1401
0
      peer->precision = PRECISION;
1402
0
    } else {
1403
0
      peer->precision = ((pp->sloppyclockflag & CLK_FLAG3) ?
1404
0
             HIGHPRECISION : PRECISION);
1405
0
    }
1406
0
  }
1407
1408
  /* Notice and log any change (eg from initial defaults) for flags. */
1409
0
  if(up->saved_flags != pp->sloppyclockflag) {
1410
0
#ifdef DEBUG
1411
0
    msyslog(LOG_NOTICE, "ARCRON: flags enabled: %s%s%s%s",
1412
0
      ((pp->sloppyclockflag & CLK_FLAG1) ? "1" : "."),
1413
0
      ((pp->sloppyclockflag & CLK_FLAG2) ? "2" : "."),
1414
0
      ((pp->sloppyclockflag & CLK_FLAG3) ? "3" : "."),
1415
0
      ((pp->sloppyclockflag & CLK_FLAG4) ? "4" : "."));
1416
    /* Note effects of flags changing... */
1417
0
    if(debug) {
1418
0
      printf("arc: PRECISION = %d.\n", peer->precision);
1419
0
    }
1420
0
#endif
1421
0
    up->saved_flags = pp->sloppyclockflag;
1422
0
  }
1423
1424
  /* Note time of last believable timestamp. */
1425
0
  pp->lastrec = up->lastrec;
1426
1427
#ifdef ARCRON_LEAPSECOND_KEEN
1428
  /* Find out if a leap-second might just have happened...
1429
     (ie is this the first hour of the first day of Jan or Jul?)
1430
  */
1431
  if((pp->hour == 0) &&
1432
     (pp->day == 1) &&
1433
     ((month == 1) || (month == 7))) {
1434
    if(possible_leap >= 0) {
1435
      /* A leap may have happened, and no resync has started yet...*/
1436
      possible_leap = 1;
1437
    }
1438
  } else {
1439
    /* Definitely not leap-second territory... */
1440
    possible_leap = 0;
1441
  }
1442
#endif
1443
1444
0
  if (!refclock_process(pp)) {
1445
0
    pp->lencode = 0;
1446
0
    refclock_report(peer, CEVNT_BADTIME);
1447
0
    return;
1448
0
  }
1449
0
  record_clock_stats(&peer->srcadr, pp->a_lastcode);
1450
0
  refclock_receive(peer);
1451
0
}
1452
1453
1454
/* request_time() sends a time request to the clock with given peer. */
1455
/* This automatically reports a fault if necessary. */
1456
/* No data should be sent after this until arc_poll() returns. */
1457
static  void    request_time    (int, struct peer *);
1458
static void
1459
request_time(
1460
  int unit,
1461
  struct peer *peer
1462
  )
1463
0
{
1464
0
  struct refclockproc *pp = peer->procptr;
1465
0
  register struct arcunit *up = pp->unitptr;
1466
0
#ifdef DEBUG
1467
0
  if(debug) { printf("arc: unit %d: requesting time.\n", unit); }
1468
0
#endif
1469
0
  if (!send_slow(up, pp->io.fd, "o\r")) {
1470
0
#ifdef DEBUG
1471
0
    if (debug) {
1472
0
      printf("arc: unit %d: problem sending", unit);
1473
0
    }
1474
0
#endif
1475
0
    pp->lencode = 0;
1476
0
    refclock_report(peer, CEVNT_FAULT);
1477
0
    return;
1478
0
  }
1479
0
  pp->polls++;
1480
0
}
1481
1482
/*
1483
 * arc_poll - called by the transmit procedure
1484
 */
1485
static void
1486
arc_poll(
1487
  int unit,
1488
  struct peer *peer
1489
  )
1490
0
{
1491
0
  register struct arcunit *up;
1492
0
  struct refclockproc *pp;
1493
0
  int resync_needed;              /* Should we start a resync? */
1494
1495
0
  pp = peer->procptr;
1496
0
  up = pp->unitptr;
1497
#if 0
1498
  pp->lencode = 0;
1499
  memset(pp->a_lastcode, 0, sizeof(pp->a_lastcode));
1500
#endif
1501
1502
#if 0
1503
  /* Flush input. */
1504
  tcflush(pp->io.fd, TCIFLUSH);
1505
#endif
1506
1507
  /* Resync if our next scheduled resync time is here or has passed. */
1508
0
  resync_needed = ( !(pp->sloppyclockflag & CLK_FLAG2) &&
1509
0
        (up->next_resync <= current_time) );
1510
1511
#ifdef ARCRON_LEAPSECOND_KEEN
1512
  /*
1513
    Try to catch a potential leap-second insertion or deletion quickly.
1514
1515
    In addition to the normal NTP fun of clocks that don't report
1516
    leap-seconds spooking their hosts, this clock does not even
1517
    sample the radio sugnal the whole time, so may miss a
1518
    leap-second insertion or deletion for up to a whole sample
1519
    time.
1520
1521
    To try to minimise this effect, if in the first few minutes of
1522
    the day immediately following a leap-second-insertion point
1523
    (ie in the first hour of the first day of the first and sixth
1524
    months), and if the last resync was in the previous day, and a
1525
    resync is not already in progress, resync the clock
1526
    immediately.
1527
1528
  */
1529
  if((possible_leap > 0) &&       /* Must be 00:XX 01/0{1,7}/XXXX. */
1530
     (!up->resyncing)) {          /* No resync in progress yet. */
1531
    resync_needed = 1;
1532
    possible_leap = -1;          /* Prevent multiple resyncs. */
1533
    msyslog(LOG_NOTICE,"ARCRON: unit %d: checking for leap second",unit);
1534
  }
1535
#endif
1536
1537
  /* Do a resync if required... */
1538
0
  if(resync_needed) {
1539
    /* First, reset quality value to `unknown' so we can detect */
1540
    /* when a quality message has been responded to by this     */
1541
    /* being set to some other value.                           */
1542
0
    up->quality = QUALITY_UNKNOWN;
1543
1544
    /* Note that we are resyncing... */
1545
0
    up->resyncing = 1;
1546
1547
    /* Now actually send the resync command and an immediate poll. */
1548
0
#ifdef DEBUG
1549
0
    if(debug) { printf("arc: sending resync command (h\\r).\n"); }
1550
0
#endif
1551
0
    msyslog(LOG_NOTICE, "ARCRON: unit %d: sending resync command", unit);
1552
0
    send_slow(up, pp->io.fd, "h\r");
1553
1554
    /* Schedule our next resync... */
1555
0
    up->next_resync = current_time + DEFAULT_RESYNC_TIME;
1556
1557
    /* Drop through to request time if appropriate. */
1558
0
  }
1559
1560
  /* If clock quality is too poor to trust, indicate a fault. */
1561
  /* If quality is QUALITY_UNKNOWN and ARCRON_KEEN is defined,*/
1562
  /* we'll cross our fingers and just hope that the thing     */
1563
  /* synced so quickly we did not catch it---we'll            */
1564
  /* double-check the clock is OK elsewhere.                  */
1565
0
  if(
1566
0
#ifdef ARCRON_KEEN
1567
0
    (up->quality != QUALITY_UNKNOWN) &&
1568
#else
1569
    (up->quality == QUALITY_UNKNOWN) ||
1570
#endif
1571
0
    (up->quality < MIN_CLOCK_QUALITY_OK)) {
1572
0
#ifdef DEBUG
1573
0
    if(debug) {
1574
0
      printf("arc: clock quality %d too poor.\n", up->quality);
1575
0
    }
1576
0
#endif
1577
0
    pp->lencode = 0;
1578
0
    refclock_report(peer, CEVNT_FAULT);
1579
0
    return;
1580
0
  }
1581
  /* This is the normal case: request a timestamp. */
1582
0
  request_time(unit, peer);
1583
0
}
1584
1585
#else
1586
NONEMPTY_TRANSLATION_UNIT
1587
#endif