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

1.1       misho       1: /*
                      2:  * /src/NTP/REPOSITORY/ntp4-dev/ntpd/refclock_parse.c,v 4.81 2009/05/01 10:15:29 kardel RELEASE_20090105_A
                      3:  *
                      4:  * refclock_parse.c,v 4.81 2009/05/01 10:15:29 kardel RELEASE_20090105_A
                      5:  *
                      6:  * generic reference clock driver for several DCF/GPS/MSF/... receivers
                      7:  *
                      8:  * PPS notes:
                      9:  *   On systems that support PPSAPI (RFC2783) PPSAPI is the
                     10:  *   preferred interface.
                     11:  *
                     12:  *   Optionally make use of a STREAMS module for input processing where
                     13:  *   available and configured. This STREAMS module reduces the time
                     14:  *   stamp latency for serial and PPS events.
                     15:  *   Currently the STREAMS module is only available for Suns running
                     16:  *   SunOS 4.x and SunOS5.x.
                     17:  *
                     18:  * Copyright (c) 1995-2009 by Frank Kardel <kardel <AT> ntp.org>
                     19:  * Copyright (c) 1989-1994 by Frank Kardel, Friedrich-Alexander Universität Erlangen-Nürnberg, Germany
                     20:  *
                     21:  * Redistribution and use in source and binary forms, with or without
                     22:  * modification, are permitted provided that the following conditions
                     23:  * are met:
                     24:  * 1. Redistributions of source code must retain the above copyright
                     25:  *    notice, this list of conditions and the following disclaimer.
                     26:  * 2. Redistributions in binary form must reproduce the above copyright
                     27:  *    notice, this list of conditions and the following disclaimer in the
                     28:  *    documentation and/or other materials provided with the distribution.
                     29:  * 3. Neither the name of the author nor the names of its contributors
                     30:  *    may be used to endorse or promote products derived from this software
                     31:  *    without specific prior written permission.
                     32:  *
                     33:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
                     34:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     35:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     36:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
                     37:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     38:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     39:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     40:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     41:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     42:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     43:  * SUCH DAMAGE.
                     44:  *
                     45:  */
                     46: 
                     47: #ifdef HAVE_CONFIG_H
                     48: # include "config.h"
                     49: #endif
                     50: 
                     51: #if defined(REFCLOCK) && defined(CLOCK_PARSE)
                     52: 
                     53: /*
                     54:  * This driver currently provides the support for
                     55:  *   - Meinberg receiver DCF77 PZF 535 (TCXO version)       (DCF)
                     56:  *   - Meinberg receiver DCF77 PZF 535 (OCXO version)       (DCF)
                     57:  *   - Meinberg receiver DCF77 PZF 509                      (DCF)
                     58:  *   - Meinberg receiver DCF77 AM receivers (e.g. C51)      (DCF)
                     59:  *   - IGEL CLOCK                                           (DCF)
                     60:  *   - ELV DCF7000                                          (DCF)
                     61:  *   - Schmid clock                                         (DCF)
                     62:  *   - Conrad DCF77 receiver module                         (DCF)
                     63:  *   - FAU DCF77 NTP receiver (TimeBrick)                   (DCF)
                     64:  *   - WHARTON 400A Series clock                           (DCF)
                     65:  *
                     66:  *   - Meinberg GPS166/GPS167                               (GPS)
                     67:  *   - Trimble (TSIP and TAIP protocol)                     (GPS)
                     68:  *
                     69:  *   - RCC8000 MSF Receiver                                 (MSF)
                     70:  *   - VARITEXT clock                                      (MSF)
                     71:  */
                     72: 
                     73: /*
                     74:  * Meinberg receivers are usually connected via a
                     75:  * 9600 baud serial line
                     76:  *
                     77:  * The Meinberg GPS receivers also have a special NTP time stamp
                     78:  * format. The firmware release is Uni-Erlangen.
                     79:  *
                     80:  * Meinberg generic receiver setup:
                     81:  *     output time code every second
                     82:  *     Baud rate 9600 7E2S
                     83:  *
                     84:  * Meinberg GPS16x setup:
                     85:  *      output time code every second
                     86:  *      Baudrate 19200 8N1
                     87:  *
                     88:  * This software supports the standard data formats used
                     89:  * in Meinberg receivers.
                     90:  *
                     91:  * Special software versions are only sensible for the
                     92:  * GPS 16x family of receivers.
                     93:  *
                     94:  * Meinberg can be reached via: http://www.meinberg.de/
                     95:  */
                     96: 
                     97: #include "ntpd.h"
                     98: #include "ntp_refclock.h"
                     99: #include "ntp_unixtime.h"      /* includes <sys/time.h> */
                    100: #include "ntp_control.h"
                    101: #include "ntp_string.h"
                    102: 
                    103: #include <stdio.h>
                    104: #include <ctype.h>
                    105: #ifndef TM_IN_SYS_TIME
                    106: # include <time.h>
                    107: #endif
                    108: 
                    109: #ifdef HAVE_UNISTD_H
                    110: # include <unistd.h>
                    111: #endif
                    112: 
                    113: #if !defined(STREAM) && !defined(HAVE_SYSV_TTYS) && !defined(HAVE_BSD_TTYS) && !defined(HAVE_TERMIOS)
                    114: # include "Bletch:  Define one of {STREAM,HAVE_SYSV_TTYS,HAVE_TERMIOS}"
                    115: #endif
                    116: 
                    117: #ifdef STREAM
                    118: # include <sys/stream.h>
                    119: # include <sys/stropts.h>
                    120: #endif
                    121: 
                    122: #ifdef HAVE_TERMIOS
                    123: # define TTY_GETATTR(_FD_, _ARG_) tcgetattr((_FD_), (_ARG_))
                    124: # define TTY_SETATTR(_FD_, _ARG_) tcsetattr((_FD_), TCSANOW, (_ARG_))
                    125: # undef HAVE_SYSV_TTYS
                    126: #endif
                    127: 
                    128: #ifdef HAVE_SYSV_TTYS
                    129: # define TTY_GETATTR(_FD_, _ARG_) ioctl((_FD_), TCGETA, (_ARG_))
                    130: # define TTY_SETATTR(_FD_, _ARG_) ioctl((_FD_), TCSETAW, (_ARG_))
                    131: #endif
                    132: 
                    133: #ifdef HAVE_BSD_TTYS
                    134: /* #error CURRENTLY NO BSD TTY SUPPORT */
                    135: # include "Bletch: BSD TTY not currently supported"
                    136: #endif
                    137: 
                    138: #ifdef HAVE_SYS_IOCTL_H
                    139: # include <sys/ioctl.h>
                    140: #endif
                    141: 
                    142: #ifdef HAVE_PPSAPI
                    143: # include "ppsapi_timepps.h"
                    144: # include "refclock_atom.h"
                    145: #endif
                    146: 
                    147: #ifdef PPS
                    148: # ifdef HAVE_SYS_PPSCLOCK_H
                    149: #  include <sys/ppsclock.h>
                    150: # endif
                    151: # ifdef HAVE_TIO_SERIAL_STUFF
                    152: #  include <linux/serial.h>
                    153: # endif
                    154: #endif
                    155: 
                    156: #define BUFFER_SIZE(_BUF, _PTR) ((_BUF) + sizeof(_BUF) - (_PTR))
                    157: #define BUFFER_SIZES(_BUF, _PTR, _SZ) ((_BUF) + (_SZ) - (_PTR))
                    158: 
                    159: /*
                    160:  * document type of PPS interfacing - copy of ifdef mechanism in local_input()
                    161:  */
                    162: #undef PPS_METHOD 
                    163: 
                    164: #ifdef HAVE_PPSAPI
                    165: #define PPS_METHOD "PPS API"
                    166: #else
                    167: #ifdef TIOCDCDTIMESTAMP
                    168: #define PPS_METHOD "TIOCDCDTIMESTAMP"
                    169: #else /* TIOCDCDTIMESTAMP */
                    170: #if defined(HAVE_STRUCT_PPSCLOCKEV) && (defined(HAVE_CIOGETEV) || defined(HAVE_TIOCGPPSEV))
                    171: #ifdef HAVE_CIOGETEV
                    172: #define PPS_METHOD "CIOGETEV"
                    173: #endif
                    174: #ifdef HAVE_TIOCGPPSEV
                    175: #define PPS_METHOD "TIOCGPPSEV"
                    176: #endif
                    177: #endif
                    178: #endif /* TIOCDCDTIMESTAMP */
                    179: #endif /* HAVE_PPSAPI */
                    180: 
                    181: #include "ntp_io.h"
                    182: #include "ntp_stdlib.h"
                    183: 
                    184: #include "parse.h"
                    185: #include "mbg_gps166.h"
                    186: #include "trimble.h"
                    187: #include "binio.h"
                    188: #include "ascii.h"
                    189: #include "ieee754io.h"
                    190: #include "recvbuff.h"
                    191: 
                    192: static char rcsid[] = "refclock_parse.c,v 4.81 2009/05/01 10:15:29 kardel RELEASE_20090105_A+POWERUPTRUST";
                    193: 
                    194: /**===========================================================================
                    195:  ** external interface to ntp mechanism
                    196:  **/
                    197: 
                    198: static int     parse_start     (int, struct peer *);
                    199: static void    parse_shutdown  (int, struct peer *);
                    200: static void    parse_poll      (int, struct peer *);
                    201: static void    parse_control   (int, struct refclockstat *, struct refclockstat *, struct peer *);
                    202: 
                    203: struct refclock refclock_parse = {
                    204:        parse_start,
                    205:        parse_shutdown,
                    206:        parse_poll,
                    207:        parse_control,
                    208:        noentry,
                    209:        noentry,
                    210:        NOFLAGS
                    211: };
                    212: 
                    213: /*
                    214:  * Definitions
                    215:  */
                    216: #define        MAXUNITS        4       /* maximum number of "PARSE" units permitted */
                    217: #define PARSEDEVICE    "/dev/refclock-%d" /* device to open %d is unit number */
                    218: #define PARSEPPSDEVICE "/dev/refclockpps-%d" /* optional pps device to open %d is unit number */
                    219: 
                    220: #undef ABS
                    221: #define ABS(_X_) (((_X_) < 0) ? -(_X_) : (_X_))
                    222: 
                    223: #define PARSE_HARDPPS_DISABLE 0
                    224: #define PARSE_HARDPPS_ENABLE  1
                    225: 
                    226: /**===========================================================================
                    227:  ** function vector for dynamically binding io handling mechanism
                    228:  **/
                    229: 
                    230: struct parseunit;              /* to keep inquiring minds happy */
                    231: 
                    232: typedef struct bind
                    233: {
                    234:   const char *bd_description;                                  /* name of type of binding */
                    235:   int  (*bd_init)     (struct parseunit *);                    /* initialize */
                    236:   void (*bd_end)      (struct parseunit *);                    /* end */
                    237:   int   (*bd_setcs)    (struct parseunit *, parsectl_t *);     /* set character size */
                    238:   int  (*bd_disable)  (struct parseunit *);                    /* disable */
                    239:   int  (*bd_enable)   (struct parseunit *);                    /* enable */
                    240:   int  (*bd_getfmt)   (struct parseunit *, parsectl_t *);      /* get format */
                    241:   int  (*bd_setfmt)   (struct parseunit *, parsectl_t *);      /* setfmt */
                    242:   int  (*bd_timecode) (struct parseunit *, parsectl_t *);      /* get time code */
                    243:   void (*bd_receive)  (struct recvbuf *);                      /* receive operation */
                    244:   int  (*bd_io_input) (struct recvbuf *);                      /* input operation */
                    245: } bind_t;
                    246: 
                    247: #define PARSE_END(_X_)                 (*(_X_)->binding->bd_end)(_X_)
                    248: #define PARSE_SETCS(_X_, _CS_)         (*(_X_)->binding->bd_setcs)(_X_, _CS_)
                    249: #define PARSE_ENABLE(_X_)              (*(_X_)->binding->bd_enable)(_X_)
                    250: #define PARSE_DISABLE(_X_)             (*(_X_)->binding->bd_disable)(_X_)
                    251: #define PARSE_GETFMT(_X_, _DCT_)       (*(_X_)->binding->bd_getfmt)(_X_, _DCT_)
                    252: #define PARSE_SETFMT(_X_, _DCT_)       (*(_X_)->binding->bd_setfmt)(_X_, _DCT_)
                    253: #define PARSE_GETTIMECODE(_X_, _DCT_)  (*(_X_)->binding->bd_timecode)(_X_, _DCT_)
                    254: 
                    255: /*
                    256:  * special handling flags
                    257:  */
                    258: #define PARSE_F_PPSONSECOND    0x00000001 /* PPS pulses are on second */
                    259: #define PARSE_F_POWERUPTRUST   0x00000100 /* POWERUP state ist trusted for */
                    260:                                            /* trusttime after SYNC was seen */
                    261: /**===========================================================================
                    262:  ** error message regression handling
                    263:  **
                    264:  ** there are quite a few errors that can occur in rapid succession such as
                    265:  ** noisy input data or no data at all. in order to reduce the amount of
                    266:  ** syslog messages in such case, we are using a backoff algorithm. We limit
                    267:  ** the number of error messages of a certain class to 1 per time unit. if a
                    268:  ** configurable number of messages is displayed that way, we move on to the
                    269:  ** next time unit / count for that class. a count of messages that have been
                    270:  ** suppressed is held and displayed whenever a corresponding message is
                    271:  ** displayed. the time units for a message class will also be displayed.
                    272:  ** whenever an error condition clears we reset the error message state,
                    273:  ** thus we would still generate much output on pathological conditions
                    274:  ** where the system oscillates between OK and NOT OK states. coping
                    275:  ** with that condition is currently considered too complicated.
                    276:  **/
                    277: 
                    278: #define ERR_ALL                (unsigned)~0    /* "all" errors */
                    279: #define ERR_BADDATA    (unsigned)0     /* unusable input data/conversion errors */
                    280: #define ERR_NODATA     (unsigned)1     /* no input data */
                    281: #define ERR_BADIO      (unsigned)2     /* read/write/select errors */
                    282: #define ERR_BADSTATUS  (unsigned)3     /* unsync states */
                    283: #define ERR_BADEVENT   (unsigned)4     /* non nominal events */
                    284: #define ERR_INTERNAL   (unsigned)5     /* internal error */
                    285: #define ERR_CNT                (unsigned)(ERR_INTERNAL+1)
                    286: 
                    287: #define ERR(_X_)       if (list_err(parse, (_X_)))
                    288: 
                    289: struct errorregression
                    290: {
                    291:        u_long err_count;       /* number of repititions per class */
                    292:        u_long err_delay;       /* minimum delay between messages */
                    293: };
                    294: 
                    295: static struct errorregression
                    296: err_baddata[] =                        /* error messages for bad input data */
                    297: {
                    298:        { 1,       0 },         /* output first message immediately */
                    299:        { 5,      60 },         /* output next five messages in 60 second intervals */
                    300:        { 3,    3600 },         /* output next 3 messages in hour intervals */
                    301:        { 0, 12*3600 }          /* repeat messages only every 12 hours */
                    302: };
                    303: 
                    304: static struct errorregression
                    305: err_nodata[] =                 /* error messages for missing input data */
                    306: {
                    307:        { 1,       0 },         /* output first message immediately */
                    308:        { 5,      60 },         /* output next five messages in 60 second intervals */
                    309:        { 3,    3600 },         /* output next 3 messages in hour intervals */
                    310:        { 0, 12*3600 }          /* repeat messages only every 12 hours */
                    311: };
                    312: 
                    313: static struct errorregression
                    314: err_badstatus[] =              /* unsynchronized state messages */
                    315: {
                    316:        { 1,       0 },         /* output first message immediately */
                    317:        { 5,      60 },         /* output next five messages in 60 second intervals */
                    318:        { 3,    3600 },         /* output next 3 messages in hour intervals */
                    319:        { 0, 12*3600 }          /* repeat messages only every 12 hours */
                    320: };
                    321: 
                    322: static struct errorregression
                    323: err_badio[] =                  /* io failures (bad reads, selects, ...) */
                    324: {
                    325:        { 1,       0 },         /* output first message immediately */
                    326:        { 5,      60 },         /* output next five messages in 60 second intervals */
                    327:        { 5,    3600 },         /* output next 3 messages in hour intervals */
                    328:        { 0, 12*3600 }          /* repeat messages only every 12 hours */
                    329: };
                    330: 
                    331: static struct errorregression
                    332: err_badevent[] =               /* non nominal events */
                    333: {
                    334:        { 20,      0 },         /* output first message immediately */
                    335:        { 6,      60 },         /* output next five messages in 60 second intervals */
                    336:        { 5,    3600 },         /* output next 3 messages in hour intervals */
                    337:        { 0, 12*3600 }          /* repeat messages only every 12 hours */
                    338: };
                    339: 
                    340: static struct errorregression
                    341: err_internal[] =               /* really bad things - basically coding/OS errors */
                    342: {
                    343:        { 0,       0 },         /* output all messages immediately */
                    344: };
                    345: 
                    346: static struct errorregression *
                    347: err_tbl[] =
                    348: {
                    349:        err_baddata,
                    350:        err_nodata,
                    351:        err_badio,
                    352:        err_badstatus,
                    353:        err_badevent,
                    354:        err_internal
                    355: };
                    356: 
                    357: struct errorinfo
                    358: {
                    359:        u_long err_started;     /* begin time (ntp) of error condition */
                    360:        u_long err_last;        /* last time (ntp) error occurred */
                    361:        u_long err_cnt; /* number of error repititions */
                    362:        u_long err_suppressed;  /* number of suppressed messages */
                    363:        struct errorregression *err_stage; /* current error stage */
                    364: };
                    365: 
                    366: /**===========================================================================
                    367:  ** refclock instance data
                    368:  **/
                    369: 
                    370: struct parseunit
                    371: {
                    372:        /*
                    373:         * NTP management
                    374:         */
                    375:        struct peer         *peer;              /* backlink to peer structure - refclock inactive if 0  */
                    376:        struct refclockproc *generic;           /* backlink to refclockproc structure */
                    377: 
                    378:        /*
                    379:         * PARSE io
                    380:         */
                    381:        bind_t       *binding;          /* io handling binding */
                    382:        
                    383:        /*
                    384:         * parse state
                    385:         */
                    386:        parse_t       parseio;          /* io handling structure (user level parsing) */
                    387: 
                    388:        /*
                    389:         * type specific parameters
                    390:         */
                    391:        struct parse_clockinfo   *parse_type;           /* link to clock description */
                    392: 
                    393:        /*
                    394:         * clock state handling/reporting
                    395:         */
                    396:        u_char        flags;            /* flags (leap_control) */
                    397:        u_long        lastchange;       /* time (ntp) when last state change accured */
                    398:        u_long        statetime[CEVNT_MAX+1]; /* accumulated time of clock states */
                    399:        u_long        pollneeddata;     /* current_time(!=0) for receive sample expected in PPS mode */
                    400:        u_short       lastformat;       /* last format used */
                    401:        u_long        lastsync;         /* time (ntp) when clock was last seen fully synchronized */
                    402:         u_long        maxunsync;        /* max time in seconds a receiver is trusted after loosing synchronisation */
                    403:         double        ppsphaseadjust;   /* phase adjustment of PPS time stamp */
                    404:         u_long        lastmissed;       /* time (ntp) when poll didn't get data (powerup heuristic) */
                    405:        u_long        ppsserial;        /* magic cookie for ppsclock serials (avoids stale ppsclock data) */
                    406:        int           ppsfd;            /* fd to ise for PPS io */
                    407: #ifdef HAVE_PPSAPI
                    408:         int           hardppsstate;     /* current hard pps state */
                    409:        struct refclock_atom atom;      /* PPSAPI structure */
                    410: #endif
                    411:        parsetime_t   timedata;         /* last (parse module) data */
                    412:        void         *localdata;        /* optional local, receiver-specific data */
                    413:         unsigned long localstate;       /* private local state */
                    414:        struct errorinfo errors[ERR_CNT];  /* error state table for suppressing excessive error messages */
                    415:        struct ctl_var *kv;             /* additional pseudo variables */
                    416:        u_long        laststatistic;    /* time when staticstics where output */
                    417: };
                    418: 
                    419: 
                    420: /**===========================================================================
                    421:  ** Clockinfo section all parameter for specific clock types
                    422:  ** includes NTP parameters, TTY parameters and IO handling parameters
                    423:  **/
                    424: 
                    425: static void    poll_dpoll      (struct parseunit *);
                    426: static void    poll_poll       (struct peer *);
                    427: static int     poll_init       (struct parseunit *);
                    428: 
                    429: typedef struct poll_info
                    430: {
                    431:        u_long      rate;               /* poll rate - once every "rate" seconds - 0 off */
                    432:        const char *string;             /* string to send for polling */
                    433:        u_long      count;              /* number of characters in string */
                    434: } poll_info_t;
                    435: 
                    436: #define NO_CL_FLAGS    0
                    437: #define NO_POLL                0
                    438: #define NO_INIT                0
                    439: #define NO_END         0
                    440: #define NO_EVENT       0
                    441: #define NO_LCLDATA     0
                    442: #define NO_MESSAGE     0
                    443: #define NO_PPSDELAY     0
                    444: 
                    445: #define DCF_ID         "DCF"   /* generic DCF */
                    446: #define DCF_A_ID       "DCFa"  /* AM demodulation */
                    447: #define DCF_P_ID       "DCFp"  /* psuedo random phase shift */
                    448: #define GPS_ID         "GPS"   /* GPS receiver */
                    449: 
                    450: #define        NOCLOCK_ROOTDELAY       0.0
                    451: #define        NOCLOCK_BASEDELAY       0.0
                    452: #define        NOCLOCK_DESCRIPTION     0
                    453: #define NOCLOCK_MAXUNSYNC       0
                    454: #define NOCLOCK_CFLAG           0
                    455: #define NOCLOCK_IFLAG           0
                    456: #define NOCLOCK_OFLAG           0
                    457: #define NOCLOCK_LFLAG           0
                    458: #define NOCLOCK_ID             "TILT"
                    459: #define NOCLOCK_POLL           NO_POLL
                    460: #define NOCLOCK_INIT           NO_INIT
                    461: #define NOCLOCK_END            NO_END
                    462: #define NOCLOCK_DATA           NO_LCLDATA
                    463: #define NOCLOCK_FORMAT         ""
                    464: #define NOCLOCK_TYPE           CTL_SST_TS_UNSPEC
                    465: #define NOCLOCK_SAMPLES                0
                    466: #define NOCLOCK_KEEP           0 
                    467: 
                    468: #define DCF_TYPE               CTL_SST_TS_LF
                    469: #define GPS_TYPE               CTL_SST_TS_UHF
                    470: 
                    471: /*
                    472:  * receiver specific constants
                    473:  */
                    474: #define MBG_SPEED              (B9600)
                    475: #define MBG_CFLAG              (CS7|PARENB|CREAD|CLOCAL|HUPCL|CSTOPB)
                    476: #define MBG_IFLAG              (IGNBRK|IGNPAR|ISTRIP)
                    477: #define MBG_OFLAG              0
                    478: #define MBG_LFLAG              0
                    479: #define MBG_FLAGS               PARSE_F_PPSONSECOND
                    480: 
                    481: /*
                    482:  * Meinberg DCF77 receivers
                    483:  */
                    484: #define        DCFUA31_ROOTDELAY       0.0  /* 0 */
                    485: #define        DCFUA31_BASEDELAY       0.010  /* 10.7421875ms: 10 ms (+/- 3 ms) */
                    486: #define        DCFUA31_DESCRIPTION     "Meinberg DCF77 C51 or compatible"
                    487: #define DCFUA31_MAXUNSYNC       60*30       /* only trust clock for 1/2 hour */
                    488: #define DCFUA31_SPEED          MBG_SPEED
                    489: #define DCFUA31_CFLAG           MBG_CFLAG
                    490: #define DCFUA31_IFLAG           MBG_IFLAG
                    491: #define DCFUA31_OFLAG           MBG_OFLAG
                    492: #define DCFUA31_LFLAG           MBG_LFLAG
                    493: #define DCFUA31_SAMPLES                5
                    494: #define DCFUA31_KEEP           3
                    495: #define DCFUA31_FORMAT         "Meinberg Standard"
                    496: 
                    497: /*
                    498:  * Meinberg DCF PZF535/TCXO (FM/PZF) receiver
                    499:  */
                    500: #define        DCFPZF535_ROOTDELAY     0.0
                    501: #define        DCFPZF535_BASEDELAY     0.001968  /* 1.968ms +- 104us (oscilloscope) - relative to start (end of STX) */
                    502: #define        DCFPZF535_DESCRIPTION   "Meinberg DCF PZF 535/509 / TCXO"
                    503: #define DCFPZF535_MAXUNSYNC     60*60*12           /* only trust clock for 12 hours
                    504:                                                    * @ 5e-8df/f we have accumulated
                    505:                                                    * at most 2.16 ms (thus we move to
                    506:                                                    * NTP synchronisation */
                    507: #define DCFPZF535_SPEED                MBG_SPEED
                    508: #define DCFPZF535_CFLAG         MBG_CFLAG
                    509: #define DCFPZF535_IFLAG         MBG_IFLAG
                    510: #define DCFPZF535_OFLAG         MBG_OFLAG
                    511: #define DCFPZF535_LFLAG         MBG_LFLAG
                    512: #define DCFPZF535_SAMPLES             5
                    513: #define DCFPZF535_KEEP                3
                    514: #define DCFPZF535_FORMAT       "Meinberg Standard"
                    515: 
                    516: /*
                    517:  * Meinberg DCF PZF535/OCXO receiver
                    518:  */
                    519: #define        DCFPZF535OCXO_ROOTDELAY 0.0
                    520: #define        DCFPZF535OCXO_BASEDELAY 0.001968 /* 1.968ms +- 104us (oscilloscope) - relative to start (end of STX) */
                    521: #define        DCFPZF535OCXO_DESCRIPTION "Meinberg DCF PZF 535/509 / OCXO"
                    522: #define DCFPZF535OCXO_MAXUNSYNC     60*60*96       /* only trust clock for 4 days
                    523:                                                    * @ 5e-9df/f we have accumulated
                    524:                                                    * at most an error of 1.73 ms
                    525:                                                    * (thus we move to NTP synchronisation) */
                    526: #define DCFPZF535OCXO_SPEED        MBG_SPEED
                    527: #define DCFPZF535OCXO_CFLAG         MBG_CFLAG
                    528: #define DCFPZF535OCXO_IFLAG         MBG_IFLAG
                    529: #define DCFPZF535OCXO_OFLAG         MBG_OFLAG
                    530: #define DCFPZF535OCXO_LFLAG         MBG_LFLAG
                    531: #define DCFPZF535OCXO_SAMPLES             5
                    532: #define DCFPZF535OCXO_KEEP                3
                    533: #define DCFPZF535OCXO_FORMAT       "Meinberg Standard"
                    534: 
                    535: /*
                    536:  * Meinberg GPS16X receiver
                    537:  */
                    538: static void    gps16x_message   (struct parseunit *, parsetime_t *);
                    539: static  int     gps16x_poll_init (struct parseunit *);
                    540: 
                    541: #define        GPS16X_ROOTDELAY        0.0         /* nothing here */
                    542: #define        GPS16X_BASEDELAY        0.001968         /* XXX to be fixed ! 1.968ms +- 104us (oscilloscope) - relative to start (end of STX) */
                    543: #define        GPS16X_DESCRIPTION      "Meinberg GPS16x receiver"
                    544: #define GPS16X_MAXUNSYNC        60*60*96       /* only trust clock for 4 days
                    545:                                                * @ 5e-9df/f we have accumulated
                    546:                                                * at most an error of 1.73 ms
                    547:                                                * (thus we move to NTP synchronisation) */
                    548: #define GPS16X_SPEED           B19200
                    549: #define GPS16X_CFLAG            (CS8|CREAD|CLOCAL|HUPCL)
                    550: #define GPS16X_IFLAG            (IGNBRK|IGNPAR)
                    551: #define GPS16X_OFLAG            MBG_OFLAG
                    552: #define GPS16X_LFLAG            MBG_LFLAG
                    553: #define GPS16X_POLLRATE        6
                    554: #define GPS16X_POLLCMD ""
                    555: #define GPS16X_CMDSIZE 0
                    556: 
                    557: static poll_info_t gps16x_pollinfo = { GPS16X_POLLRATE, GPS16X_POLLCMD, GPS16X_CMDSIZE };
                    558: 
                    559: #define GPS16X_INIT            gps16x_poll_init
                    560: #define GPS16X_POLL            0
                    561: #define GPS16X_END             0
                    562: #define GPS16X_DATA            ((void *)(&gps16x_pollinfo))
                    563: #define GPS16X_MESSAGE         gps16x_message
                    564: #define GPS16X_ID              GPS_ID
                    565: #define GPS16X_FORMAT          "Meinberg GPS Extended"
                    566: #define GPS16X_SAMPLES         5
                    567: #define GPS16X_KEEP            3
                    568: 
                    569: /*
                    570:  * ELV DCF7000 Wallclock-Receiver/Switching Clock (Kit)
                    571:  *
                    572:  * This is really not the hottest clock - but before you have nothing ...
                    573:  */
                    574: #define DCF7000_ROOTDELAY      0.0 /* 0 */
                    575: #define DCF7000_BASEDELAY      0.405 /* slow blow */
                    576: #define DCF7000_DESCRIPTION    "ELV DCF7000"
                    577: #define DCF7000_MAXUNSYNC      (60*5) /* sorry - but it just was not build as a clock */
                    578: #define DCF7000_SPEED          (B9600)
                    579: #define DCF7000_CFLAG           (CS8|CREAD|PARENB|PARODD|CLOCAL|HUPCL)
                    580: #define DCF7000_IFLAG          (IGNBRK)
                    581: #define DCF7000_OFLAG          0
                    582: #define DCF7000_LFLAG          0
                    583: #define DCF7000_SAMPLES                5
                    584: #define DCF7000_KEEP           3
                    585: #define DCF7000_FORMAT         "ELV DCF7000"
                    586: 
                    587: /*
                    588:  * Schmid DCF Receiver Kit
                    589:  *
                    590:  * When the WSDCF clock is operating optimally we want the primary clock
                    591:  * distance to come out at 300 ms.  Thus, peer.distance in the WSDCF peer
                    592:  * structure is set to 290 ms and we compute delays which are at least
                    593:  * 10 ms long.  The following are 290 ms and 10 ms expressed in u_fp format
                    594:  */
                    595: #define WS_POLLRATE    1       /* every second - watch interdependency with poll routine */
                    596: #define WS_POLLCMD     "\163"
                    597: #define WS_CMDSIZE     1
                    598: 
                    599: static poll_info_t wsdcf_pollinfo = { WS_POLLRATE, WS_POLLCMD, WS_CMDSIZE };
                    600: 
                    601: #define WSDCF_INIT             poll_init
                    602: #define WSDCF_POLL             poll_dpoll
                    603: #define WSDCF_END              0
                    604: #define WSDCF_DATA             ((void *)(&wsdcf_pollinfo))
                    605: #define        WSDCF_ROOTDELAY         0.0     /* 0 */
                    606: #define        WSDCF_BASEDELAY         0.010   /*  ~  10ms */
                    607: #define WSDCF_DESCRIPTION      "WS/DCF Receiver"
                    608: #define WSDCF_FORMAT           "Schmid"
                    609: #define WSDCF_MAXUNSYNC                (60*60) /* assume this beast hold at 1 h better than 2 ms XXX-must verify */
                    610: #define WSDCF_SPEED            (B1200)
                    611: #define WSDCF_CFLAG            (CS8|CREAD|CLOCAL)
                    612: #define WSDCF_IFLAG            0
                    613: #define WSDCF_OFLAG            0
                    614: #define WSDCF_LFLAG            0
                    615: #define WSDCF_SAMPLES          5
                    616: #define WSDCF_KEEP             3
                    617: 
                    618: /*
                    619:  * RAW DCF77 - input of DCF marks via RS232 - many variants
                    620:  */
                    621: #define RAWDCF_FLAGS           0
                    622: #define RAWDCF_ROOTDELAY       0.0 /* 0 */
                    623: #define RAWDCF_BASEDELAY       0.258
                    624: #define RAWDCF_FORMAT          "RAW DCF77 Timecode"
                    625: #define RAWDCF_MAXUNSYNC       (0) /* sorry - its a true receiver - no signal - no time */
                    626: #define RAWDCF_SPEED           (B50)
                    627: #ifdef NO_PARENB_IGNPAR /* Was: defined(SYS_IRIX4) || defined(SYS_IRIX5) */
                    628: /* somehow doesn't grok PARENB & IGNPAR (mj) */
                    629: # define RAWDCF_CFLAG            (CS8|CREAD|CLOCAL)
                    630: #else
                    631: # define RAWDCF_CFLAG            (CS8|CREAD|CLOCAL|PARENB)
                    632: #endif
                    633: #ifdef RAWDCF_NO_IGNPAR /* Was: defined(SYS_LINUX) && defined(CLOCK_RAWDCF) */
                    634: # define RAWDCF_IFLAG          0
                    635: #else
                    636: # define RAWDCF_IFLAG          (IGNPAR)
                    637: #endif
                    638: #define RAWDCF_OFLAG           0
                    639: #define RAWDCF_LFLAG           0
                    640: #define RAWDCF_SAMPLES         20
                    641: #define RAWDCF_KEEP            12
                    642: #define RAWDCF_INIT            0
                    643: 
                    644: /*
                    645:  * RAW DCF variants
                    646:  */
                    647: /*
                    648:  * Conrad receiver
                    649:  *
                    650:  * simplest (cheapest) DCF clock - e. g. DCF77 receiver by Conrad
                    651:  * (~40DM - roughly $30 ) followed by a level converter for RS232
                    652:  */
                    653: #define CONRAD_BASEDELAY       0.292 /* Conrad receiver @ 50 Baud on a Sun */
                    654: #define CONRAD_DESCRIPTION     "RAW DCF77 CODE (Conrad DCF77 receiver module)"
                    655: 
                    656: /* Gude Analog- und Digitalsystem GmbH 'Expert mouseCLOCK USB v2.0' */
                    657: #define GUDE_EMC_USB_V20_SPEED            (B4800)
                    658: #define GUDE_EMC_USB_V20_BASEDELAY        0.425 /* USB serial<->USB converter FTDI232R */
                    659: #define GUDE_EMC_USB_V20_DESCRIPTION      "RAW DCF77 CODE (Expert mouseCLOCK USB v2.0)"
                    660: 
                    661: /*
                    662:  * TimeBrick receiver
                    663:  */
                    664: #define TIMEBRICK_BASEDELAY    0.210 /* TimeBrick @ 50 Baud on a Sun */
                    665: #define TIMEBRICK_DESCRIPTION  "RAW DCF77 CODE (TimeBrick)"
                    666: 
                    667: /*
                    668:  * IGEL:clock receiver
                    669:  */
                    670: #define IGELCLOCK_BASEDELAY    0.258 /* IGEL:clock receiver */
                    671: #define IGELCLOCK_DESCRIPTION  "RAW DCF77 CODE (IGEL:clock)"
                    672: #define IGELCLOCK_SPEED                (B1200)
                    673: #define IGELCLOCK_CFLAG                (CS8|CREAD|HUPCL|CLOCAL)
                    674: 
                    675: /*
                    676:  * RAWDCF receivers that need to be powered from DTR
                    677:  * (like Expert mouse clock)
                    678:  */
                    679: static int     rawdcf_init_1   (struct parseunit *);
                    680: #define RAWDCFDTRSET_DESCRIPTION       "RAW DCF77 CODE (DTR SET/RTS CLR)"
                    681: #define RAWDCFDTRSET75_DESCRIPTION     "RAW DCF77 CODE (DTR SET/RTS CLR @ 75 baud)"
                    682: #define RAWDCFDTRSET_INIT              rawdcf_init_1
                    683: 
                    684: /*
                    685:  * RAWDCF receivers that need to be powered from
                    686:  * DTR CLR and RTS SET
                    687:  */
                    688: static int     rawdcf_init_2   (struct parseunit *);
                    689: #define RAWDCFDTRCLRRTSSET_DESCRIPTION "RAW DCF77 CODE (DTR CLR/RTS SET)"
                    690: #define RAWDCFDTRCLRRTSSET75_DESCRIPTION "RAW DCF77 CODE (DTR CLR/RTS SET @ 75 baud)"
                    691: #define RAWDCFDTRCLRRTSSET_INIT        rawdcf_init_2
                    692: 
                    693: /*
                    694:  * Trimble GPS receivers (TAIP and TSIP protocols)
                    695:  */
                    696: #ifndef TRIM_POLLRATE
                    697: #define TRIM_POLLRATE  0       /* only true direct polling */
                    698: #endif
                    699: 
                    700: #define TRIM_TAIPPOLLCMD       ">SRM;FR_FLAG=F;EC_FLAG=F<>QTM<"
                    701: #define TRIM_TAIPCMDSIZE       (sizeof(TRIM_TAIPPOLLCMD)-1)
                    702: 
                    703: static poll_info_t trimbletaip_pollinfo = { TRIM_POLLRATE, TRIM_TAIPPOLLCMD, TRIM_TAIPCMDSIZE };
                    704: static int     trimbletaip_init        (struct parseunit *);
                    705: static void    trimbletaip_event       (struct parseunit *, int);
                    706: 
                    707: /* query time & UTC correction data */
                    708: static char tsipquery[] = { DLE, 0x21, DLE, ETX, DLE, 0x2F, DLE, ETX };
                    709: 
                    710: static poll_info_t trimbletsip_pollinfo = { TRIM_POLLRATE, tsipquery, sizeof(tsipquery) };
                    711: static int     trimbletsip_init        (struct parseunit *);
                    712: static void    trimbletsip_end         (struct parseunit *);
                    713: static void    trimbletsip_message     (struct parseunit *, parsetime_t *);
                    714: static void    trimbletsip_event       (struct parseunit *, int);
                    715: 
                    716: #define TRIMBLETSIP_IDLE_TIME      (300) /* 5 minutes silence at most */
                    717: #define TRIMBLE_RESET_HOLDOFF       TRIMBLETSIP_IDLE_TIME
                    718: 
                    719: #define TRIMBLETAIP_SPEED          (B4800)
                    720: #define TRIMBLETAIP_CFLAG           (CS8|CREAD|CLOCAL)
                    721: #define TRIMBLETAIP_IFLAG           (BRKINT|IGNPAR|ISTRIP|ICRNL|IXON)
                    722: #define TRIMBLETAIP_OFLAG           (OPOST|ONLCR)
                    723: #define TRIMBLETAIP_LFLAG           (0)
                    724: 
                    725: #define TRIMBLETSIP_SPEED          (B9600)
                    726: #define TRIMBLETSIP_CFLAG           (CS8|CLOCAL|CREAD|PARENB|PARODD)
                    727: #define TRIMBLETSIP_IFLAG           (IGNBRK)
                    728: #define TRIMBLETSIP_OFLAG           (0)
                    729: #define TRIMBLETSIP_LFLAG           (ICANON)
                    730: 
                    731: #define TRIMBLETSIP_SAMPLES        5
                    732: #define TRIMBLETSIP_KEEP           3
                    733: #define TRIMBLETAIP_SAMPLES        5
                    734: #define TRIMBLETAIP_KEEP           3
                    735: 
                    736: #define TRIMBLETAIP_FLAGS          (PARSE_F_PPSONSECOND)
                    737: #define TRIMBLETSIP_FLAGS          (TRIMBLETAIP_FLAGS)
                    738: 
                    739: #define TRIMBLETAIP_POLL           poll_dpoll
                    740: #define TRIMBLETSIP_POLL           poll_dpoll
                    741: 
                    742: #define TRIMBLETAIP_INIT           trimbletaip_init
                    743: #define TRIMBLETSIP_INIT           trimbletsip_init
                    744: 
                    745: #define TRIMBLETAIP_EVENT          trimbletaip_event   
                    746: 
                    747: #define TRIMBLETSIP_EVENT          trimbletsip_event   
                    748: #define TRIMBLETSIP_MESSAGE        trimbletsip_message
                    749: 
                    750: #define TRIMBLETAIP_END                    0
                    751: #define TRIMBLETSIP_END                    trimbletsip_end
                    752: 
                    753: #define TRIMBLETAIP_DATA           ((void *)(&trimbletaip_pollinfo))
                    754: #define TRIMBLETSIP_DATA           ((void *)(&trimbletsip_pollinfo))
                    755: 
                    756: #define TRIMBLETAIP_ID             GPS_ID
                    757: #define TRIMBLETSIP_ID             GPS_ID
                    758: 
                    759: #define TRIMBLETAIP_FORMAT         "Trimble TAIP"
                    760: #define TRIMBLETSIP_FORMAT         "Trimble TSIP"
                    761: 
                    762: #define TRIMBLETAIP_ROOTDELAY        0x0
                    763: #define TRIMBLETSIP_ROOTDELAY        0x0
                    764: 
                    765: #define TRIMBLETAIP_BASEDELAY        0.0
                    766: #define TRIMBLETSIP_BASEDELAY        0.020     /* GPS time message latency */
                    767: 
                    768: #define TRIMBLETAIP_DESCRIPTION      "Trimble GPS (TAIP) receiver"
                    769: #define TRIMBLETSIP_DESCRIPTION      "Trimble GPS (TSIP) receiver"
                    770: 
                    771: #define TRIMBLETAIP_MAXUNSYNC        0
                    772: #define TRIMBLETSIP_MAXUNSYNC        0
                    773: 
                    774: #define TRIMBLETAIP_EOL                    '<'
                    775: 
                    776: /*
                    777:  * RadioCode Clocks RCC 800 receiver
                    778:  */
                    779: #define RCC_POLLRATE   0       /* only true direct polling */
                    780: #define RCC_POLLCMD    "\r"
                    781: #define RCC_CMDSIZE    1
                    782: 
                    783: static poll_info_t rcc8000_pollinfo = { RCC_POLLRATE, RCC_POLLCMD, RCC_CMDSIZE };
                    784: #define RCC8000_FLAGS          0
                    785: #define RCC8000_POLL            poll_dpoll
                    786: #define RCC8000_INIT            poll_init
                    787: #define RCC8000_END             0
                    788: #define RCC8000_DATA            ((void *)(&rcc8000_pollinfo))
                    789: #define RCC8000_ROOTDELAY       0.0
                    790: #define RCC8000_BASEDELAY       0.0
                    791: #define RCC8000_ID              "MSF"
                    792: #define RCC8000_DESCRIPTION     "RCC 8000 MSF Receiver"
                    793: #define RCC8000_FORMAT          "Radiocode RCC8000"
                    794: #define RCC8000_MAXUNSYNC       (60*60) /* should be ok for an hour */
                    795: #define RCC8000_SPEED          (B2400)
                    796: #define RCC8000_CFLAG           (CS8|CREAD|CLOCAL)
                    797: #define RCC8000_IFLAG           (IGNBRK|IGNPAR)
                    798: #define RCC8000_OFLAG           0
                    799: #define RCC8000_LFLAG           0
                    800: #define RCC8000_SAMPLES         5
                    801: #define RCC8000_KEEP           3
                    802: 
                    803: /*
                    804:  * Hopf Radio clock 6021 Format 
                    805:  *
                    806:  */
                    807: #define HOPF6021_ROOTDELAY     0.0
                    808: #define HOPF6021_BASEDELAY     0.0
                    809: #define HOPF6021_DESCRIPTION   "HOPF 6021"
                    810: #define HOPF6021_FORMAT         "hopf Funkuhr 6021"
                    811: #define HOPF6021_MAXUNSYNC     (60*60)  /* should be ok for an hour */
                    812: #define HOPF6021_SPEED         (B9600)
                    813: #define HOPF6021_CFLAG          (CS8|CREAD|CLOCAL)
                    814: #define HOPF6021_IFLAG         (IGNBRK|ISTRIP)
                    815: #define HOPF6021_OFLAG         0
                    816: #define HOPF6021_LFLAG         0
                    817: #define HOPF6021_FLAGS          0
                    818: #define HOPF6021_SAMPLES        5
                    819: #define HOPF6021_KEEP          3
                    820: 
                    821: /*
                    822:  * Diem's Computime Radio Clock Receiver
                    823:  */
                    824: #define COMPUTIME_FLAGS       0
                    825: #define COMPUTIME_ROOTDELAY   0.0
                    826: #define COMPUTIME_BASEDELAY   0.0
                    827: #define COMPUTIME_ID          DCF_ID
                    828: #define COMPUTIME_DESCRIPTION "Diem's Computime receiver"
                    829: #define COMPUTIME_FORMAT      "Diem's Computime Radio Clock"
                    830: #define COMPUTIME_TYPE        DCF_TYPE
                    831: #define COMPUTIME_MAXUNSYNC   (60*60)       /* only trust clock for 1 hour */
                    832: #define COMPUTIME_SPEED       (B9600)
                    833: #define COMPUTIME_CFLAG       (CSTOPB|CS7|CREAD|CLOCAL)
                    834: #define COMPUTIME_IFLAG       (IGNBRK|IGNPAR|ISTRIP)
                    835: #define COMPUTIME_OFLAG       0
                    836: #define COMPUTIME_LFLAG       0
                    837: #define COMPUTIME_SAMPLES     5
                    838: #define COMPUTIME_KEEP        3
                    839: 
                    840: /*
                    841:  * Varitext Radio Clock Receiver
                    842:  */
                    843: #define VARITEXT_FLAGS       0
                    844: #define VARITEXT_ROOTDELAY   0.0
                    845: #define VARITEXT_BASEDELAY   0.0
                    846: #define VARITEXT_ID          "MSF"
                    847: #define VARITEXT_DESCRIPTION "Varitext receiver"
                    848: #define VARITEXT_FORMAT      "Varitext Radio Clock"
                    849: #define VARITEXT_TYPE        DCF_TYPE
                    850: #define VARITEXT_MAXUNSYNC   (60*60)       /* only trust clock for 1 hour */
                    851: #define VARITEXT_SPEED       (B9600)
                    852: #define VARITEXT_CFLAG       (CS7|CREAD|CLOCAL|PARENB|PARODD)
                    853: #define VARITEXT_IFLAG       (IGNPAR|IGNBRK|INPCK) /*|ISTRIP)*/
                    854: #define VARITEXT_OFLAG       0
                    855: #define VARITEXT_LFLAG       0
                    856: #define VARITEXT_SAMPLES     32
                    857: #define VARITEXT_KEEP        20
                    858: 
                    859: static struct parse_clockinfo
                    860: {
                    861:        u_long  cl_flags;               /* operation flags (PPS interpretation, trust handling) */
                    862:   void  (*cl_poll)    (struct parseunit *);                    /* active poll routine */
                    863:   int   (*cl_init)    (struct parseunit *);                    /* active poll init routine */
                    864:   void  (*cl_event)   (struct parseunit *, int);               /* special event handling (e.g. reset clock) */
                    865:   void  (*cl_end)     (struct parseunit *);                    /* active poll end routine */
                    866:   void  (*cl_message) (struct parseunit *, parsetime_t *);     /* process a lower layer message */
                    867:        void   *cl_data;                /* local data area for "poll" mechanism */
                    868:        double    cl_rootdelay;         /* rootdelay */
                    869:        double    cl_basedelay;         /* current offset by which the RS232
                    870:                                time code is delayed from the actual time */
                    871:        const char *cl_id;              /* ID code */
                    872:        const char *cl_description;             /* device name */
                    873:        const char *cl_format;          /* fixed format */
                    874:        u_char  cl_type;                /* clock type (ntp control) */
                    875:        u_long  cl_maxunsync;           /* time to trust oscillator after losing synch */
                    876:        u_long  cl_speed;               /* terminal input & output baudrate */
                    877:        u_long  cl_cflag;             /* terminal control flags */
                    878:        u_long  cl_iflag;             /* terminal input flags */
                    879:        u_long  cl_oflag;             /* terminal output flags */
                    880:        u_long  cl_lflag;             /* terminal local flags */
                    881:        u_long  cl_samples;           /* samples for median filter */
                    882:        u_long  cl_keep;              /* samples for median filter to keep */
                    883: } parse_clockinfo[] =
                    884: {
                    885:        {                               /* mode 0 */
                    886:                MBG_FLAGS,
                    887:                NO_POLL,
                    888:                NO_INIT,
                    889:                NO_EVENT,
                    890:                NO_END,
                    891:                NO_MESSAGE,
                    892:                NO_LCLDATA,
                    893:                DCFPZF535_ROOTDELAY,
                    894:                DCFPZF535_BASEDELAY,
                    895:                DCF_P_ID,
                    896:                DCFPZF535_DESCRIPTION,
                    897:                DCFPZF535_FORMAT,
                    898:                DCF_TYPE,
                    899:                DCFPZF535_MAXUNSYNC,
                    900:                DCFPZF535_SPEED,
                    901:                DCFPZF535_CFLAG,
                    902:                DCFPZF535_IFLAG,
                    903:                DCFPZF535_OFLAG,
                    904:                DCFPZF535_LFLAG,
                    905:                DCFPZF535_SAMPLES,
                    906:                DCFPZF535_KEEP
                    907:        },
                    908:        {                               /* mode 1 */
                    909:                MBG_FLAGS,
                    910:                NO_POLL,
                    911:                NO_INIT,
                    912:                NO_EVENT,
                    913:                NO_END,
                    914:                NO_MESSAGE,
                    915:                NO_LCLDATA,
                    916:                DCFPZF535OCXO_ROOTDELAY,
                    917:                DCFPZF535OCXO_BASEDELAY,
                    918:                DCF_P_ID,
                    919:                DCFPZF535OCXO_DESCRIPTION,
                    920:                DCFPZF535OCXO_FORMAT,
                    921:                DCF_TYPE,
                    922:                DCFPZF535OCXO_MAXUNSYNC,
                    923:                DCFPZF535OCXO_SPEED,
                    924:                DCFPZF535OCXO_CFLAG,
                    925:                DCFPZF535OCXO_IFLAG,
                    926:                DCFPZF535OCXO_OFLAG,
                    927:                DCFPZF535OCXO_LFLAG,
                    928:                DCFPZF535OCXO_SAMPLES,
                    929:                DCFPZF535OCXO_KEEP
                    930:        },
                    931:        {                               /* mode 2 */
                    932:                MBG_FLAGS,
                    933:                NO_POLL,
                    934:                NO_INIT,
                    935:                NO_EVENT,
                    936:                NO_END,
                    937:                NO_MESSAGE,
                    938:                NO_LCLDATA,
                    939:                DCFUA31_ROOTDELAY,
                    940:                DCFUA31_BASEDELAY,
                    941:                DCF_A_ID,
                    942:                DCFUA31_DESCRIPTION,
                    943:                DCFUA31_FORMAT,
                    944:                DCF_TYPE,
                    945:                DCFUA31_MAXUNSYNC,
                    946:                DCFUA31_SPEED,
                    947:                DCFUA31_CFLAG,
                    948:                DCFUA31_IFLAG,
                    949:                DCFUA31_OFLAG,
                    950:                DCFUA31_LFLAG,
                    951:                DCFUA31_SAMPLES,
                    952:                DCFUA31_KEEP
                    953:        },
                    954:        {                               /* mode 3 */
                    955:                MBG_FLAGS,
                    956:                NO_POLL,
                    957:                NO_INIT,
                    958:                NO_EVENT,
                    959:                NO_END,
                    960:                NO_MESSAGE,
                    961:                NO_LCLDATA,
                    962:                DCF7000_ROOTDELAY,
                    963:                DCF7000_BASEDELAY,
                    964:                DCF_A_ID,
                    965:                DCF7000_DESCRIPTION,
                    966:                DCF7000_FORMAT,
                    967:                DCF_TYPE,
                    968:                DCF7000_MAXUNSYNC,
                    969:                DCF7000_SPEED,
                    970:                DCF7000_CFLAG,
                    971:                DCF7000_IFLAG,
                    972:                DCF7000_OFLAG,
                    973:                DCF7000_LFLAG,
                    974:                DCF7000_SAMPLES,
                    975:                DCF7000_KEEP
                    976:        },
                    977:        {                               /* mode 4 */
                    978:                NO_CL_FLAGS,
                    979:                WSDCF_POLL,
                    980:                WSDCF_INIT,
                    981:                NO_EVENT,
                    982:                WSDCF_END,
                    983:                NO_MESSAGE,
                    984:                WSDCF_DATA,
                    985:                WSDCF_ROOTDELAY,
                    986:                WSDCF_BASEDELAY,
                    987:                DCF_A_ID,
                    988:                WSDCF_DESCRIPTION,
                    989:                WSDCF_FORMAT,
                    990:                DCF_TYPE,
                    991:                WSDCF_MAXUNSYNC,
                    992:                WSDCF_SPEED,
                    993:                WSDCF_CFLAG,
                    994:                WSDCF_IFLAG,
                    995:                WSDCF_OFLAG,
                    996:                WSDCF_LFLAG,
                    997:                WSDCF_SAMPLES,
                    998:                WSDCF_KEEP
                    999:        },
                   1000:        {                               /* mode 5 */
                   1001:                RAWDCF_FLAGS,
                   1002:                NO_POLL,
                   1003:                RAWDCF_INIT,
                   1004:                NO_EVENT,
                   1005:                NO_END,
                   1006:                NO_MESSAGE,
                   1007:                NO_LCLDATA,
                   1008:                RAWDCF_ROOTDELAY,
                   1009:                CONRAD_BASEDELAY,
                   1010:                DCF_A_ID,
                   1011:                CONRAD_DESCRIPTION,
                   1012:                RAWDCF_FORMAT,
                   1013:                DCF_TYPE,
                   1014:                RAWDCF_MAXUNSYNC,
                   1015:                RAWDCF_SPEED,
                   1016:                RAWDCF_CFLAG,
                   1017:                RAWDCF_IFLAG,
                   1018:                RAWDCF_OFLAG,
                   1019:                RAWDCF_LFLAG,
                   1020:                RAWDCF_SAMPLES,
                   1021:                RAWDCF_KEEP
                   1022:        },
                   1023:        {                               /* mode 6 */
                   1024:                RAWDCF_FLAGS,
                   1025:                NO_POLL,
                   1026:                RAWDCF_INIT,
                   1027:                NO_EVENT,
                   1028:                NO_END,
                   1029:                NO_MESSAGE,
                   1030:                NO_LCLDATA,
                   1031:                RAWDCF_ROOTDELAY,
                   1032:                TIMEBRICK_BASEDELAY,
                   1033:                DCF_A_ID,
                   1034:                TIMEBRICK_DESCRIPTION,
                   1035:                RAWDCF_FORMAT,
                   1036:                DCF_TYPE,
                   1037:                RAWDCF_MAXUNSYNC,
                   1038:                RAWDCF_SPEED,
                   1039:                RAWDCF_CFLAG,
                   1040:                RAWDCF_IFLAG,
                   1041:                RAWDCF_OFLAG,
                   1042:                RAWDCF_LFLAG,
                   1043:                RAWDCF_SAMPLES,
                   1044:                RAWDCF_KEEP
                   1045:        },
                   1046:        {                               /* mode 7 */
                   1047:                MBG_FLAGS,
                   1048:                GPS16X_POLL,
                   1049:                GPS16X_INIT,
                   1050:                NO_EVENT,
                   1051:                GPS16X_END,
                   1052:                GPS16X_MESSAGE,
                   1053:                GPS16X_DATA,
                   1054:                GPS16X_ROOTDELAY,
                   1055:                GPS16X_BASEDELAY,
                   1056:                GPS16X_ID,
                   1057:                GPS16X_DESCRIPTION,
                   1058:                GPS16X_FORMAT,
                   1059:                GPS_TYPE,
                   1060:                GPS16X_MAXUNSYNC,
                   1061:                GPS16X_SPEED,
                   1062:                GPS16X_CFLAG,
                   1063:                GPS16X_IFLAG,
                   1064:                GPS16X_OFLAG,
                   1065:                GPS16X_LFLAG,
                   1066:                GPS16X_SAMPLES,
                   1067:                GPS16X_KEEP
                   1068:        },
                   1069:        {                               /* mode 8 */
                   1070:                RAWDCF_FLAGS,
                   1071:                NO_POLL,
                   1072:                NO_INIT,
                   1073:                NO_EVENT,
                   1074:                NO_END,
                   1075:                NO_MESSAGE,
                   1076:                NO_LCLDATA,
                   1077:                RAWDCF_ROOTDELAY,
                   1078:                IGELCLOCK_BASEDELAY,
                   1079:                DCF_A_ID,
                   1080:                IGELCLOCK_DESCRIPTION,
                   1081:                RAWDCF_FORMAT,
                   1082:                DCF_TYPE,
                   1083:                RAWDCF_MAXUNSYNC,
                   1084:                IGELCLOCK_SPEED,
                   1085:                IGELCLOCK_CFLAG,
                   1086:                RAWDCF_IFLAG,
                   1087:                RAWDCF_OFLAG,
                   1088:                RAWDCF_LFLAG,
                   1089:                RAWDCF_SAMPLES,
                   1090:                RAWDCF_KEEP
                   1091:        },
                   1092:        {                               /* mode 9 */
                   1093:                TRIMBLETAIP_FLAGS,
                   1094: #if TRIM_POLLRATE              /* DHD940515: Allow user config */
                   1095:                NO_POLL,
                   1096: #else
                   1097:                TRIMBLETAIP_POLL,
                   1098: #endif
                   1099:                TRIMBLETAIP_INIT,
                   1100:                TRIMBLETAIP_EVENT,
                   1101:                TRIMBLETAIP_END,
                   1102:                NO_MESSAGE,
                   1103:                TRIMBLETAIP_DATA,
                   1104:                TRIMBLETAIP_ROOTDELAY,
                   1105:                TRIMBLETAIP_BASEDELAY,
                   1106:                TRIMBLETAIP_ID,
                   1107:                TRIMBLETAIP_DESCRIPTION,
                   1108:                TRIMBLETAIP_FORMAT,
                   1109:                GPS_TYPE,
                   1110:                TRIMBLETAIP_MAXUNSYNC,
                   1111:                TRIMBLETAIP_SPEED,
                   1112:                TRIMBLETAIP_CFLAG,
                   1113:                TRIMBLETAIP_IFLAG,
                   1114:                TRIMBLETAIP_OFLAG,
                   1115:                TRIMBLETAIP_LFLAG,
                   1116:                TRIMBLETAIP_SAMPLES,
                   1117:                TRIMBLETAIP_KEEP
                   1118:        },
                   1119:        {                               /* mode 10 */
                   1120:                TRIMBLETSIP_FLAGS,
                   1121: #if TRIM_POLLRATE              /* DHD940515: Allow user config */
                   1122:                NO_POLL,
                   1123: #else
                   1124:                TRIMBLETSIP_POLL,
                   1125: #endif
                   1126:                TRIMBLETSIP_INIT,
                   1127:                TRIMBLETSIP_EVENT,
                   1128:                TRIMBLETSIP_END,
                   1129:                TRIMBLETSIP_MESSAGE,
                   1130:                TRIMBLETSIP_DATA,
                   1131:                TRIMBLETSIP_ROOTDELAY,
                   1132:                TRIMBLETSIP_BASEDELAY,
                   1133:                TRIMBLETSIP_ID,
                   1134:                TRIMBLETSIP_DESCRIPTION,
                   1135:                TRIMBLETSIP_FORMAT,
                   1136:                GPS_TYPE,
                   1137:                TRIMBLETSIP_MAXUNSYNC,
                   1138:                TRIMBLETSIP_SPEED,
                   1139:                TRIMBLETSIP_CFLAG,
                   1140:                TRIMBLETSIP_IFLAG,
                   1141:                TRIMBLETSIP_OFLAG,
                   1142:                TRIMBLETSIP_LFLAG,
                   1143:                TRIMBLETSIP_SAMPLES,
                   1144:                TRIMBLETSIP_KEEP
                   1145:        },
                   1146:        {                             /* mode 11 */
                   1147:                NO_CL_FLAGS,
                   1148:                RCC8000_POLL,
                   1149:                RCC8000_INIT,
                   1150:                NO_EVENT,
                   1151:                RCC8000_END,
                   1152:                NO_MESSAGE,
                   1153:                RCC8000_DATA,
                   1154:                RCC8000_ROOTDELAY,
                   1155:                RCC8000_BASEDELAY,
                   1156:                RCC8000_ID,
                   1157:                RCC8000_DESCRIPTION,
                   1158:                RCC8000_FORMAT,
                   1159:                DCF_TYPE,
                   1160:                RCC8000_MAXUNSYNC,
                   1161:                RCC8000_SPEED,
                   1162:                RCC8000_CFLAG,
                   1163:                RCC8000_IFLAG,
                   1164:                RCC8000_OFLAG,
                   1165:                RCC8000_LFLAG,
                   1166:                RCC8000_SAMPLES,
                   1167:                RCC8000_KEEP
                   1168:        },
                   1169:        {                             /* mode 12 */
                   1170:                HOPF6021_FLAGS,
                   1171:                NO_POLL,     
                   1172:                NO_INIT,
                   1173:                NO_EVENT,
                   1174:                NO_END,
                   1175:                NO_MESSAGE,
                   1176:                NO_LCLDATA,
                   1177:                HOPF6021_ROOTDELAY,
                   1178:                HOPF6021_BASEDELAY,
                   1179:                DCF_ID,
                   1180:                HOPF6021_DESCRIPTION,
                   1181:                HOPF6021_FORMAT,
                   1182:                DCF_TYPE,
                   1183:                HOPF6021_MAXUNSYNC,
                   1184:                HOPF6021_SPEED,
                   1185:                HOPF6021_CFLAG,
                   1186:                HOPF6021_IFLAG,
                   1187:                HOPF6021_OFLAG,
                   1188:                HOPF6021_LFLAG,
                   1189:                HOPF6021_SAMPLES,
                   1190:                HOPF6021_KEEP
                   1191:        },
                   1192:        {                            /* mode 13 */
                   1193:                COMPUTIME_FLAGS,
                   1194:                NO_POLL,
                   1195:                NO_INIT,
                   1196:                NO_EVENT,
                   1197:                NO_END,
                   1198:                NO_MESSAGE,
                   1199:                NO_LCLDATA,
                   1200:                COMPUTIME_ROOTDELAY,
                   1201:                COMPUTIME_BASEDELAY,
                   1202:                COMPUTIME_ID,
                   1203:                COMPUTIME_DESCRIPTION,
                   1204:                COMPUTIME_FORMAT,
                   1205:                COMPUTIME_TYPE,
                   1206:                COMPUTIME_MAXUNSYNC,
                   1207:                COMPUTIME_SPEED,
                   1208:                COMPUTIME_CFLAG,
                   1209:                COMPUTIME_IFLAG,
                   1210:                COMPUTIME_OFLAG,
                   1211:                COMPUTIME_LFLAG,
                   1212:                COMPUTIME_SAMPLES,
                   1213:                COMPUTIME_KEEP
                   1214:        },
                   1215:        {                               /* mode 14 */
                   1216:                RAWDCF_FLAGS,
                   1217:                NO_POLL,
                   1218:                RAWDCFDTRSET_INIT,
                   1219:                NO_EVENT,
                   1220:                NO_END,
                   1221:                NO_MESSAGE,
                   1222:                NO_LCLDATA,
                   1223:                RAWDCF_ROOTDELAY,
                   1224:                RAWDCF_BASEDELAY,
                   1225:                DCF_A_ID,
                   1226:                RAWDCFDTRSET_DESCRIPTION,
                   1227:                RAWDCF_FORMAT,
                   1228:                DCF_TYPE,
                   1229:                RAWDCF_MAXUNSYNC,
                   1230:                RAWDCF_SPEED,
                   1231:                RAWDCF_CFLAG,
                   1232:                RAWDCF_IFLAG,
                   1233:                RAWDCF_OFLAG,
                   1234:                RAWDCF_LFLAG,
                   1235:                RAWDCF_SAMPLES,
                   1236:                RAWDCF_KEEP
                   1237:        },
                   1238:        {                               /* mode 15 */
                   1239:                0,                              /* operation flags (io modes) */
                   1240:                NO_POLL,                        /* active poll routine */
                   1241:                NO_INIT,                        /* active poll init routine */
                   1242:                NO_EVENT,                       /* special event handling (e.g. reset clock) */
                   1243:                NO_END,                         /* active poll end routine */
                   1244:                NO_MESSAGE,                     /* process a lower layer message */
                   1245:                NO_LCLDATA,                     /* local data area for "poll" mechanism */
                   1246:                0,                              /* rootdelay */
                   1247:                11.0 /* bits */ / 9600,         /* current offset by which the RS232
                   1248:                                                time code is delayed from the actual time */
                   1249:                DCF_ID,                         /* ID code */
                   1250:                "WHARTON 400A Series clock",    /* device name */
                   1251:                "WHARTON 400A Series clock Output Format 1",    /* fixed format */
                   1252:                        /* Must match a format-name in a libparse/clk_xxx.c file */
                   1253:                DCF_TYPE,                       /* clock type (ntp control) */
                   1254:                (1*60*60),                      /* time to trust oscillator after losing synch */
                   1255:                B9600,                          /* terminal input & output baudrate */
                   1256:                (CS8|CREAD|PARENB|CLOCAL|HUPCL),/* terminal control flags */
                   1257:                0,                              /* terminal input flags */
                   1258:                0,                              /* terminal output flags */
                   1259:                0,                              /* terminal local flags */
                   1260:                5,                              /* samples for median filter */
                   1261:                3,                              /* samples for median filter to keep */
                   1262:        },
                   1263:        {                               /* mode 16 - RAWDCF RTS set, DTR clr */
                   1264:                RAWDCF_FLAGS,
                   1265:                NO_POLL,
                   1266:                RAWDCFDTRCLRRTSSET_INIT,
                   1267:                NO_EVENT,
                   1268:                NO_END,
                   1269:                NO_MESSAGE,
                   1270:                NO_LCLDATA,
                   1271:                RAWDCF_ROOTDELAY,
                   1272:                RAWDCF_BASEDELAY,
                   1273:                DCF_A_ID,
                   1274:                RAWDCFDTRCLRRTSSET_DESCRIPTION,
                   1275:                RAWDCF_FORMAT,
                   1276:                DCF_TYPE,
                   1277:                RAWDCF_MAXUNSYNC,
                   1278:                RAWDCF_SPEED,
                   1279:                RAWDCF_CFLAG,
                   1280:                RAWDCF_IFLAG,
                   1281:                RAWDCF_OFLAG,
                   1282:                RAWDCF_LFLAG,
                   1283:                RAWDCF_SAMPLES,
                   1284:                RAWDCF_KEEP
                   1285:        },
                   1286:         {                            /* mode 17 */
                   1287:                 VARITEXT_FLAGS,
                   1288:                 NO_POLL,
                   1289:                 NO_INIT,
                   1290:                 NO_EVENT,
                   1291:                 NO_END,
                   1292:                 NO_MESSAGE,
                   1293:                 NO_LCLDATA,
                   1294:                 VARITEXT_ROOTDELAY,
                   1295:                 VARITEXT_BASEDELAY,
                   1296:                 VARITEXT_ID,
                   1297:                 VARITEXT_DESCRIPTION,
                   1298:                 VARITEXT_FORMAT,
                   1299:                 VARITEXT_TYPE,
                   1300:                 VARITEXT_MAXUNSYNC,
                   1301:                 VARITEXT_SPEED,
                   1302:                 VARITEXT_CFLAG,
                   1303:                 VARITEXT_IFLAG,
                   1304:                 VARITEXT_OFLAG,
                   1305:                 VARITEXT_LFLAG,
                   1306:                 VARITEXT_SAMPLES,
                   1307:                 VARITEXT_KEEP
                   1308:         },
                   1309:        {                               /* mode 18 */
                   1310:                MBG_FLAGS,
                   1311:                NO_POLL,
                   1312:                NO_INIT,
                   1313:                NO_EVENT,
                   1314:                GPS16X_END,
                   1315:                GPS16X_MESSAGE,
                   1316:                GPS16X_DATA,
                   1317:                GPS16X_ROOTDELAY,
                   1318:                GPS16X_BASEDELAY,
                   1319:                GPS16X_ID,
                   1320:                GPS16X_DESCRIPTION,
                   1321:                GPS16X_FORMAT,
                   1322:                GPS_TYPE,
                   1323:                GPS16X_MAXUNSYNC,
                   1324:                GPS16X_SPEED,
                   1325:                GPS16X_CFLAG,
                   1326:                GPS16X_IFLAG,
                   1327:                GPS16X_OFLAG,
                   1328:                GPS16X_LFLAG,
                   1329:                GPS16X_SAMPLES,
                   1330:                GPS16X_KEEP
                   1331:        },
                   1332:        {                               /* mode 19 */
                   1333:                RAWDCF_FLAGS,
                   1334:                NO_POLL,
                   1335:                RAWDCF_INIT,
                   1336:                NO_EVENT,
                   1337:                NO_END,
                   1338:                NO_MESSAGE,
                   1339:                NO_LCLDATA,
                   1340:                RAWDCF_ROOTDELAY,
                   1341:                GUDE_EMC_USB_V20_BASEDELAY,
                   1342:                DCF_A_ID,
                   1343:                GUDE_EMC_USB_V20_DESCRIPTION,
                   1344:                RAWDCF_FORMAT,
                   1345:                DCF_TYPE,
                   1346:                RAWDCF_MAXUNSYNC,
                   1347:                GUDE_EMC_USB_V20_SPEED,
                   1348:                RAWDCF_CFLAG,
                   1349:                RAWDCF_IFLAG,
                   1350:                RAWDCF_OFLAG,
                   1351:                RAWDCF_LFLAG,
                   1352:                RAWDCF_SAMPLES,
                   1353:                RAWDCF_KEEP
                   1354:        },
                   1355:        {                               /* mode 20, like mode 14 but driven by 75 baud */
                   1356:                RAWDCF_FLAGS,
                   1357:                NO_POLL,
                   1358:                RAWDCFDTRSET_INIT,
                   1359:                NO_EVENT,
                   1360:                NO_END,
                   1361:                NO_MESSAGE,
                   1362:                NO_LCLDATA,
                   1363:                RAWDCF_ROOTDELAY,
                   1364:                RAWDCF_BASEDELAY,
                   1365:                DCF_A_ID,
                   1366:                RAWDCFDTRSET75_DESCRIPTION,
                   1367:                RAWDCF_FORMAT,
                   1368:                DCF_TYPE,
                   1369:                RAWDCF_MAXUNSYNC,
                   1370:                B75,
                   1371:                RAWDCF_CFLAG,
                   1372:                RAWDCF_IFLAG,
                   1373:                RAWDCF_OFLAG,
                   1374:                RAWDCF_LFLAG,
                   1375:                RAWDCF_SAMPLES,
                   1376:                RAWDCF_KEEP
                   1377:        },
                   1378:        {                               /* mode 21, like mode 16 but driven by 75 baud
                   1379:                                         - RAWDCF RTS set, DTR clr */
                   1380:                RAWDCF_FLAGS,
                   1381:                NO_POLL,
                   1382:                RAWDCFDTRCLRRTSSET_INIT,
                   1383:                NO_EVENT,
                   1384:                NO_END,
                   1385:                NO_MESSAGE,
                   1386:                NO_LCLDATA,
                   1387:                RAWDCF_ROOTDELAY,
                   1388:                RAWDCF_BASEDELAY,
                   1389:                DCF_A_ID,
                   1390:                RAWDCFDTRCLRRTSSET75_DESCRIPTION,
                   1391:                RAWDCF_FORMAT,
                   1392:                DCF_TYPE,
                   1393:                RAWDCF_MAXUNSYNC,
                   1394:                B75,
                   1395:                RAWDCF_CFLAG,
                   1396:                RAWDCF_IFLAG,
                   1397:                RAWDCF_OFLAG,
                   1398:                RAWDCF_LFLAG,
                   1399:                RAWDCF_SAMPLES,
                   1400:                RAWDCF_KEEP
                   1401:        },
                   1402:        {                               /* mode 22 - like 2 with POWERUP trust */
                   1403:                MBG_FLAGS | PARSE_F_POWERUPTRUST,
                   1404:                NO_POLL,
                   1405:                NO_INIT,
                   1406:                NO_EVENT,
                   1407:                NO_END,
                   1408:                NO_MESSAGE,
                   1409:                NO_LCLDATA,
                   1410:                DCFUA31_ROOTDELAY,
                   1411:                DCFUA31_BASEDELAY,
                   1412:                DCF_A_ID,
                   1413:                DCFUA31_DESCRIPTION,
                   1414:                DCFUA31_FORMAT,
                   1415:                DCF_TYPE,
                   1416:                DCFUA31_MAXUNSYNC,
                   1417:                DCFUA31_SPEED,
                   1418:                DCFUA31_CFLAG,
                   1419:                DCFUA31_IFLAG,
                   1420:                DCFUA31_OFLAG,
                   1421:                DCFUA31_LFLAG,
                   1422:                DCFUA31_SAMPLES,
                   1423:                DCFUA31_KEEP
                   1424:        },
                   1425:        {                               /* mode 23 - like 7 with POWERUP trust */
                   1426:                MBG_FLAGS | PARSE_F_POWERUPTRUST,
                   1427:                GPS16X_POLL,
                   1428:                GPS16X_INIT,
                   1429:                NO_EVENT,
                   1430:                GPS16X_END,
                   1431:                GPS16X_MESSAGE,
                   1432:                GPS16X_DATA,
                   1433:                GPS16X_ROOTDELAY,
                   1434:                GPS16X_BASEDELAY,
                   1435:                GPS16X_ID,
                   1436:                GPS16X_DESCRIPTION,
                   1437:                GPS16X_FORMAT,
                   1438:                GPS_TYPE,
                   1439:                GPS16X_MAXUNSYNC,
                   1440:                GPS16X_SPEED,
                   1441:                GPS16X_CFLAG,
                   1442:                GPS16X_IFLAG,
                   1443:                GPS16X_OFLAG,
                   1444:                GPS16X_LFLAG,
                   1445:                GPS16X_SAMPLES,
                   1446:                GPS16X_KEEP
                   1447:        },
                   1448: };
                   1449: 
                   1450: static int ncltypes = sizeof(parse_clockinfo) / sizeof(struct parse_clockinfo);
                   1451: 
                   1452: #define CLK_REALTYPE(x) ((int)(((x)->ttl) & 0x7F))
                   1453: #define CLK_TYPE(x)    ((CLK_REALTYPE(x) >= ncltypes) ? ~0 : CLK_REALTYPE(x))
                   1454: #define CLK_UNIT(x)    ((int)REFCLOCKUNIT(&(x)->srcadr))
                   1455: #define CLK_PPS(x)     (((x)->ttl) & 0x80)
                   1456: 
                   1457: /*
                   1458:  * Other constant stuff
                   1459:  */
                   1460: #define        PARSEHSREFID    0x7f7f08ff      /* 127.127.8.255 refid for hi strata */
                   1461: 
                   1462: #define PARSESTATISTICS   (60*60)              /* output state statistics every hour */
                   1463: 
                   1464: static int notice = 0;
                   1465: 
                   1466: #define PARSE_STATETIME(parse, i) ((parse->generic->currentstatus == i) ? parse->statetime[i] + current_time - parse->lastchange : parse->statetime[i])
                   1467: 
                   1468: static void parse_event   (struct parseunit *, int);
                   1469: static void parse_process (struct parseunit *, parsetime_t *);
                   1470: static void clear_err     (struct parseunit *, u_long);
                   1471: static int  list_err      (struct parseunit *, u_long);
                   1472: static char * l_mktime    (u_long);
                   1473: 
                   1474: /**===========================================================================
                   1475:  ** implementation error message regression module
                   1476:  **/
                   1477: static void
                   1478: clear_err(
                   1479:        struct parseunit *parse,
                   1480:        u_long            lstate
                   1481:        )
                   1482: {
                   1483:        if (lstate == ERR_ALL)
                   1484:        {
                   1485:                int i;
                   1486: 
                   1487:                for (i = 0; i < ERR_CNT; i++)
                   1488:                {
                   1489:                        parse->errors[i].err_stage   = err_tbl[i];
                   1490:                        parse->errors[i].err_cnt     = 0;
                   1491:                        parse->errors[i].err_last    = 0;
                   1492:                        parse->errors[i].err_started = 0;
                   1493:                        parse->errors[i].err_suppressed = 0;
                   1494:                }
                   1495:        }
                   1496:        else
                   1497:        {
                   1498:                parse->errors[lstate].err_stage   = err_tbl[lstate];
                   1499:                parse->errors[lstate].err_cnt     = 0;
                   1500:                parse->errors[lstate].err_last    = 0;
                   1501:                parse->errors[lstate].err_started = 0;
                   1502:                parse->errors[lstate].err_suppressed = 0;
                   1503:        }
                   1504: }
                   1505: 
                   1506: static int
                   1507: list_err(
                   1508:        struct parseunit *parse,
                   1509:        u_long            lstate
                   1510:        )
                   1511: {
                   1512:        int do_it;
                   1513:        struct errorinfo *err = &parse->errors[lstate];
                   1514: 
                   1515:        if (err->err_started == 0)
                   1516:        {
                   1517:                err->err_started = current_time;
                   1518:        }
                   1519: 
                   1520:        do_it = (current_time - err->err_last) >= err->err_stage->err_delay;
                   1521: 
                   1522:        if (do_it)
                   1523:            err->err_cnt++;
                   1524:   
                   1525:        if (err->err_stage->err_count &&
                   1526:            (err->err_cnt >= err->err_stage->err_count))
                   1527:        {
                   1528:                err->err_stage++;
                   1529:                err->err_cnt = 0;
                   1530:        }
                   1531: 
                   1532:        if (!err->err_cnt && do_it)
                   1533:            msyslog(LOG_INFO, "PARSE receiver #%d: interval for following error message class is at least %s",
                   1534:                    CLK_UNIT(parse->peer), l_mktime(err->err_stage->err_delay));
                   1535: 
                   1536:        if (!do_it)
                   1537:            err->err_suppressed++;
                   1538:        else
                   1539:            err->err_last = current_time;
                   1540: 
                   1541:        if (do_it && err->err_suppressed)
                   1542:        {
                   1543:                msyslog(LOG_INFO, "PARSE receiver #%d: %ld message%s suppressed, error condition class persists for %s",
                   1544:                        CLK_UNIT(parse->peer), err->err_suppressed, (err->err_suppressed == 1) ? " was" : "s where",
                   1545:                        l_mktime(current_time - err->err_started));
                   1546:                err->err_suppressed = 0;
                   1547:        }
                   1548:   
                   1549:        return do_it;
                   1550: }
                   1551: 
                   1552: /*--------------------------------------------------
                   1553:  * mkreadable - make a printable ascii string (without
                   1554:  * embedded quotes so that the ntpq protocol isn't
                   1555:  * fooled
                   1556:  */
                   1557: #ifndef isprint
                   1558: #define isprint(_X_) (((_X_) > 0x1F) && ((_X_) < 0x7F))
                   1559: #endif
                   1560: 
                   1561: static char *
                   1562: mkreadable(
                   1563:        char  *buffer,
                   1564:        long  blen,
                   1565:        const char  *src,
                   1566:        u_long  srclen,
                   1567:        int hex
                   1568:        )
                   1569: {
                   1570:        char *b    = buffer;
                   1571:        char *endb = NULL;
                   1572: 
                   1573:        if (blen < 4)
                   1574:                return NULL;            /* don't bother with mini buffers */
                   1575: 
                   1576:        endb = buffer + blen - 4;
                   1577: 
                   1578:        blen--;                 /* account for '\0' */
                   1579: 
                   1580:        while (blen && srclen--)
                   1581:        {
                   1582:                if (!hex &&             /* no binary only */
                   1583:                    (*src != '\\') &&   /* no plain \ */
                   1584:                    (*src != '"') &&    /* no " */
                   1585:                    isprint((int)*src)) /* only printables */
                   1586:                {                       /* they are easy... */
                   1587:                        *buffer++ = *src++;
                   1588:                        blen--;
                   1589:                }
                   1590:                else
                   1591:                {
                   1592:                        if (blen < 4)
                   1593:                        {
                   1594:                                while (blen--)
                   1595:                                {
                   1596:                                        *buffer++ = '.';
                   1597:                                }
                   1598:                                *buffer = '\0';
                   1599:                                return b;
                   1600:                        }
                   1601:                        else
                   1602:                        {
                   1603:                                if (*src == '\\')
                   1604:                                {
                   1605:                                        strcpy(buffer,"\\\\");
                   1606:                                        buffer += 2;
                   1607:                                        blen   -= 2;
                   1608:                                        src++;
                   1609:                                }
                   1610:                                else
                   1611:                                {
                   1612:                                        snprintf(buffer, blen, "\\x%02x", *src++);
                   1613:                                        blen   -= 4;
                   1614:                                        buffer += 4;
                   1615:                                }
                   1616:                        }
                   1617:                }
                   1618:                if (srclen && !blen && endb) /* overflow - set last chars to ... */
                   1619:                        strcpy(endb, "...");
                   1620:        }
                   1621: 
                   1622:        *buffer = '\0';
                   1623:        return b;
                   1624: }
                   1625: 
                   1626: 
                   1627: /*--------------------------------------------------
                   1628:  * mkascii - make a printable ascii string
                   1629:  * assumes (unless defined better) 7-bit ASCII
                   1630:  */
                   1631: static char *
                   1632: mkascii(
                   1633:        char  *buffer,
                   1634:        long  blen,
                   1635:        const char  *src,
                   1636:        u_long  srclen
                   1637:        )
                   1638: {
                   1639:        return mkreadable(buffer, blen, src, srclen, 0);
                   1640: }
                   1641: 
                   1642: /**===========================================================================
                   1643:  ** implementation of i/o handling methods
                   1644:  ** (all STREAM, partial STREAM, user level)
                   1645:  **/
                   1646: 
                   1647: /*
                   1648:  * define possible io handling methods
                   1649:  */
                   1650: #ifdef STREAM
                   1651: static int  ppsclock_init   (struct parseunit *);
                   1652: static int  stream_init     (struct parseunit *);
                   1653: static void stream_end      (struct parseunit *);
                   1654: static int  stream_enable   (struct parseunit *);
                   1655: static int  stream_disable  (struct parseunit *);
                   1656: static int  stream_setcs    (struct parseunit *, parsectl_t *);
                   1657: static int  stream_getfmt   (struct parseunit *, parsectl_t *);
                   1658: static int  stream_setfmt   (struct parseunit *, parsectl_t *);
                   1659: static int  stream_timecode (struct parseunit *, parsectl_t *);
                   1660: static void stream_receive  (struct recvbuf *);
                   1661: #endif
                   1662:                                         
                   1663: static int  local_init     (struct parseunit *);
                   1664: static void local_end      (struct parseunit *);
                   1665: static int  local_nop      (struct parseunit *);
                   1666: static int  local_setcs    (struct parseunit *, parsectl_t *);
                   1667: static int  local_getfmt   (struct parseunit *, parsectl_t *);
                   1668: static int  local_setfmt   (struct parseunit *, parsectl_t *);
                   1669: static int  local_timecode (struct parseunit *, parsectl_t *);
                   1670: static void local_receive  (struct recvbuf *);
                   1671: static int  local_input    (struct recvbuf *);
                   1672: 
                   1673: static bind_t io_bindings[] =
                   1674: {
                   1675: #ifdef STREAM
                   1676:        {
                   1677:                "parse STREAM",
                   1678:                stream_init,
                   1679:                stream_end,
                   1680:                stream_setcs,
                   1681:                stream_disable,
                   1682:                stream_enable,
                   1683:                stream_getfmt,
                   1684:                stream_setfmt,
                   1685:                stream_timecode,
                   1686:                stream_receive,
                   1687:                0,
                   1688:        },
                   1689:        {
                   1690:                "ppsclock STREAM",
                   1691:                ppsclock_init,
                   1692:                local_end,
                   1693:                local_setcs,
                   1694:                local_nop,
                   1695:                local_nop,
                   1696:                local_getfmt,
                   1697:                local_setfmt,
                   1698:                local_timecode,
                   1699:                local_receive,
                   1700:                local_input,
                   1701:        },
                   1702: #endif
                   1703:        {
                   1704:                "normal",
                   1705:                local_init,
                   1706:                local_end,
                   1707:                local_setcs,
                   1708:                local_nop,
                   1709:                local_nop,
                   1710:                local_getfmt,
                   1711:                local_setfmt,
                   1712:                local_timecode,
                   1713:                local_receive,
                   1714:                local_input,
                   1715:        },
                   1716:        {
                   1717:                (char *)0,
                   1718:        }
                   1719: };
                   1720: 
                   1721: #ifdef STREAM
                   1722: 
                   1723: #define fix_ts(_X_) \
                   1724:                         if ((&(_X_))->tv.tv_usec >= 1000000)                \
                   1725:                           {                                                 \
                   1726:                            (&(_X_))->tv.tv_usec -= 1000000;                \
                   1727:                            (&(_X_))->tv.tv_sec  += 1;                      \
                   1728:                          }
                   1729: 
                   1730: #define cvt_ts(_X_, _Y_) \
                   1731:                         {                                                   \
                   1732:                          l_fp ts;                                          \
                   1733:                          fix_ts((_X_));                                    \
                   1734:                          if (!buftvtots((const char *)&(&(_X_))->tv, &ts)) \
                   1735:                            {                                               \
                   1736:                               ERR(ERR_BADDATA)                             \
                   1737:                                 msyslog(LOG_ERR,"parse: stream_receive: timestamp conversion error (buftvtots) (%s) (%ld.%06ld) ", (_Y_), (long)(&(_X_))->tv.tv_sec, (long)(&(_X_))->tv.tv_usec);\
                   1738:                              return;                                       \
                   1739:                            }                                               \
                   1740:                          else                                              \
                   1741:                            {                                               \
                   1742:                              (&(_X_))->fp = ts;                            \
                   1743:                            }                                               \
                   1744:                        }
                   1745: 
                   1746: /*--------------------------------------------------
                   1747:  * ppsclock STREAM init
                   1748:  */
                   1749: static int
                   1750: ppsclock_init(
                   1751:        struct parseunit *parse
                   1752:        )
                   1753: {
                   1754:         static char m1[] = "ppsclocd";
                   1755:        static char m2[] = "ppsclock";
                   1756:        
                   1757:        /*
                   1758:         * now push the parse streams module
                   1759:         * it will ensure exclusive access to the device
                   1760:         */
                   1761:        if (ioctl(parse->ppsfd, I_PUSH, (caddr_t)m1) == -1 &&
                   1762:            ioctl(parse->ppsfd, I_PUSH, (caddr_t)m2) == -1)
                   1763:        {
                   1764:                if (errno != EINVAL)
                   1765:                {
                   1766:                        msyslog(LOG_ERR, "PARSE receiver #%d: ppsclock_init: ioctl(fd, I_PUSH, \"ppsclock\"): %m",
                   1767:                                CLK_UNIT(parse->peer));
                   1768:                }
                   1769:                return 0;
                   1770:        }
                   1771:        if (!local_init(parse))
                   1772:        {
                   1773:                (void)ioctl(parse->ppsfd, I_POP, (caddr_t)0);
                   1774:                return 0;
                   1775:        }
                   1776: 
                   1777:        parse->flags |= PARSE_PPSCLOCK;
                   1778:        return 1;
                   1779: }
                   1780: 
                   1781: /*--------------------------------------------------
                   1782:  * parse STREAM init
                   1783:  */
                   1784: static int
                   1785: stream_init(
                   1786:        struct parseunit *parse
                   1787:        )
                   1788: {
                   1789:        static char m1[] = "parse";
                   1790:        /*
                   1791:         * now push the parse streams module
                   1792:         * to test whether it is there (neat interface 8-( )
                   1793:         */
                   1794:        if (ioctl(parse->generic->io.fd, I_PUSH, (caddr_t)m1) == -1)
                   1795:        {
                   1796:                if (errno != EINVAL) /* accept non-existence */
                   1797:                {
                   1798:                        msyslog(LOG_ERR, "PARSE receiver #%d: stream_init: ioctl(fd, I_PUSH, \"parse\"): %m", CLK_UNIT(parse->peer));
                   1799:                }
                   1800:                return 0;
                   1801:        }
                   1802:        else
                   1803:        {
                   1804:                while(ioctl(parse->generic->io.fd, I_POP, (caddr_t)0) == 0)
                   1805:                    /* empty loop */;
                   1806: 
                   1807:                /*
                   1808:                 * now push it a second time after we have removed all
                   1809:                 * module garbage
                   1810:                 */
                   1811:                if (ioctl(parse->generic->io.fd, I_PUSH, (caddr_t)m1) == -1)
                   1812:                {
                   1813:                        msyslog(LOG_ERR, "PARSE receiver #%d: stream_init: ioctl(fd, I_PUSH, \"parse\"): %m", CLK_UNIT(parse->peer));
                   1814:                        return 0;
                   1815:                }
                   1816:                else
                   1817:                {
                   1818:                        return 1;
                   1819:                }
                   1820:        }
                   1821: }
                   1822: 
                   1823: /*--------------------------------------------------
                   1824:  * parse STREAM end
                   1825:  */
                   1826: static void
                   1827: stream_end(
                   1828:        struct parseunit *parse
                   1829:        )
                   1830: {
                   1831:        while(ioctl(parse->generic->io.fd, I_POP, (caddr_t)0) == 0)
                   1832:            /* empty loop */;
                   1833: }
                   1834: 
                   1835: /*--------------------------------------------------
                   1836:  * STREAM setcs
                   1837:  */
                   1838: static int
                   1839: stream_setcs(
                   1840:        struct parseunit *parse,
                   1841:        parsectl_t  *tcl
                   1842:        )
                   1843: {
                   1844:        struct strioctl strioc;
                   1845:   
                   1846:        strioc.ic_cmd     = PARSEIOC_SETCS;
                   1847:        strioc.ic_timout  = 0;
                   1848:        strioc.ic_dp      = (char *)tcl;
                   1849:        strioc.ic_len     = sizeof (*tcl);
                   1850: 
                   1851:        if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1)
                   1852:        {
                   1853:                msyslog(LOG_ERR, "PARSE receiver #%d: stream_setcs: ioctl(fd, I_STR, PARSEIOC_SETCS): %m", CLK_UNIT(parse->peer));
                   1854:                return 0;
                   1855:        }
                   1856:        return 1;
                   1857: }
                   1858: 
                   1859: /*--------------------------------------------------
                   1860:  * STREAM enable
                   1861:  */
                   1862: static int
                   1863: stream_enable(
                   1864:        struct parseunit *parse
                   1865:        )
                   1866: {
                   1867:        struct strioctl strioc;
                   1868:   
                   1869:        strioc.ic_cmd     = PARSEIOC_ENABLE;
                   1870:        strioc.ic_timout  = 0;
                   1871:        strioc.ic_dp      = (char *)0;
                   1872:        strioc.ic_len     = 0;
                   1873: 
                   1874:        if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1)
                   1875:        {
                   1876:                msyslog(LOG_ERR, "PARSE receiver #%d: stream_enable: ioctl(fd, I_STR, PARSEIOC_ENABLE): %m", CLK_UNIT(parse->peer));
                   1877:                return 0;
                   1878:        }
                   1879:        parse->generic->io.clock_recv = stream_receive; /* ok - parse input in kernel */
                   1880:        return 1;
                   1881: }
                   1882: 
                   1883: /*--------------------------------------------------
                   1884:  * STREAM disable
                   1885:  */
                   1886: static int
                   1887: stream_disable(
                   1888:        struct parseunit *parse
                   1889:        )
                   1890: {
                   1891:        struct strioctl strioc;
                   1892:   
                   1893:        strioc.ic_cmd     = PARSEIOC_DISABLE;
                   1894:        strioc.ic_timout  = 0;
                   1895:        strioc.ic_dp      = (char *)0;
                   1896:        strioc.ic_len     = 0;
                   1897: 
                   1898:        if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1)
                   1899:        {
                   1900:                msyslog(LOG_ERR, "PARSE receiver #%d: stream_disable: ioctl(fd, I_STR, PARSEIOC_DISABLE): %m", CLK_UNIT(parse->peer));
                   1901:                return 0;
                   1902:        }
                   1903:        parse->generic->io.clock_recv = local_receive; /* ok - parse input in daemon */
                   1904:        return 1;
                   1905: }
                   1906: 
                   1907: /*--------------------------------------------------
                   1908:  * STREAM getfmt
                   1909:  */
                   1910: static int
                   1911: stream_getfmt(
                   1912:        struct parseunit *parse,
                   1913:        parsectl_t  *tcl
                   1914:        )
                   1915: {
                   1916:        struct strioctl strioc;
                   1917:   
                   1918:        strioc.ic_cmd     = PARSEIOC_GETFMT;
                   1919:        strioc.ic_timout  = 0;
                   1920:        strioc.ic_dp      = (char *)tcl;
                   1921:        strioc.ic_len     = sizeof (*tcl);
                   1922:        if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1)
                   1923:        {
                   1924:                msyslog(LOG_ERR, "PARSE receiver #%d: ioctl(fd, I_STR, PARSEIOC_GETFMT): %m", CLK_UNIT(parse->peer));
                   1925:                return 0;
                   1926:        }
                   1927:        return 1;
                   1928: }
                   1929: 
                   1930: /*--------------------------------------------------
                   1931:  * STREAM setfmt
                   1932:  */
                   1933: static int
                   1934: stream_setfmt(
                   1935:        struct parseunit *parse,
                   1936:        parsectl_t  *tcl
                   1937:        )
                   1938: {
                   1939:        struct strioctl strioc;
                   1940:   
                   1941:        strioc.ic_cmd     = PARSEIOC_SETFMT;
                   1942:        strioc.ic_timout  = 0;
                   1943:        strioc.ic_dp      = (char *)tcl;
                   1944:        strioc.ic_len     = sizeof (*tcl);
                   1945: 
                   1946:        if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1)
                   1947:        {
                   1948:                msyslog(LOG_ERR, "PARSE receiver #%d: stream_setfmt: ioctl(fd, I_STR, PARSEIOC_SETFMT): %m", CLK_UNIT(parse->peer));
                   1949:                return 0;
                   1950:        }
                   1951:        return 1;
                   1952: }
                   1953: 
                   1954: 
                   1955: /*--------------------------------------------------
                   1956:  * STREAM timecode
                   1957:  */
                   1958: static int
                   1959: stream_timecode(
                   1960:        struct parseunit *parse,
                   1961:        parsectl_t  *tcl
                   1962:        )
                   1963: {
                   1964:        struct strioctl strioc;
                   1965:   
                   1966:        strioc.ic_cmd     = PARSEIOC_TIMECODE;
                   1967:        strioc.ic_timout  = 0;
                   1968:        strioc.ic_dp      = (char *)tcl;
                   1969:        strioc.ic_len     = sizeof (*tcl);
                   1970:        
                   1971:        if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1)
                   1972:        {
                   1973:                ERR(ERR_INTERNAL)
                   1974:                        msyslog(LOG_ERR, "PARSE receiver #%d: stream_timecode: ioctl(fd, I_STR, PARSEIOC_TIMECODE): %m", CLK_UNIT(parse->peer));
                   1975:                return 0;
                   1976:        }
                   1977:        clear_err(parse, ERR_INTERNAL);
                   1978:        return 1;
                   1979: }
                   1980: 
                   1981: /*--------------------------------------------------
                   1982:  * STREAM receive
                   1983:  */
                   1984: static void
                   1985: stream_receive(
                   1986:        struct recvbuf *rbufp
                   1987:        )
                   1988: {
                   1989:        struct parseunit *parse = (struct parseunit *)((void *)rbufp->recv_srcclock);
                   1990:        parsetime_t parsetime;
                   1991: 
                   1992:        if (!parse->peer)
                   1993:            return;
                   1994: 
                   1995:        if (rbufp->recv_length != sizeof(parsetime_t))
                   1996:        {
                   1997:                ERR(ERR_BADIO)
                   1998:                        msyslog(LOG_ERR,"PARSE receiver #%d: stream_receive: bad size (got %d expected %d)",
                   1999:                                CLK_UNIT(parse->peer), rbufp->recv_length, (int)sizeof(parsetime_t));
                   2000:                parse_event(parse, CEVNT_BADREPLY);
                   2001:                return;
                   2002:        }
                   2003:        clear_err(parse, ERR_BADIO);
                   2004:   
                   2005:        memmove((caddr_t)&parsetime,
                   2006:                (caddr_t)rbufp->recv_buffer,
                   2007:                sizeof(parsetime_t));
                   2008: 
                   2009: #ifdef DEBUG
                   2010:        if (debug > 3)
                   2011:          {
                   2012:            printf("PARSE receiver #%d: status %06x, state %08x, time %lx.%08lx, stime %lx.%08lx, ptime %lx.%08lx\n",
                   2013:                   CLK_UNIT(parse->peer),
                   2014:                   (unsigned int)parsetime.parse_status,
                   2015:                   (unsigned int)parsetime.parse_state,
                   2016:                   (unsigned long)parsetime.parse_time.tv.tv_sec,
                   2017:                   (unsigned long)parsetime.parse_time.tv.tv_usec,
                   2018:                   (unsigned long)parsetime.parse_stime.tv.tv_sec,
                   2019:                   (unsigned long)parsetime.parse_stime.tv.tv_usec,
                   2020:                   (unsigned long)parsetime.parse_ptime.tv.tv_sec,
                   2021:                   (unsigned long)parsetime.parse_ptime.tv.tv_usec);
                   2022:          }
                   2023: #endif
                   2024: 
                   2025:        /*
                   2026:         * switch time stamp world - be sure to normalize small usec field
                   2027:         * errors.
                   2028:         */
                   2029: 
                   2030:        cvt_ts(parsetime.parse_stime, "parse_stime");
                   2031: 
                   2032:        if (PARSE_TIMECODE(parsetime.parse_state))
                   2033:        {
                   2034:            cvt_ts(parsetime.parse_time, "parse_time");
                   2035:        }
                   2036: 
                   2037:        if (PARSE_PPS(parsetime.parse_state))
                   2038:            cvt_ts(parsetime.parse_ptime, "parse_ptime");
                   2039: 
                   2040:        parse_process(parse, &parsetime);
                   2041: }
                   2042: #endif
                   2043: 
                   2044: /*--------------------------------------------------
                   2045:  * local init
                   2046:  */
                   2047: static int
                   2048: local_init(
                   2049:        struct parseunit *parse
                   2050:        )
                   2051: {
                   2052:        return parse_ioinit(&parse->parseio);
                   2053: }
                   2054: 
                   2055: /*--------------------------------------------------
                   2056:  * local end
                   2057:  */
                   2058: static void
                   2059: local_end(
                   2060:        struct parseunit *parse
                   2061:        )
                   2062: {
                   2063:        parse_ioend(&parse->parseio);
                   2064: }
                   2065: 
                   2066: 
                   2067: /*--------------------------------------------------
                   2068:  * local nop
                   2069:  */
                   2070: static int
                   2071: local_nop(
                   2072:        struct parseunit *parse
                   2073:        )
                   2074: {
                   2075:        return 1;
                   2076: }
                   2077: 
                   2078: /*--------------------------------------------------
                   2079:  * local setcs
                   2080:  */
                   2081: static int
                   2082: local_setcs(
                   2083:        struct parseunit *parse,
                   2084:        parsectl_t  *tcl
                   2085:        )
                   2086: {
                   2087:        return parse_setcs(tcl, &parse->parseio);
                   2088: }
                   2089: 
                   2090: /*--------------------------------------------------
                   2091:  * local getfmt
                   2092:  */
                   2093: static int
                   2094: local_getfmt(
                   2095:        struct parseunit *parse,
                   2096:        parsectl_t  *tcl
                   2097:        )
                   2098: {
                   2099:        return parse_getfmt(tcl, &parse->parseio);
                   2100: }
                   2101: 
                   2102: /*--------------------------------------------------
                   2103:  * local setfmt
                   2104:  */
                   2105: static int
                   2106: local_setfmt(
                   2107:        struct parseunit *parse,
                   2108:        parsectl_t  *tcl
                   2109:        )
                   2110: {
                   2111:        return parse_setfmt(tcl, &parse->parseio);
                   2112: }
                   2113: 
                   2114: /*--------------------------------------------------
                   2115:  * local timecode
                   2116:  */
                   2117: static int
                   2118: local_timecode(
                   2119:        struct parseunit *parse,
                   2120:        parsectl_t  *tcl
                   2121:        )
                   2122: {
                   2123:        return parse_timecode(tcl, &parse->parseio);
                   2124: }
                   2125: 
                   2126: 
                   2127: /*--------------------------------------------------
                   2128:  * local input
                   2129:  */
                   2130: static int
                   2131: local_input(
                   2132:        struct recvbuf *rbufp
                   2133:        )
                   2134: {
                   2135:        struct parseunit *parse = (struct parseunit *)((void *)rbufp->recv_srcclock);
                   2136:        int count;
                   2137:        unsigned char *s;
                   2138:        timestamp_t ts;
                   2139: 
                   2140:        if (!parse->peer)
                   2141:                return 0;
                   2142: 
                   2143:        /*
                   2144:         * eat all characters, parsing then and feeding complete samples
                   2145:         */
                   2146:        count = rbufp->recv_length;
                   2147:        s = (unsigned char *)rbufp->recv_buffer;
                   2148:        ts.fp = rbufp->recv_time;
                   2149: 
                   2150:        while (count--)
                   2151:        {
                   2152:                if (parse_ioread(&parse->parseio, (unsigned int)(*s++), &ts))
                   2153:                {
                   2154:                        struct recvbuf *buf;
                   2155: 
                   2156:                        /*
                   2157:                         * got something good to eat
                   2158:                         */
                   2159:                        if (!PARSE_PPS(parse->parseio.parse_dtime.parse_state))
                   2160:                        {
                   2161: #ifdef HAVE_PPSAPI
                   2162:                                if (parse->flags & PARSE_PPSCLOCK)
                   2163:                                {
                   2164:                                        struct timespec pps_timeout;
                   2165:                                        pps_info_t      pps_info;
                   2166:                                
                   2167:                                        pps_timeout.tv_sec  = 0;
                   2168:                                        pps_timeout.tv_nsec = 0;
                   2169: 
                   2170:                                        if (time_pps_fetch(parse->atom.handle, PPS_TSFMT_TSPEC, &pps_info,
                   2171:                                                           &pps_timeout) == 0)
                   2172:                                        {
                   2173:                                                if (pps_info.assert_sequence + pps_info.clear_sequence != parse->ppsserial)
                   2174:                                                {
                   2175:                                                        double dtemp;
                   2176: 
                   2177:                                                        struct timespec pts;
                   2178:                                                        /*
                   2179:                                                         * add PPS time stamp if available via ppsclock module
                   2180:                                                         * and not supplied already.
                   2181:                                                         */
                   2182:                                                        if (parse->flags & PARSE_CLEAR)
                   2183:                                                          pts = pps_info.clear_timestamp;
                   2184:                                                        else
                   2185:                                                          pts = pps_info.assert_timestamp;
                   2186: 
                   2187:                                                        parse->parseio.parse_dtime.parse_ptime.fp.l_ui = pts.tv_sec + JAN_1970;
                   2188: 
                   2189:                                                        dtemp = pts.tv_nsec / 1e9;
                   2190:                                                        if (dtemp < 0.) {
                   2191:                                                                dtemp += 1;
                   2192:                                                                parse->parseio.parse_dtime.parse_ptime.fp.l_ui--;
                   2193:                                                        }
                   2194:                                                        if (dtemp > 1.) {
                   2195:                                                                dtemp -= 1;
                   2196:                                                                parse->parseio.parse_dtime.parse_ptime.fp.l_ui++;
                   2197:                                                        }
                   2198:                                                        parse->parseio.parse_dtime.parse_ptime.fp.l_uf = dtemp * FRAC;
                   2199: 
                   2200:                                                        parse->parseio.parse_dtime.parse_state |= PARSEB_PPS|PARSEB_S_PPS;
                   2201: #ifdef DEBUG
                   2202:                                                        if (debug > 3)
                   2203:                                                        {
                   2204:                                                                printf(
                   2205:                                                                       "parse: local_receive: fd %d PPSAPI seq %ld - PPS %s\n",
                   2206:                                                                       rbufp->fd,
                   2207:                                                                       (long)pps_info.assert_sequence + (long)pps_info.clear_sequence,
                   2208:                                                                       lfptoa(&parse->parseio.parse_dtime.parse_ptime.fp, 6));
                   2209:                                                        }
                   2210: #endif
                   2211:                                                }
                   2212: #ifdef DEBUG
                   2213:                                                else
                   2214:                                                {
                   2215:                                                        if (debug > 3)
                   2216:                                                        {
                   2217:                                                                printf(
                   2218:                                                                       "parse: local_receive: fd %d PPSAPI seq assert %ld, seq clear %ld - NO PPS event\n",
                   2219:                                                                       rbufp->fd,
                   2220:                                                                       (long)pps_info.assert_sequence, (long)pps_info.clear_sequence);
                   2221:                                                        }
                   2222:                                                }
                   2223: #endif
                   2224:                                                parse->ppsserial = pps_info.assert_sequence + pps_info.clear_sequence;
                   2225:                                        }
                   2226: #ifdef DEBUG
                   2227:                                        else
                   2228:                                        {
                   2229:                                                if (debug > 3)
                   2230:                                                {
                   2231:                                                        printf(
                   2232:                                                               "parse: local_receive: fd %d PPSAPI time_pps_fetch errno = %d\n",
                   2233:                                                               rbufp->fd,
                   2234:                                                               errno);
                   2235:                                                }
                   2236:                                        }
                   2237: #endif
                   2238:                                }
                   2239: #else
                   2240: #ifdef TIOCDCDTIMESTAMP
                   2241:                                struct timeval dcd_time;
                   2242:                                
                   2243:                                if (ioctl(parse->ppsfd, TIOCDCDTIMESTAMP, &dcd_time) != -1)
                   2244:                                {
                   2245:                                        l_fp tstmp;
                   2246:                                        
                   2247:                                        TVTOTS(&dcd_time, &tstmp);
                   2248:                                        tstmp.l_ui += JAN_1970;
                   2249:                                        L_SUB(&ts.fp, &tstmp);
                   2250:                                        if (ts.fp.l_ui == 0)
                   2251:                                        {
                   2252: #ifdef DEBUG
                   2253:                                                if (debug)
                   2254:                                                {
                   2255:                                                        printf(
                   2256:                                                               "parse: local_receive: fd %d DCDTIMESTAMP %s\n",
                   2257:                                                               parse->ppsfd,
                   2258:                                                               lfptoa(&tstmp, 6));
                   2259:                                                        printf(" sigio %s\n",
                   2260:                                                               lfptoa(&ts.fp, 6));
                   2261:                                                }
                   2262: #endif
                   2263:                                                parse->parseio.parse_dtime.parse_ptime.fp = tstmp;
                   2264:                                                parse->parseio.parse_dtime.parse_state |= PARSEB_PPS|PARSEB_S_PPS;
                   2265:                                        }
                   2266:                                }
                   2267: #else /* TIOCDCDTIMESTAMP */
                   2268: #if defined(HAVE_STRUCT_PPSCLOCKEV) && (defined(HAVE_CIOGETEV) || defined(HAVE_TIOCGPPSEV))
                   2269:                                if (parse->flags & PARSE_PPSCLOCK)
                   2270:                                  {
                   2271:                                    l_fp tts;
                   2272:                                    struct ppsclockev ev;
                   2273: 
                   2274: #ifdef HAVE_CIOGETEV
                   2275:                                    if (ioctl(parse->ppsfd, CIOGETEV, (caddr_t)&ev) == 0)
                   2276: #endif
                   2277: #ifdef HAVE_TIOCGPPSEV
                   2278:                                    if (ioctl(parse->ppsfd, TIOCGPPSEV, (caddr_t)&ev) == 0)
                   2279: #endif
                   2280:                                        {
                   2281:                                          if (ev.serial != parse->ppsserial)
                   2282:                                            {
                   2283:                                              /*
                   2284:                                               * add PPS time stamp if available via ppsclock module
                   2285:                                               * and not supplied already.
                   2286:                                               */
                   2287:                                              if (!buftvtots((const char *)&ev.tv, &tts))
                   2288:                                                {
                   2289:                                                  ERR(ERR_BADDATA)
                   2290:                                                    msyslog(LOG_ERR,"parse: local_receive: timestamp conversion error (buftvtots) (ppsclockev.tv)");
                   2291:                                                }
                   2292:                                              else
                   2293:                                                {
                   2294:                                                  parse->parseio.parse_dtime.parse_ptime.fp = tts;
                   2295:                                                  parse->parseio.parse_dtime.parse_state |= PARSEB_PPS|PARSEB_S_PPS;
                   2296:                                                }
                   2297:                                            }
                   2298:                                          parse->ppsserial = ev.serial;
                   2299:                                        }
                   2300:                                  }
                   2301: #endif
                   2302: #endif /* TIOCDCDTIMESTAMP */
                   2303: #endif /* !HAVE_PPSAPI */
                   2304:                        }
                   2305:                        if (count)
                   2306:                        {       /* simulate receive */
                   2307:                                buf = get_free_recv_buffer();
                   2308:                                if (buf != NULL) {
                   2309:                                        memmove((caddr_t)buf->recv_buffer,
                   2310:                                                (caddr_t)&parse->parseio.parse_dtime,
                   2311:                                                sizeof(parsetime_t));
                   2312:                                        buf->recv_length  = sizeof(parsetime_t);
                   2313:                                        buf->recv_time    = rbufp->recv_time;
                   2314:                                        buf->srcadr       = rbufp->srcadr;
                   2315:                                        buf->dstadr       = rbufp->dstadr;
                   2316:                                        buf->receiver     = rbufp->receiver;
                   2317:                                        buf->fd           = rbufp->fd;
                   2318:                                        buf->X_from_where = rbufp->X_from_where;
                   2319:                                        add_full_recv_buffer(buf);
                   2320:                                }
                   2321:                                parse_iodone(&parse->parseio);
                   2322:                        }
                   2323:                        else
                   2324:                        {
                   2325:                                memmove((caddr_t)rbufp->recv_buffer,
                   2326:                                        (caddr_t)&parse->parseio.parse_dtime,
                   2327:                                        sizeof(parsetime_t));
                   2328:                                parse_iodone(&parse->parseio);
                   2329:                                rbufp->recv_length = sizeof(parsetime_t);
                   2330:                                return 1; /* got something & in place return */
                   2331:                        }
                   2332:                }
                   2333:        }
                   2334:        return 0;               /* nothing to pass up */
                   2335: }
                   2336: 
                   2337: /*--------------------------------------------------
                   2338:  * local receive
                   2339:  */
                   2340: static void
                   2341: local_receive(
                   2342:        struct recvbuf *rbufp
                   2343:        )
                   2344: {
                   2345:        struct parseunit *parse = (struct parseunit *)((void *)rbufp->recv_srcclock);
                   2346:        parsetime_t parsetime;
                   2347: 
                   2348:        if (!parse->peer)
                   2349:            return;
                   2350: 
                   2351:        if (rbufp->recv_length != sizeof(parsetime_t))
                   2352:        {
                   2353:                ERR(ERR_BADIO)
                   2354:                        msyslog(LOG_ERR,"PARSE receiver #%d: local_receive: bad size (got %d expected %d)",
                   2355:                                CLK_UNIT(parse->peer), rbufp->recv_length, (int)sizeof(parsetime_t));
                   2356:                parse_event(parse, CEVNT_BADREPLY);
                   2357:                return;
                   2358:        }
                   2359:        clear_err(parse, ERR_BADIO);
                   2360:   
                   2361:        memmove((caddr_t)&parsetime,
                   2362:                (caddr_t)rbufp->recv_buffer,
                   2363:                sizeof(parsetime_t));
                   2364: 
                   2365: #ifdef DEBUG
                   2366:        if (debug > 3)
                   2367:          {
                   2368:            printf("PARSE receiver #%d: status %06x, state %08x, time(fp) %lx.%08lx, stime(fp) %lx.%08lx, ptime(fp) %lx.%08lx\n",
                   2369:                   CLK_UNIT(parse->peer),
                   2370:                   (unsigned int)parsetime.parse_status,
                   2371:                   (unsigned int)parsetime.parse_state,
                   2372:                   (unsigned long)parsetime.parse_time.fp.l_ui,
                   2373:                   (unsigned long)parsetime.parse_time.fp.l_uf,
                   2374:                   (unsigned long)parsetime.parse_stime.fp.l_ui,
                   2375:                   (unsigned long)parsetime.parse_stime.fp.l_uf,
                   2376:                   (unsigned long)parsetime.parse_ptime.fp.l_ui,
                   2377:                   (unsigned long)parsetime.parse_ptime.fp.l_uf);
                   2378:          }
                   2379: #endif
                   2380: 
                   2381:        parse_process(parse, &parsetime);
                   2382: }
                   2383: 
                   2384: /*--------------------------------------------------
                   2385:  * init_iobinding - find and initialize lower layers
                   2386:  */
                   2387: static bind_t *
                   2388: init_iobinding(
                   2389:        struct parseunit *parse
                   2390:        )
                   2391: {
                   2392:   bind_t *b = io_bindings;
                   2393: 
                   2394:        while (b->bd_description != (char *)0)
                   2395:        {
                   2396:                if ((*b->bd_init)(parse))
                   2397:                {
                   2398:                        return b;
                   2399:                }
                   2400:                b++;
                   2401:        }
                   2402:        return (bind_t *)0;
                   2403: }
                   2404: 
                   2405: /**===========================================================================
                   2406:  ** support routines
                   2407:  **/
                   2408: 
                   2409: /*--------------------------------------------------
                   2410:  * convert a flag field to a string
                   2411:  */
                   2412: static char *
                   2413: parsestate(
                   2414:        u_long lstate,
                   2415:        char *buffer,
                   2416:        int size
                   2417:        )
                   2418: {
                   2419:        static struct bits
                   2420:        {
                   2421:                u_long      bit;
                   2422:                const char *name;
                   2423:        } flagstrings[] =
                   2424:          {
                   2425:                  { PARSEB_ANNOUNCE,   "DST SWITCH WARNING" },
                   2426:                  { PARSEB_POWERUP,    "NOT SYNCHRONIZED" },
                   2427:                  { PARSEB_NOSYNC,     "TIME CODE NOT CONFIRMED" },
                   2428:                  { PARSEB_DST,        "DST" },
                   2429:                  { PARSEB_UTC,        "UTC DISPLAY" },
                   2430:                  { PARSEB_LEAPADD,    "LEAP ADD WARNING" },
                   2431:                  { PARSEB_LEAPDEL,    "LEAP DELETE WARNING" },
                   2432:                  { PARSEB_LEAPSECOND, "LEAP SECOND" },
                   2433:                  { PARSEB_ALTERNATE,  "ALTERNATE ANTENNA" },
                   2434:                  { PARSEB_TIMECODE,   "TIME CODE" },
                   2435:                  { PARSEB_PPS,        "PPS" },
                   2436:                  { PARSEB_POSITION,   "POSITION" },
                   2437:                  { 0 }
                   2438:          };
                   2439: 
                   2440:        static struct sbits
                   2441:        {
                   2442:                u_long      bit;
                   2443:                const char *name;
                   2444:        } sflagstrings[] =
                   2445:          {
                   2446:                  { PARSEB_S_LEAP,     "LEAP INDICATION" },
                   2447:                  { PARSEB_S_PPS,      "PPS SIGNAL" },
                   2448:                  { PARSEB_S_ANTENNA,  "ANTENNA" },
                   2449:                  { PARSEB_S_POSITION, "POSITION" },
                   2450:                  { 0 }
                   2451:          };
                   2452:        int i;
                   2453:        char *s, *t;
                   2454: 
                   2455: 
                   2456:        *buffer = '\0';
                   2457:        s = t = buffer;
                   2458: 
                   2459:        i = 0;
                   2460:        while (flagstrings[i].bit)
                   2461:        {
                   2462:                if (flagstrings[i].bit & lstate)
                   2463:                {
                   2464:                        if (s != t)
                   2465:                                strncpy(t, "; ", BUFFER_SIZES(buffer, t, size));
                   2466:                        strncat(t, flagstrings[i].name, BUFFER_SIZES(buffer, t, size));
                   2467:                        t += strlen(t);
                   2468:                }
                   2469:                i++;
                   2470:        }
                   2471: 
                   2472:        if (lstate & (PARSEB_S_LEAP|PARSEB_S_ANTENNA|PARSEB_S_PPS|PARSEB_S_POSITION))
                   2473:        {
                   2474:                if (s != t)
                   2475:                        strncpy(t, "; ", BUFFER_SIZES(buffer, t, size));
                   2476: 
                   2477:                t += strlen(t);
                   2478: 
                   2479:                strncpy(t, "(", BUFFER_SIZES(buffer, t, size));
                   2480: 
                   2481:                s = t = t + strlen(t);
                   2482: 
                   2483:                i = 0;
                   2484:                while (sflagstrings[i].bit)
                   2485:                {
                   2486:                        if (sflagstrings[i].bit & lstate)
                   2487:                        {
                   2488:                                if (t != s)
                   2489:                                {
                   2490:                                        strncpy(t, "; ", BUFFER_SIZES(buffer, t, size));
                   2491:                                        t += 2;
                   2492:                                }
                   2493:        
                   2494:                                strncpy(t, sflagstrings[i].name, BUFFER_SIZES(buffer, t, size));
                   2495:                                t += strlen(t);
                   2496:                        }
                   2497:                        i++;
                   2498:                }
                   2499:                strncpy(t, ")", BUFFER_SIZES(buffer, t, size));
                   2500:        }
                   2501:        return buffer;
                   2502: }
                   2503: 
                   2504: /*--------------------------------------------------
                   2505:  * convert a status flag field to a string
                   2506:  */
                   2507: static char *
                   2508: parsestatus(
                   2509:        u_long lstate,
                   2510:        char *buffer,
                   2511:        int size
                   2512:        )
                   2513: {
                   2514:        static struct bits
                   2515:        {
                   2516:                u_long      bit;
                   2517:                const char *name;
                   2518:        } flagstrings[] =
                   2519:          {
                   2520:                  { CVT_OK,      "CONVERSION SUCCESSFUL" },
                   2521:                  { CVT_NONE,    "NO CONVERSION" },
                   2522:                  { CVT_FAIL,    "CONVERSION FAILED" },
                   2523:                  { CVT_BADFMT,  "ILLEGAL FORMAT" },
                   2524:                  { CVT_BADDATE, "DATE ILLEGAL" },
                   2525:                  { CVT_BADTIME, "TIME ILLEGAL" },
                   2526:                  { CVT_ADDITIONAL, "ADDITIONAL DATA" },
                   2527:                  { 0 }
                   2528:          };
                   2529:        int i;
                   2530: 
                   2531:        *buffer = '\0';
                   2532: 
                   2533:        i = 0;
                   2534:        while (flagstrings[i].bit)
                   2535:        {
                   2536:                if (flagstrings[i].bit & lstate)
                   2537:                {
                   2538:                        if (buffer[0])
                   2539:                                strncat(buffer, "; ", size);
                   2540:                        strncat(buffer, flagstrings[i].name, size);
                   2541:                }
                   2542:                i++;
                   2543:        }
                   2544: 
                   2545:        return buffer;
                   2546: }
                   2547: 
                   2548: /*--------------------------------------------------
                   2549:  * convert a clock status flag field to a string
                   2550:  */
                   2551: static const char *
                   2552: clockstatus(
                   2553:        u_long lstate
                   2554:        )
                   2555: {
                   2556:        static char buffer[20];
                   2557:        static struct status
                   2558:        {
                   2559:                u_long      value;
                   2560:                const char *name;
                   2561:        } flagstrings[] =
                   2562:          {
                   2563:                  { CEVNT_NOMINAL, "NOMINAL" },
                   2564:                  { CEVNT_TIMEOUT, "NO RESPONSE" },
                   2565:                  { CEVNT_BADREPLY,"BAD FORMAT" },
                   2566:                  { CEVNT_FAULT,   "FAULT" },
                   2567:                  { CEVNT_PROP,    "PROPAGATION DELAY" },
                   2568:                  { CEVNT_BADDATE, "ILLEGAL DATE" },
                   2569:                  { CEVNT_BADTIME, "ILLEGAL TIME" },
                   2570:                  { (unsigned)~0L }
                   2571:          };
                   2572:        int i;
                   2573: 
                   2574:        i = 0;
                   2575:        while (flagstrings[i].value != ~0)
                   2576:        {
                   2577:                if (flagstrings[i].value == lstate)
                   2578:                {
                   2579:                        return flagstrings[i].name;
                   2580:                }
                   2581:                i++;
                   2582:        }
                   2583: 
                   2584:        snprintf(buffer, sizeof(buffer), "unknown #%ld", (u_long)lstate);
                   2585: 
                   2586:        return buffer;
                   2587: }
                   2588: 
                   2589: 
                   2590: /*--------------------------------------------------
                   2591:  * l_mktime - make representation of a relative time
                   2592:  */
                   2593: static char *
                   2594: l_mktime(
                   2595:        u_long delta
                   2596:        )
                   2597: {
                   2598:        u_long tmp, m, s;
                   2599:        static char buffer[40];
                   2600:        char *t;
                   2601: 
                   2602:        buffer[0] = '\0';
                   2603: 
                   2604:        if ((tmp = delta / (60*60*24)) != 0)
                   2605:        {
                   2606:                snprintf(buffer, BUFFER_SIZE(buffer, buffer), "%ldd+", (u_long)tmp);
                   2607:                delta -= tmp * 60*60*24;
                   2608:        }
                   2609: 
                   2610:        s = delta % 60;
                   2611:        delta /= 60;
                   2612:        m = delta % 60;
                   2613:        delta /= 60;
                   2614: 
                   2615:        t = buffer + strlen(buffer);
                   2616: 
                   2617:        snprintf(t, BUFFER_SIZE(buffer, t), "%02d:%02d:%02d",
                   2618:                 (int)delta, (int)m, (int)s);
                   2619: 
                   2620:        return buffer;
                   2621: }
                   2622: 
                   2623: 
                   2624: /*--------------------------------------------------
                   2625:  * parse_statistics - list summary of clock states
                   2626:  */
                   2627: static void
                   2628: parse_statistics(
                   2629:        struct parseunit *parse
                   2630:        )
                   2631: {
                   2632:        int i;
                   2633: 
                   2634:        NLOG(NLOG_CLOCKSTATIST) /* conditional if clause for conditional syslog */
                   2635:                {
                   2636:                        msyslog(LOG_INFO, "PARSE receiver #%d: running time: %s",
                   2637:                                CLK_UNIT(parse->peer),
                   2638:                                l_mktime(current_time - parse->generic->timestarted));
                   2639: 
                   2640:                        msyslog(LOG_INFO, "PARSE receiver #%d: current status: %s",
                   2641:                                CLK_UNIT(parse->peer),
                   2642:                                clockstatus(parse->generic->currentstatus));
                   2643: 
                   2644:                        for (i = 0; i <= CEVNT_MAX; i++)
                   2645:                        {
                   2646:                                u_long s_time;
                   2647:                                u_long percent, d = current_time - parse->generic->timestarted;
                   2648: 
                   2649:                                percent = s_time = PARSE_STATETIME(parse, i);
                   2650: 
                   2651:                                while (((u_long)(~0) / 10000) < percent)
                   2652:                                {
                   2653:                                        percent /= 10;
                   2654:                                        d       /= 10;
                   2655:                                }
                   2656: 
                   2657:                                if (d)
                   2658:                                    percent = (percent * 10000) / d;
                   2659:                                else
                   2660:                                    percent = 10000;
                   2661: 
                   2662:                                if (s_time)
                   2663:                                    msyslog(LOG_INFO, "PARSE receiver #%d: state %18s: %13s (%3ld.%02ld%%)",
                   2664:                                            CLK_UNIT(parse->peer),
                   2665:                                            clockstatus((unsigned int)i),
                   2666:                                            l_mktime(s_time),
                   2667:                                            percent / 100, percent % 100);
                   2668:                        }
                   2669:                }
                   2670: }
                   2671: 
                   2672: /*--------------------------------------------------
                   2673:  * cparse_statistics - wrapper for statistics call
                   2674:  */
                   2675: static void
                   2676: cparse_statistics(
                   2677:         struct parseunit *parse
                   2678:        )
                   2679: {
                   2680:        if (parse->laststatistic + PARSESTATISTICS < current_time)
                   2681:                parse_statistics(parse);
                   2682:        parse->laststatistic = current_time;
                   2683: }
                   2684: 
                   2685: /**===========================================================================
                   2686:  ** ntp interface routines
                   2687:  **/
                   2688: 
                   2689: /*--------------------------------------------------
                   2690:  * parse_shutdown - shut down a PARSE clock
                   2691:  */
                   2692: static void
                   2693: parse_shutdown(
                   2694:        int unit,
                   2695:        struct peer *peer
                   2696:        )
                   2697: {
                   2698:        struct parseunit *parse = (struct parseunit *)0;
                   2699: 
                   2700:        if (peer && peer->procptr)
                   2701:                parse = (struct parseunit *)peer->procptr->unitptr;
                   2702: 
                   2703:        if (!parse)
                   2704:        {
                   2705:                /* nothing to clean up */
                   2706:                return;
                   2707:        }
                   2708: 
                   2709:         if (!parse->peer)
                   2710:        {
                   2711:                msyslog(LOG_INFO, "PARSE receiver #%d: INTERNAL ERROR - unit already inactive - shutdown ignored", unit);
                   2712:                return;
                   2713:        }
                   2714: 
                   2715: #ifdef HAVE_PPSAPI
                   2716:        if (parse->flags & PARSE_PPSCLOCK)
                   2717:        {
                   2718:                (void)time_pps_destroy(parse->atom.handle);
                   2719:        }
                   2720: #endif
                   2721:        if (parse->generic->io.fd != parse->ppsfd && parse->ppsfd != -1)
                   2722:                (void)close(parse->ppsfd);  /* close separate PPS source */
                   2723: 
                   2724:        /*
                   2725:         * print statistics a last time and
                   2726:         * stop statistics machine
                   2727:         */
                   2728:        parse_statistics(parse);
                   2729: 
                   2730:        if (parse->parse_type->cl_end)
                   2731:        {
                   2732:                parse->parse_type->cl_end(parse);
                   2733:        }
                   2734:        
                   2735:        /*
                   2736:         * cleanup before leaving this world
                   2737:         */
                   2738:        if (parse->binding)
                   2739:            PARSE_END(parse);
                   2740: 
                   2741:        /*
                   2742:         * Tell the I/O module to turn us off.  We're history.
                   2743:         */
                   2744:        io_closeclock(&parse->generic->io);
                   2745: 
                   2746:        free_varlist(parse->kv);
                   2747:   
                   2748:        NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */
                   2749:                msyslog(LOG_INFO, "PARSE receiver #%d: reference clock \"%s\" removed",
                   2750:                        CLK_UNIT(parse->peer), parse->parse_type->cl_description);
                   2751: 
                   2752:        parse->peer = (struct peer *)0; /* unused now */
                   2753:        peer->procptr->unitptr = (caddr_t)0;
                   2754:        free(parse);
                   2755: }
                   2756: 
                   2757: #ifdef HAVE_PPSAPI
                   2758: /*----------------------------------------
                   2759:  * set up HARDPPS via PPSAPI
                   2760:  */
                   2761: static void
                   2762: parse_hardpps(
                   2763:              struct parseunit *parse,
                   2764:              int mode
                   2765:              )
                   2766: {
                   2767:         if (parse->hardppsstate == mode)
                   2768:                return;
                   2769: 
                   2770:        if (CLK_PPS(parse->peer) && (parse->flags & PARSE_PPSKERNEL)) {
                   2771:                int     i = 0;
                   2772: 
                   2773:                if (mode == PARSE_HARDPPS_ENABLE) 
                   2774:                        {
                   2775:                                if (parse->flags & PARSE_CLEAR)
                   2776:                                        i = PPS_CAPTURECLEAR;
                   2777:                                else
                   2778:                                        i = PPS_CAPTUREASSERT;
                   2779:                        }
                   2780:                
                   2781:                if (time_pps_kcbind(parse->atom.handle, PPS_KC_HARDPPS, i,
                   2782:                    PPS_TSFMT_TSPEC) < 0) {
                   2783:                        msyslog(LOG_ERR, "PARSE receiver #%d: time_pps_kcbind failed: %m",
                   2784:                                CLK_UNIT(parse->peer));
                   2785:                } else {
                   2786:                        NLOG(NLOG_CLOCKINFO)
                   2787:                                msyslog(LOG_INFO, "PARSE receiver #%d: kernel PPS synchronisation %sabled",
                   2788:                                        CLK_UNIT(parse->peer), (mode == PARSE_HARDPPS_ENABLE) ? "en" : "dis");
                   2789:                        /*
                   2790:                         * tell the rest, that we have a kernel PPS source, iff we ever enable HARDPPS
                   2791:                         */
                   2792:                        if (mode == PARSE_HARDPPS_ENABLE)
                   2793:                                pps_enable = 1;
                   2794:                }
                   2795:        }
                   2796: 
                   2797:        parse->hardppsstate = mode;
                   2798: }
                   2799: 
                   2800: /*----------------------------------------
                   2801:  * set up PPS via PPSAPI
                   2802:  */
                   2803: static int
                   2804: parse_ppsapi(
                   2805:             struct parseunit *parse
                   2806:        )
                   2807: {
                   2808:        int cap, mode_ppsoffset;
                   2809:        char *cp;
                   2810:        
                   2811:        parse->flags &= ~PARSE_PPSCLOCK;
                   2812: 
                   2813:        /*
                   2814:         * collect PPSAPI offset capability - should move into generic handling
                   2815:         */
                   2816:        if (time_pps_getcap(parse->atom.handle, &cap) < 0) {
                   2817:                msyslog(LOG_ERR, "PARSE receiver #%d: parse_ppsapi: time_pps_getcap failed: %m",
                   2818:                        CLK_UNIT(parse->peer));
                   2819:                
                   2820:                return 0;
                   2821:        }
                   2822: 
                   2823:        /*
                   2824:         * initialize generic PPSAPI interface
                   2825:         *
                   2826:         * we leave out CLK_FLAG3 as time_pps_kcbind()
                   2827:         * is handled here for now. Ideally this should also
                   2828:         * be part of the generic PPSAPI interface
                   2829:         */
                   2830:        if (!refclock_params(parse->flags & (CLK_FLAG1|CLK_FLAG2|CLK_FLAG4), &parse->atom))
                   2831:                return 0;
                   2832: 
                   2833:        /* nb. only turn things on, if someone else has turned something
                   2834:         *      on before we get here, leave it alone!
                   2835:         */
                   2836: 
                   2837:        if (parse->flags & PARSE_CLEAR) {
                   2838:                cp = "CLEAR";
                   2839:                mode_ppsoffset = PPS_OFFSETCLEAR;
                   2840:        } else {
                   2841:                cp = "ASSERT";
                   2842:                mode_ppsoffset = PPS_OFFSETASSERT;
                   2843:        }
                   2844: 
                   2845:        msyslog(LOG_INFO, "PARSE receiver #%d: initializing PPS to %s",
                   2846:                CLK_UNIT(parse->peer), cp);
                   2847: 
                   2848:        if (!(mode_ppsoffset & cap)) {
                   2849:          msyslog(LOG_WARNING, "PARSE receiver #%d: Cannot set PPS_%sCLEAR, this will increase jitter (PPS API capabilities=0x%x)",
                   2850:                  CLK_UNIT(parse->peer), cp, cap);
                   2851:                mode_ppsoffset = 0;
                   2852:        } else {
                   2853:                if (mode_ppsoffset == PPS_OFFSETCLEAR) 
                   2854:                        {
                   2855:                                parse->atom.pps_params.clear_offset.tv_sec = -parse->ppsphaseadjust;
                   2856:                                parse->atom.pps_params.clear_offset.tv_nsec = -1e9*(parse->ppsphaseadjust - (long)parse->ppsphaseadjust);
                   2857:                        }
                   2858:          
                   2859:                if (mode_ppsoffset == PPS_OFFSETASSERT)
                   2860:                        {
                   2861:                                parse->atom.pps_params.assert_offset.tv_sec = -parse->ppsphaseadjust;
                   2862:                                parse->atom.pps_params.assert_offset.tv_nsec = -1e9*(parse->ppsphaseadjust - (long)parse->ppsphaseadjust);
                   2863:                        }
                   2864:        }
                   2865:        
                   2866:        parse->atom.pps_params.mode |= mode_ppsoffset;
                   2867: 
                   2868:        if (time_pps_setparams(parse->atom.handle, &parse->atom.pps_params) < 0) {
                   2869:          msyslog(LOG_ERR, "PARSE receiver #%d: FAILED set PPS parameters: %m",
                   2870:                  CLK_UNIT(parse->peer));
                   2871:                return 0;
                   2872:        }
                   2873: 
                   2874:        parse->flags |= PARSE_PPSCLOCK;
                   2875:        return 1;
                   2876: }
                   2877: #else
                   2878: #define parse_hardpps(_PARSE_, _MODE_) /* empty */
                   2879: #endif
                   2880: 
                   2881: /*--------------------------------------------------
                   2882:  * parse_start - open the PARSE devices and initialize data for processing
                   2883:  */
                   2884: static int
                   2885: parse_start(
                   2886:        int sysunit,
                   2887:        struct peer *peer
                   2888:        )
                   2889: {
                   2890:        u_int unit;
                   2891:        int fd232;
                   2892: #ifdef HAVE_TERMIOS
                   2893:        struct termios tio;             /* NEEDED FOR A LONG TIME ! */
                   2894: #endif
                   2895: #ifdef HAVE_SYSV_TTYS
                   2896:        struct termio tio;              /* NEEDED FOR A LONG TIME ! */
                   2897: #endif
                   2898:        struct parseunit * parse;
                   2899:        char parsedev[sizeof(PARSEDEVICE)+20];
                   2900:        char parseppsdev[sizeof(PARSEPPSDEVICE)+20];
                   2901:        parsectl_t tmp_ctl;
                   2902:        u_int type;
                   2903: 
                   2904:        /*
                   2905:         * get out Copyright information once
                   2906:         */
                   2907:        if (!notice)
                   2908:         {
                   2909:                NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */
                   2910:                        msyslog(LOG_INFO, "NTP PARSE support: Copyright (c) 1989-2009, Frank Kardel");
                   2911:                notice = 1;
                   2912:        }
                   2913: 
                   2914:        type = CLK_TYPE(peer);
                   2915:        unit = CLK_UNIT(peer);
                   2916: 
                   2917:        if ((type == ~0) || (parse_clockinfo[type].cl_description == (char *)0))
                   2918:        {
                   2919:                msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: unsupported clock type %d (max %d)",
                   2920:                        unit, CLK_REALTYPE(peer), ncltypes-1);
                   2921:                return 0;
                   2922:        }
                   2923: 
                   2924:        /*
                   2925:         * Unit okay, attempt to open the device.
                   2926:         */
                   2927:        (void) snprintf(parsedev, sizeof(parsedev), PARSEDEVICE, unit);
                   2928:        (void) snprintf(parseppsdev, sizeof(parsedev), PARSEPPSDEVICE, unit);
                   2929: 
                   2930: #ifndef O_NOCTTY
                   2931: #define O_NOCTTY 0
                   2932: #endif
                   2933: 
                   2934:        fd232 = open(parsedev, O_RDWR | O_NOCTTY
                   2935: #ifdef O_NONBLOCK
                   2936:                     | O_NONBLOCK
                   2937: #endif
                   2938:                     , 0777);
                   2939: 
                   2940:        if (fd232 == -1)
                   2941:        {
                   2942:                msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: open of %s failed: %m", unit, parsedev);
                   2943:                return 0;
                   2944:        }
                   2945: 
                   2946:        parse = (struct parseunit *)emalloc(sizeof(struct parseunit));
                   2947: 
                   2948:        memset((char *)parse, 0, sizeof(struct parseunit));
                   2949: 
                   2950:        parse->generic = peer->procptr;  /* link up */
                   2951:        parse->generic->unitptr = (caddr_t)parse; /* link down */
                   2952: 
                   2953:        /*
                   2954:         * Set up the structures
                   2955:         */
                   2956:        parse->generic->timestarted    = current_time;
                   2957:        parse->lastchange     = current_time;
                   2958: 
                   2959:        parse->flags          = 0;
                   2960:        parse->pollneeddata   = 0;
                   2961:        parse->laststatistic  = current_time;
                   2962:        parse->lastformat     = (unsigned short)~0;     /* assume no format known */
                   2963:        parse->timedata.parse_status = (unsigned short)~0;      /* be sure to mark initial status change */
                   2964:        parse->lastmissed     = 0;      /* assume got everything */
                   2965:        parse->ppsserial      = 0;
                   2966:        parse->ppsfd          = -1;
                   2967:        parse->localdata      = (void *)0;
                   2968:        parse->localstate     = 0;
                   2969:        parse->kv             = (struct ctl_var *)0;
                   2970: 
                   2971:        clear_err(parse, ERR_ALL);
                   2972:   
                   2973:        parse->parse_type     = &parse_clockinfo[type];
                   2974:        
                   2975:        parse->maxunsync      = parse->parse_type->cl_maxunsync;
                   2976: 
                   2977:        parse->generic->fudgetime1 = parse->parse_type->cl_basedelay;
                   2978: 
                   2979:        parse->generic->fudgetime2 = 0.0;
                   2980:        parse->ppsphaseadjust = parse->generic->fudgetime2;
                   2981: 
                   2982:        parse->generic->clockdesc  = parse->parse_type->cl_description;
                   2983: 
                   2984:        peer->rootdelay       = parse->parse_type->cl_rootdelay;
                   2985:        peer->sstclktype      = parse->parse_type->cl_type;
                   2986:        peer->precision       = sys_precision;
                   2987:        
                   2988:        peer->stratum         = STRATUM_REFCLOCK;
                   2989: 
                   2990:        if (peer->stratum <= 1)
                   2991:            memmove((char *)&parse->generic->refid, parse->parse_type->cl_id, 4);
                   2992:        else
                   2993:            parse->generic->refid = htonl(PARSEHSREFID);
                   2994:        
                   2995:        parse->generic->io.fd = fd232;
                   2996:        
                   2997:        parse->peer = peer;             /* marks it also as busy */
                   2998: 
                   2999:        /*
                   3000:         * configure terminal line
                   3001:         */
                   3002:        if (TTY_GETATTR(fd232, &tio) == -1)
                   3003:        {
                   3004:                msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: tcgetattr(%d, &tio): %m", unit, fd232);
                   3005:                parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
                   3006:                return 0;
                   3007:        }
                   3008:        else
                   3009:        {
                   3010: #ifndef _PC_VDISABLE
                   3011:                memset((char *)tio.c_cc, 0, sizeof(tio.c_cc));
                   3012: #else
                   3013:                int disablec;
                   3014:                errno = 0;              /* pathconf can deliver -1 without changing errno ! */
                   3015: 
                   3016:                disablec = fpathconf(parse->generic->io.fd, _PC_VDISABLE);
                   3017:                if (disablec == -1 && errno)
                   3018:                {
                   3019:                        msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: fpathconf(fd, _PC_VDISABLE): %m", CLK_UNIT(parse->peer));
                   3020:                        memset((char *)tio.c_cc, 0, sizeof(tio.c_cc)); /* best guess */
                   3021:                }
                   3022:                else
                   3023:                    if (disablec != -1)
                   3024:                        memset((char *)tio.c_cc, disablec, sizeof(tio.c_cc));
                   3025: #endif
                   3026: 
                   3027: #if defined (VMIN) || defined(VTIME)
                   3028:                if ((parse_clockinfo[type].cl_lflag & ICANON) == 0)
                   3029:                {
                   3030: #ifdef VMIN
                   3031:                        tio.c_cc[VMIN]   = 1;
                   3032: #endif
                   3033: #ifdef VTIME
                   3034:                        tio.c_cc[VTIME]  = 0;
                   3035: #endif
                   3036:                }
                   3037: #endif
                   3038: 
                   3039:                tio.c_cflag = parse_clockinfo[type].cl_cflag;
                   3040:                tio.c_iflag = parse_clockinfo[type].cl_iflag;
                   3041:                tio.c_oflag = parse_clockinfo[type].cl_oflag;
                   3042:                tio.c_lflag = parse_clockinfo[type].cl_lflag;
                   3043:        
                   3044: 
                   3045: #ifdef HAVE_TERMIOS
                   3046:                if ((cfsetospeed(&tio, parse_clockinfo[type].cl_speed) == -1) ||
                   3047:                    (cfsetispeed(&tio, parse_clockinfo[type].cl_speed) == -1))
                   3048:                {
                   3049:                        msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: tcset{i,o}speed(&tio, speed): %m", unit);
                   3050:                        parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
                   3051:                        return 0;
                   3052:                }
                   3053: #else
                   3054:                tio.c_cflag     |= parse_clockinfo[type].cl_speed;
                   3055: #endif
                   3056: 
                   3057:                /*
                   3058:                 * set up pps device
                   3059:                 * if the PARSEPPSDEVICE can be opened that will be used
                   3060:                 * for PPS else PARSEDEVICE will be used
                   3061:                 */
                   3062:                parse->ppsfd = open(parseppsdev, O_RDWR | O_NOCTTY
                   3063: #ifdef O_NONBLOCK
                   3064:                                    | O_NONBLOCK
                   3065: #endif
                   3066:                                    , 0777);
                   3067: 
                   3068:                if (parse->ppsfd == -1)
                   3069:                {
                   3070:                        parse->ppsfd = fd232;
                   3071:                }
                   3072: 
                   3073: /*
                   3074:  * Linux PPS - the old way
                   3075:  */
                   3076: #if defined(HAVE_TIO_SERIAL_STUFF)             /* Linux hack: define PPS interface */
                   3077:                {
                   3078:                        struct serial_struct    ss;
                   3079:                        if (ioctl(parse->ppsfd, TIOCGSERIAL, &ss) < 0 ||
                   3080:                            (
                   3081: #ifdef ASYNC_LOW_LATENCY
                   3082:                             ss.flags |= ASYNC_LOW_LATENCY,
                   3083: #endif
                   3084: #ifndef HAVE_PPSAPI
                   3085: #ifdef ASYNC_PPS_CD_NEG
                   3086:                             ss.flags |= ASYNC_PPS_CD_NEG,
                   3087: #endif
                   3088: #endif
                   3089:                             ioctl(parse->ppsfd, TIOCSSERIAL, &ss)) < 0) {
                   3090:                                msyslog(LOG_NOTICE, "refclock_parse: TIOCSSERIAL fd %d, %m", parse->ppsfd);
                   3091:                                msyslog(LOG_NOTICE,
                   3092:                                        "refclock_parse: optional PPS processing not available");
                   3093:                        } else {
                   3094:                                parse->flags    |= PARSE_PPSCLOCK;
                   3095: #ifdef ASYNC_PPS_CD_NEG
                   3096:                                NLOG(NLOG_CLOCKINFO)
                   3097:                                  msyslog(LOG_INFO,
                   3098:                                          "refclock_parse: PPS detection on");
                   3099: #endif
                   3100:                        }
                   3101:                }
                   3102: #endif
                   3103: 
                   3104: /*
                   3105:  * SUN the Solaris way
                   3106:  */
                   3107: #ifdef HAVE_TIOCSPPS                   /* SUN PPS support */
                   3108:                if (CLK_PPS(parse->peer))
                   3109:                    {
                   3110:                        int i = 1;
                   3111:                    
                   3112:                        if (ioctl(parse->ppsfd, TIOCSPPS, (caddr_t)&i) == 0)
                   3113:                            {
                   3114:                                parse->flags |= PARSE_PPSCLOCK;
                   3115:                            }
                   3116:                    }
                   3117: #endif
                   3118: 
                   3119: /*
                   3120:  * PPS via PPSAPI
                   3121:  */
                   3122: #if defined(HAVE_PPSAPI)
                   3123:                parse->hardppsstate = PARSE_HARDPPS_DISABLE;
                   3124:                if (CLK_PPS(parse->peer))
                   3125:                {
                   3126:                  if (!refclock_ppsapi(parse->ppsfd, &parse->atom))
                   3127:                    {
                   3128:                      msyslog(LOG_NOTICE, "PARSE receiver #%d: parse_start: could not set up PPS: %m", CLK_UNIT(parse->peer));
                   3129:                    }
                   3130:                  else
                   3131:                    {
                   3132:                      parse_ppsapi(parse);
                   3133:                    }
                   3134:                }
                   3135: #endif
                   3136: 
                   3137:                if (TTY_SETATTR(fd232, &tio) == -1)
                   3138:                {
                   3139:                        msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: tcsetattr(%d, &tio): %m", unit, fd232);
                   3140:                        parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
                   3141:                        return 0;
                   3142:                }
                   3143:        }
                   3144: 
                   3145:        /*
                   3146:         * pick correct input machine
                   3147:         */
                   3148:        parse->generic->io.srcclock = (caddr_t)parse;
                   3149:        parse->generic->io.datalen = 0;
                   3150:        
                   3151:        parse->binding = init_iobinding(parse);
                   3152: 
                   3153:        if (parse->binding == (bind_t *)0)
                   3154:                {
                   3155:                        msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: io sub system initialisation failed.", CLK_UNIT(parse->peer));
                   3156:                        parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
                   3157:                        return 0;                       /* well, ok - special initialisation broke */
                   3158:                }      
                   3159: 
                   3160:        parse->generic->io.clock_recv = parse->binding->bd_receive; /* pick correct receive routine */
                   3161:        parse->generic->io.io_input   = parse->binding->bd_io_input; /* pick correct input routine */
                   3162: 
                   3163:        /*
                   3164:         * as we always(?) get 8 bit chars we want to be
                   3165:         * sure, that the upper bits are zero for less
                   3166:         * than 8 bit I/O - so we pass that information on.
                   3167:         * note that there can be only one bit count format
                   3168:         * per file descriptor
                   3169:         */
                   3170: 
                   3171:        switch (tio.c_cflag & CSIZE)
                   3172:        {
                   3173:            case CS5:
                   3174:                tmp_ctl.parsesetcs.parse_cs = PARSE_IO_CS5;
                   3175:                break;
                   3176: 
                   3177:            case CS6:
                   3178:                tmp_ctl.parsesetcs.parse_cs = PARSE_IO_CS6;
                   3179:                break;
                   3180: 
                   3181:            case CS7:
                   3182:                tmp_ctl.parsesetcs.parse_cs = PARSE_IO_CS7;
                   3183:                break;
                   3184: 
                   3185:            case CS8:
                   3186:                tmp_ctl.parsesetcs.parse_cs = PARSE_IO_CS8;
                   3187:                break;
                   3188:        }
                   3189: 
                   3190:        if (!PARSE_SETCS(parse, &tmp_ctl))
                   3191:        {
                   3192:                msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: parse_setcs() FAILED.", unit);
                   3193:                parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
                   3194:                return 0;                       /* well, ok - special initialisation broke */
                   3195:        }
                   3196:   
                   3197:        strncpy(tmp_ctl.parseformat.parse_buffer, parse->parse_type->cl_format, sizeof(tmp_ctl.parseformat.parse_buffer));
                   3198:        tmp_ctl.parseformat.parse_count = strlen(tmp_ctl.parseformat.parse_buffer);
                   3199: 
                   3200:        if (!PARSE_SETFMT(parse, &tmp_ctl))
                   3201:        {
                   3202:                msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: parse_setfmt() FAILED.", unit);
                   3203:                parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
                   3204:                return 0;                       /* well, ok - special initialisation broke */
                   3205:        }
                   3206:   
                   3207:        /*
                   3208:         * get rid of all IO accumulated so far
                   3209:         */
                   3210: #ifdef HAVE_TERMIOS
                   3211:        (void) tcflush(parse->generic->io.fd, TCIOFLUSH);
                   3212: #else
                   3213: #if defined(TCFLSH) && defined(TCIOFLUSH)
                   3214:        {
                   3215:                int flshcmd = TCIOFLUSH;
                   3216: 
                   3217:                (void) ioctl(parse->generic->io.fd, TCFLSH, (caddr_t)&flshcmd);
                   3218:        }
                   3219: #endif
                   3220: #endif
                   3221: 
                   3222:        /*
                   3223:         * try to do any special initializations
                   3224:         */
                   3225:        if (parse->parse_type->cl_init)
                   3226:                {
                   3227:                        if (parse->parse_type->cl_init(parse))
                   3228:                                {
                   3229:                                        parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
                   3230:                                        return 0;               /* well, ok - special initialisation broke */
                   3231:                                }
                   3232:                }
                   3233:        
                   3234:        /*
                   3235:         * Insert in async io device list.
                   3236:         */
                   3237:        if (!io_addclock(&parse->generic->io))
                   3238:         {
                   3239:                msyslog(LOG_ERR,
                   3240:                        "PARSE receiver #%d: parse_start: addclock %s fails (ABORT - clock type requires async io)", CLK_UNIT(parse->peer), parsedev);
                   3241:                parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
                   3242:                return 0;
                   3243:        }
                   3244: 
                   3245:        /*
                   3246:         * print out configuration
                   3247:         */
                   3248:        NLOG(NLOG_CLOCKINFO)
                   3249:                {
                   3250:                        /* conditional if clause for conditional syslog */
                   3251:                        msyslog(LOG_INFO, "PARSE receiver #%d: reference clock \"%s\" (I/O device %s, PPS device %s) added",
                   3252:                                CLK_UNIT(parse->peer),
                   3253:                                parse->parse_type->cl_description, parsedev,
                   3254:                                (parse->ppsfd != parse->generic->io.fd) ? parseppsdev : parsedev);
                   3255: 
                   3256:                        msyslog(LOG_INFO, "PARSE receiver #%d: Stratum %d, trust time %s, precision %d",
                   3257:                                CLK_UNIT(parse->peer),
                   3258:                                parse->peer->stratum,
                   3259:                                l_mktime(parse->maxunsync), parse->peer->precision);
                   3260: 
                   3261:                        msyslog(LOG_INFO, "PARSE receiver #%d: rootdelay %.6f s, phase adjustment %.6f s, PPS phase adjustment %.6f s, %s IO handling",
                   3262:                                CLK_UNIT(parse->peer),
                   3263:                                parse->parse_type->cl_rootdelay,
                   3264:                                parse->generic->fudgetime1,
                   3265:                                parse->ppsphaseadjust,
                   3266:                                 parse->binding->bd_description);
                   3267: 
                   3268:                        msyslog(LOG_INFO, "PARSE receiver #%d: Format recognition: %s", CLK_UNIT(parse->peer),
                   3269:                                parse->parse_type->cl_format);
                   3270:                         msyslog(LOG_INFO, "PARSE receiver #%d: %sPPS support%s", CLK_UNIT(parse->peer),
                   3271:                                CLK_PPS(parse->peer) ? "" : "NO ",
                   3272:                                CLK_PPS(parse->peer) ?
                   3273: #ifdef PPS_METHOD
                   3274:                                " (implementation " PPS_METHOD ")"
                   3275: #else
                   3276:                                ""
                   3277: #endif
                   3278:                                : ""
                   3279:                                );
                   3280:                }
                   3281: 
                   3282:        return 1;
                   3283: }
                   3284: 
                   3285: /*--------------------------------------------------
                   3286:  * parse_ctl - process changes on flags/time values
                   3287:  */
                   3288: static void
                   3289: parse_ctl(
                   3290:            struct parseunit *parse,
                   3291:            struct refclockstat *in
                   3292:            )
                   3293: {
                   3294:         if (in)
                   3295:        {
                   3296:                if (in->haveflags & (CLK_HAVEFLAG1|CLK_HAVEFLAG2|CLK_HAVEFLAG3|CLK_HAVEFLAG4))
                   3297:                {
                   3298:                  parse->flags = (parse->flags & ~(CLK_FLAG1|CLK_FLAG2|CLK_FLAG3|CLK_FLAG4)) |
                   3299:                    (in->flags & (CLK_FLAG1|CLK_FLAG2|CLK_FLAG3|CLK_FLAG4));
                   3300: #if defined(HAVE_PPSAPI)
                   3301:                  if (CLK_PPS(parse->peer))
                   3302:                    {
                   3303:                      parse_ppsapi(parse);
                   3304:                    }
                   3305: #endif
                   3306:                }
                   3307:                
                   3308:                if (in->haveflags & CLK_HAVETIME1)
                   3309:                 {
                   3310:                  parse->generic->fudgetime1 = in->fudgetime1;
                   3311:                  msyslog(LOG_INFO, "PARSE receiver #%d: new phase adjustment %.6f s",
                   3312:                          CLK_UNIT(parse->peer),
                   3313:                          parse->generic->fudgetime1);
                   3314:                }
                   3315:                
                   3316:                if (in->haveflags & CLK_HAVETIME2)
                   3317:                 {
                   3318:                  parse->generic->fudgetime2 = in->fudgetime2;
                   3319:                  if (parse->flags & PARSE_TRUSTTIME) 
                   3320:                    {
                   3321:                      parse->maxunsync = (u_long)ABS(in->fudgetime2);
                   3322:                      msyslog(LOG_INFO, "PARSE receiver #%d: new trust time %s",
                   3323:                              CLK_UNIT(parse->peer),
                   3324:                              l_mktime(parse->maxunsync));
                   3325:                    }
                   3326:                  else
                   3327:                    {
                   3328:                      parse->ppsphaseadjust = in->fudgetime2;
                   3329:                      msyslog(LOG_INFO, "PARSE receiver #%d: new PPS phase adjustment %.6f s",
                   3330:                          CLK_UNIT(parse->peer),
                   3331:                              parse->ppsphaseadjust);
                   3332: #if defined(HAVE_PPSAPI)
                   3333:                      if (CLK_PPS(parse->peer))
                   3334:                      {
                   3335:                              parse_ppsapi(parse);
                   3336:                      }
                   3337: #endif
                   3338:                    }
                   3339:                }
                   3340:        }
                   3341: }
                   3342: 
                   3343: /*--------------------------------------------------
                   3344:  * parse_poll - called by the transmit procedure
                   3345:  */
                   3346: static void
                   3347: parse_poll(
                   3348:        int unit,
                   3349:        struct peer *peer
                   3350:        )
                   3351: {
                   3352:        struct parseunit *parse = (struct parseunit *)peer->procptr->unitptr;
                   3353: 
                   3354:        if (peer != parse->peer)
                   3355:        {
                   3356:                msyslog(LOG_ERR,
                   3357:                        "PARSE receiver #%d: poll: INTERNAL: peer incorrect",
                   3358:                        unit);
                   3359:                return;
                   3360:        }
                   3361: 
                   3362:        /*
                   3363:         * Update clock stat counters
                   3364:         */
                   3365:        parse->generic->polls++;
                   3366: 
                   3367:        if (parse->pollneeddata && 
                   3368:            ((current_time - parse->pollneeddata) > (1<<(max(min(parse->peer->hpoll, parse->peer->ppoll), parse->peer->minpoll)))))
                   3369:        {
                   3370:                /*
                   3371:                 * start worrying when exceeding a poll inteval
                   3372:                 * bad news - didn't get a response last time
                   3373:                 */
                   3374:                parse->lastmissed = current_time;
                   3375:                parse_event(parse, CEVNT_TIMEOUT);
                   3376:                
                   3377:                ERR(ERR_NODATA)
                   3378:                        msyslog(LOG_WARNING, "PARSE receiver #%d: no data from device within poll interval (check receiver / wiring)", CLK_UNIT(parse->peer));
                   3379:        }
                   3380: 
                   3381:        /*
                   3382:         * we just mark that we want the next sample for the clock filter
                   3383:         */
                   3384:        parse->pollneeddata = current_time;
                   3385: 
                   3386:        if (parse->parse_type->cl_poll)
                   3387:        {
                   3388:                parse->parse_type->cl_poll(parse);
                   3389:        }
                   3390: 
                   3391:        cparse_statistics(parse);
                   3392: 
                   3393:        return;
                   3394: }
                   3395: 
                   3396: #define LEN_STATES 300         /* length of state string */
                   3397: 
                   3398: /*--------------------------------------------------
                   3399:  * parse_control - set fudge factors, return statistics
                   3400:  */
                   3401: static void
                   3402: parse_control(
                   3403:        int unit,
                   3404:        struct refclockstat *in,
                   3405:        struct refclockstat *out,
                   3406:        struct peer *peer
                   3407:        )
                   3408: {
                   3409:         struct parseunit *parse = (struct parseunit *)peer->procptr->unitptr;
                   3410:        parsectl_t tmpctl;
                   3411: 
                   3412:        static char outstatus[400];     /* status output buffer */
                   3413: 
                   3414:        if (out)
                   3415:        {
                   3416:                out->lencode       = 0;
                   3417:                out->p_lastcode    = 0;
                   3418:                out->kv_list       = (struct ctl_var *)0;
                   3419:        }
                   3420: 
                   3421:        if (!parse || !parse->peer)
                   3422:        {
                   3423:                msyslog(LOG_ERR, "PARSE receiver #%d: parse_control: unit invalid (UNIT INACTIVE)",
                   3424:                        unit);
                   3425:                return;
                   3426:        }
                   3427: 
                   3428:        unit = CLK_UNIT(parse->peer);
                   3429: 
                   3430:        /*
                   3431:         * handle changes
                   3432:         */
                   3433:        parse_ctl(parse, in);
                   3434:                
                   3435:        /*
                   3436:         * supply data
                   3437:         */
                   3438:        if (out)
                   3439:        {
                   3440:                u_long sum = 0;
                   3441:                char *tt, *start;
                   3442:                int i;
                   3443: 
                   3444:                outstatus[0] = '\0';
                   3445: 
                   3446:                out->type       = REFCLK_PARSE;
                   3447: 
                   3448:                /*
                   3449:                 * keep fudgetime2 in sync with TRUSTTIME/MAXUNSYNC flag1
                   3450:                 */
                   3451:                parse->generic->fudgetime2 = (parse->flags & PARSE_TRUSTTIME) ? (double)parse->maxunsync : parse->ppsphaseadjust;
                   3452: 
                   3453:                /*
                   3454:                 * figure out skew between PPS and RS232 - just for informational
                   3455:                 * purposes
                   3456:                 */
                   3457:                if (PARSE_SYNC(parse->timedata.parse_state))
                   3458:                {
                   3459:                        if (PARSE_PPS(parse->timedata.parse_state) && PARSE_TIMECODE(parse->timedata.parse_state))
                   3460:                        {
                   3461:                                l_fp off;
                   3462: 
                   3463:                                /*
                   3464:                                 * we have a PPS and RS232 signal - calculate the skew
                   3465:                                 * WARNING: assumes on TIMECODE == PULSE (timecode after pulse)
                   3466:                                 */
                   3467:                                off = parse->timedata.parse_stime.fp;
                   3468:                                L_SUB(&off, &parse->timedata.parse_ptime.fp); /* true offset */
                   3469:                                tt = add_var(&out->kv_list, 80, RO);
                   3470:                                snprintf(tt, 80, "refclock_ppsskew=%s", lfptoms(&off, 6));
                   3471:                        }
                   3472:                }
                   3473: 
                   3474:                if (PARSE_PPS(parse->timedata.parse_state))
                   3475:                {
                   3476:                        tt = add_var(&out->kv_list, 80, RO|DEF);
                   3477:                        snprintf(tt, 80, "refclock_ppstime=\"%s\"", gmprettydate(&parse->timedata.parse_ptime.fp));
                   3478:                }
                   3479: 
                   3480:                start = tt = add_var(&out->kv_list, 128, RO|DEF);
                   3481:                snprintf(tt, 128, "refclock_time=\"");
                   3482:                tt += strlen(tt);
                   3483: 
                   3484:                if (parse->timedata.parse_time.fp.l_ui == 0)
                   3485:                {
                   3486:                        strncpy(tt, "<UNDEFINED>\"", BUFFER_SIZES(start, tt, 128));
                   3487:                }
                   3488:                else
                   3489:                {
                   3490:                        snprintf(tt, 128, "%s\"", gmprettydate(&parse->timedata.parse_time.fp));
                   3491:                }
                   3492: 
                   3493:                if (!PARSE_GETTIMECODE(parse, &tmpctl))
                   3494:                {
                   3495:                        ERR(ERR_INTERNAL)
                   3496:                                msyslog(LOG_ERR, "PARSE receiver #%d: parse_control: parse_timecode() FAILED", unit);
                   3497:                }
                   3498:                else
                   3499:                {
                   3500:                        start = tt = add_var(&out->kv_list, 512, RO|DEF);
                   3501:                        snprintf(tt, 512, "refclock_status=\"");
                   3502:                        tt += strlen(tt);
                   3503: 
                   3504:                        /*
                   3505:                         * copy PPS flags from last read transaction (informational only)
                   3506:                         */
                   3507:                        tmpctl.parsegettc.parse_state |= parse->timedata.parse_state &
                   3508:                                (PARSEB_PPS|PARSEB_S_PPS);
                   3509: 
                   3510:                        (void) parsestate(tmpctl.parsegettc.parse_state, tt, BUFFER_SIZES(start, tt, 512));
                   3511: 
                   3512:                        strncat(tt, "\"", BUFFER_SIZES(start, tt, 512));
                   3513: 
                   3514:                        if (tmpctl.parsegettc.parse_count)
                   3515:                            mkascii(outstatus+strlen(outstatus), (int)(sizeof(outstatus)- strlen(outstatus) - 1),
                   3516:                                    tmpctl.parsegettc.parse_buffer, (unsigned)(tmpctl.parsegettc.parse_count));
                   3517: 
                   3518:                }
                   3519:        
                   3520:                tmpctl.parseformat.parse_format = tmpctl.parsegettc.parse_format;
                   3521:        
                   3522:                if (!PARSE_GETFMT(parse, &tmpctl))
                   3523:                {
                   3524:                        ERR(ERR_INTERNAL)
                   3525:                                msyslog(LOG_ERR, "PARSE receiver #%d: parse_control: parse_getfmt() FAILED", unit);
                   3526:                }
                   3527:                else
                   3528:                {
                   3529:                        tt = add_var(&out->kv_list, 80, RO|DEF);
                   3530:                        snprintf(tt, 80, "refclock_format=\"");
                   3531: 
                   3532:                        strncat(tt, tmpctl.parseformat.parse_buffer, tmpctl.parseformat.parse_count);
                   3533:                        strncat(tt,"\"", 80);
                   3534:                }
                   3535: 
                   3536:                /*
                   3537:                 * gather state statistics
                   3538:                 */
                   3539: 
                   3540:                start = tt = add_var(&out->kv_list, LEN_STATES, RO|DEF);
                   3541:                strncpy(tt, "refclock_states=\"", LEN_STATES);
                   3542:                tt += strlen(tt);
                   3543: 
                   3544:                for (i = 0; i <= CEVNT_MAX; i++)
                   3545:                {
                   3546:                        u_long s_time;
                   3547:                        u_long d = current_time - parse->generic->timestarted;
                   3548:                        u_long percent;
                   3549: 
                   3550:                        percent = s_time = PARSE_STATETIME(parse, i);
                   3551: 
                   3552:                        while (((u_long)(~0) / 10000) < percent)
                   3553:                        {
                   3554:                                percent /= 10;
                   3555:                                d       /= 10;
                   3556:                        }
                   3557:        
                   3558:                        if (d)
                   3559:                            percent = (percent * 10000) / d;
                   3560:                        else
                   3561:                            percent = 10000;
                   3562: 
                   3563:                        if (s_time)
                   3564:                        {
                   3565:                                char item[80];
                   3566:                                int count;
                   3567:                                
                   3568:                                snprintf(item, 80, "%s%s%s: %s (%d.%02d%%)",
                   3569:                                        sum ? "; " : "",
                   3570:                                        (parse->generic->currentstatus == i) ? "*" : "",
                   3571:                                        clockstatus((unsigned int)i),
                   3572:                                        l_mktime(s_time),
                   3573:                                        (int)(percent / 100), (int)(percent % 100));
                   3574:                                if ((count = strlen(item)) < (LEN_STATES - 40 - (tt - start)))
                   3575:                                        {
                   3576:                                                strncpy(tt, item, BUFFER_SIZES(start, tt, LEN_STATES));
                   3577:                                                tt  += count;
                   3578:                                        }
                   3579:                                sum += s_time;
                   3580:                        }
                   3581:                }
                   3582:                
                   3583:                snprintf(tt, BUFFER_SIZES(start, tt, LEN_STATES), "; running time: %s\"", l_mktime(sum));
                   3584:                
                   3585:                tt = add_var(&out->kv_list, 32, RO);
                   3586:                snprintf(tt, 32,  "refclock_id=\"%s\"", parse->parse_type->cl_id);
                   3587:                
                   3588:                tt = add_var(&out->kv_list, 80, RO);
                   3589:                snprintf(tt, 80,  "refclock_iomode=\"%s\"", parse->binding->bd_description);
                   3590: 
                   3591:                tt = add_var(&out->kv_list, 128, RO);
                   3592:                snprintf(tt, 128, "refclock_driver_version=\"%s\"", rcsid);
                   3593:                
                   3594:                {
                   3595:                        struct ctl_var *k;
                   3596:                        
                   3597:                        k = parse->kv;
                   3598:                        while (k && !(k->flags & EOV))
                   3599:                        {
                   3600:                                set_var(&out->kv_list, k->text, strlen(k->text)+1, k->flags);
                   3601:                                k++;
                   3602:                        }
                   3603:                }
                   3604:       
                   3605:                out->lencode       = strlen(outstatus);
                   3606:                out->p_lastcode    = outstatus;
                   3607:        }
                   3608: }
                   3609: 
                   3610: /**===========================================================================
                   3611:  ** processing routines
                   3612:  **/
                   3613: 
                   3614: /*--------------------------------------------------
                   3615:  * event handling - note that nominal events will also be posted
                   3616:  * keep track of state dwelling times
                   3617:  */
                   3618: static void
                   3619: parse_event(
                   3620:        struct parseunit *parse,
                   3621:        int event
                   3622:        )
                   3623: {
                   3624:        if (parse->generic->currentstatus != (u_char) event)
                   3625:        {
                   3626:                parse->statetime[parse->generic->currentstatus] += current_time - parse->lastchange;
                   3627:                parse->lastchange              = current_time;
                   3628: 
                   3629:                if (parse->parse_type->cl_event)
                   3630:                    parse->parse_type->cl_event(parse, event);
                   3631:       
                   3632:                if (event == CEVNT_NOMINAL)
                   3633:                {
                   3634:                        NLOG(NLOG_CLOCKSTATUS)
                   3635:                                msyslog(LOG_INFO, "PARSE receiver #%d: SYNCHRONIZED",
                   3636:                                        CLK_UNIT(parse->peer));
                   3637:                }
                   3638: 
                   3639:                refclock_report(parse->peer, event);
                   3640:        }
                   3641: }
                   3642: 
                   3643: /*--------------------------------------------------
                   3644:  * process a PARSE time sample
                   3645:  */
                   3646: static void
                   3647: parse_process(
                   3648:        struct parseunit *parse,
                   3649:        parsetime_t      *parsetime
                   3650:        )
                   3651: {
                   3652:        l_fp off, rectime, reftime;
                   3653:        double fudge;
                   3654:        
                   3655:        /*
                   3656:         * check for changes in conversion status
                   3657:         * (only one for each new status !)
                   3658:         */
                   3659:        if (((parsetime->parse_status & CVT_MASK) != CVT_OK) &&
                   3660:            ((parsetime->parse_status & CVT_MASK) != CVT_NONE) &&
                   3661:            (parse->timedata.parse_status != parsetime->parse_status))
                   3662:        {
                   3663:                char buffer[400];
                   3664:                
                   3665:                NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */
                   3666:                        msyslog(LOG_WARNING, "PARSE receiver #%d: conversion status \"%s\"",
                   3667:                                CLK_UNIT(parse->peer), parsestatus(parsetime->parse_status, buffer, sizeof(buffer)));
                   3668:                
                   3669:                if ((parsetime->parse_status & CVT_MASK) == CVT_FAIL)
                   3670:                {
                   3671:                        /*
                   3672:                         * tell more about the story - list time code
                   3673:                         * there is a slight change for a race condition and
                   3674:                         * the time code might be overwritten by the next packet
                   3675:                         */
                   3676:                        parsectl_t tmpctl;
                   3677:                        
                   3678:                        if (!PARSE_GETTIMECODE(parse, &tmpctl))
                   3679:                        {
                   3680:                                ERR(ERR_INTERNAL)
                   3681:                                        msyslog(LOG_ERR, "PARSE receiver #%d: parse_process: parse_timecode() FAILED", CLK_UNIT(parse->peer));
                   3682:                        }
                   3683:                        else
                   3684:                        {
                   3685:                                ERR(ERR_BADDATA)
                   3686:                                        msyslog(LOG_WARNING, "PARSE receiver #%d: FAILED TIMECODE: \"%s\" (check receiver configuration / wiring)",
                   3687:                                                CLK_UNIT(parse->peer), mkascii(buffer, sizeof buffer, tmpctl.parsegettc.parse_buffer, (unsigned)(tmpctl.parsegettc.parse_count - 1)));
                   3688:                        }
                   3689:                }
                   3690:        }
                   3691: 
                   3692:        /*
                   3693:         * examine status and post appropriate events
                   3694:         */
                   3695:        if ((parsetime->parse_status & CVT_MASK) != CVT_OK)
                   3696:        {
                   3697:                /*
                   3698:                 * got bad data - tell the rest of the system
                   3699:                 */
                   3700:                switch (parsetime->parse_status & CVT_MASK)
                   3701:                {
                   3702:                case CVT_NONE:
                   3703:                        if ((parsetime->parse_status & CVT_ADDITIONAL) &&
                   3704:                            parse->parse_type->cl_message)
                   3705:                                parse->parse_type->cl_message(parse, parsetime);
                   3706:                        /*
                   3707:                         * save PPS information that comes piggyback
                   3708:                         */
                   3709:                        if (PARSE_PPS(parsetime->parse_state))
                   3710:                          {
                   3711:                            parse->timedata.parse_state |= PARSEB_PPS|PARSEB_S_PPS;
                   3712:                            parse->timedata.parse_ptime  = parsetime->parse_ptime;
                   3713:                          }
                   3714:                        break;          /* well, still waiting - timeout is handled at higher levels */
                   3715:                            
                   3716:                case CVT_FAIL:
                   3717:                        if (parsetime->parse_status & CVT_BADFMT)
                   3718:                        {
                   3719:                                parse_event(parse, CEVNT_BADREPLY);
                   3720:                        }
                   3721:                        else
                   3722:                                if (parsetime->parse_status & CVT_BADDATE)
                   3723:                                {
                   3724:                                        parse_event(parse, CEVNT_BADDATE);
                   3725:                                }
                   3726:                                else
                   3727:                                        if (parsetime->parse_status & CVT_BADTIME)
                   3728:                                        {
                   3729:                                                parse_event(parse, CEVNT_BADTIME);
                   3730:                                        }
                   3731:                                        else
                   3732:                                        {
                   3733:                                                parse_event(parse, CEVNT_BADREPLY); /* for the lack of something better */
                   3734:                                        }
                   3735:                }
                   3736:                return;                 /* skip the rest - useless */
                   3737:        }
                   3738: 
                   3739:        /*
                   3740:         * check for format changes
                   3741:         * (in case somebody has swapped clocks 8-)
                   3742:         */
                   3743:        if (parse->lastformat != parsetime->parse_format)
                   3744:        {
                   3745:                parsectl_t tmpctl;
                   3746:        
                   3747:                tmpctl.parseformat.parse_format = parsetime->parse_format;
                   3748: 
                   3749:                if (!PARSE_GETFMT(parse, &tmpctl))
                   3750:                {
                   3751:                        ERR(ERR_INTERNAL)
                   3752:                                msyslog(LOG_ERR, "PARSE receiver #%d: parse_getfmt() FAILED", CLK_UNIT(parse->peer));
                   3753:                }
                   3754:                else
                   3755:                {
                   3756:                        NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */
                   3757:                                msyslog(LOG_INFO, "PARSE receiver #%d: packet format \"%s\"",
                   3758:                                        CLK_UNIT(parse->peer), tmpctl.parseformat.parse_buffer);
                   3759:                }
                   3760:                parse->lastformat = parsetime->parse_format;
                   3761:        }
                   3762: 
                   3763:        /*
                   3764:         * now, any changes ?
                   3765:         */
                   3766:        if ((parse->timedata.parse_state ^ parsetime->parse_state) &
                   3767:            ~(unsigned)(PARSEB_PPS|PARSEB_S_PPS))
                   3768:        {
                   3769:                char tmp1[200];
                   3770:                char tmp2[200];
                   3771:                /*
                   3772:                 * something happend - except for PPS events
                   3773:                 */
                   3774:        
                   3775:                (void) parsestate(parsetime->parse_state, tmp1, sizeof(tmp1));
                   3776:                (void) parsestate(parse->timedata.parse_state, tmp2, sizeof(tmp2));
                   3777:        
                   3778:                NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */
                   3779:                        msyslog(LOG_INFO,"PARSE receiver #%d: STATE CHANGE: %s -> %s",
                   3780:                                CLK_UNIT(parse->peer), tmp2, tmp1);
                   3781:        }
                   3782: 
                   3783:        /*
                   3784:         * carry on PPS information if still usable
                   3785:         */
                   3786:        if (PARSE_PPS(parse->timedata.parse_state) && !PARSE_PPS(parsetime->parse_state))
                   3787:         {
                   3788:                parsetime->parse_state |= PARSEB_PPS|PARSEB_S_PPS;
                   3789:                parsetime->parse_ptime  = parse->timedata.parse_ptime;
                   3790:        }
                   3791: 
                   3792:        /*
                   3793:         * remember for future
                   3794:         */
                   3795:        parse->timedata = *parsetime;
                   3796: 
                   3797:        /*
                   3798:         * check to see, whether the clock did a complete powerup or lost PZF signal
                   3799:         * and post correct events for current condition
                   3800:         */
                   3801:        if (PARSE_POWERUP(parsetime->parse_state))
                   3802:        {
                   3803:                /*
                   3804:                 * this is bad, as we have completely lost synchronisation
                   3805:                 * well this is a problem with the receiver here
                   3806:                 * for PARSE Meinberg DCF77 receivers the lost synchronisation
                   3807:                 * is true as it is the powerup state and the time is taken
                   3808:                 * from a crude real time clock chip
                   3809:                 * for the PZF/GPS series this is only partly true, as
                   3810:                 * PARSE_POWERUP only means that the pseudo random
                   3811:                 * phase shift sequence cannot be found. this is only
                   3812:                 * bad, if we have never seen the clock in the SYNC
                   3813:                 * state, where the PHASE and EPOCH are correct.
                   3814:                 * for reporting events the above business does not
                   3815:                 * really matter, but we can use the time code
                   3816:                 * even in the POWERUP state after having seen
                   3817:                 * the clock in the synchronized state (PZF class
                   3818:                 * receivers) unless we have had a telegram disruption
                   3819:                 * after having seen the clock in the SYNC state. we
                   3820:                 * thus require having seen the clock in SYNC state
                   3821:                 * *after* having missed telegrams (noresponse) from
                   3822:                 * the clock. one problem remains: we might use erroneously
                   3823:                 * POWERUP data if the disruption is shorter than 1 polling
                   3824:                 * interval. fortunately powerdowns last usually longer than 64
                   3825:                 * seconds and the receiver is at least 2 minutes in the
                   3826:                 * POWERUP or NOSYNC state before switching to SYNC
                   3827:                 * for GPS receivers this can mean antenna problems and other causes.
                   3828:                 * the additional grace period can be enables by a clock
                   3829:                 * mode having the PARSE_F_POWERUPTRUST flag in cl_flag set.
                   3830:                 */
                   3831:                parse_event(parse, CEVNT_FAULT);
                   3832:                NLOG(NLOG_CLOCKSTATUS)
                   3833:                        ERR(ERR_BADSTATUS)
                   3834:                        msyslog(LOG_ERR,"PARSE receiver #%d: NOT SYNCHRONIZED/RECEIVER PROBLEMS",
                   3835:                                CLK_UNIT(parse->peer));
                   3836:        }
                   3837:        else
                   3838:        {
                   3839:                /*
                   3840:                 * we have two states left
                   3841:                 *
                   3842:                 * SYNC:
                   3843:                 *  this state means that the EPOCH (timecode) and PHASE
                   3844:                 *  information has be read correctly (at least two
                   3845:                 *  successive PARSE timecodes were received correctly)
                   3846:                 *  this is the best possible state - full trust
                   3847:                 *
                   3848:                 * NOSYNC:
                   3849:                 *  The clock should be on phase with respect to the second
                   3850:                 *  signal, but the timecode has not been received correctly within
                   3851:                 *  at least the last two minutes. this is a sort of half baked state
                   3852:                 *  for PARSE Meinberg DCF77 clocks this is bad news (clock running
                   3853:                 *  without timecode confirmation)
                   3854:                 *  PZF 535 has also no time confirmation, but the phase should be
                   3855:                 *  very precise as the PZF signal can be decoded
                   3856:                 */
                   3857: 
                   3858:                if (PARSE_SYNC(parsetime->parse_state))
                   3859:                {
                   3860:                        /*
                   3861:                         * currently completely synchronized - best possible state
                   3862:                         */
                   3863:                        parse->lastsync = current_time;
                   3864:                        clear_err(parse, ERR_BADSTATUS);
                   3865:                }
                   3866:                else
                   3867:                {
                   3868:                        /*
                   3869:                         * we have had some problems receiving the time code
                   3870:                         */
                   3871:                        parse_event(parse, CEVNT_PROP);
                   3872:                        NLOG(NLOG_CLOCKSTATUS)
                   3873:                                ERR(ERR_BADSTATUS)
                   3874:                                msyslog(LOG_ERR,"PARSE receiver #%d: TIMECODE NOT CONFIRMED",
                   3875:                                        CLK_UNIT(parse->peer));
                   3876:                }
                   3877:        }
                   3878: 
                   3879:        fudge = parse->generic->fudgetime1; /* standard RS232 Fudgefactor */
                   3880:        
                   3881:        if (PARSE_TIMECODE(parsetime->parse_state))
                   3882:        {
                   3883:                rectime = parsetime->parse_stime.fp;
                   3884:                off = reftime = parsetime->parse_time.fp;
                   3885:        
                   3886:                L_SUB(&off, &rectime); /* prepare for PPS adjustments logic */
                   3887: 
                   3888: #ifdef DEBUG
                   3889:                if (debug > 3)
                   3890:                        printf("PARSE receiver #%d: Reftime %s, Recvtime %s - initial offset %s\n",
                   3891:                               CLK_UNIT(parse->peer),
                   3892:                               prettydate(&reftime),
                   3893:                               prettydate(&rectime),
                   3894:                               lfptoa(&off,6));
                   3895: #endif
                   3896:        }
                   3897: 
                   3898:        if (PARSE_PPS(parsetime->parse_state) && CLK_PPS(parse->peer))
                   3899:        {
                   3900:                l_fp offset;
                   3901:                double ppsphaseadjust = parse->ppsphaseadjust;
                   3902: 
                   3903: #ifdef HAVE_PPSAPI
                   3904:                /*
                   3905:                 * set fudge = 0.0 if already included in PPS time stamps
                   3906:                 */
                   3907:                if (parse->atom.pps_params.mode & (PPS_OFFSETCLEAR|PPS_OFFSETASSERT))
                   3908:                        {
                   3909:                                ppsphaseadjust = 0.0;
                   3910:                        }
                   3911: #endif
                   3912: 
                   3913:                /*
                   3914:                 * we have a PPS signal - much better than the RS232 stuff (we hope)
                   3915:                 */
                   3916:                offset = parsetime->parse_ptime.fp;
                   3917: 
                   3918: #ifdef DEBUG
                   3919:                if (debug > 3)
                   3920:                        printf("PARSE receiver #%d: PPStime %s\n",
                   3921:                                CLK_UNIT(parse->peer),
                   3922:                                prettydate(&offset));
                   3923: #endif
                   3924:                if (PARSE_TIMECODE(parsetime->parse_state))
                   3925:                {
                   3926:                        if (M_ISGEQ(off.l_i, off.l_f, -1, 0x80000000) &&
                   3927:                            M_ISGEQ(0, 0x7fffffff, off.l_i, off.l_f))
                   3928:                        {
                   3929:                                fudge = ppsphaseadjust; /* pick PPS fudge factor */
                   3930:                        
                   3931:                                /*
                   3932:                                 * RS232 offsets within [-0.5..0.5[ - take PPS offsets
                   3933:                                 */
                   3934: 
                   3935:                                if (parse->parse_type->cl_flags & PARSE_F_PPSONSECOND)
                   3936:                                {
                   3937:                                        reftime = off = offset;
                   3938:                                        if (reftime.l_uf & (unsigned)0x80000000)
                   3939:                                                reftime.l_ui++;
                   3940:                                        reftime.l_uf = 0;
                   3941: 
                   3942:                                        
                   3943:                                        /*
                   3944:                                         * implied on second offset
                   3945:                                         */
                   3946:                                        off.l_uf = ~off.l_uf; /* map [0.5..1[ -> [-0.5..0[ */
                   3947:                                        off.l_ui = (off.l_f < 0) ? ~0 : 0; /* sign extend */
                   3948:                                }
                   3949:                                else
                   3950:                                {
                   3951:                                        /*
                   3952:                                         * time code describes pulse
                   3953:                                         */
                   3954:                                        reftime = off = parsetime->parse_time.fp;
                   3955: 
                   3956:                                        L_SUB(&off, &offset); /* true offset */
                   3957:                                }
                   3958:                        }
                   3959:                        /*
                   3960:                         * take RS232 offset when PPS when out of bounds
                   3961:                         */
                   3962:                }
                   3963:                else
                   3964:                {
                   3965:                        fudge = ppsphaseadjust; /* pick PPS fudge factor */
                   3966:                        /*
                   3967:                         * Well, no time code to guide us - assume on second pulse
                   3968:                         * and pray, that we are within [-0.5..0.5[
                   3969:                         */
                   3970:                        off = offset;
                   3971:                        reftime = offset;
                   3972:                        if (reftime.l_uf & (unsigned)0x80000000)
                   3973:                                reftime.l_ui++;
                   3974:                        reftime.l_uf = 0;
                   3975:                        /*
                   3976:                         * implied on second offset
                   3977:                         */
                   3978:                        off.l_uf = ~off.l_uf; /* map [0.5..1[ -> [-0.5..0[ */
                   3979:                        off.l_ui = (off.l_f < 0) ? ~0 : 0; /* sign extend */
                   3980:                }
                   3981:        }
                   3982:        else
                   3983:        {
                   3984:                if (!PARSE_TIMECODE(parsetime->parse_state))
                   3985:                {
                   3986:                        /*
                   3987:                         * Well, no PPS, no TIMECODE, no more work ...
                   3988:                         */
                   3989:                        if ((parsetime->parse_status & CVT_ADDITIONAL) &&
                   3990:                            parse->parse_type->cl_message)
                   3991:                                parse->parse_type->cl_message(parse, parsetime);
                   3992:                        return;
                   3993:                }
                   3994:        }
                   3995: 
                   3996: #ifdef DEBUG
                   3997:        if (debug > 3)
                   3998:                printf("PARSE receiver #%d: Reftime %s, Recvtime %s - final offset %s\n",
                   3999:                        CLK_UNIT(parse->peer),
                   4000:                        prettydate(&reftime),
                   4001:                        prettydate(&rectime),
                   4002:                        lfptoa(&off,6));
                   4003: #endif
                   4004: 
                   4005: 
                   4006:        rectime = reftime;
                   4007:        L_SUB(&rectime, &off);  /* just to keep the ntp interface happy */
                   4008:        
                   4009: #ifdef DEBUG
                   4010:        if (debug > 3)
                   4011:                printf("PARSE receiver #%d: calculated Reftime %s, Recvtime %s\n",
                   4012:                        CLK_UNIT(parse->peer),
                   4013:                        prettydate(&reftime),
                   4014:                        prettydate(&rectime));
                   4015: #endif
                   4016: 
                   4017:        if ((parsetime->parse_status & CVT_ADDITIONAL) &&
                   4018:            parse->parse_type->cl_message)
                   4019:                parse->parse_type->cl_message(parse, parsetime);
                   4020: 
                   4021:        if (PARSE_SYNC(parsetime->parse_state))
                   4022:        {
                   4023:                /*
                   4024:                 * log OK status
                   4025:                 */
                   4026:                parse_event(parse, CEVNT_NOMINAL);
                   4027:        }
                   4028: 
                   4029:        clear_err(parse, ERR_BADIO);
                   4030:        clear_err(parse, ERR_BADDATA);
                   4031:        clear_err(parse, ERR_NODATA);
                   4032:        clear_err(parse, ERR_INTERNAL);
                   4033:   
                   4034:        /*
                   4035:         * and now stick it into the clock machine
                   4036:         * samples are only valid iff lastsync is not too old and
                   4037:         * we have seen the clock in sync at least once
                   4038:         * after the last time we didn't see an expected data telegram
                   4039:         * at startup being not in sync is also bad just like
                   4040:         * POWERUP state unless PARSE_F_POWERUPTRUST is set 
                   4041:         * see the clock states section above for more reasoning
                   4042:         */
                   4043:        if (((current_time - parse->lastsync) > parse->maxunsync)           ||
                   4044:            (parse->lastsync < parse->lastmissed)                           ||
                   4045:            ((parse->lastsync == 0) && !PARSE_SYNC(parsetime->parse_state)) ||
                   4046:            (((parse->parse_type->cl_flags & PARSE_F_POWERUPTRUST) == 0) &&
                   4047:             PARSE_POWERUP(parsetime->parse_state)))
                   4048:        {
                   4049:                parse->generic->leap = LEAP_NOTINSYNC;
                   4050:                parse->lastsync = 0;    /* wait for full sync again */
                   4051:        }
                   4052:        else
                   4053:        {
                   4054:                if (PARSE_LEAPADD(parsetime->parse_state))
                   4055:                {
                   4056:                        /*
                   4057:                         * we pick this state also for time code that pass leap warnings
                   4058:                         * without direction information (as earth is currently slowing
                   4059:                         * down).
                   4060:                         */
                   4061:                        parse->generic->leap = (parse->flags & PARSE_LEAP_DELETE) ? LEAP_DELSECOND : LEAP_ADDSECOND;
                   4062:                }
                   4063:                else
                   4064:                    if (PARSE_LEAPDEL(parsetime->parse_state))
                   4065:                    {
                   4066:                            parse->generic->leap = LEAP_DELSECOND;
                   4067:                    }
                   4068:                    else
                   4069:                    {
                   4070:                            parse->generic->leap = LEAP_NOWARNING;
                   4071:                    }
                   4072:        }
                   4073: 
                   4074:        if (parse->generic->leap != LEAP_NOTINSYNC)
                   4075:        {
                   4076:                /*
                   4077:                 * only good/trusted samples are interesting
                   4078:                 */
                   4079: #ifdef DEBUG
                   4080:                if (debug > 2) 
                   4081:                        {
                   4082:                                printf("PARSE receiver #%d: refclock_process_offset(reftime=%s, rectime=%s, Fudge=%f)\n",
                   4083:                                       CLK_UNIT(parse->peer),
                   4084:                                       prettydate(&reftime),
                   4085:                                       prettydate(&rectime),
                   4086:                                       fudge);
                   4087:                        }
                   4088: #endif
                   4089:                parse->generic->lastref = reftime;
                   4090:                
                   4091:                refclock_process_offset(parse->generic, reftime, rectime, fudge);
                   4092: 
                   4093: #ifdef HAVE_PPSAPI
                   4094:                /*
                   4095:                 * pass PPS information on to PPS clock
                   4096:                 */
                   4097:                if (PARSE_PPS(parsetime->parse_state) && CLK_PPS(parse->peer))
                   4098:                        {
                   4099:                          /* refclock_pps includes fudgetime1 - we keep the RS232 offset in there :-( */
                   4100:                                double savedtime1 = parse->generic->fudgetime1;
                   4101: 
                   4102:                                parse->generic->fudgetime1 = fudge;
                   4103:                                
                   4104:                                if (refclock_pps(parse->peer, &parse->atom,
                   4105:                                                 parse->flags & (CLK_FLAG1|CLK_FLAG2|CLK_FLAG3|CLK_FLAG4))) {
                   4106:                                        parse->peer->flags |= FLAG_PPS;
                   4107:                                } else {
                   4108:                                        parse->peer->flags &= ~FLAG_PPS;
                   4109:                                }
                   4110: 
                   4111:                                parse->generic->fudgetime1 = savedtime1;
                   4112: 
                   4113:                                parse_hardpps(parse, PARSE_HARDPPS_ENABLE);
                   4114:                        }
                   4115: #endif
                   4116:        } else {
                   4117:                parse_hardpps(parse, PARSE_HARDPPS_DISABLE);
                   4118:                parse->peer->flags &= ~FLAG_PPS;
                   4119:        }
                   4120: 
                   4121:        /*
                   4122:         * ready, unless the machine wants a sample or 
                   4123:         * we are in fast startup mode (peer->dist > MAXDISTANCE)
                   4124:         */
                   4125:        if (!parse->pollneeddata && parse->peer->disp <= MAXDISTANCE)
                   4126:            return;
                   4127: 
                   4128:        parse->pollneeddata = 0;
                   4129: 
                   4130:        parse->timedata.parse_state &= ~(unsigned)(PARSEB_PPS|PARSEB_S_PPS);
                   4131: 
                   4132:        refclock_receive(parse->peer);
                   4133: }
                   4134: 
                   4135: /**===========================================================================
                   4136:  ** special code for special clocks
                   4137:  **/
                   4138: 
                   4139: static void
                   4140: mk_utcinfo(
                   4141:           char *t,
                   4142:           int wnt,
                   4143:           int wnlsf,
                   4144:           int dn,
                   4145:           int dtls,
                   4146:           int dtlsf,
                   4147:           int size
                   4148:           )
                   4149: {
                   4150:   l_fp leapdate;
                   4151:   char *start = t;
                   4152:   
                   4153:   snprintf(t, size, "current correction %d sec", dtls);
                   4154:   t += strlen(t);
                   4155:   
                   4156:   if (wnlsf < 990)
                   4157:     wnlsf += 1024;
                   4158:   
                   4159:   if (wnt < 990)
                   4160:     wnt += 1024;
                   4161:   
                   4162:   gpstolfp((unsigned short)wnlsf, (unsigned short)dn, 0, &leapdate);
                   4163:   
                   4164:   if ((dtlsf != dtls) &&
                   4165:       ((wnlsf - wnt) < 52))
                   4166:     {
                   4167:            snprintf(t, BUFFER_SIZES(start, t, size), ", next correction %d sec on %s, new GPS-UTC offset %d",
                   4168:              dtlsf - dtls, gmprettydate(&leapdate), dtlsf);
                   4169:     }
                   4170:   else
                   4171:     {
                   4172:            snprintf(t, BUFFER_SIZES(start, t, size), ", last correction on %s",
                   4173:              gmprettydate(&leapdate));
                   4174:     }
                   4175: }
                   4176: 
                   4177: #ifdef CLOCK_MEINBERG
                   4178: /**===========================================================================
                   4179:  ** Meinberg GPS166/GPS167 support
                   4180:  **/
                   4181: 
                   4182: /*------------------------------------------------------------
                   4183:  * gps16x_message - process GPS16x messages
                   4184:  */
                   4185: static void
                   4186: gps16x_message(
                   4187:               struct parseunit *parse,
                   4188:               parsetime_t      *parsetime
                   4189:               )
                   4190: {
                   4191:        if (parse->timedata.parse_msglen && parsetime->parse_msg[0] == SOH)
                   4192:        {
                   4193:                GPS_MSG_HDR header;
                   4194:                unsigned char *bufp = (unsigned char *)parsetime->parse_msg + 1;
                   4195:                
                   4196: #ifdef DEBUG
                   4197:                if (debug > 2)
                   4198:                {
                   4199:                        char msgbuffer[600];
                   4200:                        
                   4201:                        mkreadable(msgbuffer, sizeof(msgbuffer), (char *)parsetime->parse_msg, parsetime->parse_msglen, 1);
                   4202:                        printf("PARSE receiver #%d: received message (%d bytes) >%s<\n",
                   4203:                                CLK_UNIT(parse->peer),
                   4204:                                parsetime->parse_msglen,
                   4205:                                msgbuffer);
                   4206:                }
                   4207: #endif
                   4208:                get_mbg_header(&bufp, &header);
                   4209:                if (header.gps_hdr_csum == mbg_csum(parsetime->parse_msg + 1, 6) &&
                   4210:                    (header.gps_len == 0 ||
                   4211:                     (header.gps_len < sizeof(parsetime->parse_msg) &&
                   4212:                      header.gps_data_csum == mbg_csum(bufp, header.gps_len))))
                   4213:                {
                   4214:                        /*
                   4215:                         * clean message
                   4216:                         */
                   4217:                        switch (header.gps_cmd)
                   4218:                        {
                   4219:                        case GPS_SW_REV:
                   4220:                                {
                   4221:                                        char buffer[64];
                   4222:                                        SW_REV gps_sw_rev;
                   4223:                                        
                   4224:                                        get_mbg_sw_rev(&bufp, &gps_sw_rev);
                   4225:                                        snprintf(buffer, sizeof(buffer), "meinberg_gps_version=\"%x.%02x%s%s\"",
                   4226:                                                (gps_sw_rev.code >> 8) & 0xFF,
                   4227:                                                gps_sw_rev.code & 0xFF,
                   4228:                                                gps_sw_rev.name[0] ? " " : "",
                   4229:                                                gps_sw_rev.name);
                   4230:                                        set_var(&parse->kv, buffer, strlen(buffer)+1, RO|DEF);
                   4231:                                }
                   4232:                        break;
                   4233: 
                   4234:                        case GPS_STAT:
                   4235:                                {
                   4236:                                        static struct state
                   4237:                                        {
                   4238:                                                unsigned short flag; /* status flag */
                   4239:                                                unsigned const char *string; /* bit name */
                   4240:                                        } states[] =
                   4241:                                          {
                   4242:                                                  { TM_ANT_DISCONN, (const unsigned char *)"ANTENNA FAULTY" },
                   4243:                                                  { TM_SYN_FLAG,    (const unsigned char *)"NO SYNC SIGNAL" },
                   4244:                                                  { TM_NO_SYNC,     (const unsigned char *)"NO SYNC POWERUP" },
                   4245:                                                  { TM_NO_POS,      (const unsigned char *)"NO POSITION" },
                   4246:                                                  { 0, (const unsigned char *)"" }
                   4247:                                          };
                   4248:                                        unsigned short status;
                   4249:                                        struct state *s = states;
                   4250:                                        char buffer[512];
                   4251:                                        char *p, *b;
                   4252:                                        
                   4253:                                        status = get_lsb_short(&bufp);
                   4254:                                        snprintf(buffer, sizeof(buffer), "meinberg_gps_status=\"[0x%04x] ", status);
                   4255:                                        
                   4256:                                        if (status)
                   4257:                                        {
                   4258:                                                p = b = buffer + strlen(buffer);
                   4259:                                                while (s->flag)
                   4260:                                                {
                   4261:                                                        if (status & s->flag)
                   4262:                                                        {
                   4263:                                                                if (p != b)
                   4264:                                                                {
                   4265:                                                                        *p++ = ',';
                   4266:                                                                        *p++ = ' ';
                   4267:                                                                }
                   4268:                                                                
                   4269:                                                                strncat(p, (const char *)s->string, sizeof(buffer));
                   4270:                                                        }
                   4271:                                                        s++;
                   4272:                                                }
                   4273:                
                   4274:                                                *p++ = '"';
                   4275:                                                *p   = '\0';
                   4276:                                        }
                   4277:                                        else
                   4278:                                        {
                   4279:                                                strncat(buffer, "<OK>\"", sizeof(buffer));
                   4280:                                        }
                   4281:                
                   4282:                                        set_var(&parse->kv, buffer, strlen(buffer)+1, RO|DEF);
                   4283:                                }
                   4284:                        break;
                   4285: 
                   4286:                        case GPS_POS_XYZ:
                   4287:                                {
                   4288:                                        XYZ xyz;
                   4289:                                        char buffer[256];
                   4290:                                        
                   4291:                                        get_mbg_xyz(&bufp, xyz);
                   4292:                                        snprintf(buffer, sizeof(buffer), "gps_position(XYZ)=\"%s m, %s m, %s m\"",
                   4293:                                                mfptoa(xyz[XP].l_ui, xyz[XP].l_uf, 1),
                   4294:                                                mfptoa(xyz[YP].l_ui, xyz[YP].l_uf, 1),
                   4295:                                                mfptoa(xyz[ZP].l_ui, xyz[ZP].l_uf, 1));
                   4296:                                        
                   4297:                                        set_var(&parse->kv, buffer, sizeof(buffer), RO|DEF);
                   4298:                                }
                   4299:                        break;
                   4300:              
                   4301:                        case GPS_POS_LLA:
                   4302:                                {
                   4303:                                        LLA lla;
                   4304:                                        char buffer[256];
                   4305:                                        
                   4306:                                        get_mbg_lla(&bufp, lla);
                   4307:                                        
                   4308:                                        snprintf(buffer, sizeof(buffer), "gps_position(LLA)=\"%s deg, %s deg, %s m\"",
                   4309:                                                mfptoa(lla[LAT].l_ui, lla[LAT].l_uf, 4),
                   4310:                                                mfptoa(lla[LON].l_ui, lla[LON].l_uf, 4), 
                   4311:                                                mfptoa(lla[ALT].l_ui, lla[ALT].l_uf, 1));
                   4312:                                        
                   4313:                                        set_var(&parse->kv, buffer, sizeof(buffer), RO|DEF);
                   4314:                                }
                   4315:                        break;
                   4316:              
                   4317:                        case GPS_TZDL:
                   4318:                                break;
                   4319:              
                   4320:                        case GPS_PORT_PARM:
                   4321:                                break;
                   4322:              
                   4323:                        case GPS_SYNTH:
                   4324:                                break;
                   4325:                                
                   4326:                        case GPS_ANT_INFO:
                   4327:                                {
                   4328:                                        ANT_INFO antinfo;
                   4329:                                        char buffer[512];
                   4330:                                        char *p;
                   4331:                                        
                   4332:                                        get_mbg_antinfo(&bufp, &antinfo);
                   4333:                                        snprintf(buffer, sizeof(buffer), "meinberg_antenna_status=\"");
                   4334:                                        p = buffer + strlen(buffer);
                   4335:                                        
                   4336:                                        switch (antinfo.status)
                   4337:                                        {
                   4338:                                        case ANT_INVALID:
                   4339:                                                strncat(p, "<OK>", BUFFER_SIZE(buffer, p));
                   4340:                                                p += strlen(p);
                   4341:                                                break;
                   4342:                                                
                   4343:                                        case ANT_DISCONN:
                   4344:                                                strncat(p, "DISCONNECTED since ", BUFFER_SIZE(buffer, p));
                   4345:                                                NLOG(NLOG_CLOCKSTATUS)
                   4346:                                                        ERR(ERR_BADSTATUS)
                   4347:                                                        msyslog(LOG_ERR,"PARSE receiver #%d: ANTENNA FAILURE: %s",
                   4348:                                                                CLK_UNIT(parse->peer), p);
                   4349:                                                
                   4350:                                                p += strlen(p);
                   4351:                                                mbg_tm_str(&p, &antinfo.tm_disconn, BUFFER_SIZE(buffer, p));
                   4352:                                                *p = '\0';
                   4353:                                                break;
                   4354:                    
                   4355:                                        case ANT_RECONN:
                   4356:                                                strncat(p, "RECONNECTED on ", BUFFER_SIZE(buffer, p));
                   4357:                                                p += strlen(p);
                   4358:                                                mbg_tm_str(&p, &antinfo.tm_reconn, BUFFER_SIZE(buffer, p));
                   4359:                                                snprintf(p, BUFFER_SIZE(buffer, p), ", reconnect clockoffset %c%ld.%07ld s, disconnect time ",
                   4360:                                                        (antinfo.delta_t < 0) ? '-' : '+',
                   4361:                                                        ABS(antinfo.delta_t) / 10000,
                   4362:                                                        ABS(antinfo.delta_t) % 10000);
                   4363:                                                p += strlen(p);
                   4364:                                                mbg_tm_str(&p, &antinfo.tm_disconn, BUFFER_SIZE(buffer, p));
                   4365:                                                *p = '\0';
                   4366:                                                break;
                   4367:                    
                   4368:                                        default:
                   4369:                                                snprintf(p, BUFFER_SIZE(buffer, p), "bad status 0x%04x", antinfo.status);
                   4370:                                                p += strlen(p);
                   4371:                                                break;
                   4372:                                        }
                   4373:                                        
                   4374:                                        strncat(p, "\"", BUFFER_SIZE(buffer, p));
                   4375:                                        
                   4376:                                        set_var(&parse->kv, buffer, strlen(buffer)+1, RO|DEF);
                   4377:                                }
                   4378:                        break;
                   4379:              
                   4380:                        case GPS_UCAP:
                   4381:                                break;
                   4382:                                
                   4383:                        case GPS_CFGH:
                   4384:                                {
                   4385:                                        CFGH cfgh;
                   4386:                                        char buffer[512];
                   4387:                                        char *p;
                   4388:                                        
                   4389:                                        get_mbg_cfgh(&bufp, &cfgh);
                   4390:                                        if (cfgh.valid)
                   4391:                                        {
                   4392:                                                int i;
                   4393:                                                
                   4394:                                                p = buffer;
                   4395:                                                strncpy(buffer, "gps_tot_51=\"", BUFFER_SIZE(buffer, p));
                   4396:                                                p += strlen(p);
                   4397:                                                mbg_tgps_str(&p, &cfgh.tot_51, BUFFER_SIZE(buffer, p));
                   4398:                                                strncpy(p, "\"", BUFFER_SIZE(buffer, p));
                   4399:                                                set_var(&parse->kv, buffer, strlen(buffer)+1, RO);
                   4400:                                                
                   4401:                                                p = buffer;
                   4402:                                                strncpy(buffer, "gps_tot_63=\"", BUFFER_SIZE(buffer, p));
                   4403:                                                p += strlen(p);
                   4404:                                                mbg_tgps_str(&p, &cfgh.tot_63, BUFFER_SIZE(buffer, p));
                   4405:                                                strncpy(p, "\"", BUFFER_SIZE(buffer, p));
                   4406:                                                set_var(&parse->kv, buffer, strlen(buffer)+1, RO);
                   4407:                                                
                   4408:                                                p = buffer;
                   4409:                                                strncpy(buffer, "gps_t0a=\"", BUFFER_SIZE(buffer, p));
                   4410:                                                p += strlen(p);
                   4411:                                                mbg_tgps_str(&p, &cfgh.t0a, BUFFER_SIZE(buffer, p));
                   4412:                                                strncpy(p, "\"", BUFFER_SIZE(buffer, p));
                   4413:                                                set_var(&parse->kv, buffer, strlen(buffer)+1, RO);
                   4414:                                                
                   4415:                                                for (i = MIN_SVNO; i < MAX_SVNO; i++)
                   4416:                                                {
                   4417:                                                        p = buffer;
                   4418:                                                        snprintf(p, BUFFER_SIZE(buffer, p), "gps_cfg[%d]=\"[0x%x] ", i, cfgh.cfg[i]);
                   4419:                                                        p += strlen(p);
                   4420:                                                        switch (cfgh.cfg[i] & 0x7)
                   4421:                                                        {
                   4422:                                                        case 0:
                   4423:                                                                strncpy(p, "BLOCK I", BUFFER_SIZE(buffer, p));
                   4424:                                                                break;
                   4425:                                                        case 1:
                   4426:                                                                strncpy(p, "BLOCK II", BUFFER_SIZE(buffer, p));
                   4427:                                                                break;
                   4428:                                                        default:
                   4429:                                                                strncpy(p, "bad CFG", BUFFER_SIZE(buffer, p));
                   4430:                                                                break;
                   4431:                                                        }
                   4432:                                                        strncat(p, "\"", BUFFER_SIZE(buffer, p));
                   4433:                                                        set_var(&parse->kv, buffer, strlen(buffer)+1, RO);
                   4434:                                                        
                   4435:                                                        p = buffer;
                   4436:                                                        snprintf(p, BUFFER_SIZE(buffer, p), "gps_health[%d]=\"[0x%x] ", i, cfgh.health[i]);
                   4437:                                                        p += strlen(p);
                   4438:                                                        switch ((cfgh.health[i] >> 5) & 0x7 )
                   4439:                                                        {
                   4440:                                                        case 0:
                   4441:                                                                strncpy(p, "OK;", BUFFER_SIZE(buffer, p));
                   4442:                                                                break;
                   4443:                                                        case 1:
                   4444:                                                                strncpy(p, "PARITY;", BUFFER_SIZE(buffer, p));
                   4445:                                                                break;
                   4446:                                                        case 2:
                   4447:                                                                strncpy(p, "TLM/HOW;", BUFFER_SIZE(buffer, p));
                   4448:                                                                break;
                   4449:                                                        case 3:
                   4450:                                                                strncpy(p, "Z-COUNT;", BUFFER_SIZE(buffer, p));
                   4451:                                                                break;
                   4452:                                                        case 4:
                   4453:                                                                strncpy(p, "SUBFRAME 1,2,3;", BUFFER_SIZE(buffer, p));
                   4454:                                                                break;
                   4455:                                                        case 5:
                   4456:                                                                strncpy(p, "SUBFRAME 4,5;", BUFFER_SIZE(buffer, p));
                   4457:                                                                break;
                   4458:                                                        case 6:
                   4459:                                                                strncpy(p, "UPLOAD BAD;", BUFFER_SIZE(buffer, p));
                   4460:                                                                break;
                   4461:                                                        case 7:
                   4462:                                                                strncpy(p, "DATA BAD;", BUFFER_SIZE(buffer, p));
                   4463:                                                                break;
                   4464:                                                        }
                   4465:                                                        
                   4466:                                                        p += strlen(p);
                   4467:                                                        
                   4468:                                                        switch (cfgh.health[i] & 0x1F)
                   4469:                                                        {
                   4470:                                                        case 0:
                   4471:                                                                strncpy(p, "SIGNAL OK", BUFFER_SIZE(buffer, p));
                   4472:                                                                break;
                   4473:                                                        case 0x1C:
                   4474:                                                                strncpy(p, "SV TEMP OUT", BUFFER_SIZE(buffer, p));
                   4475:                                                                break;
                   4476:                                                        case 0x1D:
                   4477:                                                                strncpy(p, "SV WILL BE TEMP OUT", BUFFER_SIZE(buffer, p));
                   4478:                                                                break;
                   4479:                                                        case 0x1E:
                   4480:                                                                break;
                   4481:                                                        case 0x1F:
                   4482:                                                                strncpy(p, "MULTIPLE ERRS", BUFFER_SIZE(buffer, p));
                   4483:                                                                break;
                   4484:                                                        default:
                   4485:                                                                strncpy(p, "TRANSMISSION PROBLEMS", BUFFER_SIZE(buffer, p));
                   4486:                                                                break;
                   4487:                                                        }
                   4488:                                                        
                   4489:                                                        strncat(p, "\"", sizeof(buffer));
                   4490:                                                        set_var(&parse->kv, buffer, strlen(buffer)+1, RO);
                   4491:                                                }
                   4492:                                        }
                   4493:                                }
                   4494:                        break;
                   4495:              
                   4496:                        case GPS_ALM:
                   4497:                                break;
                   4498:                                
                   4499:                        case GPS_EPH:
                   4500:                                break;
                   4501:                                
                   4502:                        case GPS_UTC:
                   4503:                                {
                   4504:                                        UTC utc;
                   4505:                                        char buffer[512];
                   4506:                                        char *p;
                   4507:                                        
                   4508:                                        p = buffer;
                   4509:                                        
                   4510:                                        get_mbg_utc(&bufp, &utc);
                   4511:                                        
                   4512:                                        if (utc.valid)
                   4513:                                        {
                   4514:                                                strncpy(p, "gps_utc_correction=\"", sizeof(buffer));
                   4515:                                                p += strlen(p);
                   4516:                                                mk_utcinfo(p, utc.t0t.wn, utc.WNlsf, utc.DNt, utc.delta_tls, utc.delta_tlsf, BUFFER_SIZE(buffer, p));
                   4517:                                                strncat(p, "\"", BUFFER_SIZE(buffer, p));
                   4518:                                        }
                   4519:                                        else
                   4520:                                        {
                   4521:                                                strncpy(p, "gps_utc_correction=\"<NO UTC DATA>\"", BUFFER_SIZE(buffer, p));
                   4522:                                        }
                   4523:                                        set_var(&parse->kv, buffer, strlen(buffer)+1, RO|DEF);
                   4524:                                }
                   4525:                        break;
                   4526:                        
                   4527:                        case GPS_IONO:
                   4528:                                break;
                   4529:                                
                   4530:                        case GPS_ASCII_MSG:
                   4531:                                {
                   4532:                                        ASCII_MSG gps_ascii_msg;
                   4533:                                        char buffer[128];
                   4534:                
                   4535:                                        get_mbg_ascii_msg(&bufp, &gps_ascii_msg);
                   4536:                                        
                   4537:                                        if (gps_ascii_msg.valid)
                   4538:                                                {
                   4539:                                                        char buffer1[128];
                   4540:                                                        mkreadable(buffer1, sizeof(buffer1), gps_ascii_msg.s, strlen(gps_ascii_msg.s), (int)0);
                   4541:                                                        
                   4542:                                                        snprintf(buffer, sizeof(buffer), "gps_message=\"%s\"", buffer1);
                   4543:                                                }
                   4544:                                        else
                   4545:                                                strncpy(buffer, "gps_message=<NONE>", sizeof(buffer));
                   4546:                                        
                   4547:                                        set_var(&parse->kv, buffer, strlen(buffer)+1, RO|DEF);
                   4548:                                }
                   4549:                        
                   4550:                        break;
                   4551:              
                   4552:                        default:
                   4553:                                break;
                   4554:                        }
                   4555:                }
                   4556:                else
                   4557:                {
                   4558:                        msyslog(LOG_DEBUG, "PARSE receiver #%d: gps16x_message: message checksum error: hdr_csum = 0x%x (expected 0x%lx), data_len = %d, data_csum = 0x%x (expected 0x%lx)",
                   4559:                                CLK_UNIT(parse->peer),
                   4560:                                header.gps_hdr_csum, mbg_csum(parsetime->parse_msg + 1, 6),
                   4561:                                header.gps_len,
                   4562:                                header.gps_data_csum, mbg_csum(bufp, (unsigned)((header.gps_len < sizeof(parsetime->parse_msg)) ? header.gps_len : 0)));
                   4563:                }
                   4564:        }
                   4565:   
                   4566:        return;
                   4567: }
                   4568: 
                   4569: /*------------------------------------------------------------
                   4570:  * gps16x_poll - query the reciver peridically
                   4571:  */
                   4572: static void
                   4573: gps16x_poll(
                   4574:            struct peer *peer
                   4575:            )
                   4576: {
                   4577:        struct parseunit *parse = (struct parseunit *)peer->procptr->unitptr;
                   4578:        
                   4579:        static GPS_MSG_HDR sequence[] = 
                   4580:        {
                   4581:                { GPS_SW_REV,          0, 0, 0 },
                   4582:                { GPS_STAT,            0, 0, 0 },
                   4583:                { GPS_UTC,             0, 0, 0 },
                   4584:                { GPS_ASCII_MSG,       0, 0, 0 },
                   4585:                { GPS_ANT_INFO,        0, 0, 0 },
                   4586:                { GPS_CFGH,            0, 0, 0 },
                   4587:                { GPS_POS_XYZ,         0, 0, 0 },
                   4588:                { GPS_POS_LLA,         0, 0, 0 },
                   4589:                { (unsigned short)~0,  0, 0, 0 }
                   4590:        };
                   4591:       
                   4592:        int rtc;
                   4593:        unsigned char cmd_buffer[64];
                   4594:        unsigned char *outp = cmd_buffer;
                   4595:        GPS_MSG_HDR *header;
                   4596:        
                   4597:        if (((poll_info_t *)parse->parse_type->cl_data)->rate)
                   4598:        {
                   4599:                parse->peer->nextaction = current_time + ((poll_info_t *)parse->parse_type->cl_data)->rate;
                   4600:        }
                   4601: 
                   4602:        if (sequence[parse->localstate].gps_cmd == (unsigned short)~0)
                   4603:                parse->localstate = 0;
                   4604:        
                   4605:        header = sequence + parse->localstate++;
                   4606:        
                   4607:        *outp++ = SOH;          /* start command */
                   4608:        
                   4609:        put_mbg_header(&outp, header);
                   4610:        outp = cmd_buffer + 1;
                   4611:        
                   4612:        header->gps_hdr_csum = (short)mbg_csum(outp, 6);
                   4613:        put_mbg_header(&outp, header);
                   4614:        
                   4615: #ifdef DEBUG
                   4616:        if (debug > 2)
                   4617:        {
                   4618:                char buffer[128];
                   4619:                
                   4620:                mkreadable(buffer, sizeof(buffer), (char *)cmd_buffer, (unsigned)(outp - cmd_buffer), 1);
                   4621:                printf("PARSE receiver #%d: transmitted message #%ld (%d bytes) >%s<\n",
                   4622:                       CLK_UNIT(parse->peer),
                   4623:                       parse->localstate - 1,
                   4624:                       (int)(outp - cmd_buffer),
                   4625:                       buffer); 
                   4626:        }
                   4627: #endif
                   4628:   
                   4629:        rtc = write(parse->generic->io.fd, cmd_buffer, (unsigned long)(outp - cmd_buffer));
                   4630:        
                   4631:        if (rtc < 0)
                   4632:        {
                   4633:                ERR(ERR_BADIO)
                   4634:                        msyslog(LOG_ERR, "PARSE receiver #%d: gps16x_poll: failed to send cmd to clock: %m", CLK_UNIT(parse->peer));
                   4635:        }
                   4636:        else
                   4637:        if (rtc != outp - cmd_buffer)
                   4638:        {
                   4639:                ERR(ERR_BADIO)
                   4640:                        msyslog(LOG_ERR, "PARSE receiver #%d: gps16x_poll: failed to send cmd incomplete (%d of %d bytes sent)", CLK_UNIT(parse->peer), rtc, (int)(outp - cmd_buffer));
                   4641:        }
                   4642: 
                   4643:        clear_err(parse, ERR_BADIO);
                   4644:        return;
                   4645: }
                   4646: 
                   4647: /*--------------------------------------------------
                   4648:  * init routine - setup timer
                   4649:  */
                   4650: static int
                   4651: gps16x_poll_init(
                   4652:        struct parseunit *parse
                   4653:        )
                   4654: {
                   4655:        if (((poll_info_t *)parse->parse_type->cl_data)->rate)
                   4656:        {
                   4657:                parse->peer->action = gps16x_poll;
                   4658:                gps16x_poll(parse->peer);
                   4659:        }
                   4660: 
                   4661:        return 0;
                   4662: }
                   4663: 
                   4664: #else
                   4665: static void
                   4666: gps16x_message(
                   4667:               struct parseunit *parse,
                   4668:               parsetime_t      *parsetime
                   4669:               )
                   4670: {}
                   4671: static int
                   4672: gps16x_poll_init(
                   4673:        struct parseunit *parse
                   4674:        )
                   4675: {
                   4676:        return 1;
                   4677: }
                   4678: #endif /* CLOCK_MEINBERG */
                   4679: 
                   4680: /**===========================================================================
                   4681:  ** clock polling support
                   4682:  **/
                   4683: 
                   4684: /*--------------------------------------------------
                   4685:  * direct poll routine
                   4686:  */
                   4687: static void
                   4688: poll_dpoll(
                   4689:        struct parseunit *parse
                   4690:        )
                   4691: {
                   4692:        int rtc;
                   4693:        const char *ps = ((poll_info_t *)parse->parse_type->cl_data)->string;
                   4694:        int   ct = ((poll_info_t *)parse->parse_type->cl_data)->count;
                   4695: 
                   4696:        rtc = write(parse->generic->io.fd, ps, (unsigned long)ct);
                   4697:        if (rtc < 0)
                   4698:        {
                   4699:                ERR(ERR_BADIO)
                   4700:                        msyslog(LOG_ERR, "PARSE receiver #%d: poll_dpoll: failed to send cmd to clock: %m", CLK_UNIT(parse->peer));
                   4701:        }
                   4702:        else
                   4703:            if (rtc != ct)
                   4704:            {
                   4705:                    ERR(ERR_BADIO)
                   4706:                            msyslog(LOG_ERR, "PARSE receiver #%d: poll_dpoll: failed to send cmd incomplete (%d of %d bytes sent)", CLK_UNIT(parse->peer), rtc, ct);
                   4707:            }
                   4708:        clear_err(parse, ERR_BADIO);
                   4709: }
                   4710: 
                   4711: /*--------------------------------------------------
                   4712:  * periodic poll routine
                   4713:  */
                   4714: static void
                   4715: poll_poll(
                   4716:        struct peer *peer
                   4717:        )
                   4718: {
                   4719:        struct parseunit *parse = (struct parseunit *)peer->procptr->unitptr;
                   4720:        
                   4721:        if (parse->parse_type->cl_poll)
                   4722:                parse->parse_type->cl_poll(parse);
                   4723: 
                   4724:        if (((poll_info_t *)parse->parse_type->cl_data)->rate)
                   4725:        {
                   4726:                parse->peer->nextaction = current_time + ((poll_info_t *)parse->parse_type->cl_data)->rate;
                   4727:        }
                   4728: }
                   4729: 
                   4730: /*--------------------------------------------------
                   4731:  * init routine - setup timer
                   4732:  */
                   4733: static int
                   4734: poll_init(
                   4735:        struct parseunit *parse
                   4736:        )
                   4737: {
                   4738:        if (((poll_info_t *)parse->parse_type->cl_data)->rate)
                   4739:        {
                   4740:                parse->peer->action = poll_poll;
                   4741:                poll_poll(parse->peer);
                   4742:        }
                   4743: 
                   4744:        return 0;
                   4745: }
                   4746: 
                   4747: /**===========================================================================
                   4748:  ** Trimble support
                   4749:  **/
                   4750: 
                   4751: /*-------------------------------------------------------------
                   4752:  * trimble TAIP init routine - setup EOL and then do poll_init.
                   4753:  */
                   4754: static int
                   4755: trimbletaip_init(
                   4756:        struct parseunit *parse
                   4757:        )
                   4758: {
                   4759: #ifdef HAVE_TERMIOS
                   4760:        struct termios tio;
                   4761: #endif
                   4762: #ifdef HAVE_SYSV_TTYS
                   4763:        struct termio tio;
                   4764: #endif
                   4765:        /*
                   4766:         * configure terminal line for trimble receiver
                   4767:         */
                   4768:        if (TTY_GETATTR(parse->generic->io.fd, &tio) == -1)
                   4769:        {
                   4770:                msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_init: tcgetattr(fd, &tio): %m", CLK_UNIT(parse->peer));
                   4771:                return 0;
                   4772:        }
                   4773:        else
                   4774:        {
                   4775:                tio.c_cc[VEOL] = TRIMBLETAIP_EOL;
                   4776:        
                   4777:                if (TTY_SETATTR(parse->generic->io.fd, &tio) == -1)
                   4778:                {
                   4779:                        msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_init: tcsetattr(fd, &tio): %m", CLK_UNIT(parse->peer));
                   4780:                        return 0;
                   4781:                }
                   4782:        }
                   4783:        return poll_init(parse);
                   4784: }
                   4785: 
                   4786: /*--------------------------------------------------
                   4787:  * trimble TAIP event routine - reset receiver upon data format trouble
                   4788:  */
                   4789: static const char *taipinit[] = {
                   4790:        ">FPV00000000<",
                   4791:        ">SRM;ID_FLAG=F;CS_FLAG=T;EC_FLAG=F;FR_FLAG=T;CR_FLAG=F<",
                   4792:        ">FTM00020001<",
                   4793:        (char *)0
                   4794: };
                   4795:       
                   4796: static void
                   4797: trimbletaip_event(
                   4798:        struct parseunit *parse,
                   4799:        int event
                   4800:        )
                   4801: {
                   4802:        switch (event)
                   4803:        {
                   4804:            case CEVNT_BADREPLY:        /* reset on garbled input */
                   4805:            case CEVNT_TIMEOUT:         /* reset on no input */
                   4806:                    {
                   4807:                            const char **iv;
                   4808: 
                   4809:                            iv = taipinit;
                   4810:                            while (*iv)
                   4811:                            {
                   4812:                                    int rtc = write(parse->generic->io.fd, *iv, strlen(*iv));
                   4813:                                    if (rtc < 0)
                   4814:                                    {
                   4815:                                            msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_event: failed to send cmd to clock: %m", CLK_UNIT(parse->peer));
                   4816:                                            return;
                   4817:                                    }
                   4818:                                    else
                   4819:                                    {
                   4820:                                            if (rtc != strlen(*iv))
                   4821:                                            {
                   4822:                                                    msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_event: failed to send cmd incomplete (%d of %d bytes sent)",
                   4823:                                                            CLK_UNIT(parse->peer), rtc, (int)strlen(*iv));
                   4824:                                                    return;
                   4825:                                            }
                   4826:                                    }
                   4827:                                    iv++;
                   4828:                            }
                   4829: 
                   4830:                            NLOG(NLOG_CLOCKINFO)
                   4831:                                    ERR(ERR_BADIO)
                   4832:                                    msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_event: RECEIVER INITIALIZED",
                   4833:                                            CLK_UNIT(parse->peer));
                   4834:                    }
                   4835:                    break;
                   4836: 
                   4837:            default:                    /* ignore */
                   4838:                break;
                   4839:        }
                   4840: }
                   4841: 
                   4842: /*
                   4843:  * This driver supports the Trimble SVee Six Plus GPS receiver module.
                   4844:  * It should support other Trimble receivers which use the Trimble Standard
                   4845:  * Interface Protocol (see below).
                   4846:  *
                   4847:  * The module has a serial I/O port for command/data and a 1 pulse-per-second
                   4848:  * output, about 1 microsecond wide. The leading edge of the pulse is
                   4849:  * coincident with the change of the GPS second. This is the same as
                   4850:  * the change of the UTC second +/- ~1 microsecond. Some other clocks
                   4851:  * specifically use a feature in the data message as a timing reference, but
                   4852:  * the SVee Six Plus does not do this. In fact there is considerable jitter
                   4853:  * on the timing of the messages, so this driver only supports the use
                   4854:  * of the PPS pulse for accurate timing. Where it is determined that
                   4855:  * the offset is way off, when first starting up ntpd for example,
                   4856:  * the timing of the data stream is used until the offset becomes low enough
                   4857:  * (|offset| < CLOCK_MAX), at which point the pps offset is used.
                   4858:  *
                   4859:  * It can use either option for receiving PPS information - the 'ppsclock'
                   4860:  * stream pushed onto the serial data interface to timestamp the Carrier
                   4861:  * Detect interrupts, where the 1PPS connects to the CD line. This only
                   4862:  * works on SunOS 4.1.x currently. To select this, define PPSPPS in
                   4863:  * Config.local. The other option is to use a pulse-stretcher/level-converter
                   4864:  * to convert the PPS pulse into a RS232 start pulse & feed this into another
                   4865:  * tty port. To use this option, define PPSCLK in Config.local. The pps input,
                   4866:  * by whichever method, is handled in ntp_loopfilter.c
                   4867:  *
                   4868:  * The receiver uses a serial message protocol called Trimble Standard
                   4869:  * Interface Protocol (it can support others but this driver only supports
                   4870:  * TSIP). Messages in this protocol have the following form:
                   4871:  *
                   4872:  * <DLE><id> ... <data> ... <DLE><ETX>
                   4873:  *
                   4874:  * Any bytes within the <data> portion of value 10 hex (<DLE>) are doubled
                   4875:  * on transmission and compressed back to one on reception. Otherwise
                   4876:  * the values of data bytes can be anything. The serial interface is RS-422
                   4877:  * asynchronous using 9600 baud, 8 data bits with odd party (**note** 9 bits
                   4878:  * in total!), and 1 stop bit. The protocol supports byte, integer, single,
                   4879:  * and double datatypes. Integers are two bytes, sent most significant first.
                   4880:  * Singles are IEEE754 single precision floating point numbers (4 byte) sent
                   4881:  * sign & exponent first. Doubles are IEEE754 double precision floating point
                   4882:  * numbers (8 byte) sent sign & exponent first.
                   4883:  * The receiver supports a large set of messages, only a small subset of
                   4884:  * which are used here. From driver to receiver the following are used:
                   4885:  *
                   4886:  *  ID    Description
                   4887:  *
                   4888:  *  21    Request current time
                   4889:  *  22    Mode Select
                   4890:  *  2C    Set/Request operating parameters
                   4891:  *  2F    Request UTC info
                   4892:  *  35    Set/Request I/O options
                   4893: 
                   4894:  * From receiver to driver the following are recognised:
                   4895:  *
                   4896:  *  ID    Description
                   4897:  *
                   4898:  *  41    GPS Time
                   4899:  *  44    Satellite selection, PDOP, mode
                   4900:  *  46    Receiver health
                   4901:  *  4B    Machine code/status
                   4902:  *  4C    Report operating parameters (debug only)
                   4903:  *  4F    UTC correction data (used to get leap second warnings)
                   4904:  *  55    I/O options (debug only)
                   4905:  *
                   4906:  * All others are accepted but ignored.
                   4907:  *
                   4908:  */
                   4909: 
                   4910: #define PI             3.1415926535898 /* lots of sig figs */
                   4911: #define D2R            PI/180.0
                   4912: 
                   4913: /*-------------------------------------------------------------------
                   4914:  * sendcmd, sendbyte, sendetx, sendflt, sendint implement the command
                   4915:  * interface to the receiver.
                   4916:  *
                   4917:  * CAVEAT: the sendflt, sendint routines are byte order dependend and
                   4918:  * float implementation dependend - these must be converted to portable
                   4919:  * versions !
                   4920:  *
                   4921:  * CURRENT LIMITATION: float implementation. This runs only on systems
                   4922:  * with IEEE754 floats as native floats
                   4923:  */
                   4924: 
                   4925: typedef struct trimble
                   4926: {
                   4927:        u_long last_msg;        /* last message received */
                   4928:        u_long last_reset;      /* last time a reset was issued */
                   4929:        u_char qtracking;       /* query tracking status */
                   4930:        u_long ctrack;          /* current tracking set */
                   4931:        u_long ltrack;          /* last tracking set */
                   4932: } trimble_t;
                   4933: 
                   4934: union uval {
                   4935:        u_char  bd[8];
                   4936:        int     iv;
                   4937:        float   fv;
                   4938:        double  dv;
                   4939: };
                   4940:   
                   4941: struct txbuf
                   4942: {
                   4943:        short idx;                      /* index to first unused byte */
                   4944:        u_char *txt;                    /* pointer to actual data buffer */
                   4945: };
                   4946: 
                   4947: void   sendcmd         (struct txbuf *buf, int c); 
                   4948: void   sendbyte        (struct txbuf *buf, int b); 
                   4949: void   sendetx         (struct txbuf *buf, struct parseunit *parse); 
                   4950: void   sendint         (struct txbuf *buf, int a); 
                   4951: void   sendflt         (struct txbuf *buf, double a); 
                   4952:  
                   4953: void
                   4954: sendcmd(
                   4955:        struct txbuf *buf,
                   4956:        int c
                   4957:        )
                   4958: {
                   4959:        buf->txt[0] = DLE;
                   4960:        buf->txt[1] = (u_char)c;
                   4961:        buf->idx = 2;
                   4962: }
                   4963: 
                   4964: void   sendcmd         (struct txbuf *buf, int c); 
                   4965: void   sendbyte        (struct txbuf *buf, int b); 
                   4966: void   sendetx         (struct txbuf *buf, struct parseunit *parse); 
                   4967: void   sendint         (struct txbuf *buf, int a); 
                   4968: void   sendflt         (struct txbuf *buf, double a); 
                   4969:  
                   4970: void
                   4971: sendbyte(
                   4972:        struct txbuf *buf,
                   4973:        int b
                   4974:        )
                   4975: {
                   4976:        if (b == DLE)
                   4977:            buf->txt[buf->idx++] = DLE;
                   4978:        buf->txt[buf->idx++] = (u_char)b;
                   4979: }
                   4980: 
                   4981: void
                   4982: sendetx(
                   4983:        struct txbuf *buf,
                   4984:        struct parseunit *parse
                   4985:        )
                   4986: {
                   4987:        buf->txt[buf->idx++] = DLE;
                   4988:        buf->txt[buf->idx++] = ETX;
                   4989: 
                   4990:        if (write(parse->generic->io.fd, buf->txt, (unsigned long)buf->idx) != buf->idx)
                   4991:        {
                   4992:                ERR(ERR_BADIO)
                   4993:                        msyslog(LOG_ERR, "PARSE receiver #%d: sendetx: failed to send cmd to clock: %m", CLK_UNIT(parse->peer));
                   4994:        }
                   4995:        else
                   4996:        {
                   4997: #ifdef DEBUG
                   4998:          if (debug > 2)
                   4999:          {
                   5000:                  char buffer[256];
                   5001:                  
                   5002:                  mkreadable(buffer, sizeof(buffer), (char *)buf->txt, (unsigned)buf->idx, 1);
                   5003:                  printf("PARSE receiver #%d: transmitted message (%d bytes) >%s<\n",
                   5004:                         CLK_UNIT(parse->peer),
                   5005:                         buf->idx, buffer); 
                   5006:          }
                   5007: #endif
                   5008:                clear_err(parse, ERR_BADIO);
                   5009:        }
                   5010: }
                   5011: 
                   5012: void  
                   5013: sendint(
                   5014:        struct txbuf *buf,
                   5015:        int a
                   5016:        )
                   5017: {
                   5018:        /* send 16bit int, msbyte first */
                   5019:        sendbyte(buf, (u_char)((a>>8) & 0xff));
                   5020:        sendbyte(buf, (u_char)(a & 0xff));
                   5021: }
                   5022: 
                   5023: void
                   5024: sendflt(
                   5025:        struct txbuf *buf,
                   5026:        double a
                   5027:        )
                   5028: {
                   5029:        int i;
                   5030:        union uval uval;
                   5031: 
                   5032:        uval.fv = a;
                   5033: #ifdef WORDS_BIGENDIAN
                   5034:        for (i=0; i<=3; i++)
                   5035: #else
                   5036:            for (i=3; i>=0; i--)
                   5037: #endif
                   5038:                sendbyte(buf, uval.bd[i]);
                   5039: }
                   5040: 
                   5041: #define TRIM_POS_OPT   0x13    /* output position with high precision */
                   5042: #define TRIM_TIME_OPT  0x03    /* use UTC time stamps, on second */
                   5043: 
                   5044: /*--------------------------------------------------
                   5045:  * trimble TSIP setup routine
                   5046:  */
                   5047: static int
                   5048: trimbletsip_setup(
                   5049:                  struct parseunit *parse,
                   5050:                  const char *reason
                   5051:                  )
                   5052: {
                   5053:        u_char buffer[256];
                   5054:        struct txbuf buf;
                   5055:        trimble_t *t = parse->localdata;
                   5056: 
                   5057:        if (t && t->last_reset &&
                   5058:            ((t->last_reset + TRIMBLE_RESET_HOLDOFF) > current_time)) {
                   5059:                return 1;       /* not yet */
                   5060:        }
                   5061: 
                   5062:        if (t)
                   5063:                t->last_reset = current_time;
                   5064:                        
                   5065:        buf.txt = buffer;
                   5066:   
                   5067:        sendcmd(&buf, CMD_CVERSION);    /* request software versions */
                   5068:        sendetx(&buf, parse);
                   5069:        
                   5070:        sendcmd(&buf, CMD_COPERPARAM);  /* set operating parameters */
                   5071:        sendbyte(&buf, 4);      /* static */
                   5072:        sendflt(&buf, 5.0*D2R); /* elevation angle mask = 10 deg XXX */
                   5073:        sendflt(&buf, 4.0);     /* s/n ratio mask = 6 XXX */
                   5074:        sendflt(&buf, 12.0);    /* PDOP mask = 12 */
                   5075:        sendflt(&buf, 8.0);     /* PDOP switch level = 8 */
                   5076:        sendetx(&buf, parse);
                   5077:        
                   5078:        sendcmd(&buf, CMD_CMODESEL);    /* fix mode select */
                   5079:        sendbyte(&buf, 1);      /* time transfer mode */
                   5080:        sendetx(&buf, parse);
                   5081:        
                   5082:        sendcmd(&buf, CMD_CMESSAGE);    /* request system message */
                   5083:        sendetx(&buf, parse);
                   5084:        
                   5085:        sendcmd(&buf, CMD_CSUPER);      /* superpacket fix */
                   5086:        sendbyte(&buf, 0x2);    /* binary mode */
                   5087:        sendetx(&buf, parse);
                   5088:        
                   5089:        sendcmd(&buf, CMD_CIOOPTIONS);  /* set I/O options */
                   5090:        sendbyte(&buf, TRIM_POS_OPT);   /* position output */
                   5091:        sendbyte(&buf, 0x00);   /* no velocity output */
                   5092:        sendbyte(&buf, TRIM_TIME_OPT);  /* UTC, compute on seconds */
                   5093:        sendbyte(&buf, 0x00);   /* no raw measurements */
                   5094:        sendetx(&buf, parse);
                   5095:        
                   5096:        sendcmd(&buf, CMD_CUTCPARAM);   /* request UTC correction data */
                   5097:        sendetx(&buf, parse);
                   5098: 
                   5099:        NLOG(NLOG_CLOCKINFO)
                   5100:                ERR(ERR_BADIO)
                   5101:                msyslog(LOG_ERR, "PARSE receiver #%d: trimbletsip_setup: RECEIVER RE-INITIALIZED (%s)", CLK_UNIT(parse->peer), reason);
                   5102: 
                   5103:        return 0;
                   5104: }
                   5105: 
                   5106: /*--------------------------------------------------
                   5107:  * TRIMBLE TSIP check routine
                   5108:  */
                   5109: static void
                   5110: trimble_check(
                   5111:              struct peer *peer
                   5112:              )
                   5113: {
                   5114:        struct parseunit *parse = (struct parseunit *)peer->procptr->unitptr;
                   5115:        trimble_t *t = parse->localdata;
                   5116:        u_char buffer[256];
                   5117:        struct txbuf buf;
                   5118:        buf.txt = buffer;
                   5119:        
                   5120:        if (t)
                   5121:        {
                   5122:                if (current_time > t->last_msg + TRIMBLETSIP_IDLE_TIME)
                   5123:                        (void)trimbletsip_setup(parse, "message timeout");
                   5124:        }
                   5125: 
                   5126:        poll_poll(parse->peer); /* emit query string and re-arm timer */
                   5127:        
                   5128:        if (t && t->qtracking)
                   5129:        {
                   5130:                u_long oldsats = t->ltrack & ~t->ctrack;
                   5131:                
                   5132:                t->qtracking = 0;
                   5133:                t->ltrack = t->ctrack;
                   5134:                
                   5135:                if (oldsats)
                   5136:                {
                   5137:                        int i;
                   5138:                                
                   5139:                        for (i = 0; oldsats; i++) {
                   5140:                                if (oldsats & (1 << i))
                   5141:                                        {
                   5142:                                                sendcmd(&buf, CMD_CSTATTRACK);
                   5143:                                                sendbyte(&buf, i+1);    /* old sat */
                   5144:                                                sendetx(&buf, parse);
                   5145:                                        }
                   5146:                                oldsats &= ~(1 << i);
                   5147:                        }
                   5148:                }
                   5149:                                                
                   5150:                sendcmd(&buf, CMD_CSTATTRACK);
                   5151:                sendbyte(&buf, 0x00);   /* current tracking set */
                   5152:                sendetx(&buf, parse);
                   5153:        }
                   5154: }
                   5155: 
                   5156: /*--------------------------------------------------
                   5157:  * TRIMBLE TSIP end routine
                   5158:  */
                   5159: static void
                   5160: trimbletsip_end(
                   5161:              struct parseunit *parse
                   5162:              )
                   5163: {      trimble_t *t = parse->localdata;
                   5164:        
                   5165:        if (t)
                   5166:        {
                   5167:                free(t);
                   5168:                parse->localdata = (void *)0;
                   5169:        }
                   5170:        parse->peer->nextaction = 0;
                   5171:        parse->peer->action = (void (*) (struct peer *))0;
                   5172: }
                   5173: 
                   5174: /*--------------------------------------------------
                   5175:  * TRIMBLE TSIP init routine
                   5176:  */
                   5177: static int
                   5178: trimbletsip_init(
                   5179:        struct parseunit *parse
                   5180:        )
                   5181: {
                   5182: #if defined(VEOL) || defined(VEOL2)
                   5183: #ifdef HAVE_TERMIOS
                   5184:        struct termios tio;             /* NEEDED FOR A LONG TIME ! */
                   5185: #endif
                   5186: #ifdef HAVE_SYSV_TTYS
                   5187:        struct termio tio;              /* NEEDED FOR A LONG TIME ! */
                   5188: #endif
                   5189:        /*
                   5190:         * allocate local data area
                   5191:         */
                   5192:        if (!parse->localdata)
                   5193:        {
                   5194:                trimble_t *t;
                   5195:                
                   5196:                t = (trimble_t *)(parse->localdata = emalloc(sizeof(trimble_t)));
                   5197:                
                   5198:                if (t)
                   5199:                {
                   5200:                        memset((char *)t, 0, sizeof(trimble_t));
                   5201:                        t->last_msg = current_time;
                   5202:                }
                   5203:        }
                   5204: 
                   5205:        parse->peer->action     = trimble_check;
                   5206:        parse->peer->nextaction = current_time;
                   5207: 
                   5208:        /*
                   5209:         * configure terminal line for ICANON mode with VEOL characters
                   5210:         */
                   5211:        if (TTY_GETATTR(parse->generic->io.fd, &tio) == -1)
                   5212:        {
                   5213:                msyslog(LOG_ERR, "PARSE receiver #%d: trimbletsip_init: tcgetattr(%d, &tio): %m", CLK_UNIT(parse->peer), parse->generic->io.fd);
                   5214:                return 0;
                   5215:        }
                   5216:        else
                   5217:        {
                   5218:                if ((parse_clockinfo[CLK_TYPE(parse->peer)].cl_lflag & ICANON))
                   5219:                {
                   5220: #ifdef VEOL
                   5221:                        tio.c_cc[VEOL]  = ETX;
                   5222: #endif
                   5223: #ifdef VEOL2
                   5224:                        tio.c_cc[VEOL2]  = DLE;
                   5225: #endif
                   5226:                }
                   5227: 
                   5228:                if (TTY_SETATTR(parse->generic->io.fd, &tio) == -1)
                   5229:                {
                   5230:                        msyslog(LOG_ERR, "PARSE receiver #%d: trimbletsip_init: tcsetattr(%d, &tio): %m", CLK_UNIT(parse->peer), parse->generic->io.fd);
                   5231:                        return 0;
                   5232:                }
                   5233:        }
                   5234: #endif
                   5235:        return trimbletsip_setup(parse, "initial startup");
                   5236: }
                   5237: 
                   5238: /*------------------------------------------------------------
                   5239:  * trimbletsip_event - handle Trimble events
                   5240:  * simple evente handler - attempt to re-initialize receiver
                   5241:  */
                   5242: static void
                   5243: trimbletsip_event(
                   5244:        struct parseunit *parse,
                   5245:        int event
                   5246:        )
                   5247: {
                   5248:        switch (event)
                   5249:        {
                   5250:            case CEVNT_BADREPLY:        /* reset on garbled input */
                   5251:            case CEVNT_TIMEOUT:         /* reset on no input */
                   5252:                    (void)trimbletsip_setup(parse, "event BAD_REPLY/TIMEOUT");
                   5253:                    break;
                   5254: 
                   5255:            default:                    /* ignore */
                   5256:                break;
                   5257:        }
                   5258: }
                   5259: 
                   5260: /*
                   5261:  * getflt, getint convert fields in the incoming data into the
                   5262:  * appropriate type of item
                   5263:  *
                   5264:  * CAVEAT: these routines are currently definitely byte order dependent
                   5265:  * and assume Representation(float) == IEEE754
                   5266:  * These functions MUST be converted to portable versions (especially
                   5267:  * converting the float representation into ntp_fp formats in order
                   5268:  * to avoid floating point operations at all!
                   5269:  */
                   5270: 
                   5271: static float
                   5272: getflt(
                   5273:        u_char *bp
                   5274:        )
                   5275: {
                   5276:        union uval uval;
                   5277:        
                   5278: #ifdef WORDS_BIGENDIAN
                   5279:        uval.bd[0] = *bp++;
                   5280:        uval.bd[1] = *bp++;
                   5281:        uval.bd[2] = *bp++;
                   5282:        uval.bd[3] = *bp;
                   5283: #else  /* ! WORDS_BIGENDIAN */
                   5284:        uval.bd[3] = *bp++;
                   5285:        uval.bd[2] = *bp++;
                   5286:        uval.bd[1] = *bp++;
                   5287:        uval.bd[0] = *bp;
                   5288: #endif /* ! WORDS_BIGENDIAN */
                   5289:        return uval.fv;
                   5290: }
                   5291: 
                   5292: static double
                   5293: getdbl(
                   5294:        u_char *bp
                   5295:        )
                   5296: {
                   5297:        union uval uval;
                   5298:        
                   5299: #ifdef WORDS_BIGENDIAN
                   5300:        uval.bd[0] = *bp++;
                   5301:        uval.bd[1] = *bp++;
                   5302:        uval.bd[2] = *bp++;
                   5303:        uval.bd[3] = *bp++;
                   5304:        uval.bd[4] = *bp++;
                   5305:        uval.bd[5] = *bp++;
                   5306:        uval.bd[6] = *bp++;
                   5307:        uval.bd[7] = *bp;
                   5308: #else  /* ! WORDS_BIGENDIAN */
                   5309:        uval.bd[7] = *bp++;
                   5310:        uval.bd[6] = *bp++;
                   5311:        uval.bd[5] = *bp++;
                   5312:        uval.bd[4] = *bp++;
                   5313:        uval.bd[3] = *bp++;
                   5314:        uval.bd[2] = *bp++;
                   5315:        uval.bd[1] = *bp++;
                   5316:        uval.bd[0] = *bp;
                   5317: #endif /* ! WORDS_BIGENDIAN */
                   5318:        return uval.dv;
                   5319: }
                   5320: 
                   5321: static int
                   5322: getshort(
                   5323:         unsigned char *p
                   5324:         )
                   5325: {
                   5326:        return get_msb_short(&p);
                   5327: }
                   5328: 
                   5329: /*--------------------------------------------------
                   5330:  * trimbletsip_message - process trimble messages
                   5331:  */
                   5332: #define RTOD (180.0 / 3.1415926535898)
                   5333: #define mb(_X_) (buffer[2+(_X_)]) /* shortcut for buffer access */
                   5334: 
                   5335: static void
                   5336: trimbletsip_message(
                   5337:                    struct parseunit *parse,
                   5338:                    parsetime_t      *parsetime
                   5339:                    )
                   5340: {
                   5341:        unsigned char *buffer = parsetime->parse_msg;
                   5342:        unsigned int   size   = parsetime->parse_msglen;
                   5343:        
                   5344:        if ((size < 4) ||
                   5345:            (buffer[0]      != DLE) ||
                   5346:            (buffer[size-1] != ETX) ||
                   5347:            (buffer[size-2] != DLE))
                   5348:        {
                   5349: #ifdef DEBUG
                   5350:                if (debug > 2) {
                   5351:                        int i;
                   5352: 
                   5353:                        printf("TRIMBLE BAD packet, size %d:\n  ", size);
                   5354:                        for (i = 0; i < size; i++) {
                   5355:                                printf ("%2.2x, ", buffer[i]&0xff);
                   5356:                                if (i%16 == 15) printf("\n\t");
                   5357:                        }
                   5358:                        printf("\n");
                   5359:                }
                   5360: #endif
                   5361:                return;
                   5362:        }
                   5363:        else
                   5364:        {
                   5365:                int var_flag;
                   5366:                trimble_t *tr = parse->localdata;
                   5367:                unsigned int cmd = buffer[1];
                   5368:                char pbuffer[200];
                   5369:                char *t = pbuffer;
                   5370:                cmd_info_t *s;
                   5371:                
                   5372: #ifdef DEBUG
                   5373:                if (debug > 3) {
                   5374:                        int i;
                   5375: 
                   5376:                        printf("TRIMBLE packet 0x%02x, size %d:\n       ", cmd, size);
                   5377:                        for (i = 0; i < size; i++) {
                   5378:                                printf ("%2.2x, ", buffer[i]&0xff);
                   5379:                                if (i%16 == 15) printf("\n\t");
                   5380:                        }
                   5381:                        printf("\n");
                   5382:                }
                   5383: #endif
                   5384: 
                   5385:                if (tr)
                   5386:                        tr->last_msg = current_time;
                   5387:                
                   5388:                s = trimble_convert(cmd, trimble_rcmds);
                   5389:                
                   5390:                if (s)
                   5391:                {
                   5392:                        snprintf(t, BUFFER_SIZE(pbuffer, t), "%s=\"", s->varname);
                   5393:                }
                   5394:                else
                   5395:                {
                   5396:                        DPRINTF(1, ("TRIMBLE UNKNOWN COMMAND 0x%02x\n", cmd));
                   5397:                        return;
                   5398:                }
                   5399: 
                   5400:                var_flag = s->varmode;
                   5401: 
                   5402:                t += strlen(t);
                   5403:                
                   5404:                switch(cmd)
                   5405:                {
                   5406:                case CMD_RCURTIME:
                   5407:                        snprintf(t, BUFFER_SIZE(pbuffer, t), "%f, %d, %f",
                   5408:                                 getflt((unsigned char *)&mb(0)), getshort((unsigned char *)&mb(4)),
                   5409:                                 getflt((unsigned char *)&mb(6)));
                   5410:                        break;
                   5411:                        
                   5412:                case CMD_RBEST4:
                   5413:                        strncpy(t, "mode: ", BUFFER_SIZE(pbuffer, t));
                   5414:                        t += strlen(t);
                   5415:                        switch (mb(0) & 0xF)
                   5416:                        {
                   5417:                        default:
                   5418:                                snprintf(t, BUFFER_SIZE(pbuffer, t), "0x%x", mb(0) & 0x7);
                   5419:                                break;
                   5420: 
                   5421:                        case 1:
                   5422:                                strncpy(t, "0D", BUFFER_SIZE(pbuffer, t));
                   5423:                                break;
                   5424:                                
                   5425:                        case 3:
                   5426:                                strncpy(t, "2D", BUFFER_SIZE(pbuffer, t));
                   5427:                                break;
                   5428:                                
                   5429:                        case 4:
                   5430:                                strncpy(t, "3D", BUFFER_SIZE(pbuffer, t));
                   5431:                                break;
                   5432:                        }
                   5433:                        t += strlen(t);
                   5434:                        if (mb(0) & 0x10)
                   5435:                                strncpy(t, "-MANUAL, ", BUFFER_SIZE(pbuffer, t));
                   5436:                        else
                   5437:                                strncpy(t, "-AUTO, ", BUFFER_SIZE(pbuffer, t));
                   5438:                        t += strlen(t);
                   5439:                        
                   5440:                        snprintf(t, BUFFER_SIZE(pbuffer, t), "satellites %02d %02d %02d %02d, PDOP %.2f, HDOP %.2f, VDOP %.2f, TDOP %.2f",
                   5441:                                mb(1), mb(2), mb(3), mb(4),
                   5442:                                getflt((unsigned char *)&mb(5)),
                   5443:                                getflt((unsigned char *)&mb(9)),
                   5444:                                getflt((unsigned char *)&mb(13)),
                   5445:                                getflt((unsigned char *)&mb(17)));
                   5446: 
                   5447:                        break;
                   5448:                        
                   5449:                case CMD_RVERSION:
                   5450:                        snprintf(t, BUFFER_SIZE(pbuffer, t), "%d.%d (%d/%d/%d)",
                   5451:                                mb(0)&0xff, mb(1)&0xff, 1900+(mb(4)&0xff), mb(2)&0xff, mb(3)&0xff);
                   5452:                        break;
                   5453:                        
                   5454:                case CMD_RRECVHEALTH:
                   5455:                {
                   5456:                        static const char *msgs[] =
                   5457:                        {
                   5458:                                "Battery backup failed",
                   5459:                                "Signal processor error",
                   5460:                                "Alignment error, channel or chip 1",
                   5461:                                "Alignment error, channel or chip 2",
                   5462:                                "Antenna feed line fault",
                   5463:                                "Excessive ref freq. error",
                   5464:                                "<BIT 6>",
                   5465:                                "<BIT 7>"
                   5466:                        };
                   5467:                        
                   5468:                        int i, bits;
                   5469:                        
                   5470:                        switch (mb(0) & 0xFF)
                   5471:                        {
                   5472:                        default:
                   5473:                                snprintf(t, BUFFER_SIZE(pbuffer, t), "illegal value 0x%02x", mb(0) & 0xFF);
                   5474:                                break;
                   5475:                        case 0x00:
                   5476:                                strncpy(t, "doing position fixes", BUFFER_SIZE(pbuffer, t));
                   5477:                                break;
                   5478:                        case 0x01:
                   5479:                                strncpy(t, "no GPS time yet", BUFFER_SIZE(pbuffer, t));
                   5480:                                break;
                   5481:                        case 0x03:
                   5482:                                strncpy(t, "PDOP too high", BUFFER_SIZE(pbuffer, t));
                   5483:                                break;
                   5484:                        case 0x08:
                   5485:                                strncpy(t, "no usable satellites", BUFFER_SIZE(pbuffer, t));
                   5486:                                break;
                   5487:                        case 0x09:
                   5488:                                strncpy(t, "only ONE usable satellite", BUFFER_SIZE(pbuffer, t));
                   5489:                                break;
                   5490:                        case 0x0A:
                   5491:                                strncpy(t, "only TWO usable satellites", BUFFER_SIZE(pbuffer, t));
                   5492:                                break;
                   5493:                        case 0x0B:
                   5494:                                strncpy(t, "only THREE usable satellites", BUFFER_SIZE(pbuffer, t));
                   5495:                                break;
                   5496:                        case 0x0C:
                   5497:                                strncpy(t, "the chosen satellite is unusable", BUFFER_SIZE(pbuffer, t));
                   5498:                                break;
                   5499:                        }
                   5500: 
                   5501:                        t += strlen(t);
                   5502: 
                   5503:                        bits = mb(1) & 0xFF;
                   5504:                        
                   5505:                        for (i = 0; i < 8; i++)
                   5506:                                if (bits & (0x1<<i))
                   5507:                                {
                   5508:                                        snprintf(t, BUFFER_SIZE(pbuffer, t), ", %s", msgs[i]);
                   5509:                                        t += strlen(t);
                   5510:                                }
                   5511:                }
                   5512:                break;
                   5513:                        
                   5514:                case CMD_RMESSAGE:
                   5515:                        mkreadable(t, (int)BUFFER_SIZE(pbuffer, t), (char *)&mb(0), (unsigned)(size - 2 - (&mb(0) - buffer)), 0);
                   5516:                        break;
                   5517:                        
                   5518:                case CMD_RMACHSTAT:
                   5519:                {
                   5520:                        static const char *msgs[] =
                   5521:                        {
                   5522:                                "Synthesizer Fault",
                   5523:                                "Battery Powered Time Clock Fault",
                   5524:                                "A-to-D Converter Fault",
                   5525:                                "The almanac stored in the receiver is not complete and current",
                   5526:                                "<BIT 4>",
                   5527:                                "<BIT 5",
                   5528:                                "<BIT 6>",
                   5529:                                "<BIT 7>"
                   5530:                        };
                   5531:                        
                   5532:                        int i, bits;
                   5533: 
                   5534:                        snprintf(t, BUFFER_SIZE(pbuffer, t), "machine id 0x%02x", mb(0) & 0xFF);
                   5535:                        t += strlen(t);
                   5536:                        
                   5537:                        bits = mb(1) & 0xFF;
                   5538:                        
                   5539:                        for (i = 0; i < 8; i++)
                   5540:                                if (bits & (0x1<<i))
                   5541:                                {
                   5542:                                        snprintf(t, BUFFER_SIZE(pbuffer, t), ", %s", msgs[i]);
                   5543:                                        t += strlen(t);
                   5544:                                }
                   5545: 
                   5546:                        snprintf(t, BUFFER_SIZE(pbuffer, t), ", Superpackets %ssupported", (mb(2) & 0xFF) ? "" :"un" );
                   5547:                }
                   5548:                break;
                   5549:                        
                   5550:                case CMD_ROPERPARAM:
                   5551:                        snprintf(t, BUFFER_SIZE(pbuffer, t), "%2x %.1f %.1f %.1f %.1f",
                   5552:                                mb(0), getflt((unsigned char *)&mb(1)), getflt((unsigned char *)&mb(5)),
                   5553:                                getflt((unsigned char *)&mb(9)), getflt((unsigned char *)&mb(13)));
                   5554:                        break;
                   5555:                        
                   5556:                case CMD_RUTCPARAM:
                   5557:                {
                   5558:                        float t0t = getflt((unsigned char *)&mb(14));
                   5559:                        short wnt = getshort((unsigned char *)&mb(18));
                   5560:                        short dtls = getshort((unsigned char *)&mb(12));
                   5561:                        short wnlsf = getshort((unsigned char *)&mb(20));
                   5562:                        short dn = getshort((unsigned char *)&mb(22));
                   5563:                        short dtlsf = getshort((unsigned char *)&mb(24));
                   5564: 
                   5565:                        if ((int)t0t != 0)
                   5566:                          {
                   5567:                                  mk_utcinfo(t, wnt, wnlsf, dn, dtls, dtlsf, BUFFER_SIZE(pbuffer, t));
                   5568:                          }
                   5569:                        else
                   5570:                          {
                   5571:                            strncpy(t, "<NO UTC DATA>", BUFFER_SIZE(pbuffer, t));
                   5572:                          }
                   5573:                }
                   5574:                break;
                   5575: 
                   5576:                case CMD_RSAT1BIAS:
                   5577:                        snprintf(t, BUFFER_SIZE(pbuffer, t), "%.1fm %.2fm/s at %.1fs",
                   5578:                                getflt(&mb(0)), getflt(&mb(4)), getflt(&mb(8)));
                   5579:                        break;
                   5580: 
                   5581:                case CMD_RIOOPTIONS:
                   5582:                {
                   5583:                        snprintf(t, BUFFER_SIZE(pbuffer, t), "%02x %02x %02x %02x",
                   5584:                                mb(0), mb(1), mb(2), mb(3));
                   5585:                        if (mb(0) != TRIM_POS_OPT ||
                   5586:                            mb(2) != TRIM_TIME_OPT)
                   5587:                        {
                   5588:                                (void)trimbletsip_setup(parse, "bad io options");
                   5589:                        }
                   5590:                }
                   5591:                break;
                   5592:                
                   5593:                case CMD_RSPOSXYZ:
                   5594:                {
                   5595:                        double x = getflt((unsigned char *)&mb(0));
                   5596:                        double y = getflt((unsigned char *)&mb(4));
                   5597:                        double z = getflt((unsigned char *)&mb(8));
                   5598:                        double f = getflt((unsigned char *)&mb(12));
                   5599:                        
                   5600:                        if (f > 0.0)
                   5601:                          snprintf(t, BUFFER_SIZE(pbuffer, t), "x= %.1fm, y= %.1fm, z= %.1fm, time_of_fix= %f sec",
                   5602:                                  x, y, z,
                   5603:                                  f);
                   5604:                        else
                   5605:                          return;
                   5606:                }
                   5607:                break;
                   5608: 
                   5609:                case CMD_RSLLAPOS:
                   5610:                {
                   5611:                        double lat = getflt((unsigned char *)&mb(0));
                   5612:                        double lng = getflt((unsigned char *)&mb(4));
                   5613:                        double f   = getflt((unsigned char *)&mb(12));
                   5614:                        
                   5615:                        if (f > 0.0)
                   5616:                          snprintf(t, BUFFER_SIZE(pbuffer, t), "lat %f %c, long %f %c, alt %.2fm",
                   5617:                                  ((lat < 0.0) ? (-lat) : (lat))*RTOD, (lat < 0.0 ? 'S' : 'N'),
                   5618:                                  ((lng < 0.0) ? (-lng) : (lng))*RTOD, (lng < 0.0 ? 'W' : 'E'),
                   5619:                                  getflt((unsigned char *)&mb(8)));
                   5620:                        else
                   5621:                          return;
                   5622:                }
                   5623:                break;
                   5624: 
                   5625:                case CMD_RDOUBLEXYZ:
                   5626:                {
                   5627:                        double x = getdbl((unsigned char *)&mb(0));
                   5628:                        double y = getdbl((unsigned char *)&mb(8));
                   5629:                        double z = getdbl((unsigned char *)&mb(16));
                   5630:                        snprintf(t, BUFFER_SIZE(pbuffer, t), "x= %.1fm, y= %.1fm, z= %.1fm",
                   5631:                                x, y, z);
                   5632:                }
                   5633:                break;
                   5634:                                
                   5635:                case CMD_RDOUBLELLA:
                   5636:                {
                   5637:                        double lat = getdbl((unsigned char *)&mb(0));
                   5638:                        double lng = getdbl((unsigned char *)&mb(8));
                   5639:                        snprintf(t, BUFFER_SIZE(pbuffer, t), "lat %f %c, lon %f %c, alt %.2fm",
                   5640:                                ((lat < 0.0) ? (-lat) : (lat))*RTOD, (lat < 0.0 ? 'S' : 'N'),
                   5641:                                ((lng < 0.0) ? (-lng) : (lng))*RTOD, (lng < 0.0 ? 'W' : 'E'),
                   5642:                                getdbl((unsigned char *)&mb(16)));
                   5643:                }
                   5644:                break;
                   5645: 
                   5646:                case CMD_RALLINVIEW:
                   5647:                {
                   5648:                        int i, sats;
                   5649:                        
                   5650:                        strncpy(t, "mode: ", BUFFER_SIZE(pbuffer, t));
                   5651:                        t += strlen(t);
                   5652:                        switch (mb(0) & 0x7)
                   5653:                        {
                   5654:                        default:
                   5655:                                snprintf(t, BUFFER_SIZE(pbuffer, t), "0x%x", mb(0) & 0x7);
                   5656:                                break;
                   5657: 
                   5658:                        case 3:
                   5659:                                strncpy(t, "2D", BUFFER_SIZE(pbuffer, t));
                   5660:                                break;
                   5661:                                
                   5662:                        case 4:
                   5663:                                strncpy(t, "3D", BUFFER_SIZE(pbuffer, t));
                   5664:                                break;
                   5665:                        }
                   5666:                        t += strlen(t);
                   5667:                        if (mb(0) & 0x8)
                   5668:                                strncpy(t, "-MANUAL, ", BUFFER_SIZE(pbuffer, t));
                   5669:                        else
                   5670:                                strncpy(t, "-AUTO, ", BUFFER_SIZE(pbuffer, t));
                   5671:                        t += strlen(t);
                   5672:                        
                   5673:                        sats = (mb(0)>>4) & 0xF;
                   5674:                        
                   5675:                        snprintf(t, BUFFER_SIZE(pbuffer, t), "PDOP %.2f, HDOP %.2f, VDOP %.2f, TDOP %.2f, %d satellite%s in view: ",
                   5676:                                getflt((unsigned char *)&mb(1)),
                   5677:                                getflt((unsigned char *)&mb(5)),
                   5678:                                getflt((unsigned char *)&mb(9)),
                   5679:                                getflt((unsigned char *)&mb(13)),
                   5680:                                sats, (sats == 1) ? "" : "s");
                   5681:                        t += strlen(t);
                   5682: 
                   5683:                        for (i=0; i < sats; i++)
                   5684:                        {
                   5685:                                snprintf(t, BUFFER_SIZE(pbuffer, t), "%s%02d", i ? ", " : "", mb(17+i));
                   5686:                                t += strlen(t);
                   5687:                                if (tr)
                   5688:                                        tr->ctrack |= (1 << (mb(17+i)-1));
                   5689:                        }
                   5690: 
                   5691:                        if (tr)
                   5692:                         { /* mark for tracking status query */
                   5693:                                tr->qtracking = 1;
                   5694:                        }
                   5695:                }
                   5696:                break;
                   5697:                
                   5698:                case CMD_RSTATTRACK:
                   5699:                {
                   5700:                        snprintf(t-2, BUFFER_SIZE(pbuffer, t-2), "[%02d]=\"", mb(0)); /* add index to var name */
                   5701:                        t += strlen(t);
                   5702: 
                   5703:                        if (getflt((unsigned char *)&mb(4)) < 0.0)
                   5704:                        {
                   5705:                                strncpy(t, "<NO MEASUREMENTS>", BUFFER_SIZE(pbuffer, t));
                   5706:                                var_flag &= ~DEF;
                   5707:                        }
                   5708:                        else
                   5709:                        {       
                   5710:                                snprintf(t, BUFFER_SIZE(pbuffer, t), "ch=%d, acq=%s, eph=%d, signal_level= %5.2f, elevation= %5.2f, azimuth= %6.2f",
                   5711:                                        (mb(1) & 0xFF)>>3,
                   5712:                                        mb(2) ? ((mb(2) == 1) ? "ACQ" : "SRCH") : "NEVER",
                   5713:                                        mb(3),
                   5714:                                        getflt((unsigned char *)&mb(4)),
                   5715:                                        getflt((unsigned char *)&mb(12)) * RTOD,
                   5716:                                        getflt((unsigned char *)&mb(16)) * RTOD);
                   5717:                                t += strlen(t);
                   5718:                                if (mb(20))
                   5719:                                {
                   5720:                                        var_flag &= ~DEF;
                   5721:                                        strncpy(t, ", OLD", BUFFER_SIZE(pbuffer, t));
                   5722:                                }
                   5723:                                t += strlen(t);
                   5724:                                if (mb(22))
                   5725:                                {
                   5726:                                        if (mb(22) == 1)
                   5727:                                                strncpy(t, ", BAD PARITY", BUFFER_SIZE(pbuffer, t));
                   5728:                                        else
                   5729:                                                if (mb(22) == 2)
                   5730:                                                        strncpy(t, ", BAD EPH HEALTH", BUFFER_SIZE(pbuffer, t));
                   5731:                                }
                   5732:                                t += strlen(t);
                   5733:                                if (mb(23))
                   5734:                                        strncpy(t, ", collecting data", BUFFER_SIZE(pbuffer, t));
                   5735:                        }
                   5736:                }
                   5737:                break;
                   5738:                
                   5739:                default:
                   5740:                        strncpy(t, "<UNDECODED>", BUFFER_SIZE(pbuffer, t));
                   5741:                        break;
                   5742:                }
                   5743:                t += strlen(t);
                   5744: 
                   5745:                strncpy(t,"\"", BUFFER_SIZE(pbuffer, t));
                   5746:                set_var(&parse->kv, pbuffer, sizeof(pbuffer), var_flag);
                   5747:        }
                   5748: }
                   5749: 
                   5750: 
                   5751: /**============================================================
                   5752:  ** RAWDCF support
                   5753:  **/
                   5754: 
                   5755: /*--------------------------------------------------
                   5756:  * rawdcf_init_1 - set up modem lines for RAWDCF receivers
                   5757:  * SET DTR line
                   5758:  */
                   5759: #if defined(TIOCMSET) && (defined(TIOCM_DTR) || defined(CIOCM_DTR))
                   5760: static int
                   5761: rawdcf_init_1(
                   5762:        struct parseunit *parse
                   5763:        )
                   5764: {
                   5765:        /* fixed 2000 for using with Linux by Wolfram Pienkoss <wp@bszh.de> */
                   5766:        /*
                   5767:         * You can use the RS232 to supply the power for a DCF77 receiver.
                   5768:         * Here a voltage between the DTR and the RTS line is used. Unfortunately
                   5769:         * the name has changed from CIOCM_DTR to TIOCM_DTR recently.
                   5770:         */
                   5771:        int sl232;
                   5772: 
                   5773:        if (ioctl(parse->generic->io.fd, TIOCMGET, (caddr_t)&sl232) == -1)
                   5774:        {
                   5775:                msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_1: WARNING: ioctl(fd, TIOCMGET, [C|T]IOCM_DTR): %m", CLK_UNIT(parse->peer));
                   5776:                return 0;
                   5777:        }
                   5778: 
                   5779: #ifdef TIOCM_DTR
                   5780:        sl232 = (sl232 & ~TIOCM_RTS) | TIOCM_DTR;       /* turn on DTR, clear RTS for power supply */
                   5781: #else
                   5782:        sl232 = (sl232 & ~CIOCM_RTS) | CIOCM_DTR;       /* turn on DTR, clear RTS for power supply */
                   5783: #endif
                   5784: 
                   5785:        if (ioctl(parse->generic->io.fd, TIOCMSET, (caddr_t)&sl232) == -1)
                   5786:        {
                   5787:                msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_1: WARNING: ioctl(fd, TIOCMSET, [C|T]IOCM_DTR): %m", CLK_UNIT(parse->peer));
                   5788:        }
                   5789:        return 0;
                   5790: }
                   5791: #else
                   5792: static int
                   5793: rawdcfdtr_init_1(
                   5794:        struct parseunit *parse
                   5795:        )
                   5796: {
                   5797:        msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_1: WARNING: OS interface incapable of setting DTR to power DCF modules", CLK_UNIT(parse->peer));
                   5798:        return 0;
                   5799: }
                   5800: #endif  /* DTR initialisation type */
                   5801: 
                   5802: /*--------------------------------------------------
                   5803:  * rawdcf_init_2 - set up modem lines for RAWDCF receivers
                   5804:  * CLR DTR line, SET RTS line
                   5805:  */
                   5806: #if defined(TIOCMSET) &&  (defined(TIOCM_RTS) || defined(CIOCM_RTS))
                   5807: static int
                   5808: rawdcf_init_2(
                   5809:        struct parseunit *parse
                   5810:        )
                   5811: {
                   5812:        /* fixed 2000 for using with Linux by Wolfram Pienkoss <wp@bszh.de> */
                   5813:        /*
                   5814:         * You can use the RS232 to supply the power for a DCF77 receiver.
                   5815:         * Here a voltage between the DTR and the RTS line is used. Unfortunately
                   5816:         * the name has changed from CIOCM_DTR to TIOCM_DTR recently.
                   5817:         */
                   5818:        int sl232;
                   5819: 
                   5820:        if (ioctl(parse->generic->io.fd, TIOCMGET, (caddr_t)&sl232) == -1)
                   5821:        {
                   5822:                msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_2: WARNING: ioctl(fd, TIOCMGET, [C|T]IOCM_RTS): %m", CLK_UNIT(parse->peer));
                   5823:                return 0;
                   5824:        }
                   5825: 
                   5826: #ifdef TIOCM_RTS
                   5827:        sl232 = (sl232 & ~TIOCM_DTR) | TIOCM_RTS;       /* turn on RTS, clear DTR for power supply */
                   5828: #else
                   5829:        sl232 = (sl232 & ~CIOCM_DTR) | CIOCM_RTS;       /* turn on RTS, clear DTR for power supply */
                   5830: #endif
                   5831: 
                   5832:        if (ioctl(parse->generic->io.fd, TIOCMSET, (caddr_t)&sl232) == -1)
                   5833:        {
                   5834:                msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_2: WARNING: ioctl(fd, TIOCMSET, [C|T]IOCM_RTS): %m", CLK_UNIT(parse->peer));
                   5835:        }
                   5836:        return 0;
                   5837: }
                   5838: #else
                   5839: static int
                   5840: rawdcf_init_2(
                   5841:        struct parseunit *parse
                   5842:        )
                   5843: {
                   5844:        msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_2: WARNING: OS interface incapable of setting RTS to power DCF modules", CLK_UNIT(parse->peer));
                   5845:        return 0;
                   5846: }
                   5847: #endif  /* DTR initialisation type */
                   5848: 
                   5849: #else  /* defined(REFCLOCK) && defined(PARSE) */
                   5850: int refclock_parse_bs;
                   5851: #endif /* defined(REFCLOCK) && defined(PARSE) */
                   5852: 
                   5853: /*
                   5854:  * History:
                   5855:  *
                   5856:  * refclock_parse.c,v
                   5857:  * Revision 4.81  2009/05/01 10:15:29  kardel
                   5858:  * use new refclock_ppsapi interface
                   5859:  *
                   5860:  * Revision 4.80  2007/08/11 12:06:29  kardel
                   5861:  * update comments wrt/ to PPS
                   5862:  *
                   5863:  * Revision 4.79  2007/08/11 11:52:23  kardel
                   5864:  * - terminate io bindings before io_closeclock() will close our file descriptor
                   5865:  *
                   5866:  * Revision 4.78  2006/12/22 20:08:27  kardel
                   5867:  * Bug 746 (RFE): add configuration for Expert mouseCLOCK USB v2.0 as mode 19
                   5868:  *
                   5869:  * Revision 4.77  2006/08/05 07:44:49  kardel
                   5870:  * support optionally separate PPS devices via /dev/refclockpps-{0..3}
                   5871:  *
                   5872:  * Revision 4.76  2006/06/22 18:40:47  kardel
                   5873:  * clean up signedness (gcc 4)
                   5874:  *
                   5875:  * Revision 4.75  2006/06/22 16:58:10  kardel
                   5876:  * Bug #632: call parse_ppsapi() in parse_ctl() when updating
                   5877:  * the PPS offset. Fix sign of offset passed to kernel.
                   5878:  *
                   5879:  * Revision 4.74  2006/06/18 21:18:37  kardel
                   5880:  * NetBSD Coverity CID 3796: possible NULL deref
                   5881:  *
                   5882:  * Revision 4.73  2006/05/26 14:23:46  kardel
                   5883:  * cleanup of copyright info
                   5884:  *
                   5885:  * Revision 4.72  2006/05/26 14:19:43  kardel
                   5886:  * cleanup of ioctl cruft
                   5887:  *
                   5888:  * Revision 4.71  2006/05/26 14:15:57  kardel
                   5889:  * delay adding refclock to async refclock io after all initializations
                   5890:  *
                   5891:  * Revision 4.70  2006/05/25 18:20:50  kardel
                   5892:  * bug #619
                   5893:  * terminate parse io engine after de-registering
                   5894:  * from refclock io engine
                   5895:  *
                   5896:  * Revision 4.69  2006/05/25 17:28:02  kardel
                   5897:  * complete refclock io structure initialization *before* inserting it into the
                   5898:  * refclock input machine (avoids null pointer deref) (bug #619)
                   5899:  *
                   5900:  * Revision 4.68  2006/05/01 17:02:51  kardel
                   5901:  * copy receiver method also for newlwy created receive buffers
                   5902:  *
                   5903:  * Revision 4.67  2006/05/01 14:37:29  kardel
                   5904:  * If an input buffer parses into more than one message do insert the
                   5905:  * parsed message in a new input buffer instead of processing it
                   5906:  * directly. This avoids deed complicated processing in signal
                   5907:  * handling.
                   5908:  *
                   5909:  * Revision 4.66  2006/03/18 00:45:30  kardel
                   5910:  * coverity fixes found in NetBSD coverity scan
                   5911:  *
                   5912:  * Revision 4.65  2006/01/26 06:08:33  kardel
                   5913:  * output errno on PPS setup failure
                   5914:  *
                   5915:  * Revision 4.64  2005/11/09 20:44:47  kardel
                   5916:  * utilize full PPS timestamp resolution from PPS API
                   5917:  *
                   5918:  * Revision 4.63  2005/10/07 22:10:25  kardel
                   5919:  * bounded buffer implementation
                   5920:  *
                   5921:  * Revision 4.62.2.2  2005/09/25 10:20:16  kardel
                   5922:  * avoid unexpected buffer overflows due to sprintf("%f") on strange floats:
                   5923:  * replace almost all str* and *printf functions be their buffer bounded
                   5924:  * counterparts
                   5925:  *
                   5926:  * Revision 4.62.2.1  2005/08/27 16:19:27  kardel
                   5927:  * limit re-set rate of trimble clocks
                   5928:  *
                   5929:  * Revision 4.62  2005/08/06 17:40:00  kardel
                   5930:  * cleanup size handling wrt/ to buffer boundaries
                   5931:  *
                   5932:  * Revision 4.61  2005/07/27 21:16:19  kardel
                   5933:  * fix a long (> 11 years) misconfiguration wrt/ Meinberg cflag factory
                   5934:  * default setup. CSTOPB was missing for the 7E2 default data format of
                   5935:  * the DCF77 clocks.
                   5936:  *
                   5937:  * Revision 4.60  2005/07/17 21:14:44  kardel
                   5938:  * change contents of version string to include the RCS/CVS Id
                   5939:  *
                   5940:  * Revision 4.59  2005/07/06 06:56:38  kardel
                   5941:  * syntax error
                   5942:  *
                   5943:  * Revision 4.58  2005/07/04 13:10:40  kardel
                   5944:  * fix bug 455: tripping over NULL pointer on cleanup
                   5945:  * fix shadow storage logic for ppsphaseadjust and trustime wrt/ time2
                   5946:  * fix compiler warnings for some platforms wrt/ printf formatstrings and
                   5947:  *     varying structure element sizes
                   5948:  * reorder assignment in binding to avoid tripping over NULL pointers
                   5949:  *
                   5950:  * Revision 4.57  2005/06/25 09:25:19  kardel
                   5951:  * sort out log output sequence
                   5952:  *
                   5953:  * Revision 4.56  2005/06/14 21:47:27  kardel
                   5954:  * collect samples only if samples are ok (sync or trusted flywheel)
                   5955:  * propagate pps phase adjustment value to kernel via PPSAPI to help HARDPPS
                   5956:  * en- and dis-able HARDPPS in correlation to receiver sync state
                   5957:  *
                   5958:  * Revision 4.55  2005/06/02 21:28:31  kardel
                   5959:  * clarify trust logic
                   5960:  *
                   5961:  * Revision 4.54  2005/06/02 17:06:49  kardel
                   5962:  * change status reporting to use fixed refclock_report()
                   5963:  *
                   5964:  * Revision 4.53  2005/06/02 16:33:31  kardel
                   5965:  * fix acceptance of clocks unsync clocks right at start
                   5966:  *
                   5967:  * Revision 4.52  2005/05/26 21:55:06  kardel
                   5968:  * cleanup status reporting
                   5969:  *
                   5970:  * Revision 4.51  2005/05/26 19:19:14  kardel
                   5971:  * implement fast refclock startup
                   5972:  *
                   5973:  * Revision 4.50  2005/04/16 20:51:35  kardel
                   5974:  * set pps_enable = 1 when binding a kernel PPS source
                   5975:  *
                   5976:  * Revision 4.49  2005/04/16 17:29:26  kardel
                   5977:  * add non polling clock type 18 for just listenning to Meinberg clocks
                   5978:  *
                   5979:  * Revision 4.48  2005/04/16 16:22:27  kardel
                   5980:  * bk sync 20050415 ntp-dev
                   5981:  *
                   5982:  * Revision 4.47  2004/11/29 10:42:48  kardel
                   5983:  * bk sync ntp-dev 20041129
                   5984:  *
                   5985:  * Revision 4.46  2004/11/29 10:26:29  kardel
                   5986:  * keep fudgetime2 in sync with trusttime/ppsphaseadjust depending in flag1
                   5987:  *
                   5988:  * Revision 4.45  2004/11/14 20:53:20  kardel
                   5989:  * clear PPS flags after using them
                   5990:  *
                   5991:  * Revision 4.44  2004/11/14 15:29:41  kardel
                   5992:  * support PPSAPI, upgrade Copyright to Berkeley style
                   5993:  *
                   5994:  * Revision 4.43  2001/05/26 22:53:16  kardel
                   5995:  * 20010526 reconcilation
                   5996:  *
                   5997:  * Revision 4.42  2000/05/14 15:31:51  kardel
                   5998:  * PPSAPI && RAWDCF modemline support
                   5999:  *
                   6000:  * Revision 4.41  2000/04/09 19:50:45  kardel
                   6001:  * fixed rawdcfdtr_init() -> rawdcf_init_1
                   6002:  *
                   6003:  * Revision 4.40  2000/04/09 15:27:55  kardel
                   6004:  * modem line fiddle in rawdcf_init_2
                   6005:  *
                   6006:  * Revision 4.39  2000/03/18 09:16:55  kardel
                   6007:  * PPSAPI integration
                   6008:  *
                   6009:  * Revision 4.38  2000/03/05 20:25:06  kardel
                   6010:  * support PPSAPI
                   6011:  *
                   6012:  * Revision 4.37  2000/03/05 20:11:14  kardel
                   6013:  * 4.0.99g reconcilation
                   6014:  *
                   6015:  * Revision 4.36  1999/11/28 17:18:20  kardel
                   6016:  * disabled burst mode
                   6017:  *
                   6018:  * Revision 4.35  1999/11/28 09:14:14  kardel
                   6019:  * RECON_4_0_98F
                   6020:  *
                   6021:  * Revision 4.34  1999/05/14 06:08:05  kardel
                   6022:  * store current_time in a suitable container (u_long)
                   6023:  *
                   6024:  * Revision 4.33  1999/05/13 21:48:38  kardel
                   6025:  * double the no response timeout interval
                   6026:  *
                   6027:  * Revision 4.32  1999/05/13 20:09:13  kardel
                   6028:  * complain only about missing polls after a full poll interval
                   6029:  *
                   6030:  * Revision 4.31  1999/05/13 19:59:32  kardel
                   6031:  * add clock type 16 for RTS set DTR clr in RAWDCF
                   6032:  *
                   6033:  * Revision 4.30  1999/02/28 20:36:43  kardel
                   6034:  * fixed printf fmt
                   6035:  *
                   6036:  * Revision 4.29  1999/02/28 19:58:23  kardel
                   6037:  * updated copyright information
                   6038:  *
                   6039:  * Revision 4.28  1999/02/28 19:01:50  kardel
                   6040:  * improved debug out on sent Meinberg messages
                   6041:  *
                   6042:  * Revision 4.27  1999/02/28 18:05:55  kardel
                   6043:  * no linux/ppsclock.h stuff
                   6044:  *
                   6045:  * Revision 4.26  1999/02/28 15:27:27  kardel
                   6046:  * wharton clock integration
                   6047:  *
                   6048:  * Revision 4.25  1999/02/28 14:04:46  kardel
                   6049:  * added missing double quotes to UTC information string
                   6050:  *
                   6051:  * Revision 4.24  1999/02/28 12:06:50  kardel
                   6052:  * (parse_control): using gmprettydate instead of prettydate()
                   6053:  * (mk_utcinfo): new function for formatting GPS derived UTC information
                   6054:  * (gps16x_message): changed to use mk_utcinfo()
                   6055:  * (trimbletsip_message): changed to use mk_utcinfo()
                   6056:  * ignoring position information in unsynchronized mode
                   6057:  * (parse_start): augument linux support for optional ASYNC_LOW_LATENCY
                   6058:  *
                   6059:  * Revision 4.23  1999/02/23 19:47:53  kardel
                   6060:  * fixed #endifs
                   6061:  * (stream_receive): fixed formats
                   6062:  *
                   6063:  * Revision 4.22  1999/02/22 06:21:02  kardel
                   6064:  * use new autoconfig symbols
                   6065:  *
                   6066:  * Revision 4.21  1999/02/21 12:18:13  kardel
                   6067:  * 4.91f reconcilation
                   6068:  *
                   6069:  * Revision 4.20  1999/02/21 10:53:36  kardel
                   6070:  * initial Linux PPSkit version
                   6071:  *
                   6072:  * Revision 4.19  1999/02/07 09:10:45  kardel
                   6073:  * clarify STREAMS mitigation rules in comment
                   6074:  *
                   6075:  * Revision 4.18  1998/12/20 23:45:34  kardel
                   6076:  * fix types and warnings
                   6077:  *
                   6078:  * Revision 4.17  1998/11/15 21:24:51  kardel
                   6079:  * cannot access mbg_ routines when CLOCK_MEINBERG
                   6080:  * is not defined
                   6081:  *
                   6082:  * Revision 4.16  1998/11/15 20:28:17  kardel
                   6083:  * Release 4.0.73e13 reconcilation
                   6084:  *
                   6085:  * Revision 4.15  1998/08/22 21:56:08  kardel
                   6086:  * fixed IO handling for non-STREAM IO
                   6087:  *
                   6088:  * Revision 4.14  1998/08/16 19:00:48  kardel
                   6089:  * (gps16x_message): reduced UTC parameter information (dropped A0,A1)
                   6090:  * made uval a local variable (killed one of the last globals)
                   6091:  * (sendetx): added logging of messages when in debug mode
                   6092:  * (trimble_check): added periodic checks to facilitate re-initialization
                   6093:  * (trimbletsip_init): made use of EOL character if in non-kernel operation
                   6094:  * (trimbletsip_message): extended message interpretation
                   6095:  * (getdbl): fixed data conversion
                   6096:  *
                   6097:  * Revision 4.13  1998/08/09 22:29:13  kardel
                   6098:  * Trimble TSIP support
                   6099:  *
                   6100:  * Revision 4.12  1998/07/11 10:05:34  kardel
                   6101:  * Release 4.0.73d reconcilation
                   6102:  *
                   6103:  * Revision 4.11  1998/06/14 21:09:42  kardel
                   6104:  * Sun acc cleanup
                   6105:  *
                   6106:  * Revision 4.10  1998/06/13 12:36:45  kardel
                   6107:  * signed/unsigned, name clashes
                   6108:  *
                   6109:  * Revision 4.9  1998/06/12 15:30:00  kardel
                   6110:  * prototype fixes
                   6111:  *
                   6112:  * Revision 4.8  1998/06/12 11:19:42  kardel
                   6113:  * added direct input processing routine for refclocks in
                   6114:  * order to avaiod that single character io gobbles up all
                   6115:  * receive buffers and drops input data. (Problem started
                   6116:  * with fast machines so a character a buffer was possible
                   6117:  * one of the few cases where faster machines break existing
                   6118:  * allocation algorithms)
                   6119:  *
                   6120:  * Revision 4.7  1998/06/06 18:35:20  kardel
                   6121:  * (parse_start): added BURST mode initialisation
                   6122:  *
                   6123:  * Revision 4.6  1998/05/27 06:12:46  kardel
                   6124:  * RAWDCF_BASEDELAY default added
                   6125:  * old comment removed
                   6126:  * casts for ioctl()
                   6127:  *
                   6128:  * Revision 4.5  1998/05/25 22:05:09  kardel
                   6129:  * RAWDCF_SETDTR option removed
                   6130:  * clock type 14 attempts to set DTR for
                   6131:  * power supply of RAWDCF receivers
                   6132:  *
                   6133:  * Revision 4.4  1998/05/24 16:20:47  kardel
                   6134:  * updated comments referencing Meinberg clocks
                   6135:  * added RAWDCF clock with DTR set option as type 14
                   6136:  *
                   6137:  * Revision 4.3  1998/05/24 10:48:33  kardel
                   6138:  * calibrated CONRAD RAWDCF default fudge factor
                   6139:  *
                   6140:  * Revision 4.2  1998/05/24 09:59:35  kardel
                   6141:  * corrected version information (ntpq support)
                   6142:  *
                   6143:  * Revision 4.1  1998/05/24 09:52:31  kardel
                   6144:  * use fixed format only (new IO model)
                   6145:  * output debug to stdout instead of msyslog()
                   6146:  * don't include >"< in ASCII output in order not to confuse
                   6147:  * ntpq parsing
                   6148:  *
                   6149:  * Revision 4.0  1998/04/10 19:52:11  kardel
                   6150:  * Start 4.0 release version numbering
                   6151:  *
                   6152:  * Revision 1.2  1998/04/10 19:28:04  kardel
                   6153:  * initial NTP VERSION 4 integration of PARSE with GPS166 binary support
                   6154:  * derived from 3.105.1.2 from V3 tree
                   6155:  *
                   6156:  * Revision information 3.1 - 3.105 from log deleted 1998/04/10 kardel
                   6157:  *
                   6158:  */

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