Annotation of embedaddon/ntp/ntpd/refclock_arc.c, revision 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>