File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / ntp / ntpd / refclock_parse.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue May 29 12:08:37 2012 UTC (12 years, 2 months ago) by misho
Branches: ntp, MAIN
CVS tags: v4_2_6p5p0, v4_2_6p5, HEAD
ntp 4.2.6p5

    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>