Annotation of embedaddon/ntp/ntpd/refclock_arc.c, revision 1.1.1.1

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>