154359Sroberto/*
2182007Sroberto * /src/NTP/REPOSITORY/ntp4-dev/ntpd/refclock_parse.c,v 4.80 2007/08/11 12:06:29 kardel Exp
354359Sroberto *
4182007Sroberto * refclock_parse.c,v 4.80 2007/08/11 12:06:29 kardel Exp
554359Sroberto *
6182007Sroberto * generic reference clock driver for several DCF/GPS/MSF/... receivers
754359Sroberto *
8182007Sroberto * PPS notes:
9182007Sroberto *   On systems that support PPSAPI (RFC2783) PPSAPI is the
10182007Sroberto *   preferred interface.
1154359Sroberto *
12182007Sroberto *   Optionally make use of a STREAMS module for input processing where
13182007Sroberto *   available and configured. This STREAMS module reduces the time
14182007Sroberto *   stamp latency for serial and PPS events.
15182007Sroberto *   Currently the STREAMS module is only available for Suns running
16182007Sroberto *   SunOS 4.x and SunOS5.x.
1754359Sroberto *
18182007Sroberto * Copyright (c) 1995-2007 by Frank Kardel <kardel <AT> ntp.org>
1954359Sroberto * Copyright (c) 1989-1994 by Frank Kardel, Friedrich-Alexander Universit�t Erlangen-N�rnberg, Germany
2054359Sroberto *
21182007Sroberto * Redistribution and use in source and binary forms, with or without
22182007Sroberto * modification, are permitted provided that the following conditions
23182007Sroberto * are met:
24182007Sroberto * 1. Redistributions of source code must retain the above copyright
25182007Sroberto *    notice, this list of conditions and the following disclaimer.
26182007Sroberto * 2. Redistributions in binary form must reproduce the above copyright
27182007Sroberto *    notice, this list of conditions and the following disclaimer in the
28182007Sroberto *    documentation and/or other materials provided with the distribution.
29182007Sroberto * 3. Neither the name of the author nor the names of its contributors
30182007Sroberto *    may be used to endorse or promote products derived from this software
31182007Sroberto *    without specific prior written permission.
3254359Sroberto *
33182007Sroberto * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
34182007Sroberto * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
35182007Sroberto * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
36182007Sroberto * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
37182007Sroberto * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
38182007Sroberto * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
39182007Sroberto * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
40182007Sroberto * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
41182007Sroberto * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
42182007Sroberto * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
43182007Sroberto * SUCH DAMAGE.
4454359Sroberto *
4554359Sroberto */
4654359Sroberto
4754359Sroberto#ifdef HAVE_CONFIG_H
48182007Sroberto# include "config.h"
4954359Sroberto#endif
5054359Sroberto
5154359Sroberto#if defined(REFCLOCK) && defined(CLOCK_PARSE)
5254359Sroberto
5354359Sroberto/*
5454359Sroberto * This driver currently provides the support for
5554359Sroberto *   - Meinberg receiver DCF77 PZF 535 (TCXO version)       (DCF)
5654359Sroberto *   - Meinberg receiver DCF77 PZF 535 (OCXO version)       (DCF)
5754359Sroberto *   - Meinberg receiver DCF77 PZF 509                      (DCF)
5854359Sroberto *   - Meinberg receiver DCF77 AM receivers (e.g. C51)      (DCF)
5954359Sroberto *   - IGEL CLOCK                                           (DCF)
6054359Sroberto *   - ELV DCF7000                                          (DCF)
6154359Sroberto *   - Schmid clock                                         (DCF)
6254359Sroberto *   - Conrad DCF77 receiver module                         (DCF)
6354359Sroberto *   - FAU DCF77 NTP receiver (TimeBrick)                   (DCF)
64182007Sroberto *   - WHARTON 400A Series clock			    (DCF)
6554359Sroberto *
6654359Sroberto *   - Meinberg GPS166/GPS167                               (GPS)
6754359Sroberto *   - Trimble (TSIP and TAIP protocol)                     (GPS)
6854359Sroberto *
6954359Sroberto *   - RCC8000 MSF Receiver                                 (MSF)
7054359Sroberto *   - VARITEXT clock					    (MSF)
7154359Sroberto */
7254359Sroberto
7354359Sroberto/*
7454359Sroberto * Meinberg receivers are usually connected via a
7554359Sroberto * 9600 baud serial line
7654359Sroberto *
7754359Sroberto * The Meinberg GPS receivers also have a special NTP time stamp
7854359Sroberto * format. The firmware release is Uni-Erlangen.
7954359Sroberto *
8054359Sroberto * Meinberg generic receiver setup:
8154359Sroberto *	output time code every second
8254359Sroberto *	Baud rate 9600 7E2S
8354359Sroberto *
8454359Sroberto * Meinberg GPS16x setup:
8554359Sroberto *      output time code every second
8654359Sroberto *      Baudrate 19200 8N1
8754359Sroberto *
8854359Sroberto * This software supports the standard data formats used
8954359Sroberto * in Meinberg receivers.
9054359Sroberto *
9154359Sroberto * Special software versions are only sensible for the
9254359Sroberto * GPS 16x family of receivers.
9354359Sroberto *
9454359Sroberto * Meinberg can be reached via: http://www.meinberg.de/
9554359Sroberto */
9654359Sroberto
9754359Sroberto#include "ntpd.h"
9854359Sroberto#include "ntp_refclock.h"
9954359Sroberto#include "ntp_unixtime.h"	/* includes <sys/time.h> */
10054359Sroberto#include "ntp_control.h"
101182007Sroberto#include "ntp_string.h"
10254359Sroberto
10354359Sroberto#include <stdio.h>
10454359Sroberto#include <ctype.h>
10554359Sroberto#ifndef TM_IN_SYS_TIME
10654359Sroberto# include <time.h>
10754359Sroberto#endif
10854359Sroberto
109182007Sroberto#ifdef HAVE_UNISTD_H
110182007Sroberto# include <unistd.h>
111182007Sroberto#endif
112182007Sroberto
11354359Sroberto#if !defined(STREAM) && !defined(HAVE_SYSV_TTYS) && !defined(HAVE_BSD_TTYS) && !defined(HAVE_TERMIOS)
11454359Sroberto# include "Bletch:  Define one of {STREAM,HAVE_SYSV_TTYS,HAVE_TERMIOS}"
11554359Sroberto#endif
11654359Sroberto
11754359Sroberto#ifdef STREAM
11854359Sroberto# include <sys/stream.h>
11954359Sroberto# include <sys/stropts.h>
12054359Sroberto#endif
12154359Sroberto
12254359Sroberto#ifdef HAVE_TERMIOS
12354359Sroberto# define TTY_GETATTR(_FD_, _ARG_) tcgetattr((_FD_), (_ARG_))
12454359Sroberto# define TTY_SETATTR(_FD_, _ARG_) tcsetattr((_FD_), TCSANOW, (_ARG_))
12554359Sroberto# undef HAVE_SYSV_TTYS
12654359Sroberto#endif
12754359Sroberto
12854359Sroberto#ifdef HAVE_SYSV_TTYS
12954359Sroberto# define TTY_GETATTR(_FD_, _ARG_) ioctl((_FD_), TCGETA, (_ARG_))
13054359Sroberto# define TTY_SETATTR(_FD_, _ARG_) ioctl((_FD_), TCSETAW, (_ARG_))
13154359Sroberto#endif
13254359Sroberto
13354359Sroberto#ifdef HAVE_BSD_TTYS
13454359Sroberto/* #error CURRENTLY NO BSD TTY SUPPORT */
13554359Sroberto# include "Bletch: BSD TTY not currently supported"
13654359Sroberto#endif
13754359Sroberto
13854359Sroberto#ifdef HAVE_SYS_IOCTL_H
13954359Sroberto# include <sys/ioctl.h>
14054359Sroberto#endif
14154359Sroberto
142182007Sroberto#ifdef HAVE_PPSAPI
143182007Sroberto# include "ppsapi_timepps.h"
144182007Sroberto#endif
145182007Sroberto
14654359Sroberto#ifdef PPS
147182007Sroberto# ifdef HAVE_SYS_PPSCLOCK_H
148182007Sroberto#  include <sys/ppsclock.h>
149182007Sroberto# endif
150182007Sroberto# ifdef HAVE_TIO_SERIAL_STUFF
151182007Sroberto#  include <linux/serial.h>
152182007Sroberto# endif
15354359Sroberto#endif
154182007Sroberto
155182007Sroberto#define BUFFER_SIZE(_BUF, _PTR) ((_BUF) + sizeof(_BUF) - (_PTR))
156182007Sroberto#define BUFFER_SIZES(_BUF, _PTR, _SZ) ((_BUF) + (_SZ) - (_PTR))
157182007Sroberto
158182007Sroberto/*
159182007Sroberto * document type of PPS interfacing - copy of ifdef mechanism in local_input()
160182007Sroberto */
161182007Sroberto#undef PPS_METHOD
162182007Sroberto
163182007Sroberto#ifdef HAVE_PPSAPI
164182007Sroberto#define PPS_METHOD "PPS API"
165182007Sroberto#else
166182007Sroberto#ifdef TIOCDCDTIMESTAMP
167182007Sroberto#define PPS_METHOD "TIOCDCDTIMESTAMP"
168182007Sroberto#else /* TIOCDCDTIMESTAMP */
169182007Sroberto#if defined(HAVE_STRUCT_PPSCLOCKEV) && (defined(HAVE_CIOGETEV) || defined(HAVE_TIOCGPPSEV))
170182007Sroberto#ifdef HAVE_CIOGETEV
171182007Sroberto#define PPS_METHOD "CIOGETEV"
17254359Sroberto#endif
173182007Sroberto#ifdef HAVE_TIOCGPPSEV
174182007Sroberto#define PPS_METHOD "TIOCGPPSEV"
17554359Sroberto#endif
176182007Sroberto#endif
177182007Sroberto#endif /* TIOCDCDTIMESTAMP */
178182007Sroberto#endif /* HAVE_PPSAPI */
17954359Sroberto
18054359Sroberto#include "ntp_io.h"
18154359Sroberto#include "ntp_stdlib.h"
18254359Sroberto
18354359Sroberto#include "parse.h"
18454359Sroberto#include "mbg_gps166.h"
18554359Sroberto#include "trimble.h"
18654359Sroberto#include "binio.h"
18754359Sroberto#include "ascii.h"
18854359Sroberto#include "ieee754io.h"
189182007Sroberto#include "recvbuff.h"
19054359Sroberto
191182007Srobertostatic char rcsid[] = "refclock_parse.c,v 4.80 2007/08/11 12:06:29 kardel Exp";
19254359Sroberto
19354359Sroberto/**===========================================================================
19454359Sroberto ** external interface to ntp mechanism
19554359Sroberto **/
19654359Sroberto
19754359Srobertostatic	int	parse_start	P((int, struct peer *));
19854359Srobertostatic	void	parse_shutdown	P((int, struct peer *));
19954359Srobertostatic	void	parse_poll	P((int, struct peer *));
20054359Srobertostatic	void	parse_control	P((int, struct refclockstat *, struct refclockstat *, struct peer *));
20154359Sroberto
20254359Srobertostruct	refclock refclock_parse = {
20354359Sroberto	parse_start,
20454359Sroberto	parse_shutdown,
20554359Sroberto	parse_poll,
20654359Sroberto	parse_control,
207182007Sroberto	noentry,
208182007Sroberto	noentry,
20954359Sroberto	NOFLAGS
21054359Sroberto};
21154359Sroberto
21254359Sroberto/*
21354359Sroberto * Definitions
21454359Sroberto */
21554359Sroberto#define	MAXUNITS	4	/* maximum number of "PARSE" units permitted */
21654359Sroberto#define PARSEDEVICE	"/dev/refclock-%d" /* device to open %d is unit number */
217182007Sroberto#define PARSEPPSDEVICE	"/dev/refclockpps-%d" /* optional pps device to open %d is unit number */
21854359Sroberto
21954359Sroberto#undef ABS
22054359Sroberto#define ABS(_X_) (((_X_) < 0) ? -(_X_) : (_X_))
22154359Sroberto
222182007Sroberto#define PARSE_HARDPPS_DISABLE 0
223182007Sroberto#define PARSE_HARDPPS_ENABLE  1
224182007Sroberto
22554359Sroberto/**===========================================================================
22654359Sroberto ** function vector for dynamically binding io handling mechanism
22754359Sroberto **/
22854359Sroberto
22954359Srobertostruct parseunit;		/* to keep inquiring minds happy */
23054359Sroberto
23154359Srobertotypedef struct bind
23254359Sroberto{
23354359Sroberto  const char *bd_description;	                                /* name of type of binding */
23454359Sroberto  int	(*bd_init)     P((struct parseunit *));			/* initialize */
23554359Sroberto  void	(*bd_end)      P((struct parseunit *));			/* end */
23654359Sroberto  int   (*bd_setcs)    P((struct parseunit *, parsectl_t *));	/* set character size */
23754359Sroberto  int	(*bd_disable)  P((struct parseunit *));			/* disable */
23854359Sroberto  int	(*bd_enable)   P((struct parseunit *));			/* enable */
23954359Sroberto  int	(*bd_getfmt)   P((struct parseunit *, parsectl_t *));	/* get format */
24054359Sroberto  int	(*bd_setfmt)   P((struct parseunit *, parsectl_t *));	/* setfmt */
24154359Sroberto  int	(*bd_timecode) P((struct parseunit *, parsectl_t *));	/* get time code */
24254359Sroberto  void	(*bd_receive)  P((struct recvbuf *));			/* receive operation */
24354359Sroberto  int	(*bd_io_input) P((struct recvbuf *));			/* input operation */
24454359Sroberto} bind_t;
24554359Sroberto
24654359Sroberto#define PARSE_END(_X_)			(*(_X_)->binding->bd_end)(_X_)
24754359Sroberto#define PARSE_SETCS(_X_, _CS_)		(*(_X_)->binding->bd_setcs)(_X_, _CS_)
24854359Sroberto#define PARSE_ENABLE(_X_)		(*(_X_)->binding->bd_enable)(_X_)
24954359Sroberto#define PARSE_DISABLE(_X_)		(*(_X_)->binding->bd_disable)(_X_)
25054359Sroberto#define PARSE_GETFMT(_X_, _DCT_)	(*(_X_)->binding->bd_getfmt)(_X_, _DCT_)
25154359Sroberto#define PARSE_SETFMT(_X_, _DCT_)	(*(_X_)->binding->bd_setfmt)(_X_, _DCT_)
25254359Sroberto#define PARSE_GETTIMECODE(_X_, _DCT_)	(*(_X_)->binding->bd_timecode)(_X_, _DCT_)
25354359Sroberto
25454359Sroberto/*
25554359Sroberto * io modes
25654359Sroberto */
25754359Sroberto#define PARSE_F_PPSPPS		0x0001 /* use loopfilter PPS code (CIOGETEV) */
25854359Sroberto#define PARSE_F_PPSONSECOND	0x0002 /* PPS pulses are on second */
25954359Sroberto
26054359Sroberto
26154359Sroberto/**===========================================================================
26254359Sroberto ** error message regression handling
26354359Sroberto **
26454359Sroberto ** there are quite a few errors that can occur in rapid succession such as
26554359Sroberto ** noisy input data or no data at all. in order to reduce the amount of
26654359Sroberto ** syslog messages in such case, we are using a backoff algorithm. We limit
26754359Sroberto ** the number of error messages of a certain class to 1 per time unit. if a
26854359Sroberto ** configurable number of messages is displayed that way, we move on to the
26954359Sroberto ** next time unit / count for that class. a count of messages that have been
27054359Sroberto ** suppressed is held and displayed whenever a corresponding message is
27154359Sroberto ** displayed. the time units for a message class will also be displayed.
27254359Sroberto ** whenever an error condition clears we reset the error message state,
27354359Sroberto ** thus we would still generate much output on pathological conditions
27454359Sroberto ** where the system oscillates between OK and NOT OK states. coping
27554359Sroberto ** with that condition is currently considered too complicated.
27654359Sroberto **/
27754359Sroberto
27854359Sroberto#define ERR_ALL	        (unsigned)~0	/* "all" errors */
27954359Sroberto#define ERR_BADDATA	(unsigned)0	/* unusable input data/conversion errors */
28054359Sroberto#define ERR_NODATA	(unsigned)1	/* no input data */
28154359Sroberto#define ERR_BADIO	(unsigned)2	/* read/write/select errors */
28254359Sroberto#define ERR_BADSTATUS	(unsigned)3	/* unsync states */
28354359Sroberto#define ERR_BADEVENT	(unsigned)4	/* non nominal events */
28454359Sroberto#define ERR_INTERNAL	(unsigned)5	/* internal error */
28554359Sroberto#define ERR_CNT		(unsigned)(ERR_INTERNAL+1)
28654359Sroberto
28754359Sroberto#define ERR(_X_)	if (list_err(parse, (_X_)))
28854359Sroberto
28954359Srobertostruct errorregression
29054359Sroberto{
29154359Sroberto	u_long err_count;	/* number of repititions per class */
29254359Sroberto	u_long err_delay;	/* minimum delay between messages */
29354359Sroberto};
29454359Sroberto
29554359Srobertostatic struct errorregression
29654359Srobertoerr_baddata[] =			/* error messages for bad input data */
29754359Sroberto{
29854359Sroberto	{ 1,       0 },		/* output first message immediately */
29954359Sroberto	{ 5,      60 },		/* output next five messages in 60 second intervals */
30054359Sroberto	{ 3,    3600 },		/* output next 3 messages in hour intervals */
30154359Sroberto	{ 0, 12*3600 }		/* repeat messages only every 12 hours */
30254359Sroberto};
30354359Sroberto
30454359Srobertostatic struct errorregression
30554359Srobertoerr_nodata[] =			/* error messages for missing input data */
30654359Sroberto{
30754359Sroberto	{ 1,       0 },		/* output first message immediately */
30854359Sroberto	{ 5,      60 },		/* output next five messages in 60 second intervals */
30954359Sroberto	{ 3,    3600 },		/* output next 3 messages in hour intervals */
31054359Sroberto	{ 0, 12*3600 }		/* repeat messages only every 12 hours */
31154359Sroberto};
31254359Sroberto
31354359Srobertostatic struct errorregression
31454359Srobertoerr_badstatus[] =		/* unsynchronized state messages */
31554359Sroberto{
31654359Sroberto	{ 1,       0 },		/* output first message immediately */
31754359Sroberto	{ 5,      60 },		/* output next five messages in 60 second intervals */
31854359Sroberto	{ 3,    3600 },		/* output next 3 messages in hour intervals */
31954359Sroberto	{ 0, 12*3600 }		/* repeat messages only every 12 hours */
32054359Sroberto};
32154359Sroberto
32254359Srobertostatic struct errorregression
32354359Srobertoerr_badio[] =			/* io failures (bad reads, selects, ...) */
32454359Sroberto{
32554359Sroberto	{ 1,       0 },		/* output first message immediately */
32654359Sroberto	{ 5,      60 },		/* output next five messages in 60 second intervals */
32754359Sroberto	{ 5,    3600 },		/* output next 3 messages in hour intervals */
32854359Sroberto	{ 0, 12*3600 }		/* repeat messages only every 12 hours */
32954359Sroberto};
33054359Sroberto
33154359Srobertostatic struct errorregression
33254359Srobertoerr_badevent[] =		/* non nominal events */
33354359Sroberto{
33454359Sroberto	{ 20,      0 },		/* output first message immediately */
33554359Sroberto	{ 6,      60 },		/* output next five messages in 60 second intervals */
33654359Sroberto	{ 5,    3600 },		/* output next 3 messages in hour intervals */
33754359Sroberto	{ 0, 12*3600 }		/* repeat messages only every 12 hours */
33854359Sroberto};
33954359Sroberto
34054359Srobertostatic struct errorregression
34154359Srobertoerr_internal[] =		/* really bad things - basically coding/OS errors */
34254359Sroberto{
34354359Sroberto	{ 0,       0 },		/* output all messages immediately */
34454359Sroberto};
34554359Sroberto
34654359Srobertostatic struct errorregression *
34754359Srobertoerr_tbl[] =
34854359Sroberto{
34954359Sroberto	err_baddata,
35054359Sroberto	err_nodata,
35154359Sroberto	err_badio,
35254359Sroberto	err_badstatus,
35354359Sroberto	err_badevent,
35454359Sroberto	err_internal
35554359Sroberto};
35654359Sroberto
35754359Srobertostruct errorinfo
35854359Sroberto{
35954359Sroberto	u_long err_started;	/* begin time (ntp) of error condition */
36054359Sroberto	u_long err_last;	/* last time (ntp) error occurred */
36154359Sroberto	u_long err_cnt;	/* number of error repititions */
36254359Sroberto	u_long err_suppressed;	/* number of suppressed messages */
36354359Sroberto	struct errorregression *err_stage; /* current error stage */
36454359Sroberto};
36554359Sroberto
36654359Sroberto/**===========================================================================
36754359Sroberto ** refclock instance data
36854359Sroberto **/
36954359Sroberto
37054359Srobertostruct parseunit
37154359Sroberto{
37254359Sroberto	/*
37354359Sroberto	 * NTP management
37454359Sroberto	 */
37554359Sroberto	struct peer         *peer;		/* backlink to peer structure - refclock inactive if 0  */
37654359Sroberto	struct refclockproc *generic;		/* backlink to refclockproc structure */
37754359Sroberto
37854359Sroberto	/*
37954359Sroberto	 * PARSE io
38054359Sroberto	 */
38154359Sroberto	bind_t	     *binding;	        /* io handling binding */
38254359Sroberto
38354359Sroberto	/*
38454359Sroberto	 * parse state
38554359Sroberto	 */
38654359Sroberto	parse_t	      parseio;	        /* io handling structure (user level parsing) */
38754359Sroberto
38854359Sroberto	/*
38954359Sroberto	 * type specific parameters
39054359Sroberto	 */
39154359Sroberto	struct parse_clockinfo   *parse_type;	        /* link to clock description */
39254359Sroberto
39354359Sroberto	/*
39454359Sroberto	 * clock state handling/reporting
39554359Sroberto	 */
39654359Sroberto	u_char	      flags;	        /* flags (leap_control) */
39754359Sroberto	u_long	      lastchange;       /* time (ntp) when last state change accured */
39854359Sroberto	u_long	      statetime[CEVNT_MAX+1]; /* accumulated time of clock states */
39956746Sroberto	u_long        pollneeddata; 	/* current_time(!=0) for receive sample expected in PPS mode */
40054359Sroberto	u_short	      lastformat;       /* last format used */
40154359Sroberto	u_long        lastsync;		/* time (ntp) when clock was last seen fully synchronized */
402182007Sroberto        u_long        maxunsync;        /* max time in seconds a receiver is trusted after loosing synchronisation */
403182007Sroberto        double        ppsphaseadjust;   /* phase adjustment of PPS time stamp */
404182007Sroberto        u_long        lastmissed;       /* time (ntp) when poll didn't get data (powerup heuristic) */
40554359Sroberto	u_long        ppsserial;        /* magic cookie for ppsclock serials (avoids stale ppsclock data) */
406182007Sroberto	int	      ppsfd;	        /* fd to ise for PPS io */
407182007Sroberto#ifdef HAVE_PPSAPI
408182007Sroberto        pps_handle_t  ppshandle;        /* store PPSAPI handle */
409182007Sroberto        pps_params_t  ppsparams;        /* current PPS parameters */
410182007Sroberto        int           hardppsstate;     /* current hard pps state */
411182007Sroberto#endif
412182007Sroberto	parsetime_t   timedata;		/* last (parse module) data */
41354359Sroberto	void         *localdata;        /* optional local, receiver-specific data */
41454359Sroberto        unsigned long localstate;       /* private local state */
41554359Sroberto	struct errorinfo errors[ERR_CNT];  /* error state table for suppressing excessive error messages */
41654359Sroberto	struct ctl_var *kv;	        /* additional pseudo variables */
41754359Sroberto	u_long        laststatistic;    /* time when staticstics where output */
41854359Sroberto};
41954359Sroberto
42054359Sroberto
42154359Sroberto/**===========================================================================
42254359Sroberto ** Clockinfo section all parameter for specific clock types
42354359Sroberto ** includes NTP parameters, TTY parameters and IO handling parameters
42454359Sroberto **/
42554359Sroberto
42654359Srobertostatic	void	poll_dpoll	P((struct parseunit *));
42754359Srobertostatic	void	poll_poll	P((struct peer *));
42854359Srobertostatic	int	poll_init	P((struct parseunit *));
42954359Sroberto
43054359Srobertotypedef struct poll_info
43154359Sroberto{
43254359Sroberto	u_long      rate;		/* poll rate - once every "rate" seconds - 0 off */
43354359Sroberto	const char *string;		/* string to send for polling */
43454359Sroberto	u_long      count;		/* number of characters in string */
43554359Sroberto} poll_info_t;
43654359Sroberto
43754359Sroberto#define NO_CL_FLAGS	0
43854359Sroberto#define NO_POLL		0
43954359Sroberto#define NO_INIT		0
44054359Sroberto#define NO_END		0
44154359Sroberto#define NO_EVENT	0
442182007Sroberto#define NO_LCLDATA	0
44354359Sroberto#define NO_MESSAGE	0
44454359Sroberto#define NO_PPSDELAY     0
44554359Sroberto
44654359Sroberto#define DCF_ID		"DCF"	/* generic DCF */
44754359Sroberto#define DCF_A_ID	"DCFa"	/* AM demodulation */
44854359Sroberto#define DCF_P_ID	"DCFp"	/* psuedo random phase shift */
44954359Sroberto#define GPS_ID		"GPS"	/* GPS receiver */
45054359Sroberto
45154359Sroberto#define	NOCLOCK_ROOTDELAY	0.0
45254359Sroberto#define	NOCLOCK_BASEDELAY	0.0
45354359Sroberto#define	NOCLOCK_DESCRIPTION	0
45454359Sroberto#define NOCLOCK_MAXUNSYNC       0
45554359Sroberto#define NOCLOCK_CFLAG           0
45654359Sroberto#define NOCLOCK_IFLAG           0
45754359Sroberto#define NOCLOCK_OFLAG           0
45854359Sroberto#define NOCLOCK_LFLAG           0
45954359Sroberto#define NOCLOCK_ID		"TILT"
46054359Sroberto#define NOCLOCK_POLL		NO_POLL
46154359Sroberto#define NOCLOCK_INIT		NO_INIT
46254359Sroberto#define NOCLOCK_END		NO_END
463182007Sroberto#define NOCLOCK_DATA		NO_LCLDATA
46454359Sroberto#define NOCLOCK_FORMAT		""
46554359Sroberto#define NOCLOCK_TYPE		CTL_SST_TS_UNSPEC
46654359Sroberto#define NOCLOCK_SAMPLES		0
46754359Sroberto#define NOCLOCK_KEEP		0
46854359Sroberto
46954359Sroberto#define DCF_TYPE		CTL_SST_TS_LF
47054359Sroberto#define GPS_TYPE		CTL_SST_TS_UHF
47154359Sroberto
47254359Sroberto/*
47354359Sroberto * receiver specific constants
47454359Sroberto */
47554359Sroberto#define MBG_SPEED		(B9600)
476182007Sroberto#define MBG_CFLAG		(CS7|PARENB|CREAD|CLOCAL|HUPCL|CSTOPB)
47754359Sroberto#define MBG_IFLAG		(IGNBRK|IGNPAR|ISTRIP)
47854359Sroberto#define MBG_OFLAG		0
47954359Sroberto#define MBG_LFLAG		0
48054359Sroberto#define MBG_FLAGS               PARSE_F_PPSONSECOND
48154359Sroberto
48254359Sroberto/*
48354359Sroberto * Meinberg DCF77 receivers
48454359Sroberto */
48554359Sroberto#define	DCFUA31_ROOTDELAY	0.0  /* 0 */
48654359Sroberto#define	DCFUA31_BASEDELAY	0.010  /* 10.7421875ms: 10 ms (+/- 3 ms) */
48754359Sroberto#define	DCFUA31_DESCRIPTION	"Meinberg DCF77 C51 or compatible"
48854359Sroberto#define DCFUA31_MAXUNSYNC       60*30       /* only trust clock for 1/2 hour */
48954359Sroberto#define DCFUA31_SPEED		MBG_SPEED
49054359Sroberto#define DCFUA31_CFLAG           MBG_CFLAG
49154359Sroberto#define DCFUA31_IFLAG           MBG_IFLAG
49254359Sroberto#define DCFUA31_OFLAG           MBG_OFLAG
49354359Sroberto#define DCFUA31_LFLAG           MBG_LFLAG
49454359Sroberto#define DCFUA31_SAMPLES		5
49554359Sroberto#define DCFUA31_KEEP		3
49654359Sroberto#define DCFUA31_FORMAT		"Meinberg Standard"
49754359Sroberto
49854359Sroberto/*
49954359Sroberto * Meinberg DCF PZF535/TCXO (FM/PZF) receiver
50054359Sroberto */
50154359Sroberto#define	DCFPZF535_ROOTDELAY	0.0
50254359Sroberto#define	DCFPZF535_BASEDELAY	0.001968  /* 1.968ms +- 104us (oscilloscope) - relative to start (end of STX) */
50354359Sroberto#define	DCFPZF535_DESCRIPTION	"Meinberg DCF PZF 535/509 / TCXO"
50454359Sroberto#define DCFPZF535_MAXUNSYNC     60*60*12           /* only trust clock for 12 hours
50554359Sroberto						    * @ 5e-8df/f we have accumulated
50654359Sroberto						    * at most 2.16 ms (thus we move to
50754359Sroberto						    * NTP synchronisation */
50854359Sroberto#define DCFPZF535_SPEED		MBG_SPEED
50954359Sroberto#define DCFPZF535_CFLAG         MBG_CFLAG
51054359Sroberto#define DCFPZF535_IFLAG         MBG_IFLAG
51154359Sroberto#define DCFPZF535_OFLAG         MBG_OFLAG
51254359Sroberto#define DCFPZF535_LFLAG         MBG_LFLAG
51354359Sroberto#define DCFPZF535_SAMPLES	       5
51454359Sroberto#define DCFPZF535_KEEP		       3
51554359Sroberto#define DCFPZF535_FORMAT	"Meinberg Standard"
51654359Sroberto
51754359Sroberto/*
51854359Sroberto * Meinberg DCF PZF535/OCXO receiver
51954359Sroberto */
52054359Sroberto#define	DCFPZF535OCXO_ROOTDELAY	0.0
52154359Sroberto#define	DCFPZF535OCXO_BASEDELAY	0.001968 /* 1.968ms +- 104us (oscilloscope) - relative to start (end of STX) */
52254359Sroberto#define	DCFPZF535OCXO_DESCRIPTION "Meinberg DCF PZF 535/509 / OCXO"
52354359Sroberto#define DCFPZF535OCXO_MAXUNSYNC     60*60*96       /* only trust clock for 4 days
52454359Sroberto						    * @ 5e-9df/f we have accumulated
52554359Sroberto						    * at most an error of 1.73 ms
52654359Sroberto						    * (thus we move to NTP synchronisation) */
52754359Sroberto#define DCFPZF535OCXO_SPEED	    MBG_SPEED
52854359Sroberto#define DCFPZF535OCXO_CFLAG         MBG_CFLAG
52954359Sroberto#define DCFPZF535OCXO_IFLAG         MBG_IFLAG
53054359Sroberto#define DCFPZF535OCXO_OFLAG         MBG_OFLAG
53154359Sroberto#define DCFPZF535OCXO_LFLAG         MBG_LFLAG
53254359Sroberto#define DCFPZF535OCXO_SAMPLES		   5
53354359Sroberto#define DCFPZF535OCXO_KEEP	           3
53454359Sroberto#define DCFPZF535OCXO_FORMAT	    "Meinberg Standard"
53554359Sroberto
53654359Sroberto/*
53754359Sroberto * Meinberg GPS16X receiver
53854359Sroberto */
53954359Srobertostatic	void	gps16x_message	 P((struct parseunit *, parsetime_t *));
54054359Srobertostatic  int     gps16x_poll_init P((struct parseunit *));
54154359Sroberto
54254359Sroberto#define	GPS16X_ROOTDELAY	0.0         /* nothing here */
54354359Sroberto#define	GPS16X_BASEDELAY	0.001968         /* XXX to be fixed ! 1.968ms +- 104us (oscilloscope) - relative to start (end of STX) */
54454359Sroberto#define	GPS16X_DESCRIPTION      "Meinberg GPS16x receiver"
54554359Sroberto#define GPS16X_MAXUNSYNC        60*60*96       /* only trust clock for 4 days
54654359Sroberto						* @ 5e-9df/f we have accumulated
54754359Sroberto						* at most an error of 1.73 ms
54854359Sroberto						* (thus we move to NTP synchronisation) */
54954359Sroberto#define GPS16X_SPEED		B19200
55054359Sroberto#define GPS16X_CFLAG            (CS8|CREAD|CLOCAL|HUPCL)
55154359Sroberto#define GPS16X_IFLAG            (IGNBRK|IGNPAR)
55254359Sroberto#define GPS16X_OFLAG            MBG_OFLAG
55354359Sroberto#define GPS16X_LFLAG            MBG_LFLAG
55454359Sroberto#define GPS16X_POLLRATE	6
55554359Sroberto#define GPS16X_POLLCMD	""
55654359Sroberto#define GPS16X_CMDSIZE	0
55754359Sroberto
55854359Srobertostatic poll_info_t gps16x_pollinfo = { GPS16X_POLLRATE, GPS16X_POLLCMD, GPS16X_CMDSIZE };
55954359Sroberto
56054359Sroberto#define GPS16X_INIT		gps16x_poll_init
56154359Sroberto#define GPS16X_POLL	        0
56254359Sroberto#define GPS16X_END		0
56354359Sroberto#define GPS16X_DATA		((void *)(&gps16x_pollinfo))
56454359Sroberto#define GPS16X_MESSAGE		gps16x_message
56554359Sroberto#define GPS16X_ID		GPS_ID
56654359Sroberto#define GPS16X_FORMAT		"Meinberg GPS Extended"
56754359Sroberto#define GPS16X_SAMPLES		5
56854359Sroberto#define GPS16X_KEEP		3
56954359Sroberto
57054359Sroberto/*
57154359Sroberto * ELV DCF7000 Wallclock-Receiver/Switching Clock (Kit)
57254359Sroberto *
57354359Sroberto * This is really not the hottest clock - but before you have nothing ...
57454359Sroberto */
57554359Sroberto#define DCF7000_ROOTDELAY	0.0 /* 0 */
57654359Sroberto#define DCF7000_BASEDELAY	0.405 /* slow blow */
57754359Sroberto#define DCF7000_DESCRIPTION	"ELV DCF7000"
57854359Sroberto#define DCF7000_MAXUNSYNC	(60*5) /* sorry - but it just was not build as a clock */
57954359Sroberto#define DCF7000_SPEED		(B9600)
58054359Sroberto#define DCF7000_CFLAG           (CS8|CREAD|PARENB|PARODD|CLOCAL|HUPCL)
58154359Sroberto#define DCF7000_IFLAG		(IGNBRK)
58254359Sroberto#define DCF7000_OFLAG		0
58354359Sroberto#define DCF7000_LFLAG		0
58454359Sroberto#define DCF7000_SAMPLES		5
58554359Sroberto#define DCF7000_KEEP		3
58654359Sroberto#define DCF7000_FORMAT		"ELV DCF7000"
58754359Sroberto
58854359Sroberto/*
58954359Sroberto * Schmid DCF Receiver Kit
59054359Sroberto *
59154359Sroberto * When the WSDCF clock is operating optimally we want the primary clock
59254359Sroberto * distance to come out at 300 ms.  Thus, peer.distance in the WSDCF peer
59354359Sroberto * structure is set to 290 ms and we compute delays which are at least
59454359Sroberto * 10 ms long.  The following are 290 ms and 10 ms expressed in u_fp format
59554359Sroberto */
59654359Sroberto#define WS_POLLRATE	1	/* every second - watch interdependency with poll routine */
59754359Sroberto#define WS_POLLCMD	"\163"
59854359Sroberto#define WS_CMDSIZE	1
59954359Sroberto
60054359Srobertostatic poll_info_t wsdcf_pollinfo = { WS_POLLRATE, WS_POLLCMD, WS_CMDSIZE };
60154359Sroberto
60254359Sroberto#define WSDCF_INIT		poll_init
60354359Sroberto#define WSDCF_POLL		poll_dpoll
60454359Sroberto#define WSDCF_END		0
60554359Sroberto#define WSDCF_DATA		((void *)(&wsdcf_pollinfo))
60654359Sroberto#define	WSDCF_ROOTDELAY		0.0	/* 0 */
60754359Sroberto#define	WSDCF_BASEDELAY	 	0.010	/*  ~  10ms */
60854359Sroberto#define WSDCF_DESCRIPTION	"WS/DCF Receiver"
60954359Sroberto#define WSDCF_FORMAT		"Schmid"
61054359Sroberto#define WSDCF_MAXUNSYNC		(60*60)	/* assume this beast hold at 1 h better than 2 ms XXX-must verify */
61154359Sroberto#define WSDCF_SPEED		(B1200)
61254359Sroberto#define WSDCF_CFLAG		(CS8|CREAD|CLOCAL)
61354359Sroberto#define WSDCF_IFLAG		0
61454359Sroberto#define WSDCF_OFLAG		0
61554359Sroberto#define WSDCF_LFLAG		0
61654359Sroberto#define WSDCF_SAMPLES		5
61754359Sroberto#define WSDCF_KEEP		3
61854359Sroberto
61954359Sroberto/*
62054359Sroberto * RAW DCF77 - input of DCF marks via RS232 - many variants
62154359Sroberto */
62254359Sroberto#define RAWDCF_FLAGS		0
62354359Sroberto#define RAWDCF_ROOTDELAY	0.0 /* 0 */
62454359Sroberto#define RAWDCF_BASEDELAY	0.258
62554359Sroberto#define RAWDCF_FORMAT		"RAW DCF77 Timecode"
62654359Sroberto#define RAWDCF_MAXUNSYNC	(0) /* sorry - its a true receiver - no signal - no time */
62754359Sroberto#define RAWDCF_SPEED		(B50)
62854359Sroberto#ifdef NO_PARENB_IGNPAR /* Was: defined(SYS_IRIX4) || defined(SYS_IRIX5) */
62954359Sroberto/* somehow doesn't grok PARENB & IGNPAR (mj) */
63054359Sroberto# define RAWDCF_CFLAG            (CS8|CREAD|CLOCAL)
63154359Sroberto#else
63254359Sroberto# define RAWDCF_CFLAG            (CS8|CREAD|CLOCAL|PARENB)
63354359Sroberto#endif
63454359Sroberto#ifdef RAWDCF_NO_IGNPAR /* Was: defined(SYS_LINUX) && defined(CLOCK_RAWDCF) */
63554359Sroberto# define RAWDCF_IFLAG		0
63654359Sroberto#else
63754359Sroberto# define RAWDCF_IFLAG		(IGNPAR)
63854359Sroberto#endif
63954359Sroberto#define RAWDCF_OFLAG		0
64054359Sroberto#define RAWDCF_LFLAG		0
64154359Sroberto#define RAWDCF_SAMPLES		20
64254359Sroberto#define RAWDCF_KEEP		12
64354359Sroberto#define RAWDCF_INIT		0
64454359Sroberto
64554359Sroberto/*
64654359Sroberto * RAW DCF variants
64754359Sroberto */
64854359Sroberto/*
64954359Sroberto * Conrad receiver
65054359Sroberto *
65154359Sroberto * simplest (cheapest) DCF clock - e. g. DCF77 receiver by Conrad
65254359Sroberto * (~40DM - roughly $30 ) followed by a level converter for RS232
65354359Sroberto */
65454359Sroberto#define CONRAD_BASEDELAY	0.292 /* Conrad receiver @ 50 Baud on a Sun */
65554359Sroberto#define CONRAD_DESCRIPTION	"RAW DCF77 CODE (Conrad DCF77 receiver module)"
65654359Sroberto
657182007Sroberto/* Gude Analog- und Digitalsystem GmbH 'Expert mouseCLOCK USB v2.0' */
658182007Sroberto#define GUDE_EMC_USB_V20_SPEED            (B4800)
659182007Sroberto#define GUDE_EMC_USB_V20_BASEDELAY        0.425 /* USB serial<->USB converter FTDI232R */
660182007Sroberto#define GUDE_EMC_USB_V20_DESCRIPTION      "RAW DCF77 CODE (Expert mouseCLOCK USB v2.0)"
661182007Sroberto
66254359Sroberto/*
66354359Sroberto * TimeBrick receiver
66454359Sroberto */
66554359Sroberto#define TIMEBRICK_BASEDELAY	0.210 /* TimeBrick @ 50 Baud on a Sun */
66654359Sroberto#define TIMEBRICK_DESCRIPTION	"RAW DCF77 CODE (TimeBrick)"
66754359Sroberto
66854359Sroberto/*
66954359Sroberto * IGEL:clock receiver
67054359Sroberto */
67154359Sroberto#define IGELCLOCK_BASEDELAY	0.258 /* IGEL:clock receiver */
67254359Sroberto#define IGELCLOCK_DESCRIPTION	"RAW DCF77 CODE (IGEL:clock)"
67354359Sroberto#define IGELCLOCK_SPEED		(B1200)
67454359Sroberto#define IGELCLOCK_CFLAG		(CS8|CREAD|HUPCL|CLOCAL)
67554359Sroberto
67654359Sroberto/*
67754359Sroberto * RAWDCF receivers that need to be powered from DTR
67854359Sroberto * (like Expert mouse clock)
67954359Sroberto */
68056746Srobertostatic	int	rawdcf_init_1	P((struct parseunit *));
68156746Sroberto#define RAWDCFDTRSET_DESCRIPTION	"RAW DCF77 CODE (DTR SET/RTS CLR)"
68256746Sroberto#define RAWDCFDTRSET_INIT 		rawdcf_init_1
68354359Sroberto
68454359Sroberto/*
68556746Sroberto * RAWDCF receivers that need to be powered from
68656746Sroberto * DTR CLR and RTS SET
68754359Sroberto */
68856746Srobertostatic	int	rawdcf_init_2	P((struct parseunit *));
68956746Sroberto#define RAWDCFDTRCLRRTSSET_DESCRIPTION	"RAW DCF77 CODE (DTR CLR/RTS SET)"
69056746Sroberto#define RAWDCFDTRCLRRTSSET_INIT	rawdcf_init_2
69154359Sroberto
69254359Sroberto/*
69354359Sroberto * Trimble GPS receivers (TAIP and TSIP protocols)
69454359Sroberto */
69554359Sroberto#ifndef TRIM_POLLRATE
69654359Sroberto#define TRIM_POLLRATE	0	/* only true direct polling */
69754359Sroberto#endif
69854359Sroberto
69954359Sroberto#define TRIM_TAIPPOLLCMD	">SRM;FR_FLAG=F;EC_FLAG=F<>QTM<"
70054359Sroberto#define TRIM_TAIPCMDSIZE	(sizeof(TRIM_TAIPPOLLCMD)-1)
70154359Sroberto
70254359Srobertostatic poll_info_t trimbletaip_pollinfo = { TRIM_POLLRATE, TRIM_TAIPPOLLCMD, TRIM_TAIPCMDSIZE };
70354359Srobertostatic	int	trimbletaip_init	P((struct parseunit *));
70454359Srobertostatic	void	trimbletaip_event	P((struct parseunit *, int));
70554359Sroberto
70654359Sroberto/* query time & UTC correction data */
70754359Srobertostatic char tsipquery[] = { DLE, 0x21, DLE, ETX, DLE, 0x2F, DLE, ETX };
70854359Sroberto
70954359Srobertostatic poll_info_t trimbletsip_pollinfo = { TRIM_POLLRATE, tsipquery, sizeof(tsipquery) };
71054359Srobertostatic	int	trimbletsip_init	P((struct parseunit *));
71154359Srobertostatic	void	trimbletsip_end   	P((struct parseunit *));
71254359Srobertostatic	void	trimbletsip_message	P((struct parseunit *, parsetime_t *));
71354359Srobertostatic	void	trimbletsip_event	P((struct parseunit *, int));
71454359Sroberto
71554359Sroberto#define TRIMBLETSIP_IDLE_TIME	    (300) /* 5 minutes silence at most */
716182007Sroberto#define TRIMBLE_RESET_HOLDOFF       TRIMBLETSIP_IDLE_TIME
71754359Sroberto
71854359Sroberto#define TRIMBLETAIP_SPEED	    (B4800)
71954359Sroberto#define TRIMBLETAIP_CFLAG           (CS8|CREAD|CLOCAL)
72054359Sroberto#define TRIMBLETAIP_IFLAG           (BRKINT|IGNPAR|ISTRIP|ICRNL|IXON)
72154359Sroberto#define TRIMBLETAIP_OFLAG           (OPOST|ONLCR)
72254359Sroberto#define TRIMBLETAIP_LFLAG           (0)
72354359Sroberto
72454359Sroberto#define TRIMBLETSIP_SPEED	    (B9600)
72554359Sroberto#define TRIMBLETSIP_CFLAG           (CS8|CLOCAL|CREAD|PARENB|PARODD)
72654359Sroberto#define TRIMBLETSIP_IFLAG           (IGNBRK)
72754359Sroberto#define TRIMBLETSIP_OFLAG           (0)
72854359Sroberto#define TRIMBLETSIP_LFLAG           (ICANON)
72954359Sroberto
73054359Sroberto#define TRIMBLETSIP_SAMPLES	    5
73154359Sroberto#define TRIMBLETSIP_KEEP	    3
73254359Sroberto#define TRIMBLETAIP_SAMPLES	    5
73354359Sroberto#define TRIMBLETAIP_KEEP	    3
73454359Sroberto
73554359Sroberto#define TRIMBLETAIP_FLAGS	    (PARSE_F_PPSONSECOND)
73654359Sroberto#define TRIMBLETSIP_FLAGS	    (TRIMBLETAIP_FLAGS)
73754359Sroberto
73854359Sroberto#define TRIMBLETAIP_POLL	    poll_dpoll
73954359Sroberto#define TRIMBLETSIP_POLL	    poll_dpoll
74054359Sroberto
74154359Sroberto#define TRIMBLETAIP_INIT	    trimbletaip_init
74254359Sroberto#define TRIMBLETSIP_INIT	    trimbletsip_init
74354359Sroberto
74454359Sroberto#define TRIMBLETAIP_EVENT	    trimbletaip_event
74554359Sroberto
74654359Sroberto#define TRIMBLETSIP_EVENT	    trimbletsip_event
74754359Sroberto#define TRIMBLETSIP_MESSAGE	    trimbletsip_message
74854359Sroberto
74954359Sroberto#define TRIMBLETAIP_END		    0
75054359Sroberto#define TRIMBLETSIP_END		    trimbletsip_end
75154359Sroberto
75254359Sroberto#define TRIMBLETAIP_DATA	    ((void *)(&trimbletaip_pollinfo))
75354359Sroberto#define TRIMBLETSIP_DATA	    ((void *)(&trimbletsip_pollinfo))
75454359Sroberto
75554359Sroberto#define TRIMBLETAIP_ID		    GPS_ID
75654359Sroberto#define TRIMBLETSIP_ID		    GPS_ID
75754359Sroberto
75854359Sroberto#define TRIMBLETAIP_FORMAT	    "Trimble TAIP"
75954359Sroberto#define TRIMBLETSIP_FORMAT	    "Trimble TSIP"
76054359Sroberto
76154359Sroberto#define TRIMBLETAIP_ROOTDELAY        0x0
76254359Sroberto#define TRIMBLETSIP_ROOTDELAY        0x0
76354359Sroberto
76454359Sroberto#define TRIMBLETAIP_BASEDELAY        0.0
76554359Sroberto#define TRIMBLETSIP_BASEDELAY        0.020	/* GPS time message latency */
76654359Sroberto
76754359Sroberto#define TRIMBLETAIP_DESCRIPTION      "Trimble GPS (TAIP) receiver"
76854359Sroberto#define TRIMBLETSIP_DESCRIPTION      "Trimble GPS (TSIP) receiver"
76954359Sroberto
77054359Sroberto#define TRIMBLETAIP_MAXUNSYNC        0
77154359Sroberto#define TRIMBLETSIP_MAXUNSYNC        0
77254359Sroberto
77354359Sroberto#define TRIMBLETAIP_EOL		    '<'
77454359Sroberto
77554359Sroberto/*
77654359Sroberto * RadioCode Clocks RCC 800 receiver
77754359Sroberto */
77854359Sroberto#define RCC_POLLRATE   0       /* only true direct polling */
77954359Sroberto#define RCC_POLLCMD    "\r"
78054359Sroberto#define RCC_CMDSIZE    1
78154359Sroberto
78254359Srobertostatic poll_info_t rcc8000_pollinfo = { RCC_POLLRATE, RCC_POLLCMD, RCC_CMDSIZE };
78354359Sroberto#define RCC8000_FLAGS		0
78454359Sroberto#define RCC8000_POLL            poll_dpoll
78554359Sroberto#define RCC8000_INIT            poll_init
78654359Sroberto#define RCC8000_END             0
78754359Sroberto#define RCC8000_DATA            ((void *)(&rcc8000_pollinfo))
78854359Sroberto#define RCC8000_ROOTDELAY       0.0
78954359Sroberto#define RCC8000_BASEDELAY       0.0
79054359Sroberto#define RCC8000_ID              "MSF"
79154359Sroberto#define RCC8000_DESCRIPTION     "RCC 8000 MSF Receiver"
79254359Sroberto#define RCC8000_FORMAT          "Radiocode RCC8000"
79354359Sroberto#define RCC8000_MAXUNSYNC       (60*60) /* should be ok for an hour */
79454359Sroberto#define RCC8000_SPEED		(B2400)
79554359Sroberto#define RCC8000_CFLAG           (CS8|CREAD|CLOCAL)
79654359Sroberto#define RCC8000_IFLAG           (IGNBRK|IGNPAR)
79754359Sroberto#define RCC8000_OFLAG           0
79854359Sroberto#define RCC8000_LFLAG           0
79954359Sroberto#define RCC8000_SAMPLES         5
80054359Sroberto#define RCC8000_KEEP	        3
80154359Sroberto
80254359Sroberto/*
80354359Sroberto * Hopf Radio clock 6021 Format
80454359Sroberto *
80554359Sroberto */
80654359Sroberto#define HOPF6021_ROOTDELAY	0.0
80754359Sroberto#define HOPF6021_BASEDELAY	0.0
80854359Sroberto#define HOPF6021_DESCRIPTION	"HOPF 6021"
80954359Sroberto#define HOPF6021_FORMAT         "hopf Funkuhr 6021"
81054359Sroberto#define HOPF6021_MAXUNSYNC	(60*60)  /* should be ok for an hour */
81154359Sroberto#define HOPF6021_SPEED         (B9600)
81254359Sroberto#define HOPF6021_CFLAG          (CS8|CREAD|CLOCAL)
81354359Sroberto#define HOPF6021_IFLAG		(IGNBRK|ISTRIP)
81454359Sroberto#define HOPF6021_OFLAG		0
81554359Sroberto#define HOPF6021_LFLAG		0
81654359Sroberto#define HOPF6021_FLAGS          0
81754359Sroberto#define HOPF6021_SAMPLES        5
81854359Sroberto#define HOPF6021_KEEP	        3
81954359Sroberto
82054359Sroberto/*
82154359Sroberto * Diem's Computime Radio Clock Receiver
82254359Sroberto */
82354359Sroberto#define COMPUTIME_FLAGS       0
82454359Sroberto#define COMPUTIME_ROOTDELAY   0.0
82554359Sroberto#define COMPUTIME_BASEDELAY   0.0
82654359Sroberto#define COMPUTIME_ID          DCF_ID
82754359Sroberto#define COMPUTIME_DESCRIPTION "Diem's Computime receiver"
82854359Sroberto#define COMPUTIME_FORMAT      "Diem's Computime Radio Clock"
82954359Sroberto#define COMPUTIME_TYPE        DCF_TYPE
83054359Sroberto#define COMPUTIME_MAXUNSYNC   (60*60)       /* only trust clock for 1 hour */
83154359Sroberto#define COMPUTIME_SPEED       (B9600)
83254359Sroberto#define COMPUTIME_CFLAG       (CSTOPB|CS7|CREAD|CLOCAL)
83354359Sroberto#define COMPUTIME_IFLAG       (IGNBRK|IGNPAR|ISTRIP)
83454359Sroberto#define COMPUTIME_OFLAG       0
83554359Sroberto#define COMPUTIME_LFLAG       0
83654359Sroberto#define COMPUTIME_SAMPLES     5
83754359Sroberto#define COMPUTIME_KEEP        3
83854359Sroberto
83954359Sroberto/*
84054359Sroberto * Varitext Radio Clock Receiver
84154359Sroberto */
84254359Sroberto#define VARITEXT_FLAGS       0
84354359Sroberto#define VARITEXT_ROOTDELAY   0.0
84454359Sroberto#define VARITEXT_BASEDELAY   0.0
84554359Sroberto#define VARITEXT_ID          "MSF"
84654359Sroberto#define VARITEXT_DESCRIPTION "Varitext receiver"
84754359Sroberto#define VARITEXT_FORMAT      "Varitext Radio Clock"
84854359Sroberto#define VARITEXT_TYPE        DCF_TYPE
84954359Sroberto#define VARITEXT_MAXUNSYNC   (60*60)       /* only trust clock for 1 hour */
85054359Sroberto#define VARITEXT_SPEED       (B9600)
85154359Sroberto#define VARITEXT_CFLAG       (CS7|CREAD|CLOCAL|PARENB|PARODD)
85254359Sroberto#define VARITEXT_IFLAG       (IGNPAR|IGNBRK|INPCK) /*|ISTRIP)*/
85354359Sroberto#define VARITEXT_OFLAG       0
85454359Sroberto#define VARITEXT_LFLAG       0
85554359Sroberto#define VARITEXT_SAMPLES     32
85654359Sroberto#define VARITEXT_KEEP        20
85754359Sroberto
85854359Srobertostatic struct parse_clockinfo
85954359Sroberto{
86054359Sroberto	u_long  cl_flags;		/* operation flags (io modes) */
86154359Sroberto  void  (*cl_poll)    P((struct parseunit *));			/* active poll routine */
86254359Sroberto  int   (*cl_init)    P((struct parseunit *));			/* active poll init routine */
86354359Sroberto  void  (*cl_event)   P((struct parseunit *, int));		/* special event handling (e.g. reset clock) */
86454359Sroberto  void  (*cl_end)     P((struct parseunit *));			/* active poll end routine */
86554359Sroberto  void  (*cl_message) P((struct parseunit *, parsetime_t *));	/* process a lower layer message */
86654359Sroberto	void   *cl_data;		/* local data area for "poll" mechanism */
86754359Sroberto	double    cl_rootdelay;		/* rootdelay */
86854359Sroberto	double    cl_basedelay;		/* current offset by which the RS232
86954359Sroberto				time code is delayed from the actual time */
87054359Sroberto	const char *cl_id;		/* ID code */
87154359Sroberto	const char *cl_description;		/* device name */
87254359Sroberto	const char *cl_format;		/* fixed format */
87354359Sroberto	u_char  cl_type;		/* clock type (ntp control) */
874132451Sroberto	u_long  cl_maxunsync;		/* time to trust oscillator after losing synch */
87554359Sroberto	u_long  cl_speed;		/* terminal input & output baudrate */
87654359Sroberto	u_long  cl_cflag;             /* terminal control flags */
87754359Sroberto	u_long  cl_iflag;             /* terminal input flags */
87854359Sroberto	u_long  cl_oflag;             /* terminal output flags */
87954359Sroberto	u_long  cl_lflag;             /* terminal local flags */
88054359Sroberto	u_long  cl_samples;	      /* samples for median filter */
88154359Sroberto	u_long  cl_keep;              /* samples for median filter to keep */
88254359Sroberto} parse_clockinfo[] =
88354359Sroberto{
88454359Sroberto	{				/* mode 0 */
88554359Sroberto		MBG_FLAGS,
88654359Sroberto		NO_POLL,
88754359Sroberto		NO_INIT,
88854359Sroberto		NO_EVENT,
88954359Sroberto		NO_END,
89054359Sroberto		NO_MESSAGE,
891182007Sroberto		NO_LCLDATA,
89254359Sroberto		DCFPZF535_ROOTDELAY,
89354359Sroberto		DCFPZF535_BASEDELAY,
89454359Sroberto		DCF_P_ID,
89554359Sroberto		DCFPZF535_DESCRIPTION,
89654359Sroberto		DCFPZF535_FORMAT,
89754359Sroberto		DCF_TYPE,
89854359Sroberto		DCFPZF535_MAXUNSYNC,
89954359Sroberto		DCFPZF535_SPEED,
90054359Sroberto		DCFPZF535_CFLAG,
90154359Sroberto		DCFPZF535_IFLAG,
90254359Sroberto		DCFPZF535_OFLAG,
90354359Sroberto		DCFPZF535_LFLAG,
90454359Sroberto		DCFPZF535_SAMPLES,
90554359Sroberto		DCFPZF535_KEEP
90654359Sroberto	},
90754359Sroberto	{				/* mode 1 */
90854359Sroberto		MBG_FLAGS,
90954359Sroberto		NO_POLL,
91054359Sroberto		NO_INIT,
91154359Sroberto		NO_EVENT,
91254359Sroberto		NO_END,
91354359Sroberto		NO_MESSAGE,
914182007Sroberto		NO_LCLDATA,
91554359Sroberto		DCFPZF535OCXO_ROOTDELAY,
91654359Sroberto		DCFPZF535OCXO_BASEDELAY,
91754359Sroberto		DCF_P_ID,
91854359Sroberto		DCFPZF535OCXO_DESCRIPTION,
91954359Sroberto		DCFPZF535OCXO_FORMAT,
92054359Sroberto		DCF_TYPE,
92154359Sroberto		DCFPZF535OCXO_MAXUNSYNC,
92254359Sroberto		DCFPZF535OCXO_SPEED,
92354359Sroberto		DCFPZF535OCXO_CFLAG,
92454359Sroberto		DCFPZF535OCXO_IFLAG,
92554359Sroberto		DCFPZF535OCXO_OFLAG,
92654359Sroberto		DCFPZF535OCXO_LFLAG,
92754359Sroberto		DCFPZF535OCXO_SAMPLES,
92854359Sroberto		DCFPZF535OCXO_KEEP
92954359Sroberto	},
93054359Sroberto	{				/* mode 2 */
93154359Sroberto		MBG_FLAGS,
93254359Sroberto		NO_POLL,
93354359Sroberto		NO_INIT,
93454359Sroberto		NO_EVENT,
93554359Sroberto		NO_END,
93654359Sroberto		NO_MESSAGE,
937182007Sroberto		NO_LCLDATA,
93854359Sroberto		DCFUA31_ROOTDELAY,
93954359Sroberto		DCFUA31_BASEDELAY,
94054359Sroberto		DCF_A_ID,
94154359Sroberto		DCFUA31_DESCRIPTION,
94254359Sroberto		DCFUA31_FORMAT,
94354359Sroberto		DCF_TYPE,
94454359Sroberto		DCFUA31_MAXUNSYNC,
94554359Sroberto		DCFUA31_SPEED,
94654359Sroberto		DCFUA31_CFLAG,
94754359Sroberto		DCFUA31_IFLAG,
94854359Sroberto		DCFUA31_OFLAG,
94954359Sroberto		DCFUA31_LFLAG,
95054359Sroberto		DCFUA31_SAMPLES,
95154359Sroberto		DCFUA31_KEEP
95254359Sroberto	},
95354359Sroberto	{				/* mode 3 */
95454359Sroberto		MBG_FLAGS,
95554359Sroberto		NO_POLL,
95654359Sroberto		NO_INIT,
95754359Sroberto		NO_EVENT,
95854359Sroberto		NO_END,
95954359Sroberto		NO_MESSAGE,
960182007Sroberto		NO_LCLDATA,
96154359Sroberto		DCF7000_ROOTDELAY,
96254359Sroberto		DCF7000_BASEDELAY,
96354359Sroberto		DCF_A_ID,
96454359Sroberto		DCF7000_DESCRIPTION,
96554359Sroberto		DCF7000_FORMAT,
96654359Sroberto		DCF_TYPE,
96754359Sroberto		DCF7000_MAXUNSYNC,
96854359Sroberto		DCF7000_SPEED,
96954359Sroberto		DCF7000_CFLAG,
97054359Sroberto		DCF7000_IFLAG,
97154359Sroberto		DCF7000_OFLAG,
97254359Sroberto		DCF7000_LFLAG,
97354359Sroberto		DCF7000_SAMPLES,
97454359Sroberto		DCF7000_KEEP
97554359Sroberto	},
97654359Sroberto	{				/* mode 4 */
97754359Sroberto		NO_CL_FLAGS,
97854359Sroberto		WSDCF_POLL,
97954359Sroberto		WSDCF_INIT,
98054359Sroberto		NO_EVENT,
98154359Sroberto		WSDCF_END,
98254359Sroberto		NO_MESSAGE,
98354359Sroberto		WSDCF_DATA,
98454359Sroberto		WSDCF_ROOTDELAY,
98554359Sroberto		WSDCF_BASEDELAY,
98654359Sroberto		DCF_A_ID,
98754359Sroberto		WSDCF_DESCRIPTION,
98854359Sroberto		WSDCF_FORMAT,
98954359Sroberto		DCF_TYPE,
99054359Sroberto		WSDCF_MAXUNSYNC,
99154359Sroberto		WSDCF_SPEED,
99254359Sroberto		WSDCF_CFLAG,
99354359Sroberto		WSDCF_IFLAG,
99454359Sroberto		WSDCF_OFLAG,
99554359Sroberto		WSDCF_LFLAG,
99654359Sroberto		WSDCF_SAMPLES,
99754359Sroberto		WSDCF_KEEP
99854359Sroberto	},
99954359Sroberto	{				/* mode 5 */
100054359Sroberto		RAWDCF_FLAGS,
100154359Sroberto		NO_POLL,
100254359Sroberto		RAWDCF_INIT,
100354359Sroberto		NO_EVENT,
100454359Sroberto		NO_END,
100554359Sroberto		NO_MESSAGE,
1006182007Sroberto		NO_LCLDATA,
100754359Sroberto		RAWDCF_ROOTDELAY,
100854359Sroberto		CONRAD_BASEDELAY,
100954359Sroberto		DCF_A_ID,
101054359Sroberto		CONRAD_DESCRIPTION,
101154359Sroberto		RAWDCF_FORMAT,
101254359Sroberto		DCF_TYPE,
101354359Sroberto		RAWDCF_MAXUNSYNC,
101454359Sroberto		RAWDCF_SPEED,
101554359Sroberto		RAWDCF_CFLAG,
101654359Sroberto		RAWDCF_IFLAG,
101754359Sroberto		RAWDCF_OFLAG,
101854359Sroberto		RAWDCF_LFLAG,
101954359Sroberto		RAWDCF_SAMPLES,
102054359Sroberto		RAWDCF_KEEP
102154359Sroberto	},
102254359Sroberto	{				/* mode 6 */
102354359Sroberto		RAWDCF_FLAGS,
102454359Sroberto		NO_POLL,
102554359Sroberto		RAWDCF_INIT,
102654359Sroberto		NO_EVENT,
102754359Sroberto		NO_END,
102854359Sroberto		NO_MESSAGE,
1029182007Sroberto		NO_LCLDATA,
103054359Sroberto		RAWDCF_ROOTDELAY,
103154359Sroberto		TIMEBRICK_BASEDELAY,
103254359Sroberto		DCF_A_ID,
103354359Sroberto		TIMEBRICK_DESCRIPTION,
103454359Sroberto		RAWDCF_FORMAT,
103554359Sroberto		DCF_TYPE,
103654359Sroberto		RAWDCF_MAXUNSYNC,
103754359Sroberto		RAWDCF_SPEED,
103854359Sroberto		RAWDCF_CFLAG,
103954359Sroberto		RAWDCF_IFLAG,
104054359Sroberto		RAWDCF_OFLAG,
104154359Sroberto		RAWDCF_LFLAG,
104254359Sroberto		RAWDCF_SAMPLES,
104354359Sroberto		RAWDCF_KEEP
104454359Sroberto	},
104554359Sroberto	{				/* mode 7 */
104654359Sroberto		MBG_FLAGS,
104754359Sroberto		GPS16X_POLL,
104854359Sroberto		GPS16X_INIT,
104954359Sroberto		NO_EVENT,
105054359Sroberto		GPS16X_END,
105154359Sroberto		GPS16X_MESSAGE,
105254359Sroberto		GPS16X_DATA,
105354359Sroberto		GPS16X_ROOTDELAY,
105454359Sroberto		GPS16X_BASEDELAY,
105554359Sroberto		GPS16X_ID,
105654359Sroberto		GPS16X_DESCRIPTION,
105754359Sroberto		GPS16X_FORMAT,
105854359Sroberto		GPS_TYPE,
105954359Sroberto		GPS16X_MAXUNSYNC,
106054359Sroberto		GPS16X_SPEED,
106154359Sroberto		GPS16X_CFLAG,
106254359Sroberto		GPS16X_IFLAG,
106354359Sroberto		GPS16X_OFLAG,
106454359Sroberto		GPS16X_LFLAG,
106554359Sroberto		GPS16X_SAMPLES,
106654359Sroberto		GPS16X_KEEP
106754359Sroberto	},
106854359Sroberto	{				/* mode 8 */
106954359Sroberto		RAWDCF_FLAGS,
107054359Sroberto		NO_POLL,
107154359Sroberto		NO_INIT,
107254359Sroberto		NO_EVENT,
107354359Sroberto		NO_END,
107454359Sroberto		NO_MESSAGE,
1075182007Sroberto		NO_LCLDATA,
107654359Sroberto		RAWDCF_ROOTDELAY,
107754359Sroberto		IGELCLOCK_BASEDELAY,
107854359Sroberto		DCF_A_ID,
107954359Sroberto		IGELCLOCK_DESCRIPTION,
108054359Sroberto		RAWDCF_FORMAT,
108154359Sroberto		DCF_TYPE,
108254359Sroberto		RAWDCF_MAXUNSYNC,
108354359Sroberto		IGELCLOCK_SPEED,
108454359Sroberto		IGELCLOCK_CFLAG,
108554359Sroberto		RAWDCF_IFLAG,
108654359Sroberto		RAWDCF_OFLAG,
108754359Sroberto		RAWDCF_LFLAG,
108854359Sroberto		RAWDCF_SAMPLES,
108954359Sroberto		RAWDCF_KEEP
109054359Sroberto	},
109154359Sroberto	{				/* mode 9 */
109254359Sroberto		TRIMBLETAIP_FLAGS,
109354359Sroberto#if TRIM_POLLRATE		/* DHD940515: Allow user config */
109454359Sroberto		NO_POLL,
109554359Sroberto#else
109654359Sroberto		TRIMBLETAIP_POLL,
109754359Sroberto#endif
109854359Sroberto		TRIMBLETAIP_INIT,
109954359Sroberto		TRIMBLETAIP_EVENT,
110054359Sroberto		TRIMBLETAIP_END,
110154359Sroberto		NO_MESSAGE,
110254359Sroberto		TRIMBLETAIP_DATA,
110354359Sroberto		TRIMBLETAIP_ROOTDELAY,
110454359Sroberto		TRIMBLETAIP_BASEDELAY,
110554359Sroberto		TRIMBLETAIP_ID,
110654359Sroberto		TRIMBLETAIP_DESCRIPTION,
110754359Sroberto		TRIMBLETAIP_FORMAT,
110854359Sroberto		GPS_TYPE,
110954359Sroberto		TRIMBLETAIP_MAXUNSYNC,
111054359Sroberto		TRIMBLETAIP_SPEED,
111154359Sroberto		TRIMBLETAIP_CFLAG,
111254359Sroberto		TRIMBLETAIP_IFLAG,
111354359Sroberto		TRIMBLETAIP_OFLAG,
111454359Sroberto		TRIMBLETAIP_LFLAG,
111554359Sroberto		TRIMBLETAIP_SAMPLES,
111654359Sroberto		TRIMBLETAIP_KEEP
111754359Sroberto	},
111854359Sroberto	{				/* mode 10 */
111954359Sroberto		TRIMBLETSIP_FLAGS,
112054359Sroberto#if TRIM_POLLRATE		/* DHD940515: Allow user config */
112154359Sroberto		NO_POLL,
112254359Sroberto#else
112354359Sroberto		TRIMBLETSIP_POLL,
112454359Sroberto#endif
112554359Sroberto		TRIMBLETSIP_INIT,
112654359Sroberto		TRIMBLETSIP_EVENT,
112754359Sroberto		TRIMBLETSIP_END,
112854359Sroberto		TRIMBLETSIP_MESSAGE,
112954359Sroberto		TRIMBLETSIP_DATA,
113054359Sroberto		TRIMBLETSIP_ROOTDELAY,
113154359Sroberto		TRIMBLETSIP_BASEDELAY,
113254359Sroberto		TRIMBLETSIP_ID,
113354359Sroberto		TRIMBLETSIP_DESCRIPTION,
113454359Sroberto		TRIMBLETSIP_FORMAT,
113554359Sroberto		GPS_TYPE,
113654359Sroberto		TRIMBLETSIP_MAXUNSYNC,
113754359Sroberto		TRIMBLETSIP_SPEED,
113854359Sroberto		TRIMBLETSIP_CFLAG,
113954359Sroberto		TRIMBLETSIP_IFLAG,
114054359Sroberto		TRIMBLETSIP_OFLAG,
114154359Sroberto		TRIMBLETSIP_LFLAG,
114254359Sroberto		TRIMBLETSIP_SAMPLES,
114354359Sroberto		TRIMBLETSIP_KEEP
114454359Sroberto	},
114554359Sroberto	{                             /* mode 11 */
114654359Sroberto		NO_CL_FLAGS,
114754359Sroberto		RCC8000_POLL,
114854359Sroberto		RCC8000_INIT,
114954359Sroberto		NO_EVENT,
115054359Sroberto		RCC8000_END,
115154359Sroberto		NO_MESSAGE,
115254359Sroberto		RCC8000_DATA,
115354359Sroberto		RCC8000_ROOTDELAY,
115454359Sroberto		RCC8000_BASEDELAY,
115554359Sroberto		RCC8000_ID,
115654359Sroberto		RCC8000_DESCRIPTION,
115754359Sroberto		RCC8000_FORMAT,
115854359Sroberto		DCF_TYPE,
115954359Sroberto		RCC8000_MAXUNSYNC,
116054359Sroberto		RCC8000_SPEED,
116154359Sroberto		RCC8000_CFLAG,
116254359Sroberto		RCC8000_IFLAG,
116354359Sroberto		RCC8000_OFLAG,
116454359Sroberto		RCC8000_LFLAG,
116554359Sroberto		RCC8000_SAMPLES,
116654359Sroberto		RCC8000_KEEP
116754359Sroberto	},
116854359Sroberto	{                             /* mode 12 */
116954359Sroberto		HOPF6021_FLAGS,
117054359Sroberto		NO_POLL,
117154359Sroberto		NO_INIT,
117254359Sroberto		NO_EVENT,
117354359Sroberto		NO_END,
117454359Sroberto		NO_MESSAGE,
1175182007Sroberto		NO_LCLDATA,
117654359Sroberto		HOPF6021_ROOTDELAY,
117754359Sroberto		HOPF6021_BASEDELAY,
117854359Sroberto		DCF_ID,
117954359Sroberto		HOPF6021_DESCRIPTION,
118054359Sroberto		HOPF6021_FORMAT,
118154359Sroberto		DCF_TYPE,
118254359Sroberto		HOPF6021_MAXUNSYNC,
118354359Sroberto		HOPF6021_SPEED,
118454359Sroberto		HOPF6021_CFLAG,
118554359Sroberto		HOPF6021_IFLAG,
118654359Sroberto		HOPF6021_OFLAG,
118754359Sroberto		HOPF6021_LFLAG,
118854359Sroberto		HOPF6021_SAMPLES,
118954359Sroberto		HOPF6021_KEEP
119054359Sroberto	},
119154359Sroberto	{                            /* mode 13 */
119254359Sroberto		COMPUTIME_FLAGS,
119354359Sroberto		NO_POLL,
119454359Sroberto		NO_INIT,
119554359Sroberto		NO_EVENT,
119654359Sroberto		NO_END,
119754359Sroberto		NO_MESSAGE,
1198182007Sroberto		NO_LCLDATA,
119954359Sroberto		COMPUTIME_ROOTDELAY,
120054359Sroberto		COMPUTIME_BASEDELAY,
120154359Sroberto		COMPUTIME_ID,
120254359Sroberto		COMPUTIME_DESCRIPTION,
120354359Sroberto		COMPUTIME_FORMAT,
120454359Sroberto		COMPUTIME_TYPE,
120554359Sroberto		COMPUTIME_MAXUNSYNC,
120654359Sroberto		COMPUTIME_SPEED,
120754359Sroberto		COMPUTIME_CFLAG,
120854359Sroberto		COMPUTIME_IFLAG,
120954359Sroberto		COMPUTIME_OFLAG,
121054359Sroberto		COMPUTIME_LFLAG,
121154359Sroberto		COMPUTIME_SAMPLES,
121254359Sroberto		COMPUTIME_KEEP
121354359Sroberto	},
121454359Sroberto	{				/* mode 14 */
121554359Sroberto		RAWDCF_FLAGS,
121654359Sroberto		NO_POLL,
121756746Sroberto		RAWDCFDTRSET_INIT,
121854359Sroberto		NO_EVENT,
121954359Sroberto		NO_END,
122054359Sroberto		NO_MESSAGE,
1221182007Sroberto		NO_LCLDATA,
122254359Sroberto		RAWDCF_ROOTDELAY,
122354359Sroberto		RAWDCF_BASEDELAY,
122454359Sroberto		DCF_A_ID,
122556746Sroberto		RAWDCFDTRSET_DESCRIPTION,
122654359Sroberto		RAWDCF_FORMAT,
122754359Sroberto		DCF_TYPE,
122854359Sroberto		RAWDCF_MAXUNSYNC,
122954359Sroberto		RAWDCF_SPEED,
123054359Sroberto		RAWDCF_CFLAG,
123154359Sroberto		RAWDCF_IFLAG,
123254359Sroberto		RAWDCF_OFLAG,
123354359Sroberto		RAWDCF_LFLAG,
123454359Sroberto		RAWDCF_SAMPLES,
123554359Sroberto		RAWDCF_KEEP
123654359Sroberto	},
123754359Sroberto	{				/* mode 15 */
123856746Sroberto		0,				/* operation flags (io modes) */
123982498Sroberto  		NO_POLL,			/* active poll routine */
124082498Sroberto		NO_INIT,			/* active poll init routine */
124156746Sroberto  		NO_EVENT,		        /* special event handling (e.g. reset clock) */
124256746Sroberto  		NO_END,				/* active poll end routine */
124356746Sroberto  		NO_MESSAGE,			/* process a lower layer message */
1244182007Sroberto		NO_LCLDATA,			/* local data area for "poll" mechanism */
124556746Sroberto		0,				/* rootdelay */
124682498Sroberto		11.0 /* bits */ / 9600,		/* current offset by which the RS232
124756746Sroberto				           	time code is delayed from the actual time */
124856746Sroberto		DCF_ID,				/* ID code */
124956746Sroberto		"WHARTON 400A Series clock",	/* device name */
125082498Sroberto		"WHARTON 400A Series clock Output Format 1",	/* fixed format */
125156746Sroberto			/* Must match a format-name in a libparse/clk_xxx.c file */
125256746Sroberto		DCF_TYPE,			/* clock type (ntp control) */
1253132451Sroberto		(1*60*60),		        /* time to trust oscillator after losing synch */
125456746Sroberto		B9600,				/* terminal input & output baudrate */
125556746Sroberto		(CS8|CREAD|PARENB|CLOCAL|HUPCL),/* terminal control flags */
125656746Sroberto		0,				/* terminal input flags */
125756746Sroberto		0,				/* terminal output flags */
125856746Sroberto		0,				/* terminal local flags */
125956746Sroberto		5,				/* samples for median filter */
126056746Sroberto		3,				/* samples for median filter to keep */
126154359Sroberto	},
126256746Sroberto	{				/* mode 16 - RAWDCF RTS set, DTR clr */
126356746Sroberto		RAWDCF_FLAGS,
126456746Sroberto		NO_POLL,
126556746Sroberto		RAWDCFDTRCLRRTSSET_INIT,
126656746Sroberto		NO_EVENT,
126756746Sroberto		NO_END,
126856746Sroberto		NO_MESSAGE,
1269182007Sroberto		NO_LCLDATA,
127056746Sroberto		RAWDCF_ROOTDELAY,
127156746Sroberto		RAWDCF_BASEDELAY,
127256746Sroberto		DCF_A_ID,
127356746Sroberto		RAWDCFDTRCLRRTSSET_DESCRIPTION,
127456746Sroberto		RAWDCF_FORMAT,
127556746Sroberto		DCF_TYPE,
127656746Sroberto		RAWDCF_MAXUNSYNC,
127756746Sroberto		RAWDCF_SPEED,
127856746Sroberto		RAWDCF_CFLAG,
127956746Sroberto		RAWDCF_IFLAG,
128056746Sroberto		RAWDCF_OFLAG,
128156746Sroberto		RAWDCF_LFLAG,
128256746Sroberto		RAWDCF_SAMPLES,
128356746Sroberto		RAWDCF_KEEP
128456746Sroberto	},
128556746Sroberto        {                            /* mode 17 */
128654359Sroberto                VARITEXT_FLAGS,
128754359Sroberto                NO_POLL,
128854359Sroberto                NO_INIT,
128954359Sroberto                NO_EVENT,
129054359Sroberto                NO_END,
129154359Sroberto                NO_MESSAGE,
1292182007Sroberto                NO_LCLDATA,
129354359Sroberto                VARITEXT_ROOTDELAY,
129454359Sroberto                VARITEXT_BASEDELAY,
129554359Sroberto                VARITEXT_ID,
129654359Sroberto                VARITEXT_DESCRIPTION,
129754359Sroberto                VARITEXT_FORMAT,
129854359Sroberto                VARITEXT_TYPE,
129954359Sroberto                VARITEXT_MAXUNSYNC,
130054359Sroberto                VARITEXT_SPEED,
130154359Sroberto                VARITEXT_CFLAG,
130254359Sroberto                VARITEXT_IFLAG,
130354359Sroberto                VARITEXT_OFLAG,
130454359Sroberto                VARITEXT_LFLAG,
130554359Sroberto                VARITEXT_SAMPLES,
130654359Sroberto                VARITEXT_KEEP
1307182007Sroberto        },
1308182007Sroberto	{				/* mode 18 */
1309182007Sroberto		MBG_FLAGS,
1310182007Sroberto		NO_POLL,
1311182007Sroberto		NO_INIT,
1312182007Sroberto		NO_EVENT,
1313182007Sroberto		GPS16X_END,
1314182007Sroberto		GPS16X_MESSAGE,
1315182007Sroberto		GPS16X_DATA,
1316182007Sroberto		GPS16X_ROOTDELAY,
1317182007Sroberto		GPS16X_BASEDELAY,
1318182007Sroberto		GPS16X_ID,
1319182007Sroberto		GPS16X_DESCRIPTION,
1320182007Sroberto		GPS16X_FORMAT,
1321182007Sroberto		GPS_TYPE,
1322182007Sroberto		GPS16X_MAXUNSYNC,
1323182007Sroberto		GPS16X_SPEED,
1324182007Sroberto		GPS16X_CFLAG,
1325182007Sroberto		GPS16X_IFLAG,
1326182007Sroberto		GPS16X_OFLAG,
1327182007Sroberto		GPS16X_LFLAG,
1328182007Sroberto		GPS16X_SAMPLES,
1329182007Sroberto		GPS16X_KEEP
1330182007Sroberto	},
1331182007Sroberto	{				/* mode 19 */
1332182007Sroberto		RAWDCF_FLAGS,
1333182007Sroberto		NO_POLL,
1334182007Sroberto		RAWDCF_INIT,
1335182007Sroberto		NO_EVENT,
1336182007Sroberto		NO_END,
1337182007Sroberto		NO_MESSAGE,
1338182007Sroberto		NO_LCLDATA,
1339182007Sroberto		RAWDCF_ROOTDELAY,
1340182007Sroberto		GUDE_EMC_USB_V20_BASEDELAY,
1341182007Sroberto		DCF_A_ID,
1342182007Sroberto		GUDE_EMC_USB_V20_DESCRIPTION,
1343182007Sroberto		RAWDCF_FORMAT,
1344182007Sroberto		DCF_TYPE,
1345182007Sroberto		RAWDCF_MAXUNSYNC,
1346182007Sroberto		GUDE_EMC_USB_V20_SPEED,
1347182007Sroberto		RAWDCF_CFLAG,
1348182007Sroberto		RAWDCF_IFLAG,
1349182007Sroberto		RAWDCF_OFLAG,
1350182007Sroberto		RAWDCF_LFLAG,
1351182007Sroberto		RAWDCF_SAMPLES,
1352182007Sroberto		RAWDCF_KEEP
1353182007Sroberto	},
135454359Sroberto};
135554359Sroberto
135654359Srobertostatic int ncltypes = sizeof(parse_clockinfo) / sizeof(struct parse_clockinfo);
135754359Sroberto
1358132451Sroberto#define CLK_REALTYPE(x) ((int)(((x)->ttl) & 0x7F))
135954359Sroberto#define CLK_TYPE(x)	((CLK_REALTYPE(x) >= ncltypes) ? ~0 : CLK_REALTYPE(x))
136054359Sroberto#define CLK_UNIT(x)	((int)REFCLOCKUNIT(&(x)->srcadr))
1361132451Sroberto#define CLK_PPS(x)	(((x)->ttl) & 0x80)
136254359Sroberto
136354359Sroberto/*
136454359Sroberto * Other constant stuff
136554359Sroberto */
136654359Sroberto#define	PARSEHSREFID	0x7f7f08ff	/* 127.127.8.255 refid for hi strata */
136754359Sroberto
136854359Sroberto#define PARSESTATISTICS   (60*60)	        /* output state statistics every hour */
136954359Sroberto
137054359Srobertostatic int notice = 0;
137154359Sroberto
137254359Sroberto#define PARSE_STATETIME(parse, i) ((parse->generic->currentstatus == i) ? parse->statetime[i] + current_time - parse->lastchange : parse->statetime[i])
137354359Sroberto
137454359Srobertostatic void parse_event   P((struct parseunit *, int));
137554359Srobertostatic void parse_process P((struct parseunit *, parsetime_t *));
137654359Srobertostatic void clear_err     P((struct parseunit *, u_long));
137754359Srobertostatic int  list_err      P((struct parseunit *, u_long));
137854359Srobertostatic char * l_mktime    P((u_long));
137954359Sroberto
138054359Sroberto/**===========================================================================
138154359Sroberto ** implementation error message regression module
138254359Sroberto **/
138354359Srobertostatic void
138454359Srobertoclear_err(
138554359Sroberto	struct parseunit *parse,
138654359Sroberto	u_long            lstate
138754359Sroberto	)
138854359Sroberto{
138954359Sroberto	if (lstate == ERR_ALL)
139054359Sroberto	{
139154359Sroberto		int i;
139254359Sroberto
139354359Sroberto		for (i = 0; i < ERR_CNT; i++)
139454359Sroberto		{
139554359Sroberto			parse->errors[i].err_stage   = err_tbl[i];
139654359Sroberto			parse->errors[i].err_cnt     = 0;
139754359Sroberto			parse->errors[i].err_last    = 0;
139854359Sroberto			parse->errors[i].err_started = 0;
139954359Sroberto			parse->errors[i].err_suppressed = 0;
140054359Sroberto		}
140154359Sroberto	}
140254359Sroberto	else
140354359Sroberto	{
140454359Sroberto		parse->errors[lstate].err_stage   = err_tbl[lstate];
140554359Sroberto		parse->errors[lstate].err_cnt     = 0;
140654359Sroberto		parse->errors[lstate].err_last    = 0;
140754359Sroberto		parse->errors[lstate].err_started = 0;
140854359Sroberto		parse->errors[lstate].err_suppressed = 0;
140954359Sroberto	}
141054359Sroberto}
141154359Sroberto
141254359Srobertostatic int
141354359Srobertolist_err(
141454359Sroberto	struct parseunit *parse,
141554359Sroberto	u_long            lstate
141654359Sroberto	)
141754359Sroberto{
141854359Sroberto	int do_it;
141954359Sroberto	struct errorinfo *err = &parse->errors[lstate];
142054359Sroberto
142154359Sroberto	if (err->err_started == 0)
142254359Sroberto	{
142354359Sroberto		err->err_started = current_time;
142454359Sroberto	}
142554359Sroberto
142654359Sroberto	do_it = (current_time - err->err_last) >= err->err_stage->err_delay;
142754359Sroberto
142854359Sroberto	if (do_it)
142954359Sroberto	    err->err_cnt++;
143054359Sroberto
143154359Sroberto	if (err->err_stage->err_count &&
143254359Sroberto	    (err->err_cnt >= err->err_stage->err_count))
143354359Sroberto	{
143454359Sroberto		err->err_stage++;
143554359Sroberto		err->err_cnt = 0;
143654359Sroberto	}
143754359Sroberto
143854359Sroberto	if (!err->err_cnt && do_it)
143954359Sroberto	    msyslog(LOG_INFO, "PARSE receiver #%d: interval for following error message class is at least %s",
144054359Sroberto		    CLK_UNIT(parse->peer), l_mktime(err->err_stage->err_delay));
144154359Sroberto
144254359Sroberto	if (!do_it)
144354359Sroberto	    err->err_suppressed++;
144454359Sroberto	else
144554359Sroberto	    err->err_last = current_time;
144654359Sroberto
144754359Sroberto	if (do_it && err->err_suppressed)
144854359Sroberto	{
144954359Sroberto		msyslog(LOG_INFO, "PARSE receiver #%d: %ld message%s suppressed, error condition class persists for %s",
145054359Sroberto			CLK_UNIT(parse->peer), err->err_suppressed, (err->err_suppressed == 1) ? " was" : "s where",
145154359Sroberto			l_mktime(current_time - err->err_started));
145254359Sroberto		err->err_suppressed = 0;
145354359Sroberto	}
145454359Sroberto
145554359Sroberto	return do_it;
145654359Sroberto}
145754359Sroberto
145854359Sroberto/*--------------------------------------------------
145954359Sroberto * mkreadable - make a printable ascii string (without
146054359Sroberto * embedded quotes so that the ntpq protocol isn't
146154359Sroberto * fooled
146254359Sroberto */
146354359Sroberto#ifndef isprint
146454359Sroberto#define isprint(_X_) (((_X_) > 0x1F) && ((_X_) < 0x7F))
146554359Sroberto#endif
146654359Sroberto
146754359Srobertostatic char *
146854359Srobertomkreadable(
146954359Sroberto	char  *buffer,
147054359Sroberto	long  blen,
147154359Sroberto	const char  *src,
147254359Sroberto	u_long  srclen,
147354359Sroberto	int hex
147454359Sroberto	)
147554359Sroberto{
147654359Sroberto	char *b    = buffer;
147754359Sroberto	char *endb = (char *)0;
147854359Sroberto
147954359Sroberto	if (blen < 4)
148054359Sroberto		return (char *)0;		/* don't bother with mini buffers */
148154359Sroberto
148254359Sroberto	endb = buffer + blen - 4;
148354359Sroberto
148454359Sroberto	blen--;			/* account for '\0' */
148554359Sroberto
148654359Sroberto	while (blen && srclen--)
148754359Sroberto	{
148854359Sroberto		if (!hex &&             /* no binary only */
148954359Sroberto		    (*src != '\\') &&   /* no plain \ */
149054359Sroberto		    (*src != '"') &&    /* no " */
149154359Sroberto		    isprint((int)*src))	/* only printables */
149254359Sroberto		{			/* they are easy... */
149354359Sroberto			*buffer++ = *src++;
149454359Sroberto			blen--;
149554359Sroberto		}
149654359Sroberto		else
149754359Sroberto		{
149854359Sroberto			if (blen < 4)
149954359Sroberto			{
150054359Sroberto				while (blen--)
150154359Sroberto				{
150254359Sroberto					*buffer++ = '.';
150354359Sroberto				}
150454359Sroberto				*buffer = '\0';
150554359Sroberto				return b;
150654359Sroberto			}
150754359Sroberto			else
150854359Sroberto			{
150954359Sroberto				if (*src == '\\')
151054359Sroberto				{
151154359Sroberto					strcpy(buffer,"\\\\");
151254359Sroberto					buffer += 2;
151354359Sroberto					blen   -= 2;
151454359Sroberto					src++;
151554359Sroberto				}
151654359Sroberto				else
151754359Sroberto				{
151854359Sroberto					sprintf(buffer, "\\x%02x", *src++);
151954359Sroberto					blen   -= 4;
152054359Sroberto					buffer += 4;
152154359Sroberto				}
152254359Sroberto			}
152354359Sroberto		}
152454359Sroberto		if (srclen && !blen && endb) /* overflow - set last chars to ... */
152554359Sroberto			strcpy(endb, "...");
152654359Sroberto	}
152754359Sroberto
152854359Sroberto	*buffer = '\0';
152954359Sroberto	return b;
153054359Sroberto}
153154359Sroberto
153254359Sroberto
153354359Sroberto/*--------------------------------------------------
153454359Sroberto * mkascii - make a printable ascii string
153554359Sroberto * assumes (unless defined better) 7-bit ASCII
153654359Sroberto */
153754359Srobertostatic char *
153854359Srobertomkascii(
153954359Sroberto	char  *buffer,
154054359Sroberto	long  blen,
154154359Sroberto	const char  *src,
154254359Sroberto	u_long  srclen
154354359Sroberto	)
154454359Sroberto{
154554359Sroberto	return mkreadable(buffer, blen, src, srclen, 0);
154654359Sroberto}
154754359Sroberto
154854359Sroberto/**===========================================================================
154954359Sroberto ** implementation of i/o handling methods
155054359Sroberto ** (all STREAM, partial STREAM, user level)
155154359Sroberto **/
155254359Sroberto
155354359Sroberto/*
155454359Sroberto * define possible io handling methods
155554359Sroberto */
155654359Sroberto#ifdef STREAM
155754359Srobertostatic int  ppsclock_init   P((struct parseunit *));
155854359Srobertostatic int  stream_init     P((struct parseunit *));
155954359Srobertostatic void stream_end      P((struct parseunit *));
156054359Srobertostatic int  stream_enable   P((struct parseunit *));
156154359Srobertostatic int  stream_disable  P((struct parseunit *));
156254359Srobertostatic int  stream_setcs    P((struct parseunit *, parsectl_t *));
156354359Srobertostatic int  stream_getfmt   P((struct parseunit *, parsectl_t *));
156454359Srobertostatic int  stream_setfmt   P((struct parseunit *, parsectl_t *));
156554359Srobertostatic int  stream_timecode P((struct parseunit *, parsectl_t *));
156654359Srobertostatic void stream_receive  P((struct recvbuf *));
156754359Sroberto#endif
156854359Sroberto
156954359Srobertostatic int  local_init     P((struct parseunit *));
157054359Srobertostatic void local_end      P((struct parseunit *));
157154359Srobertostatic int  local_nop      P((struct parseunit *));
157254359Srobertostatic int  local_setcs    P((struct parseunit *, parsectl_t *));
157354359Srobertostatic int  local_getfmt   P((struct parseunit *, parsectl_t *));
157454359Srobertostatic int  local_setfmt   P((struct parseunit *, parsectl_t *));
157554359Srobertostatic int  local_timecode P((struct parseunit *, parsectl_t *));
157654359Srobertostatic void local_receive  P((struct recvbuf *));
157754359Srobertostatic int  local_input    P((struct recvbuf *));
157854359Sroberto
157954359Srobertostatic bind_t io_bindings[] =
158054359Sroberto{
158154359Sroberto#ifdef STREAM
158254359Sroberto	{
158354359Sroberto		"parse STREAM",
158454359Sroberto		stream_init,
158554359Sroberto		stream_end,
158654359Sroberto		stream_setcs,
158754359Sroberto		stream_disable,
158854359Sroberto		stream_enable,
158954359Sroberto		stream_getfmt,
159054359Sroberto		stream_setfmt,
159154359Sroberto		stream_timecode,
159254359Sroberto		stream_receive,
159354359Sroberto		0,
159454359Sroberto	},
159554359Sroberto	{
159654359Sroberto		"ppsclock STREAM",
159754359Sroberto		ppsclock_init,
159854359Sroberto		local_end,
159954359Sroberto		local_setcs,
160054359Sroberto		local_nop,
160154359Sroberto		local_nop,
160254359Sroberto		local_getfmt,
160354359Sroberto		local_setfmt,
160454359Sroberto		local_timecode,
160554359Sroberto		local_receive,
160654359Sroberto		local_input,
160754359Sroberto	},
160854359Sroberto#endif
160954359Sroberto	{
161054359Sroberto		"normal",
161154359Sroberto		local_init,
161254359Sroberto		local_end,
161354359Sroberto		local_setcs,
161454359Sroberto		local_nop,
161554359Sroberto		local_nop,
161654359Sroberto		local_getfmt,
161754359Sroberto		local_setfmt,
161854359Sroberto		local_timecode,
161954359Sroberto		local_receive,
162054359Sroberto		local_input,
162154359Sroberto	},
162254359Sroberto	{
162354359Sroberto		(char *)0,
162454359Sroberto	}
162554359Sroberto};
162654359Sroberto
162754359Sroberto#ifdef STREAM
162854359Sroberto
162954359Sroberto#define fix_ts(_X_) \
163054359Sroberto                        if ((&(_X_))->tv.tv_usec >= 1000000)                \
163154359Sroberto                          {                                                 \
163254359Sroberto			    (&(_X_))->tv.tv_usec -= 1000000;                \
163354359Sroberto			    (&(_X_))->tv.tv_sec  += 1;                      \
163454359Sroberto			  }
163554359Sroberto
163654359Sroberto#define cvt_ts(_X_, _Y_) \
163754359Sroberto                        {                                                   \
163854359Sroberto			  l_fp ts;				            \
163954359Sroberto			  fix_ts((_X_));                                    \
164054359Sroberto			  if (!buftvtots((const char *)&(&(_X_))->tv, &ts)) \
164154359Sroberto			    {                                               \
164254359Sroberto                              ERR(ERR_BADDATA)	 		            \
164354359Sroberto                                msyslog(LOG_ERR,"parse: stream_receive: timestamp conversion error (buftvtots) (%s) (%ld.%06ld) ", (_Y_), (long)(&(_X_))->tv.tv_sec, (long)(&(_X_))->tv.tv_usec);\
164454359Sroberto			      return;                                       \
164554359Sroberto			    }                                               \
164654359Sroberto			  else                                              \
164754359Sroberto			    {                                               \
164854359Sroberto			      (&(_X_))->fp = ts;                            \
164954359Sroberto			    }                                               \
165054359Sroberto		        }
165154359Sroberto
165254359Sroberto/*--------------------------------------------------
165354359Sroberto * ppsclock STREAM init
165454359Sroberto */
165554359Srobertostatic int
165654359Srobertoppsclock_init(
165754359Sroberto	struct parseunit *parse
165854359Sroberto	)
165954359Sroberto{
166054359Sroberto        static char m1[] = "ppsclocd";
166154359Sroberto	static char m2[] = "ppsclock";
166254359Sroberto
166354359Sroberto	/*
166454359Sroberto	 * now push the parse streams module
166554359Sroberto	 * it will ensure exclusive access to the device
166654359Sroberto	 */
1667182007Sroberto	if (ioctl(parse->ppsfd, I_PUSH, (caddr_t)m1) == -1 &&
1668182007Sroberto	    ioctl(parse->ppsfd, I_PUSH, (caddr_t)m2) == -1)
166954359Sroberto	{
167054359Sroberto		if (errno != EINVAL)
167156746Sroberto		{
167256746Sroberto			msyslog(LOG_ERR, "PARSE receiver #%d: ppsclock_init: ioctl(fd, I_PUSH, \"ppsclock\"): %m",
167356746Sroberto				CLK_UNIT(parse->peer));
167454359Sroberto		}
167554359Sroberto		return 0;
167654359Sroberto	}
167754359Sroberto	if (!local_init(parse))
167854359Sroberto	{
1679182007Sroberto		(void)ioctl(parse->ppsfd, I_POP, (caddr_t)0);
168054359Sroberto		return 0;
168154359Sroberto	}
168254359Sroberto
168354359Sroberto	parse->flags |= PARSE_PPSCLOCK;
168454359Sroberto	return 1;
168554359Sroberto}
168654359Sroberto
168754359Sroberto/*--------------------------------------------------
168854359Sroberto * parse STREAM init
168954359Sroberto */
169054359Srobertostatic int
169154359Srobertostream_init(
169254359Sroberto	struct parseunit *parse
169354359Sroberto	)
169454359Sroberto{
169554359Sroberto	static char m1[] = "parse";
169654359Sroberto	/*
169754359Sroberto	 * now push the parse streams module
169854359Sroberto	 * to test whether it is there (neat interface 8-( )
169954359Sroberto	 */
170054359Sroberto	if (ioctl(parse->generic->io.fd, I_PUSH, (caddr_t)m1) == -1)
170154359Sroberto	{
170254359Sroberto		if (errno != EINVAL) /* accept non-existence */
170356746Sroberto		{
170456746Sroberto			msyslog(LOG_ERR, "PARSE receiver #%d: stream_init: ioctl(fd, I_PUSH, \"parse\"): %m", CLK_UNIT(parse->peer));
170554359Sroberto		}
170654359Sroberto		return 0;
170754359Sroberto	}
170854359Sroberto	else
170954359Sroberto	{
171054359Sroberto		while(ioctl(parse->generic->io.fd, I_POP, (caddr_t)0) == 0)
171154359Sroberto		    /* empty loop */;
171254359Sroberto
171354359Sroberto		/*
171454359Sroberto		 * now push it a second time after we have removed all
171554359Sroberto		 * module garbage
171654359Sroberto		 */
171754359Sroberto		if (ioctl(parse->generic->io.fd, I_PUSH, (caddr_t)m1) == -1)
171854359Sroberto		{
171954359Sroberto			msyslog(LOG_ERR, "PARSE receiver #%d: stream_init: ioctl(fd, I_PUSH, \"parse\"): %m", CLK_UNIT(parse->peer));
172054359Sroberto			return 0;
172154359Sroberto		}
172254359Sroberto		else
172354359Sroberto		{
172454359Sroberto			return 1;
172554359Sroberto		}
172654359Sroberto	}
172754359Sroberto}
172854359Sroberto
172954359Sroberto/*--------------------------------------------------
173054359Sroberto * parse STREAM end
173154359Sroberto */
173254359Srobertostatic void
173354359Srobertostream_end(
173454359Sroberto	struct parseunit *parse
173554359Sroberto	)
173654359Sroberto{
173754359Sroberto	while(ioctl(parse->generic->io.fd, I_POP, (caddr_t)0) == 0)
173854359Sroberto	    /* empty loop */;
173954359Sroberto}
174054359Sroberto
174154359Sroberto/*--------------------------------------------------
174254359Sroberto * STREAM setcs
174354359Sroberto */
174454359Srobertostatic int
174554359Srobertostream_setcs(
174654359Sroberto	struct parseunit *parse,
174754359Sroberto	parsectl_t  *tcl
174854359Sroberto	)
174954359Sroberto{
175054359Sroberto	struct strioctl strioc;
175154359Sroberto
175254359Sroberto	strioc.ic_cmd     = PARSEIOC_SETCS;
175354359Sroberto	strioc.ic_timout  = 0;
175454359Sroberto	strioc.ic_dp      = (char *)tcl;
175554359Sroberto	strioc.ic_len     = sizeof (*tcl);
175654359Sroberto
175754359Sroberto	if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1)
175854359Sroberto	{
175954359Sroberto		msyslog(LOG_ERR, "PARSE receiver #%d: stream_setcs: ioctl(fd, I_STR, PARSEIOC_SETCS): %m", CLK_UNIT(parse->peer));
176054359Sroberto		return 0;
176154359Sroberto	}
176254359Sroberto	return 1;
176354359Sroberto}
176454359Sroberto
176554359Sroberto/*--------------------------------------------------
176654359Sroberto * STREAM enable
176754359Sroberto */
176854359Srobertostatic int
176954359Srobertostream_enable(
177054359Sroberto	struct parseunit *parse
177154359Sroberto	)
177254359Sroberto{
177354359Sroberto	struct strioctl strioc;
177454359Sroberto
177554359Sroberto	strioc.ic_cmd     = PARSEIOC_ENABLE;
177654359Sroberto	strioc.ic_timout  = 0;
177754359Sroberto	strioc.ic_dp      = (char *)0;
177854359Sroberto	strioc.ic_len     = 0;
177954359Sroberto
178054359Sroberto	if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1)
178154359Sroberto	{
178254359Sroberto		msyslog(LOG_ERR, "PARSE receiver #%d: stream_enable: ioctl(fd, I_STR, PARSEIOC_ENABLE): %m", CLK_UNIT(parse->peer));
178354359Sroberto		return 0;
178454359Sroberto	}
178554359Sroberto	parse->generic->io.clock_recv = stream_receive; /* ok - parse input in kernel */
178654359Sroberto	return 1;
178754359Sroberto}
178854359Sroberto
178954359Sroberto/*--------------------------------------------------
179054359Sroberto * STREAM disable
179154359Sroberto */
179254359Srobertostatic int
179354359Srobertostream_disable(
179454359Sroberto	struct parseunit *parse
179554359Sroberto	)
179654359Sroberto{
179754359Sroberto	struct strioctl strioc;
179854359Sroberto
179954359Sroberto	strioc.ic_cmd     = PARSEIOC_DISABLE;
180054359Sroberto	strioc.ic_timout  = 0;
180154359Sroberto	strioc.ic_dp      = (char *)0;
180254359Sroberto	strioc.ic_len     = 0;
180354359Sroberto
180454359Sroberto	if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1)
180554359Sroberto	{
180654359Sroberto		msyslog(LOG_ERR, "PARSE receiver #%d: stream_disable: ioctl(fd, I_STR, PARSEIOC_DISABLE): %m", CLK_UNIT(parse->peer));
180754359Sroberto		return 0;
180854359Sroberto	}
180954359Sroberto	parse->generic->io.clock_recv = local_receive; /* ok - parse input in daemon */
181054359Sroberto	return 1;
181154359Sroberto}
181254359Sroberto
181354359Sroberto/*--------------------------------------------------
181454359Sroberto * STREAM getfmt
181554359Sroberto */
181654359Srobertostatic int
181754359Srobertostream_getfmt(
181854359Sroberto	struct parseunit *parse,
181954359Sroberto	parsectl_t  *tcl
182054359Sroberto	)
182154359Sroberto{
182254359Sroberto	struct strioctl strioc;
182354359Sroberto
182454359Sroberto	strioc.ic_cmd     = PARSEIOC_GETFMT;
182554359Sroberto	strioc.ic_timout  = 0;
182654359Sroberto	strioc.ic_dp      = (char *)tcl;
182754359Sroberto	strioc.ic_len     = sizeof (*tcl);
182854359Sroberto	if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1)
182954359Sroberto	{
183054359Sroberto		msyslog(LOG_ERR, "PARSE receiver #%d: ioctl(fd, I_STR, PARSEIOC_GETFMT): %m", CLK_UNIT(parse->peer));
183154359Sroberto		return 0;
183254359Sroberto	}
183354359Sroberto	return 1;
183454359Sroberto}
183554359Sroberto
183654359Sroberto/*--------------------------------------------------
183754359Sroberto * STREAM setfmt
183854359Sroberto */
183954359Srobertostatic int
184054359Srobertostream_setfmt(
184154359Sroberto	struct parseunit *parse,
184254359Sroberto	parsectl_t  *tcl
184354359Sroberto	)
184454359Sroberto{
184554359Sroberto	struct strioctl strioc;
184654359Sroberto
184754359Sroberto	strioc.ic_cmd     = PARSEIOC_SETFMT;
184854359Sroberto	strioc.ic_timout  = 0;
184954359Sroberto	strioc.ic_dp      = (char *)tcl;
185054359Sroberto	strioc.ic_len     = sizeof (*tcl);
185154359Sroberto
185254359Sroberto	if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1)
185354359Sroberto	{
185454359Sroberto		msyslog(LOG_ERR, "PARSE receiver #%d: stream_setfmt: ioctl(fd, I_STR, PARSEIOC_SETFMT): %m", CLK_UNIT(parse->peer));
185554359Sroberto		return 0;
185654359Sroberto	}
185754359Sroberto	return 1;
185854359Sroberto}
185954359Sroberto
186054359Sroberto
186154359Sroberto/*--------------------------------------------------
186254359Sroberto * STREAM timecode
186354359Sroberto */
186454359Srobertostatic int
186554359Srobertostream_timecode(
186654359Sroberto	struct parseunit *parse,
186754359Sroberto	parsectl_t  *tcl
186854359Sroberto	)
186954359Sroberto{
187054359Sroberto	struct strioctl strioc;
187154359Sroberto
187254359Sroberto	strioc.ic_cmd     = PARSEIOC_TIMECODE;
187354359Sroberto	strioc.ic_timout  = 0;
187454359Sroberto	strioc.ic_dp      = (char *)tcl;
187554359Sroberto	strioc.ic_len     = sizeof (*tcl);
187654359Sroberto
187754359Sroberto	if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1)
187854359Sroberto	{
187954359Sroberto		ERR(ERR_INTERNAL)
188054359Sroberto			msyslog(LOG_ERR, "PARSE receiver #%d: stream_timecode: ioctl(fd, I_STR, PARSEIOC_TIMECODE): %m", CLK_UNIT(parse->peer));
188154359Sroberto		return 0;
188254359Sroberto	}
188354359Sroberto	clear_err(parse, ERR_INTERNAL);
188454359Sroberto	return 1;
188554359Sroberto}
188654359Sroberto
188754359Sroberto/*--------------------------------------------------
188854359Sroberto * STREAM receive
188954359Sroberto */
189054359Srobertostatic void
189154359Srobertostream_receive(
189254359Sroberto	struct recvbuf *rbufp
189354359Sroberto	)
189454359Sroberto{
189554359Sroberto	struct parseunit *parse = (struct parseunit *)((void *)rbufp->recv_srcclock);
189654359Sroberto	parsetime_t parsetime;
189754359Sroberto
189854359Sroberto	if (!parse->peer)
189954359Sroberto	    return;
190054359Sroberto
190154359Sroberto	if (rbufp->recv_length != sizeof(parsetime_t))
190254359Sroberto	{
190354359Sroberto		ERR(ERR_BADIO)
190454359Sroberto			msyslog(LOG_ERR,"PARSE receiver #%d: stream_receive: bad size (got %d expected %d)",
190554359Sroberto				CLK_UNIT(parse->peer), rbufp->recv_length, (int)sizeof(parsetime_t));
190654359Sroberto		parse_event(parse, CEVNT_BADREPLY);
190754359Sroberto		return;
190854359Sroberto	}
190954359Sroberto	clear_err(parse, ERR_BADIO);
191054359Sroberto
191154359Sroberto	memmove((caddr_t)&parsetime,
191254359Sroberto		(caddr_t)rbufp->recv_buffer,
191354359Sroberto		sizeof(parsetime_t));
191454359Sroberto
191554359Sroberto#ifdef DEBUG
191654359Sroberto	if (debug > 3)
191754359Sroberto	  {
191854359Sroberto	    printf("PARSE receiver #%d: status %06x, state %08x, time %lx.%08lx, stime %lx.%08lx, ptime %lx.%08lx\n",
191954359Sroberto		   CLK_UNIT(parse->peer),
192054359Sroberto		   (unsigned int)parsetime.parse_status,
192154359Sroberto		   (unsigned int)parsetime.parse_state,
1922182007Sroberto		   (unsigned long)parsetime.parse_time.tv.tv_sec,
1923182007Sroberto		   (unsigned long)parsetime.parse_time.tv.tv_usec,
1924182007Sroberto		   (unsigned long)parsetime.parse_stime.tv.tv_sec,
1925182007Sroberto		   (unsigned long)parsetime.parse_stime.tv.tv_usec,
1926182007Sroberto		   (unsigned long)parsetime.parse_ptime.tv.tv_sec,
1927182007Sroberto		   (unsigned long)parsetime.parse_ptime.tv.tv_usec);
192854359Sroberto	  }
192954359Sroberto#endif
193054359Sroberto
193154359Sroberto	/*
193254359Sroberto	 * switch time stamp world - be sure to normalize small usec field
193354359Sroberto	 * errors.
193454359Sroberto	 */
193554359Sroberto
193654359Sroberto	cvt_ts(parsetime.parse_stime, "parse_stime");
193754359Sroberto
193854359Sroberto	if (PARSE_TIMECODE(parsetime.parse_state))
193954359Sroberto	{
194054359Sroberto	    cvt_ts(parsetime.parse_time, "parse_time");
194154359Sroberto	}
194254359Sroberto
194354359Sroberto	if (PARSE_PPS(parsetime.parse_state))
194454359Sroberto	    cvt_ts(parsetime.parse_ptime, "parse_ptime");
194554359Sroberto
194654359Sroberto	parse_process(parse, &parsetime);
194754359Sroberto}
194854359Sroberto#endif
194954359Sroberto
195054359Sroberto/*--------------------------------------------------
195154359Sroberto * local init
195254359Sroberto */
195354359Srobertostatic int
195454359Srobertolocal_init(
195554359Sroberto	struct parseunit *parse
195654359Sroberto	)
195754359Sroberto{
195854359Sroberto	return parse_ioinit(&parse->parseio);
195954359Sroberto}
196054359Sroberto
196154359Sroberto/*--------------------------------------------------
196254359Sroberto * local end
196354359Sroberto */
196454359Srobertostatic void
196554359Srobertolocal_end(
196654359Sroberto	struct parseunit *parse
196754359Sroberto	)
196854359Sroberto{
196954359Sroberto	parse_ioend(&parse->parseio);
197054359Sroberto}
197154359Sroberto
197254359Sroberto
197354359Sroberto/*--------------------------------------------------
197454359Sroberto * local nop
197554359Sroberto */
197654359Srobertostatic int
197754359Srobertolocal_nop(
197854359Sroberto	struct parseunit *parse
197954359Sroberto	)
198054359Sroberto{
198154359Sroberto	return 1;
198254359Sroberto}
198354359Sroberto
198454359Sroberto/*--------------------------------------------------
198554359Sroberto * local setcs
198654359Sroberto */
198754359Srobertostatic int
198854359Srobertolocal_setcs(
198954359Sroberto	struct parseunit *parse,
199054359Sroberto	parsectl_t  *tcl
199154359Sroberto	)
199254359Sroberto{
199354359Sroberto	return parse_setcs(tcl, &parse->parseio);
199454359Sroberto}
199554359Sroberto
199654359Sroberto/*--------------------------------------------------
199754359Sroberto * local getfmt
199854359Sroberto */
199954359Srobertostatic int
200054359Srobertolocal_getfmt(
200154359Sroberto	struct parseunit *parse,
200254359Sroberto	parsectl_t  *tcl
200354359Sroberto	)
200454359Sroberto{
200554359Sroberto	return parse_getfmt(tcl, &parse->parseio);
200654359Sroberto}
200754359Sroberto
200854359Sroberto/*--------------------------------------------------
200954359Sroberto * local setfmt
201054359Sroberto */
201154359Srobertostatic int
201254359Srobertolocal_setfmt(
201354359Sroberto	struct parseunit *parse,
201454359Sroberto	parsectl_t  *tcl
201554359Sroberto	)
201654359Sroberto{
201754359Sroberto	return parse_setfmt(tcl, &parse->parseio);
201854359Sroberto}
201954359Sroberto
202054359Sroberto/*--------------------------------------------------
202154359Sroberto * local timecode
202254359Sroberto */
202354359Srobertostatic int
202454359Srobertolocal_timecode(
202554359Sroberto	struct parseunit *parse,
202654359Sroberto	parsectl_t  *tcl
202754359Sroberto	)
202854359Sroberto{
202954359Sroberto	return parse_timecode(tcl, &parse->parseio);
203054359Sroberto}
203154359Sroberto
203254359Sroberto
203354359Sroberto/*--------------------------------------------------
203454359Sroberto * local input
203554359Sroberto */
203654359Srobertostatic int
203754359Srobertolocal_input(
203854359Sroberto	struct recvbuf *rbufp
203954359Sroberto	)
204054359Sroberto{
204154359Sroberto	struct parseunit *parse = (struct parseunit *)((void *)rbufp->recv_srcclock);
204254359Sroberto	int count;
204354359Sroberto	unsigned char *s;
204454359Sroberto	timestamp_t ts;
204554359Sroberto
204654359Sroberto	if (!parse->peer)
204754359Sroberto		return 0;
204854359Sroberto
204954359Sroberto	/*
205054359Sroberto	 * eat all characters, parsing then and feeding complete samples
205154359Sroberto	 */
205254359Sroberto	count = rbufp->recv_length;
205354359Sroberto	s = (unsigned char *)rbufp->recv_buffer;
205454359Sroberto	ts.fp = rbufp->recv_time;
205554359Sroberto
205654359Sroberto	while (count--)
205754359Sroberto	{
205854359Sroberto		if (parse_ioread(&parse->parseio, (unsigned int)(*s++), &ts))
205954359Sroberto		{
2060182007Sroberto			struct recvbuf *buf;
206154359Sroberto
206254359Sroberto			/*
206354359Sroberto			 * got something good to eat
206454359Sroberto			 */
206554359Sroberto			if (!PARSE_PPS(parse->parseio.parse_dtime.parse_state))
206654359Sroberto			{
2067182007Sroberto#ifdef HAVE_PPSAPI
2068182007Sroberto				if (parse->flags & PARSE_PPSCLOCK)
2069182007Sroberto				{
2070182007Sroberto					struct timespec pps_timeout;
2071182007Sroberto					pps_info_t      pps_info;
2072182007Sroberto
2073182007Sroberto					pps_timeout.tv_sec  = 0;
2074182007Sroberto					pps_timeout.tv_nsec = 0;
2075182007Sroberto
2076182007Sroberto					if (time_pps_fetch(parse->ppshandle, PPS_TSFMT_TSPEC, &pps_info,
2077182007Sroberto							   &pps_timeout) == 0)
2078182007Sroberto					{
2079182007Sroberto						if (pps_info.assert_sequence + pps_info.clear_sequence != parse->ppsserial)
2080182007Sroberto						{
2081182007Sroberto							double dtemp;
2082182007Sroberto
2083182007Sroberto						        struct timespec pts;
2084182007Sroberto							/*
2085182007Sroberto							 * add PPS time stamp if available via ppsclock module
2086182007Sroberto							 * and not supplied already.
2087182007Sroberto							 */
2088182007Sroberto							if (parse->flags & PARSE_CLEAR)
2089182007Sroberto							  pts = pps_info.clear_timestamp;
2090182007Sroberto							else
2091182007Sroberto							  pts = pps_info.assert_timestamp;
2092182007Sroberto
2093182007Sroberto							parse->parseio.parse_dtime.parse_ptime.fp.l_ui = pts.tv_sec + JAN_1970;
2094182007Sroberto
2095182007Sroberto							dtemp = pts.tv_nsec / 1e9;
2096182007Sroberto							if (dtemp < 0.) {
2097182007Sroberto								dtemp += 1;
2098182007Sroberto								parse->parseio.parse_dtime.parse_ptime.fp.l_ui--;
2099182007Sroberto							}
2100182007Sroberto							if (dtemp > 1.) {
2101182007Sroberto								dtemp -= 1;
2102182007Sroberto								parse->parseio.parse_dtime.parse_ptime.fp.l_ui++;
2103182007Sroberto							}
2104182007Sroberto							parse->parseio.parse_dtime.parse_ptime.fp.l_uf = dtemp * FRAC;
2105182007Sroberto
2106182007Sroberto						        parse->parseio.parse_dtime.parse_state |= PARSEB_PPS|PARSEB_S_PPS;
2107182007Sroberto#ifdef DEBUG
2108182007Sroberto							if (debug > 3)
2109182007Sroberto							{
2110182007Sroberto								printf(
2111182007Sroberto								       "parse: local_receive: fd %d PPSAPI seq %ld - PPS %s\n",
2112182007Sroberto								       rbufp->fd,
2113182007Sroberto								       (long)pps_info.assert_sequence + (long)pps_info.clear_sequence,
2114182007Sroberto								       lfptoa(&parse->parseio.parse_dtime.parse_ptime.fp, 6));
2115182007Sroberto							}
2116182007Sroberto#endif
2117182007Sroberto						}
2118182007Sroberto#ifdef DEBUG
2119182007Sroberto						else
2120182007Sroberto						{
2121182007Sroberto							if (debug > 3)
2122182007Sroberto							{
2123182007Sroberto								printf(
2124182007Sroberto								       "parse: local_receive: fd %d PPSAPI seq assert %ld, seq clear %ld - NO PPS event\n",
2125182007Sroberto								       rbufp->fd,
2126182007Sroberto								       (long)pps_info.assert_sequence, (long)pps_info.clear_sequence);
2127182007Sroberto							}
2128182007Sroberto						}
2129182007Sroberto#endif
2130182007Sroberto						parse->ppsserial = pps_info.assert_sequence + pps_info.clear_sequence;
2131182007Sroberto					}
2132182007Sroberto#ifdef DEBUG
2133182007Sroberto					else
2134182007Sroberto					{
2135182007Sroberto						if (debug > 3)
2136182007Sroberto						{
2137182007Sroberto							printf(
2138182007Sroberto							       "parse: local_receive: fd %d PPSAPI time_pps_fetch errno = %d\n",
2139182007Sroberto							       rbufp->fd,
2140182007Sroberto							       errno);
2141182007Sroberto						}
2142182007Sroberto					}
2143182007Sroberto#endif
2144182007Sroberto				}
2145182007Sroberto#else
214654359Sroberto#ifdef TIOCDCDTIMESTAMP
214754359Sroberto				struct timeval dcd_time;
214854359Sroberto
2149182007Sroberto				if (ioctl(parse->ppsfd, TIOCDCDTIMESTAMP, &dcd_time) != -1)
215054359Sroberto				{
215154359Sroberto					l_fp tstmp;
215254359Sroberto
215354359Sroberto					TVTOTS(&dcd_time, &tstmp);
215454359Sroberto					tstmp.l_ui += JAN_1970;
215554359Sroberto					L_SUB(&ts.fp, &tstmp);
215654359Sroberto					if (ts.fp.l_ui == 0)
215754359Sroberto					{
215854359Sroberto#ifdef DEBUG
215954359Sroberto						if (debug)
216054359Sroberto						{
216154359Sroberto							printf(
216254359Sroberto							       "parse: local_receive: fd %d DCDTIMESTAMP %s\n",
2163182007Sroberto							       parse->ppsfd,
216454359Sroberto							       lfptoa(&tstmp, 6));
216554359Sroberto							printf(" sigio %s\n",
216654359Sroberto							       lfptoa(&ts.fp, 6));
216754359Sroberto						}
216854359Sroberto#endif
216954359Sroberto						parse->parseio.parse_dtime.parse_ptime.fp = tstmp;
217054359Sroberto						parse->parseio.parse_dtime.parse_state |= PARSEB_PPS|PARSEB_S_PPS;
217154359Sroberto					}
217254359Sroberto				}
217354359Sroberto#else /* TIOCDCDTIMESTAMP */
217454359Sroberto#if defined(HAVE_STRUCT_PPSCLOCKEV) && (defined(HAVE_CIOGETEV) || defined(HAVE_TIOCGPPSEV))
217554359Sroberto				if (parse->flags & PARSE_PPSCLOCK)
2176182007Sroberto				  {
2177182007Sroberto				    l_fp tts;
2178182007Sroberto				    struct ppsclockev ev;
217954359Sroberto
218054359Sroberto#ifdef HAVE_CIOGETEV
2181182007Sroberto				    if (ioctl(parse->ppsfd, CIOGETEV, (caddr_t)&ev) == 0)
218254359Sroberto#endif
218354359Sroberto#ifdef HAVE_TIOCGPPSEV
2184182007Sroberto				    if (ioctl(parse->ppsfd, TIOCGPPSEV, (caddr_t)&ev) == 0)
218554359Sroberto#endif
218654359Sroberto					{
2187182007Sroberto					  if (ev.serial != parse->ppsserial)
2188182007Sroberto					    {
2189182007Sroberto					      /*
2190182007Sroberto					       * add PPS time stamp if available via ppsclock module
2191182007Sroberto					       * and not supplied already.
2192182007Sroberto					       */
2193182007Sroberto					      if (!buftvtots((const char *)&ev.tv, &tts))
219454359Sroberto						{
2195182007Sroberto						  ERR(ERR_BADDATA)
2196182007Sroberto						    msyslog(LOG_ERR,"parse: local_receive: timestamp conversion error (buftvtots) (ppsclockev.tv)");
219754359Sroberto						}
2198182007Sroberto					      else
2199182007Sroberto						{
2200182007Sroberto						  parse->parseio.parse_dtime.parse_ptime.fp = tts;
2201182007Sroberto						  parse->parseio.parse_dtime.parse_state |= PARSEB_PPS|PARSEB_S_PPS;
2202182007Sroberto						}
2203182007Sroberto					    }
2204182007Sroberto					  parse->ppsserial = ev.serial;
220554359Sroberto					}
2206182007Sroberto				  }
220754359Sroberto#endif
220854359Sroberto#endif /* TIOCDCDTIMESTAMP */
2209182007Sroberto#endif /* !HAVE_PPSAPI */
221054359Sroberto			}
221154359Sroberto			if (count)
221254359Sroberto			{	/* simulate receive */
2213182007Sroberto				buf = get_free_recv_buffer();
2214182007Sroberto				if (buf != NULL) {
2215182007Sroberto					memmove((caddr_t)buf->recv_buffer,
2216182007Sroberto						(caddr_t)&parse->parseio.parse_dtime,
2217182007Sroberto						sizeof(parsetime_t));
2218182007Sroberto					buf->recv_length  = sizeof(parsetime_t);
2219182007Sroberto					buf->recv_time    = rbufp->recv_time;
2220182007Sroberto					buf->srcadr       = rbufp->srcadr;
2221182007Sroberto					buf->dstadr       = rbufp->dstadr;
2222182007Sroberto					buf->receiver     = rbufp->receiver;
2223182007Sroberto					buf->fd           = rbufp->fd;
2224182007Sroberto					buf->X_from_where = rbufp->X_from_where;
2225182007Sroberto					add_full_recv_buffer(buf);
2226182007Sroberto				}
222754359Sroberto				parse_iodone(&parse->parseio);
222854359Sroberto			}
222954359Sroberto			else
223054359Sroberto			{
223156746Sroberto				memmove((caddr_t)rbufp->recv_buffer,
223256746Sroberto					(caddr_t)&parse->parseio.parse_dtime,
223356746Sroberto					sizeof(parsetime_t));
223456746Sroberto				parse_iodone(&parse->parseio);
223554359Sroberto				rbufp->recv_length = sizeof(parsetime_t);
223654359Sroberto				return 1; /* got something & in place return */
223754359Sroberto			}
223854359Sroberto		}
223954359Sroberto	}
224054359Sroberto	return 0;		/* nothing to pass up */
224154359Sroberto}
224254359Sroberto
224354359Sroberto/*--------------------------------------------------
224454359Sroberto * local receive
224554359Sroberto */
224654359Srobertostatic void
224754359Srobertolocal_receive(
224854359Sroberto	struct recvbuf *rbufp
224954359Sroberto	)
225054359Sroberto{
225154359Sroberto	struct parseunit *parse = (struct parseunit *)((void *)rbufp->recv_srcclock);
225254359Sroberto	parsetime_t parsetime;
225354359Sroberto
225454359Sroberto	if (!parse->peer)
225554359Sroberto	    return;
225654359Sroberto
225754359Sroberto	if (rbufp->recv_length != sizeof(parsetime_t))
225854359Sroberto	{
225954359Sroberto		ERR(ERR_BADIO)
226054359Sroberto			msyslog(LOG_ERR,"PARSE receiver #%d: local_receive: bad size (got %d expected %d)",
226154359Sroberto				CLK_UNIT(parse->peer), rbufp->recv_length, (int)sizeof(parsetime_t));
226254359Sroberto		parse_event(parse, CEVNT_BADREPLY);
226354359Sroberto		return;
226454359Sroberto	}
226554359Sroberto	clear_err(parse, ERR_BADIO);
226654359Sroberto
226754359Sroberto	memmove((caddr_t)&parsetime,
226854359Sroberto		(caddr_t)rbufp->recv_buffer,
226954359Sroberto		sizeof(parsetime_t));
227054359Sroberto
227154359Sroberto#ifdef DEBUG
227254359Sroberto	if (debug > 3)
227354359Sroberto	  {
2274182007Sroberto	    printf("PARSE receiver #%d: status %06x, state %08x, time(fp) %lx.%08lx, stime(fp) %lx.%08lx, ptime(fp) %lx.%08lx\n",
227554359Sroberto		   CLK_UNIT(parse->peer),
227654359Sroberto		   (unsigned int)parsetime.parse_status,
227754359Sroberto		   (unsigned int)parsetime.parse_state,
2278182007Sroberto		   (unsigned long)parsetime.parse_time.fp.l_ui,
2279182007Sroberto		   (unsigned long)parsetime.parse_time.fp.l_uf,
2280182007Sroberto		   (unsigned long)parsetime.parse_stime.fp.l_ui,
2281182007Sroberto		   (unsigned long)parsetime.parse_stime.fp.l_uf,
2282182007Sroberto		   (unsigned long)parsetime.parse_ptime.fp.l_ui,
2283182007Sroberto		   (unsigned long)parsetime.parse_ptime.fp.l_uf);
228454359Sroberto	  }
228554359Sroberto#endif
228654359Sroberto
228754359Sroberto	parse_process(parse, &parsetime);
228854359Sroberto}
228954359Sroberto
229054359Sroberto/*--------------------------------------------------
229154359Sroberto * init_iobinding - find and initialize lower layers
229254359Sroberto */
229354359Srobertostatic bind_t *
229454359Srobertoinit_iobinding(
229554359Sroberto	struct parseunit *parse
229654359Sroberto	)
229754359Sroberto{
229854359Sroberto  bind_t *b = io_bindings;
229954359Sroberto
230054359Sroberto	while (b->bd_description != (char *)0)
230154359Sroberto	{
230254359Sroberto		if ((*b->bd_init)(parse))
230354359Sroberto		{
230454359Sroberto			return b;
230554359Sroberto		}
230654359Sroberto		b++;
230754359Sroberto	}
230854359Sroberto	return (bind_t *)0;
230954359Sroberto}
231054359Sroberto
231154359Sroberto/**===========================================================================
231254359Sroberto ** support routines
231354359Sroberto **/
231454359Sroberto
231554359Sroberto/*--------------------------------------------------
231654359Sroberto * convert a flag field to a string
231754359Sroberto */
231854359Srobertostatic char *
231954359Srobertoparsestate(
232054359Sroberto	u_long lstate,
2321182007Sroberto	char *buffer,
2322182007Sroberto	int size
232354359Sroberto	)
232454359Sroberto{
232554359Sroberto	static struct bits
232654359Sroberto	{
232754359Sroberto		u_long      bit;
232854359Sroberto		const char *name;
232954359Sroberto	} flagstrings[] =
233054359Sroberto	  {
233156746Sroberto		  { PARSEB_ANNOUNCE,   "DST SWITCH WARNING" },
233256746Sroberto		  { PARSEB_POWERUP,    "NOT SYNCHRONIZED" },
233356746Sroberto		  { PARSEB_NOSYNC,     "TIME CODE NOT CONFIRMED" },
233456746Sroberto		  { PARSEB_DST,        "DST" },
233556746Sroberto		  { PARSEB_UTC,        "UTC DISPLAY" },
233656746Sroberto		  { PARSEB_LEAPADD,    "LEAP ADD WARNING" },
233756746Sroberto		  { PARSEB_LEAPDEL,    "LEAP DELETE WARNING" },
233854359Sroberto		  { PARSEB_LEAPSECOND, "LEAP SECOND" },
233956746Sroberto		  { PARSEB_ALTERNATE,  "ALTERNATE ANTENNA" },
234056746Sroberto		  { PARSEB_TIMECODE,   "TIME CODE" },
234156746Sroberto		  { PARSEB_PPS,        "PPS" },
234256746Sroberto		  { PARSEB_POSITION,   "POSITION" },
234354359Sroberto		  { 0 }
234454359Sroberto	  };
234554359Sroberto
234654359Sroberto	static struct sbits
234754359Sroberto	{
234854359Sroberto		u_long      bit;
234954359Sroberto		const char *name;
235054359Sroberto	} sflagstrings[] =
235154359Sroberto	  {
235254359Sroberto		  { PARSEB_S_LEAP,     "LEAP INDICATION" },
235354359Sroberto		  { PARSEB_S_PPS,      "PPS SIGNAL" },
235454359Sroberto		  { PARSEB_S_ANTENNA,  "ANTENNA" },
235554359Sroberto		  { PARSEB_S_POSITION, "POSITION" },
235654359Sroberto		  { 0 }
235754359Sroberto	  };
235854359Sroberto	int i;
2359182007Sroberto	char *s, *t;
236054359Sroberto
2361182007Sroberto
236254359Sroberto	*buffer = '\0';
2363182007Sroberto	s = t = buffer;
236454359Sroberto
236554359Sroberto	i = 0;
236654359Sroberto	while (flagstrings[i].bit)
236754359Sroberto	{
236854359Sroberto		if (flagstrings[i].bit & lstate)
236954359Sroberto		{
2370182007Sroberto			if (s != t)
2371182007Sroberto				strncpy(t, "; ", BUFFER_SIZES(buffer, t, size));
2372182007Sroberto			strncat(t, flagstrings[i].name, BUFFER_SIZES(buffer, t, size));
2373182007Sroberto			t += strlen(t);
237454359Sroberto		}
237554359Sroberto		i++;
237654359Sroberto	}
237754359Sroberto
237854359Sroberto	if (lstate & (PARSEB_S_LEAP|PARSEB_S_ANTENNA|PARSEB_S_PPS|PARSEB_S_POSITION))
237954359Sroberto	{
2380182007Sroberto		if (s != t)
2381182007Sroberto			strncpy(t, "; ", BUFFER_SIZES(buffer, t, size));
238254359Sroberto
2383182007Sroberto		t += strlen(t);
238454359Sroberto
2385182007Sroberto		strncpy(t, "(", BUFFER_SIZES(buffer, t, size));
238654359Sroberto
2387182007Sroberto		s = t = t + strlen(t);
238854359Sroberto
238954359Sroberto		i = 0;
239054359Sroberto		while (sflagstrings[i].bit)
239154359Sroberto		{
239254359Sroberto			if (sflagstrings[i].bit & lstate)
239354359Sroberto			{
239454359Sroberto				if (t != s)
239554359Sroberto				{
2396182007Sroberto					strncpy(t, "; ", BUFFER_SIZES(buffer, t, size));
239754359Sroberto					t += 2;
239854359Sroberto				}
239954359Sroberto
2400182007Sroberto				strncpy(t, sflagstrings[i].name, BUFFER_SIZES(buffer, t, size));
240154359Sroberto				t += strlen(t);
240254359Sroberto			}
240354359Sroberto			i++;
240454359Sroberto		}
2405182007Sroberto		strncpy(t, ")", BUFFER_SIZES(buffer, t, size));
240654359Sroberto	}
240754359Sroberto	return buffer;
240854359Sroberto}
240954359Sroberto
241054359Sroberto/*--------------------------------------------------
241154359Sroberto * convert a status flag field to a string
241254359Sroberto */
241354359Srobertostatic char *
241454359Srobertoparsestatus(
241554359Sroberto	u_long lstate,
2416182007Sroberto	char *buffer,
2417182007Sroberto	int size
241854359Sroberto	)
241954359Sroberto{
242054359Sroberto	static struct bits
242154359Sroberto	{
242254359Sroberto		u_long      bit;
242354359Sroberto		const char *name;
242454359Sroberto	} flagstrings[] =
242554359Sroberto	  {
242654359Sroberto		  { CVT_OK,      "CONVERSION SUCCESSFUL" },
242754359Sroberto		  { CVT_NONE,    "NO CONVERSION" },
242854359Sroberto		  { CVT_FAIL,    "CONVERSION FAILED" },
242954359Sroberto		  { CVT_BADFMT,  "ILLEGAL FORMAT" },
243054359Sroberto		  { CVT_BADDATE, "DATE ILLEGAL" },
243154359Sroberto		  { CVT_BADTIME, "TIME ILLEGAL" },
243254359Sroberto		  { CVT_ADDITIONAL, "ADDITIONAL DATA" },
243354359Sroberto		  { 0 }
243454359Sroberto	  };
243554359Sroberto	int i;
243654359Sroberto
243754359Sroberto	*buffer = '\0';
243854359Sroberto
243954359Sroberto	i = 0;
244054359Sroberto	while (flagstrings[i].bit)
244154359Sroberto	{
244254359Sroberto		if (flagstrings[i].bit & lstate)
244354359Sroberto		{
244454359Sroberto			if (buffer[0])
2445182007Sroberto				strncat(buffer, "; ", size);
2446182007Sroberto			strncat(buffer, flagstrings[i].name, size);
244754359Sroberto		}
244854359Sroberto		i++;
244954359Sroberto	}
245054359Sroberto
245154359Sroberto	return buffer;
245254359Sroberto}
245354359Sroberto
245454359Sroberto/*--------------------------------------------------
245554359Sroberto * convert a clock status flag field to a string
245654359Sroberto */
245754359Srobertostatic const char *
245854359Srobertoclockstatus(
245954359Sroberto	u_long lstate
246054359Sroberto	)
246154359Sroberto{
246254359Sroberto	static char buffer[20];
246354359Sroberto	static struct status
246454359Sroberto	{
246554359Sroberto		u_long      value;
246654359Sroberto		const char *name;
246754359Sroberto	} flagstrings[] =
246854359Sroberto	  {
246954359Sroberto		  { CEVNT_NOMINAL, "NOMINAL" },
247054359Sroberto		  { CEVNT_TIMEOUT, "NO RESPONSE" },
247154359Sroberto		  { CEVNT_BADREPLY,"BAD FORMAT" },
247254359Sroberto		  { CEVNT_FAULT,   "FAULT" },
247354359Sroberto		  { CEVNT_PROP,    "PROPAGATION DELAY" },
247454359Sroberto		  { CEVNT_BADDATE, "ILLEGAL DATE" },
247554359Sroberto		  { CEVNT_BADTIME, "ILLEGAL TIME" },
247654359Sroberto		  { (unsigned)~0L }
247754359Sroberto	  };
247854359Sroberto	int i;
247954359Sroberto
248054359Sroberto	i = 0;
248154359Sroberto	while (flagstrings[i].value != ~0)
248254359Sroberto	{
248354359Sroberto		if (flagstrings[i].value == lstate)
248454359Sroberto		{
248554359Sroberto			return flagstrings[i].name;
248654359Sroberto		}
248754359Sroberto		i++;
248854359Sroberto	}
248954359Sroberto
2490182007Sroberto	snprintf(buffer, sizeof(buffer), "unknown #%ld", (u_long)lstate);
249154359Sroberto
249254359Sroberto	return buffer;
249354359Sroberto}
249454359Sroberto
249554359Sroberto
249654359Sroberto/*--------------------------------------------------
249754359Sroberto * l_mktime - make representation of a relative time
249854359Sroberto */
249954359Srobertostatic char *
250054359Srobertol_mktime(
250154359Sroberto	u_long delta
250254359Sroberto	)
250354359Sroberto{
250454359Sroberto	u_long tmp, m, s;
250554359Sroberto	static char buffer[40];
2506182007Sroberto	char *t;
250754359Sroberto
250854359Sroberto	buffer[0] = '\0';
250954359Sroberto
251054359Sroberto	if ((tmp = delta / (60*60*24)) != 0)
251154359Sroberto	{
2512182007Sroberto		snprintf(buffer, BUFFER_SIZE(buffer, buffer), "%ldd+", (u_long)tmp);
251354359Sroberto		delta -= tmp * 60*60*24;
251454359Sroberto	}
251554359Sroberto
251654359Sroberto	s = delta % 60;
251754359Sroberto	delta /= 60;
251854359Sroberto	m = delta % 60;
251954359Sroberto	delta /= 60;
252054359Sroberto
2521182007Sroberto	t = buffer + strlen(buffer);
252254359Sroberto
2523182007Sroberto	snprintf(t, BUFFER_SIZE(buffer, t), "%02d:%02d:%02d",
2524182007Sroberto		 (int)delta, (int)m, (int)s);
2525182007Sroberto
252654359Sroberto	return buffer;
252754359Sroberto}
252854359Sroberto
252954359Sroberto
253054359Sroberto/*--------------------------------------------------
253154359Sroberto * parse_statistics - list summary of clock states
253254359Sroberto */
253354359Srobertostatic void
253454359Srobertoparse_statistics(
253554359Sroberto	struct parseunit *parse
253654359Sroberto	)
253754359Sroberto{
253854359Sroberto	int i;
253954359Sroberto
254054359Sroberto	NLOG(NLOG_CLOCKSTATIST) /* conditional if clause for conditional syslog */
254154359Sroberto		{
254254359Sroberto			msyslog(LOG_INFO, "PARSE receiver #%d: running time: %s",
254354359Sroberto				CLK_UNIT(parse->peer),
254454359Sroberto				l_mktime(current_time - parse->generic->timestarted));
254554359Sroberto
254654359Sroberto			msyslog(LOG_INFO, "PARSE receiver #%d: current status: %s",
254754359Sroberto				CLK_UNIT(parse->peer),
254854359Sroberto				clockstatus(parse->generic->currentstatus));
254954359Sroberto
255054359Sroberto			for (i = 0; i <= CEVNT_MAX; i++)
255154359Sroberto			{
255254359Sroberto				u_long s_time;
255354359Sroberto				u_long percent, d = current_time - parse->generic->timestarted;
255454359Sroberto
255554359Sroberto				percent = s_time = PARSE_STATETIME(parse, i);
255654359Sroberto
255754359Sroberto				while (((u_long)(~0) / 10000) < percent)
255854359Sroberto				{
255954359Sroberto					percent /= 10;
256054359Sroberto					d       /= 10;
256154359Sroberto				}
256254359Sroberto
256354359Sroberto				if (d)
256454359Sroberto				    percent = (percent * 10000) / d;
256554359Sroberto				else
256654359Sroberto				    percent = 10000;
256754359Sroberto
256854359Sroberto				if (s_time)
256954359Sroberto				    msyslog(LOG_INFO, "PARSE receiver #%d: state %18s: %13s (%3ld.%02ld%%)",
257054359Sroberto					    CLK_UNIT(parse->peer),
257154359Sroberto					    clockstatus((unsigned int)i),
257254359Sroberto					    l_mktime(s_time),
257354359Sroberto					    percent / 100, percent % 100);
257454359Sroberto			}
257554359Sroberto		}
257654359Sroberto}
257754359Sroberto
257854359Sroberto/*--------------------------------------------------
257954359Sroberto * cparse_statistics - wrapper for statistics call
258054359Sroberto */
258154359Srobertostatic void
258254359Srobertocparse_statistics(
2583182007Sroberto        struct parseunit *parse
258454359Sroberto	)
258554359Sroberto{
258654359Sroberto	if (parse->laststatistic + PARSESTATISTICS < current_time)
258754359Sroberto		parse_statistics(parse);
258854359Sroberto	parse->laststatistic = current_time;
258954359Sroberto}
259054359Sroberto
259154359Sroberto/**===========================================================================
259254359Sroberto ** ntp interface routines
259354359Sroberto **/
259454359Sroberto
259554359Sroberto/*--------------------------------------------------
259654359Sroberto * parse_shutdown - shut down a PARSE clock
259754359Sroberto */
259854359Srobertostatic void
259954359Srobertoparse_shutdown(
260054359Sroberto	int unit,
260154359Sroberto	struct peer *peer
260254359Sroberto	)
260354359Sroberto{
2604182007Sroberto	struct parseunit *parse = (struct parseunit *)0;
260554359Sroberto
2606182007Sroberto	if (peer && peer->procptr)
2607182007Sroberto		parse = (struct parseunit *)peer->procptr->unitptr;
2608182007Sroberto
2609182007Sroberto	if (!parse)
261054359Sroberto	{
2611182007Sroberto		/* nothing to clean up */
261254359Sroberto		return;
261354359Sroberto	}
261454359Sroberto
2615182007Sroberto        if (!parse->peer)
2616182007Sroberto	{
2617182007Sroberto		msyslog(LOG_INFO, "PARSE receiver #%d: INTERNAL ERROR - unit already inactive - shutdown ignored", unit);
2618182007Sroberto		return;
2619182007Sroberto	}
2620182007Sroberto
2621182007Sroberto#ifdef HAVE_PPSAPI
2622182007Sroberto	if (parse->flags & PARSE_PPSCLOCK)
2623182007Sroberto	{
2624182007Sroberto		(void)time_pps_destroy(parse->ppshandle);
2625182007Sroberto	}
2626182007Sroberto#endif
2627182007Sroberto	if (parse->generic->io.fd != parse->ppsfd && parse->ppsfd != -1)
2628182007Sroberto		(void)close(parse->ppsfd);  /* close separate PPS source */
2629182007Sroberto
263054359Sroberto	/*
263154359Sroberto	 * print statistics a last time and
263254359Sroberto	 * stop statistics machine
263354359Sroberto	 */
263454359Sroberto	parse_statistics(parse);
263554359Sroberto
263654359Sroberto	if (parse->parse_type->cl_end)
263754359Sroberto	{
263854359Sroberto		parse->parse_type->cl_end(parse);
263954359Sroberto	}
264054359Sroberto
2641182007Sroberto	/*
2642182007Sroberto	 * cleanup before leaving this world
2643182007Sroberto	 */
264454359Sroberto	if (parse->binding)
264554359Sroberto	    PARSE_END(parse);
264654359Sroberto
264754359Sroberto	/*
264854359Sroberto	 * Tell the I/O module to turn us off.  We're history.
264954359Sroberto	 */
265054359Sroberto	io_closeclock(&parse->generic->io);
265154359Sroberto
265254359Sroberto	free_varlist(parse->kv);
265354359Sroberto
265454359Sroberto	NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */
265554359Sroberto		msyslog(LOG_INFO, "PARSE receiver #%d: reference clock \"%s\" removed",
265654359Sroberto			CLK_UNIT(parse->peer), parse->parse_type->cl_description);
265754359Sroberto
265854359Sroberto	parse->peer = (struct peer *)0; /* unused now */
2659182007Sroberto	peer->procptr->unitptr = (caddr_t)0;
266054359Sroberto	free(parse);
266154359Sroberto}
266254359Sroberto
2663182007Sroberto#ifdef HAVE_PPSAPI
2664182007Sroberto/*----------------------------------------
2665182007Sroberto * set up HARDPPS via PPSAPI
2666182007Sroberto */
2667182007Srobertostatic void
2668182007Srobertoparse_hardpps(
2669182007Sroberto	      struct parseunit *parse,
2670182007Sroberto	      int mode
2671182007Sroberto	      )
2672182007Sroberto{
2673182007Sroberto        if (parse->hardppsstate == mode)
2674182007Sroberto	        return;
2675182007Sroberto
2676182007Sroberto	if (CLK_PPS(parse->peer) && (parse->flags & PARSE_PPSKERNEL)) {
2677182007Sroberto		int	i = 0;
2678182007Sroberto
2679182007Sroberto		if (mode == PARSE_HARDPPS_ENABLE)
2680182007Sroberto		        {
2681182007Sroberto			        if (parse->flags & PARSE_CLEAR)
2682182007Sroberto				        i = PPS_CAPTURECLEAR;
2683182007Sroberto				else
2684182007Sroberto				        i = PPS_CAPTUREASSERT;
2685182007Sroberto			}
2686182007Sroberto
2687182007Sroberto		if (time_pps_kcbind(parse->ppshandle, PPS_KC_HARDPPS, i,
2688182007Sroberto		    PPS_TSFMT_TSPEC) < 0) {
2689182007Sroberto		        msyslog(LOG_ERR, "PARSE receiver #%d: time_pps_kcbind failed: %m",
2690182007Sroberto				CLK_UNIT(parse->peer));
2691182007Sroberto		} else {
2692182007Sroberto		        NLOG(NLOG_CLOCKINFO)
2693182007Sroberto		                msyslog(LOG_INFO, "PARSE receiver #%d: kernel PPS synchronisation %sabled",
2694182007Sroberto					CLK_UNIT(parse->peer), (mode == PARSE_HARDPPS_ENABLE) ? "en" : "dis");
2695182007Sroberto			/*
2696182007Sroberto			 * tell the rest, that we have a kernel PPS source, iff we ever enable HARDPPS
2697182007Sroberto			 */
2698182007Sroberto			if (mode == PARSE_HARDPPS_ENABLE)
2699182007Sroberto			        pps_enable = 1;
2700182007Sroberto		}
2701182007Sroberto	}
2702182007Sroberto
2703182007Sroberto	parse->hardppsstate = mode;
2704182007Sroberto}
2705182007Sroberto
2706182007Sroberto/*----------------------------------------
2707182007Sroberto * set up PPS via PPSAPI
2708182007Sroberto */
2709182007Srobertostatic int
2710182007Srobertoparse_ppsapi(
2711182007Sroberto	     struct parseunit *parse
2712182007Sroberto	)
2713182007Sroberto{
2714182007Sroberto	int cap, mode, mode1;
2715182007Sroberto	char *cp;
2716182007Sroberto
2717182007Sroberto	parse->flags &= ~PARSE_PPSCLOCK;
2718182007Sroberto
2719182007Sroberto	if (time_pps_getcap(parse->ppshandle, &cap) < 0) {
2720182007Sroberto		msyslog(LOG_ERR, "PARSE receiver #%d: parse_ppsapi: time_pps_getcap failed: %m",
2721182007Sroberto			CLK_UNIT(parse->peer));
2722182007Sroberto
2723182007Sroberto		return 0;
2724182007Sroberto	}
2725182007Sroberto
2726182007Sroberto	if (time_pps_getparams(parse->ppshandle, &parse->ppsparams) < 0) {
2727182007Sroberto		msyslog(LOG_ERR, "PARSE receiver #%d: parse_ppsapi: time_pps_getparams failed: %m",
2728182007Sroberto			CLK_UNIT(parse->peer));
2729182007Sroberto		return 0;
2730182007Sroberto	}
2731182007Sroberto
2732182007Sroberto	/* nb. only turn things on, if someone else has turned something
2733182007Sroberto	 *	on before we get here, leave it alone!
2734182007Sroberto	 */
2735182007Sroberto
2736182007Sroberto	if (parse->flags & PARSE_CLEAR) {
2737182007Sroberto		cp = "CLEAR";
2738182007Sroberto		mode = PPS_CAPTURECLEAR;
2739182007Sroberto		mode1 = PPS_OFFSETCLEAR;
2740182007Sroberto	} else {
2741182007Sroberto		cp = "ASSERT";
2742182007Sroberto		mode = PPS_CAPTUREASSERT;
2743182007Sroberto		mode1 = PPS_OFFSETASSERT;
2744182007Sroberto	}
2745182007Sroberto
2746182007Sroberto	msyslog(LOG_INFO, "PARSE receiver #%d: initializing PPS to %s",
2747182007Sroberto		CLK_UNIT(parse->peer), cp);
2748182007Sroberto
2749182007Sroberto	if (!(mode & cap)) {
2750182007Sroberto	  msyslog(LOG_ERR, "PARSE receiver #%d: FAILED to initialize PPS to %s (PPS API capabilities=0x%x)",
2751182007Sroberto		  CLK_UNIT(parse->peer), cp, cap);
2752182007Sroberto
2753182007Sroberto		return 0;
2754182007Sroberto	}
2755182007Sroberto
2756182007Sroberto	if (!(mode1 & cap)) {
2757182007Sroberto	  msyslog(LOG_WARNING, "PARSE receiver #%d: Cannot set PPS_%sCLEAR, this will increase jitter (PPS API capabilities=0x%x)",
2758182007Sroberto		  CLK_UNIT(parse->peer), cp, cap);
2759182007Sroberto		mode1 = 0;
2760182007Sroberto	} else {
2761182007Sroberto	        if (mode1 == PPS_OFFSETCLEAR)
2762182007Sroberto		        {
2763182007Sroberto			        parse->ppsparams.clear_offset.tv_sec = -parse->ppsphaseadjust;
2764182007Sroberto			        parse->ppsparams.clear_offset.tv_nsec = -1e9*(parse->ppsphaseadjust - (long)parse->ppsphaseadjust);
2765182007Sroberto			}
2766182007Sroberto
2767182007Sroberto		if (mode1 == PPS_OFFSETASSERT)
2768182007Sroberto	                {
2769182007Sroberto		                parse->ppsparams.assert_offset.tv_sec = -parse->ppsphaseadjust;
2770182007Sroberto				parse->ppsparams.assert_offset.tv_nsec = -1e9*(parse->ppsphaseadjust - (long)parse->ppsphaseadjust);
2771182007Sroberto			}
2772182007Sroberto	}
2773182007Sroberto
2774182007Sroberto	/* only set what is legal */
2775182007Sroberto
2776182007Sroberto	parse->ppsparams.mode = (mode | mode1 | PPS_TSFMT_TSPEC) & cap;
2777182007Sroberto
2778182007Sroberto	if (time_pps_setparams(parse->ppshandle, &parse->ppsparams) < 0) {
2779182007Sroberto	  msyslog(LOG_ERR, "PARSE receiver #%d: FAILED set PPS parameters: %m",
2780182007Sroberto		  CLK_UNIT(parse->peer));
2781182007Sroberto		return 0;
2782182007Sroberto	}
2783182007Sroberto
2784182007Sroberto	parse->flags |= PARSE_PPSCLOCK;
2785182007Sroberto	return 1;
2786182007Sroberto}
2787182007Sroberto#else
2788182007Sroberto#define parse_hardpps(_PARSE_, _MODE_) /* empty */
2789182007Sroberto#endif
2790182007Sroberto
279154359Sroberto/*--------------------------------------------------
279254359Sroberto * parse_start - open the PARSE devices and initialize data for processing
279354359Sroberto */
279454359Srobertostatic int
279554359Srobertoparse_start(
279654359Sroberto	int sysunit,
279754359Sroberto	struct peer *peer
279854359Sroberto	)
279954359Sroberto{
280054359Sroberto	u_int unit;
280154359Sroberto	int fd232;
280254359Sroberto#ifdef HAVE_TERMIOS
280354359Sroberto	struct termios tio;		/* NEEDED FOR A LONG TIME ! */
280454359Sroberto#endif
280554359Sroberto#ifdef HAVE_SYSV_TTYS
280654359Sroberto	struct termio tio;		/* NEEDED FOR A LONG TIME ! */
280754359Sroberto#endif
280854359Sroberto	struct parseunit * parse;
280954359Sroberto	char parsedev[sizeof(PARSEDEVICE)+20];
2810182007Sroberto	char parseppsdev[sizeof(PARSEPPSDEVICE)+20];
281154359Sroberto	parsectl_t tmp_ctl;
281254359Sroberto	u_int type;
281354359Sroberto
2814182007Sroberto	/*
2815182007Sroberto	 * get out Copyright information once
2816182007Sroberto	 */
2817182007Sroberto	if (!notice)
2818182007Sroberto        {
2819182007Sroberto		NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */
2820182007Sroberto			msyslog(LOG_INFO, "NTP PARSE support: Copyright (c) 1989-2006, Frank Kardel");
2821182007Sroberto		notice = 1;
2822182007Sroberto	}
2823182007Sroberto
282454359Sroberto	type = CLK_TYPE(peer);
282554359Sroberto	unit = CLK_UNIT(peer);
282654359Sroberto
282754359Sroberto	if ((type == ~0) || (parse_clockinfo[type].cl_description == (char *)0))
282854359Sroberto	{
282954359Sroberto		msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: unsupported clock type %d (max %d)",
283054359Sroberto			unit, CLK_REALTYPE(peer), ncltypes-1);
283154359Sroberto		return 0;
283254359Sroberto	}
283354359Sroberto
283454359Sroberto	/*
283554359Sroberto	 * Unit okay, attempt to open the device.
283654359Sroberto	 */
2837182007Sroberto	(void) snprintf(parsedev, sizeof(parsedev), PARSEDEVICE, unit);
2838182007Sroberto	(void) snprintf(parseppsdev, sizeof(parsedev), PARSEPPSDEVICE, unit);
283954359Sroberto
284054359Sroberto#ifndef O_NOCTTY
284154359Sroberto#define O_NOCTTY 0
284254359Sroberto#endif
284354359Sroberto
284454359Sroberto	fd232 = open(parsedev, O_RDWR | O_NOCTTY
284554359Sroberto#ifdef O_NONBLOCK
284654359Sroberto		     | O_NONBLOCK
284754359Sroberto#endif
284854359Sroberto		     , 0777);
284954359Sroberto
285054359Sroberto	if (fd232 == -1)
285154359Sroberto	{
285254359Sroberto		msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: open of %s failed: %m", unit, parsedev);
285354359Sroberto		return 0;
285454359Sroberto	}
285554359Sroberto
285654359Sroberto	parse = (struct parseunit *)emalloc(sizeof(struct parseunit));
285754359Sroberto
285854359Sroberto	memset((char *)parse, 0, sizeof(struct parseunit));
285954359Sroberto
286054359Sroberto	parse->generic = peer->procptr;	 /* link up */
286154359Sroberto	parse->generic->unitptr = (caddr_t)parse; /* link down */
286254359Sroberto
286354359Sroberto	/*
286454359Sroberto	 * Set up the structures
286554359Sroberto	 */
286654359Sroberto	parse->generic->timestarted    = current_time;
286754359Sroberto	parse->lastchange     = current_time;
286854359Sroberto
286954359Sroberto	parse->flags          = 0;
287054359Sroberto	parse->pollneeddata   = 0;
287154359Sroberto	parse->laststatistic  = current_time;
287254359Sroberto	parse->lastformat     = (unsigned short)~0;	/* assume no format known */
2873182007Sroberto	parse->timedata.parse_status = (unsigned short)~0;	/* be sure to mark initial status change */
287454359Sroberto	parse->lastmissed     = 0;	/* assume got everything */
287554359Sroberto	parse->ppsserial      = 0;
2876182007Sroberto	parse->ppsfd	      = -1;
287754359Sroberto	parse->localdata      = (void *)0;
287854359Sroberto	parse->localstate     = 0;
287954359Sroberto	parse->kv             = (struct ctl_var *)0;
288054359Sroberto
288154359Sroberto	clear_err(parse, ERR_ALL);
288254359Sroberto
288354359Sroberto	parse->parse_type     = &parse_clockinfo[type];
288454359Sroberto
2885182007Sroberto	parse->maxunsync      = parse->parse_type->cl_maxunsync;
2886182007Sroberto
288754359Sroberto	parse->generic->fudgetime1 = parse->parse_type->cl_basedelay;
288854359Sroberto
288954359Sroberto	parse->generic->fudgetime2 = 0.0;
2890182007Sroberto	parse->ppsphaseadjust = parse->generic->fudgetime2;
289154359Sroberto
2892182007Sroberto	parse->generic->clockdesc  = parse->parse_type->cl_description;
289354359Sroberto
289454359Sroberto	peer->rootdelay       = parse->parse_type->cl_rootdelay;
289554359Sroberto	peer->sstclktype      = parse->parse_type->cl_type;
289654359Sroberto	peer->precision       = sys_precision;
289754359Sroberto
289854359Sroberto	peer->stratum         = STRATUM_REFCLOCK;
2899182007Sroberto
290054359Sroberto	if (peer->stratum <= 1)
290154359Sroberto	    memmove((char *)&parse->generic->refid, parse->parse_type->cl_id, 4);
290254359Sroberto	else
290354359Sroberto	    parse->generic->refid = htonl(PARSEHSREFID);
290454359Sroberto
290554359Sroberto	parse->generic->io.fd = fd232;
290654359Sroberto
290754359Sroberto	parse->peer = peer;		/* marks it also as busy */
290854359Sroberto
290954359Sroberto	/*
291054359Sroberto	 * configure terminal line
291154359Sroberto	 */
291254359Sroberto	if (TTY_GETATTR(fd232, &tio) == -1)
291354359Sroberto	{
291454359Sroberto		msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: tcgetattr(%d, &tio): %m", unit, fd232);
291554359Sroberto		parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
291654359Sroberto		return 0;
291754359Sroberto	}
291854359Sroberto	else
291954359Sroberto	{
292054359Sroberto#ifndef _PC_VDISABLE
292154359Sroberto		memset((char *)tio.c_cc, 0, sizeof(tio.c_cc));
292254359Sroberto#else
292354359Sroberto		int disablec;
292454359Sroberto		errno = 0;		/* pathconf can deliver -1 without changing errno ! */
292554359Sroberto
292654359Sroberto		disablec = fpathconf(parse->generic->io.fd, _PC_VDISABLE);
292754359Sroberto		if (disablec == -1 && errno)
292854359Sroberto		{
292954359Sroberto			msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: fpathconf(fd, _PC_VDISABLE): %m", CLK_UNIT(parse->peer));
293054359Sroberto			memset((char *)tio.c_cc, 0, sizeof(tio.c_cc)); /* best guess */
293154359Sroberto		}
293254359Sroberto		else
293354359Sroberto		    if (disablec != -1)
293454359Sroberto			memset((char *)tio.c_cc, disablec, sizeof(tio.c_cc));
293554359Sroberto#endif
293654359Sroberto
293754359Sroberto#if defined (VMIN) || defined(VTIME)
293854359Sroberto		if ((parse_clockinfo[type].cl_lflag & ICANON) == 0)
293954359Sroberto		{
294054359Sroberto#ifdef VMIN
294154359Sroberto			tio.c_cc[VMIN]   = 1;
294254359Sroberto#endif
294354359Sroberto#ifdef VTIME
294454359Sroberto			tio.c_cc[VTIME]  = 0;
294554359Sroberto#endif
294654359Sroberto		}
294754359Sroberto#endif
294854359Sroberto
294954359Sroberto		tio.c_cflag = parse_clockinfo[type].cl_cflag;
295054359Sroberto		tio.c_iflag = parse_clockinfo[type].cl_iflag;
295154359Sroberto		tio.c_oflag = parse_clockinfo[type].cl_oflag;
295254359Sroberto		tio.c_lflag = parse_clockinfo[type].cl_lflag;
295354359Sroberto
295454359Sroberto
295554359Sroberto#ifdef HAVE_TERMIOS
295654359Sroberto		if ((cfsetospeed(&tio, parse_clockinfo[type].cl_speed) == -1) ||
295754359Sroberto		    (cfsetispeed(&tio, parse_clockinfo[type].cl_speed) == -1))
295854359Sroberto		{
295954359Sroberto			msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: tcset{i,o}speed(&tio, speed): %m", unit);
296054359Sroberto			parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
296154359Sroberto			return 0;
296254359Sroberto		}
296354359Sroberto#else
296454359Sroberto		tio.c_cflag     |= parse_clockinfo[type].cl_speed;
296554359Sroberto#endif
296654359Sroberto
2967182007Sroberto		/*
2968182007Sroberto		 * set up pps device
2969182007Sroberto		 * if the PARSEPPSDEVICE can be opened that will be used
2970182007Sroberto		 * for PPS else PARSEDEVICE will be used
2971182007Sroberto		 */
2972182007Sroberto		parse->ppsfd = open(parseppsdev, O_RDWR | O_NOCTTY
2973182007Sroberto#ifdef O_NONBLOCK
2974182007Sroberto				    | O_NONBLOCK
2975182007Sroberto#endif
2976182007Sroberto				    , 0777);
2977182007Sroberto
2978182007Sroberto		if (parse->ppsfd == -1)
2979182007Sroberto		{
2980182007Sroberto			parse->ppsfd = fd232;
2981182007Sroberto		}
2982182007Sroberto
2983182007Sroberto/*
2984182007Sroberto * Linux PPS - the old way
2985182007Sroberto */
298654359Sroberto#if defined(HAVE_TIO_SERIAL_STUFF)		/* Linux hack: define PPS interface */
298754359Sroberto		{
2988182007Sroberto			struct serial_struct	ss;
2989182007Sroberto			if (ioctl(parse->ppsfd, TIOCGSERIAL, &ss) < 0 ||
2990182007Sroberto			    (
299154359Sroberto#ifdef ASYNC_LOW_LATENCY
2992182007Sroberto			     ss.flags |= ASYNC_LOW_LATENCY,
299354359Sroberto#endif
2994182007Sroberto#ifndef HAVE_PPSAPI
299554359Sroberto#ifdef ASYNC_PPS_CD_NEG
2996182007Sroberto			     ss.flags |= ASYNC_PPS_CD_NEG,
299754359Sroberto#endif
2998182007Sroberto#endif
2999182007Sroberto			     ioctl(parse->ppsfd, TIOCSSERIAL, &ss)) < 0) {
3000182007Sroberto				msyslog(LOG_NOTICE, "refclock_parse: TIOCSSERIAL fd %d, %m", parse->ppsfd);
3001182007Sroberto				msyslog(LOG_NOTICE,
3002182007Sroberto					"refclock_parse: optional PPS processing not available");
3003182007Sroberto			} else {
3004182007Sroberto				parse->flags    |= PARSE_PPSCLOCK;
3005182007Sroberto#ifdef ASYNC_PPS_CD_NEG
3006182007Sroberto				NLOG(NLOG_CLOCKINFO)
3007182007Sroberto				  msyslog(LOG_INFO,
3008182007Sroberto					  "refclock_parse: PPS detection on");
3009182007Sroberto#endif
3010182007Sroberto			}
301154359Sroberto		}
301254359Sroberto#endif
3013182007Sroberto
3014182007Sroberto/*
3015182007Sroberto * SUN the Solaris way
3016182007Sroberto */
301754359Sroberto#ifdef HAVE_TIOCSPPS			/* SUN PPS support */
301854359Sroberto		if (CLK_PPS(parse->peer))
3019182007Sroberto		    {
3020182007Sroberto			int i = 1;
302154359Sroberto
3022182007Sroberto			if (ioctl(parse->ppsfd, TIOCSPPS, (caddr_t)&i) == 0)
3023182007Sroberto			    {
3024182007Sroberto				parse->flags |= PARSE_PPSCLOCK;
3025182007Sroberto			    }
3026182007Sroberto		    }
302754359Sroberto#endif
302854359Sroberto
3029182007Sroberto/*
3030182007Sroberto * PPS via PPSAPI
3031182007Sroberto */
3032182007Sroberto#if defined(HAVE_PPSAPI)
3033182007Sroberto		parse->hardppsstate = PARSE_HARDPPS_DISABLE;
3034182007Sroberto		if (CLK_PPS(parse->peer))
3035182007Sroberto		{
3036182007Sroberto		  if (time_pps_create(parse->ppsfd, &parse->ppshandle) < 0)
3037182007Sroberto		    {
3038182007Sroberto		      msyslog(LOG_NOTICE, "PARSE receiver #%d: parse_start: could not set up PPS: %m", CLK_UNIT(parse->peer));
3039182007Sroberto		    }
3040182007Sroberto		  else
3041182007Sroberto		    {
3042182007Sroberto		      parse_ppsapi(parse);
3043182007Sroberto		    }
3044182007Sroberto		}
3045182007Sroberto#endif
3046182007Sroberto
304754359Sroberto		if (TTY_SETATTR(fd232, &tio) == -1)
304854359Sroberto		{
304954359Sroberto			msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: tcsetattr(%d, &tio): %m", unit, fd232);
305054359Sroberto			parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
305154359Sroberto			return 0;
305254359Sroberto		}
305354359Sroberto	}
305454359Sroberto
305554359Sroberto	/*
3056182007Sroberto	 * pick correct input machine
305754359Sroberto	 */
305854359Sroberto	parse->generic->io.srcclock = (caddr_t)parse;
305954359Sroberto	parse->generic->io.datalen = 0;
306054359Sroberto
306154359Sroberto	parse->binding = init_iobinding(parse);
306254359Sroberto
306354359Sroberto	if (parse->binding == (bind_t *)0)
306454359Sroberto		{
306554359Sroberto			msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: io sub system initialisation failed.", CLK_UNIT(parse->peer));
306654359Sroberto			parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
306754359Sroberto			return 0;			/* well, ok - special initialisation broke */
306854359Sroberto		}
306954359Sroberto
3070182007Sroberto	parse->generic->io.clock_recv = parse->binding->bd_receive; /* pick correct receive routine */
3071182007Sroberto	parse->generic->io.io_input   = parse->binding->bd_io_input; /* pick correct input routine */
3072182007Sroberto
307354359Sroberto	/*
307454359Sroberto	 * as we always(?) get 8 bit chars we want to be
307554359Sroberto	 * sure, that the upper bits are zero for less
307654359Sroberto	 * than 8 bit I/O - so we pass that information on.
307754359Sroberto	 * note that there can be only one bit count format
307854359Sroberto	 * per file descriptor
307954359Sroberto	 */
308054359Sroberto
308154359Sroberto	switch (tio.c_cflag & CSIZE)
308254359Sroberto	{
308354359Sroberto	    case CS5:
308454359Sroberto		tmp_ctl.parsesetcs.parse_cs = PARSE_IO_CS5;
308554359Sroberto		break;
308654359Sroberto
308754359Sroberto	    case CS6:
308854359Sroberto		tmp_ctl.parsesetcs.parse_cs = PARSE_IO_CS6;
308954359Sroberto		break;
309054359Sroberto
309154359Sroberto	    case CS7:
309254359Sroberto		tmp_ctl.parsesetcs.parse_cs = PARSE_IO_CS7;
309354359Sroberto		break;
309454359Sroberto
309554359Sroberto	    case CS8:
309654359Sroberto		tmp_ctl.parsesetcs.parse_cs = PARSE_IO_CS8;
309754359Sroberto		break;
309854359Sroberto	}
309954359Sroberto
310054359Sroberto	if (!PARSE_SETCS(parse, &tmp_ctl))
310154359Sroberto	{
310254359Sroberto		msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: parse_setcs() FAILED.", unit);
310354359Sroberto		parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
310454359Sroberto		return 0;			/* well, ok - special initialisation broke */
310554359Sroberto	}
310654359Sroberto
3107182007Sroberto	strncpy(tmp_ctl.parseformat.parse_buffer, parse->parse_type->cl_format, sizeof(tmp_ctl.parseformat.parse_buffer));
310854359Sroberto	tmp_ctl.parseformat.parse_count = strlen(tmp_ctl.parseformat.parse_buffer);
310954359Sroberto
311054359Sroberto	if (!PARSE_SETFMT(parse, &tmp_ctl))
311154359Sroberto	{
311254359Sroberto		msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: parse_setfmt() FAILED.", unit);
311354359Sroberto		parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
311454359Sroberto		return 0;			/* well, ok - special initialisation broke */
311554359Sroberto	}
311654359Sroberto
311754359Sroberto	/*
311854359Sroberto	 * get rid of all IO accumulated so far
311954359Sroberto	 */
312054359Sroberto#ifdef HAVE_TERMIOS
312154359Sroberto	(void) tcflush(parse->generic->io.fd, TCIOFLUSH);
312254359Sroberto#else
3123182007Sroberto#if defined(TCFLSH) && defined(TCIOFLUSH)
312454359Sroberto	{
312554359Sroberto		int flshcmd = TCIOFLUSH;
312654359Sroberto
312754359Sroberto		(void) ioctl(parse->generic->io.fd, TCFLSH, (caddr_t)&flshcmd);
312854359Sroberto	}
312954359Sroberto#endif
313054359Sroberto#endif
313156746Sroberto
313254359Sroberto	/*
313354359Sroberto	 * try to do any special initializations
313454359Sroberto	 */
313554359Sroberto	if (parse->parse_type->cl_init)
313654359Sroberto		{
313754359Sroberto			if (parse->parse_type->cl_init(parse))
313854359Sroberto				{
313954359Sroberto					parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
314054359Sroberto					return 0;		/* well, ok - special initialisation broke */
314154359Sroberto				}
314254359Sroberto		}
314354359Sroberto
314454359Sroberto	/*
3145182007Sroberto	 * Insert in async io device list.
314654359Sroberto	 */
3147182007Sroberto	if (!io_addclock(&parse->generic->io))
314854359Sroberto        {
3149182007Sroberto		msyslog(LOG_ERR,
3150182007Sroberto			"PARSE receiver #%d: parse_start: addclock %s fails (ABORT - clock type requires async io)", CLK_UNIT(parse->peer), parsedev);
3151182007Sroberto		parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
3152182007Sroberto		return 0;
315354359Sroberto	}
315454359Sroberto
315554359Sroberto	/*
315654359Sroberto	 * print out configuration
315754359Sroberto	 */
315854359Sroberto	NLOG(NLOG_CLOCKINFO)
315954359Sroberto		{
316054359Sroberto			/* conditional if clause for conditional syslog */
3161182007Sroberto			msyslog(LOG_INFO, "PARSE receiver #%d: reference clock \"%s\" (I/O device %s, PPS device %s) added",
316254359Sroberto				CLK_UNIT(parse->peer),
3163182007Sroberto				parse->parse_type->cl_description, parsedev,
3164182007Sroberto				(parse->ppsfd != parse->generic->io.fd) ? parseppsdev : parsedev);
316554359Sroberto
3166182007Sroberto			msyslog(LOG_INFO, "PARSE receiver #%d: Stratum %d, trust time %s, precision %d",
316754359Sroberto				CLK_UNIT(parse->peer),
3168182007Sroberto				parse->peer->stratum,
3169182007Sroberto				l_mktime(parse->maxunsync), parse->peer->precision);
317054359Sroberto
3171182007Sroberto			msyslog(LOG_INFO, "PARSE receiver #%d: rootdelay %.6f s, phase adjustment %.6f s, PPS phase adjustment %.6f s, %s IO handling",
317254359Sroberto				CLK_UNIT(parse->peer),
317354359Sroberto				parse->parse_type->cl_rootdelay,
317454359Sroberto				parse->generic->fudgetime1,
3175182007Sroberto				parse->ppsphaseadjust,
3176182007Sroberto                                parse->binding->bd_description);
317754359Sroberto
3178182007Sroberto			msyslog(LOG_INFO, "PARSE receiver #%d: Format recognition: %s", CLK_UNIT(parse->peer),
317954359Sroberto				parse->parse_type->cl_format);
3180182007Sroberto                        msyslog(LOG_INFO, "PARSE receiver #%d: %sPPS support%s", CLK_UNIT(parse->peer),
3181182007Sroberto				CLK_PPS(parse->peer) ? "" : "NO ",
3182182007Sroberto				CLK_PPS(parse->peer) ?
3183182007Sroberto#ifdef PPS_METHOD
3184182007Sroberto				" (implementation " PPS_METHOD ")"
3185182007Sroberto#else
3186182007Sroberto				""
318754359Sroberto#endif
3188182007Sroberto				: ""
3189182007Sroberto				);
319054359Sroberto		}
319154359Sroberto
319254359Sroberto	return 1;
319354359Sroberto}
319454359Sroberto
319554359Sroberto/*--------------------------------------------------
3196182007Sroberto * parse_ctl - process changes on flags/time values
3197182007Sroberto */
3198182007Srobertostatic void
3199182007Srobertoparse_ctl(
3200182007Sroberto	    struct parseunit *parse,
3201182007Sroberto	    struct refclockstat *in
3202182007Sroberto	    )
3203182007Sroberto{
3204182007Sroberto        if (in)
3205182007Sroberto	{
3206182007Sroberto		if (in->haveflags & (CLK_HAVEFLAG1|CLK_HAVEFLAG2|CLK_HAVEFLAG3|CLK_HAVEFLAG4))
3207182007Sroberto		{
3208182007Sroberto		  parse->flags = (parse->flags & ~(CLK_FLAG1|CLK_FLAG2|CLK_FLAG3|CLK_FLAG4)) |
3209182007Sroberto		    (in->flags & (CLK_FLAG1|CLK_FLAG2|CLK_FLAG3|CLK_FLAG4));
3210182007Sroberto#if defined(HAVE_PPSAPI)
3211182007Sroberto		  if (CLK_PPS(parse->peer))
3212182007Sroberto		    {
3213182007Sroberto		      parse_ppsapi(parse);
3214182007Sroberto		    }
3215182007Sroberto#endif
3216182007Sroberto		}
3217182007Sroberto
3218182007Sroberto		if (in->haveflags & CLK_HAVETIME1)
3219182007Sroberto                {
3220182007Sroberto		  parse->generic->fudgetime1 = in->fudgetime1;
3221182007Sroberto		  msyslog(LOG_INFO, "PARSE receiver #%d: new phase adjustment %.6f s",
3222182007Sroberto			  CLK_UNIT(parse->peer),
3223182007Sroberto			  parse->generic->fudgetime1);
3224182007Sroberto		}
3225182007Sroberto
3226182007Sroberto		if (in->haveflags & CLK_HAVETIME2)
3227182007Sroberto                {
3228182007Sroberto		  parse->generic->fudgetime2 = in->fudgetime2;
3229182007Sroberto		  if (parse->flags & PARSE_TRUSTTIME)
3230182007Sroberto		    {
3231182007Sroberto		      parse->maxunsync = (u_long)ABS(in->fudgetime2);
3232182007Sroberto		      msyslog(LOG_INFO, "PARSE receiver #%d: new trust time %s",
3233182007Sroberto			      CLK_UNIT(parse->peer),
3234182007Sroberto			      l_mktime(parse->maxunsync));
3235182007Sroberto		    }
3236182007Sroberto		  else
3237182007Sroberto		    {
3238182007Sroberto		      parse->ppsphaseadjust = in->fudgetime2;
3239182007Sroberto		      msyslog(LOG_INFO, "PARSE receiver #%d: new PPS phase adjustment %.6f s",
3240182007Sroberto			  CLK_UNIT(parse->peer),
3241182007Sroberto			      parse->ppsphaseadjust);
3242182007Sroberto#if defined(HAVE_PPSAPI)
3243182007Sroberto		      if (CLK_PPS(parse->peer))
3244182007Sroberto		      {
3245182007Sroberto			      parse_ppsapi(parse);
3246182007Sroberto		      }
3247182007Sroberto#endif
3248182007Sroberto		    }
3249182007Sroberto		}
3250182007Sroberto	}
3251182007Sroberto}
3252182007Sroberto
3253182007Sroberto/*--------------------------------------------------
325454359Sroberto * parse_poll - called by the transmit procedure
325554359Sroberto */
325654359Srobertostatic void
325754359Srobertoparse_poll(
325854359Sroberto	int unit,
325954359Sroberto	struct peer *peer
326054359Sroberto	)
326154359Sroberto{
326254359Sroberto	struct parseunit *parse = (struct parseunit *)peer->procptr->unitptr;
326354359Sroberto
326454359Sroberto	if (peer != parse->peer)
326554359Sroberto	{
326654359Sroberto		msyslog(LOG_ERR,
326754359Sroberto			"PARSE receiver #%d: poll: INTERNAL: peer incorrect",
326854359Sroberto			unit);
326954359Sroberto		return;
327054359Sroberto	}
327154359Sroberto
327254359Sroberto	/*
327354359Sroberto	 * Update clock stat counters
327454359Sroberto	 */
327554359Sroberto	parse->generic->polls++;
327654359Sroberto
327756746Sroberto	if (parse->pollneeddata &&
327856746Sroberto	    ((current_time - parse->pollneeddata) > (1<<(max(min(parse->peer->hpoll, parse->peer->ppoll), parse->peer->minpoll)))))
327954359Sroberto	{
328054359Sroberto		/*
328156746Sroberto		 * start worrying when exceeding a poll inteval
328254359Sroberto		 * bad news - didn't get a response last time
328354359Sroberto		 */
328454359Sroberto		parse->lastmissed = current_time;
328554359Sroberto		parse_event(parse, CEVNT_TIMEOUT);
328654359Sroberto
328754359Sroberto		ERR(ERR_NODATA)
3288182007Sroberto			msyslog(LOG_WARNING, "PARSE receiver #%d: no data from device within poll interval (check receiver / wiring)", CLK_UNIT(parse->peer));
328954359Sroberto	}
329054359Sroberto
329154359Sroberto	/*
329254359Sroberto	 * we just mark that we want the next sample for the clock filter
329354359Sroberto	 */
329456746Sroberto	parse->pollneeddata = current_time;
329554359Sroberto
329654359Sroberto	if (parse->parse_type->cl_poll)
329754359Sroberto	{
329854359Sroberto		parse->parse_type->cl_poll(parse);
329954359Sroberto	}
330054359Sroberto
330154359Sroberto	cparse_statistics(parse);
330254359Sroberto
330354359Sroberto	return;
330454359Sroberto}
330554359Sroberto
330654359Sroberto#define LEN_STATES 300		/* length of state string */
330754359Sroberto
330854359Sroberto/*--------------------------------------------------
330954359Sroberto * parse_control - set fudge factors, return statistics
331054359Sroberto */
331154359Srobertostatic void
331254359Srobertoparse_control(
331354359Sroberto	int unit,
331454359Sroberto	struct refclockstat *in,
331554359Sroberto	struct refclockstat *out,
331654359Sroberto	struct peer *peer
331754359Sroberto	)
331854359Sroberto{
3319182007Sroberto        struct parseunit *parse = (struct parseunit *)peer->procptr->unitptr;
332054359Sroberto	parsectl_t tmpctl;
332154359Sroberto
332254359Sroberto	static char outstatus[400];	/* status output buffer */
332354359Sroberto
332454359Sroberto	if (out)
332554359Sroberto	{
332654359Sroberto		out->lencode       = 0;
332754359Sroberto		out->p_lastcode    = 0;
332854359Sroberto		out->kv_list       = (struct ctl_var *)0;
332954359Sroberto	}
333054359Sroberto
333154359Sroberto	if (!parse || !parse->peer)
333254359Sroberto	{
333354359Sroberto		msyslog(LOG_ERR, "PARSE receiver #%d: parse_control: unit invalid (UNIT INACTIVE)",
333454359Sroberto			unit);
333554359Sroberto		return;
333654359Sroberto	}
333754359Sroberto
333854359Sroberto	unit = CLK_UNIT(parse->peer);
333954359Sroberto
3340182007Sroberto	/*
3341182007Sroberto	 * handle changes
3342182007Sroberto	 */
3343182007Sroberto	parse_ctl(parse, in);
3344182007Sroberto
3345182007Sroberto	/*
3346182007Sroberto	 * supply data
3347182007Sroberto	 */
334854359Sroberto	if (out)
334954359Sroberto	{
335054359Sroberto		u_long sum = 0;
3351182007Sroberto		char *tt, *start;
335254359Sroberto		int i;
335354359Sroberto
335454359Sroberto		outstatus[0] = '\0';
335554359Sroberto
335654359Sroberto		out->type       = REFCLK_PARSE;
335754359Sroberto
335854359Sroberto		/*
3359182007Sroberto		 * keep fudgetime2 in sync with TRUSTTIME/MAXUNSYNC flag1
3360182007Sroberto		 */
3361182007Sroberto		parse->generic->fudgetime2 = (parse->flags & PARSE_TRUSTTIME) ? (double)parse->maxunsync : parse->ppsphaseadjust;
3362182007Sroberto
3363182007Sroberto		/*
336454359Sroberto		 * figure out skew between PPS and RS232 - just for informational
3365182007Sroberto		 * purposes
336654359Sroberto		 */
3367182007Sroberto		if (PARSE_SYNC(parse->timedata.parse_state))
336854359Sroberto		{
3369182007Sroberto			if (PARSE_PPS(parse->timedata.parse_state) && PARSE_TIMECODE(parse->timedata.parse_state))
337054359Sroberto			{
337154359Sroberto				l_fp off;
337254359Sroberto
337354359Sroberto				/*
337454359Sroberto				 * we have a PPS and RS232 signal - calculate the skew
337554359Sroberto				 * WARNING: assumes on TIMECODE == PULSE (timecode after pulse)
337654359Sroberto				 */
3377182007Sroberto				off = parse->timedata.parse_stime.fp;
3378182007Sroberto				L_SUB(&off, &parse->timedata.parse_ptime.fp); /* true offset */
337954359Sroberto				tt = add_var(&out->kv_list, 80, RO);
3380182007Sroberto				snprintf(tt, 80, "refclock_ppsskew=%s", lfptoms(&off, 6));
338154359Sroberto			}
338254359Sroberto		}
338354359Sroberto
3384182007Sroberto		if (PARSE_PPS(parse->timedata.parse_state))
338554359Sroberto		{
338654359Sroberto			tt = add_var(&out->kv_list, 80, RO|DEF);
3387182007Sroberto			snprintf(tt, 80, "refclock_ppstime=\"%s\"", gmprettydate(&parse->timedata.parse_ptime.fp));
338854359Sroberto		}
338954359Sroberto
3390182007Sroberto		start = tt = add_var(&out->kv_list, 128, RO|DEF);
3391182007Sroberto		snprintf(tt, 128, "refclock_time=\"");
339254359Sroberto		tt += strlen(tt);
339354359Sroberto
3394182007Sroberto		if (parse->timedata.parse_time.fp.l_ui == 0)
339554359Sroberto		{
3396182007Sroberto			strncpy(tt, "<UNDEFINED>\"", BUFFER_SIZES(start, tt, 128));
339754359Sroberto		}
339854359Sroberto		else
339954359Sroberto		{
3400182007Sroberto			snprintf(tt, 128, "%s\"", gmprettydate(&parse->timedata.parse_time.fp));
340154359Sroberto		}
340254359Sroberto
340354359Sroberto		if (!PARSE_GETTIMECODE(parse, &tmpctl))
340454359Sroberto		{
340554359Sroberto			ERR(ERR_INTERNAL)
340654359Sroberto				msyslog(LOG_ERR, "PARSE receiver #%d: parse_control: parse_timecode() FAILED", unit);
340754359Sroberto		}
340854359Sroberto		else
340954359Sroberto		{
3410182007Sroberto			start = tt = add_var(&out->kv_list, 512, RO|DEF);
3411182007Sroberto			snprintf(tt, 512, "refclock_status=\"");
341254359Sroberto			tt += strlen(tt);
341354359Sroberto
341454359Sroberto			/*
341554359Sroberto			 * copy PPS flags from last read transaction (informational only)
341654359Sroberto			 */
3417182007Sroberto			tmpctl.parsegettc.parse_state |= parse->timedata.parse_state &
341854359Sroberto				(PARSEB_PPS|PARSEB_S_PPS);
341954359Sroberto
3420182007Sroberto			(void) parsestate(tmpctl.parsegettc.parse_state, tt, BUFFER_SIZES(start, tt, 512));
342154359Sroberto
3422182007Sroberto			strncat(tt, "\"", BUFFER_SIZES(start, tt, 512));
342354359Sroberto
342454359Sroberto			if (tmpctl.parsegettc.parse_count)
342554359Sroberto			    mkascii(outstatus+strlen(outstatus), (int)(sizeof(outstatus)- strlen(outstatus) - 1),
3426182007Sroberto				    tmpctl.parsegettc.parse_buffer, (unsigned)(tmpctl.parsegettc.parse_count));
342754359Sroberto
342854359Sroberto		}
342954359Sroberto
343054359Sroberto		tmpctl.parseformat.parse_format = tmpctl.parsegettc.parse_format;
343154359Sroberto
343254359Sroberto		if (!PARSE_GETFMT(parse, &tmpctl))
343354359Sroberto		{
343454359Sroberto			ERR(ERR_INTERNAL)
343554359Sroberto				msyslog(LOG_ERR, "PARSE receiver #%d: parse_control: parse_getfmt() FAILED", unit);
343654359Sroberto		}
343754359Sroberto		else
343854359Sroberto		{
343954359Sroberto			tt = add_var(&out->kv_list, 80, RO|DEF);
3440182007Sroberto			snprintf(tt, 80, "refclock_format=\"");
344154359Sroberto
344254359Sroberto			strncat(tt, tmpctl.parseformat.parse_buffer, tmpctl.parseformat.parse_count);
3443182007Sroberto			strncat(tt,"\"", 80);
344454359Sroberto		}
344554359Sroberto
344654359Sroberto		/*
344754359Sroberto		 * gather state statistics
344854359Sroberto		 */
344954359Sroberto
345054359Sroberto		start = tt = add_var(&out->kv_list, LEN_STATES, RO|DEF);
3451182007Sroberto		strncpy(tt, "refclock_states=\"", LEN_STATES);
345254359Sroberto		tt += strlen(tt);
345354359Sroberto
345454359Sroberto		for (i = 0; i <= CEVNT_MAX; i++)
345554359Sroberto		{
345654359Sroberto			u_long s_time;
345754359Sroberto			u_long d = current_time - parse->generic->timestarted;
345854359Sroberto			u_long percent;
345954359Sroberto
346054359Sroberto			percent = s_time = PARSE_STATETIME(parse, i);
346154359Sroberto
346254359Sroberto			while (((u_long)(~0) / 10000) < percent)
346354359Sroberto			{
346454359Sroberto				percent /= 10;
346554359Sroberto				d       /= 10;
346654359Sroberto			}
346754359Sroberto
346854359Sroberto			if (d)
346954359Sroberto			    percent = (percent * 10000) / d;
347054359Sroberto			else
347154359Sroberto			    percent = 10000;
347254359Sroberto
347354359Sroberto			if (s_time)
347454359Sroberto			{
347554359Sroberto				char item[80];
347654359Sroberto				int count;
347754359Sroberto
3478182007Sroberto				snprintf(item, 80, "%s%s%s: %s (%d.%02d%%)",
347954359Sroberto					sum ? "; " : "",
348054359Sroberto					(parse->generic->currentstatus == i) ? "*" : "",
348154359Sroberto					clockstatus((unsigned int)i),
348254359Sroberto					l_mktime(s_time),
348354359Sroberto					(int)(percent / 100), (int)(percent % 100));
348454359Sroberto				if ((count = strlen(item)) < (LEN_STATES - 40 - (tt - start)))
348554359Sroberto					{
3486182007Sroberto						strncpy(tt, item, BUFFER_SIZES(start, tt, LEN_STATES));
348754359Sroberto						tt  += count;
348854359Sroberto					}
348954359Sroberto				sum += s_time;
349054359Sroberto			}
349154359Sroberto		}
349254359Sroberto
3493182007Sroberto		snprintf(tt, BUFFER_SIZES(start, tt, LEN_STATES), "; running time: %s\"", l_mktime(sum));
349454359Sroberto
349554359Sroberto		tt = add_var(&out->kv_list, 32, RO);
3496182007Sroberto		snprintf(tt, 32,  "refclock_id=\"%s\"", parse->parse_type->cl_id);
349754359Sroberto
349854359Sroberto		tt = add_var(&out->kv_list, 80, RO);
3499182007Sroberto		snprintf(tt, 80,  "refclock_iomode=\"%s\"", parse->binding->bd_description);
350054359Sroberto
350154359Sroberto		tt = add_var(&out->kv_list, 128, RO);
3502182007Sroberto		snprintf(tt, 128, "refclock_driver_version=\"%s\"", rcsid);
350354359Sroberto
350454359Sroberto		{
350554359Sroberto			struct ctl_var *k;
350654359Sroberto
350754359Sroberto			k = parse->kv;
350854359Sroberto			while (k && !(k->flags & EOV))
350954359Sroberto			{
351054359Sroberto				set_var(&out->kv_list, k->text, strlen(k->text)+1, k->flags);
351154359Sroberto				k++;
351254359Sroberto			}
351354359Sroberto		}
351454359Sroberto
351554359Sroberto		out->lencode       = strlen(outstatus);
351654359Sroberto		out->p_lastcode    = outstatus;
351754359Sroberto	}
351854359Sroberto}
351954359Sroberto
352054359Sroberto/**===========================================================================
352154359Sroberto ** processing routines
352254359Sroberto **/
352354359Sroberto
352454359Sroberto/*--------------------------------------------------
352554359Sroberto * event handling - note that nominal events will also be posted
3526182007Sroberto * keep track of state dwelling times
352754359Sroberto */
352854359Srobertostatic void
352954359Srobertoparse_event(
353054359Sroberto	struct parseunit *parse,
353154359Sroberto	int event
353254359Sroberto	)
353354359Sroberto{
353454359Sroberto	if (parse->generic->currentstatus != (u_char) event)
353554359Sroberto	{
353654359Sroberto		parse->statetime[parse->generic->currentstatus] += current_time - parse->lastchange;
353754359Sroberto		parse->lastchange              = current_time;
353854359Sroberto
353954359Sroberto		if (parse->parse_type->cl_event)
354054359Sroberto		    parse->parse_type->cl_event(parse, event);
354154359Sroberto
3542182007Sroberto		if (event == CEVNT_NOMINAL)
354354359Sroberto		{
354454359Sroberto			NLOG(NLOG_CLOCKSTATUS)
354554359Sroberto				msyslog(LOG_INFO, "PARSE receiver #%d: SYNCHRONIZED",
354654359Sroberto					CLK_UNIT(parse->peer));
354754359Sroberto		}
354854359Sroberto
3549182007Sroberto		refclock_report(parse->peer, event);
355054359Sroberto	}
355154359Sroberto}
355254359Sroberto
355354359Sroberto/*--------------------------------------------------
355454359Sroberto * process a PARSE time sample
355554359Sroberto */
355654359Srobertostatic void
355754359Srobertoparse_process(
355854359Sroberto	struct parseunit *parse,
355954359Sroberto	parsetime_t      *parsetime
356054359Sroberto	)
356154359Sroberto{
356254359Sroberto	l_fp off, rectime, reftime;
356354359Sroberto	double fudge;
356454359Sroberto
356554359Sroberto	/*
356654359Sroberto	 * check for changes in conversion status
356754359Sroberto	 * (only one for each new status !)
356854359Sroberto	 */
356954359Sroberto	if (((parsetime->parse_status & CVT_MASK) != CVT_OK) &&
357054359Sroberto	    ((parsetime->parse_status & CVT_MASK) != CVT_NONE) &&
3571182007Sroberto	    (parse->timedata.parse_status != parsetime->parse_status))
357254359Sroberto	{
357354359Sroberto		char buffer[400];
357454359Sroberto
357554359Sroberto		NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */
357654359Sroberto			msyslog(LOG_WARNING, "PARSE receiver #%d: conversion status \"%s\"",
3577182007Sroberto				CLK_UNIT(parse->peer), parsestatus(parsetime->parse_status, buffer, sizeof(buffer)));
357854359Sroberto
357954359Sroberto		if ((parsetime->parse_status & CVT_MASK) == CVT_FAIL)
358054359Sroberto		{
358154359Sroberto			/*
358254359Sroberto			 * tell more about the story - list time code
358354359Sroberto			 * there is a slight change for a race condition and
358454359Sroberto			 * the time code might be overwritten by the next packet
358554359Sroberto			 */
358654359Sroberto			parsectl_t tmpctl;
358754359Sroberto
358854359Sroberto			if (!PARSE_GETTIMECODE(parse, &tmpctl))
358954359Sroberto			{
359054359Sroberto				ERR(ERR_INTERNAL)
359154359Sroberto					msyslog(LOG_ERR, "PARSE receiver #%d: parse_process: parse_timecode() FAILED", CLK_UNIT(parse->peer));
359254359Sroberto			}
359354359Sroberto			else
359454359Sroberto			{
359554359Sroberto				ERR(ERR_BADDATA)
3596182007Sroberto					msyslog(LOG_WARNING, "PARSE receiver #%d: FAILED TIMECODE: \"%s\" (check receiver configuration / wiring)",
359754359Sroberto						CLK_UNIT(parse->peer), mkascii(buffer, sizeof buffer, tmpctl.parsegettc.parse_buffer, (unsigned)(tmpctl.parsegettc.parse_count - 1)));
359854359Sroberto			}
359954359Sroberto		}
360054359Sroberto	}
360154359Sroberto
360254359Sroberto	/*
360354359Sroberto	 * examine status and post appropriate events
360454359Sroberto	 */
360554359Sroberto	if ((parsetime->parse_status & CVT_MASK) != CVT_OK)
360654359Sroberto	{
360754359Sroberto		/*
360854359Sroberto		 * got bad data - tell the rest of the system
360954359Sroberto		 */
361054359Sroberto		switch (parsetime->parse_status & CVT_MASK)
361154359Sroberto		{
361254359Sroberto		case CVT_NONE:
361354359Sroberto			if ((parsetime->parse_status & CVT_ADDITIONAL) &&
361454359Sroberto			    parse->parse_type->cl_message)
361554359Sroberto				parse->parse_type->cl_message(parse, parsetime);
3616182007Sroberto			/*
3617182007Sroberto			 * save PPS information that comes piggyback
3618182007Sroberto			 */
3619182007Sroberto			if (PARSE_PPS(parsetime->parse_state))
3620182007Sroberto			  {
3621182007Sroberto			    parse->timedata.parse_state |= PARSEB_PPS|PARSEB_S_PPS;
3622182007Sroberto			    parse->timedata.parse_ptime  = parsetime->parse_ptime;
3623182007Sroberto			  }
362454359Sroberto			break; 		/* well, still waiting - timeout is handled at higher levels */
362554359Sroberto
362654359Sroberto		case CVT_FAIL:
362754359Sroberto			if (parsetime->parse_status & CVT_BADFMT)
362854359Sroberto			{
362954359Sroberto				parse_event(parse, CEVNT_BADREPLY);
363054359Sroberto			}
363154359Sroberto			else
363254359Sroberto				if (parsetime->parse_status & CVT_BADDATE)
363354359Sroberto				{
363454359Sroberto					parse_event(parse, CEVNT_BADDATE);
363554359Sroberto				}
363654359Sroberto				else
363754359Sroberto					if (parsetime->parse_status & CVT_BADTIME)
363854359Sroberto					{
363954359Sroberto						parse_event(parse, CEVNT_BADTIME);
364054359Sroberto					}
364154359Sroberto					else
364254359Sroberto					{
364354359Sroberto						parse_event(parse, CEVNT_BADREPLY); /* for the lack of something better */
364454359Sroberto					}
364554359Sroberto		}
364654359Sroberto		return;			/* skip the rest - useless */
364754359Sroberto	}
364854359Sroberto
364954359Sroberto	/*
365054359Sroberto	 * check for format changes
365154359Sroberto	 * (in case somebody has swapped clocks 8-)
365254359Sroberto	 */
365354359Sroberto	if (parse->lastformat != parsetime->parse_format)
365454359Sroberto	{
365554359Sroberto		parsectl_t tmpctl;
365654359Sroberto
365754359Sroberto		tmpctl.parseformat.parse_format = parsetime->parse_format;
365854359Sroberto
365954359Sroberto		if (!PARSE_GETFMT(parse, &tmpctl))
366054359Sroberto		{
366154359Sroberto			ERR(ERR_INTERNAL)
366254359Sroberto				msyslog(LOG_ERR, "PARSE receiver #%d: parse_getfmt() FAILED", CLK_UNIT(parse->peer));
366354359Sroberto		}
366454359Sroberto		else
366554359Sroberto		{
366654359Sroberto			NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */
366754359Sroberto				msyslog(LOG_INFO, "PARSE receiver #%d: packet format \"%s\"",
366854359Sroberto					CLK_UNIT(parse->peer), tmpctl.parseformat.parse_buffer);
366954359Sroberto		}
367054359Sroberto		parse->lastformat = parsetime->parse_format;
367154359Sroberto	}
367254359Sroberto
367354359Sroberto	/*
367454359Sroberto	 * now, any changes ?
367554359Sroberto	 */
3676182007Sroberto	if ((parse->timedata.parse_state ^ parsetime->parse_state) &
3677182007Sroberto	    ~(unsigned)(PARSEB_PPS|PARSEB_S_PPS))
367854359Sroberto	{
367954359Sroberto		char tmp1[200];
368054359Sroberto		char tmp2[200];
368154359Sroberto		/*
3682182007Sroberto		 * something happend - except for PPS events
368354359Sroberto		 */
368454359Sroberto
3685182007Sroberto		(void) parsestate(parsetime->parse_state, tmp1, sizeof(tmp1));
3686182007Sroberto		(void) parsestate(parse->timedata.parse_state, tmp2, sizeof(tmp2));
368754359Sroberto
368854359Sroberto		NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */
368954359Sroberto			msyslog(LOG_INFO,"PARSE receiver #%d: STATE CHANGE: %s -> %s",
369054359Sroberto				CLK_UNIT(parse->peer), tmp2, tmp1);
369154359Sroberto	}
369254359Sroberto
369354359Sroberto	/*
3694182007Sroberto	 * carry on PPS information if still usable
3695182007Sroberto	 */
3696182007Sroberto	if (PARSE_PPS(parse->timedata.parse_state) && !PARSE_PPS(parsetime->parse_state))
3697182007Sroberto        {
3698182007Sroberto	        parsetime->parse_state |= PARSEB_PPS|PARSEB_S_PPS;
3699182007Sroberto		parsetime->parse_ptime  = parse->timedata.parse_ptime;
3700182007Sroberto	}
3701182007Sroberto
3702182007Sroberto	/*
370354359Sroberto	 * remember for future
370454359Sroberto	 */
3705182007Sroberto	parse->timedata = *parsetime;
370654359Sroberto
370754359Sroberto	/*
370854359Sroberto	 * check to see, whether the clock did a complete powerup or lost PZF signal
370954359Sroberto	 * and post correct events for current condition
371054359Sroberto	 */
371154359Sroberto	if (PARSE_POWERUP(parsetime->parse_state))
371254359Sroberto	{
371354359Sroberto		/*
371454359Sroberto		 * this is bad, as we have completely lost synchronisation
371554359Sroberto		 * well this is a problem with the receiver here
371654359Sroberto		 * for PARSE Meinberg DCF77 receivers the lost synchronisation
371754359Sroberto		 * is true as it is the powerup state and the time is taken
371854359Sroberto		 * from a crude real time clock chip
371954359Sroberto		 * for the PZF series this is only partly true, as
372054359Sroberto		 * PARSE_POWERUP only means that the pseudo random
372154359Sroberto		 * phase shift sequence cannot be found. this is only
372254359Sroberto		 * bad, if we have never seen the clock in the SYNC
372354359Sroberto		 * state, where the PHASE and EPOCH are correct.
372454359Sroberto		 * for reporting events the above business does not
372554359Sroberto		 * really matter, but we can use the time code
372654359Sroberto		 * even in the POWERUP state after having seen
372754359Sroberto		 * the clock in the synchronized state (PZF class
372854359Sroberto		 * receivers) unless we have had a telegram disruption
372954359Sroberto		 * after having seen the clock in the SYNC state. we
373054359Sroberto		 * thus require having seen the clock in SYNC state
373154359Sroberto		 * *after* having missed telegrams (noresponse) from
373254359Sroberto		 * the clock. one problem remains: we might use erroneously
373354359Sroberto		 * POWERUP data if the disruption is shorter than 1 polling
373454359Sroberto		 * interval. fortunately powerdowns last usually longer than 64
373554359Sroberto		 * seconds and the receiver is at least 2 minutes in the
373654359Sroberto		 * POWERUP or NOSYNC state before switching to SYNC
373754359Sroberto		 */
373854359Sroberto		parse_event(parse, CEVNT_FAULT);
373954359Sroberto		NLOG(NLOG_CLOCKSTATUS)
374054359Sroberto			ERR(ERR_BADSTATUS)
374154359Sroberto			msyslog(LOG_ERR,"PARSE receiver #%d: NOT SYNCHRONIZED",
374254359Sroberto				CLK_UNIT(parse->peer));
374354359Sroberto	}
374454359Sroberto	else
374554359Sroberto	{
374654359Sroberto		/*
374754359Sroberto		 * we have two states left
374854359Sroberto		 *
374954359Sroberto		 * SYNC:
375054359Sroberto		 *  this state means that the EPOCH (timecode) and PHASE
375154359Sroberto		 *  information has be read correctly (at least two
375254359Sroberto		 *  successive PARSE timecodes were received correctly)
375354359Sroberto		 *  this is the best possible state - full trust
375454359Sroberto		 *
375554359Sroberto		 * NOSYNC:
375654359Sroberto		 *  The clock should be on phase with respect to the second
375754359Sroberto		 *  signal, but the timecode has not been received correctly within
375854359Sroberto		 *  at least the last two minutes. this is a sort of half baked state
375954359Sroberto		 *  for PARSE Meinberg DCF77 clocks this is bad news (clock running
376054359Sroberto		 *  without timecode confirmation)
376154359Sroberto		 *  PZF 535 has also no time confirmation, but the phase should be
376254359Sroberto		 *  very precise as the PZF signal can be decoded
376354359Sroberto		 */
376454359Sroberto
376554359Sroberto		if (PARSE_SYNC(parsetime->parse_state))
376654359Sroberto		{
376754359Sroberto			/*
376854359Sroberto			 * currently completely synchronized - best possible state
376954359Sroberto			 */
377054359Sroberto			parse->lastsync = current_time;
377154359Sroberto			clear_err(parse, ERR_BADSTATUS);
377254359Sroberto		}
377354359Sroberto		else
377454359Sroberto		{
377554359Sroberto			/*
377654359Sroberto			 * we have had some problems receiving the time code
377754359Sroberto			 */
377854359Sroberto			parse_event(parse, CEVNT_PROP);
377954359Sroberto			NLOG(NLOG_CLOCKSTATUS)
378054359Sroberto				ERR(ERR_BADSTATUS)
378154359Sroberto				msyslog(LOG_ERR,"PARSE receiver #%d: TIMECODE NOT CONFIRMED",
378254359Sroberto					CLK_UNIT(parse->peer));
378354359Sroberto		}
378454359Sroberto	}
378554359Sroberto
378654359Sroberto	fudge = parse->generic->fudgetime1; /* standard RS232 Fudgefactor */
378754359Sroberto
378854359Sroberto	if (PARSE_TIMECODE(parsetime->parse_state))
378954359Sroberto	{
379054359Sroberto		rectime = parsetime->parse_stime.fp;
379154359Sroberto		off = reftime = parsetime->parse_time.fp;
379254359Sroberto
379354359Sroberto		L_SUB(&off, &rectime); /* prepare for PPS adjustments logic */
379454359Sroberto
379554359Sroberto#ifdef DEBUG
379654359Sroberto		if (debug > 3)
379754359Sroberto			printf("PARSE receiver #%d: Reftime %s, Recvtime %s - initial offset %s\n",
379854359Sroberto			       CLK_UNIT(parse->peer),
379954359Sroberto			       prettydate(&reftime),
380054359Sroberto			       prettydate(&rectime),
380154359Sroberto			       lfptoa(&off,6));
380254359Sroberto#endif
380354359Sroberto	}
380454359Sroberto
380554359Sroberto	if (PARSE_PPS(parsetime->parse_state) && CLK_PPS(parse->peer))
380654359Sroberto	{
380754359Sroberto		l_fp offset;
3808182007Sroberto		double ppsphaseadjust = parse->ppsphaseadjust;
380954359Sroberto
3810182007Sroberto#ifdef HAVE_PPSAPI
381154359Sroberto		/*
3812182007Sroberto		 * set fudge = 0.0 if already included in PPS time stamps
3813182007Sroberto		 */
3814182007Sroberto		if (parse->ppsparams.mode & (PPS_OFFSETCLEAR|PPS_OFFSETASSERT))
3815182007Sroberto		        {
3816182007Sroberto			        ppsphaseadjust = 0.0;
3817182007Sroberto			}
3818182007Sroberto#endif
3819182007Sroberto
3820182007Sroberto		/*
382154359Sroberto		 * we have a PPS signal - much better than the RS232 stuff (we hope)
382254359Sroberto		 */
382354359Sroberto		offset = parsetime->parse_ptime.fp;
382454359Sroberto
382554359Sroberto#ifdef DEBUG
382654359Sroberto		if (debug > 3)
382754359Sroberto			printf("PARSE receiver #%d: PPStime %s\n",
382854359Sroberto				CLK_UNIT(parse->peer),
382954359Sroberto				prettydate(&offset));
383054359Sroberto#endif
383154359Sroberto		if (PARSE_TIMECODE(parsetime->parse_state))
383254359Sroberto		{
383354359Sroberto			if (M_ISGEQ(off.l_i, off.l_f, -1, 0x80000000) &&
383454359Sroberto			    M_ISGEQ(0, 0x7fffffff, off.l_i, off.l_f))
383554359Sroberto			{
3836182007Sroberto				fudge = ppsphaseadjust; /* pick PPS fudge factor */
383754359Sroberto
383854359Sroberto				/*
383954359Sroberto				 * RS232 offsets within [-0.5..0.5[ - take PPS offsets
384054359Sroberto				 */
384154359Sroberto
384254359Sroberto				if (parse->parse_type->cl_flags & PARSE_F_PPSONSECOND)
384354359Sroberto				{
384454359Sroberto					reftime = off = offset;
384554359Sroberto					if (reftime.l_uf & (unsigned)0x80000000)
384654359Sroberto						reftime.l_ui++;
384754359Sroberto					reftime.l_uf = 0;
384856746Sroberto
384954359Sroberto
385054359Sroberto					/*
385154359Sroberto					 * implied on second offset
385254359Sroberto					 */
385354359Sroberto					off.l_uf = ~off.l_uf; /* map [0.5..1[ -> [-0.5..0[ */
385454359Sroberto					off.l_ui = (off.l_f < 0) ? ~0 : 0; /* sign extend */
385554359Sroberto				}
385654359Sroberto				else
385754359Sroberto				{
385854359Sroberto					/*
385954359Sroberto					 * time code describes pulse
386054359Sroberto					 */
386154359Sroberto					reftime = off = parsetime->parse_time.fp;
386254359Sroberto
386354359Sroberto					L_SUB(&off, &offset); /* true offset */
386454359Sroberto				}
386554359Sroberto			}
386654359Sroberto			/*
386754359Sroberto			 * take RS232 offset when PPS when out of bounds
386854359Sroberto			 */
386954359Sroberto		}
387054359Sroberto		else
387154359Sroberto		{
3872182007Sroberto			fudge = ppsphaseadjust; /* pick PPS fudge factor */
387354359Sroberto			/*
387454359Sroberto			 * Well, no time code to guide us - assume on second pulse
387554359Sroberto			 * and pray, that we are within [-0.5..0.5[
387654359Sroberto			 */
387754359Sroberto			off = offset;
387854359Sroberto			reftime = offset;
387954359Sroberto			if (reftime.l_uf & (unsigned)0x80000000)
388054359Sroberto				reftime.l_ui++;
388154359Sroberto			reftime.l_uf = 0;
388254359Sroberto			/*
388354359Sroberto			 * implied on second offset
388454359Sroberto			 */
388554359Sroberto			off.l_uf = ~off.l_uf; /* map [0.5..1[ -> [-0.5..0[ */
388654359Sroberto			off.l_ui = (off.l_f < 0) ? ~0 : 0; /* sign extend */
388754359Sroberto		}
388854359Sroberto	}
388954359Sroberto	else
389054359Sroberto	{
389154359Sroberto		if (!PARSE_TIMECODE(parsetime->parse_state))
389254359Sroberto		{
389354359Sroberto			/*
389454359Sroberto			 * Well, no PPS, no TIMECODE, no more work ...
389554359Sroberto			 */
389654359Sroberto			if ((parsetime->parse_status & CVT_ADDITIONAL) &&
389754359Sroberto			    parse->parse_type->cl_message)
389854359Sroberto				parse->parse_type->cl_message(parse, parsetime);
389954359Sroberto			return;
390054359Sroberto		}
390154359Sroberto	}
390254359Sroberto
390354359Sroberto#ifdef DEBUG
390454359Sroberto	if (debug > 3)
390554359Sroberto		printf("PARSE receiver #%d: Reftime %s, Recvtime %s - final offset %s\n",
390654359Sroberto			CLK_UNIT(parse->peer),
390754359Sroberto			prettydate(&reftime),
390854359Sroberto			prettydate(&rectime),
390954359Sroberto			lfptoa(&off,6));
391054359Sroberto#endif
391154359Sroberto
391254359Sroberto
391354359Sroberto	rectime = reftime;
391454359Sroberto	L_SUB(&rectime, &off);	/* just to keep the ntp interface happy */
391554359Sroberto
391654359Sroberto#ifdef DEBUG
391754359Sroberto	if (debug > 3)
391854359Sroberto		printf("PARSE receiver #%d: calculated Reftime %s, Recvtime %s\n",
391954359Sroberto			CLK_UNIT(parse->peer),
392054359Sroberto			prettydate(&reftime),
392154359Sroberto			prettydate(&rectime));
392254359Sroberto#endif
392354359Sroberto
392454359Sroberto	if ((parsetime->parse_status & CVT_ADDITIONAL) &&
392554359Sroberto	    parse->parse_type->cl_message)
392654359Sroberto		parse->parse_type->cl_message(parse, parsetime);
392754359Sroberto
392854359Sroberto	if (PARSE_SYNC(parsetime->parse_state))
392954359Sroberto	{
393054359Sroberto		/*
393154359Sroberto		 * log OK status
393254359Sroberto		 */
393354359Sroberto		parse_event(parse, CEVNT_NOMINAL);
393454359Sroberto	}
393554359Sroberto
393654359Sroberto	clear_err(parse, ERR_BADIO);
393754359Sroberto	clear_err(parse, ERR_BADDATA);
393854359Sroberto	clear_err(parse, ERR_NODATA);
393954359Sroberto	clear_err(parse, ERR_INTERNAL);
394054359Sroberto
394154359Sroberto	/*
394254359Sroberto	 * and now stick it into the clock machine
394354359Sroberto	 * samples are only valid iff lastsync is not too old and
394454359Sroberto	 * we have seen the clock in sync at least once
394554359Sroberto	 * after the last time we didn't see an expected data telegram
3946182007Sroberto	 * at startup being not in sync is also bad just like
3947182007Sroberto	 * POWERUP state
394854359Sroberto	 * see the clock states section above for more reasoning
394954359Sroberto	 */
3950182007Sroberto	if (((current_time - parse->lastsync) > parse->maxunsync) ||
3951182007Sroberto	    (parse->lastsync < parse->lastmissed) ||
3952182007Sroberto	    ((parse->lastsync == 0) && !PARSE_SYNC(parsetime->parse_state)) ||
3953182007Sroberto	    PARSE_POWERUP(parsetime->parse_state))
395454359Sroberto	{
395554359Sroberto		parse->generic->leap = LEAP_NOTINSYNC;
3956182007Sroberto		parse->lastsync = 0;	/* wait for full sync again */
395754359Sroberto	}
395854359Sroberto	else
395954359Sroberto	{
396054359Sroberto		if (PARSE_LEAPADD(parsetime->parse_state))
396154359Sroberto		{
396254359Sroberto			/*
396354359Sroberto			 * we pick this state also for time code that pass leap warnings
396454359Sroberto			 * without direction information (as earth is currently slowing
396554359Sroberto			 * down).
396654359Sroberto			 */
396754359Sroberto			parse->generic->leap = (parse->flags & PARSE_LEAP_DELETE) ? LEAP_DELSECOND : LEAP_ADDSECOND;
396854359Sroberto		}
396954359Sroberto		else
397054359Sroberto		    if (PARSE_LEAPDEL(parsetime->parse_state))
397154359Sroberto		    {
397254359Sroberto			    parse->generic->leap = LEAP_DELSECOND;
397354359Sroberto		    }
397454359Sroberto		    else
397554359Sroberto		    {
397654359Sroberto			    parse->generic->leap = LEAP_NOWARNING;
397754359Sroberto		    }
397854359Sroberto	}
3979182007Sroberto
3980182007Sroberto	if (parse->generic->leap != LEAP_NOTINSYNC)
3981182007Sroberto	{
3982182007Sroberto	        /*
3983182007Sroberto		 * only good/trusted samples are interesting
3984182007Sroberto		 */
3985182007Sroberto#ifdef DEBUG
3986182007Sroberto	        if (debug > 2)
3987182007Sroberto		        {
3988182007Sroberto			        printf("PARSE receiver #%d: refclock_process_offset(reftime=%s, rectime=%s, Fudge=%f)\n",
3989182007Sroberto				       CLK_UNIT(parse->peer),
3990182007Sroberto				       prettydate(&reftime),
3991182007Sroberto				       prettydate(&rectime),
3992182007Sroberto				       fudge);
3993182007Sroberto			}
3994182007Sroberto#endif
3995182007Sroberto		parse->generic->lastref = reftime;
3996182007Sroberto
3997182007Sroberto		refclock_process_offset(parse->generic, reftime, rectime, fudge);
3998182007Sroberto
3999182007Sroberto		/*
4000182007Sroberto		 * pass PPS information on to PPS clock
4001182007Sroberto		 */
4002182007Sroberto		if (PARSE_PPS(parsetime->parse_state) && CLK_PPS(parse->peer))
4003182007Sroberto		        {
4004182007Sroberto			        (void) pps_sample(&parse->timedata.parse_ptime.fp);
4005182007Sroberto				parse_hardpps(parse, PARSE_HARDPPS_ENABLE);
4006182007Sroberto			}
4007182007Sroberto	} else {
4008182007Sroberto	        parse_hardpps(parse, PARSE_HARDPPS_DISABLE);
4009182007Sroberto	}
4010182007Sroberto
401154359Sroberto	/*
4012182007Sroberto	 * ready, unless the machine wants a sample or
4013182007Sroberto	 * we are in fast startup mode (peer->dist > MAXDISTANCE)
401454359Sroberto	 */
4015182007Sroberto	if (!parse->pollneeddata && parse->peer->disp <= MAXDISTANCE)
401654359Sroberto	    return;
401754359Sroberto
401854359Sroberto	parse->pollneeddata = 0;
401954359Sroberto
4020182007Sroberto	parse->timedata.parse_state &= ~(unsigned)(PARSEB_PPS|PARSEB_S_PPS);
4021182007Sroberto
402254359Sroberto	refclock_receive(parse->peer);
402354359Sroberto}
402456746Sroberto
402554359Sroberto/**===========================================================================
402654359Sroberto ** special code for special clocks
402754359Sroberto **/
402854359Sroberto
402954359Srobertostatic void
403054359Srobertomk_utcinfo(
403154359Sroberto	   char *t,
403254359Sroberto	   int wnt,
403354359Sroberto	   int wnlsf,
403454359Sroberto	   int dn,
403554359Sroberto	   int dtls,
4036182007Sroberto	   int dtlsf,
4037182007Sroberto	   int size
403854359Sroberto	   )
403954359Sroberto{
404054359Sroberto  l_fp leapdate;
4041182007Sroberto  char *start = t;
404254359Sroberto
4043182007Sroberto  snprintf(t, size, "current correction %d sec", dtls);
404454359Sroberto  t += strlen(t);
404554359Sroberto
404654359Sroberto  if (wnlsf < 990)
404754359Sroberto    wnlsf += 1024;
404854359Sroberto
404954359Sroberto  if (wnt < 990)
405054359Sroberto    wnt += 1024;
405154359Sroberto
405254359Sroberto  gpstolfp((unsigned short)wnlsf, (unsigned short)dn, 0, &leapdate);
405354359Sroberto
405454359Sroberto  if ((dtlsf != dtls) &&
405554359Sroberto      ((wnlsf - wnt) < 52))
405654359Sroberto    {
4057182007Sroberto	    snprintf(t, BUFFER_SIZES(start, t, size), ", next correction %d sec on %s, new GPS-UTC offset %d",
405854359Sroberto	      dtlsf - dtls, gmprettydate(&leapdate), dtlsf);
405954359Sroberto    }
406054359Sroberto  else
406154359Sroberto    {
4062182007Sroberto	    snprintf(t, BUFFER_SIZES(start, t, size), ", last correction on %s",
406354359Sroberto	      gmprettydate(&leapdate));
406454359Sroberto    }
406554359Sroberto}
406654359Sroberto
406754359Sroberto#ifdef CLOCK_MEINBERG
406854359Sroberto/**===========================================================================
406954359Sroberto ** Meinberg GPS166/GPS167 support
407054359Sroberto **/
407154359Sroberto
407254359Sroberto/*------------------------------------------------------------
407354359Sroberto * gps16x_message - process GPS16x messages
407454359Sroberto */
407554359Srobertostatic void
407654359Srobertogps16x_message(
407754359Sroberto	       struct parseunit *parse,
407854359Sroberto	       parsetime_t      *parsetime
407954359Sroberto	       )
408054359Sroberto{
4081182007Sroberto	if (parse->timedata.parse_msglen && parsetime->parse_msg[0] == SOH)
408254359Sroberto	{
408354359Sroberto		GPS_MSG_HDR header;
408454359Sroberto		unsigned char *bufp = (unsigned char *)parsetime->parse_msg + 1;
408554359Sroberto
408654359Sroberto#ifdef DEBUG
408754359Sroberto		if (debug > 2)
408854359Sroberto		{
408954359Sroberto			char msgbuffer[600];
409054359Sroberto
409154359Sroberto			mkreadable(msgbuffer, sizeof(msgbuffer), (char *)parsetime->parse_msg, parsetime->parse_msglen, 1);
409254359Sroberto			printf("PARSE receiver #%d: received message (%d bytes) >%s<\n",
409354359Sroberto				CLK_UNIT(parse->peer),
409454359Sroberto				parsetime->parse_msglen,
409554359Sroberto				msgbuffer);
409654359Sroberto		}
409754359Sroberto#endif
409854359Sroberto		get_mbg_header(&bufp, &header);
409954359Sroberto		if (header.gps_hdr_csum == mbg_csum(parsetime->parse_msg + 1, 6) &&
410054359Sroberto		    (header.gps_len == 0 ||
410154359Sroberto		     (header.gps_len < sizeof(parsetime->parse_msg) &&
410254359Sroberto		      header.gps_data_csum == mbg_csum(bufp, header.gps_len))))
410354359Sroberto		{
410454359Sroberto			/*
410554359Sroberto			 * clean message
410654359Sroberto			 */
410754359Sroberto			switch (header.gps_cmd)
410854359Sroberto			{
410954359Sroberto			case GPS_SW_REV:
411054359Sroberto				{
411154359Sroberto					char buffer[64];
411254359Sroberto					SW_REV gps_sw_rev;
411354359Sroberto
411454359Sroberto					get_mbg_sw_rev(&bufp, &gps_sw_rev);
4115182007Sroberto					snprintf(buffer, sizeof(buffer), "meinberg_gps_version=\"%x.%02x%s%s\"",
411654359Sroberto						(gps_sw_rev.code >> 8) & 0xFF,
411754359Sroberto						gps_sw_rev.code & 0xFF,
411854359Sroberto						gps_sw_rev.name[0] ? " " : "",
411954359Sroberto						gps_sw_rev.name);
4120182007Sroberto					set_var(&parse->kv, buffer, strlen(buffer)+1, RO|DEF);
412154359Sroberto				}
412254359Sroberto			break;
412354359Sroberto
412454359Sroberto			case GPS_STAT:
412554359Sroberto				{
412654359Sroberto					static struct state
412754359Sroberto					{
412854359Sroberto						unsigned short flag; /* status flag */
412954359Sroberto						unsigned const char *string; /* bit name */
413054359Sroberto					} states[] =
413154359Sroberto					  {
413254359Sroberto						  { TM_ANT_DISCONN, (const unsigned char *)"ANTENNA FAULTY" },
413354359Sroberto						  { TM_SYN_FLAG,    (const unsigned char *)"NO SYNC SIGNAL" },
413454359Sroberto						  { TM_NO_SYNC,     (const unsigned char *)"NO SYNC POWERUP" },
413554359Sroberto						  { TM_NO_POS,      (const unsigned char *)"NO POSITION" },
413654359Sroberto						  { 0, (const unsigned char *)"" }
413754359Sroberto					  };
413854359Sroberto					unsigned short status;
413954359Sroberto					struct state *s = states;
414054359Sroberto					char buffer[512];
414154359Sroberto					char *p, *b;
414254359Sroberto
414354359Sroberto					status = get_lsb_short(&bufp);
4144182007Sroberto					snprintf(buffer, sizeof(buffer), "meinberg_gps_status=\"[0x%04x] ", status);
414554359Sroberto
414654359Sroberto					if (status)
414754359Sroberto					{
414854359Sroberto						p = b = buffer + strlen(buffer);
414954359Sroberto						while (s->flag)
415054359Sroberto						{
415154359Sroberto							if (status & s->flag)
415254359Sroberto							{
415354359Sroberto								if (p != b)
415454359Sroberto								{
415554359Sroberto									*p++ = ',';
415654359Sroberto									*p++ = ' ';
415754359Sroberto								}
415854359Sroberto
4159182007Sroberto								strncat(p, (const char *)s->string, sizeof(buffer));
416054359Sroberto							}
416154359Sroberto							s++;
416254359Sroberto						}
416354359Sroberto
416454359Sroberto						*p++ = '"';
416554359Sroberto						*p   = '\0';
416654359Sroberto					}
416754359Sroberto					else
416854359Sroberto					{
4169182007Sroberto						strncat(buffer, "<OK>\"", sizeof(buffer));
417054359Sroberto					}
417154359Sroberto
4172182007Sroberto					set_var(&parse->kv, buffer, strlen(buffer)+1, RO|DEF);
417354359Sroberto				}
417454359Sroberto			break;
417554359Sroberto
417654359Sroberto			case GPS_POS_XYZ:
417754359Sroberto				{
417854359Sroberto					XYZ xyz;
417954359Sroberto					char buffer[256];
418054359Sroberto
418154359Sroberto					get_mbg_xyz(&bufp, xyz);
4182182007Sroberto					snprintf(buffer, sizeof(buffer), "gps_position(XYZ)=\"%s m, %s m, %s m\"",
418354359Sroberto						mfptoa(xyz[XP].l_ui, xyz[XP].l_uf, 1),
418454359Sroberto						mfptoa(xyz[YP].l_ui, xyz[YP].l_uf, 1),
418554359Sroberto						mfptoa(xyz[ZP].l_ui, xyz[ZP].l_uf, 1));
418654359Sroberto
418754359Sroberto					set_var(&parse->kv, buffer, sizeof(buffer), RO|DEF);
418854359Sroberto				}
418954359Sroberto			break;
419054359Sroberto
419154359Sroberto			case GPS_POS_LLA:
419254359Sroberto				{
419354359Sroberto					LLA lla;
419454359Sroberto					char buffer[256];
419554359Sroberto
419654359Sroberto					get_mbg_lla(&bufp, lla);
419754359Sroberto
4198182007Sroberto					snprintf(buffer, sizeof(buffer), "gps_position(LLA)=\"%s deg, %s deg, %s m\"",
419954359Sroberto						mfptoa(lla[LAT].l_ui, lla[LAT].l_uf, 4),
420054359Sroberto						mfptoa(lla[LON].l_ui, lla[LON].l_uf, 4),
420154359Sroberto						mfptoa(lla[ALT].l_ui, lla[ALT].l_uf, 1));
420254359Sroberto
420354359Sroberto					set_var(&parse->kv, buffer, sizeof(buffer), RO|DEF);
420454359Sroberto				}
420554359Sroberto			break;
420654359Sroberto
420754359Sroberto			case GPS_TZDL:
420854359Sroberto				break;
420954359Sroberto
421054359Sroberto			case GPS_PORT_PARM:
421154359Sroberto				break;
421254359Sroberto
421354359Sroberto			case GPS_SYNTH:
421454359Sroberto				break;
421554359Sroberto
421654359Sroberto			case GPS_ANT_INFO:
421754359Sroberto				{
421854359Sroberto					ANT_INFO antinfo;
4219182007Sroberto					char buffer[512];
4220182007Sroberto					char *p;
422154359Sroberto
422254359Sroberto					get_mbg_antinfo(&bufp, &antinfo);
4223182007Sroberto					snprintf(buffer, sizeof(buffer), "meinberg_antenna_status=\"");
422454359Sroberto					p = buffer + strlen(buffer);
422554359Sroberto
422654359Sroberto					switch (antinfo.status)
422754359Sroberto					{
422854359Sroberto					case ANT_INVALID:
4229182007Sroberto						strncat(p, "<OK>", BUFFER_SIZE(buffer, p));
423054359Sroberto						p += strlen(p);
423154359Sroberto						break;
423254359Sroberto
423354359Sroberto					case ANT_DISCONN:
4234182007Sroberto						strncat(p, "DISCONNECTED since ", BUFFER_SIZE(buffer, p));
423554359Sroberto						NLOG(NLOG_CLOCKSTATUS)
423654359Sroberto							ERR(ERR_BADSTATUS)
423754359Sroberto							msyslog(LOG_ERR,"PARSE receiver #%d: ANTENNA FAILURE: %s",
423854359Sroberto								CLK_UNIT(parse->peer), p);
423954359Sroberto
424054359Sroberto						p += strlen(p);
4241182007Sroberto						mbg_tm_str(&p, &antinfo.tm_disconn, BUFFER_SIZE(buffer, p));
424254359Sroberto						*p = '\0';
424354359Sroberto						break;
424454359Sroberto
424554359Sroberto					case ANT_RECONN:
4246182007Sroberto						strncat(p, "RECONNECTED on ", BUFFER_SIZE(buffer, p));
424754359Sroberto						p += strlen(p);
4248182007Sroberto						mbg_tm_str(&p, &antinfo.tm_reconn, BUFFER_SIZE(buffer, p));
4249182007Sroberto						snprintf(p, BUFFER_SIZE(buffer, p), ", reconnect clockoffset %c%ld.%07ld s, disconnect time ",
425054359Sroberto							(antinfo.delta_t < 0) ? '-' : '+',
425154359Sroberto							ABS(antinfo.delta_t) / 10000,
425254359Sroberto							ABS(antinfo.delta_t) % 10000);
425354359Sroberto						p += strlen(p);
4254182007Sroberto						mbg_tm_str(&p, &antinfo.tm_disconn, BUFFER_SIZE(buffer, p));
425554359Sroberto						*p = '\0';
425654359Sroberto						break;
425754359Sroberto
425854359Sroberto					default:
4259182007Sroberto						snprintf(p, BUFFER_SIZE(buffer, p), "bad status 0x%04x", antinfo.status);
426054359Sroberto						p += strlen(p);
426154359Sroberto						break;
426254359Sroberto					}
426354359Sroberto
4264182007Sroberto					strncat(p, "\"", BUFFER_SIZE(buffer, p));
426554359Sroberto
4266182007Sroberto					set_var(&parse->kv, buffer, strlen(buffer)+1, RO|DEF);
426754359Sroberto				}
426854359Sroberto			break;
426954359Sroberto
427054359Sroberto			case GPS_UCAP:
427154359Sroberto				break;
427254359Sroberto
427354359Sroberto			case GPS_CFGH:
427454359Sroberto				{
427554359Sroberto					CFGH cfgh;
4276182007Sroberto					char buffer[512];
4277182007Sroberto					char *p;
427854359Sroberto
427954359Sroberto					get_mbg_cfgh(&bufp, &cfgh);
428054359Sroberto					if (cfgh.valid)
428154359Sroberto					{
428254359Sroberto						int i;
428354359Sroberto
428454359Sroberto						p = buffer;
4285182007Sroberto						strncpy(buffer, "gps_tot_51=\"", BUFFER_SIZE(buffer, p));
428654359Sroberto						p += strlen(p);
4287182007Sroberto						mbg_tgps_str(&p, &cfgh.tot_51, BUFFER_SIZE(buffer, p));
4288182007Sroberto						strncpy(p, "\"", BUFFER_SIZE(buffer, p));
4289182007Sroberto						set_var(&parse->kv, buffer, strlen(buffer)+1, RO);
429054359Sroberto
429154359Sroberto						p = buffer;
4292182007Sroberto						strncpy(buffer, "gps_tot_63=\"", BUFFER_SIZE(buffer, p));
429354359Sroberto						p += strlen(p);
4294182007Sroberto						mbg_tgps_str(&p, &cfgh.tot_63, BUFFER_SIZE(buffer, p));
4295182007Sroberto						strncpy(p, "\"", BUFFER_SIZE(buffer, p));
4296182007Sroberto						set_var(&parse->kv, buffer, strlen(buffer)+1, RO);
429754359Sroberto
429854359Sroberto						p = buffer;
4299182007Sroberto						strncpy(buffer, "gps_t0a=\"", BUFFER_SIZE(buffer, p));
430054359Sroberto						p += strlen(p);
4301182007Sroberto						mbg_tgps_str(&p, &cfgh.t0a, BUFFER_SIZE(buffer, p));
4302182007Sroberto						strncpy(p, "\"", BUFFER_SIZE(buffer, p));
4303182007Sroberto						set_var(&parse->kv, buffer, strlen(buffer)+1, RO);
430454359Sroberto
4305182007Sroberto						for (i = MIN_SVNO; i < MAX_SVNO; i++)
430654359Sroberto						{
430754359Sroberto							p = buffer;
4308182007Sroberto							snprintf(p, BUFFER_SIZE(buffer, p), "gps_cfg[%d]=\"[0x%x] ", i, cfgh.cfg[i]);
430954359Sroberto							p += strlen(p);
431054359Sroberto							switch (cfgh.cfg[i] & 0x7)
431154359Sroberto							{
431254359Sroberto							case 0:
4313182007Sroberto								strncpy(p, "BLOCK I", BUFFER_SIZE(buffer, p));
431454359Sroberto								break;
431554359Sroberto							case 1:
4316182007Sroberto								strncpy(p, "BLOCK II", BUFFER_SIZE(buffer, p));
431754359Sroberto								break;
431854359Sroberto							default:
4319182007Sroberto								strncpy(p, "bad CFG", BUFFER_SIZE(buffer, p));
432054359Sroberto								break;
432154359Sroberto							}
4322182007Sroberto							strncat(p, "\"", BUFFER_SIZE(buffer, p));
4323182007Sroberto							set_var(&parse->kv, buffer, strlen(buffer)+1, RO);
432454359Sroberto
432554359Sroberto							p = buffer;
4326182007Sroberto							snprintf(p, BUFFER_SIZE(buffer, p), "gps_health[%d]=\"[0x%x] ", i, cfgh.health[i]);
432754359Sroberto							p += strlen(p);
432854359Sroberto							switch ((cfgh.health[i] >> 5) & 0x7 )
432954359Sroberto							{
433054359Sroberto							case 0:
4331182007Sroberto								strncpy(p, "OK;", BUFFER_SIZE(buffer, p));
433254359Sroberto								break;
433354359Sroberto							case 1:
4334182007Sroberto								strncpy(p, "PARITY;", BUFFER_SIZE(buffer, p));
433554359Sroberto								break;
433654359Sroberto							case 2:
4337182007Sroberto								strncpy(p, "TLM/HOW;", BUFFER_SIZE(buffer, p));
433854359Sroberto								break;
433954359Sroberto							case 3:
4340182007Sroberto								strncpy(p, "Z-COUNT;", BUFFER_SIZE(buffer, p));
434154359Sroberto								break;
434254359Sroberto							case 4:
4343182007Sroberto								strncpy(p, "SUBFRAME 1,2,3;", BUFFER_SIZE(buffer, p));
434454359Sroberto								break;
434554359Sroberto							case 5:
4346182007Sroberto								strncpy(p, "SUBFRAME 4,5;", BUFFER_SIZE(buffer, p));
434754359Sroberto								break;
434854359Sroberto							case 6:
4349182007Sroberto								strncpy(p, "UPLOAD BAD;", BUFFER_SIZE(buffer, p));
435054359Sroberto								break;
435154359Sroberto							case 7:
4352182007Sroberto								strncpy(p, "DATA BAD;", BUFFER_SIZE(buffer, p));
435354359Sroberto								break;
435454359Sroberto							}
435554359Sroberto
435654359Sroberto							p += strlen(p);
435754359Sroberto
435854359Sroberto							switch (cfgh.health[i] & 0x1F)
435954359Sroberto							{
436054359Sroberto							case 0:
4361182007Sroberto								strncpy(p, "SIGNAL OK", BUFFER_SIZE(buffer, p));
436254359Sroberto								break;
436354359Sroberto							case 0x1C:
4364182007Sroberto								strncpy(p, "SV TEMP OUT", BUFFER_SIZE(buffer, p));
436554359Sroberto								break;
436654359Sroberto							case 0x1D:
4367182007Sroberto								strncpy(p, "SV WILL BE TEMP OUT", BUFFER_SIZE(buffer, p));
436854359Sroberto								break;
436954359Sroberto							case 0x1E:
437054359Sroberto								break;
437154359Sroberto							case 0x1F:
4372182007Sroberto								strncpy(p, "MULTIPLE ERRS", BUFFER_SIZE(buffer, p));
437354359Sroberto								break;
437454359Sroberto							default:
4375182007Sroberto								strncpy(p, "TRANSMISSION PROBLEMS", BUFFER_SIZE(buffer, p));
437654359Sroberto								break;
437754359Sroberto							}
437854359Sroberto
4379182007Sroberto							strncat(p, "\"", sizeof(buffer));
4380182007Sroberto							set_var(&parse->kv, buffer, strlen(buffer)+1, RO);
438154359Sroberto						}
438254359Sroberto					}
438354359Sroberto				}
438454359Sroberto			break;
438554359Sroberto
438654359Sroberto			case GPS_ALM:
438754359Sroberto				break;
438854359Sroberto
438954359Sroberto			case GPS_EPH:
439054359Sroberto				break;
439154359Sroberto
439254359Sroberto			case GPS_UTC:
439354359Sroberto				{
439454359Sroberto					UTC utc;
439554359Sroberto					char buffer[512];
439654359Sroberto					char *p;
439754359Sroberto
439854359Sroberto					p = buffer;
439954359Sroberto
440054359Sroberto					get_mbg_utc(&bufp, &utc);
440154359Sroberto
440254359Sroberto					if (utc.valid)
440354359Sroberto					{
4404182007Sroberto						strncpy(p, "gps_utc_correction=\"", sizeof(buffer));
440554359Sroberto						p += strlen(p);
4406182007Sroberto						mk_utcinfo(p, utc.t0t.wn, utc.WNlsf, utc.DNt, utc.delta_tls, utc.delta_tlsf, BUFFER_SIZE(buffer, p));
4407182007Sroberto						strncat(p, "\"", BUFFER_SIZE(buffer, p));
440854359Sroberto					}
440954359Sroberto					else
441054359Sroberto					{
4411182007Sroberto						strncpy(p, "gps_utc_correction=\"<NO UTC DATA>\"", BUFFER_SIZE(buffer, p));
441254359Sroberto					}
4413182007Sroberto					set_var(&parse->kv, buffer, strlen(buffer)+1, RO|DEF);
441454359Sroberto				}
441554359Sroberto			break;
441654359Sroberto
441754359Sroberto			case GPS_IONO:
441854359Sroberto				break;
441954359Sroberto
442054359Sroberto			case GPS_ASCII_MSG:
442154359Sroberto				{
442254359Sroberto					ASCII_MSG gps_ascii_msg;
442354359Sroberto					char buffer[128];
442454359Sroberto
442554359Sroberto					get_mbg_ascii_msg(&bufp, &gps_ascii_msg);
442654359Sroberto
442754359Sroberto					if (gps_ascii_msg.valid)
442854359Sroberto						{
442954359Sroberto							char buffer1[128];
443054359Sroberto							mkreadable(buffer1, sizeof(buffer1), gps_ascii_msg.s, strlen(gps_ascii_msg.s), (int)0);
443154359Sroberto
4432182007Sroberto							snprintf(buffer, sizeof(buffer), "gps_message=\"%s\"", buffer1);
443354359Sroberto						}
443454359Sroberto					else
4435182007Sroberto						strncpy(buffer, "gps_message=<NONE>", sizeof(buffer));
443654359Sroberto
4437182007Sroberto					set_var(&parse->kv, buffer, strlen(buffer)+1, RO|DEF);
443854359Sroberto				}
443954359Sroberto
444054359Sroberto			break;
444154359Sroberto
444254359Sroberto			default:
444354359Sroberto				break;
444454359Sroberto			}
444554359Sroberto		}
444654359Sroberto		else
444754359Sroberto		{
444854359Sroberto			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)",
444954359Sroberto				CLK_UNIT(parse->peer),
445054359Sroberto				header.gps_hdr_csum, mbg_csum(parsetime->parse_msg + 1, 6),
445154359Sroberto				header.gps_len,
445254359Sroberto				header.gps_data_csum, mbg_csum(bufp, (unsigned)((header.gps_len < sizeof(parsetime->parse_msg)) ? header.gps_len : 0)));
445354359Sroberto		}
445454359Sroberto	}
445554359Sroberto
445654359Sroberto	return;
445754359Sroberto}
445854359Sroberto
445954359Sroberto/*------------------------------------------------------------
446054359Sroberto * gps16x_poll - query the reciver peridically
446154359Sroberto */
446254359Srobertostatic void
446354359Srobertogps16x_poll(
446454359Sroberto	    struct peer *peer
446554359Sroberto	    )
446654359Sroberto{
446754359Sroberto	struct parseunit *parse = (struct parseunit *)peer->procptr->unitptr;
446854359Sroberto
446954359Sroberto	static GPS_MSG_HDR sequence[] =
447054359Sroberto	{
447154359Sroberto		{ GPS_SW_REV,          0, 0, 0 },
447254359Sroberto		{ GPS_STAT,            0, 0, 0 },
447354359Sroberto		{ GPS_UTC,             0, 0, 0 },
447454359Sroberto		{ GPS_ASCII_MSG,       0, 0, 0 },
447554359Sroberto		{ GPS_ANT_INFO,        0, 0, 0 },
447654359Sroberto		{ GPS_CFGH,            0, 0, 0 },
447754359Sroberto		{ GPS_POS_XYZ,         0, 0, 0 },
447854359Sroberto		{ GPS_POS_LLA,         0, 0, 0 },
447954359Sroberto		{ (unsigned short)~0,  0, 0, 0 }
448054359Sroberto	};
448154359Sroberto
448254359Sroberto	int rtc;
448354359Sroberto	unsigned char cmd_buffer[64];
448454359Sroberto	unsigned char *outp = cmd_buffer;
448554359Sroberto	GPS_MSG_HDR *header;
448654359Sroberto
448754359Sroberto	if (((poll_info_t *)parse->parse_type->cl_data)->rate)
448854359Sroberto	{
448954359Sroberto		parse->peer->nextaction = current_time + ((poll_info_t *)parse->parse_type->cl_data)->rate;
449054359Sroberto	}
449154359Sroberto
449254359Sroberto	if (sequence[parse->localstate].gps_cmd == (unsigned short)~0)
449354359Sroberto		parse->localstate = 0;
449454359Sroberto
449554359Sroberto	header = sequence + parse->localstate++;
449654359Sroberto
449754359Sroberto	*outp++ = SOH;		/* start command */
449854359Sroberto
449954359Sroberto	put_mbg_header(&outp, header);
450054359Sroberto	outp = cmd_buffer + 1;
450154359Sroberto
450254359Sroberto	header->gps_hdr_csum = (short)mbg_csum(outp, 6);
450354359Sroberto	put_mbg_header(&outp, header);
450454359Sroberto
450554359Sroberto#ifdef DEBUG
450654359Sroberto	if (debug > 2)
450754359Sroberto	{
450854359Sroberto		char buffer[128];
450954359Sroberto
451054359Sroberto		mkreadable(buffer, sizeof(buffer), (char *)cmd_buffer, (unsigned)(outp - cmd_buffer), 1);
451154359Sroberto		printf("PARSE receiver #%d: transmitted message #%ld (%d bytes) >%s<\n",
451254359Sroberto		       CLK_UNIT(parse->peer),
451354359Sroberto		       parse->localstate - 1,
451454359Sroberto		       (int)(outp - cmd_buffer),
451554359Sroberto		       buffer);
451654359Sroberto	}
451754359Sroberto#endif
451854359Sroberto
451954359Sroberto	rtc = write(parse->generic->io.fd, cmd_buffer, (unsigned long)(outp - cmd_buffer));
452054359Sroberto
452154359Sroberto	if (rtc < 0)
452254359Sroberto	{
452354359Sroberto		ERR(ERR_BADIO)
452454359Sroberto			msyslog(LOG_ERR, "PARSE receiver #%d: gps16x_poll: failed to send cmd to clock: %m", CLK_UNIT(parse->peer));
452554359Sroberto	}
452654359Sroberto	else
452754359Sroberto	if (rtc != outp - cmd_buffer)
452854359Sroberto	{
452954359Sroberto		ERR(ERR_BADIO)
453054359Sroberto			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));
453154359Sroberto	}
453254359Sroberto
453354359Sroberto	clear_err(parse, ERR_BADIO);
453454359Sroberto	return;
453554359Sroberto}
453654359Sroberto
453754359Sroberto/*--------------------------------------------------
453854359Sroberto * init routine - setup timer
453954359Sroberto */
454054359Srobertostatic int
454154359Srobertogps16x_poll_init(
454254359Sroberto	struct parseunit *parse
454354359Sroberto	)
454454359Sroberto{
454554359Sroberto	if (((poll_info_t *)parse->parse_type->cl_data)->rate)
454654359Sroberto	{
454754359Sroberto		parse->peer->action = gps16x_poll;
454854359Sroberto		gps16x_poll(parse->peer);
454954359Sroberto	}
455054359Sroberto
455154359Sroberto	return 0;
455254359Sroberto}
455354359Sroberto
455454359Sroberto#else
455554359Srobertostatic void
455654359Srobertogps16x_message(
455754359Sroberto	       struct parseunit *parse,
455854359Sroberto	       parsetime_t      *parsetime
455954359Sroberto	       )
456054359Sroberto{}
456154359Srobertostatic int
456254359Srobertogps16x_poll_init(
456354359Sroberto	struct parseunit *parse
456454359Sroberto	)
456554359Sroberto{
456654359Sroberto	return 1;
456754359Sroberto}
456854359Sroberto#endif /* CLOCK_MEINBERG */
456954359Sroberto
457054359Sroberto/**===========================================================================
457154359Sroberto ** clock polling support
457254359Sroberto **/
457354359Sroberto
457454359Sroberto/*--------------------------------------------------
457554359Sroberto * direct poll routine
457654359Sroberto */
457754359Srobertostatic void
457854359Srobertopoll_dpoll(
457954359Sroberto	struct parseunit *parse
458054359Sroberto	)
458154359Sroberto{
458254359Sroberto	int rtc;
458354359Sroberto	const char *ps = ((poll_info_t *)parse->parse_type->cl_data)->string;
458454359Sroberto	int   ct = ((poll_info_t *)parse->parse_type->cl_data)->count;
458554359Sroberto
458654359Sroberto	rtc = write(parse->generic->io.fd, ps, (unsigned long)ct);
458754359Sroberto	if (rtc < 0)
458854359Sroberto	{
458954359Sroberto		ERR(ERR_BADIO)
459054359Sroberto			msyslog(LOG_ERR, "PARSE receiver #%d: poll_dpoll: failed to send cmd to clock: %m", CLK_UNIT(parse->peer));
459154359Sroberto	}
459254359Sroberto	else
459354359Sroberto	    if (rtc != ct)
459454359Sroberto	    {
459554359Sroberto		    ERR(ERR_BADIO)
459654359Sroberto			    msyslog(LOG_ERR, "PARSE receiver #%d: poll_dpoll: failed to send cmd incomplete (%d of %d bytes sent)", CLK_UNIT(parse->peer), rtc, ct);
459754359Sroberto	    }
459854359Sroberto	clear_err(parse, ERR_BADIO);
459954359Sroberto}
460054359Sroberto
460154359Sroberto/*--------------------------------------------------
460254359Sroberto * periodic poll routine
460354359Sroberto */
460454359Srobertostatic void
460554359Srobertopoll_poll(
460654359Sroberto	struct peer *peer
460754359Sroberto	)
460854359Sroberto{
460954359Sroberto	struct parseunit *parse = (struct parseunit *)peer->procptr->unitptr;
461054359Sroberto
461154359Sroberto	if (parse->parse_type->cl_poll)
461254359Sroberto		parse->parse_type->cl_poll(parse);
461354359Sroberto
461454359Sroberto	if (((poll_info_t *)parse->parse_type->cl_data)->rate)
461554359Sroberto	{
461654359Sroberto		parse->peer->nextaction = current_time + ((poll_info_t *)parse->parse_type->cl_data)->rate;
461754359Sroberto	}
461854359Sroberto}
461954359Sroberto
462054359Sroberto/*--------------------------------------------------
462154359Sroberto * init routine - setup timer
462254359Sroberto */
462354359Srobertostatic int
462454359Srobertopoll_init(
462554359Sroberto	struct parseunit *parse
462654359Sroberto	)
462754359Sroberto{
462854359Sroberto	if (((poll_info_t *)parse->parse_type->cl_data)->rate)
462954359Sroberto	{
463054359Sroberto		parse->peer->action = poll_poll;
463154359Sroberto		poll_poll(parse->peer);
463254359Sroberto	}
463354359Sroberto
463454359Sroberto	return 0;
463554359Sroberto}
463656746Sroberto
463754359Sroberto/**===========================================================================
463854359Sroberto ** Trimble support
463954359Sroberto **/
464054359Sroberto
464154359Sroberto/*-------------------------------------------------------------
464254359Sroberto * trimble TAIP init routine - setup EOL and then do poll_init.
464354359Sroberto */
464454359Srobertostatic int
464554359Srobertotrimbletaip_init(
464654359Sroberto	struct parseunit *parse
464754359Sroberto	)
464854359Sroberto{
464954359Sroberto#ifdef HAVE_TERMIOS
465054359Sroberto	struct termios tio;
465154359Sroberto#endif
465254359Sroberto#ifdef HAVE_SYSV_TTYS
465354359Sroberto	struct termio tio;
465454359Sroberto#endif
465554359Sroberto	/*
465654359Sroberto	 * configure terminal line for trimble receiver
465754359Sroberto	 */
465854359Sroberto	if (TTY_GETATTR(parse->generic->io.fd, &tio) == -1)
465954359Sroberto	{
466054359Sroberto		msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_init: tcgetattr(fd, &tio): %m", CLK_UNIT(parse->peer));
466154359Sroberto		return 0;
466254359Sroberto	}
466354359Sroberto	else
466454359Sroberto	{
466554359Sroberto		tio.c_cc[VEOL] = TRIMBLETAIP_EOL;
466654359Sroberto
466754359Sroberto		if (TTY_SETATTR(parse->generic->io.fd, &tio) == -1)
466854359Sroberto		{
466954359Sroberto			msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_init: tcsetattr(fd, &tio): %m", CLK_UNIT(parse->peer));
467054359Sroberto			return 0;
467154359Sroberto		}
467254359Sroberto	}
467354359Sroberto	return poll_init(parse);
467454359Sroberto}
467554359Sroberto
467654359Sroberto/*--------------------------------------------------
467754359Sroberto * trimble TAIP event routine - reset receiver upon data format trouble
467854359Sroberto */
467954359Srobertostatic const char *taipinit[] = {
468054359Sroberto	">FPV00000000<",
468154359Sroberto	">SRM;ID_FLAG=F;CS_FLAG=T;EC_FLAG=F;FR_FLAG=T;CR_FLAG=F<",
468254359Sroberto	">FTM00020001<",
468354359Sroberto	(char *)0
468454359Sroberto};
468554359Sroberto
468654359Srobertostatic void
468754359Srobertotrimbletaip_event(
468854359Sroberto	struct parseunit *parse,
468954359Sroberto	int event
469054359Sroberto	)
469154359Sroberto{
469254359Sroberto	switch (event)
469354359Sroberto	{
469454359Sroberto	    case CEVNT_BADREPLY:	/* reset on garbled input */
469554359Sroberto	    case CEVNT_TIMEOUT:		/* reset on no input */
469654359Sroberto		    {
469754359Sroberto			    const char **iv;
469854359Sroberto
469954359Sroberto			    iv = taipinit;
470054359Sroberto			    while (*iv)
470154359Sroberto			    {
470254359Sroberto				    int rtc = write(parse->generic->io.fd, *iv, strlen(*iv));
470354359Sroberto				    if (rtc < 0)
470454359Sroberto				    {
470554359Sroberto					    msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_event: failed to send cmd to clock: %m", CLK_UNIT(parse->peer));
470654359Sroberto					    return;
470754359Sroberto				    }
470854359Sroberto				    else
470954359Sroberto				    {
471054359Sroberto					    if (rtc != strlen(*iv))
471154359Sroberto					    {
471254359Sroberto						    msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_event: failed to send cmd incomplete (%d of %d bytes sent)",
471354359Sroberto							    CLK_UNIT(parse->peer), rtc, (int)strlen(*iv));
471454359Sroberto						    return;
471554359Sroberto					    }
471654359Sroberto				    }
471754359Sroberto				    iv++;
471854359Sroberto			    }
471954359Sroberto
472054359Sroberto			    NLOG(NLOG_CLOCKINFO)
472154359Sroberto				    ERR(ERR_BADIO)
472254359Sroberto				    msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_event: RECEIVER INITIALIZED",
472354359Sroberto					    CLK_UNIT(parse->peer));
472454359Sroberto		    }
472554359Sroberto		    break;
472654359Sroberto
472754359Sroberto	    default:			/* ignore */
472854359Sroberto		break;
472954359Sroberto	}
473054359Sroberto}
473154359Sroberto
473254359Sroberto/*
473354359Sroberto * This driver supports the Trimble SVee Six Plus GPS receiver module.
473454359Sroberto * It should support other Trimble receivers which use the Trimble Standard
473554359Sroberto * Interface Protocol (see below).
473654359Sroberto *
473754359Sroberto * The module has a serial I/O port for command/data and a 1 pulse-per-second
473854359Sroberto * output, about 1 microsecond wide. The leading edge of the pulse is
473954359Sroberto * coincident with the change of the GPS second. This is the same as
474054359Sroberto * the change of the UTC second +/- ~1 microsecond. Some other clocks
474154359Sroberto * specifically use a feature in the data message as a timing reference, but
474254359Sroberto * the SVee Six Plus does not do this. In fact there is considerable jitter
474354359Sroberto * on the timing of the messages, so this driver only supports the use
474454359Sroberto * of the PPS pulse for accurate timing. Where it is determined that
474554359Sroberto * the offset is way off, when first starting up ntpd for example,
474654359Sroberto * the timing of the data stream is used until the offset becomes low enough
474756746Sroberto * (|offset| < CLOCK_MAX), at which point the pps offset is used.
474854359Sroberto *
474954359Sroberto * It can use either option for receiving PPS information - the 'ppsclock'
475054359Sroberto * stream pushed onto the serial data interface to timestamp the Carrier
475154359Sroberto * Detect interrupts, where the 1PPS connects to the CD line. This only
475254359Sroberto * works on SunOS 4.1.x currently. To select this, define PPSPPS in
475354359Sroberto * Config.local. The other option is to use a pulse-stretcher/level-converter
475454359Sroberto * to convert the PPS pulse into a RS232 start pulse & feed this into another
475554359Sroberto * tty port. To use this option, define PPSCLK in Config.local. The pps input,
475654359Sroberto * by whichever method, is handled in ntp_loopfilter.c
475754359Sroberto *
475854359Sroberto * The receiver uses a serial message protocol called Trimble Standard
475954359Sroberto * Interface Protocol (it can support others but this driver only supports
476054359Sroberto * TSIP). Messages in this protocol have the following form:
476154359Sroberto *
476254359Sroberto * <DLE><id> ... <data> ... <DLE><ETX>
476354359Sroberto *
476454359Sroberto * Any bytes within the <data> portion of value 10 hex (<DLE>) are doubled
476554359Sroberto * on transmission and compressed back to one on reception. Otherwise
476654359Sroberto * the values of data bytes can be anything. The serial interface is RS-422
476754359Sroberto * asynchronous using 9600 baud, 8 data bits with odd party (**note** 9 bits
476854359Sroberto * in total!), and 1 stop bit. The protocol supports byte, integer, single,
476954359Sroberto * and double datatypes. Integers are two bytes, sent most significant first.
477054359Sroberto * Singles are IEEE754 single precision floating point numbers (4 byte) sent
477154359Sroberto * sign & exponent first. Doubles are IEEE754 double precision floating point
477254359Sroberto * numbers (8 byte) sent sign & exponent first.
477354359Sroberto * The receiver supports a large set of messages, only a small subset of
477454359Sroberto * which are used here. From driver to receiver the following are used:
477554359Sroberto *
477654359Sroberto *  ID    Description
477754359Sroberto *
477854359Sroberto *  21    Request current time
477954359Sroberto *  22    Mode Select
478054359Sroberto *  2C    Set/Request operating parameters
478154359Sroberto *  2F    Request UTC info
478254359Sroberto *  35    Set/Request I/O options
478354359Sroberto
478454359Sroberto * From receiver to driver the following are recognised:
478554359Sroberto *
478654359Sroberto *  ID    Description
478754359Sroberto *
478854359Sroberto *  41    GPS Time
478954359Sroberto *  44    Satellite selection, PDOP, mode
479054359Sroberto *  46    Receiver health
479154359Sroberto *  4B    Machine code/status
479254359Sroberto *  4C    Report operating parameters (debug only)
479354359Sroberto *  4F    UTC correction data (used to get leap second warnings)
479454359Sroberto *  55    I/O options (debug only)
479554359Sroberto *
479654359Sroberto * All others are accepted but ignored.
479754359Sroberto *
479854359Sroberto */
479954359Sroberto
480054359Sroberto#define PI		3.1415926535898	/* lots of sig figs */
480154359Sroberto#define D2R		PI/180.0
480254359Sroberto
480354359Sroberto/*-------------------------------------------------------------------
480454359Sroberto * sendcmd, sendbyte, sendetx, sendflt, sendint implement the command
480554359Sroberto * interface to the receiver.
480654359Sroberto *
480754359Sroberto * CAVEAT: the sendflt, sendint routines are byte order dependend and
480854359Sroberto * float implementation dependend - these must be converted to portable
480954359Sroberto * versions !
481054359Sroberto *
481154359Sroberto * CURRENT LIMITATION: float implementation. This runs only on systems
481254359Sroberto * with IEEE754 floats as native floats
481354359Sroberto */
481454359Sroberto
481554359Srobertotypedef struct trimble
481654359Sroberto{
481754359Sroberto	u_long last_msg;	/* last message received */
4818182007Sroberto	u_long last_reset;	/* last time a reset was issued */
481954359Sroberto	u_char qtracking;	/* query tracking status */
482054359Sroberto	u_long ctrack;		/* current tracking set */
482154359Sroberto	u_long ltrack;		/* last tracking set */
482254359Sroberto} trimble_t;
482354359Sroberto
482454359Srobertounion uval {
482554359Sroberto	u_char  bd[8];
482654359Sroberto	int     iv;
482754359Sroberto	float   fv;
482854359Sroberto	double  dv;
482954359Sroberto};
483054359Sroberto
483154359Srobertostruct txbuf
483254359Sroberto{
483354359Sroberto	short idx;			/* index to first unused byte */
483454359Sroberto	u_char *txt;			/* pointer to actual data buffer */
483554359Sroberto};
483654359Sroberto
483756746Srobertovoid	sendcmd		P((struct txbuf *buf, int c));
483856746Srobertovoid	sendbyte	P((struct txbuf *buf, int b));
483956746Srobertovoid	sendetx		P((struct txbuf *buf, struct parseunit *parse));
484056746Srobertovoid	sendint		P((struct txbuf *buf, int a));
484156746Srobertovoid	sendflt		P((struct txbuf *buf, double a));
484256746Sroberto
484354359Srobertovoid
484454359Srobertosendcmd(
484554359Sroberto	struct txbuf *buf,
484654359Sroberto	int c
484754359Sroberto	)
484854359Sroberto{
484954359Sroberto	buf->txt[0] = DLE;
485054359Sroberto	buf->txt[1] = (u_char)c;
485154359Sroberto	buf->idx = 2;
485254359Sroberto}
485354359Sroberto
4854182007Srobertovoid	sendcmd		P((struct txbuf *buf, int c));
4855182007Srobertovoid	sendbyte	P((struct txbuf *buf, int b));
4856182007Srobertovoid	sendetx		P((struct txbuf *buf, struct parseunit *parse));
4857182007Srobertovoid	sendint		P((struct txbuf *buf, int a));
4858182007Srobertovoid	sendflt		P((struct txbuf *buf, double a));
4859182007Sroberto
486054359Srobertovoid
486154359Srobertosendbyte(
486254359Sroberto	struct txbuf *buf,
486354359Sroberto	int b
486454359Sroberto	)
486554359Sroberto{
486654359Sroberto	if (b == DLE)
486754359Sroberto	    buf->txt[buf->idx++] = DLE;
486854359Sroberto	buf->txt[buf->idx++] = (u_char)b;
486954359Sroberto}
487054359Sroberto
487154359Srobertovoid
487254359Srobertosendetx(
487354359Sroberto	struct txbuf *buf,
487454359Sroberto	struct parseunit *parse
487554359Sroberto	)
487654359Sroberto{
487754359Sroberto	buf->txt[buf->idx++] = DLE;
487854359Sroberto	buf->txt[buf->idx++] = ETX;
487954359Sroberto
488054359Sroberto	if (write(parse->generic->io.fd, buf->txt, (unsigned long)buf->idx) != buf->idx)
488154359Sroberto	{
488254359Sroberto		ERR(ERR_BADIO)
488354359Sroberto			msyslog(LOG_ERR, "PARSE receiver #%d: sendetx: failed to send cmd to clock: %m", CLK_UNIT(parse->peer));
488454359Sroberto	}
488554359Sroberto	else
488654359Sroberto	{
488754359Sroberto#ifdef DEBUG
488854359Sroberto	  if (debug > 2)
488954359Sroberto	  {
489054359Sroberto		  char buffer[256];
489154359Sroberto
489254359Sroberto		  mkreadable(buffer, sizeof(buffer), (char *)buf->txt, (unsigned)buf->idx, 1);
489354359Sroberto		  printf("PARSE receiver #%d: transmitted message (%d bytes) >%s<\n",
489454359Sroberto			 CLK_UNIT(parse->peer),
489554359Sroberto			 buf->idx, buffer);
489654359Sroberto	  }
489754359Sroberto#endif
489854359Sroberto		clear_err(parse, ERR_BADIO);
489954359Sroberto	}
490054359Sroberto}
490154359Sroberto
490254359Srobertovoid
490354359Srobertosendint(
490454359Sroberto	struct txbuf *buf,
490554359Sroberto	int a
490654359Sroberto	)
490754359Sroberto{
490854359Sroberto	/* send 16bit int, msbyte first */
490954359Sroberto	sendbyte(buf, (u_char)((a>>8) & 0xff));
491054359Sroberto	sendbyte(buf, (u_char)(a & 0xff));
491154359Sroberto}
491254359Sroberto
491354359Srobertovoid
491454359Srobertosendflt(
491554359Sroberto	struct txbuf *buf,
491654359Sroberto	double a
491754359Sroberto	)
491854359Sroberto{
491954359Sroberto	int i;
492054359Sroberto	union uval uval;
492154359Sroberto
492254359Sroberto	uval.fv = a;
492354359Sroberto#ifdef WORDS_BIGENDIAN
492454359Sroberto	for (i=0; i<=3; i++)
492554359Sroberto#else
492654359Sroberto	    for (i=3; i>=0; i--)
492754359Sroberto#endif
492854359Sroberto		sendbyte(buf, uval.bd[i]);
492954359Sroberto}
493054359Sroberto
493154359Sroberto#define TRIM_POS_OPT	0x13	/* output position with high precision */
493254359Sroberto#define TRIM_TIME_OPT	0x03	/* use UTC time stamps, on second */
493354359Sroberto
493454359Sroberto/*--------------------------------------------------
493554359Sroberto * trimble TSIP setup routine
493654359Sroberto */
493754359Srobertostatic int
493854359Srobertotrimbletsip_setup(
493954359Sroberto		  struct parseunit *parse,
494054359Sroberto		  const char *reason
494156746Sroberto		  )
494254359Sroberto{
494354359Sroberto	u_char buffer[256];
494454359Sroberto	struct txbuf buf;
4945182007Sroberto	trimble_t *t = parse->localdata;
494654359Sroberto
4947182007Sroberto	if (t && t->last_reset &&
4948182007Sroberto	    ((t->last_reset + TRIMBLE_RESET_HOLDOFF) > current_time)) {
4949182007Sroberto		return 1;	/* not yet */
4950182007Sroberto	}
4951182007Sroberto
4952182007Sroberto	if (t)
4953182007Sroberto		t->last_reset = current_time;
4954182007Sroberto
495554359Sroberto	buf.txt = buffer;
495654359Sroberto
495754359Sroberto	sendcmd(&buf, CMD_CVERSION);	/* request software versions */
495856746Sroberto	sendetx(&buf, parse);
495956746Sroberto
496054359Sroberto	sendcmd(&buf, CMD_COPERPARAM);	/* set operating parameters */
496156746Sroberto	sendbyte(&buf, 4);	/* static */
496256746Sroberto	sendflt(&buf, 5.0*D2R);	/* elevation angle mask = 10 deg XXX */
496356746Sroberto	sendflt(&buf, 4.0);	/* s/n ratio mask = 6 XXX */
496456746Sroberto	sendflt(&buf, 12.0);	/* PDOP mask = 12 */
496556746Sroberto	sendflt(&buf, 8.0);	/* PDOP switch level = 8 */
496656746Sroberto	sendetx(&buf, parse);
496756746Sroberto
496854359Sroberto	sendcmd(&buf, CMD_CMODESEL);	/* fix mode select */
4969182007Sroberto	sendbyte(&buf, 1);	/* time transfer mode */
497056746Sroberto	sendetx(&buf, parse);
497156746Sroberto
497254359Sroberto	sendcmd(&buf, CMD_CMESSAGE);	/* request system message */
497356746Sroberto	sendetx(&buf, parse);
497456746Sroberto
497554359Sroberto	sendcmd(&buf, CMD_CSUPER);	/* superpacket fix */
497656746Sroberto	sendbyte(&buf, 0x2);	/* binary mode */
497756746Sroberto	sendetx(&buf, parse);
497856746Sroberto
497954359Sroberto	sendcmd(&buf, CMD_CIOOPTIONS);	/* set I/O options */
498054359Sroberto	sendbyte(&buf, TRIM_POS_OPT);	/* position output */
498154359Sroberto	sendbyte(&buf, 0x00);	/* no velocity output */
498254359Sroberto	sendbyte(&buf, TRIM_TIME_OPT);	/* UTC, compute on seconds */
498354359Sroberto	sendbyte(&buf, 0x00);	/* no raw measurements */
498456746Sroberto	sendetx(&buf, parse);
498556746Sroberto
498654359Sroberto	sendcmd(&buf, CMD_CUTCPARAM);	/* request UTC correction data */
498754359Sroberto	sendetx(&buf, parse);
498854359Sroberto
498954359Sroberto	NLOG(NLOG_CLOCKINFO)
499054359Sroberto		ERR(ERR_BADIO)
499154359Sroberto		msyslog(LOG_ERR, "PARSE receiver #%d: trimbletsip_setup: RECEIVER RE-INITIALIZED (%s)", CLK_UNIT(parse->peer), reason);
499254359Sroberto
499354359Sroberto	return 0;
499454359Sroberto}
499554359Sroberto
499654359Sroberto/*--------------------------------------------------
499754359Sroberto * TRIMBLE TSIP check routine
499854359Sroberto */
499954359Srobertostatic void
500054359Srobertotrimble_check(
500154359Sroberto	      struct peer *peer
500254359Sroberto	      )
500354359Sroberto{
500454359Sroberto	struct parseunit *parse = (struct parseunit *)peer->procptr->unitptr;
500554359Sroberto	trimble_t *t = parse->localdata;
500654359Sroberto	u_char buffer[256];
500754359Sroberto	struct txbuf buf;
500854359Sroberto	buf.txt = buffer;
500954359Sroberto
501054359Sroberto	if (t)
501154359Sroberto	{
501254359Sroberto		if (current_time > t->last_msg + TRIMBLETSIP_IDLE_TIME)
501354359Sroberto			(void)trimbletsip_setup(parse, "message timeout");
501454359Sroberto	}
5015182007Sroberto
501654359Sroberto	poll_poll(parse->peer);	/* emit query string and re-arm timer */
501754359Sroberto
5018182007Sroberto	if (t && t->qtracking)
501954359Sroberto	{
502054359Sroberto		u_long oldsats = t->ltrack & ~t->ctrack;
502154359Sroberto
502254359Sroberto		t->qtracking = 0;
502354359Sroberto		t->ltrack = t->ctrack;
502454359Sroberto
502554359Sroberto		if (oldsats)
502654359Sroberto		{
502754359Sroberto			int i;
502854359Sroberto
5029182007Sroberto			for (i = 0; oldsats; i++) {
503054359Sroberto				if (oldsats & (1 << i))
503154359Sroberto					{
503254359Sroberto						sendcmd(&buf, CMD_CSTATTRACK);
503354359Sroberto						sendbyte(&buf, i+1);	/* old sat */
503454359Sroberto						sendetx(&buf, parse);
503554359Sroberto					}
5036182007Sroberto				oldsats &= ~(1 << i);
5037182007Sroberto			}
503854359Sroberto		}
503954359Sroberto
504054359Sroberto		sendcmd(&buf, CMD_CSTATTRACK);
504154359Sroberto		sendbyte(&buf, 0x00);	/* current tracking set */
504254359Sroberto		sendetx(&buf, parse);
504354359Sroberto	}
504454359Sroberto}
504554359Sroberto
504654359Sroberto/*--------------------------------------------------
504754359Sroberto * TRIMBLE TSIP end routine
504854359Sroberto */
504954359Srobertostatic void
505054359Srobertotrimbletsip_end(
505154359Sroberto	      struct parseunit *parse
505254359Sroberto	      )
505354359Sroberto{	trimble_t *t = parse->localdata;
505454359Sroberto
505554359Sroberto	if (t)
505654359Sroberto	{
505754359Sroberto		free(t);
505854359Sroberto		parse->localdata = (void *)0;
505954359Sroberto	}
506054359Sroberto	parse->peer->nextaction = 0;
506154359Sroberto	parse->peer->action = (void (*) P((struct peer *)))0;
506254359Sroberto}
506354359Sroberto
506454359Sroberto/*--------------------------------------------------
506554359Sroberto * TRIMBLE TSIP init routine
506654359Sroberto */
506754359Srobertostatic int
506854359Srobertotrimbletsip_init(
506954359Sroberto	struct parseunit *parse
507054359Sroberto	)
507154359Sroberto{
507254359Sroberto#if defined(VEOL) || defined(VEOL2)
507354359Sroberto#ifdef HAVE_TERMIOS
507454359Sroberto	struct termios tio;		/* NEEDED FOR A LONG TIME ! */
507554359Sroberto#endif
507654359Sroberto#ifdef HAVE_SYSV_TTYS
507754359Sroberto	struct termio tio;		/* NEEDED FOR A LONG TIME ! */
507854359Sroberto#endif
507954359Sroberto	/*
508054359Sroberto	 * allocate local data area
508154359Sroberto	 */
508254359Sroberto	if (!parse->localdata)
508354359Sroberto	{
508454359Sroberto		trimble_t *t;
508554359Sroberto
508654359Sroberto		t = (trimble_t *)(parse->localdata = emalloc(sizeof(trimble_t)));
508754359Sroberto
508854359Sroberto		if (t)
508954359Sroberto		{
509054359Sroberto			memset((char *)t, 0, sizeof(trimble_t));
509154359Sroberto			t->last_msg = current_time;
509254359Sroberto		}
509354359Sroberto	}
509454359Sroberto
509554359Sroberto	parse->peer->action     = trimble_check;
509654359Sroberto	parse->peer->nextaction = current_time;
509754359Sroberto
509854359Sroberto	/*
509954359Sroberto	 * configure terminal line for ICANON mode with VEOL characters
510054359Sroberto	 */
510154359Sroberto	if (TTY_GETATTR(parse->generic->io.fd, &tio) == -1)
510254359Sroberto	{
510354359Sroberto		msyslog(LOG_ERR, "PARSE receiver #%d: trimbletsip_init: tcgetattr(%d, &tio): %m", CLK_UNIT(parse->peer), parse->generic->io.fd);
510454359Sroberto		return 0;
510554359Sroberto	}
510654359Sroberto	else
510754359Sroberto	{
510854359Sroberto		if ((parse_clockinfo[CLK_TYPE(parse->peer)].cl_lflag & ICANON))
510954359Sroberto		{
511054359Sroberto#ifdef VEOL
511154359Sroberto			tio.c_cc[VEOL]  = ETX;
511254359Sroberto#endif
511354359Sroberto#ifdef VEOL2
511454359Sroberto			tio.c_cc[VEOL2]  = DLE;
511554359Sroberto#endif
511656746Sroberto		}
511754359Sroberto
511854359Sroberto		if (TTY_SETATTR(parse->generic->io.fd, &tio) == -1)
511954359Sroberto		{
512054359Sroberto			msyslog(LOG_ERR, "PARSE receiver #%d: trimbletsip_init: tcsetattr(%d, &tio): %m", CLK_UNIT(parse->peer), parse->generic->io.fd);
512154359Sroberto			return 0;
512254359Sroberto		}
512354359Sroberto	}
512454359Sroberto#endif
512554359Sroberto	return trimbletsip_setup(parse, "initial startup");
512654359Sroberto}
512754359Sroberto
512854359Sroberto/*------------------------------------------------------------
512954359Sroberto * trimbletsip_event - handle Trimble events
513054359Sroberto * simple evente handler - attempt to re-initialize receiver
513154359Sroberto */
513254359Srobertostatic void
513354359Srobertotrimbletsip_event(
513454359Sroberto	struct parseunit *parse,
513554359Sroberto	int event
513654359Sroberto	)
513754359Sroberto{
513854359Sroberto	switch (event)
513954359Sroberto	{
514054359Sroberto	    case CEVNT_BADREPLY:	/* reset on garbled input */
514154359Sroberto	    case CEVNT_TIMEOUT:		/* reset on no input */
514254359Sroberto		    (void)trimbletsip_setup(parse, "event BAD_REPLY/TIMEOUT");
514354359Sroberto		    break;
514454359Sroberto
514554359Sroberto	    default:			/* ignore */
514654359Sroberto		break;
514754359Sroberto	}
514854359Sroberto}
514954359Sroberto
515054359Sroberto/*
515154359Sroberto * getflt, getint convert fields in the incoming data into the
515254359Sroberto * appropriate type of item
515354359Sroberto *
515454359Sroberto * CAVEAT: these routines are currently definitely byte order dependent
515554359Sroberto * and assume Representation(float) == IEEE754
515654359Sroberto * These functions MUST be converted to portable versions (especially
515754359Sroberto * converting the float representation into ntp_fp formats in order
515854359Sroberto * to avoid floating point operations at all!
515954359Sroberto */
516054359Sroberto
516154359Srobertostatic float
516254359Srobertogetflt(
516354359Sroberto	u_char *bp
516454359Sroberto	)
516554359Sroberto{
516654359Sroberto	union uval uval;
516754359Sroberto
516854359Sroberto#ifdef WORDS_BIGENDIAN
516954359Sroberto	uval.bd[0] = *bp++;
517054359Sroberto	uval.bd[1] = *bp++;
517154359Sroberto	uval.bd[2] = *bp++;
517254359Sroberto	uval.bd[3] = *bp;
517354359Sroberto#else  /* ! WORDS_BIGENDIAN */
517454359Sroberto	uval.bd[3] = *bp++;
517554359Sroberto	uval.bd[2] = *bp++;
517654359Sroberto	uval.bd[1] = *bp++;
517754359Sroberto	uval.bd[0] = *bp;
517854359Sroberto#endif /* ! WORDS_BIGENDIAN */
517954359Sroberto	return uval.fv;
518054359Sroberto}
518154359Sroberto
518254359Srobertostatic double
518354359Srobertogetdbl(
518454359Sroberto	u_char *bp
518554359Sroberto	)
518654359Sroberto{
518754359Sroberto	union uval uval;
518854359Sroberto
518954359Sroberto#ifdef WORDS_BIGENDIAN
519054359Sroberto	uval.bd[0] = *bp++;
519154359Sroberto	uval.bd[1] = *bp++;
519254359Sroberto	uval.bd[2] = *bp++;
519354359Sroberto	uval.bd[3] = *bp++;
519454359Sroberto	uval.bd[4] = *bp++;
519554359Sroberto	uval.bd[5] = *bp++;
519654359Sroberto	uval.bd[6] = *bp++;
519754359Sroberto	uval.bd[7] = *bp;
519854359Sroberto#else  /* ! WORDS_BIGENDIAN */
519954359Sroberto	uval.bd[7] = *bp++;
520054359Sroberto	uval.bd[6] = *bp++;
520154359Sroberto	uval.bd[5] = *bp++;
520254359Sroberto	uval.bd[4] = *bp++;
520354359Sroberto	uval.bd[3] = *bp++;
520454359Sroberto	uval.bd[2] = *bp++;
520554359Sroberto	uval.bd[1] = *bp++;
520654359Sroberto	uval.bd[0] = *bp;
520754359Sroberto#endif /* ! WORDS_BIGENDIAN */
520854359Sroberto	return uval.dv;
520954359Sroberto}
521054359Sroberto
521154359Srobertostatic int
521254359Srobertogetshort(
521354359Sroberto	 unsigned char *p
521454359Sroberto	 )
521554359Sroberto{
521654359Sroberto	return get_msb_short(&p);
521754359Sroberto}
521854359Sroberto
521954359Sroberto/*--------------------------------------------------
522054359Sroberto * trimbletsip_message - process trimble messages
522154359Sroberto */
522254359Sroberto#define RTOD (180.0 / 3.1415926535898)
522354359Sroberto#define mb(_X_) (buffer[2+(_X_)]) /* shortcut for buffer access */
522454359Sroberto
522554359Srobertostatic void
522654359Srobertotrimbletsip_message(
522754359Sroberto		    struct parseunit *parse,
522854359Sroberto		    parsetime_t      *parsetime
522954359Sroberto		    )
523054359Sroberto{
523154359Sroberto	unsigned char *buffer = parsetime->parse_msg;
523254359Sroberto	unsigned int   size   = parsetime->parse_msglen;
523354359Sroberto
523454359Sroberto	if ((size < 4) ||
523554359Sroberto	    (buffer[0]      != DLE) ||
523654359Sroberto	    (buffer[size-1] != ETX) ||
523754359Sroberto	    (buffer[size-2] != DLE))
523854359Sroberto	{
523954359Sroberto#ifdef DEBUG
524054359Sroberto		if (debug > 2) {
524154359Sroberto			int i;
524254359Sroberto
524354359Sroberto			printf("TRIMBLE BAD packet, size %d:\n	", size);
524454359Sroberto			for (i = 0; i < size; i++) {
524554359Sroberto				printf ("%2.2x, ", buffer[i]&0xff);
524654359Sroberto				if (i%16 == 15) printf("\n\t");
524754359Sroberto			}
524854359Sroberto			printf("\n");
524954359Sroberto		}
525054359Sroberto#endif
525154359Sroberto		return;
525254359Sroberto	}
525354359Sroberto	else
525454359Sroberto	{
525554359Sroberto		int var_flag;
525654359Sroberto		trimble_t *tr = parse->localdata;
525754359Sroberto		unsigned int cmd = buffer[1];
525854359Sroberto		char pbuffer[200];
525954359Sroberto		char *t = pbuffer;
526054359Sroberto		cmd_info_t *s;
526154359Sroberto
526254359Sroberto#ifdef DEBUG
526354359Sroberto		if (debug > 3) {
526454359Sroberto			int i;
526554359Sroberto
526654359Sroberto			printf("TRIMBLE packet 0x%02x, size %d:\n	", cmd, size);
526754359Sroberto			for (i = 0; i < size; i++) {
526854359Sroberto				printf ("%2.2x, ", buffer[i]&0xff);
526954359Sroberto				if (i%16 == 15) printf("\n\t");
527054359Sroberto			}
527154359Sroberto			printf("\n");
527254359Sroberto		}
527354359Sroberto#endif
527454359Sroberto
527554359Sroberto		if (tr)
527654359Sroberto			tr->last_msg = current_time;
527754359Sroberto
527854359Sroberto		s = trimble_convert(cmd, trimble_rcmds);
527954359Sroberto
528054359Sroberto		if (s)
528154359Sroberto		{
5282182007Sroberto			snprintf(t, BUFFER_SIZE(pbuffer, t), "%s=\"", s->varname);
528354359Sroberto		}
528454359Sroberto		else
528554359Sroberto		{
5286182007Sroberto			DPRINTF(1, ("TRIMBLE UNKNOWN COMMAND 0x%02x\n", cmd));
528754359Sroberto			return;
528854359Sroberto		}
528954359Sroberto
529054359Sroberto		var_flag = s->varmode;
529154359Sroberto
529254359Sroberto		t += strlen(t);
529354359Sroberto
529454359Sroberto		switch(cmd)
529554359Sroberto		{
529654359Sroberto		case CMD_RCURTIME:
5297182007Sroberto			snprintf(t, BUFFER_SIZE(pbuffer, t), "%f, %d, %f",
5298182007Sroberto				 getflt((unsigned char *)&mb(0)), getshort((unsigned char *)&mb(4)),
5299182007Sroberto				 getflt((unsigned char *)&mb(6)));
530054359Sroberto			break;
530154359Sroberto
530254359Sroberto		case CMD_RBEST4:
5303182007Sroberto			strncpy(t, "mode: ", BUFFER_SIZE(pbuffer, t));
530454359Sroberto			t += strlen(t);
530554359Sroberto			switch (mb(0) & 0xF)
530654359Sroberto			{
530754359Sroberto			default:
5308182007Sroberto				snprintf(t, BUFFER_SIZE(pbuffer, t), "0x%x", mb(0) & 0x7);
530954359Sroberto				break;
531054359Sroberto
531154359Sroberto			case 1:
5312182007Sroberto				strncpy(t, "0D", BUFFER_SIZE(pbuffer, t));
531354359Sroberto				break;
531454359Sroberto
531554359Sroberto			case 3:
5316182007Sroberto				strncpy(t, "2D", BUFFER_SIZE(pbuffer, t));
531754359Sroberto				break;
531854359Sroberto
531954359Sroberto			case 4:
5320182007Sroberto				strncpy(t, "3D", BUFFER_SIZE(pbuffer, t));
532154359Sroberto				break;
532254359Sroberto			}
532354359Sroberto			t += strlen(t);
532454359Sroberto			if (mb(0) & 0x10)
5325182007Sroberto				strncpy(t, "-MANUAL, ", BUFFER_SIZE(pbuffer, t));
532654359Sroberto			else
5327182007Sroberto				strncpy(t, "-AUTO, ", BUFFER_SIZE(pbuffer, t));
532854359Sroberto			t += strlen(t);
532954359Sroberto
5330182007Sroberto			snprintf(t, BUFFER_SIZE(pbuffer, t), "satellites %02d %02d %02d %02d, PDOP %.2f, HDOP %.2f, VDOP %.2f, TDOP %.2f",
533154359Sroberto				mb(1), mb(2), mb(3), mb(4),
533254359Sroberto				getflt((unsigned char *)&mb(5)),
533354359Sroberto				getflt((unsigned char *)&mb(9)),
533454359Sroberto				getflt((unsigned char *)&mb(13)),
533554359Sroberto				getflt((unsigned char *)&mb(17)));
533654359Sroberto
533754359Sroberto			break;
533854359Sroberto
533954359Sroberto		case CMD_RVERSION:
5340182007Sroberto			snprintf(t, BUFFER_SIZE(pbuffer, t), "%d.%d (%d/%d/%d)",
534154359Sroberto				mb(0)&0xff, mb(1)&0xff, 1900+(mb(4)&0xff), mb(2)&0xff, mb(3)&0xff);
534254359Sroberto			break;
534354359Sroberto
534454359Sroberto		case CMD_RRECVHEALTH:
534554359Sroberto		{
534654359Sroberto			static const char *msgs[] =
534754359Sroberto			{
534854359Sroberto				"Battery backup failed",
534954359Sroberto				"Signal processor error",
535054359Sroberto				"Alignment error, channel or chip 1",
535154359Sroberto				"Alignment error, channel or chip 2",
535254359Sroberto				"Antenna feed line fault",
535354359Sroberto				"Excessive ref freq. error",
535454359Sroberto				"<BIT 6>",
535554359Sroberto				"<BIT 7>"
535654359Sroberto			};
535754359Sroberto
535854359Sroberto			int i, bits;
535954359Sroberto
536054359Sroberto			switch (mb(0) & 0xFF)
536154359Sroberto			{
536254359Sroberto			default:
5363182007Sroberto				snprintf(t, BUFFER_SIZE(pbuffer, t), "illegal value 0x%02x", mb(0) & 0xFF);
536454359Sroberto				break;
536554359Sroberto			case 0x00:
5366182007Sroberto				strncpy(t, "doing position fixes", BUFFER_SIZE(pbuffer, t));
536754359Sroberto				break;
536854359Sroberto			case 0x01:
5369182007Sroberto				strncpy(t, "no GPS time yet", BUFFER_SIZE(pbuffer, t));
537054359Sroberto				break;
537154359Sroberto			case 0x03:
5372182007Sroberto				strncpy(t, "PDOP too high", BUFFER_SIZE(pbuffer, t));
537354359Sroberto				break;
537454359Sroberto			case 0x08:
5375182007Sroberto				strncpy(t, "no usable satellites", BUFFER_SIZE(pbuffer, t));
537654359Sroberto				break;
537754359Sroberto			case 0x09:
5378182007Sroberto				strncpy(t, "only ONE usable satellite", BUFFER_SIZE(pbuffer, t));
537954359Sroberto				break;
538054359Sroberto			case 0x0A:
5381182007Sroberto				strncpy(t, "only TWO usable satellites", BUFFER_SIZE(pbuffer, t));
538254359Sroberto				break;
538354359Sroberto			case 0x0B:
5384182007Sroberto				strncpy(t, "only THREE usable satellites", BUFFER_SIZE(pbuffer, t));
538554359Sroberto				break;
538654359Sroberto			case 0x0C:
5387182007Sroberto				strncpy(t, "the chosen satellite is unusable", BUFFER_SIZE(pbuffer, t));
538854359Sroberto				break;
538954359Sroberto			}
539054359Sroberto
539154359Sroberto			t += strlen(t);
539254359Sroberto
539354359Sroberto			bits = mb(1) & 0xFF;
539454359Sroberto
539554359Sroberto			for (i = 0; i < 8; i++)
539654359Sroberto				if (bits & (0x1<<i))
539754359Sroberto				{
5398182007Sroberto					snprintf(t, BUFFER_SIZE(pbuffer, t), ", %s", msgs[i]);
539954359Sroberto					t += strlen(t);
540054359Sroberto				}
540154359Sroberto		}
540254359Sroberto		break;
540354359Sroberto
540454359Sroberto		case CMD_RMESSAGE:
5405182007Sroberto			mkreadable(t, (int)BUFFER_SIZE(pbuffer, t), (char *)&mb(0), (unsigned)(size - 2 - (&mb(0) - buffer)), 0);
540654359Sroberto			break;
540754359Sroberto
540854359Sroberto		case CMD_RMACHSTAT:
540954359Sroberto		{
541054359Sroberto			static const char *msgs[] =
541154359Sroberto			{
541254359Sroberto				"Synthesizer Fault",
541354359Sroberto				"Battery Powered Time Clock Fault",
541454359Sroberto				"A-to-D Converter Fault",
541554359Sroberto				"The almanac stored in the receiver is not complete and current",
541654359Sroberto				"<BIT 4>",
541754359Sroberto				"<BIT 5",
541854359Sroberto				"<BIT 6>",
541954359Sroberto				"<BIT 7>"
542054359Sroberto			};
542154359Sroberto
542254359Sroberto			int i, bits;
542354359Sroberto
5424182007Sroberto			snprintf(t, BUFFER_SIZE(pbuffer, t), "machine id 0x%02x", mb(0) & 0xFF);
542554359Sroberto			t += strlen(t);
542654359Sroberto
542754359Sroberto			bits = mb(1) & 0xFF;
542854359Sroberto
542954359Sroberto			for (i = 0; i < 8; i++)
543054359Sroberto				if (bits & (0x1<<i))
543154359Sroberto				{
5432182007Sroberto					snprintf(t, BUFFER_SIZE(pbuffer, t), ", %s", msgs[i]);
543354359Sroberto					t += strlen(t);
543454359Sroberto				}
543554359Sroberto
5436182007Sroberto			snprintf(t, BUFFER_SIZE(pbuffer, t), ", Superpackets %ssupported", (mb(2) & 0xFF) ? "" :"un" );
543754359Sroberto		}
543854359Sroberto		break;
543954359Sroberto
544054359Sroberto		case CMD_ROPERPARAM:
5441182007Sroberto			snprintf(t, BUFFER_SIZE(pbuffer, t), "%2x %.1f %.1f %.1f %.1f",
544254359Sroberto				mb(0), getflt((unsigned char *)&mb(1)), getflt((unsigned char *)&mb(5)),
544354359Sroberto				getflt((unsigned char *)&mb(9)), getflt((unsigned char *)&mb(13)));
544454359Sroberto			break;
544554359Sroberto
544654359Sroberto		case CMD_RUTCPARAM:
544754359Sroberto		{
544854359Sroberto			float t0t = getflt((unsigned char *)&mb(14));
544954359Sroberto			short wnt = getshort((unsigned char *)&mb(18));
545054359Sroberto			short dtls = getshort((unsigned char *)&mb(12));
545154359Sroberto			short wnlsf = getshort((unsigned char *)&mb(20));
545254359Sroberto			short dn = getshort((unsigned char *)&mb(22));
545354359Sroberto			short dtlsf = getshort((unsigned char *)&mb(24));
545454359Sroberto
545554359Sroberto			if ((int)t0t != 0)
545654359Sroberto			  {
5457182007Sroberto				  mk_utcinfo(t, wnt, wnlsf, dn, dtls, dtlsf, BUFFER_SIZE(pbuffer, t));
545854359Sroberto			  }
545954359Sroberto			else
546054359Sroberto			  {
5461182007Sroberto			    strncpy(t, "<NO UTC DATA>", BUFFER_SIZE(pbuffer, t));
546254359Sroberto			  }
546354359Sroberto		}
546454359Sroberto		break;
546554359Sroberto
546654359Sroberto		case CMD_RSAT1BIAS:
5467182007Sroberto			snprintf(t, BUFFER_SIZE(pbuffer, t), "%.1fm %.2fm/s at %.1fs",
546854359Sroberto				getflt(&mb(0)), getflt(&mb(4)), getflt(&mb(8)));
546954359Sroberto			break;
547054359Sroberto
547154359Sroberto		case CMD_RIOOPTIONS:
547254359Sroberto		{
5473182007Sroberto			snprintf(t, BUFFER_SIZE(pbuffer, t), "%02x %02x %02x %02x",
547454359Sroberto				mb(0), mb(1), mb(2), mb(3));
547554359Sroberto			if (mb(0) != TRIM_POS_OPT ||
547654359Sroberto			    mb(2) != TRIM_TIME_OPT)
547754359Sroberto			{
547854359Sroberto				(void)trimbletsip_setup(parse, "bad io options");
547954359Sroberto			}
548054359Sroberto		}
548154359Sroberto		break;
548254359Sroberto
548354359Sroberto		case CMD_RSPOSXYZ:
548454359Sroberto		{
548554359Sroberto			double x = getflt((unsigned char *)&mb(0));
548654359Sroberto			double y = getflt((unsigned char *)&mb(4));
548754359Sroberto			double z = getflt((unsigned char *)&mb(8));
548854359Sroberto			double f = getflt((unsigned char *)&mb(12));
548954359Sroberto
549054359Sroberto			if (f > 0.0)
5491182007Sroberto			  snprintf(t, BUFFER_SIZE(pbuffer, t), "x= %.1fm, y= %.1fm, z= %.1fm, time_of_fix= %f sec",
549254359Sroberto				  x, y, z,
549354359Sroberto				  f);
549454359Sroberto			else
549554359Sroberto			  return;
549654359Sroberto		}
549754359Sroberto		break;
549854359Sroberto
549954359Sroberto		case CMD_RSLLAPOS:
550054359Sroberto		{
550154359Sroberto			double lat = getflt((unsigned char *)&mb(0));
550254359Sroberto			double lng = getflt((unsigned char *)&mb(4));
550354359Sroberto			double f   = getflt((unsigned char *)&mb(12));
550454359Sroberto
550554359Sroberto			if (f > 0.0)
5506182007Sroberto			  snprintf(t, BUFFER_SIZE(pbuffer, t), "lat %f %c, long %f %c, alt %.2fm",
550754359Sroberto				  ((lat < 0.0) ? (-lat) : (lat))*RTOD, (lat < 0.0 ? 'S' : 'N'),
550854359Sroberto				  ((lng < 0.0) ? (-lng) : (lng))*RTOD, (lng < 0.0 ? 'W' : 'E'),
550954359Sroberto				  getflt((unsigned char *)&mb(8)));
551054359Sroberto			else
551154359Sroberto			  return;
551254359Sroberto		}
551354359Sroberto		break;
551454359Sroberto
551554359Sroberto		case CMD_RDOUBLEXYZ:
551654359Sroberto		{
551754359Sroberto			double x = getdbl((unsigned char *)&mb(0));
551854359Sroberto			double y = getdbl((unsigned char *)&mb(8));
551954359Sroberto			double z = getdbl((unsigned char *)&mb(16));
5520182007Sroberto			snprintf(t, BUFFER_SIZE(pbuffer, t), "x= %.1fm, y= %.1fm, z= %.1fm",
552154359Sroberto				x, y, z);
552254359Sroberto		}
552354359Sroberto		break;
552454359Sroberto
552554359Sroberto		case CMD_RDOUBLELLA:
552654359Sroberto		{
552754359Sroberto			double lat = getdbl((unsigned char *)&mb(0));
552854359Sroberto			double lng = getdbl((unsigned char *)&mb(8));
5529182007Sroberto			snprintf(t, BUFFER_SIZE(pbuffer, t), "lat %f %c, lon %f %c, alt %.2fm",
553054359Sroberto				((lat < 0.0) ? (-lat) : (lat))*RTOD, (lat < 0.0 ? 'S' : 'N'),
553154359Sroberto				((lng < 0.0) ? (-lng) : (lng))*RTOD, (lng < 0.0 ? 'W' : 'E'),
553254359Sroberto				getdbl((unsigned char *)&mb(16)));
553354359Sroberto		}
553454359Sroberto		break;
553554359Sroberto
553654359Sroberto		case CMD_RALLINVIEW:
553754359Sroberto		{
553854359Sroberto			int i, sats;
553954359Sroberto
5540182007Sroberto			strncpy(t, "mode: ", BUFFER_SIZE(pbuffer, t));
554154359Sroberto			t += strlen(t);
554254359Sroberto			switch (mb(0) & 0x7)
554354359Sroberto			{
554454359Sroberto			default:
5545182007Sroberto				snprintf(t, BUFFER_SIZE(pbuffer, t), "0x%x", mb(0) & 0x7);
554654359Sroberto				break;
554754359Sroberto
554854359Sroberto			case 3:
5549182007Sroberto				strncpy(t, "2D", BUFFER_SIZE(pbuffer, t));
555054359Sroberto				break;
555154359Sroberto
555254359Sroberto			case 4:
5553182007Sroberto				strncpy(t, "3D", BUFFER_SIZE(pbuffer, t));
555454359Sroberto				break;
555554359Sroberto			}
555654359Sroberto			t += strlen(t);
555754359Sroberto			if (mb(0) & 0x8)
5558182007Sroberto				strncpy(t, "-MANUAL, ", BUFFER_SIZE(pbuffer, t));
555954359Sroberto			else
5560182007Sroberto				strncpy(t, "-AUTO, ", BUFFER_SIZE(pbuffer, t));
556154359Sroberto			t += strlen(t);
556254359Sroberto
556354359Sroberto			sats = (mb(0)>>4) & 0xF;
556454359Sroberto
5565182007Sroberto			snprintf(t, BUFFER_SIZE(pbuffer, t), "PDOP %.2f, HDOP %.2f, VDOP %.2f, TDOP %.2f, %d satellite%s in view: ",
556654359Sroberto				getflt((unsigned char *)&mb(1)),
556754359Sroberto				getflt((unsigned char *)&mb(5)),
556854359Sroberto				getflt((unsigned char *)&mb(9)),
556954359Sroberto				getflt((unsigned char *)&mb(13)),
557054359Sroberto				sats, (sats == 1) ? "" : "s");
557154359Sroberto			t += strlen(t);
557254359Sroberto
557354359Sroberto			for (i=0; i < sats; i++)
557454359Sroberto			{
5575182007Sroberto				snprintf(t, BUFFER_SIZE(pbuffer, t), "%s%02d", i ? ", " : "", mb(17+i));
557654359Sroberto				t += strlen(t);
557754359Sroberto				if (tr)
557854359Sroberto					tr->ctrack |= (1 << (mb(17+i)-1));
557954359Sroberto			}
558054359Sroberto
558154359Sroberto			if (tr)
558254359Sroberto                        { /* mark for tracking status query */
558354359Sroberto				tr->qtracking = 1;
558454359Sroberto			}
558554359Sroberto		}
558654359Sroberto		break;
558754359Sroberto
558854359Sroberto		case CMD_RSTATTRACK:
558954359Sroberto		{
5590182007Sroberto			snprintf(t-2, BUFFER_SIZE(pbuffer, t-2), "[%02d]=\"", mb(0)); /* add index to var name */
559154359Sroberto			t += strlen(t);
559254359Sroberto
559354359Sroberto			if (getflt((unsigned char *)&mb(4)) < 0.0)
559454359Sroberto			{
5595182007Sroberto				strncpy(t, "<NO MEASUREMENTS>", BUFFER_SIZE(pbuffer, t));
559654359Sroberto				var_flag &= ~DEF;
559754359Sroberto			}
559854359Sroberto			else
559954359Sroberto			{
5600182007Sroberto				snprintf(t, BUFFER_SIZE(pbuffer, t), "ch=%d, acq=%s, eph=%d, signal_level= %5.2f, elevation= %5.2f, azimuth= %6.2f",
560154359Sroberto					(mb(1) & 0xFF)>>3,
560254359Sroberto					mb(2) ? ((mb(2) == 1) ? "ACQ" : "SRCH") : "NEVER",
560354359Sroberto					mb(3),
560454359Sroberto					getflt((unsigned char *)&mb(4)),
560554359Sroberto					getflt((unsigned char *)&mb(12)) * RTOD,
560654359Sroberto					getflt((unsigned char *)&mb(16)) * RTOD);
560754359Sroberto				t += strlen(t);
560854359Sroberto				if (mb(20))
560954359Sroberto				{
561054359Sroberto					var_flag &= ~DEF;
5611182007Sroberto					strncpy(t, ", OLD", BUFFER_SIZE(pbuffer, t));
561254359Sroberto				}
561354359Sroberto				t += strlen(t);
561454359Sroberto				if (mb(22))
561554359Sroberto				{
561654359Sroberto					if (mb(22) == 1)
5617182007Sroberto						strncpy(t, ", BAD PARITY", BUFFER_SIZE(pbuffer, t));
561854359Sroberto					else
561954359Sroberto						if (mb(22) == 2)
5620182007Sroberto							strncpy(t, ", BAD EPH HEALTH", BUFFER_SIZE(pbuffer, t));
562154359Sroberto				}
562254359Sroberto				t += strlen(t);
562354359Sroberto				if (mb(23))
5624182007Sroberto					strncpy(t, ", collecting data", BUFFER_SIZE(pbuffer, t));
562554359Sroberto			}
562654359Sroberto		}
562754359Sroberto		break;
562854359Sroberto
562954359Sroberto		default:
5630182007Sroberto			strncpy(t, "<UNDECODED>", BUFFER_SIZE(pbuffer, t));
563154359Sroberto			break;
563254359Sroberto		}
5633182007Sroberto		t += strlen(t);
5634182007Sroberto
5635182007Sroberto		strncpy(t,"\"", BUFFER_SIZE(pbuffer, t));
563654359Sroberto		set_var(&parse->kv, pbuffer, sizeof(pbuffer), var_flag);
563754359Sroberto	}
563854359Sroberto}
563954359Sroberto
564054359Sroberto
564154359Sroberto/**============================================================
564254359Sroberto ** RAWDCF support
564354359Sroberto **/
564454359Sroberto
564554359Sroberto/*--------------------------------------------------
564656746Sroberto * rawdcf_init_1 - set up modem lines for RAWDCF receivers
564756746Sroberto * SET DTR line
564854359Sroberto */
564954359Sroberto#if defined(TIOCMSET) && (defined(TIOCM_DTR) || defined(CIOCM_DTR))
565054359Srobertostatic int
565156746Srobertorawdcf_init_1(
565254359Sroberto	struct parseunit *parse
565354359Sroberto	)
565454359Sroberto{
565582498Sroberto	/* fixed 2000 for using with Linux by Wolfram Pienkoss <wp@bszh.de> */
565654359Sroberto	/*
565754359Sroberto	 * You can use the RS232 to supply the power for a DCF77 receiver.
565854359Sroberto	 * Here a voltage between the DTR and the RTS line is used. Unfortunately
565954359Sroberto	 * the name has changed from CIOCM_DTR to TIOCM_DTR recently.
566054359Sroberto	 */
566182498Sroberto	int sl232;
566282498Sroberto
566382498Sroberto	if (ioctl(parse->generic->io.fd, TIOCMGET, (caddr_t)&sl232) == -1)
566482498Sroberto	{
566582498Sroberto		msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_1: WARNING: ioctl(fd, TIOCMGET, [C|T]IOCM_DTR): %m", CLK_UNIT(parse->peer));
566682498Sroberto		return 0;
566782498Sroberto	}
566882498Sroberto
566954359Sroberto#ifdef TIOCM_DTR
567082498Sroberto	sl232 = (sl232 & ~TIOCM_RTS) | TIOCM_DTR;	/* turn on DTR, clear RTS for power supply */
567154359Sroberto#else
567282498Sroberto	sl232 = (sl232 & ~CIOCM_RTS) | CIOCM_DTR;	/* turn on DTR, clear RTS for power supply */
567354359Sroberto#endif
567454359Sroberto
567554359Sroberto	if (ioctl(parse->generic->io.fd, TIOCMSET, (caddr_t)&sl232) == -1)
567654359Sroberto	{
567756746Sroberto		msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_1: WARNING: ioctl(fd, TIOCMSET, [C|T]IOCM_DTR): %m", CLK_UNIT(parse->peer));
567854359Sroberto	}
567954359Sroberto	return 0;
568054359Sroberto}
568154359Sroberto#else
568254359Srobertostatic int
5683132451Srobertorawdcfdtr_init_1(
568454359Sroberto	struct parseunit *parse
568554359Sroberto	)
568654359Sroberto{
568756746Sroberto	msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_1: WARNING: OS interface incapable of setting DTR to power DCF modules", CLK_UNIT(parse->peer));
568854359Sroberto	return 0;
568954359Sroberto}
569054359Sroberto#endif  /* DTR initialisation type */
569154359Sroberto
569254359Sroberto/*--------------------------------------------------
569356746Sroberto * rawdcf_init_2 - set up modem lines for RAWDCF receivers
569456746Sroberto * CLR DTR line, SET RTS line
569554359Sroberto */
569656746Sroberto#if defined(TIOCMSET) &&  (defined(TIOCM_RTS) || defined(CIOCM_RTS))
569754359Srobertostatic int
569856746Srobertorawdcf_init_2(
569954359Sroberto	struct parseunit *parse
570054359Sroberto	)
570154359Sroberto{
570282498Sroberto	/* fixed 2000 for using with Linux by Wolfram Pienkoss <wp@bszh.de> */
570354359Sroberto	/*
570454359Sroberto	 * You can use the RS232 to supply the power for a DCF77 receiver.
570556746Sroberto	 * Here a voltage between the DTR and the RTS line is used. Unfortunately
570656746Sroberto	 * the name has changed from CIOCM_DTR to TIOCM_DTR recently.
570754359Sroberto	 */
570882498Sroberto	int sl232;
570982498Sroberto
571082498Sroberto	if (ioctl(parse->generic->io.fd, TIOCMGET, (caddr_t)&sl232) == -1)
571182498Sroberto	{
571282498Sroberto		msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_2: WARNING: ioctl(fd, TIOCMGET, [C|T]IOCM_RTS): %m", CLK_UNIT(parse->peer));
571382498Sroberto		return 0;
571482498Sroberto	}
571582498Sroberto
571654359Sroberto#ifdef TIOCM_RTS
571782498Sroberto	sl232 = (sl232 & ~TIOCM_DTR) | TIOCM_RTS;	/* turn on RTS, clear DTR for power supply */
571854359Sroberto#else
571982498Sroberto	sl232 = (sl232 & ~CIOCM_DTR) | CIOCM_RTS;	/* turn on RTS, clear DTR for power supply */
572054359Sroberto#endif
572154359Sroberto
572254359Sroberto	if (ioctl(parse->generic->io.fd, TIOCMSET, (caddr_t)&sl232) == -1)
572354359Sroberto	{
572456746Sroberto		msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_2: WARNING: ioctl(fd, TIOCMSET, [C|T]IOCM_RTS): %m", CLK_UNIT(parse->peer));
572554359Sroberto	}
572654359Sroberto	return 0;
572754359Sroberto}
572854359Sroberto#else
572954359Srobertostatic int
573056746Srobertorawdcf_init_2(
573154359Sroberto	struct parseunit *parse
573254359Sroberto	)
573354359Sroberto{
573456746Sroberto	msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_2: WARNING: OS interface incapable of setting RTS to power DCF modules", CLK_UNIT(parse->peer));
573554359Sroberto	return 0;
573654359Sroberto}
573756746Sroberto#endif  /* DTR initialisation type */
573854359Sroberto
573954359Sroberto#else	/* defined(REFCLOCK) && defined(PARSE) */
574054359Srobertoint refclock_parse_bs;
574154359Sroberto#endif	/* defined(REFCLOCK) && defined(PARSE) */
574254359Sroberto
574354359Sroberto/*
574454359Sroberto * History:
574554359Sroberto *
574654359Sroberto * refclock_parse.c,v
5747182007Sroberto * Revision 4.80  2007/08/11 12:06:29  kardel
5748182007Sroberto * update comments wrt/ to PPS
5749182007Sroberto *
5750182007Sroberto * Revision 4.79  2007/08/11 11:52:23  kardel
5751182007Sroberto * - terminate io bindings before io_closeclock() will close our file descriptor
5752182007Sroberto *
5753182007Sroberto * Revision 4.78  2006/12/22 20:08:27  kardel
5754182007Sroberto * Bug 746 (RFE): add configuration for Expert mouseCLOCK USB v2.0 as mode 19
5755182007Sroberto *
5756182007Sroberto * Revision 4.77  2006/08/05 07:44:49  kardel
5757182007Sroberto * support optionally separate PPS devices via /dev/refclockpps-{0..3}
5758182007Sroberto *
5759182007Sroberto * Revision 4.76  2006/06/22 18:40:47  kardel
5760182007Sroberto * clean up signedness (gcc 4)
5761182007Sroberto *
5762182007Sroberto * Revision 4.75  2006/06/22 16:58:10  kardel
5763182007Sroberto * Bug #632: call parse_ppsapi() in parse_ctl() when updating
5764182007Sroberto * the PPS offset. Fix sign of offset passed to kernel.
5765182007Sroberto *
5766182007Sroberto * Revision 4.74  2006/06/18 21:18:37  kardel
5767182007Sroberto * NetBSD Coverity CID 3796: possible NULL deref
5768182007Sroberto *
5769182007Sroberto * Revision 4.73  2006/05/26 14:23:46  kardel
5770182007Sroberto * cleanup of copyright info
5771182007Sroberto *
5772182007Sroberto * Revision 4.72  2006/05/26 14:19:43  kardel
5773182007Sroberto * cleanup of ioctl cruft
5774182007Sroberto *
5775182007Sroberto * Revision 4.71  2006/05/26 14:15:57  kardel
5776182007Sroberto * delay adding refclock to async refclock io after all initializations
5777182007Sroberto *
5778182007Sroberto * Revision 4.70  2006/05/25 18:20:50  kardel
5779182007Sroberto * bug #619
5780182007Sroberto * terminate parse io engine after de-registering
5781182007Sroberto * from refclock io engine
5782182007Sroberto *
5783182007Sroberto * Revision 4.69  2006/05/25 17:28:02  kardel
5784182007Sroberto * complete refclock io structure initialization *before* inserting it into the
5785182007Sroberto * refclock input machine (avoids null pointer deref) (bug #619)
5786182007Sroberto *
5787182007Sroberto * Revision 4.68  2006/05/01 17:02:51  kardel
5788182007Sroberto * copy receiver method also for newlwy created receive buffers
5789182007Sroberto *
5790182007Sroberto * Revision 4.67  2006/05/01 14:37:29  kardel
5791182007Sroberto * If an input buffer parses into more than one message do insert the
5792182007Sroberto * parsed message in a new input buffer instead of processing it
5793182007Sroberto * directly. This avoids deed complicated processing in signal
5794182007Sroberto * handling.
5795182007Sroberto *
5796182007Sroberto * Revision 4.66  2006/03/18 00:45:30  kardel
5797182007Sroberto * coverity fixes found in NetBSD coverity scan
5798182007Sroberto *
5799182007Sroberto * Revision 4.65  2006/01/26 06:08:33  kardel
5800182007Sroberto * output errno on PPS setup failure
5801182007Sroberto *
5802182007Sroberto * Revision 4.64  2005/11/09 20:44:47  kardel
5803182007Sroberto * utilize full PPS timestamp resolution from PPS API
5804182007Sroberto *
5805182007Sroberto * Revision 4.63  2005/10/07 22:10:25  kardel
5806182007Sroberto * bounded buffer implementation
5807182007Sroberto *
5808182007Sroberto * Revision 4.62.2.2  2005/09/25 10:20:16  kardel
5809182007Sroberto * avoid unexpected buffer overflows due to sprintf("%f") on strange floats:
5810182007Sroberto * replace almost all str* and *printf functions be their buffer bounded
5811182007Sroberto * counterparts
5812182007Sroberto *
5813182007Sroberto * Revision 4.62.2.1  2005/08/27 16:19:27  kardel
5814182007Sroberto * limit re-set rate of trimble clocks
5815182007Sroberto *
5816182007Sroberto * Revision 4.62  2005/08/06 17:40:00  kardel
5817182007Sroberto * cleanup size handling wrt/ to buffer boundaries
5818182007Sroberto *
5819182007Sroberto * Revision 4.61  2005/07/27 21:16:19  kardel
5820182007Sroberto * fix a long (> 11 years) misconfiguration wrt/ Meinberg cflag factory
5821182007Sroberto * default setup. CSTOPB was missing for the 7E2 default data format of
5822182007Sroberto * the DCF77 clocks.
5823182007Sroberto *
5824182007Sroberto * Revision 4.60  2005/07/17 21:14:44  kardel
5825182007Sroberto * change contents of version string to include the RCS/CVS Id
5826182007Sroberto *
5827182007Sroberto * Revision 4.59  2005/07/06 06:56:38  kardel
5828182007Sroberto * syntax error
5829182007Sroberto *
5830182007Sroberto * Revision 4.58  2005/07/04 13:10:40  kardel
5831182007Sroberto * fix bug 455: tripping over NULL pointer on cleanup
5832182007Sroberto * fix shadow storage logic for ppsphaseadjust and trustime wrt/ time2
5833182007Sroberto * fix compiler warnings for some platforms wrt/ printf formatstrings and
5834182007Sroberto *     varying structure element sizes
5835182007Sroberto * reorder assignment in binding to avoid tripping over NULL pointers
5836182007Sroberto *
5837182007Sroberto * Revision 4.57  2005/06/25 09:25:19  kardel
5838182007Sroberto * sort out log output sequence
5839182007Sroberto *
5840182007Sroberto * Revision 4.56  2005/06/14 21:47:27  kardel
5841182007Sroberto * collect samples only if samples are ok (sync or trusted flywheel)
5842182007Sroberto * propagate pps phase adjustment value to kernel via PPSAPI to help HARDPPS
5843182007Sroberto * en- and dis-able HARDPPS in correlation to receiver sync state
5844182007Sroberto *
5845182007Sroberto * Revision 4.55  2005/06/02 21:28:31  kardel
5846182007Sroberto * clarify trust logic
5847182007Sroberto *
5848182007Sroberto * Revision 4.54  2005/06/02 17:06:49  kardel
5849182007Sroberto * change status reporting to use fixed refclock_report()
5850182007Sroberto *
5851182007Sroberto * Revision 4.53  2005/06/02 16:33:31  kardel
5852182007Sroberto * fix acceptance of clocks unsync clocks right at start
5853182007Sroberto *
5854182007Sroberto * Revision 4.52  2005/05/26 21:55:06  kardel
5855182007Sroberto * cleanup status reporting
5856182007Sroberto *
5857182007Sroberto * Revision 4.51  2005/05/26 19:19:14  kardel
5858182007Sroberto * implement fast refclock startup
5859182007Sroberto *
5860182007Sroberto * Revision 4.50  2005/04/16 20:51:35  kardel
5861182007Sroberto * set pps_enable = 1 when binding a kernel PPS source
5862182007Sroberto *
5863182007Sroberto * Revision 4.49  2005/04/16 17:29:26  kardel
5864182007Sroberto * add non polling clock type 18 for just listenning to Meinberg clocks
5865182007Sroberto *
5866182007Sroberto * Revision 4.48  2005/04/16 16:22:27  kardel
5867182007Sroberto * bk sync 20050415 ntp-dev
5868182007Sroberto *
5869182007Sroberto * Revision 4.47  2004/11/29 10:42:48  kardel
5870182007Sroberto * bk sync ntp-dev 20041129
5871182007Sroberto *
5872182007Sroberto * Revision 4.46  2004/11/29 10:26:29  kardel
5873182007Sroberto * keep fudgetime2 in sync with trusttime/ppsphaseadjust depending in flag1
5874182007Sroberto *
5875182007Sroberto * Revision 4.45  2004/11/14 20:53:20  kardel
5876182007Sroberto * clear PPS flags after using them
5877182007Sroberto *
5878182007Sroberto * Revision 4.44  2004/11/14 15:29:41  kardel
5879182007Sroberto * support PPSAPI, upgrade Copyright to Berkeley style
5880182007Sroberto *
5881182007Sroberto * Revision 4.43  2001/05/26 22:53:16  kardel
5882182007Sroberto * 20010526 reconcilation
5883182007Sroberto *
5884182007Sroberto * Revision 4.42  2000/05/14 15:31:51  kardel
5885182007Sroberto * PPSAPI && RAWDCF modemline support
5886182007Sroberto *
5887182007Sroberto * Revision 4.41  2000/04/09 19:50:45  kardel
5888182007Sroberto * fixed rawdcfdtr_init() -> rawdcf_init_1
5889182007Sroberto *
5890182007Sroberto * Revision 4.40  2000/04/09 15:27:55  kardel
5891182007Sroberto * modem line fiddle in rawdcf_init_2
5892182007Sroberto *
5893182007Sroberto * Revision 4.39  2000/03/18 09:16:55  kardel
5894182007Sroberto * PPSAPI integration
5895182007Sroberto *
5896182007Sroberto * Revision 4.38  2000/03/05 20:25:06  kardel
5897182007Sroberto * support PPSAPI
5898182007Sroberto *
5899182007Sroberto * Revision 4.37  2000/03/05 20:11:14  kardel
5900182007Sroberto * 4.0.99g reconcilation
5901182007Sroberto *
590256746Sroberto * Revision 4.36  1999/11/28 17:18:20  kardel
590356746Sroberto * disabled burst mode
590456746Sroberto *
590556746Sroberto * Revision 4.35  1999/11/28 09:14:14  kardel
590656746Sroberto * RECON_4_0_98F
590756746Sroberto *
590856746Sroberto * Revision 4.34  1999/05/14 06:08:05  kardel
590956746Sroberto * store current_time in a suitable container (u_long)
591056746Sroberto *
591156746Sroberto * Revision 4.33  1999/05/13 21:48:38  kardel
591256746Sroberto * double the no response timeout interval
591356746Sroberto *
591456746Sroberto * Revision 4.32  1999/05/13 20:09:13  kardel
591556746Sroberto * complain only about missing polls after a full poll interval
591656746Sroberto *
591756746Sroberto * Revision 4.31  1999/05/13 19:59:32  kardel
591856746Sroberto * add clock type 16 for RTS set DTR clr in RAWDCF
591956746Sroberto *
592056746Sroberto * Revision 4.30  1999/02/28 20:36:43  kardel
592156746Sroberto * fixed printf fmt
592256746Sroberto *
592354359Sroberto * Revision 4.29  1999/02/28 19:58:23  kardel
592454359Sroberto * updated copyright information
592554359Sroberto *
592654359Sroberto * Revision 4.28  1999/02/28 19:01:50  kardel
592754359Sroberto * improved debug out on sent Meinberg messages
592854359Sroberto *
592954359Sroberto * Revision 4.27  1999/02/28 18:05:55  kardel
593054359Sroberto * no linux/ppsclock.h stuff
593154359Sroberto *
593254359Sroberto * Revision 4.26  1999/02/28 15:27:27  kardel
593354359Sroberto * wharton clock integration
593454359Sroberto *
593554359Sroberto * Revision 4.25  1999/02/28 14:04:46  kardel
593654359Sroberto * added missing double quotes to UTC information string
593754359Sroberto *
593854359Sroberto * Revision 4.24  1999/02/28 12:06:50  kardel
593954359Sroberto * (parse_control): using gmprettydate instead of prettydate()
594054359Sroberto * (mk_utcinfo): new function for formatting GPS derived UTC information
594154359Sroberto * (gps16x_message): changed to use mk_utcinfo()
594254359Sroberto * (trimbletsip_message): changed to use mk_utcinfo()
594354359Sroberto * ignoring position information in unsynchronized mode
594454359Sroberto * (parse_start): augument linux support for optional ASYNC_LOW_LATENCY
594554359Sroberto *
594654359Sroberto * Revision 4.23  1999/02/23 19:47:53  kardel
594754359Sroberto * fixed #endifs
594854359Sroberto * (stream_receive): fixed formats
594954359Sroberto *
595054359Sroberto * Revision 4.22  1999/02/22 06:21:02  kardel
595154359Sroberto * use new autoconfig symbols
595254359Sroberto *
595354359Sroberto * Revision 4.21  1999/02/21 12:18:13  kardel
595454359Sroberto * 4.91f reconcilation
595554359Sroberto *
595654359Sroberto * Revision 4.20  1999/02/21 10:53:36  kardel
595754359Sroberto * initial Linux PPSkit version
595854359Sroberto *
595954359Sroberto * Revision 4.19  1999/02/07 09:10:45  kardel
596054359Sroberto * clarify STREAMS mitigation rules in comment
596154359Sroberto *
596254359Sroberto * Revision 4.18  1998/12/20 23:45:34  kardel
596354359Sroberto * fix types and warnings
596454359Sroberto *
596554359Sroberto * Revision 4.17  1998/11/15 21:24:51  kardel
596654359Sroberto * cannot access mbg_ routines when CLOCK_MEINBERG
596754359Sroberto * is not defined
596854359Sroberto *
596954359Sroberto * Revision 4.16  1998/11/15 20:28:17  kardel
597054359Sroberto * Release 4.0.73e13 reconcilation
597154359Sroberto *
597254359Sroberto * Revision 4.15  1998/08/22 21:56:08  kardel
597354359Sroberto * fixed IO handling for non-STREAM IO
597454359Sroberto *
597554359Sroberto * Revision 4.14  1998/08/16 19:00:48  kardel
597654359Sroberto * (gps16x_message): reduced UTC parameter information (dropped A0,A1)
597754359Sroberto * made uval a local variable (killed one of the last globals)
597854359Sroberto * (sendetx): added logging of messages when in debug mode
597954359Sroberto * (trimble_check): added periodic checks to facilitate re-initialization
598054359Sroberto * (trimbletsip_init): made use of EOL character if in non-kernel operation
598154359Sroberto * (trimbletsip_message): extended message interpretation
598254359Sroberto * (getdbl): fixed data conversion
598354359Sroberto *
598454359Sroberto * Revision 4.13  1998/08/09 22:29:13  kardel
598554359Sroberto * Trimble TSIP support
598654359Sroberto *
598754359Sroberto * Revision 4.12  1998/07/11 10:05:34  kardel
598854359Sroberto * Release 4.0.73d reconcilation
598954359Sroberto *
599054359Sroberto * Revision 4.11  1998/06/14 21:09:42  kardel
599154359Sroberto * Sun acc cleanup
599254359Sroberto *
599354359Sroberto * Revision 4.10  1998/06/13 12:36:45  kardel
599454359Sroberto * signed/unsigned, name clashes
599554359Sroberto *
599654359Sroberto * Revision 4.9  1998/06/12 15:30:00  kardel
599754359Sroberto * prototype fixes
599854359Sroberto *
599954359Sroberto * Revision 4.8  1998/06/12 11:19:42  kardel
600054359Sroberto * added direct input processing routine for refclocks in
600154359Sroberto * order to avaiod that single character io gobbles up all
600254359Sroberto * receive buffers and drops input data. (Problem started
600354359Sroberto * with fast machines so a character a buffer was possible
600454359Sroberto * one of the few cases where faster machines break existing
600554359Sroberto * allocation algorithms)
600654359Sroberto *
600754359Sroberto * Revision 4.7  1998/06/06 18:35:20  kardel
600854359Sroberto * (parse_start): added BURST mode initialisation
600954359Sroberto *
601054359Sroberto * Revision 4.6  1998/05/27 06:12:46  kardel
601154359Sroberto * RAWDCF_BASEDELAY default added
601254359Sroberto * old comment removed
601354359Sroberto * casts for ioctl()
601454359Sroberto *
601554359Sroberto * Revision 4.5  1998/05/25 22:05:09  kardel
601654359Sroberto * RAWDCF_SETDTR option removed
601754359Sroberto * clock type 14 attempts to set DTR for
601854359Sroberto * power supply of RAWDCF receivers
601954359Sroberto *
602054359Sroberto * Revision 4.4  1998/05/24 16:20:47  kardel
602154359Sroberto * updated comments referencing Meinberg clocks
602254359Sroberto * added RAWDCF clock with DTR set option as type 14
602354359Sroberto *
602454359Sroberto * Revision 4.3  1998/05/24 10:48:33  kardel
602554359Sroberto * calibrated CONRAD RAWDCF default fudge factor
602654359Sroberto *
602754359Sroberto * Revision 4.2  1998/05/24 09:59:35  kardel
602854359Sroberto * corrected version information (ntpq support)
602954359Sroberto *
603054359Sroberto * Revision 4.1  1998/05/24 09:52:31  kardel
603154359Sroberto * use fixed format only (new IO model)
603254359Sroberto * output debug to stdout instead of msyslog()
603354359Sroberto * don't include >"< in ASCII output in order not to confuse
603454359Sroberto * ntpq parsing
603554359Sroberto *
603654359Sroberto * Revision 4.0  1998/04/10 19:52:11  kardel
603754359Sroberto * Start 4.0 release version numbering
603854359Sroberto *
603954359Sroberto * Revision 1.2  1998/04/10 19:28:04  kardel
604054359Sroberto * initial NTP VERSION 4 integration of PARSE with GPS166 binary support
604154359Sroberto * derived from 3.105.1.2 from V3 tree
604254359Sroberto *
604354359Sroberto * Revision information 3.1 - 3.105 from log deleted 1998/04/10 kardel
604454359Sroberto *
604554359Sroberto */
6046