PageRenderTime 114ms CodeModel.GetById 22ms app.highlight 75ms RepoModel.GetById 1ms app.codeStats 1ms

/contrib/ntp/ntpd/refclock_parse.c

https://bitbucket.org/freebsd/freebsd-head/
C | 6045 lines | 5010 code | 328 blank | 707 comment | 147 complexity | a9fc6f6dec53b0ddcd71ea98b160bb1f MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   1/*
   2 * /src/NTP/REPOSITORY/ntp4-dev/ntpd/refclock_parse.c,v 4.80 2007/08/11 12:06:29 kardel Exp
   3 *
   4 * refclock_parse.c,v 4.80 2007/08/11 12:06:29 kardel Exp
   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-2007 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#endif
 145
 146#ifdef PPS
 147# ifdef HAVE_SYS_PPSCLOCK_H
 148#  include <sys/ppsclock.h>
 149# endif
 150# ifdef HAVE_TIO_SERIAL_STUFF
 151#  include <linux/serial.h>
 152# endif
 153#endif
 154
 155#define BUFFER_SIZE(_BUF, _PTR) ((_BUF) + sizeof(_BUF) - (_PTR))
 156#define BUFFER_SIZES(_BUF, _PTR, _SZ) ((_BUF) + (_SZ) - (_PTR))
 157
 158/*
 159 * document type of PPS interfacing - copy of ifdef mechanism in local_input()
 160 */
 161#undef PPS_METHOD 
 162
 163#ifdef HAVE_PPSAPI
 164#define PPS_METHOD "PPS API"
 165#else
 166#ifdef TIOCDCDTIMESTAMP
 167#define PPS_METHOD "TIOCDCDTIMESTAMP"
 168#else /* TIOCDCDTIMESTAMP */
 169#if defined(HAVE_STRUCT_PPSCLOCKEV) && (defined(HAVE_CIOGETEV) || defined(HAVE_TIOCGPPSEV))
 170#ifdef HAVE_CIOGETEV
 171#define PPS_METHOD "CIOGETEV"
 172#endif
 173#ifdef HAVE_TIOCGPPSEV
 174#define PPS_METHOD "TIOCGPPSEV"
 175#endif
 176#endif
 177#endif /* TIOCDCDTIMESTAMP */
 178#endif /* HAVE_PPSAPI */
 179
 180#include "ntp_io.h"
 181#include "ntp_stdlib.h"
 182
 183#include "parse.h"
 184#include "mbg_gps166.h"
 185#include "trimble.h"
 186#include "binio.h"
 187#include "ascii.h"
 188#include "ieee754io.h"
 189#include "recvbuff.h"
 190
 191static char rcsid[] = "refclock_parse.c,v 4.80 2007/08/11 12:06:29 kardel Exp";
 192
 193/**===========================================================================
 194 ** external interface to ntp mechanism
 195 **/
 196
 197static	int	parse_start	P((int, struct peer *));
 198static	void	parse_shutdown	P((int, struct peer *));
 199static	void	parse_poll	P((int, struct peer *));
 200static	void	parse_control	P((int, struct refclockstat *, struct refclockstat *, struct peer *));
 201
 202struct	refclock refclock_parse = {
 203	parse_start,
 204	parse_shutdown,
 205	parse_poll,
 206	parse_control,
 207	noentry,
 208	noentry,
 209	NOFLAGS
 210};
 211
 212/*
 213 * Definitions
 214 */
 215#define	MAXUNITS	4	/* maximum number of "PARSE" units permitted */
 216#define PARSEDEVICE	"/dev/refclock-%d" /* device to open %d is unit number */
 217#define PARSEPPSDEVICE	"/dev/refclockpps-%d" /* optional pps device to open %d is unit number */
 218
 219#undef ABS
 220#define ABS(_X_) (((_X_) < 0) ? -(_X_) : (_X_))
 221
 222#define PARSE_HARDPPS_DISABLE 0
 223#define PARSE_HARDPPS_ENABLE  1
 224
 225/**===========================================================================
 226 ** function vector for dynamically binding io handling mechanism
 227 **/
 228
 229struct parseunit;		/* to keep inquiring minds happy */
 230
 231typedef struct bind
 232{
 233  const char *bd_description;	                                /* name of type of binding */
 234  int	(*bd_init)     P((struct parseunit *));			/* initialize */
 235  void	(*bd_end)      P((struct parseunit *));			/* end */
 236  int   (*bd_setcs)    P((struct parseunit *, parsectl_t *));	/* set character size */
 237  int	(*bd_disable)  P((struct parseunit *));			/* disable */
 238  int	(*bd_enable)   P((struct parseunit *));			/* enable */
 239  int	(*bd_getfmt)   P((struct parseunit *, parsectl_t *));	/* get format */
 240  int	(*bd_setfmt)   P((struct parseunit *, parsectl_t *));	/* setfmt */
 241  int	(*bd_timecode) P((struct parseunit *, parsectl_t *));	/* get time code */
 242  void	(*bd_receive)  P((struct recvbuf *));			/* receive operation */
 243  int	(*bd_io_input) P((struct recvbuf *));			/* input operation */
 244} bind_t;
 245
 246#define PARSE_END(_X_)			(*(_X_)->binding->bd_end)(_X_)
 247#define PARSE_SETCS(_X_, _CS_)		(*(_X_)->binding->bd_setcs)(_X_, _CS_)
 248#define PARSE_ENABLE(_X_)		(*(_X_)->binding->bd_enable)(_X_)
 249#define PARSE_DISABLE(_X_)		(*(_X_)->binding->bd_disable)(_X_)
 250#define PARSE_GETFMT(_X_, _DCT_)	(*(_X_)->binding->bd_getfmt)(_X_, _DCT_)
 251#define PARSE_SETFMT(_X_, _DCT_)	(*(_X_)->binding->bd_setfmt)(_X_, _DCT_)
 252#define PARSE_GETTIMECODE(_X_, _DCT_)	(*(_X_)->binding->bd_timecode)(_X_, _DCT_)
 253
 254/*
 255 * io modes
 256 */
 257#define PARSE_F_PPSPPS		0x0001 /* use loopfilter PPS code (CIOGETEV) */
 258#define PARSE_F_PPSONSECOND	0x0002 /* PPS pulses are on second */
 259
 260
 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
 289struct errorregression
 290{
 291	u_long err_count;	/* number of repititions per class */
 292	u_long err_delay;	/* minimum delay between messages */
 293};
 294
 295static struct errorregression
 296err_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
 304static struct errorregression
 305err_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
 313static struct errorregression
 314err_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
 322static struct errorregression
 323err_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
 331static struct errorregression
 332err_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
 340static struct errorregression
 341err_internal[] =		/* really bad things - basically coding/OS errors */
 342{
 343	{ 0,       0 },		/* output all messages immediately */
 344};
 345
 346static struct errorregression *
 347err_tbl[] =
 348{
 349	err_baddata,
 350	err_nodata,
 351	err_badio,
 352	err_badstatus,
 353	err_badevent,
 354	err_internal
 355};
 356
 357struct 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
 370struct 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        pps_handle_t  ppshandle;        /* store PPSAPI handle */
 409        pps_params_t  ppsparams;        /* current PPS parameters */
 410        int           hardppsstate;     /* current hard pps state */
 411#endif
 412	parsetime_t   timedata;		/* last (parse module) data */
 413	void         *localdata;        /* optional local, receiver-specific data */
 414        unsigned long localstate;       /* private local state */
 415	struct errorinfo errors[ERR_CNT];  /* error state table for suppressing excessive error messages */
 416	struct ctl_var *kv;	        /* additional pseudo variables */
 417	u_long        laststatistic;    /* time when staticstics where output */
 418};
 419
 420
 421/**===========================================================================
 422 ** Clockinfo section all parameter for specific clock types
 423 ** includes NTP parameters, TTY parameters and IO handling parameters
 424 **/
 425
 426static	void	poll_dpoll	P((struct parseunit *));
 427static	void	poll_poll	P((struct peer *));
 428static	int	poll_init	P((struct parseunit *));
 429
 430typedef struct poll_info
 431{
 432	u_long      rate;		/* poll rate - once every "rate" seconds - 0 off */
 433	const char *string;		/* string to send for polling */
 434	u_long      count;		/* number of characters in string */
 435} poll_info_t;
 436
 437#define NO_CL_FLAGS	0
 438#define NO_POLL		0
 439#define NO_INIT		0
 440#define NO_END		0
 441#define NO_EVENT	0
 442#define NO_LCLDATA	0
 443#define NO_MESSAGE	0
 444#define NO_PPSDELAY     0
 445
 446#define DCF_ID		"DCF"	/* generic DCF */
 447#define DCF_A_ID	"DCFa"	/* AM demodulation */
 448#define DCF_P_ID	"DCFp"	/* psuedo random phase shift */
 449#define GPS_ID		"GPS"	/* GPS receiver */
 450
 451#define	NOCLOCK_ROOTDELAY	0.0
 452#define	NOCLOCK_BASEDELAY	0.0
 453#define	NOCLOCK_DESCRIPTION	0
 454#define NOCLOCK_MAXUNSYNC       0
 455#define NOCLOCK_CFLAG           0
 456#define NOCLOCK_IFLAG           0
 457#define NOCLOCK_OFLAG           0
 458#define NOCLOCK_LFLAG           0
 459#define NOCLOCK_ID		"TILT"
 460#define NOCLOCK_POLL		NO_POLL
 461#define NOCLOCK_INIT		NO_INIT
 462#define NOCLOCK_END		NO_END
 463#define NOCLOCK_DATA		NO_LCLDATA
 464#define NOCLOCK_FORMAT		""
 465#define NOCLOCK_TYPE		CTL_SST_TS_UNSPEC
 466#define NOCLOCK_SAMPLES		0
 467#define NOCLOCK_KEEP		0 
 468
 469#define DCF_TYPE		CTL_SST_TS_LF
 470#define GPS_TYPE		CTL_SST_TS_UHF
 471
 472/*
 473 * receiver specific constants
 474 */
 475#define MBG_SPEED		(B9600)
 476#define MBG_CFLAG		(CS7|PARENB|CREAD|CLOCAL|HUPCL|CSTOPB)
 477#define MBG_IFLAG		(IGNBRK|IGNPAR|ISTRIP)
 478#define MBG_OFLAG		0
 479#define MBG_LFLAG		0
 480#define MBG_FLAGS               PARSE_F_PPSONSECOND
 481
 482/*
 483 * Meinberg DCF77 receivers
 484 */
 485#define	DCFUA31_ROOTDELAY	0.0  /* 0 */
 486#define	DCFUA31_BASEDELAY	0.010  /* 10.7421875ms: 10 ms (+/- 3 ms) */
 487#define	DCFUA31_DESCRIPTION	"Meinberg DCF77 C51 or compatible"
 488#define DCFUA31_MAXUNSYNC       60*30       /* only trust clock for 1/2 hour */
 489#define DCFUA31_SPEED		MBG_SPEED
 490#define DCFUA31_CFLAG           MBG_CFLAG
 491#define DCFUA31_IFLAG           MBG_IFLAG
 492#define DCFUA31_OFLAG           MBG_OFLAG
 493#define DCFUA31_LFLAG           MBG_LFLAG
 494#define DCFUA31_SAMPLES		5
 495#define DCFUA31_KEEP		3
 496#define DCFUA31_FORMAT		"Meinberg Standard"
 497
 498/*
 499 * Meinberg DCF PZF535/TCXO (FM/PZF) receiver
 500 */
 501#define	DCFPZF535_ROOTDELAY	0.0
 502#define	DCFPZF535_BASEDELAY	0.001968  /* 1.968ms +- 104us (oscilloscope) - relative to start (end of STX) */
 503#define	DCFPZF535_DESCRIPTION	"Meinberg DCF PZF 535/509 / TCXO"
 504#define DCFPZF535_MAXUNSYNC     60*60*12           /* only trust clock for 12 hours
 505						    * @ 5e-8df/f we have accumulated
 506						    * at most 2.16 ms (thus we move to
 507						    * NTP synchronisation */
 508#define DCFPZF535_SPEED		MBG_SPEED
 509#define DCFPZF535_CFLAG         MBG_CFLAG
 510#define DCFPZF535_IFLAG         MBG_IFLAG
 511#define DCFPZF535_OFLAG         MBG_OFLAG
 512#define DCFPZF535_LFLAG         MBG_LFLAG
 513#define DCFPZF535_SAMPLES	       5
 514#define DCFPZF535_KEEP		       3
 515#define DCFPZF535_FORMAT	"Meinberg Standard"
 516
 517/*
 518 * Meinberg DCF PZF535/OCXO receiver
 519 */
 520#define	DCFPZF535OCXO_ROOTDELAY	0.0
 521#define	DCFPZF535OCXO_BASEDELAY	0.001968 /* 1.968ms +- 104us (oscilloscope) - relative to start (end of STX) */
 522#define	DCFPZF535OCXO_DESCRIPTION "Meinberg DCF PZF 535/509 / OCXO"
 523#define DCFPZF535OCXO_MAXUNSYNC     60*60*96       /* only trust clock for 4 days
 524						    * @ 5e-9df/f we have accumulated
 525						    * at most an error of 1.73 ms
 526						    * (thus we move to NTP synchronisation) */
 527#define DCFPZF535OCXO_SPEED	    MBG_SPEED
 528#define DCFPZF535OCXO_CFLAG         MBG_CFLAG
 529#define DCFPZF535OCXO_IFLAG         MBG_IFLAG
 530#define DCFPZF535OCXO_OFLAG         MBG_OFLAG
 531#define DCFPZF535OCXO_LFLAG         MBG_LFLAG
 532#define DCFPZF535OCXO_SAMPLES		   5
 533#define DCFPZF535OCXO_KEEP	           3
 534#define DCFPZF535OCXO_FORMAT	    "Meinberg Standard"
 535
 536/*
 537 * Meinberg GPS16X receiver
 538 */
 539static	void	gps16x_message	 P((struct parseunit *, parsetime_t *));
 540static  int     gps16x_poll_init P((struct parseunit *));
 541
 542#define	GPS16X_ROOTDELAY	0.0         /* nothing here */
 543#define	GPS16X_BASEDELAY	0.001968         /* XXX to be fixed ! 1.968ms +- 104us (oscilloscope) - relative to start (end of STX) */
 544#define	GPS16X_DESCRIPTION      "Meinberg GPS16x receiver"
 545#define GPS16X_MAXUNSYNC        60*60*96       /* only trust clock for 4 days
 546						* @ 5e-9df/f we have accumulated
 547						* at most an error of 1.73 ms
 548						* (thus we move to NTP synchronisation) */
 549#define GPS16X_SPEED		B19200
 550#define GPS16X_CFLAG            (CS8|CREAD|CLOCAL|HUPCL)
 551#define GPS16X_IFLAG            (IGNBRK|IGNPAR)
 552#define GPS16X_OFLAG            MBG_OFLAG
 553#define GPS16X_LFLAG            MBG_LFLAG
 554#define GPS16X_POLLRATE	6
 555#define GPS16X_POLLCMD	""
 556#define GPS16X_CMDSIZE	0
 557
 558static poll_info_t gps16x_pollinfo = { GPS16X_POLLRATE, GPS16X_POLLCMD, GPS16X_CMDSIZE };
 559
 560#define GPS16X_INIT		gps16x_poll_init
 561#define GPS16X_POLL	        0
 562#define GPS16X_END		0
 563#define GPS16X_DATA		((void *)(&gps16x_pollinfo))
 564#define GPS16X_MESSAGE		gps16x_message
 565#define GPS16X_ID		GPS_ID
 566#define GPS16X_FORMAT		"Meinberg GPS Extended"
 567#define GPS16X_SAMPLES		5
 568#define GPS16X_KEEP		3
 569
 570/*
 571 * ELV DCF7000 Wallclock-Receiver/Switching Clock (Kit)
 572 *
 573 * This is really not the hottest clock - but before you have nothing ...
 574 */
 575#define DCF7000_ROOTDELAY	0.0 /* 0 */
 576#define DCF7000_BASEDELAY	0.405 /* slow blow */
 577#define DCF7000_DESCRIPTION	"ELV DCF7000"
 578#define DCF7000_MAXUNSYNC	(60*5) /* sorry - but it just was not build as a clock */
 579#define DCF7000_SPEED		(B9600)
 580#define DCF7000_CFLAG           (CS8|CREAD|PARENB|PARODD|CLOCAL|HUPCL)
 581#define DCF7000_IFLAG		(IGNBRK)
 582#define DCF7000_OFLAG		0
 583#define DCF7000_LFLAG		0
 584#define DCF7000_SAMPLES		5
 585#define DCF7000_KEEP		3
 586#define DCF7000_FORMAT		"ELV DCF7000"
 587
 588/*
 589 * Schmid DCF Receiver Kit
 590 *
 591 * When the WSDCF clock is operating optimally we want the primary clock
 592 * distance to come out at 300 ms.  Thus, peer.distance in the WSDCF peer
 593 * structure is set to 290 ms and we compute delays which are at least
 594 * 10 ms long.  The following are 290 ms and 10 ms expressed in u_fp format
 595 */
 596#define WS_POLLRATE	1	/* every second - watch interdependency with poll routine */
 597#define WS_POLLCMD	"\163"
 598#define WS_CMDSIZE	1
 599
 600static poll_info_t wsdcf_pollinfo = { WS_POLLRATE, WS_POLLCMD, WS_CMDSIZE };
 601
 602#define WSDCF_INIT		poll_init
 603#define WSDCF_POLL		poll_dpoll
 604#define WSDCF_END		0
 605#define WSDCF_DATA		((void *)(&wsdcf_pollinfo))
 606#define	WSDCF_ROOTDELAY		0.0	/* 0 */
 607#define	WSDCF_BASEDELAY	 	0.010	/*  ~  10ms */
 608#define WSDCF_DESCRIPTION	"WS/DCF Receiver"
 609#define WSDCF_FORMAT		"Schmid"
 610#define WSDCF_MAXUNSYNC		(60*60)	/* assume this beast hold at 1 h better than 2 ms XXX-must verify */
 611#define WSDCF_SPEED		(B1200)
 612#define WSDCF_CFLAG		(CS8|CREAD|CLOCAL)
 613#define WSDCF_IFLAG		0
 614#define WSDCF_OFLAG		0
 615#define WSDCF_LFLAG		0
 616#define WSDCF_SAMPLES		5
 617#define WSDCF_KEEP		3
 618
 619/*
 620 * RAW DCF77 - input of DCF marks via RS232 - many variants
 621 */
 622#define RAWDCF_FLAGS		0
 623#define RAWDCF_ROOTDELAY	0.0 /* 0 */
 624#define RAWDCF_BASEDELAY	0.258
 625#define RAWDCF_FORMAT		"RAW DCF77 Timecode"
 626#define RAWDCF_MAXUNSYNC	(0) /* sorry - its a true receiver - no signal - no time */
 627#define RAWDCF_SPEED		(B50)
 628#ifdef NO_PARENB_IGNPAR /* Was: defined(SYS_IRIX4) || defined(SYS_IRIX5) */
 629/* somehow doesn't grok PARENB & IGNPAR (mj) */
 630# define RAWDCF_CFLAG            (CS8|CREAD|CLOCAL)
 631#else
 632# define RAWDCF_CFLAG            (CS8|CREAD|CLOCAL|PARENB)
 633#endif
 634#ifdef RAWDCF_NO_IGNPAR /* Was: defined(SYS_LINUX) && defined(CLOCK_RAWDCF) */
 635# define RAWDCF_IFLAG		0
 636#else
 637# define RAWDCF_IFLAG		(IGNPAR)
 638#endif
 639#define RAWDCF_OFLAG		0
 640#define RAWDCF_LFLAG		0
 641#define RAWDCF_SAMPLES		20
 642#define RAWDCF_KEEP		12
 643#define RAWDCF_INIT		0
 644
 645/*
 646 * RAW DCF variants
 647 */
 648/*
 649 * Conrad receiver
 650 *
 651 * simplest (cheapest) DCF clock - e. g. DCF77 receiver by Conrad
 652 * (~40DM - roughly $30 ) followed by a level converter for RS232
 653 */
 654#define CONRAD_BASEDELAY	0.292 /* Conrad receiver @ 50 Baud on a Sun */
 655#define CONRAD_DESCRIPTION	"RAW DCF77 CODE (Conrad DCF77 receiver module)"
 656
 657/* Gude Analog- und Digitalsystem GmbH 'Expert mouseCLOCK USB v2.0' */
 658#define GUDE_EMC_USB_V20_SPEED            (B4800)
 659#define GUDE_EMC_USB_V20_BASEDELAY        0.425 /* USB serial<->USB converter FTDI232R */
 660#define GUDE_EMC_USB_V20_DESCRIPTION      "RAW DCF77 CODE (Expert mouseCLOCK USB v2.0)"
 661
 662/*
 663 * TimeBrick receiver
 664 */
 665#define TIMEBRICK_BASEDELAY	0.210 /* TimeBrick @ 50 Baud on a Sun */
 666#define TIMEBRICK_DESCRIPTION	"RAW DCF77 CODE (TimeBrick)"
 667
 668/*
 669 * IGEL:clock receiver
 670 */
 671#define IGELCLOCK_BASEDELAY	0.258 /* IGEL:clock receiver */
 672#define IGELCLOCK_DESCRIPTION	"RAW DCF77 CODE (IGEL:clock)"
 673#define IGELCLOCK_SPEED		(B1200)
 674#define IGELCLOCK_CFLAG		(CS8|CREAD|HUPCL|CLOCAL)
 675
 676/*
 677 * RAWDCF receivers that need to be powered from DTR
 678 * (like Expert mouse clock)
 679 */
 680static	int	rawdcf_init_1	P((struct parseunit *));
 681#define RAWDCFDTRSET_DESCRIPTION	"RAW DCF77 CODE (DTR SET/RTS CLR)"
 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 */
 688static	int	rawdcf_init_2	P((struct parseunit *));
 689#define RAWDCFDTRCLRRTSSET_DESCRIPTION	"RAW DCF77 CODE (DTR CLR/RTS SET)"
 690#define RAWDCFDTRCLRRTSSET_INIT	rawdcf_init_2
 691
 692/*
 693 * Trimble GPS receivers (TAIP and TSIP protocols)
 694 */
 695#ifndef TRIM_POLLRATE
 696#define TRIM_POLLRATE	0	/* only true direct polling */
 697#endif
 698
 699#define TRIM_TAIPPOLLCMD	">SRM;FR_FLAG=F;EC_FLAG=F<>QTM<"
 700#define TRIM_TAIPCMDSIZE	(sizeof(TRIM_TAIPPOLLCMD)-1)
 701
 702static poll_info_t trimbletaip_pollinfo = { TRIM_POLLRATE, TRIM_TAIPPOLLCMD, TRIM_TAIPCMDSIZE };
 703static	int	trimbletaip_init	P((struct parseunit *));
 704static	void	trimbletaip_event	P((struct parseunit *, int));
 705
 706/* query time & UTC correction data */
 707static char tsipquery[] = { DLE, 0x21, DLE, ETX, DLE, 0x2F, DLE, ETX };
 708
 709static poll_info_t trimbletsip_pollinfo = { TRIM_POLLRATE, tsipquery, sizeof(tsipquery) };
 710static	int	trimbletsip_init	P((struct parseunit *));
 711static	void	trimbletsip_end   	P((struct parseunit *));
 712static	void	trimbletsip_message	P((struct parseunit *, parsetime_t *));
 713static	void	trimbletsip_event	P((struct parseunit *, int));
 714
 715#define TRIMBLETSIP_IDLE_TIME	    (300) /* 5 minutes silence at most */
 716#define TRIMBLE_RESET_HOLDOFF       TRIMBLETSIP_IDLE_TIME
 717
 718#define TRIMBLETAIP_SPEED	    (B4800)
 719#define TRIMBLETAIP_CFLAG           (CS8|CREAD|CLOCAL)
 720#define TRIMBLETAIP_IFLAG           (BRKINT|IGNPAR|ISTRIP|ICRNL|IXON)
 721#define TRIMBLETAIP_OFLAG           (OPOST|ONLCR)
 722#define TRIMBLETAIP_LFLAG           (0)
 723
 724#define TRIMBLETSIP_SPEED	    (B9600)
 725#define TRIMBLETSIP_CFLAG           (CS8|CLOCAL|CREAD|PARENB|PARODD)
 726#define TRIMBLETSIP_IFLAG           (IGNBRK)
 727#define TRIMBLETSIP_OFLAG           (0)
 728#define TRIMBLETSIP_LFLAG           (ICANON)
 729
 730#define TRIMBLETSIP_SAMPLES	    5
 731#define TRIMBLETSIP_KEEP	    3
 732#define TRIMBLETAIP_SAMPLES	    5
 733#define TRIMBLETAIP_KEEP	    3
 734
 735#define TRIMBLETAIP_FLAGS	    (PARSE_F_PPSONSECOND)
 736#define TRIMBLETSIP_FLAGS	    (TRIMBLETAIP_FLAGS)
 737
 738#define TRIMBLETAIP_POLL	    poll_dpoll
 739#define TRIMBLETSIP_POLL	    poll_dpoll
 740
 741#define TRIMBLETAIP_INIT	    trimbletaip_init
 742#define TRIMBLETSIP_INIT	    trimbletsip_init
 743
 744#define TRIMBLETAIP_EVENT	    trimbletaip_event   
 745
 746#define TRIMBLETSIP_EVENT	    trimbletsip_event   
 747#define TRIMBLETSIP_MESSAGE	    trimbletsip_message
 748
 749#define TRIMBLETAIP_END		    0
 750#define TRIMBLETSIP_END		    trimbletsip_end
 751
 752#define TRIMBLETAIP_DATA	    ((void *)(&trimbletaip_pollinfo))
 753#define TRIMBLETSIP_DATA	    ((void *)(&trimbletsip_pollinfo))
 754
 755#define TRIMBLETAIP_ID		    GPS_ID
 756#define TRIMBLETSIP_ID		    GPS_ID
 757
 758#define TRIMBLETAIP_FORMAT	    "Trimble TAIP"
 759#define TRIMBLETSIP_FORMAT	    "Trimble TSIP"
 760
 761#define TRIMBLETAIP_ROOTDELAY        0x0
 762#define TRIMBLETSIP_ROOTDELAY        0x0
 763
 764#define TRIMBLETAIP_BASEDELAY        0.0
 765#define TRIMBLETSIP_BASEDELAY        0.020	/* GPS time message latency */
 766
 767#define TRIMBLETAIP_DESCRIPTION      "Trimble GPS (TAIP) receiver"
 768#define TRIMBLETSIP_DESCRIPTION      "Trimble GPS (TSIP) receiver"
 769
 770#define TRIMBLETAIP_MAXUNSYNC        0
 771#define TRIMBLETSIP_MAXUNSYNC        0
 772
 773#define TRIMBLETAIP_EOL		    '<'
 774
 775/*
 776 * RadioCode Clocks RCC 800 receiver
 777 */
 778#define RCC_POLLRATE   0       /* only true direct polling */
 779#define RCC_POLLCMD    "\r"
 780#define RCC_CMDSIZE    1
 781
 782static poll_info_t rcc8000_pollinfo = { RCC_POLLRATE, RCC_POLLCMD, RCC_CMDSIZE };
 783#define RCC8000_FLAGS		0
 784#define RCC8000_POLL            poll_dpoll
 785#define RCC8000_INIT            poll_init
 786#define RCC8000_END             0
 787#define RCC8000_DATA            ((void *)(&rcc8000_pollinfo))
 788#define RCC8000_ROOTDELAY       0.0
 789#define RCC8000_BASEDELAY       0.0
 790#define RCC8000_ID              "MSF"
 791#define RCC8000_DESCRIPTION     "RCC 8000 MSF Receiver"
 792#define RCC8000_FORMAT          "Radiocode RCC8000"
 793#define RCC8000_MAXUNSYNC       (60*60) /* should be ok for an hour */
 794#define RCC8000_SPEED		(B2400)
 795#define RCC8000_CFLAG           (CS8|CREAD|CLOCAL)
 796#define RCC8000_IFLAG           (IGNBRK|IGNPAR)
 797#define RCC8000_OFLAG           0
 798#define RCC8000_LFLAG           0
 799#define RCC8000_SAMPLES         5
 800#define RCC8000_KEEP	        3
 801
 802/*
 803 * Hopf Radio clock 6021 Format 
 804 *
 805 */
 806#define HOPF6021_ROOTDELAY	0.0
 807#define HOPF6021_BASEDELAY	0.0
 808#define HOPF6021_DESCRIPTION	"HOPF 6021"
 809#define HOPF6021_FORMAT         "hopf Funkuhr 6021"
 810#define HOPF6021_MAXUNSYNC	(60*60)  /* should be ok for an hour */
 811#define HOPF6021_SPEED         (B9600)
 812#define HOPF6021_CFLAG          (CS8|CREAD|CLOCAL)
 813#define HOPF6021_IFLAG		(IGNBRK|ISTRIP)
 814#define HOPF6021_OFLAG		0
 815#define HOPF6021_LFLAG		0
 816#define HOPF6021_FLAGS          0
 817#define HOPF6021_SAMPLES        5
 818#define HOPF6021_KEEP	        3
 819
 820/*
 821 * Diem's Computime Radio Clock Receiver
 822 */
 823#define COMPUTIME_FLAGS       0
 824#define COMPUTIME_ROOTDELAY   0.0
 825#define COMPUTIME_BASEDELAY   0.0
 826#define COMPUTIME_ID          DCF_ID
 827#define COMPUTIME_DESCRIPTION "Diem's Computime receiver"
 828#define COMPUTIME_FORMAT      "Diem's Computime Radio Clock"
 829#define COMPUTIME_TYPE        DCF_TYPE
 830#define COMPUTIME_MAXUNSYNC   (60*60)       /* only trust clock for 1 hour */
 831#define COMPUTIME_SPEED       (B9600)
 832#define COMPUTIME_CFLAG       (CSTOPB|CS7|CREAD|CLOCAL)
 833#define COMPUTIME_IFLAG       (IGNBRK|IGNPAR|ISTRIP)
 834#define COMPUTIME_OFLAG       0
 835#define COMPUTIME_LFLAG       0
 836#define COMPUTIME_SAMPLES     5
 837#define COMPUTIME_KEEP        3
 838
 839/*
 840 * Varitext Radio Clock Receiver
 841 */
 842#define VARITEXT_FLAGS       0
 843#define VARITEXT_ROOTDELAY   0.0
 844#define VARITEXT_BASEDELAY   0.0
 845#define VARITEXT_ID          "MSF"
 846#define VARITEXT_DESCRIPTION "Varitext receiver"
 847#define VARITEXT_FORMAT      "Varitext Radio Clock"
 848#define VARITEXT_TYPE        DCF_TYPE
 849#define VARITEXT_MAXUNSYNC   (60*60)       /* only trust clock for 1 hour */
 850#define VARITEXT_SPEED       (B9600)
 851#define VARITEXT_CFLAG       (CS7|CREAD|CLOCAL|PARENB|PARODD)
 852#define VARITEXT_IFLAG       (IGNPAR|IGNBRK|INPCK) /*|ISTRIP)*/
 853#define VARITEXT_OFLAG       0
 854#define VARITEXT_LFLAG       0
 855#define VARITEXT_SAMPLES     32
 856#define VARITEXT_KEEP        20
 857
 858static struct parse_clockinfo
 859{
 860	u_long  cl_flags;		/* operation flags (io modes) */
 861  void  (*cl_poll)    P((struct parseunit *));			/* active poll routine */
 862  int   (*cl_init)    P((struct parseunit *));			/* active poll init routine */
 863  void  (*cl_event)   P((struct parseunit *, int));		/* special event handling (e.g. reset clock) */
 864  void  (*cl_end)     P((struct parseunit *));			/* active poll end routine */
 865  void  (*cl_message) P((struct parseunit *, parsetime_t *));	/* process a lower layer message */
 866	void   *cl_data;		/* local data area for "poll" mechanism */
 867	double    cl_rootdelay;		/* rootdelay */
 868	double    cl_basedelay;		/* current offset by which the RS232
 869				time code is delayed from the actual time */
 870	const char *cl_id;		/* ID code */
 871	const char *cl_description;		/* device name */
 872	const char *cl_format;		/* fixed format */
 873	u_char  cl_type;		/* clock type (ntp control) */
 874	u_long  cl_maxunsync;		/* time to trust oscillator after losing synch */
 875	u_long  cl_speed;		/* terminal input & output baudrate */
 876	u_long  cl_cflag;             /* terminal control flags */
 877	u_long  cl_iflag;             /* terminal input flags */
 878	u_long  cl_oflag;             /* terminal output flags */
 879	u_long  cl_lflag;             /* terminal local flags */
 880	u_long  cl_samples;	      /* samples for median filter */
 881	u_long  cl_keep;              /* samples for median filter to keep */
 882} parse_clockinfo[] =
 883{
 884	{				/* mode 0 */
 885		MBG_FLAGS,
 886		NO_POLL,
 887		NO_INIT,
 888		NO_EVENT,
 889		NO_END,
 890		NO_MESSAGE,
 891		NO_LCLDATA,
 892		DCFPZF535_ROOTDELAY,
 893		DCFPZF535_BASEDELAY,
 894		DCF_P_ID,
 895		DCFPZF535_DESCRIPTION,
 896		DCFPZF535_FORMAT,
 897		DCF_TYPE,
 898		DCFPZF535_MAXUNSYNC,
 899		DCFPZF535_SPEED,
 900		DCFPZF535_CFLAG,
 901		DCFPZF535_IFLAG,
 902		DCFPZF535_OFLAG,
 903		DCFPZF535_LFLAG,
 904		DCFPZF535_SAMPLES,
 905		DCFPZF535_KEEP
 906	},
 907	{				/* mode 1 */
 908		MBG_FLAGS,
 909		NO_POLL,
 910		NO_INIT,
 911		NO_EVENT,
 912		NO_END,
 913		NO_MESSAGE,
 914		NO_LCLDATA,
 915		DCFPZF535OCXO_ROOTDELAY,
 916		DCFPZF535OCXO_BASEDELAY,
 917		DCF_P_ID,
 918		DCFPZF535OCXO_DESCRIPTION,
 919		DCFPZF535OCXO_FORMAT,
 920		DCF_TYPE,
 921		DCFPZF535OCXO_MAXUNSYNC,
 922		DCFPZF535OCXO_SPEED,
 923		DCFPZF535OCXO_CFLAG,
 924		DCFPZF535OCXO_IFLAG,
 925		DCFPZF535OCXO_OFLAG,
 926		DCFPZF535OCXO_LFLAG,
 927		DCFPZF535OCXO_SAMPLES,
 928		DCFPZF535OCXO_KEEP
 929	},
 930	{				/* mode 2 */
 931		MBG_FLAGS,
 932		NO_POLL,
 933		NO_INIT,
 934		NO_EVENT,
 935		NO_END,
 936		NO_MESSAGE,
 937		NO_LCLDATA,
 938		DCFUA31_ROOTDELAY,
 939		DCFUA31_BASEDELAY,
 940		DCF_A_ID,
 941		DCFUA31_DESCRIPTION,
 942		DCFUA31_FORMAT,
 943		DCF_TYPE,
 944		DCFUA31_MAXUNSYNC,
 945		DCFUA31_SPEED,
 946		DCFUA31_CFLAG,
 947		DCFUA31_IFLAG,
 948		DCFUA31_OFLAG,
 949		DCFUA31_LFLAG,
 950		DCFUA31_SAMPLES,
 951		DCFUA31_KEEP
 952	},
 953	{				/* mode 3 */
 954		MBG_FLAGS,
 955		NO_POLL,
 956		NO_INIT,
 957		NO_EVENT,
 958		NO_END,
 959		NO_MESSAGE,
 960		NO_LCLDATA,
 961		DCF7000_ROOTDELAY,
 962		DCF7000_BASEDELAY,
 963		DCF_A_ID,
 964		DCF7000_DESCRIPTION,
 965		DCF7000_FORMAT,
 966		DCF_TYPE,
 967		DCF7000_MAXUNSYNC,
 968		DCF7000_SPEED,
 969		DCF7000_CFLAG,
 970		DCF7000_IFLAG,
 971		DCF7000_OFLAG,
 972		DCF7000_LFLAG,
 973		DCF7000_SAMPLES,
 974		DCF7000_KEEP
 975	},
 976	{				/* mode 4 */
 977		NO_CL_FLAGS,
 978		WSDCF_POLL,
 979		WSDCF_INIT,
 980		NO_EVENT,
 981		WSDCF_END,
 982		NO_MESSAGE,
 983		WSDCF_DATA,
 984		WSDCF_ROOTDELAY,
 985		WSDCF_BASEDELAY,
 986		DCF_A_ID,
 987		WSDCF_DESCRIPTION,
 988		WSDCF_FORMAT,
 989		DCF_TYPE,
 990		WSDCF_MAXUNSYNC,
 991		WSDCF_SPEED,
 992		WSDCF_CFLAG,
 993		WSDCF_IFLAG,
 994		WSDCF_OFLAG,
 995		WSDCF_LFLAG,
 996		WSDCF_SAMPLES,
 997		WSDCF_KEEP
 998	},
 999	{				/* mode 5 */
1000		RAWDCF_FLAGS,
1001		NO_POLL,
1002		RAWDCF_INIT,
1003		NO_EVENT,
1004		NO_END,
1005		NO_MESSAGE,
1006		NO_LCLDATA,
1007		RAWDCF_ROOTDELAY,
1008		CONRAD_BASEDELAY,
1009		DCF_A_ID,
1010		CONRAD_DESCRIPTION,
1011		RAWDCF_FORMAT,
1012		DCF_TYPE,
1013		RAWDCF_MAXUNSYNC,
1014		RAWDCF_SPEED,
1015		RAWDCF_CFLAG,
1016		RAWDCF_IFLAG,
1017		RAWDCF_OFLAG,
1018		RAWDCF_LFLAG,
1019		RAWDCF_SAMPLES,
1020		RAWDCF_KEEP
1021	},
1022	{				/* mode 6 */
1023		RAWDCF_FLAGS,
1024		NO_POLL,
1025		RAWDCF_INIT,
1026		NO_EVENT,
1027		NO_END,
1028		NO_MESSAGE,
1029		NO_LCLDATA,
1030		RAWDCF_ROOTDELAY,
1031		TIMEBRICK_BASEDELAY,
1032		DCF_A_ID,
1033		TIMEBRICK_DESCRIPTION,
1034		RAWDCF_FORMAT,
1035		DCF_TYPE,
1036		RAWDCF_MAXUNSYNC,
1037		RAWDCF_SPEED,
1038		RAWDCF_CFLAG,
1039		RAWDCF_IFLAG,
1040		RAWDCF_OFLAG,
1041		RAWDCF_LFLAG,
1042		RAWDCF_SAMPLES,
1043		RAWDCF_KEEP
1044	},
1045	{				/* mode 7 */
1046		MBG_FLAGS,
1047		GPS16X_POLL,
1048		GPS16X_INIT,
1049		NO_EVENT,
1050		GPS16X_END,
1051		GPS16X_MESSAGE,
1052		GPS16X_DATA,
1053		GPS16X_ROOTDELAY,
1054		GPS16X_BASEDELAY,
1055		GPS16X_ID,
1056		GPS16X_DESCRIPTION,
1057		GPS16X_FORMAT,
1058		GPS_TYPE,
1059		GPS16X_MAXUNSYNC,
1060		GPS16X_SPEED,
1061		GPS16X_CFLAG,
1062		GPS16X_IFLAG,
1063		GPS16X_OFLAG,
1064		GPS16X_LFLAG,
1065		GPS16X_SAMPLES,
1066		GPS16X_KEEP
1067	},
1068	{				/* mode 8 */
1069		RAWDCF_FLAGS,
1070		NO_POLL,
1071		NO_INIT,
1072		NO_EVENT,
1073		NO_END,
1074		NO_MESSAGE,
1075		NO_LCLDATA,
1076		RAWDCF_ROOTDELAY,
1077		IGELCLOCK_BASEDELAY,
1078		DCF_A_ID,
1079		IGELCLOCK_DESCRIPTION,
1080		RAWDCF_FORMAT,
1081		DCF_TYPE,
1082		RAWDCF_MAXUNSYNC,
1083		IGELCLOCK_SPEED,
1084		IGELCLOCK_CFLAG,
1085		RAWDCF_IFLAG,
1086		RAWDCF_OFLAG,
1087		RAWDCF_LFLAG,
1088		RAWDCF_SAMPLES,
1089		RAWDCF_KEEP
1090	},
1091	{				/* mode 9 */
1092		TRIMBLETAIP_FLAGS,
1093#if TRIM_POLLRATE		/* DHD940515: Allow user config */
1094		NO_POLL,
1095#else
1096		TRIMBLETAIP_POLL,
1097#endif
1098		TRIMBLETAIP_INIT,
1099		TRIMBLETAIP_EVENT,
1100		TRIMBLETAIP_END,
1101		NO_MESSAGE,
1102		TRIMBLETAIP_DATA,
1103		TRIMBLETAIP_ROOTDELAY,
1104		TRIMBLETAIP_BASEDELAY,
1105		TRIMBLETAIP_ID,
1106		TRIMBLETAIP_DESCRIPTION,
1107		TRIMBLETAIP_FORMAT,
1108		GPS_TYPE,
1109		TRIMBLETAIP_MAXUNSYNC,
1110		TRIMBLETAIP_SPEED,
1111		TRIMBLETAIP_CFLAG,
1112		TRIMBLETAIP_IFLAG,
1113		TRIMBLETAIP_OFLAG,
1114		TRIMBLETAIP_LFLAG,
1115		TRIMBLETAIP_SAMPLES,
1116		TRIMBLETAIP_KEEP
1117	},
1118	{				/* mode 10 */
1119		TRIMBLETSIP_FLAGS,
1120#if TRIM_POLLRATE		/* DHD940515: Allow user config */
1121		NO_POLL,
1122#else
1123		TRIMBLETSIP_POLL,
1124#endif
1125		TRIMBLETSIP_INIT,
1126		TRIMBLETSIP_EVENT,
1127		TRIMBLETSIP_END,
1128		TRIMBLETSIP_MESSAGE,
1129		TRIMBLETSIP_DATA,
1130		TRIMBLETSIP_ROOTDELAY,
1131		TRIMBLETSIP_BASEDELAY,
1132		TRIMBLETSIP_ID,
1133		TRIMBLETSIP_DESCRIPTION,
1134		TRIMBLETSIP_FORMAT,
1135		GPS_TYPE,
1136		TRIMBLETSIP_MAXUNSYNC,
1137		TRIMBLETSIP_SPEED,
1138		TRIMBLETSIP_CFLAG,
1139		TRIMBLETSIP_IFLAG,
1140		TRIMBLETSIP_OFLAG,
1141		TRIMBLETSIP_LFLAG,
1142		TRIMBLETSIP_SAMPLES,
1143		TRIMBLETSIP_KEEP
1144	},
1145	{                             /* mode 11 */
1146		NO_CL_FLAGS,
1147		RCC8000_POLL,
1148		RCC8000_INIT,
1149		NO_EVENT,
1150		RCC8000_END,
1151		NO_MESSAGE,
1152		RCC8000_DATA,
1153		RCC8000_ROOTDELAY,
1154		RCC8000_BASEDELAY,
1155		RCC8000_ID,
1156		RCC8000_DESCRIPTION,
1157		RCC8000_FORMAT,
1158		DCF_TYPE,
1159		RCC8000_MAXUNSYNC,
1160		RCC8000_SPEED,
1161		RCC8000_CFLAG,
1162		RCC8000_IFLAG,
1163		RCC8000_OFLAG,
1164		RCC8000_LFLAG,
1165		RCC8000_SAMPLES,
1166		RCC8000_KEEP
1167	},
1168	{                             /* mode 12 */
1169		HOPF6021_FLAGS,
1170		NO_POLL,     
1171		NO_INIT,
1172		NO_EVENT,
1173		NO_END,
1174		NO_MESSAGE,
1175		NO_LCLDATA,
1176		HOPF6021_ROOTDELAY,
1177		HOPF6021_BASEDELAY,
1178		DCF_ID,
1179		HOPF6021_DESCRIPTION,
1180		HOPF6021_FORMAT,
1181		DCF_TYPE,
1182		HOPF6021_MAXUNSYNC,
1183		HOPF6021_SPEED,
1184		HOPF6021_CFLAG,
1185		HOPF6021_IFLAG,
1186		HOPF6021_OFLAG,
1187		HOPF6021_LFLAG,
1188		HOPF6021_SAMPLES,
1189		HOPF6021_KEEP
1190	},
1191	{                            /* mode 13 */
1192		COMPUTIME_FLAGS,
1193		NO_POLL,
1194		NO_INIT,
1195		NO_EVENT,
1196		NO_END,
1197		NO_MESSAGE,
1198		NO_LCLDATA,
1199		COMPUTIME_ROOTDELAY,
1200		COMPUTIME_BASEDELAY,
1201		COMPUTIME_ID,
1202		COMPUTIME_DESCRIPTION,
1203		COMPUTIME_FORMAT,
1204		COMPUTIME_TYPE,
1205		COMPUTIME_MAXUNSYNC,
1206		COMPUTIME_SPEED,
1207		COMPUTIME_CFLAG,
1208		COMPUTIME_IFLAG,
1209		COMPUTIME_OFLAG,
1210		COMPUTIME_LFLAG,
1211		COMPUTIME_SAMPLES,
1212		COMPUTIME_KEEP
1213	},
1214	{				/* mode 14 */
1215		RAWDCF_FLAGS,
1216		NO_POLL,
1217		RAWDCFDTRSET_INIT,
1218		NO_EVENT,
1219		NO_END,
1220		NO_MESSAGE,
1221		NO_LCLDATA,
1222		RAWDCF_ROOTDELAY,
1223		RAWDCF_BASEDELAY,
1224		DCF_A_ID,
1225		RAWDCFDTRSET_DESCRIPTION,
1226		RAWDCF_FORMAT,
1227		DCF_TYPE,
1228		RAWDCF_MAXUNSYNC,
1229		RAWDCF_SPEED,
1230		RAWDCF_CFLAG,
1231		RAWDCF_IFLAG,
1232		RAWDCF_OFLAG,
1233		RAWDCF_LFLAG,
1234		RAWDCF_SAMPLES,
1235		RAWDCF_KEEP
1236	},
1237	{				/* mode 15 */
1238		0,				/* operation flags (io modes) */
1239  		NO_POLL,			/* active poll routine */
1240		NO_INIT,			/* active poll init routine */
1241  		NO_EVENT,		        /* special event handling (e.g. reset clock) */
1242  		NO_END,				/* active poll end routine */
1243  		NO_MESSAGE,			/* process a lower layer message */
1244		NO_LCLDATA,			/* local data area for "poll" mechanism */
1245		0,				/* rootdelay */
1246		11.0 /* bits */ / 9600,		/* current offset by which the RS232
1247				           	time code is delayed from the actual time */
1248		DCF_ID,				/* ID code */
1249		"WHARTON 400A Series clock",	/* device name */
1250		"WHARTON 400A Series clock Output Format 1",	/* fixed format */
1251			/* Must match a format-name in a libparse/clk_xxx.c file */
1252		DCF_TYPE,			/* clock type (ntp control) */
1253		(1*60*60),		        /* time to trust oscillator after losing synch */
1254		B9600,				/* terminal input & output baudrate */
1255		(CS8|CREAD|PARENB|CLOCAL|HUPCL),/* terminal control flags */
1256		0,				/* terminal input flags */
1257		0,				/* terminal output flags */
1258		0,				/* terminal local flags */
1259		5,				/* samples for median filter */
1260		3,				/* samples for median filter to keep */
1261	},
1262	{				/* mode 16 - RAWDCF RTS set, DTR clr */
1263		RAWDCF_FLAGS,
1264		NO_POLL,
1265		RAWDCFDTRCLRRTSSET_INIT,
1266		NO_EVENT,
1267		NO_END,
1268		NO_MESSAGE,
1269		NO_LCLDATA,
1270		RAWDCF_ROOTDELAY,
1271		RAWDCF_BASEDELAY,
1272		DCF_A_ID,
1273		RAWDCFDTRCLRRTSSET_DESCRIPTION,
1274		RAWDCF_FORMAT,
1275		DCF_TYPE,
1276		RAWDCF_MAXUNSYNC,
1277		RAWDCF_SPEED,
1278		RAWDCF_CFLAG,
1279		RAWDCF_IFLAG,
1280		RAWDCF_OFLAG,
1281		RAWDCF_LFLAG,
1282		RAWDCF_SAMPLES,
1283		RAWDCF_KEEP
1284	},
1285        {                            /* mode 17 */
1286                VARITEXT_FLAGS,
1287                NO_POLL,
1288                NO_INIT,
1289                NO_EVENT,
1290                NO_END,
1291                NO_MESSAGE,
1292                NO_LCLDATA,
1293                VARITEXT_ROOTDELAY,
1294                VARITEXT_BASEDELAY,
1295                VARITEXT_ID,
1296                VARITEXT_DESCRIPTION,
1297                VARITEXT_FORMAT,
1298                VARITEXT_TYPE,
1299                VARITEXT_MAXUNSYNC,
1300                VARITEXT_SPEED,
1301                VARITEXT_CFLAG,
1302                VARITEXT_IFLAG,
1303                VARITEXT_OFLAG,
1304                VARITEXT_LFLAG,
1305                VARITEXT_SAMPLES,
1306                VARITEXT_KEEP
1307        },
1308	{				/* mode 18 */
1309		MBG_FLAGS,
1310		NO_POLL,
1311		NO_INIT,
1312		NO_EVENT,
1313		GPS16X_END,
1314		GPS16X_MESSAGE,
1315		GPS16X_DATA,
1316		GPS16X_ROOTDELAY,
1317		GPS16X_BASEDELAY,
1318		GPS16X_ID,
1319		GPS16X_DESCRIPTION,
1320		GPS16X_FORMAT,
1321		GPS_TYPE,
1322		GPS16X_MAXUNSYNC,
1323		GPS16X_SPEED,
1324		GPS16X_CFLAG,
1325		GPS16X_IFLAG,
1326		GPS16X_OFLAG,
1327		GPS16X_LFLAG,
1328		GPS16X_SAMPLES,
1329		GPS16X_KEEP
1330	},
1331	{				/* mode 19 */
1332		RAWDCF_FLAGS,
1333		NO_POLL,
1334		RAWDCF_INIT,
1335		NO_EVENT,
1336		NO_END,
1337		NO_MESSAGE,
1338		NO_LCLDATA,
1339		RAWDCF_ROOTDELAY,
1340		GUDE_EMC_USB_V20_BASEDELAY,
1341		DCF_A_ID,
1342		GUDE_EMC_USB_V20_DESCRIPTION,
1343		RAWDCF_FORMAT,
1344		DCF_TYPE,
1345		RAWDCF_MAXUNSYNC,
1346		GUDE_EMC_USB_V20_SPEED,
1347		RAWDCF_CFLAG,
1348		RAWDCF_IFLAG,
1349		RAWDCF_OFLAG,
1350		RAWDCF_LFLAG,
1351		RAWDCF_SAMPLES,
1352		RAWDCF_KEEP
1353	},
1354};
1355
1356static int ncltypes = sizeof(parse_clockinfo) / sizeof(struct parse_clockinfo);
1357
1358#define CLK_REALTYPE(x) ((int)(((x)->ttl) & 0x7F))
1359#define CLK_TYPE(x)	((CLK_REALTYPE(x) >= ncltypes) ? ~0 : CLK_REALTYPE(x))
1360#define CLK_UNIT(x)	((int)REFCLOCKUNIT(&(x)->srcadr))
1361#define CLK_PPS(x)	(((x)->ttl) & 0x80)
1362
1363/*
1364 * Other constant stuff
1365 */
1366#define	PARSEHSREFID	0x7f7f08ff	/* 127.127.8.255 refid for hi strata */
1367
1368#define PARSESTATISTICS   (60*60)	        /* output state statistics every hour */
1369
1370static int notice = 0;
1371
1372#define PARSE_STATETIME(parse, i) ((parse->generic->currentstatus == i) ? parse->statetime[i] + current_time - parse->lastchange : parse->statetime[i])
1373
1374static void parse_event   P((struct parseunit *, int));
1375static void parse_process P((struct parseunit *, parsetime_t *));
1376static void clear_err     P((struct parseunit *, u_long));
1377static int  list_err      P((struct parseunit *, u_long));
1378static char * l_mktime    P((u_long));
1379
1380/**===========================================================================
1381 ** implementation error message regression module
1382 **/
1383static void
1384clear_err(
1385	struct parseunit *parse,
1386	u_long            lstate
1387	)
1388{
1389	if (lstate == ERR_ALL)
1390	{
1391		int i;
1392
1393		for (i = 0; i < ERR_CNT; i++)
1394		{
1395			parse->errors[i].err_stage   = err_tbl[i];
1396			parse->errors[i].err_cnt     = 0;
1397			parse->errors[i].err_last    = 0;
1398			parse->errors[i].err_started = 0;
1399			parse->errors[i].err_suppressed = 0;
1400		}
1401	}
1402	else
1403	{
1404		parse->errors[lstate].err_stage   = err_tbl[lstate];
1405		parse->errors[lstate].err_cnt     = 0;
1406		parse->errors[lstate].err_last    = 0;
1407		parse->errors[lstate].err_started = 0;
1408		parse->errors[lstate].err_suppressed = 0;
1409	}
1410}
1411
1412static int
1413list_err(
1414	struct parseunit *parse,
1415	u_long            lstate
1416	)
1417{
1418	int do_it;
1419	struct errorinfo *err = &parse->errors[lstate];
1420
1421	if (err->err_started == 0)
1422	{
1423		err->err_started = current_time;
1424	}
1425
1426	do_it = (current_time - err->err_last) >= err->err_stage->err_delay;
1427
1428	if (do_it)
1429	    err->err_cnt++;
1430  
1431	if (err->err_stage->err_count &&
1432	    (err->err_cnt >= err->err_stage->err_count))
1433	{
1434		err->err_stage++;
1435		err->err_cnt = 0;
1436	}
1437
1438	if (!err->err_cnt && do_it)
1439	    msyslog(LOG_INFO, "PARSE receiver #%d: interval for following error message class is at least %s",
1440		    CLK_UNIT(parse->peer), l_mktime(err->err_stage->err_delay));
1441
1442	if (!do_it)
1443	    err->err_suppressed++;
1444	else
1445	    err->err_last = current_time;
1446
1447	if (do_it && err->err_suppressed)
1448	{
1449		msyslog(LOG_INFO, "PARSE receiver #%d: %ld message%s suppressed, error condition class persists for %s",
1450			CLK_UNIT(parse->peer), err->err_suppressed, (err->err_suppressed == 1) ? " was" : "s where",
1451			l_mktime(current_time - err->err_started));
1452		err->err_suppressed = 0;
1453	}
1454  
1455	return do_it;
1456}
1457
1458/*--------------------------------------------------
1459 * mkreadable - make a printable ascii string (without
1460 * embedded quotes so that the ntpq protocol isn't
1461 * fooled
1462 */
1463#ifndef isprint
1464#define isprint(_X_) (((_X_) > 0x1F) && ((_X_) < 0x7F))
1465#endif
1466
1467static char *
1468mkreadable(
1469	char  *buffer,
1470	long  blen,
1471	const char  *src,
1472	u_long  srclen,
1473	int hex
1474	)
1475{
1476	char *b    = buffer;
1477	char *endb = (char *)0;
1478
1479	if (blen < 4)
1480		return (char *)0;		/* don't bother with mini buffers */
1481
1482	endb = buffer + blen - 4;
1483
1484	blen--;			/* account for '\0' */
1485
1486	while (blen && srclen--)
1487	{
1488		if (!hex &&             /* no binary only */
1489		    (*src != '\\') &&   /* no plain \ */
1490		    (*src != '"') &&    /* no " */
1491		    isprint((int)*src))	/* only printables */
1492		{			/* they are easy... */
1493			*buffer++ = *src++;
1494			blen--;
1495		}
1496		else
1497		{
1498			if (blen < 4)
1499			{
1500				while (blen--)
1501				{
1502					*buffer++ = '.';
1503				}
1504				*buffer = '\0';
1505				return b;
1506			}
1507			else
1508			{
1509				if (*src == '\\')
1510				{
1511					strcpy(buffer,"\\\\");
1512					buffer += 2;
1513					blen   -= 2;
1514					src++;
1515				}
1516				else
1517				{
1518					sprintf(buffer, "\\x%02x", *src++);
1519					blen   -= 4;
1520					buffer += 4;
1521				}
1522			}
1523		}
1524		if (srclen && !blen && endb) /* overflow - set last chars to ... */
1525			strcpy(endb, "...");
1526	}
1527
1528	*buffer = '\0';
1529	return b;
1530}
1531
1532
1533/*--------------------------------------------------
1534 * mkascii - make a printable ascii string
1535 * assumes (unless defined better) 7-bit ASCII
1536 */
1537static char *
1538mkascii(
1539	char  *buffer,
1540	long  blen,
1541	const char  *src,
1542	u_long  srclen
1543	)
1544{
1545	return mkreadable(buffer, blen, src, srclen, 0);
1546}
1547
1548/**===========================================================================
1549 ** implementation of i/o handling methods
1550 ** (all STREAM, partial STREAM, user level)
1551 **/
1552
1553/*
1554 * define possible io handling methods
1555 */
1556#ifdef STREAM
1557static int  ppsclock_init   P((struct parseunit *));
1558static int  stream_init     P((struct parseunit *));
1559static void stream_end      P((struct parseunit *));
1560static int  stream_enable   P((struct parseunit *));
1561static int  stream_disable  P((struct parseunit *));
1562static int  stream_setcs    P((struct parseunit *, parsectl_t *));
1563static int  stream_getfmt   P((struct parseunit *, parsectl_t *));
1564static int  stream_setfmt   P((struct parseunit *, parsectl_t *));
1565static int  stream_timecode P((struct parseunit *, parsectl_t *));
1566static void stream_receive  P((struct recvbuf *));
1567#endif
1568					 
1569static int  local_init     P((struct parseunit *));
1570static void local_end      P((struct parseunit *));
1571static int  local_nop      P((struct parseunit *));
1572static int  local_setcs    P((struct parseunit *, parsectl_t *));
1573static int  local_getfmt   P((struct parseunit *, parsectl_t *));
1574static int  local_setfmt   P((struct parseunit *, parsectl_t *));
1575static int  local_timecode P((struct parseunit *, parsectl_t *));
1576static void local_receive  P((struct recvbuf *));
1577static int  local_input    P((struct recvbuf *));
1578
1579static bind_t io_bindings[] =
1580{
1581#ifdef STREAM
1582	{
1583		"parse STREAM",
1584		stream_init,
1585		stream_end,
1586		stream_setcs,
1587		stream_disable,
1588		stream_enable,
1589		stream_getfmt,
1590		stream_setfmt,
1591		stream_timecode,
1592		stream_receive,
1593		0,
1594	},
1595	{
1596		"ppsclock STREAM",
1597		ppsclock_init,
1598		local_end,
1599		local_setcs,
1600		local_nop,
1601		local_nop,
1602		local_getfmt,
1603		local_setfmt,
1604		local_timecode,
1605		local_receive,
1606		local_input,
1607	},
1608#endif
1609	{
1610		"normal",
1611		local_init,
1612		local_end,
1613		local_setcs,
1614		local_nop,
1615		local_nop,
1616		local_getfmt,
1617		local_setfmt,
1618		local_timecode,
1619		local_receive,
1620		local_input,
1621	},
1622	{
1623		(char *)0,
1624	}
1625};
1626
1627#ifdef STREAM
1628
1629#define fix_ts(_X_) \
1630                        if ((&(_X_))->tv.tv_usec >= 1000000)                \
1631                          {                                                 \
1632			    (&(_X_))->tv.tv_usec -= 1000000;                \
1633			    (&(_X_))->tv.tv_sec  += 1;                      \
1634			  }
1635
1636#define cvt_ts(_X_, _Y_) \
1637                        {                                                   \
1638			  l_fp ts;				            \
1639			  fix_ts((_X_));                                    \
1640			  if (!buftvtots((const char *)&(&(_X_))->tv, &ts)) \
1641			    {                                               \
1642                              ERR(ERR_BADDATA)	 		            \
1643                                msyslog(LOG_ERR,"parse: stream_receive: timestamp conversion error (buftvtots) (%s) (%ld.%06ld) ", (_Y_), (long)(&(_X_))->tv.tv_sec, (long)(&(_X_))->tv.tv_usec);\
1644			      return;                                       \
1645			    }                                               \
1646			  else                                              \
1647			    {                                               \
1648			      (&(_X_))->fp = ts;                            \
1649			    }                                               \
1650		        }
1651
1652/*--------------------------------------------------
1653 * ppsclock STREAM init
1654 */
1655static int
1656ppsclock_init(
1657	struct parseunit *parse
1658	)
1659{
1660        static char m1[] = "ppsclocd";
1661	static char m2[] = "ppsclock";
1662	
1663	/*
1664	 * now push the parse streams module
1665	 * it will ensure exclusive access to the device
1666	 */
1667	if (ioctl(parse->ppsfd, I_PUSH, (caddr_t)m1) == -1 &&
1668	    ioctl(parse->ppsfd, I_PUSH, (caddr_t)m2) == -1)
1669	{
1670		if (errno != EINVAL)
1671		{
1672			msyslog(LOG_ERR, "PARSE receiver #%d: ppsclock_init: ioctl(fd, I_PUSH, \"ppsclock\"): %m",
1673				CLK_UNIT(parse->peer));
1674		}
1675		return 0;
1676	}
1677	if (!local_init(parse))
1678	{
1679		(void)ioctl(parse->ppsfd, I_POP, (caddr_t)0);
1680		return 0;
1681	}
1682
1683	parse->flags |= PARSE_PPSCLOCK;
1684	return 1;
1685}
1686
1687/*--------------------------------------------------
1688 * parse STREAM init
1689 */
1690static int
1691stream_init(
1692	struct parseunit *parse
1693	)
1694{
1695	static char m1[] = "parse";
1696	/*
1697	 * now push the parse streams module
1698	 * to test whether it is there (neat interface 8-( )
1699	 */
1700	if (ioctl(parse->generic->io.fd, I_PUSH, (caddr_t)m1) == -1)
1701	{
1702		if (errno != EINVAL) /* accept non-existence */
1703		{
1704			msyslog(LOG_ERR, "PARSE receiver #%d: stream_init: ioctl(fd, I_PUSH, \"parse\"): %m", CLK_UNIT(parse->peer));
1705		}
1706		return 0;
1707	}
1708	else
1709	{
1710		while(ioctl(parse->generic->io.fd, I_POP, (caddr_t)0) == 0)
1711		    /* empty loop */;
1712
1713		/*
1714		 * now push it a second time after we have removed all
1715		 * module garbage
1716		 */
1717		if (ioctl(parse->generic->io.fd, I_PUSH, (caddr_t)m1) == -1)
1718		{
1719			msyslog(LOG_ERR, "PARSE receiver #%d: stream_init: ioctl(fd, I_PUSH, \"parse\"): %m", CLK_UNIT(parse->peer));
1720			return 0;
1721		}
1722		else
1723		{
1724			return 1;
1725		}
1726	}
1727}
1728
1729/*--------------------------------------------------
1730 * parse STREAM end
1731 */
1732static void
1733stream_end(
1734	struct parseunit *parse
1735	)
1736{
1737	while(ioctl(parse->generic->io.fd, I_POP, (caddr_t)0) == 0)
1738	    /* empty loop */;
1739}
1740
1741/*-------------------…

Large files files are truncated, but you can click here to view the full file