154359Sroberto/*
2280849Scy * /src/NTP/REPOSITORY/ntp4-dev/ntpd/refclock_parse.c,v 4.81 2009/05/01 10:15:29 kardel RELEASE_20090105_A
354359Sroberto *
4280849Scy * refclock_parse.c,v 4.81 2009/05/01 10:15:29 kardel RELEASE_20090105_A
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 *
18285169Scy * Copyright (c) 1995-2015 by Frank Kardel <kardel <AT> ntp.org>
19280849Scy * Copyright (c) 1989-1994 by Frank Kardel, Friedrich-Alexander Universitaet Erlangen-Nuernberg, 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
51280849Scy#include "ntp_types.h"
52280849Scy
5354359Sroberto#if defined(REFCLOCK) && defined(CLOCK_PARSE)
5454359Sroberto
5554359Sroberto/*
5654359Sroberto * This driver currently provides the support for
57282408Scy *   - Meinberg receiver DCF77 PZF535 (TCXO version)        (DCF)
58282408Scy *   - Meinberg receiver DCF77 PZF535 (OCXO version)        (DCF)
59282408Scy *   - Meinberg receiver DCF77 PZF509                       (DCF)
6054359Sroberto *   - Meinberg receiver DCF77 AM receivers (e.g. C51)      (DCF)
6154359Sroberto *   - IGEL CLOCK                                           (DCF)
6254359Sroberto *   - ELV DCF7000                                          (DCF)
6354359Sroberto *   - Schmid clock                                         (DCF)
6454359Sroberto *   - Conrad DCF77 receiver module                         (DCF)
6554359Sroberto *   - FAU DCF77 NTP receiver (TimeBrick)                   (DCF)
66282408Scy *   - WHARTON 400A Series clock                            (DCF)
6754359Sroberto *
68282408Scy *   - Meinberg GPS receivers                               (GPS)
6954359Sroberto *   - Trimble (TSIP and TAIP protocol)                     (GPS)
7054359Sroberto *
7154359Sroberto *   - RCC8000 MSF Receiver                                 (MSF)
72282408Scy *   - VARITEXT clock                                       (MSF)
7354359Sroberto */
7454359Sroberto
7554359Sroberto/*
7654359Sroberto * Meinberg receivers are usually connected via a
77282408Scy * 9600/7E1 or 19200/8N1 serial line.
7854359Sroberto *
7954359Sroberto * The Meinberg GPS receivers also have a special NTP time stamp
8054359Sroberto * format. The firmware release is Uni-Erlangen.
8154359Sroberto *
8254359Sroberto * Meinberg generic receiver setup:
83282408Scy *      output time code every second
84282408Scy *      Baud rate 9600 7E2S
8554359Sroberto *
86282408Scy * Meinberg GPS receiver setup:
8754359Sroberto *      output time code every second
8854359Sroberto *      Baudrate 19200 8N1
8954359Sroberto *
9054359Sroberto * This software supports the standard data formats used
9154359Sroberto * in Meinberg receivers.
9254359Sroberto *
9354359Sroberto * Special software versions are only sensible for the
94282408Scy * oldest GPS receiver, GPS16x. For newer receiver types
95282408Scy * the output string format can be configured at the device,
96282408Scy * and the device name is generally GPSxxx instead of GPS16x.
9754359Sroberto *
9854359Sroberto * Meinberg can be reached via: http://www.meinberg.de/
9954359Sroberto */
10054359Sroberto
10154359Sroberto#include "ntpd.h"
10254359Sroberto#include "ntp_refclock.h"
103280849Scy#include "timevalops.h"		/* includes <sys/time.h> */
10454359Sroberto#include "ntp_control.h"
105182007Sroberto#include "ntp_string.h"
10654359Sroberto
10754359Sroberto#include <stdio.h>
10854359Sroberto#include <ctype.h>
10954359Sroberto#ifndef TM_IN_SYS_TIME
11054359Sroberto# include <time.h>
11154359Sroberto#endif
11254359Sroberto
113182007Sroberto#ifdef HAVE_UNISTD_H
114182007Sroberto# include <unistd.h>
115182007Sroberto#endif
116182007Sroberto
11754359Sroberto#if !defined(STREAM) && !defined(HAVE_SYSV_TTYS) && !defined(HAVE_BSD_TTYS) && !defined(HAVE_TERMIOS)
11854359Sroberto# include "Bletch:  Define one of {STREAM,HAVE_SYSV_TTYS,HAVE_TERMIOS}"
11954359Sroberto#endif
12054359Sroberto
12154359Sroberto#ifdef STREAM
12254359Sroberto# include <sys/stream.h>
12354359Sroberto# include <sys/stropts.h>
12454359Sroberto#endif
12554359Sroberto
12654359Sroberto#ifdef HAVE_TERMIOS
127280849Scy# include <termios.h>
12854359Sroberto# define TTY_GETATTR(_FD_, _ARG_) tcgetattr((_FD_), (_ARG_))
12954359Sroberto# define TTY_SETATTR(_FD_, _ARG_) tcsetattr((_FD_), TCSANOW, (_ARG_))
13054359Sroberto# undef HAVE_SYSV_TTYS
13154359Sroberto#endif
13254359Sroberto
13354359Sroberto#ifdef HAVE_SYSV_TTYS
13454359Sroberto# define TTY_GETATTR(_FD_, _ARG_) ioctl((_FD_), TCGETA, (_ARG_))
13554359Sroberto# define TTY_SETATTR(_FD_, _ARG_) ioctl((_FD_), TCSETAW, (_ARG_))
13654359Sroberto#endif
13754359Sroberto
13854359Sroberto#ifdef HAVE_BSD_TTYS
13954359Sroberto/* #error CURRENTLY NO BSD TTY SUPPORT */
14054359Sroberto# include "Bletch: BSD TTY not currently supported"
14154359Sroberto#endif
14254359Sroberto
14354359Sroberto#ifdef HAVE_SYS_IOCTL_H
14454359Sroberto# include <sys/ioctl.h>
14554359Sroberto#endif
14654359Sroberto
147182007Sroberto#ifdef HAVE_PPSAPI
148182007Sroberto# include "ppsapi_timepps.h"
149280849Scy# include "refclock_atom.h"
150182007Sroberto#endif
151182007Sroberto
15254359Sroberto#ifdef PPS
153182007Sroberto# ifdef HAVE_SYS_PPSCLOCK_H
154182007Sroberto#  include <sys/ppsclock.h>
155182007Sroberto# endif
156182007Sroberto# ifdef HAVE_TIO_SERIAL_STUFF
157182007Sroberto#  include <linux/serial.h>
158182007Sroberto# endif
15954359Sroberto#endif
160182007Sroberto
161282408Scy# define BUFFER_SIZE(_BUF, _PTR)       ((int)((_BUF) + sizeof(_BUF) - (_PTR)))
162282408Scy# define BUFFER_SIZES(_BUF, _PTR, _SZ) ((int)((_BUF) + (_SZ) - (_PTR)))
163182007Sroberto
164182007Sroberto/*
165182007Sroberto * document type of PPS interfacing - copy of ifdef mechanism in local_input()
166182007Sroberto */
167282408Scy#undef PPS_METHOD
168182007Sroberto
169182007Sroberto#ifdef HAVE_PPSAPI
170182007Sroberto#define PPS_METHOD "PPS API"
171182007Sroberto#else
172182007Sroberto#ifdef TIOCDCDTIMESTAMP
173182007Sroberto#define PPS_METHOD "TIOCDCDTIMESTAMP"
174182007Sroberto#else /* TIOCDCDTIMESTAMP */
175182007Sroberto#if defined(HAVE_STRUCT_PPSCLOCKEV) && (defined(HAVE_CIOGETEV) || defined(HAVE_TIOCGPPSEV))
176182007Sroberto#ifdef HAVE_CIOGETEV
177182007Sroberto#define PPS_METHOD "CIOGETEV"
17854359Sroberto#endif
179182007Sroberto#ifdef HAVE_TIOCGPPSEV
180182007Sroberto#define PPS_METHOD "TIOCGPPSEV"
18154359Sroberto#endif
182182007Sroberto#endif
183182007Sroberto#endif /* TIOCDCDTIMESTAMP */
184182007Sroberto#endif /* HAVE_PPSAPI */
18554359Sroberto
186282408Scy/*
187282408Scy * COND_DEF can be conditionally defined as DEF or 0. If defined as DEF
188282408Scy * then some more parse-specific variables are flagged to be printed with
189282408Scy * "ntpq -c cv <assid>". This can be lengthy, so by default COND_DEF
190282408Scy * should be defined as 0.
191282408Scy */
192282408Scy#if 0
193282408Scy# define COND_DEF   DEF   // enable this for testing
194282408Scy#else
195282408Scy# define COND_DEF   0     // enable this by default
196282408Scy#endif
197282408Scy
19854359Sroberto#include "ntp_io.h"
19954359Sroberto#include "ntp_stdlib.h"
20054359Sroberto
20154359Sroberto#include "parse.h"
20254359Sroberto#include "mbg_gps166.h"
20354359Sroberto#include "trimble.h"
20454359Sroberto#include "binio.h"
20554359Sroberto#include "ascii.h"
20654359Sroberto#include "ieee754io.h"
207182007Sroberto#include "recvbuff.h"
20854359Sroberto
209280849Scystatic char rcsid[] = "refclock_parse.c,v 4.81 2009/05/01 10:15:29 kardel RELEASE_20090105_A+POWERUPTRUST";
21054359Sroberto
21154359Sroberto/**===========================================================================
21254359Sroberto ** external interface to ntp mechanism
21354359Sroberto **/
21454359Sroberto
215280849Scystatic	int	parse_start	(int, struct peer *);
216280849Scystatic	void	parse_shutdown	(int, struct peer *);
217280849Scystatic	void	parse_poll	(int, struct peer *);
218280849Scystatic	void	parse_control	(int, const struct refclockstat *, struct refclockstat *, struct peer *);
21954359Sroberto
22054359Srobertostruct	refclock refclock_parse = {
22154359Sroberto	parse_start,
22254359Sroberto	parse_shutdown,
22354359Sroberto	parse_poll,
22454359Sroberto	parse_control,
225182007Sroberto	noentry,
226182007Sroberto	noentry,
22754359Sroberto	NOFLAGS
22854359Sroberto};
22954359Sroberto
23054359Sroberto/*
23154359Sroberto * Definitions
23254359Sroberto */
23354359Sroberto#define	MAXUNITS	4	/* maximum number of "PARSE" units permitted */
23454359Sroberto#define PARSEDEVICE	"/dev/refclock-%d" /* device to open %d is unit number */
235182007Sroberto#define PARSEPPSDEVICE	"/dev/refclockpps-%d" /* optional pps device to open %d is unit number */
23654359Sroberto
23754359Sroberto#undef ABS
23854359Sroberto#define ABS(_X_) (((_X_) < 0) ? -(_X_) : (_X_))
23954359Sroberto
240182007Sroberto#define PARSE_HARDPPS_DISABLE 0
241182007Sroberto#define PARSE_HARDPPS_ENABLE  1
242182007Sroberto
24354359Sroberto/**===========================================================================
24454359Sroberto ** function vector for dynamically binding io handling mechanism
24554359Sroberto **/
24654359Sroberto
24754359Srobertostruct parseunit;		/* to keep inquiring minds happy */
24854359Sroberto
24954359Srobertotypedef struct bind
25054359Sroberto{
25154359Sroberto  const char *bd_description;	                                /* name of type of binding */
252280849Scy  int	(*bd_init)     (struct parseunit *);			/* initialize */
253280849Scy  void	(*bd_end)      (struct parseunit *);			/* end */
254280849Scy  int   (*bd_setcs)    (struct parseunit *, parsectl_t *);	/* set character size */
255280849Scy  int	(*bd_disable)  (struct parseunit *);			/* disable */
256280849Scy  int	(*bd_enable)   (struct parseunit *);			/* enable */
257280849Scy  int	(*bd_getfmt)   (struct parseunit *, parsectl_t *);	/* get format */
258280849Scy  int	(*bd_setfmt)   (struct parseunit *, parsectl_t *);	/* setfmt */
259280849Scy  int	(*bd_timecode) (struct parseunit *, parsectl_t *);	/* get time code */
260280849Scy  void	(*bd_receive)  (struct recvbuf *);			/* receive operation */
261280849Scy  int	(*bd_io_input) (struct recvbuf *);			/* input operation */
26254359Sroberto} bind_t;
26354359Sroberto
26454359Sroberto#define PARSE_END(_X_)			(*(_X_)->binding->bd_end)(_X_)
26554359Sroberto#define PARSE_SETCS(_X_, _CS_)		(*(_X_)->binding->bd_setcs)(_X_, _CS_)
26654359Sroberto#define PARSE_ENABLE(_X_)		(*(_X_)->binding->bd_enable)(_X_)
26754359Sroberto#define PARSE_DISABLE(_X_)		(*(_X_)->binding->bd_disable)(_X_)
26854359Sroberto#define PARSE_GETFMT(_X_, _DCT_)	(*(_X_)->binding->bd_getfmt)(_X_, _DCT_)
26954359Sroberto#define PARSE_SETFMT(_X_, _DCT_)	(*(_X_)->binding->bd_setfmt)(_X_, _DCT_)
27054359Sroberto#define PARSE_GETTIMECODE(_X_, _DCT_)	(*(_X_)->binding->bd_timecode)(_X_, _DCT_)
27154359Sroberto
27254359Sroberto/*
273280849Scy * special handling flags
27454359Sroberto */
275280849Scy#define PARSE_F_PPSONSECOND	0x00000001 /* PPS pulses are on second */
276280849Scy#define PARSE_F_POWERUPTRUST	0x00000100 /* POWERUP state ist trusted for */
277280849Scy                                           /* trusttime after SYNC was seen */
27854359Sroberto/**===========================================================================
27954359Sroberto ** error message regression handling
28054359Sroberto **
28154359Sroberto ** there are quite a few errors that can occur in rapid succession such as
28254359Sroberto ** noisy input data or no data at all. in order to reduce the amount of
28354359Sroberto ** syslog messages in such case, we are using a backoff algorithm. We limit
28454359Sroberto ** the number of error messages of a certain class to 1 per time unit. if a
28554359Sroberto ** configurable number of messages is displayed that way, we move on to the
28654359Sroberto ** next time unit / count for that class. a count of messages that have been
28754359Sroberto ** suppressed is held and displayed whenever a corresponding message is
28854359Sroberto ** displayed. the time units for a message class will also be displayed.
28954359Sroberto ** whenever an error condition clears we reset the error message state,
29054359Sroberto ** thus we would still generate much output on pathological conditions
29154359Sroberto ** where the system oscillates between OK and NOT OK states. coping
29254359Sroberto ** with that condition is currently considered too complicated.
29354359Sroberto **/
29454359Sroberto
29554359Sroberto#define ERR_ALL	        (unsigned)~0	/* "all" errors */
29654359Sroberto#define ERR_BADDATA	(unsigned)0	/* unusable input data/conversion errors */
29754359Sroberto#define ERR_NODATA	(unsigned)1	/* no input data */
29854359Sroberto#define ERR_BADIO	(unsigned)2	/* read/write/select errors */
29954359Sroberto#define ERR_BADSTATUS	(unsigned)3	/* unsync states */
30054359Sroberto#define ERR_BADEVENT	(unsigned)4	/* non nominal events */
30154359Sroberto#define ERR_INTERNAL	(unsigned)5	/* internal error */
30254359Sroberto#define ERR_CNT		(unsigned)(ERR_INTERNAL+1)
30354359Sroberto
30454359Sroberto#define ERR(_X_)	if (list_err(parse, (_X_)))
30554359Sroberto
30654359Srobertostruct errorregression
30754359Sroberto{
30854359Sroberto	u_long err_count;	/* number of repititions per class */
30954359Sroberto	u_long err_delay;	/* minimum delay between messages */
31054359Sroberto};
31154359Sroberto
31254359Srobertostatic struct errorregression
31354359Srobertoerr_baddata[] =			/* error messages for bad input data */
31454359Sroberto{
31554359Sroberto	{ 1,       0 },		/* output first message immediately */
31654359Sroberto	{ 5,      60 },		/* output next five messages in 60 second intervals */
31754359Sroberto	{ 3,    3600 },		/* output next 3 messages in hour intervals */
31854359Sroberto	{ 0, 12*3600 }		/* repeat messages only every 12 hours */
31954359Sroberto};
32054359Sroberto
32154359Srobertostatic struct errorregression
32254359Srobertoerr_nodata[] =			/* error messages for missing input data */
32354359Sroberto{
32454359Sroberto	{ 1,       0 },		/* output first message immediately */
32554359Sroberto	{ 5,      60 },		/* output next five messages in 60 second intervals */
32654359Sroberto	{ 3,    3600 },		/* output next 3 messages in hour intervals */
32754359Sroberto	{ 0, 12*3600 }		/* repeat messages only every 12 hours */
32854359Sroberto};
32954359Sroberto
33054359Srobertostatic struct errorregression
33154359Srobertoerr_badstatus[] =		/* unsynchronized state messages */
33254359Sroberto{
33354359Sroberto	{ 1,       0 },		/* output first message immediately */
33454359Sroberto	{ 5,      60 },		/* output next five messages in 60 second intervals */
33554359Sroberto	{ 3,    3600 },		/* output next 3 messages in hour intervals */
33654359Sroberto	{ 0, 12*3600 }		/* repeat messages only every 12 hours */
33754359Sroberto};
33854359Sroberto
33954359Srobertostatic struct errorregression
34054359Srobertoerr_badio[] =			/* io failures (bad reads, selects, ...) */
34154359Sroberto{
34254359Sroberto	{ 1,       0 },		/* output first message immediately */
34354359Sroberto	{ 5,      60 },		/* output next five messages in 60 second intervals */
34454359Sroberto	{ 5,    3600 },		/* output next 3 messages in hour intervals */
34554359Sroberto	{ 0, 12*3600 }		/* repeat messages only every 12 hours */
34654359Sroberto};
34754359Sroberto
34854359Srobertostatic struct errorregression
34954359Srobertoerr_badevent[] =		/* non nominal events */
35054359Sroberto{
35154359Sroberto	{ 20,      0 },		/* output first message immediately */
35254359Sroberto	{ 6,      60 },		/* output next five messages in 60 second intervals */
35354359Sroberto	{ 5,    3600 },		/* output next 3 messages in hour intervals */
35454359Sroberto	{ 0, 12*3600 }		/* repeat messages only every 12 hours */
35554359Sroberto};
35654359Sroberto
35754359Srobertostatic struct errorregression
35854359Srobertoerr_internal[] =		/* really bad things - basically coding/OS errors */
35954359Sroberto{
36054359Sroberto	{ 0,       0 },		/* output all messages immediately */
36154359Sroberto};
36254359Sroberto
36354359Srobertostatic struct errorregression *
36454359Srobertoerr_tbl[] =
36554359Sroberto{
36654359Sroberto	err_baddata,
36754359Sroberto	err_nodata,
36854359Sroberto	err_badio,
36954359Sroberto	err_badstatus,
37054359Sroberto	err_badevent,
37154359Sroberto	err_internal
37254359Sroberto};
37354359Sroberto
37454359Srobertostruct errorinfo
37554359Sroberto{
37654359Sroberto	u_long err_started;	/* begin time (ntp) of error condition */
37754359Sroberto	u_long err_last;	/* last time (ntp) error occurred */
37854359Sroberto	u_long err_cnt;	/* number of error repititions */
37954359Sroberto	u_long err_suppressed;	/* number of suppressed messages */
38054359Sroberto	struct errorregression *err_stage; /* current error stage */
38154359Sroberto};
38254359Sroberto
38354359Sroberto/**===========================================================================
38454359Sroberto ** refclock instance data
38554359Sroberto **/
38654359Sroberto
38754359Srobertostruct parseunit
38854359Sroberto{
38954359Sroberto	/*
39054359Sroberto	 * NTP management
39154359Sroberto	 */
39254359Sroberto	struct peer         *peer;		/* backlink to peer structure - refclock inactive if 0  */
39354359Sroberto	struct refclockproc *generic;		/* backlink to refclockproc structure */
39454359Sroberto
39554359Sroberto	/*
39654359Sroberto	 * PARSE io
39754359Sroberto	 */
39854359Sroberto	bind_t	     *binding;	        /* io handling binding */
399282408Scy
40054359Sroberto	/*
40154359Sroberto	 * parse state
40254359Sroberto	 */
40354359Sroberto	parse_t	      parseio;	        /* io handling structure (user level parsing) */
40454359Sroberto
40554359Sroberto	/*
40654359Sroberto	 * type specific parameters
40754359Sroberto	 */
40854359Sroberto	struct parse_clockinfo   *parse_type;	        /* link to clock description */
40954359Sroberto
41054359Sroberto	/*
41154359Sroberto	 * clock state handling/reporting
41254359Sroberto	 */
41354359Sroberto	u_char	      flags;	        /* flags (leap_control) */
41454359Sroberto	u_long	      lastchange;       /* time (ntp) when last state change accured */
41554359Sroberto	u_long	      statetime[CEVNT_MAX+1]; /* accumulated time of clock states */
41656746Sroberto	u_long        pollneeddata; 	/* current_time(!=0) for receive sample expected in PPS mode */
41754359Sroberto	u_short	      lastformat;       /* last format used */
41854359Sroberto	u_long        lastsync;		/* time (ntp) when clock was last seen fully synchronized */
419182007Sroberto        u_long        maxunsync;        /* max time in seconds a receiver is trusted after loosing synchronisation */
420182007Sroberto        double        ppsphaseadjust;   /* phase adjustment of PPS time stamp */
421182007Sroberto        u_long        lastmissed;       /* time (ntp) when poll didn't get data (powerup heuristic) */
42254359Sroberto	u_long        ppsserial;        /* magic cookie for ppsclock serials (avoids stale ppsclock data) */
423182007Sroberto	int	      ppsfd;	        /* fd to ise for PPS io */
424182007Sroberto#ifdef HAVE_PPSAPI
425182007Sroberto        int           hardppsstate;     /* current hard pps state */
426280849Scy	struct refclock_atom atom;      /* PPSAPI structure */
427182007Sroberto#endif
428182007Sroberto	parsetime_t   timedata;		/* last (parse module) data */
42954359Sroberto	void         *localdata;        /* optional local, receiver-specific data */
43054359Sroberto        unsigned long localstate;       /* private local state */
43154359Sroberto	struct errorinfo errors[ERR_CNT];  /* error state table for suppressing excessive error messages */
43254359Sroberto	struct ctl_var *kv;	        /* additional pseudo variables */
43354359Sroberto	u_long        laststatistic;    /* time when staticstics where output */
43454359Sroberto};
43554359Sroberto
43654359Sroberto
43754359Sroberto/**===========================================================================
43854359Sroberto ** Clockinfo section all parameter for specific clock types
43954359Sroberto ** includes NTP parameters, TTY parameters and IO handling parameters
44054359Sroberto **/
44154359Sroberto
442280849Scystatic	void	poll_dpoll	(struct parseunit *);
443280849Scystatic	void	poll_poll	(struct peer *);
444280849Scystatic	int	poll_init	(struct parseunit *);
44554359Sroberto
44654359Srobertotypedef struct poll_info
44754359Sroberto{
44854359Sroberto	u_long      rate;		/* poll rate - once every "rate" seconds - 0 off */
44954359Sroberto	const char *string;		/* string to send for polling */
45054359Sroberto	u_long      count;		/* number of characters in string */
45154359Sroberto} poll_info_t;
45254359Sroberto
45354359Sroberto#define NO_CL_FLAGS	0
45454359Sroberto#define NO_POLL		0
45554359Sroberto#define NO_INIT		0
45654359Sroberto#define NO_END		0
45754359Sroberto#define NO_EVENT	0
458182007Sroberto#define NO_LCLDATA	0
45954359Sroberto#define NO_MESSAGE	0
46054359Sroberto#define NO_PPSDELAY     0
46154359Sroberto
46254359Sroberto#define DCF_ID		"DCF"	/* generic DCF */
46354359Sroberto#define DCF_A_ID	"DCFa"	/* AM demodulation */
46454359Sroberto#define DCF_P_ID	"DCFp"	/* psuedo random phase shift */
46554359Sroberto#define GPS_ID		"GPS"	/* GPS receiver */
46654359Sroberto
467282408Scy#define NOCLOCK_ROOTDELAY       0.0
468282408Scy#define NOCLOCK_BASEDELAY       0.0
469282408Scy#define NOCLOCK_DESCRIPTION     0
47054359Sroberto#define NOCLOCK_MAXUNSYNC       0
47154359Sroberto#define NOCLOCK_CFLAG           0
47254359Sroberto#define NOCLOCK_IFLAG           0
47354359Sroberto#define NOCLOCK_OFLAG           0
47454359Sroberto#define NOCLOCK_LFLAG           0
475282408Scy#define NOCLOCK_ID              "TILT"
476282408Scy#define NOCLOCK_POLL            NO_POLL
477282408Scy#define NOCLOCK_INIT            NO_INIT
478282408Scy#define NOCLOCK_END             NO_END
479282408Scy#define NOCLOCK_DATA            NO_LCLDATA
480282408Scy#define NOCLOCK_FORMAT          ""
481282408Scy#define NOCLOCK_TYPE            CTL_SST_TS_UNSPEC
482282408Scy#define NOCLOCK_SAMPLES         0
483282408Scy#define NOCLOCK_KEEP            0
48454359Sroberto
48554359Sroberto#define DCF_TYPE		CTL_SST_TS_LF
48654359Sroberto#define GPS_TYPE		CTL_SST_TS_UHF
48754359Sroberto
48854359Sroberto/*
48954359Sroberto * receiver specific constants
49054359Sroberto */
49154359Sroberto#define MBG_SPEED		(B9600)
492182007Sroberto#define MBG_CFLAG		(CS7|PARENB|CREAD|CLOCAL|HUPCL|CSTOPB)
49354359Sroberto#define MBG_IFLAG		(IGNBRK|IGNPAR|ISTRIP)
49454359Sroberto#define MBG_OFLAG		0
49554359Sroberto#define MBG_LFLAG		0
49654359Sroberto#define MBG_FLAGS               PARSE_F_PPSONSECOND
49754359Sroberto
49854359Sroberto/*
49954359Sroberto * Meinberg DCF77 receivers
50054359Sroberto */
50154359Sroberto#define	DCFUA31_ROOTDELAY	0.0  /* 0 */
50254359Sroberto#define	DCFUA31_BASEDELAY	0.010  /* 10.7421875ms: 10 ms (+/- 3 ms) */
50354359Sroberto#define	DCFUA31_DESCRIPTION	"Meinberg DCF77 C51 or compatible"
50454359Sroberto#define DCFUA31_MAXUNSYNC       60*30       /* only trust clock for 1/2 hour */
50554359Sroberto#define DCFUA31_SPEED		MBG_SPEED
50654359Sroberto#define DCFUA31_CFLAG           MBG_CFLAG
50754359Sroberto#define DCFUA31_IFLAG           MBG_IFLAG
50854359Sroberto#define DCFUA31_OFLAG           MBG_OFLAG
50954359Sroberto#define DCFUA31_LFLAG           MBG_LFLAG
51054359Sroberto#define DCFUA31_SAMPLES		5
51154359Sroberto#define DCFUA31_KEEP		3
51254359Sroberto#define DCFUA31_FORMAT		"Meinberg Standard"
51354359Sroberto
51454359Sroberto/*
51554359Sroberto * Meinberg DCF PZF535/TCXO (FM/PZF) receiver
51654359Sroberto */
51754359Sroberto#define	DCFPZF535_ROOTDELAY	0.0
51854359Sroberto#define	DCFPZF535_BASEDELAY	0.001968  /* 1.968ms +- 104us (oscilloscope) - relative to start (end of STX) */
51954359Sroberto#define	DCFPZF535_DESCRIPTION	"Meinberg DCF PZF 535/509 / TCXO"
52054359Sroberto#define DCFPZF535_MAXUNSYNC     60*60*12           /* only trust clock for 12 hours
52154359Sroberto						    * @ 5e-8df/f we have accumulated
52254359Sroberto						    * at most 2.16 ms (thus we move to
52354359Sroberto						    * NTP synchronisation */
52454359Sroberto#define DCFPZF535_SPEED		MBG_SPEED
52554359Sroberto#define DCFPZF535_CFLAG         MBG_CFLAG
52654359Sroberto#define DCFPZF535_IFLAG         MBG_IFLAG
52754359Sroberto#define DCFPZF535_OFLAG         MBG_OFLAG
52854359Sroberto#define DCFPZF535_LFLAG         MBG_LFLAG
52954359Sroberto#define DCFPZF535_SAMPLES	       5
53054359Sroberto#define DCFPZF535_KEEP		       3
53154359Sroberto#define DCFPZF535_FORMAT	"Meinberg Standard"
53254359Sroberto
53354359Sroberto/*
53454359Sroberto * Meinberg DCF PZF535/OCXO receiver
53554359Sroberto */
53654359Sroberto#define	DCFPZF535OCXO_ROOTDELAY	0.0
53754359Sroberto#define	DCFPZF535OCXO_BASEDELAY	0.001968 /* 1.968ms +- 104us (oscilloscope) - relative to start (end of STX) */
53854359Sroberto#define	DCFPZF535OCXO_DESCRIPTION "Meinberg DCF PZF 535/509 / OCXO"
53954359Sroberto#define DCFPZF535OCXO_MAXUNSYNC     60*60*96       /* only trust clock for 4 days
54054359Sroberto						    * @ 5e-9df/f we have accumulated
54154359Sroberto						    * at most an error of 1.73 ms
54254359Sroberto						    * (thus we move to NTP synchronisation) */
54354359Sroberto#define DCFPZF535OCXO_SPEED	    MBG_SPEED
54454359Sroberto#define DCFPZF535OCXO_CFLAG         MBG_CFLAG
54554359Sroberto#define DCFPZF535OCXO_IFLAG         MBG_IFLAG
54654359Sroberto#define DCFPZF535OCXO_OFLAG         MBG_OFLAG
54754359Sroberto#define DCFPZF535OCXO_LFLAG         MBG_LFLAG
54854359Sroberto#define DCFPZF535OCXO_SAMPLES		   5
54954359Sroberto#define DCFPZF535OCXO_KEEP	           3
55054359Sroberto#define DCFPZF535OCXO_FORMAT	    "Meinberg Standard"
55154359Sroberto
55254359Sroberto/*
553282408Scy * Meinberg GPS receivers
55454359Sroberto */
555280849Scystatic	void	gps16x_message	 (struct parseunit *, parsetime_t *);
556280849Scystatic  int     gps16x_poll_init (struct parseunit *);
55754359Sroberto
55854359Sroberto#define	GPS16X_ROOTDELAY	0.0         /* nothing here */
55954359Sroberto#define	GPS16X_BASEDELAY	0.001968         /* XXX to be fixed ! 1.968ms +- 104us (oscilloscope) - relative to start (end of STX) */
560282408Scy#define	GPS16X_DESCRIPTION      "Meinberg GPS receiver"
56154359Sroberto#define GPS16X_MAXUNSYNC        60*60*96       /* only trust clock for 4 days
56254359Sroberto						* @ 5e-9df/f we have accumulated
56354359Sroberto						* at most an error of 1.73 ms
56454359Sroberto						* (thus we move to NTP synchronisation) */
56554359Sroberto#define GPS16X_SPEED		B19200
56654359Sroberto#define GPS16X_CFLAG            (CS8|CREAD|CLOCAL|HUPCL)
56754359Sroberto#define GPS16X_IFLAG            (IGNBRK|IGNPAR)
56854359Sroberto#define GPS16X_OFLAG            MBG_OFLAG
56954359Sroberto#define GPS16X_LFLAG            MBG_LFLAG
57054359Sroberto#define GPS16X_POLLRATE	6
57154359Sroberto#define GPS16X_POLLCMD	""
57254359Sroberto#define GPS16X_CMDSIZE	0
57354359Sroberto
57454359Srobertostatic poll_info_t gps16x_pollinfo = { GPS16X_POLLRATE, GPS16X_POLLCMD, GPS16X_CMDSIZE };
57554359Sroberto
57654359Sroberto#define GPS16X_INIT		gps16x_poll_init
57754359Sroberto#define GPS16X_POLL	        0
57854359Sroberto#define GPS16X_END		0
57954359Sroberto#define GPS16X_DATA		((void *)(&gps16x_pollinfo))
58054359Sroberto#define GPS16X_MESSAGE		gps16x_message
58154359Sroberto#define GPS16X_ID		GPS_ID
58254359Sroberto#define GPS16X_FORMAT		"Meinberg GPS Extended"
58354359Sroberto#define GPS16X_SAMPLES		5
58454359Sroberto#define GPS16X_KEEP		3
58554359Sroberto
58654359Sroberto/*
58754359Sroberto * ELV DCF7000 Wallclock-Receiver/Switching Clock (Kit)
58854359Sroberto *
58954359Sroberto * This is really not the hottest clock - but before you have nothing ...
59054359Sroberto */
59154359Sroberto#define DCF7000_ROOTDELAY	0.0 /* 0 */
59254359Sroberto#define DCF7000_BASEDELAY	0.405 /* slow blow */
59354359Sroberto#define DCF7000_DESCRIPTION	"ELV DCF7000"
59454359Sroberto#define DCF7000_MAXUNSYNC	(60*5) /* sorry - but it just was not build as a clock */
59554359Sroberto#define DCF7000_SPEED		(B9600)
59654359Sroberto#define DCF7000_CFLAG           (CS8|CREAD|PARENB|PARODD|CLOCAL|HUPCL)
59754359Sroberto#define DCF7000_IFLAG		(IGNBRK)
59854359Sroberto#define DCF7000_OFLAG		0
59954359Sroberto#define DCF7000_LFLAG		0
60054359Sroberto#define DCF7000_SAMPLES		5
60154359Sroberto#define DCF7000_KEEP		3
60254359Sroberto#define DCF7000_FORMAT		"ELV DCF7000"
60354359Sroberto
60454359Sroberto/*
60554359Sroberto * Schmid DCF Receiver Kit
60654359Sroberto *
60754359Sroberto * When the WSDCF clock is operating optimally we want the primary clock
60854359Sroberto * distance to come out at 300 ms.  Thus, peer.distance in the WSDCF peer
60954359Sroberto * structure is set to 290 ms and we compute delays which are at least
61054359Sroberto * 10 ms long.  The following are 290 ms and 10 ms expressed in u_fp format
61154359Sroberto */
61254359Sroberto#define WS_POLLRATE	1	/* every second - watch interdependency with poll routine */
61354359Sroberto#define WS_POLLCMD	"\163"
61454359Sroberto#define WS_CMDSIZE	1
61554359Sroberto
61654359Srobertostatic poll_info_t wsdcf_pollinfo = { WS_POLLRATE, WS_POLLCMD, WS_CMDSIZE };
61754359Sroberto
61854359Sroberto#define WSDCF_INIT		poll_init
61954359Sroberto#define WSDCF_POLL		poll_dpoll
62054359Sroberto#define WSDCF_END		0
62154359Sroberto#define WSDCF_DATA		((void *)(&wsdcf_pollinfo))
62254359Sroberto#define	WSDCF_ROOTDELAY		0.0	/* 0 */
62354359Sroberto#define	WSDCF_BASEDELAY	 	0.010	/*  ~  10ms */
62454359Sroberto#define WSDCF_DESCRIPTION	"WS/DCF Receiver"
62554359Sroberto#define WSDCF_FORMAT		"Schmid"
62654359Sroberto#define WSDCF_MAXUNSYNC		(60*60)	/* assume this beast hold at 1 h better than 2 ms XXX-must verify */
62754359Sroberto#define WSDCF_SPEED		(B1200)
62854359Sroberto#define WSDCF_CFLAG		(CS8|CREAD|CLOCAL)
62954359Sroberto#define WSDCF_IFLAG		0
63054359Sroberto#define WSDCF_OFLAG		0
63154359Sroberto#define WSDCF_LFLAG		0
63254359Sroberto#define WSDCF_SAMPLES		5
63354359Sroberto#define WSDCF_KEEP		3
63454359Sroberto
63554359Sroberto/*
63654359Sroberto * RAW DCF77 - input of DCF marks via RS232 - many variants
63754359Sroberto */
63854359Sroberto#define RAWDCF_FLAGS		0
63954359Sroberto#define RAWDCF_ROOTDELAY	0.0 /* 0 */
64054359Sroberto#define RAWDCF_BASEDELAY	0.258
64154359Sroberto#define RAWDCF_FORMAT		"RAW DCF77 Timecode"
64254359Sroberto#define RAWDCF_MAXUNSYNC	(0) /* sorry - its a true receiver - no signal - no time */
64354359Sroberto#define RAWDCF_SPEED		(B50)
64454359Sroberto#ifdef NO_PARENB_IGNPAR /* Was: defined(SYS_IRIX4) || defined(SYS_IRIX5) */
64554359Sroberto/* somehow doesn't grok PARENB & IGNPAR (mj) */
64654359Sroberto# define RAWDCF_CFLAG            (CS8|CREAD|CLOCAL)
64754359Sroberto#else
64854359Sroberto# define RAWDCF_CFLAG            (CS8|CREAD|CLOCAL|PARENB)
64954359Sroberto#endif
65054359Sroberto#ifdef RAWDCF_NO_IGNPAR /* Was: defined(SYS_LINUX) && defined(CLOCK_RAWDCF) */
65154359Sroberto# define RAWDCF_IFLAG		0
65254359Sroberto#else
65354359Sroberto# define RAWDCF_IFLAG		(IGNPAR)
65454359Sroberto#endif
65554359Sroberto#define RAWDCF_OFLAG		0
65654359Sroberto#define RAWDCF_LFLAG		0
65754359Sroberto#define RAWDCF_SAMPLES		20
65854359Sroberto#define RAWDCF_KEEP		12
65954359Sroberto#define RAWDCF_INIT		0
66054359Sroberto
66154359Sroberto/*
66254359Sroberto * RAW DCF variants
66354359Sroberto */
66454359Sroberto/*
66554359Sroberto * Conrad receiver
66654359Sroberto *
66754359Sroberto * simplest (cheapest) DCF clock - e. g. DCF77 receiver by Conrad
66854359Sroberto * (~40DM - roughly $30 ) followed by a level converter for RS232
66954359Sroberto */
67054359Sroberto#define CONRAD_BASEDELAY	0.292 /* Conrad receiver @ 50 Baud on a Sun */
67154359Sroberto#define CONRAD_DESCRIPTION	"RAW DCF77 CODE (Conrad DCF77 receiver module)"
67254359Sroberto
673182007Sroberto/* Gude Analog- und Digitalsystem GmbH 'Expert mouseCLOCK USB v2.0' */
674182007Sroberto#define GUDE_EMC_USB_V20_SPEED            (B4800)
675182007Sroberto#define GUDE_EMC_USB_V20_BASEDELAY        0.425 /* USB serial<->USB converter FTDI232R */
676182007Sroberto#define GUDE_EMC_USB_V20_DESCRIPTION      "RAW DCF77 CODE (Expert mouseCLOCK USB v2.0)"
677182007Sroberto
67854359Sroberto/*
67954359Sroberto * TimeBrick receiver
68054359Sroberto */
68154359Sroberto#define TIMEBRICK_BASEDELAY	0.210 /* TimeBrick @ 50 Baud on a Sun */
68254359Sroberto#define TIMEBRICK_DESCRIPTION	"RAW DCF77 CODE (TimeBrick)"
68354359Sroberto
68454359Sroberto/*
68554359Sroberto * IGEL:clock receiver
68654359Sroberto */
68754359Sroberto#define IGELCLOCK_BASEDELAY	0.258 /* IGEL:clock receiver */
68854359Sroberto#define IGELCLOCK_DESCRIPTION	"RAW DCF77 CODE (IGEL:clock)"
68954359Sroberto#define IGELCLOCK_SPEED		(B1200)
69054359Sroberto#define IGELCLOCK_CFLAG		(CS8|CREAD|HUPCL|CLOCAL)
69154359Sroberto
69254359Sroberto/*
69354359Sroberto * RAWDCF receivers that need to be powered from DTR
69454359Sroberto * (like Expert mouse clock)
69554359Sroberto */
696280849Scystatic	int	rawdcf_init_1	(struct parseunit *);
69756746Sroberto#define RAWDCFDTRSET_DESCRIPTION	"RAW DCF77 CODE (DTR SET/RTS CLR)"
698280849Scy#define RAWDCFDTRSET75_DESCRIPTION	"RAW DCF77 CODE (DTR SET/RTS CLR @ 75 baud)"
69956746Sroberto#define RAWDCFDTRSET_INIT 		rawdcf_init_1
70054359Sroberto
70154359Sroberto/*
70256746Sroberto * RAWDCF receivers that need to be powered from
70356746Sroberto * DTR CLR and RTS SET
70454359Sroberto */
705280849Scystatic	int	rawdcf_init_2	(struct parseunit *);
70656746Sroberto#define RAWDCFDTRCLRRTSSET_DESCRIPTION	"RAW DCF77 CODE (DTR CLR/RTS SET)"
707280849Scy#define RAWDCFDTRCLRRTSSET75_DESCRIPTION "RAW DCF77 CODE (DTR CLR/RTS SET @ 75 baud)"
70856746Sroberto#define RAWDCFDTRCLRRTSSET_INIT	rawdcf_init_2
70954359Sroberto
71054359Sroberto/*
71154359Sroberto * Trimble GPS receivers (TAIP and TSIP protocols)
71254359Sroberto */
71354359Sroberto#ifndef TRIM_POLLRATE
71454359Sroberto#define TRIM_POLLRATE	0	/* only true direct polling */
71554359Sroberto#endif
71654359Sroberto
71754359Sroberto#define TRIM_TAIPPOLLCMD	">SRM;FR_FLAG=F;EC_FLAG=F<>QTM<"
71854359Sroberto#define TRIM_TAIPCMDSIZE	(sizeof(TRIM_TAIPPOLLCMD)-1)
71954359Sroberto
72054359Srobertostatic poll_info_t trimbletaip_pollinfo = { TRIM_POLLRATE, TRIM_TAIPPOLLCMD, TRIM_TAIPCMDSIZE };
721280849Scystatic	int	trimbletaip_init	(struct parseunit *);
722280849Scystatic	void	trimbletaip_event	(struct parseunit *, int);
72354359Sroberto
72454359Sroberto/* query time & UTC correction data */
72554359Srobertostatic char tsipquery[] = { DLE, 0x21, DLE, ETX, DLE, 0x2F, DLE, ETX };
72654359Sroberto
72754359Srobertostatic poll_info_t trimbletsip_pollinfo = { TRIM_POLLRATE, tsipquery, sizeof(tsipquery) };
728280849Scystatic	int	trimbletsip_init	(struct parseunit *);
729280849Scystatic	void	trimbletsip_end   	(struct parseunit *);
730280849Scystatic	void	trimbletsip_message	(struct parseunit *, parsetime_t *);
731280849Scystatic	void	trimbletsip_event	(struct parseunit *, int);
73254359Sroberto
73354359Sroberto#define TRIMBLETSIP_IDLE_TIME	    (300) /* 5 minutes silence at most */
734182007Sroberto#define TRIMBLE_RESET_HOLDOFF       TRIMBLETSIP_IDLE_TIME
73554359Sroberto
73654359Sroberto#define TRIMBLETAIP_SPEED	    (B4800)
73754359Sroberto#define TRIMBLETAIP_CFLAG           (CS8|CREAD|CLOCAL)
73854359Sroberto#define TRIMBLETAIP_IFLAG           (BRKINT|IGNPAR|ISTRIP|ICRNL|IXON)
73954359Sroberto#define TRIMBLETAIP_OFLAG           (OPOST|ONLCR)
74054359Sroberto#define TRIMBLETAIP_LFLAG           (0)
74154359Sroberto
74254359Sroberto#define TRIMBLETSIP_SPEED	    (B9600)
74354359Sroberto#define TRIMBLETSIP_CFLAG           (CS8|CLOCAL|CREAD|PARENB|PARODD)
74454359Sroberto#define TRIMBLETSIP_IFLAG           (IGNBRK)
74554359Sroberto#define TRIMBLETSIP_OFLAG           (0)
74654359Sroberto#define TRIMBLETSIP_LFLAG           (ICANON)
74754359Sroberto
74854359Sroberto#define TRIMBLETSIP_SAMPLES	    5
74954359Sroberto#define TRIMBLETSIP_KEEP	    3
75054359Sroberto#define TRIMBLETAIP_SAMPLES	    5
75154359Sroberto#define TRIMBLETAIP_KEEP	    3
75254359Sroberto
75354359Sroberto#define TRIMBLETAIP_FLAGS	    (PARSE_F_PPSONSECOND)
75454359Sroberto#define TRIMBLETSIP_FLAGS	    (TRIMBLETAIP_FLAGS)
75554359Sroberto
75654359Sroberto#define TRIMBLETAIP_POLL	    poll_dpoll
75754359Sroberto#define TRIMBLETSIP_POLL	    poll_dpoll
75854359Sroberto
75954359Sroberto#define TRIMBLETAIP_INIT	    trimbletaip_init
76054359Sroberto#define TRIMBLETSIP_INIT	    trimbletsip_init
76154359Sroberto
762282408Scy#define TRIMBLETAIP_EVENT	    trimbletaip_event
76354359Sroberto
764282408Scy#define TRIMBLETSIP_EVENT	    trimbletsip_event
76554359Sroberto#define TRIMBLETSIP_MESSAGE	    trimbletsip_message
76654359Sroberto
76754359Sroberto#define TRIMBLETAIP_END		    0
76854359Sroberto#define TRIMBLETSIP_END		    trimbletsip_end
76954359Sroberto
77054359Sroberto#define TRIMBLETAIP_DATA	    ((void *)(&trimbletaip_pollinfo))
77154359Sroberto#define TRIMBLETSIP_DATA	    ((void *)(&trimbletsip_pollinfo))
77254359Sroberto
77354359Sroberto#define TRIMBLETAIP_ID		    GPS_ID
77454359Sroberto#define TRIMBLETSIP_ID		    GPS_ID
77554359Sroberto
77654359Sroberto#define TRIMBLETAIP_FORMAT	    "Trimble TAIP"
77754359Sroberto#define TRIMBLETSIP_FORMAT	    "Trimble TSIP"
77854359Sroberto
77954359Sroberto#define TRIMBLETAIP_ROOTDELAY        0x0
78054359Sroberto#define TRIMBLETSIP_ROOTDELAY        0x0
78154359Sroberto
78254359Sroberto#define TRIMBLETAIP_BASEDELAY        0.0
78354359Sroberto#define TRIMBLETSIP_BASEDELAY        0.020	/* GPS time message latency */
78454359Sroberto
78554359Sroberto#define TRIMBLETAIP_DESCRIPTION      "Trimble GPS (TAIP) receiver"
78654359Sroberto#define TRIMBLETSIP_DESCRIPTION      "Trimble GPS (TSIP) receiver"
78754359Sroberto
78854359Sroberto#define TRIMBLETAIP_MAXUNSYNC        0
78954359Sroberto#define TRIMBLETSIP_MAXUNSYNC        0
79054359Sroberto
79154359Sroberto#define TRIMBLETAIP_EOL		    '<'
79254359Sroberto
79354359Sroberto/*
79454359Sroberto * RadioCode Clocks RCC 800 receiver
79554359Sroberto */
79654359Sroberto#define RCC_POLLRATE   0       /* only true direct polling */
79754359Sroberto#define RCC_POLLCMD    "\r"
79854359Sroberto#define RCC_CMDSIZE    1
79954359Sroberto
80054359Srobertostatic poll_info_t rcc8000_pollinfo = { RCC_POLLRATE, RCC_POLLCMD, RCC_CMDSIZE };
80154359Sroberto#define RCC8000_FLAGS		0
80254359Sroberto#define RCC8000_POLL            poll_dpoll
80354359Sroberto#define RCC8000_INIT            poll_init
80454359Sroberto#define RCC8000_END             0
80554359Sroberto#define RCC8000_DATA            ((void *)(&rcc8000_pollinfo))
80654359Sroberto#define RCC8000_ROOTDELAY       0.0
80754359Sroberto#define RCC8000_BASEDELAY       0.0
80854359Sroberto#define RCC8000_ID              "MSF"
80954359Sroberto#define RCC8000_DESCRIPTION     "RCC 8000 MSF Receiver"
81054359Sroberto#define RCC8000_FORMAT          "Radiocode RCC8000"
81154359Sroberto#define RCC8000_MAXUNSYNC       (60*60) /* should be ok for an hour */
81254359Sroberto#define RCC8000_SPEED		(B2400)
81354359Sroberto#define RCC8000_CFLAG           (CS8|CREAD|CLOCAL)
81454359Sroberto#define RCC8000_IFLAG           (IGNBRK|IGNPAR)
81554359Sroberto#define RCC8000_OFLAG           0
81654359Sroberto#define RCC8000_LFLAG           0
81754359Sroberto#define RCC8000_SAMPLES         5
81854359Sroberto#define RCC8000_KEEP	        3
81954359Sroberto
82054359Sroberto/*
821282408Scy * Hopf Radio clock 6021 Format
82254359Sroberto *
82354359Sroberto */
82454359Sroberto#define HOPF6021_ROOTDELAY	0.0
82554359Sroberto#define HOPF6021_BASEDELAY	0.0
82654359Sroberto#define HOPF6021_DESCRIPTION	"HOPF 6021"
82754359Sroberto#define HOPF6021_FORMAT         "hopf Funkuhr 6021"
82854359Sroberto#define HOPF6021_MAXUNSYNC	(60*60)  /* should be ok for an hour */
82954359Sroberto#define HOPF6021_SPEED         (B9600)
83054359Sroberto#define HOPF6021_CFLAG          (CS8|CREAD|CLOCAL)
83154359Sroberto#define HOPF6021_IFLAG		(IGNBRK|ISTRIP)
83254359Sroberto#define HOPF6021_OFLAG		0
83354359Sroberto#define HOPF6021_LFLAG		0
83454359Sroberto#define HOPF6021_FLAGS          0
83554359Sroberto#define HOPF6021_SAMPLES        5
83654359Sroberto#define HOPF6021_KEEP	        3
83754359Sroberto
83854359Sroberto/*
83954359Sroberto * Diem's Computime Radio Clock Receiver
84054359Sroberto */
84154359Sroberto#define COMPUTIME_FLAGS       0
84254359Sroberto#define COMPUTIME_ROOTDELAY   0.0
84354359Sroberto#define COMPUTIME_BASEDELAY   0.0
84454359Sroberto#define COMPUTIME_ID          DCF_ID
84554359Sroberto#define COMPUTIME_DESCRIPTION "Diem's Computime receiver"
84654359Sroberto#define COMPUTIME_FORMAT      "Diem's Computime Radio Clock"
84754359Sroberto#define COMPUTIME_TYPE        DCF_TYPE
84854359Sroberto#define COMPUTIME_MAXUNSYNC   (60*60)       /* only trust clock for 1 hour */
84954359Sroberto#define COMPUTIME_SPEED       (B9600)
85054359Sroberto#define COMPUTIME_CFLAG       (CSTOPB|CS7|CREAD|CLOCAL)
85154359Sroberto#define COMPUTIME_IFLAG       (IGNBRK|IGNPAR|ISTRIP)
85254359Sroberto#define COMPUTIME_OFLAG       0
85354359Sroberto#define COMPUTIME_LFLAG       0
85454359Sroberto#define COMPUTIME_SAMPLES     5
85554359Sroberto#define COMPUTIME_KEEP        3
85654359Sroberto
85754359Sroberto/*
85854359Sroberto * Varitext Radio Clock Receiver
85954359Sroberto */
86054359Sroberto#define VARITEXT_FLAGS       0
86154359Sroberto#define VARITEXT_ROOTDELAY   0.0
86254359Sroberto#define VARITEXT_BASEDELAY   0.0
86354359Sroberto#define VARITEXT_ID          "MSF"
86454359Sroberto#define VARITEXT_DESCRIPTION "Varitext receiver"
86554359Sroberto#define VARITEXT_FORMAT      "Varitext Radio Clock"
86654359Sroberto#define VARITEXT_TYPE        DCF_TYPE
86754359Sroberto#define VARITEXT_MAXUNSYNC   (60*60)       /* only trust clock for 1 hour */
86854359Sroberto#define VARITEXT_SPEED       (B9600)
86954359Sroberto#define VARITEXT_CFLAG       (CS7|CREAD|CLOCAL|PARENB|PARODD)
87054359Sroberto#define VARITEXT_IFLAG       (IGNPAR|IGNBRK|INPCK) /*|ISTRIP)*/
87154359Sroberto#define VARITEXT_OFLAG       0
87254359Sroberto#define VARITEXT_LFLAG       0
87354359Sroberto#define VARITEXT_SAMPLES     32
87454359Sroberto#define VARITEXT_KEEP        20
87554359Sroberto
876280849Scy/*
877280849Scy * SEL240x Satellite Sychronized Clock
878280849Scy */
879280849Scy#define SEL240X_POLLRATE	0 /* only true direct polling */
880280849Scy#define SEL240X_POLLCMD		"BUB8"
881280849Scy#define SEL240X_CMDSIZE		4
882280849Scy
883280849Scystatic poll_info_t sel240x_pollinfo = { SEL240X_POLLRATE,
884280849Scy	                                SEL240X_POLLCMD,
885280849Scy					SEL240X_CMDSIZE };
886280849Scy#define SEL240X_FLAGS		(PARSE_F_PPSONSECOND)
887280849Scy#define SEL240X_POLL		poll_dpoll
888280849Scy#define SEL240X_INIT		poll_init
889280849Scy#define SEL240X_END		0
890280849Scy#define SEL240X_DATA            ((void *)(&sel240x_pollinfo))
891280849Scy#define SEL240X_ROOTDELAY	0.0
892280849Scy#define SEL240X_BASEDELAY	0.0
893280849Scy#define SEL240X_ID		GPS_ID
894280849Scy#define SEL240X_DESCRIPTION	"SEL240x Satellite Synchronized Clock"
895280849Scy#define SEL240X_FORMAT		"SEL B8"
896280849Scy#define SEL240X_MAXUNSYNC	60*60*12 /* only trust clock for 12 hours */
897280849Scy#define SEL240X_SPEED		(B9600)
898280849Scy#define SEL240X_CFLAG		(CS8|CREAD|CLOCAL)
899280849Scy#define SEL240X_IFLAG		(IGNBRK|IGNPAR)
900280849Scy#define SEL240X_OFLAG		(0)
901280849Scy#define SEL240X_LFLAG		(0)
902280849Scy#define SEL240X_SAMPLES		5
903280849Scy#define SEL240X_KEEP		3
904280849Scy
90554359Srobertostatic struct parse_clockinfo
90654359Sroberto{
907280849Scy	u_long  cl_flags;		/* operation flags (PPS interpretation, trust handling) */
908280849Scy  void  (*cl_poll)    (struct parseunit *);			/* active poll routine */
909280849Scy  int   (*cl_init)    (struct parseunit *);			/* active poll init routine */
910280849Scy  void  (*cl_event)   (struct parseunit *, int);		/* special event handling (e.g. reset clock) */
911280849Scy  void  (*cl_end)     (struct parseunit *);			/* active poll end routine */
912280849Scy  void  (*cl_message) (struct parseunit *, parsetime_t *);	/* process a lower layer message */
91354359Sroberto	void   *cl_data;		/* local data area for "poll" mechanism */
91454359Sroberto	double    cl_rootdelay;		/* rootdelay */
91554359Sroberto	double    cl_basedelay;		/* current offset by which the RS232
91654359Sroberto				time code is delayed from the actual time */
91754359Sroberto	const char *cl_id;		/* ID code */
91854359Sroberto	const char *cl_description;		/* device name */
91954359Sroberto	const char *cl_format;		/* fixed format */
92054359Sroberto	u_char  cl_type;		/* clock type (ntp control) */
921132451Sroberto	u_long  cl_maxunsync;		/* time to trust oscillator after losing synch */
92254359Sroberto	u_long  cl_speed;		/* terminal input & output baudrate */
92354359Sroberto	u_long  cl_cflag;             /* terminal control flags */
92454359Sroberto	u_long  cl_iflag;             /* terminal input flags */
92554359Sroberto	u_long  cl_oflag;             /* terminal output flags */
92654359Sroberto	u_long  cl_lflag;             /* terminal local flags */
92754359Sroberto	u_long  cl_samples;	      /* samples for median filter */
92854359Sroberto	u_long  cl_keep;              /* samples for median filter to keep */
92954359Sroberto} parse_clockinfo[] =
93054359Sroberto{
93154359Sroberto	{				/* mode 0 */
93254359Sroberto		MBG_FLAGS,
93354359Sroberto		NO_POLL,
93454359Sroberto		NO_INIT,
93554359Sroberto		NO_EVENT,
93654359Sroberto		NO_END,
93754359Sroberto		NO_MESSAGE,
938182007Sroberto		NO_LCLDATA,
93954359Sroberto		DCFPZF535_ROOTDELAY,
94054359Sroberto		DCFPZF535_BASEDELAY,
94154359Sroberto		DCF_P_ID,
94254359Sroberto		DCFPZF535_DESCRIPTION,
94354359Sroberto		DCFPZF535_FORMAT,
94454359Sroberto		DCF_TYPE,
94554359Sroberto		DCFPZF535_MAXUNSYNC,
94654359Sroberto		DCFPZF535_SPEED,
94754359Sroberto		DCFPZF535_CFLAG,
94854359Sroberto		DCFPZF535_IFLAG,
94954359Sroberto		DCFPZF535_OFLAG,
95054359Sroberto		DCFPZF535_LFLAG,
95154359Sroberto		DCFPZF535_SAMPLES,
95254359Sroberto		DCFPZF535_KEEP
95354359Sroberto	},
95454359Sroberto	{				/* mode 1 */
95554359Sroberto		MBG_FLAGS,
95654359Sroberto		NO_POLL,
95754359Sroberto		NO_INIT,
95854359Sroberto		NO_EVENT,
95954359Sroberto		NO_END,
96054359Sroberto		NO_MESSAGE,
961182007Sroberto		NO_LCLDATA,
96254359Sroberto		DCFPZF535OCXO_ROOTDELAY,
96354359Sroberto		DCFPZF535OCXO_BASEDELAY,
96454359Sroberto		DCF_P_ID,
96554359Sroberto		DCFPZF535OCXO_DESCRIPTION,
96654359Sroberto		DCFPZF535OCXO_FORMAT,
96754359Sroberto		DCF_TYPE,
96854359Sroberto		DCFPZF535OCXO_MAXUNSYNC,
96954359Sroberto		DCFPZF535OCXO_SPEED,
97054359Sroberto		DCFPZF535OCXO_CFLAG,
97154359Sroberto		DCFPZF535OCXO_IFLAG,
97254359Sroberto		DCFPZF535OCXO_OFLAG,
97354359Sroberto		DCFPZF535OCXO_LFLAG,
97454359Sroberto		DCFPZF535OCXO_SAMPLES,
97554359Sroberto		DCFPZF535OCXO_KEEP
97654359Sroberto	},
97754359Sroberto	{				/* mode 2 */
97854359Sroberto		MBG_FLAGS,
97954359Sroberto		NO_POLL,
98054359Sroberto		NO_INIT,
98154359Sroberto		NO_EVENT,
98254359Sroberto		NO_END,
98354359Sroberto		NO_MESSAGE,
984182007Sroberto		NO_LCLDATA,
98554359Sroberto		DCFUA31_ROOTDELAY,
98654359Sroberto		DCFUA31_BASEDELAY,
98754359Sroberto		DCF_A_ID,
98854359Sroberto		DCFUA31_DESCRIPTION,
98954359Sroberto		DCFUA31_FORMAT,
99054359Sroberto		DCF_TYPE,
99154359Sroberto		DCFUA31_MAXUNSYNC,
99254359Sroberto		DCFUA31_SPEED,
99354359Sroberto		DCFUA31_CFLAG,
99454359Sroberto		DCFUA31_IFLAG,
99554359Sroberto		DCFUA31_OFLAG,
99654359Sroberto		DCFUA31_LFLAG,
99754359Sroberto		DCFUA31_SAMPLES,
99854359Sroberto		DCFUA31_KEEP
99954359Sroberto	},
100054359Sroberto	{				/* mode 3 */
100154359Sroberto		MBG_FLAGS,
100254359Sroberto		NO_POLL,
100354359Sroberto		NO_INIT,
100454359Sroberto		NO_EVENT,
100554359Sroberto		NO_END,
100654359Sroberto		NO_MESSAGE,
1007182007Sroberto		NO_LCLDATA,
100854359Sroberto		DCF7000_ROOTDELAY,
100954359Sroberto		DCF7000_BASEDELAY,
101054359Sroberto		DCF_A_ID,
101154359Sroberto		DCF7000_DESCRIPTION,
101254359Sroberto		DCF7000_FORMAT,
101354359Sroberto		DCF_TYPE,
101454359Sroberto		DCF7000_MAXUNSYNC,
101554359Sroberto		DCF7000_SPEED,
101654359Sroberto		DCF7000_CFLAG,
101754359Sroberto		DCF7000_IFLAG,
101854359Sroberto		DCF7000_OFLAG,
101954359Sroberto		DCF7000_LFLAG,
102054359Sroberto		DCF7000_SAMPLES,
102154359Sroberto		DCF7000_KEEP
102254359Sroberto	},
102354359Sroberto	{				/* mode 4 */
102454359Sroberto		NO_CL_FLAGS,
102554359Sroberto		WSDCF_POLL,
102654359Sroberto		WSDCF_INIT,
102754359Sroberto		NO_EVENT,
102854359Sroberto		WSDCF_END,
102954359Sroberto		NO_MESSAGE,
103054359Sroberto		WSDCF_DATA,
103154359Sroberto		WSDCF_ROOTDELAY,
103254359Sroberto		WSDCF_BASEDELAY,
103354359Sroberto		DCF_A_ID,
103454359Sroberto		WSDCF_DESCRIPTION,
103554359Sroberto		WSDCF_FORMAT,
103654359Sroberto		DCF_TYPE,
103754359Sroberto		WSDCF_MAXUNSYNC,
103854359Sroberto		WSDCF_SPEED,
103954359Sroberto		WSDCF_CFLAG,
104054359Sroberto		WSDCF_IFLAG,
104154359Sroberto		WSDCF_OFLAG,
104254359Sroberto		WSDCF_LFLAG,
104354359Sroberto		WSDCF_SAMPLES,
104454359Sroberto		WSDCF_KEEP
104554359Sroberto	},
104654359Sroberto	{				/* mode 5 */
104754359Sroberto		RAWDCF_FLAGS,
104854359Sroberto		NO_POLL,
104954359Sroberto		RAWDCF_INIT,
105054359Sroberto		NO_EVENT,
105154359Sroberto		NO_END,
105254359Sroberto		NO_MESSAGE,
1053182007Sroberto		NO_LCLDATA,
105454359Sroberto		RAWDCF_ROOTDELAY,
105554359Sroberto		CONRAD_BASEDELAY,
105654359Sroberto		DCF_A_ID,
105754359Sroberto		CONRAD_DESCRIPTION,
105854359Sroberto		RAWDCF_FORMAT,
105954359Sroberto		DCF_TYPE,
106054359Sroberto		RAWDCF_MAXUNSYNC,
106154359Sroberto		RAWDCF_SPEED,
106254359Sroberto		RAWDCF_CFLAG,
106354359Sroberto		RAWDCF_IFLAG,
106454359Sroberto		RAWDCF_OFLAG,
106554359Sroberto		RAWDCF_LFLAG,
106654359Sroberto		RAWDCF_SAMPLES,
106754359Sroberto		RAWDCF_KEEP
106854359Sroberto	},
106954359Sroberto	{				/* mode 6 */
107054359Sroberto		RAWDCF_FLAGS,
107154359Sroberto		NO_POLL,
107254359Sroberto		RAWDCF_INIT,
107354359Sroberto		NO_EVENT,
107454359Sroberto		NO_END,
107554359Sroberto		NO_MESSAGE,
1076182007Sroberto		NO_LCLDATA,
107754359Sroberto		RAWDCF_ROOTDELAY,
107854359Sroberto		TIMEBRICK_BASEDELAY,
107954359Sroberto		DCF_A_ID,
108054359Sroberto		TIMEBRICK_DESCRIPTION,
108154359Sroberto		RAWDCF_FORMAT,
108254359Sroberto		DCF_TYPE,
108354359Sroberto		RAWDCF_MAXUNSYNC,
108454359Sroberto		RAWDCF_SPEED,
108554359Sroberto		RAWDCF_CFLAG,
108654359Sroberto		RAWDCF_IFLAG,
108754359Sroberto		RAWDCF_OFLAG,
108854359Sroberto		RAWDCF_LFLAG,
108954359Sroberto		RAWDCF_SAMPLES,
109054359Sroberto		RAWDCF_KEEP
109154359Sroberto	},
109254359Sroberto	{				/* mode 7 */
109354359Sroberto		MBG_FLAGS,
109454359Sroberto		GPS16X_POLL,
109554359Sroberto		GPS16X_INIT,
109654359Sroberto		NO_EVENT,
109754359Sroberto		GPS16X_END,
109854359Sroberto		GPS16X_MESSAGE,
109954359Sroberto		GPS16X_DATA,
110054359Sroberto		GPS16X_ROOTDELAY,
110154359Sroberto		GPS16X_BASEDELAY,
110254359Sroberto		GPS16X_ID,
110354359Sroberto		GPS16X_DESCRIPTION,
110454359Sroberto		GPS16X_FORMAT,
110554359Sroberto		GPS_TYPE,
110654359Sroberto		GPS16X_MAXUNSYNC,
110754359Sroberto		GPS16X_SPEED,
110854359Sroberto		GPS16X_CFLAG,
110954359Sroberto		GPS16X_IFLAG,
111054359Sroberto		GPS16X_OFLAG,
111154359Sroberto		GPS16X_LFLAG,
111254359Sroberto		GPS16X_SAMPLES,
111354359Sroberto		GPS16X_KEEP
111454359Sroberto	},
111554359Sroberto	{				/* mode 8 */
111654359Sroberto		RAWDCF_FLAGS,
111754359Sroberto		NO_POLL,
111854359Sroberto		NO_INIT,
111954359Sroberto		NO_EVENT,
112054359Sroberto		NO_END,
112154359Sroberto		NO_MESSAGE,
1122182007Sroberto		NO_LCLDATA,
112354359Sroberto		RAWDCF_ROOTDELAY,
112454359Sroberto		IGELCLOCK_BASEDELAY,
112554359Sroberto		DCF_A_ID,
112654359Sroberto		IGELCLOCK_DESCRIPTION,
112754359Sroberto		RAWDCF_FORMAT,
112854359Sroberto		DCF_TYPE,
112954359Sroberto		RAWDCF_MAXUNSYNC,
113054359Sroberto		IGELCLOCK_SPEED,
113154359Sroberto		IGELCLOCK_CFLAG,
113254359Sroberto		RAWDCF_IFLAG,
113354359Sroberto		RAWDCF_OFLAG,
113454359Sroberto		RAWDCF_LFLAG,
113554359Sroberto		RAWDCF_SAMPLES,
113654359Sroberto		RAWDCF_KEEP
113754359Sroberto	},
113854359Sroberto	{				/* mode 9 */
113954359Sroberto		TRIMBLETAIP_FLAGS,
114054359Sroberto#if TRIM_POLLRATE		/* DHD940515: Allow user config */
114154359Sroberto		NO_POLL,
114254359Sroberto#else
114354359Sroberto		TRIMBLETAIP_POLL,
114454359Sroberto#endif
114554359Sroberto		TRIMBLETAIP_INIT,
114654359Sroberto		TRIMBLETAIP_EVENT,
114754359Sroberto		TRIMBLETAIP_END,
114854359Sroberto		NO_MESSAGE,
114954359Sroberto		TRIMBLETAIP_DATA,
115054359Sroberto		TRIMBLETAIP_ROOTDELAY,
115154359Sroberto		TRIMBLETAIP_BASEDELAY,
115254359Sroberto		TRIMBLETAIP_ID,
115354359Sroberto		TRIMBLETAIP_DESCRIPTION,
115454359Sroberto		TRIMBLETAIP_FORMAT,
115554359Sroberto		GPS_TYPE,
115654359Sroberto		TRIMBLETAIP_MAXUNSYNC,
115754359Sroberto		TRIMBLETAIP_SPEED,
115854359Sroberto		TRIMBLETAIP_CFLAG,
115954359Sroberto		TRIMBLETAIP_IFLAG,
116054359Sroberto		TRIMBLETAIP_OFLAG,
116154359Sroberto		TRIMBLETAIP_LFLAG,
116254359Sroberto		TRIMBLETAIP_SAMPLES,
116354359Sroberto		TRIMBLETAIP_KEEP
116454359Sroberto	},
116554359Sroberto	{				/* mode 10 */
116654359Sroberto		TRIMBLETSIP_FLAGS,
116754359Sroberto#if TRIM_POLLRATE		/* DHD940515: Allow user config */
116854359Sroberto		NO_POLL,
116954359Sroberto#else
117054359Sroberto		TRIMBLETSIP_POLL,
117154359Sroberto#endif
117254359Sroberto		TRIMBLETSIP_INIT,
117354359Sroberto		TRIMBLETSIP_EVENT,
117454359Sroberto		TRIMBLETSIP_END,
117554359Sroberto		TRIMBLETSIP_MESSAGE,
117654359Sroberto		TRIMBLETSIP_DATA,
117754359Sroberto		TRIMBLETSIP_ROOTDELAY,
117854359Sroberto		TRIMBLETSIP_BASEDELAY,
117954359Sroberto		TRIMBLETSIP_ID,
118054359Sroberto		TRIMBLETSIP_DESCRIPTION,
118154359Sroberto		TRIMBLETSIP_FORMAT,
118254359Sroberto		GPS_TYPE,
118354359Sroberto		TRIMBLETSIP_MAXUNSYNC,
118454359Sroberto		TRIMBLETSIP_SPEED,
118554359Sroberto		TRIMBLETSIP_CFLAG,
118654359Sroberto		TRIMBLETSIP_IFLAG,
118754359Sroberto		TRIMBLETSIP_OFLAG,
118854359Sroberto		TRIMBLETSIP_LFLAG,
118954359Sroberto		TRIMBLETSIP_SAMPLES,
119054359Sroberto		TRIMBLETSIP_KEEP
119154359Sroberto	},
119254359Sroberto	{                             /* mode 11 */
119354359Sroberto		NO_CL_FLAGS,
119454359Sroberto		RCC8000_POLL,
119554359Sroberto		RCC8000_INIT,
119654359Sroberto		NO_EVENT,
119754359Sroberto		RCC8000_END,
119854359Sroberto		NO_MESSAGE,
119954359Sroberto		RCC8000_DATA,
120054359Sroberto		RCC8000_ROOTDELAY,
120154359Sroberto		RCC8000_BASEDELAY,
120254359Sroberto		RCC8000_ID,
120354359Sroberto		RCC8000_DESCRIPTION,
120454359Sroberto		RCC8000_FORMAT,
120554359Sroberto		DCF_TYPE,
120654359Sroberto		RCC8000_MAXUNSYNC,
120754359Sroberto		RCC8000_SPEED,
120854359Sroberto		RCC8000_CFLAG,
120954359Sroberto		RCC8000_IFLAG,
121054359Sroberto		RCC8000_OFLAG,
121154359Sroberto		RCC8000_LFLAG,
121254359Sroberto		RCC8000_SAMPLES,
121354359Sroberto		RCC8000_KEEP
121454359Sroberto	},
121554359Sroberto	{                             /* mode 12 */
121654359Sroberto		HOPF6021_FLAGS,
1217282408Scy		NO_POLL,
121854359Sroberto		NO_INIT,
121954359Sroberto		NO_EVENT,
122054359Sroberto		NO_END,
122154359Sroberto		NO_MESSAGE,
1222182007Sroberto		NO_LCLDATA,
122354359Sroberto		HOPF6021_ROOTDELAY,
122454359Sroberto		HOPF6021_BASEDELAY,
122554359Sroberto		DCF_ID,
122654359Sroberto		HOPF6021_DESCRIPTION,
122754359Sroberto		HOPF6021_FORMAT,
122854359Sroberto		DCF_TYPE,
122954359Sroberto		HOPF6021_MAXUNSYNC,
123054359Sroberto		HOPF6021_SPEED,
123154359Sroberto		HOPF6021_CFLAG,
123254359Sroberto		HOPF6021_IFLAG,
123354359Sroberto		HOPF6021_OFLAG,
123454359Sroberto		HOPF6021_LFLAG,
123554359Sroberto		HOPF6021_SAMPLES,
123654359Sroberto		HOPF6021_KEEP
123754359Sroberto	},
123854359Sroberto	{                            /* mode 13 */
123954359Sroberto		COMPUTIME_FLAGS,
124054359Sroberto		NO_POLL,
124154359Sroberto		NO_INIT,
124254359Sroberto		NO_EVENT,
124354359Sroberto		NO_END,
124454359Sroberto		NO_MESSAGE,
1245182007Sroberto		NO_LCLDATA,
124654359Sroberto		COMPUTIME_ROOTDELAY,
124754359Sroberto		COMPUTIME_BASEDELAY,
124854359Sroberto		COMPUTIME_ID,
124954359Sroberto		COMPUTIME_DESCRIPTION,
125054359Sroberto		COMPUTIME_FORMAT,
125154359Sroberto		COMPUTIME_TYPE,
125254359Sroberto		COMPUTIME_MAXUNSYNC,
125354359Sroberto		COMPUTIME_SPEED,
125454359Sroberto		COMPUTIME_CFLAG,
125554359Sroberto		COMPUTIME_IFLAG,
125654359Sroberto		COMPUTIME_OFLAG,
125754359Sroberto		COMPUTIME_LFLAG,
125854359Sroberto		COMPUTIME_SAMPLES,
125954359Sroberto		COMPUTIME_KEEP
126054359Sroberto	},
126154359Sroberto	{				/* mode 14 */
126254359Sroberto		RAWDCF_FLAGS,
126354359Sroberto		NO_POLL,
126456746Sroberto		RAWDCFDTRSET_INIT,
126554359Sroberto		NO_EVENT,
126654359Sroberto		NO_END,
126754359Sroberto		NO_MESSAGE,
1268182007Sroberto		NO_LCLDATA,
126954359Sroberto		RAWDCF_ROOTDELAY,
127054359Sroberto		RAWDCF_BASEDELAY,
127154359Sroberto		DCF_A_ID,
127256746Sroberto		RAWDCFDTRSET_DESCRIPTION,
127354359Sroberto		RAWDCF_FORMAT,
127454359Sroberto		DCF_TYPE,
127554359Sroberto		RAWDCF_MAXUNSYNC,
127654359Sroberto		RAWDCF_SPEED,
127754359Sroberto		RAWDCF_CFLAG,
127854359Sroberto		RAWDCF_IFLAG,
127954359Sroberto		RAWDCF_OFLAG,
128054359Sroberto		RAWDCF_LFLAG,
128154359Sroberto		RAWDCF_SAMPLES,
128254359Sroberto		RAWDCF_KEEP
128354359Sroberto	},
128454359Sroberto	{				/* mode 15 */
128556746Sroberto		0,				/* operation flags (io modes) */
128682498Sroberto  		NO_POLL,			/* active poll routine */
128782498Sroberto		NO_INIT,			/* active poll init routine */
128856746Sroberto  		NO_EVENT,		        /* special event handling (e.g. reset clock) */
128956746Sroberto  		NO_END,				/* active poll end routine */
129056746Sroberto  		NO_MESSAGE,			/* process a lower layer message */
1291182007Sroberto		NO_LCLDATA,			/* local data area for "poll" mechanism */
129256746Sroberto		0,				/* rootdelay */
129382498Sroberto		11.0 /* bits */ / 9600,		/* current offset by which the RS232
129456746Sroberto				           	time code is delayed from the actual time */
129556746Sroberto		DCF_ID,				/* ID code */
129656746Sroberto		"WHARTON 400A Series clock",	/* device name */
129782498Sroberto		"WHARTON 400A Series clock Output Format 1",	/* fixed format */
129856746Sroberto			/* Must match a format-name in a libparse/clk_xxx.c file */
129956746Sroberto		DCF_TYPE,			/* clock type (ntp control) */
1300132451Sroberto		(1*60*60),		        /* time to trust oscillator after losing synch */
130156746Sroberto		B9600,				/* terminal input & output baudrate */
130256746Sroberto		(CS8|CREAD|PARENB|CLOCAL|HUPCL),/* terminal control flags */
130356746Sroberto		0,				/* terminal input flags */
130456746Sroberto		0,				/* terminal output flags */
130556746Sroberto		0,				/* terminal local flags */
130656746Sroberto		5,				/* samples for median filter */
130756746Sroberto		3,				/* samples for median filter to keep */
130854359Sroberto	},
130956746Sroberto	{				/* mode 16 - RAWDCF RTS set, DTR clr */
131056746Sroberto		RAWDCF_FLAGS,
131156746Sroberto		NO_POLL,
131256746Sroberto		RAWDCFDTRCLRRTSSET_INIT,
131356746Sroberto		NO_EVENT,
131456746Sroberto		NO_END,
131556746Sroberto		NO_MESSAGE,
1316182007Sroberto		NO_LCLDATA,
131756746Sroberto		RAWDCF_ROOTDELAY,
131856746Sroberto		RAWDCF_BASEDELAY,
131956746Sroberto		DCF_A_ID,
132056746Sroberto		RAWDCFDTRCLRRTSSET_DESCRIPTION,
132156746Sroberto		RAWDCF_FORMAT,
132256746Sroberto		DCF_TYPE,
132356746Sroberto		RAWDCF_MAXUNSYNC,
132456746Sroberto		RAWDCF_SPEED,
132556746Sroberto		RAWDCF_CFLAG,
132656746Sroberto		RAWDCF_IFLAG,
132756746Sroberto		RAWDCF_OFLAG,
132856746Sroberto		RAWDCF_LFLAG,
132956746Sroberto		RAWDCF_SAMPLES,
133056746Sroberto		RAWDCF_KEEP
133156746Sroberto	},
133256746Sroberto        {                            /* mode 17 */
133354359Sroberto                VARITEXT_FLAGS,
133454359Sroberto                NO_POLL,
133554359Sroberto                NO_INIT,
133654359Sroberto                NO_EVENT,
133754359Sroberto                NO_END,
133854359Sroberto                NO_MESSAGE,
1339182007Sroberto                NO_LCLDATA,
134054359Sroberto                VARITEXT_ROOTDELAY,
134154359Sroberto                VARITEXT_BASEDELAY,
134254359Sroberto                VARITEXT_ID,
134354359Sroberto                VARITEXT_DESCRIPTION,
134454359Sroberto                VARITEXT_FORMAT,
134554359Sroberto                VARITEXT_TYPE,
134654359Sroberto                VARITEXT_MAXUNSYNC,
134754359Sroberto                VARITEXT_SPEED,
134854359Sroberto                VARITEXT_CFLAG,
134954359Sroberto                VARITEXT_IFLAG,
135054359Sroberto                VARITEXT_OFLAG,
135154359Sroberto                VARITEXT_LFLAG,
135254359Sroberto                VARITEXT_SAMPLES,
135354359Sroberto                VARITEXT_KEEP
1354182007Sroberto        },
1355182007Sroberto	{				/* mode 18 */
1356182007Sroberto		MBG_FLAGS,
1357182007Sroberto		NO_POLL,
1358182007Sroberto		NO_INIT,
1359182007Sroberto		NO_EVENT,
1360182007Sroberto		GPS16X_END,
1361182007Sroberto		GPS16X_MESSAGE,
1362182007Sroberto		GPS16X_DATA,
1363182007Sroberto		GPS16X_ROOTDELAY,
1364182007Sroberto		GPS16X_BASEDELAY,
1365182007Sroberto		GPS16X_ID,
1366182007Sroberto		GPS16X_DESCRIPTION,
1367182007Sroberto		GPS16X_FORMAT,
1368182007Sroberto		GPS_TYPE,
1369182007Sroberto		GPS16X_MAXUNSYNC,
1370182007Sroberto		GPS16X_SPEED,
1371182007Sroberto		GPS16X_CFLAG,
1372182007Sroberto		GPS16X_IFLAG,
1373182007Sroberto		GPS16X_OFLAG,
1374182007Sroberto		GPS16X_LFLAG,
1375182007Sroberto		GPS16X_SAMPLES,
1376182007Sroberto		GPS16X_KEEP
1377182007Sroberto	},
1378182007Sroberto	{				/* mode 19 */
1379182007Sroberto		RAWDCF_FLAGS,
1380182007Sroberto		NO_POLL,
1381182007Sroberto		RAWDCF_INIT,
1382182007Sroberto		NO_EVENT,
1383182007Sroberto		NO_END,
1384182007Sroberto		NO_MESSAGE,
1385182007Sroberto		NO_LCLDATA,
1386182007Sroberto		RAWDCF_ROOTDELAY,
1387182007Sroberto		GUDE_EMC_USB_V20_BASEDELAY,
1388182007Sroberto		DCF_A_ID,
1389182007Sroberto		GUDE_EMC_USB_V20_DESCRIPTION,
1390182007Sroberto		RAWDCF_FORMAT,
1391182007Sroberto		DCF_TYPE,
1392182007Sroberto		RAWDCF_MAXUNSYNC,
1393182007Sroberto		GUDE_EMC_USB_V20_SPEED,
1394182007Sroberto		RAWDCF_CFLAG,
1395182007Sroberto		RAWDCF_IFLAG,
1396182007Sroberto		RAWDCF_OFLAG,
1397182007Sroberto		RAWDCF_LFLAG,
1398182007Sroberto		RAWDCF_SAMPLES,
1399182007Sroberto		RAWDCF_KEEP
1400182007Sroberto	},
1401280849Scy	{				/* mode 20, like mode 14 but driven by 75 baud */
1402280849Scy		RAWDCF_FLAGS,
1403280849Scy		NO_POLL,
1404280849Scy		RAWDCFDTRSET_INIT,
1405280849Scy		NO_EVENT,
1406280849Scy		NO_END,
1407280849Scy		NO_MESSAGE,
1408280849Scy		NO_LCLDATA,
1409280849Scy		RAWDCF_ROOTDELAY,
1410280849Scy		RAWDCF_BASEDELAY,
1411280849Scy		DCF_A_ID,
1412280849Scy		RAWDCFDTRSET75_DESCRIPTION,
1413280849Scy		RAWDCF_FORMAT,
1414280849Scy		DCF_TYPE,
1415280849Scy		RAWDCF_MAXUNSYNC,
1416280849Scy		B75,
1417280849Scy		RAWDCF_CFLAG,
1418280849Scy		RAWDCF_IFLAG,
1419280849Scy		RAWDCF_OFLAG,
1420280849Scy		RAWDCF_LFLAG,
1421280849Scy		RAWDCF_SAMPLES,
1422280849Scy		RAWDCF_KEEP
1423280849Scy	},
1424280849Scy	{				/* mode 21, like mode 16 but driven by 75 baud
1425280849Scy					 - RAWDCF RTS set, DTR clr */
1426280849Scy		RAWDCF_FLAGS,
1427280849Scy		NO_POLL,
1428280849Scy		RAWDCFDTRCLRRTSSET_INIT,
1429280849Scy		NO_EVENT,
1430280849Scy		NO_END,
1431280849Scy		NO_MESSAGE,
1432280849Scy		NO_LCLDATA,
1433280849Scy		RAWDCF_ROOTDELAY,
1434280849Scy		RAWDCF_BASEDELAY,
1435280849Scy		DCF_A_ID,
1436280849Scy		RAWDCFDTRCLRRTSSET75_DESCRIPTION,
1437280849Scy		RAWDCF_FORMAT,
1438280849Scy		DCF_TYPE,
1439280849Scy		RAWDCF_MAXUNSYNC,
1440280849Scy		B75,
1441280849Scy		RAWDCF_CFLAG,
1442280849Scy		RAWDCF_IFLAG,
1443280849Scy		RAWDCF_OFLAG,
1444280849Scy		RAWDCF_LFLAG,
1445280849Scy		RAWDCF_SAMPLES,
1446280849Scy		RAWDCF_KEEP
1447280849Scy	},
1448280849Scy	{				/* mode 22 - like 2 with POWERUP trust */
1449280849Scy		MBG_FLAGS | PARSE_F_POWERUPTRUST,
1450280849Scy		NO_POLL,
1451280849Scy		NO_INIT,
1452280849Scy		NO_EVENT,
1453280849Scy		NO_END,
1454280849Scy		NO_MESSAGE,
1455280849Scy		NO_LCLDATA,
1456280849Scy		DCFUA31_ROOTDELAY,
1457280849Scy		DCFUA31_BASEDELAY,
1458280849Scy		DCF_A_ID,
1459280849Scy		DCFUA31_DESCRIPTION,
1460280849Scy		DCFUA31_FORMAT,
1461280849Scy		DCF_TYPE,
1462280849Scy		DCFUA31_MAXUNSYNC,
1463280849Scy		DCFUA31_SPEED,
1464280849Scy		DCFUA31_CFLAG,
1465280849Scy		DCFUA31_IFLAG,
1466280849Scy		DCFUA31_OFLAG,
1467280849Scy		DCFUA31_LFLAG,
1468280849Scy		DCFUA31_SAMPLES,
1469280849Scy		DCFUA31_KEEP
1470280849Scy	},
1471280849Scy	{				/* mode 23 - like 7 with POWERUP trust */
1472280849Scy		MBG_FLAGS | PARSE_F_POWERUPTRUST,
1473280849Scy		GPS16X_POLL,
1474280849Scy		GPS16X_INIT,
1475280849Scy		NO_EVENT,
1476280849Scy		GPS16X_END,
1477280849Scy		GPS16X_MESSAGE,
1478280849Scy		GPS16X_DATA,
1479280849Scy		GPS16X_ROOTDELAY,
1480280849Scy		GPS16X_BASEDELAY,
1481280849Scy		GPS16X_ID,
1482280849Scy		GPS16X_DESCRIPTION,
1483280849Scy		GPS16X_FORMAT,
1484280849Scy		GPS_TYPE,
1485280849Scy		GPS16X_MAXUNSYNC,
1486280849Scy		GPS16X_SPEED,
1487280849Scy		GPS16X_CFLAG,
1488280849Scy		GPS16X_IFLAG,
1489280849Scy		GPS16X_OFLAG,
1490280849Scy		GPS16X_LFLAG,
1491280849Scy		GPS16X_SAMPLES,
1492280849Scy		GPS16X_KEEP
1493280849Scy	},
1494280849Scy	{				/* mode 24 */
1495280849Scy		SEL240X_FLAGS,
1496280849Scy		SEL240X_POLL,
1497280849Scy		SEL240X_INIT,
1498280849Scy		NO_EVENT,
1499280849Scy		SEL240X_END,
1500280849Scy		NO_MESSAGE,
1501280849Scy		SEL240X_DATA,
1502280849Scy		SEL240X_ROOTDELAY,
1503280849Scy		SEL240X_BASEDELAY,
1504280849Scy		SEL240X_ID,
1505280849Scy		SEL240X_DESCRIPTION,
1506280849Scy		SEL240X_FORMAT,
1507280849Scy		GPS_TYPE,
1508280849Scy		SEL240X_MAXUNSYNC,
1509280849Scy		SEL240X_SPEED,
1510280849Scy		SEL240X_CFLAG,
1511280849Scy		SEL240X_IFLAG,
1512280849Scy		SEL240X_OFLAG,
1513280849Scy		SEL240X_LFLAG,
1514280849Scy		SEL240X_SAMPLES,
1515280849Scy		SEL240X_KEEP
1516280849Scy	},
151754359Sroberto};
151854359Sroberto
151954359Srobertostatic int ncltypes = sizeof(parse_clockinfo) / sizeof(struct parse_clockinfo);
152054359Sroberto
1521132451Sroberto#define CLK_REALTYPE(x) ((int)(((x)->ttl) & 0x7F))
152254359Sroberto#define CLK_TYPE(x)	((CLK_REALTYPE(x) >= ncltypes) ? ~0 : CLK_REALTYPE(x))
152354359Sroberto#define CLK_UNIT(x)	((int)REFCLOCKUNIT(&(x)->srcadr))
1524132451Sroberto#define CLK_PPS(x)	(((x)->ttl) & 0x80)
152554359Sroberto
152654359Sroberto/*
152754359Sroberto * Other constant stuff
152854359Sroberto */
152954359Sroberto#define	PARSEHSREFID	0x7f7f08ff	/* 127.127.8.255 refid for hi strata */
153054359Sroberto
153154359Sroberto#define PARSESTATISTICS   (60*60)	        /* output state statistics every hour */
153254359Sroberto
153354359Srobertostatic int notice = 0;
153454359Sroberto
153554359Sroberto#define PARSE_STATETIME(parse, i) ((parse->generic->currentstatus == i) ? parse->statetime[i] + current_time - parse->lastchange : parse->statetime[i])
153654359Sroberto
1537280849Scystatic void parse_event   (struct parseunit *, int);
1538280849Scystatic void parse_process (struct parseunit *, parsetime_t *);
1539280849Scystatic void clear_err     (struct parseunit *, u_long);
1540280849Scystatic int  list_err      (struct parseunit *, u_long);
1541280849Scystatic char * l_mktime    (u_long);
154254359Sroberto
154354359Sroberto/**===========================================================================
154454359Sroberto ** implementation error message regression module
154554359Sroberto **/
154654359Srobertostatic void
154754359Srobertoclear_err(
154854359Sroberto	struct parseunit *parse,
154954359Sroberto	u_long            lstate
155054359Sroberto	)
155154359Sroberto{
155254359Sroberto	if (lstate == ERR_ALL)
155354359Sroberto	{
1554280849Scy		size_t i;
155554359Sroberto
155654359Sroberto		for (i = 0; i < ERR_CNT; i++)
155754359Sroberto		{
155854359Sroberto			parse->errors[i].err_stage   = err_tbl[i];
155954359Sroberto			parse->errors[i].err_cnt     = 0;
156054359Sroberto			parse->errors[i].err_last    = 0;
156154359Sroberto			parse->errors[i].err_started = 0;
156254359Sroberto			parse->errors[i].err_suppressed = 0;
156354359Sroberto		}
156454359Sroberto	}
156554359Sroberto	else
156654359Sroberto	{
156754359Sroberto		parse->errors[lstate].err_stage   = err_tbl[lstate];
156854359Sroberto		parse->errors[lstate].err_cnt     = 0;
156954359Sroberto		parse->errors[lstate].err_last    = 0;
157054359Sroberto		parse->errors[lstate].err_started = 0;
157154359Sroberto		parse->errors[lstate].err_suppressed = 0;
157254359Sroberto	}
157354359Sroberto}
157454359Sroberto
157554359Srobertostatic int
157654359Srobertolist_err(
157754359Sroberto	struct parseunit *parse,
157854359Sroberto	u_long            lstate
157954359Sroberto	)
158054359Sroberto{
158154359Sroberto	int do_it;
158254359Sroberto	struct errorinfo *err = &parse->errors[lstate];
158354359Sroberto
158454359Sroberto	if (err->err_started == 0)
158554359Sroberto	{
158654359Sroberto		err->err_started = current_time;
158754359Sroberto	}
158854359Sroberto
158954359Sroberto	do_it = (current_time - err->err_last) >= err->err_stage->err_delay;
159054359Sroberto
159154359Sroberto	if (do_it)
159254359Sroberto	    err->err_cnt++;
1593282408Scy
159454359Sroberto	if (err->err_stage->err_count &&
159554359Sroberto	    (err->err_cnt >= err->err_stage->err_count))
159654359Sroberto	{
159754359Sroberto		err->err_stage++;
159854359Sroberto		err->err_cnt = 0;
159954359Sroberto	}
160054359Sroberto
160154359Sroberto	if (!err->err_cnt && do_it)
160254359Sroberto	    msyslog(LOG_INFO, "PARSE receiver #%d: interval for following error message class is at least %s",
160354359Sroberto		    CLK_UNIT(parse->peer), l_mktime(err->err_stage->err_delay));
160454359Sroberto
160554359Sroberto	if (!do_it)
160654359Sroberto	    err->err_suppressed++;
160754359Sroberto	else
160854359Sroberto	    err->err_last = current_time;
160954359Sroberto
161054359Sroberto	if (do_it && err->err_suppressed)
161154359Sroberto	{
161254359Sroberto		msyslog(LOG_INFO, "PARSE receiver #%d: %ld message%s suppressed, error condition class persists for %s",
161354359Sroberto			CLK_UNIT(parse->peer), err->err_suppressed, (err->err_suppressed == 1) ? " was" : "s where",
161454359Sroberto			l_mktime(current_time - err->err_started));
161554359Sroberto		err->err_suppressed = 0;
161654359Sroberto	}
1617282408Scy
161854359Sroberto	return do_it;
161954359Sroberto}
162054359Sroberto
162154359Sroberto/*--------------------------------------------------
162254359Sroberto * mkreadable - make a printable ascii string (without
162354359Sroberto * embedded quotes so that the ntpq protocol isn't
162454359Sroberto * fooled
162554359Sroberto */
162654359Sroberto#ifndef isprint
162754359Sroberto#define isprint(_X_) (((_X_) > 0x1F) && ((_X_) < 0x7F))
162854359Sroberto#endif
162954359Sroberto
163054359Srobertostatic char *
163154359Srobertomkreadable(
163254359Sroberto	char  *buffer,
1633293423Sdelphij	size_t blen,
163454359Sroberto	const char  *src,
1635293423Sdelphij	size_t srclen,
163654359Sroberto	int hex
163754359Sroberto	)
163854359Sroberto{
1639280849Scy	static const char ellipsis[] = "...";
164054359Sroberto	char *b    = buffer;
1641280849Scy	char *endb = NULL;
164254359Sroberto
164354359Sroberto	if (blen < 4)
1644280849Scy		return NULL;		/* don't bother with mini buffers */
164554359Sroberto
1646280849Scy	endb = buffer + blen - sizeof(ellipsis);
164754359Sroberto
164854359Sroberto	blen--;			/* account for '\0' */
164954359Sroberto
165054359Sroberto	while (blen && srclen--)
165154359Sroberto	{
165254359Sroberto		if (!hex &&             /* no binary only */
165354359Sroberto		    (*src != '\\') &&   /* no plain \ */
165454359Sroberto		    (*src != '"') &&    /* no " */
1655280849Scy		    isprint((unsigned char)*src))	/* only printables */
165654359Sroberto		{			/* they are easy... */
165754359Sroberto			*buffer++ = *src++;
165854359Sroberto			blen--;
165954359Sroberto		}
166054359Sroberto		else
166154359Sroberto		{
166254359Sroberto			if (blen < 4)
166354359Sroberto			{
166454359Sroberto				while (blen--)
166554359Sroberto				{
166654359Sroberto					*buffer++ = '.';
166754359Sroberto				}
166854359Sroberto				*buffer = '\0';
166954359Sroberto				return b;
167054359Sroberto			}
167154359Sroberto			else
167254359Sroberto			{
167354359Sroberto				if (*src == '\\')
167454359Sroberto				{
1675280849Scy					memcpy(buffer, "\\\\", 2);
167654359Sroberto					buffer += 2;
167754359Sroberto					blen   -= 2;
167854359Sroberto					src++;
167954359Sroberto				}
168054359Sroberto				else
168154359Sroberto				{
1682280849Scy					snprintf(buffer, blen, "\\x%02x", *src++);
168354359Sroberto					blen   -= 4;
168454359Sroberto					buffer += 4;
168554359Sroberto				}
168654359Sroberto			}
168754359Sroberto		}
168854359Sroberto		if (srclen && !blen && endb) /* overflow - set last chars to ... */
1689280849Scy			memcpy(endb, ellipsis, sizeof(ellipsis));
169054359Sroberto	}
169154359Sroberto
169254359Sroberto	*buffer = '\0';
169354359Sroberto	return b;
169454359Sroberto}
169554359Sroberto
169654359Sroberto
169754359Sroberto/*--------------------------------------------------
169854359Sroberto * mkascii - make a printable ascii string
169954359Sroberto * assumes (unless defined better) 7-bit ASCII
170054359Sroberto */
170154359Srobertostatic char *
170254359Srobertomkascii(
170354359Sroberto	char  *buffer,
170454359Sroberto	long  blen,
170554359Sroberto	const char  *src,
170654359Sroberto	u_long  srclen
170754359Sroberto	)
170854359Sroberto{
170954359Sroberto	return mkreadable(buffer, blen, src, srclen, 0);
171054359Sroberto}
171154359Sroberto
171254359Sroberto/**===========================================================================
171354359Sroberto ** implementation of i/o handling methods
171454359Sroberto ** (all STREAM, partial STREAM, user level)
171554359Sroberto **/
171654359Sroberto
171754359Sroberto/*
171854359Sroberto * define possible io handling methods
171954359Sroberto */
172054359Sroberto#ifdef STREAM
1721280849Scystatic int  ppsclock_init   (struct parseunit *);
1722280849Scystatic int  stream_init     (struct parseunit *);
1723280849Scystatic void stream_end      (struct parseunit *);
1724280849Scystatic int  stream_enable   (struct parseunit *);
1725280849Scystatic int  stream_disable  (struct parseunit *);
1726280849Scystatic int  stream_setcs    (struct parseunit *, parsectl_t *);
1727280849Scystatic int  stream_getfmt   (struct parseunit *, parsectl_t *);
1728280849Scystatic int  stream_setfmt   (struct parseunit *, parsectl_t *);
1729280849Scystatic int  stream_timecode (struct parseunit *, parsectl_t *);
1730280849Scystatic void stream_receive  (struct recvbuf *);
173154359Sroberto#endif
1732282408Scy
1733280849Scystatic int  local_init     (struct parseunit *);
1734280849Scystatic void local_end      (struct parseunit *);
1735280849Scystatic int  local_nop      (struct parseunit *);
1736280849Scystatic int  local_setcs    (struct parseunit *, parsectl_t *);
1737280849Scystatic int  local_getfmt   (struct parseunit *, parsectl_t *);
1738280849Scystatic int  local_setfmt   (struct parseunit *, parsectl_t *);
1739280849Scystatic int  local_timecode (struct parseunit *, parsectl_t *);
1740280849Scystatic void local_receive  (struct recvbuf *);
1741280849Scystatic int  local_input    (struct recvbuf *);
174254359Sroberto
174354359Srobertostatic bind_t io_bindings[] =
174454359Sroberto{
174554359Sroberto#ifdef STREAM
174654359Sroberto	{
174754359Sroberto		"parse STREAM",
174854359Sroberto		stream_init,
174954359Sroberto		stream_end,
175054359Sroberto		stream_setcs,
175154359Sroberto		stream_disable,
175254359Sroberto		stream_enable,
175354359Sroberto		stream_getfmt,
175454359Sroberto		stream_setfmt,
175554359Sroberto		stream_timecode,
175654359Sroberto		stream_receive,
175754359Sroberto		0,
175854359Sroberto	},
175954359Sroberto	{
176054359Sroberto		"ppsclock STREAM",
176154359Sroberto		ppsclock_init,
176254359Sroberto		local_end,
176354359Sroberto		local_setcs,
176454359Sroberto		local_nop,
176554359Sroberto		local_nop,
176654359Sroberto		local_getfmt,
176754359Sroberto		local_setfmt,
176854359Sroberto		local_timecode,
176954359Sroberto		local_receive,
177054359Sroberto		local_input,
177154359Sroberto	},
177254359Sroberto#endif
177354359Sroberto	{
177454359Sroberto		"normal",
177554359Sroberto		local_init,
177654359Sroberto		local_end,
177754359Sroberto		local_setcs,
177854359Sroberto		local_nop,
177954359Sroberto		local_nop,
178054359Sroberto		local_getfmt,
178154359Sroberto		local_setfmt,
178254359Sroberto		local_timecode,
178354359Sroberto		local_receive,
178454359Sroberto		local_input,
178554359Sroberto	},
178654359Sroberto	{
178754359Sroberto		(char *)0,
1788280849Scy		NULL,
1789280849Scy		NULL,
1790280849Scy		NULL,
1791280849Scy		NULL,
1792280849Scy		NULL,
1793280849Scy		NULL,
1794280849Scy		NULL,
1795280849Scy		NULL,
1796280849Scy		NULL,
1797280849Scy		NULL,
179854359Sroberto	}
179954359Sroberto};
180054359Sroberto
180154359Sroberto#ifdef STREAM
180254359Sroberto
180354359Sroberto/*--------------------------------------------------
180454359Sroberto * ppsclock STREAM init
180554359Sroberto */
180654359Srobertostatic int
180754359Srobertoppsclock_init(
180854359Sroberto	struct parseunit *parse
180954359Sroberto	)
181054359Sroberto{
181154359Sroberto        static char m1[] = "ppsclocd";
181254359Sroberto	static char m2[] = "ppsclock";
1813282408Scy
181454359Sroberto	/*
181554359Sroberto	 * now push the parse streams module
181654359Sroberto	 * it will ensure exclusive access to the device
181754359Sroberto	 */
1818182007Sroberto	if (ioctl(parse->ppsfd, I_PUSH, (caddr_t)m1) == -1 &&
1819182007Sroberto	    ioctl(parse->ppsfd, I_PUSH, (caddr_t)m2) == -1)
182054359Sroberto	{
182154359Sroberto		if (errno != EINVAL)
182256746Sroberto		{
182356746Sroberto			msyslog(LOG_ERR, "PARSE receiver #%d: ppsclock_init: ioctl(fd, I_PUSH, \"ppsclock\"): %m",
182456746Sroberto				CLK_UNIT(parse->peer));
182554359Sroberto		}
182654359Sroberto		return 0;
182754359Sroberto	}
182854359Sroberto	if (!local_init(parse))
182954359Sroberto	{
1830182007Sroberto		(void)ioctl(parse->ppsfd, I_POP, (caddr_t)0);
183154359Sroberto		return 0;
183254359Sroberto	}
183354359Sroberto
183454359Sroberto	parse->flags |= PARSE_PPSCLOCK;
183554359Sroberto	return 1;
183654359Sroberto}
183754359Sroberto
183854359Sroberto/*--------------------------------------------------
183954359Sroberto * parse STREAM init
184054359Sroberto */
184154359Srobertostatic int
184254359Srobertostream_init(
184354359Sroberto	struct parseunit *parse
184454359Sroberto	)
184554359Sroberto{
184654359Sroberto	static char m1[] = "parse";
184754359Sroberto	/*
184854359Sroberto	 * now push the parse streams module
184954359Sroberto	 * to test whether it is there (neat interface 8-( )
185054359Sroberto	 */
185154359Sroberto	if (ioctl(parse->generic->io.fd, I_PUSH, (caddr_t)m1) == -1)
185254359Sroberto	{
185354359Sroberto		if (errno != EINVAL) /* accept non-existence */
185456746Sroberto		{
185556746Sroberto			msyslog(LOG_ERR, "PARSE receiver #%d: stream_init: ioctl(fd, I_PUSH, \"parse\"): %m", CLK_UNIT(parse->peer));
185654359Sroberto		}
185754359Sroberto		return 0;
185854359Sroberto	}
185954359Sroberto	else
186054359Sroberto	{
186154359Sroberto		while(ioctl(parse->generic->io.fd, I_POP, (caddr_t)0) == 0)
186254359Sroberto		    /* empty loop */;
186354359Sroberto
186454359Sroberto		/*
186554359Sroberto		 * now push it a second time after we have removed all
186654359Sroberto		 * module garbage
186754359Sroberto		 */
186854359Sroberto		if (ioctl(parse->generic->io.fd, I_PUSH, (caddr_t)m1) == -1)
186954359Sroberto		{
187054359Sroberto			msyslog(LOG_ERR, "PARSE receiver #%d: stream_init: ioctl(fd, I_PUSH, \"parse\"): %m", CLK_UNIT(parse->peer));
187154359Sroberto			return 0;
187254359Sroberto		}
187354359Sroberto		else
187454359Sroberto		{
187554359Sroberto			return 1;
187654359Sroberto		}
187754359Sroberto	}
187854359Sroberto}
187954359Sroberto
188054359Sroberto/*--------------------------------------------------
188154359Sroberto * parse STREAM end
188254359Sroberto */
188354359Srobertostatic void
188454359Srobertostream_end(
188554359Sroberto	struct parseunit *parse
188654359Sroberto	)
188754359Sroberto{
188854359Sroberto	while(ioctl(parse->generic->io.fd, I_POP, (caddr_t)0) == 0)
188954359Sroberto	    /* empty loop */;
189054359Sroberto}
189154359Sroberto
189254359Sroberto/*--------------------------------------------------
189354359Sroberto * STREAM setcs
189454359Sroberto */
189554359Srobertostatic int
189654359Srobertostream_setcs(
189754359Sroberto	struct parseunit *parse,
189854359Sroberto	parsectl_t  *tcl
189954359Sroberto	)
190054359Sroberto{
190154359Sroberto	struct strioctl strioc;
1902282408Scy
190354359Sroberto	strioc.ic_cmd     = PARSEIOC_SETCS;
190454359Sroberto	strioc.ic_timout  = 0;
190554359Sroberto	strioc.ic_dp      = (char *)tcl;
190654359Sroberto	strioc.ic_len     = sizeof (*tcl);
190754359Sroberto
190854359Sroberto	if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1)
190954359Sroberto	{
191054359Sroberto		msyslog(LOG_ERR, "PARSE receiver #%d: stream_setcs: ioctl(fd, I_STR, PARSEIOC_SETCS): %m", CLK_UNIT(parse->peer));
191154359Sroberto		return 0;
191254359Sroberto	}
191354359Sroberto	return 1;
191454359Sroberto}
191554359Sroberto
191654359Sroberto/*--------------------------------------------------
191754359Sroberto * STREAM enable
191854359Sroberto */
191954359Srobertostatic int
192054359Srobertostream_enable(
192154359Sroberto	struct parseunit *parse
192254359Sroberto	)
192354359Sroberto{
192454359Sroberto	struct strioctl strioc;
1925282408Scy
192654359Sroberto	strioc.ic_cmd     = PARSEIOC_ENABLE;
192754359Sroberto	strioc.ic_timout  = 0;
192854359Sroberto	strioc.ic_dp      = (char *)0;
192954359Sroberto	strioc.ic_len     = 0;
193054359Sroberto
193154359Sroberto	if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1)
193254359Sroberto	{
193354359Sroberto		msyslog(LOG_ERR, "PARSE receiver #%d: stream_enable: ioctl(fd, I_STR, PARSEIOC_ENABLE): %m", CLK_UNIT(parse->peer));
193454359Sroberto		return 0;
193554359Sroberto	}
193654359Sroberto	parse->generic->io.clock_recv = stream_receive; /* ok - parse input in kernel */
193754359Sroberto	return 1;
193854359Sroberto}
193954359Sroberto
194054359Sroberto/*--------------------------------------------------
194154359Sroberto * STREAM disable
194254359Sroberto */
194354359Srobertostatic int
194454359Srobertostream_disable(
194554359Sroberto	struct parseunit *parse
194654359Sroberto	)
194754359Sroberto{
194854359Sroberto	struct strioctl strioc;
1949282408Scy
195054359Sroberto	strioc.ic_cmd     = PARSEIOC_DISABLE;
195154359Sroberto	strioc.ic_timout  = 0;
195254359Sroberto	strioc.ic_dp      = (char *)0;
195354359Sroberto	strioc.ic_len     = 0;
195454359Sroberto
195554359Sroberto	if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1)
195654359Sroberto	{
195754359Sroberto		msyslog(LOG_ERR, "PARSE receiver #%d: stream_disable: ioctl(fd, I_STR, PARSEIOC_DISABLE): %m", CLK_UNIT(parse->peer));
195854359Sroberto		return 0;
195954359Sroberto	}
196054359Sroberto	parse->generic->io.clock_recv = local_receive; /* ok - parse input in daemon */
196154359Sroberto	return 1;
196254359Sroberto}
196354359Sroberto
196454359Sroberto/*--------------------------------------------------
196554359Sroberto * STREAM getfmt
196654359Sroberto */
196754359Srobertostatic int
196854359Srobertostream_getfmt(
196954359Sroberto	struct parseunit *parse,
197054359Sroberto	parsectl_t  *tcl
197154359Sroberto	)
197254359Sroberto{
197354359Sroberto	struct strioctl strioc;
1974282408Scy
197554359Sroberto	strioc.ic_cmd     = PARSEIOC_GETFMT;
197654359Sroberto	strioc.ic_timout  = 0;
197754359Sroberto	strioc.ic_dp      = (char *)tcl;
197854359Sroberto	strioc.ic_len     = sizeof (*tcl);
197954359Sroberto	if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1)
198054359Sroberto	{
198154359Sroberto		msyslog(LOG_ERR, "PARSE receiver #%d: ioctl(fd, I_STR, PARSEIOC_GETFMT): %m", CLK_UNIT(parse->peer));
198254359Sroberto		return 0;
198354359Sroberto	}
198454359Sroberto	return 1;
198554359Sroberto}
198654359Sroberto
198754359Sroberto/*--------------------------------------------------
198854359Sroberto * STREAM setfmt
198954359Sroberto */
199054359Srobertostatic int
199154359Srobertostream_setfmt(
199254359Sroberto	struct parseunit *parse,
199354359Sroberto	parsectl_t  *tcl
199454359Sroberto	)
199554359Sroberto{
199654359Sroberto	struct strioctl strioc;
1997282408Scy
199854359Sroberto	strioc.ic_cmd     = PARSEIOC_SETFMT;
199954359Sroberto	strioc.ic_timout  = 0;
200054359Sroberto	strioc.ic_dp      = (char *)tcl;
200154359Sroberto	strioc.ic_len     = sizeof (*tcl);
200254359Sroberto
200354359Sroberto	if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1)
200454359Sroberto	{
200554359Sroberto		msyslog(LOG_ERR, "PARSE receiver #%d: stream_setfmt: ioctl(fd, I_STR, PARSEIOC_SETFMT): %m", CLK_UNIT(parse->peer));
200654359Sroberto		return 0;
200754359Sroberto	}
200854359Sroberto	return 1;
200954359Sroberto}
201054359Sroberto
201154359Sroberto
201254359Sroberto/*--------------------------------------------------
201354359Sroberto * STREAM timecode
201454359Sroberto */
201554359Srobertostatic int
201654359Srobertostream_timecode(
201754359Sroberto	struct parseunit *parse,
201854359Sroberto	parsectl_t  *tcl
201954359Sroberto	)
202054359Sroberto{
202154359Sroberto	struct strioctl strioc;
2022282408Scy
202354359Sroberto	strioc.ic_cmd     = PARSEIOC_TIMECODE;
202454359Sroberto	strioc.ic_timout  = 0;
202554359Sroberto	strioc.ic_dp      = (char *)tcl;
202654359Sroberto	strioc.ic_len     = sizeof (*tcl);
2027282408Scy
202854359Sroberto	if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1)
202954359Sroberto	{
203054359Sroberto		ERR(ERR_INTERNAL)
203154359Sroberto			msyslog(LOG_ERR, "PARSE receiver #%d: stream_timecode: ioctl(fd, I_STR, PARSEIOC_TIMECODE): %m", CLK_UNIT(parse->peer));
203254359Sroberto		return 0;
203354359Sroberto	}
203454359Sroberto	clear_err(parse, ERR_INTERNAL);
203554359Sroberto	return 1;
203654359Sroberto}
203754359Sroberto
203854359Sroberto/*--------------------------------------------------
203954359Sroberto * STREAM receive
204054359Sroberto */
204154359Srobertostatic void
204254359Srobertostream_receive(
204354359Sroberto	struct recvbuf *rbufp
204454359Sroberto	)
204554359Sroberto{
2046280849Scy	struct parseunit * parse;
204754359Sroberto	parsetime_t parsetime;
204854359Sroberto
2049280849Scy	parse = (struct parseunit *)rbufp->recv_peer->procptr->unitptr;
205054359Sroberto	if (!parse->peer)
205154359Sroberto	    return;
205254359Sroberto
205354359Sroberto	if (rbufp->recv_length != sizeof(parsetime_t))
205454359Sroberto	{
205554359Sroberto		ERR(ERR_BADIO)
205654359Sroberto			msyslog(LOG_ERR,"PARSE receiver #%d: stream_receive: bad size (got %d expected %d)",
205754359Sroberto				CLK_UNIT(parse->peer), rbufp->recv_length, (int)sizeof(parsetime_t));
205854359Sroberto		parse_event(parse, CEVNT_BADREPLY);
205954359Sroberto		return;
206054359Sroberto	}
206154359Sroberto	clear_err(parse, ERR_BADIO);
2062282408Scy
206354359Sroberto	memmove((caddr_t)&parsetime,
206454359Sroberto		(caddr_t)rbufp->recv_buffer,
206554359Sroberto		sizeof(parsetime_t));
206654359Sroberto
206754359Sroberto#ifdef DEBUG
206854359Sroberto	if (debug > 3)
206954359Sroberto	  {
207054359Sroberto	    printf("PARSE receiver #%d: status %06x, state %08x, time %lx.%08lx, stime %lx.%08lx, ptime %lx.%08lx\n",
207154359Sroberto		   CLK_UNIT(parse->peer),
207254359Sroberto		   (unsigned int)parsetime.parse_status,
207354359Sroberto		   (unsigned int)parsetime.parse_state,
2074182007Sroberto		   (unsigned long)parsetime.parse_time.tv.tv_sec,
2075182007Sroberto		   (unsigned long)parsetime.parse_time.tv.tv_usec,
2076182007Sroberto		   (unsigned long)parsetime.parse_stime.tv.tv_sec,
2077182007Sroberto		   (unsigned long)parsetime.parse_stime.tv.tv_usec,
2078182007Sroberto		   (unsigned long)parsetime.parse_ptime.tv.tv_sec,
2079182007Sroberto		   (unsigned long)parsetime.parse_ptime.tv.tv_usec);
208054359Sroberto	  }
208154359Sroberto#endif
208254359Sroberto
208354359Sroberto	/*
208454359Sroberto	 * switch time stamp world - be sure to normalize small usec field
208554359Sroberto	 * errors.
208654359Sroberto	 */
208754359Sroberto
2088280849Scy	parsetime.parse_stime.fp = tval_stamp_to_lfp(parsetime.parse_stime.tv);
208954359Sroberto
209054359Sroberto	if (PARSE_TIMECODE(parsetime.parse_state))
209154359Sroberto	{
2092280849Scy		parsetime.parse_time.fp = tval_stamp_to_lfp(parsetime.parse_time.tv);
209354359Sroberto	}
209454359Sroberto
209554359Sroberto	if (PARSE_PPS(parsetime.parse_state))
2096280849Scy	{
2097280849Scy		parsetime.parse_ptime.fp = tval_stamp_to_lfp(parsetime.parse_ptime.tv);
2098280849Scy	}
209954359Sroberto
210054359Sroberto	parse_process(parse, &parsetime);
210154359Sroberto}
210254359Sroberto#endif
210354359Sroberto
210454359Sroberto/*--------------------------------------------------
210554359Sroberto * local init
210654359Sroberto */
210754359Srobertostatic int
210854359Srobertolocal_init(
210954359Sroberto	struct parseunit *parse
211054359Sroberto	)
211154359Sroberto{
211254359Sroberto	return parse_ioinit(&parse->parseio);
211354359Sroberto}
211454359Sroberto
211554359Sroberto/*--------------------------------------------------
211654359Sroberto * local end
211754359Sroberto */
211854359Srobertostatic void
211954359Srobertolocal_end(
212054359Sroberto	struct parseunit *parse
212154359Sroberto	)
212254359Sroberto{
212354359Sroberto	parse_ioend(&parse->parseio);
212454359Sroberto}
212554359Sroberto
212654359Sroberto
212754359Sroberto/*--------------------------------------------------
212854359Sroberto * local nop
212954359Sroberto */
213054359Srobertostatic int
213154359Srobertolocal_nop(
213254359Sroberto	struct parseunit *parse
213354359Sroberto	)
213454359Sroberto{
213554359Sroberto	return 1;
213654359Sroberto}
213754359Sroberto
213854359Sroberto/*--------------------------------------------------
213954359Sroberto * local setcs
214054359Sroberto */
214154359Srobertostatic int
214254359Srobertolocal_setcs(
214354359Sroberto	struct parseunit *parse,
214454359Sroberto	parsectl_t  *tcl
214554359Sroberto	)
214654359Sroberto{
214754359Sroberto	return parse_setcs(tcl, &parse->parseio);
214854359Sroberto}
214954359Sroberto
215054359Sroberto/*--------------------------------------------------
215154359Sroberto * local getfmt
215254359Sroberto */
215354359Srobertostatic int
215454359Srobertolocal_getfmt(
215554359Sroberto	struct parseunit *parse,
215654359Sroberto	parsectl_t  *tcl
215754359Sroberto	)
215854359Sroberto{
215954359Sroberto	return parse_getfmt(tcl, &parse->parseio);
216054359Sroberto}
216154359Sroberto
216254359Sroberto/*--------------------------------------------------
216354359Sroberto * local setfmt
216454359Sroberto */
216554359Srobertostatic int
216654359Srobertolocal_setfmt(
216754359Sroberto	struct parseunit *parse,
216854359Sroberto	parsectl_t  *tcl
216954359Sroberto	)
217054359Sroberto{
217154359Sroberto	return parse_setfmt(tcl, &parse->parseio);
217254359Sroberto}
217354359Sroberto
217454359Sroberto/*--------------------------------------------------
217554359Sroberto * local timecode
217654359Sroberto */
217754359Srobertostatic int
217854359Srobertolocal_timecode(
217954359Sroberto	struct parseunit *parse,
218054359Sroberto	parsectl_t  *tcl
218154359Sroberto	)
218254359Sroberto{
218354359Sroberto	return parse_timecode(tcl, &parse->parseio);
218454359Sroberto}
218554359Sroberto
218654359Sroberto
218754359Sroberto/*--------------------------------------------------
218854359Sroberto * local input
218954359Sroberto */
219054359Srobertostatic int
219154359Srobertolocal_input(
219254359Sroberto	struct recvbuf *rbufp
219354359Sroberto	)
219454359Sroberto{
2195280849Scy	struct parseunit * parse;
2196280849Scy
219754359Sroberto	int count;
219854359Sroberto	unsigned char *s;
219954359Sroberto	timestamp_t ts;
220054359Sroberto
2201280849Scy	parse = (struct parseunit *)rbufp->recv_peer->procptr->unitptr;
220254359Sroberto	if (!parse->peer)
220354359Sroberto		return 0;
220454359Sroberto
220554359Sroberto	/*
220654359Sroberto	 * eat all characters, parsing then and feeding complete samples
220754359Sroberto	 */
220854359Sroberto	count = rbufp->recv_length;
220954359Sroberto	s = (unsigned char *)rbufp->recv_buffer;
221054359Sroberto	ts.fp = rbufp->recv_time;
221154359Sroberto
221254359Sroberto	while (count--)
221354359Sroberto	{
221454359Sroberto		if (parse_ioread(&parse->parseio, (unsigned int)(*s++), &ts))
221554359Sroberto		{
2216182007Sroberto			struct recvbuf *buf;
221754359Sroberto
221854359Sroberto			/*
221954359Sroberto			 * got something good to eat
222054359Sroberto			 */
222154359Sroberto			if (!PARSE_PPS(parse->parseio.parse_dtime.parse_state))
222254359Sroberto			{
2223182007Sroberto#ifdef HAVE_PPSAPI
2224182007Sroberto				if (parse->flags & PARSE_PPSCLOCK)
2225182007Sroberto				{
2226182007Sroberto					struct timespec pps_timeout;
2227182007Sroberto					pps_info_t      pps_info;
2228282408Scy
2229182007Sroberto					pps_timeout.tv_sec  = 0;
2230182007Sroberto					pps_timeout.tv_nsec = 0;
2231182007Sroberto
2232280849Scy					if (time_pps_fetch(parse->atom.handle, PPS_TSFMT_TSPEC, &pps_info,
2233182007Sroberto							   &pps_timeout) == 0)
2234182007Sroberto					{
2235182007Sroberto						if (pps_info.assert_sequence + pps_info.clear_sequence != parse->ppsserial)
2236182007Sroberto						{
2237182007Sroberto							double dtemp;
2238182007Sroberto
2239182007Sroberto						        struct timespec pts;
2240182007Sroberto							/*
2241182007Sroberto							 * add PPS time stamp if available via ppsclock module
2242182007Sroberto							 * and not supplied already.
2243182007Sroberto							 */
2244182007Sroberto							if (parse->flags & PARSE_CLEAR)
2245182007Sroberto							  pts = pps_info.clear_timestamp;
2246182007Sroberto							else
2247182007Sroberto							  pts = pps_info.assert_timestamp;
2248182007Sroberto
2249282408Scy							parse->parseio.parse_dtime.parse_ptime.fp.l_ui = (uint32_t) (pts.tv_sec + JAN_1970);
2250182007Sroberto
2251282408Scy							dtemp = (double) pts.tv_nsec / 1e9;
2252182007Sroberto							if (dtemp < 0.) {
2253182007Sroberto								dtemp += 1;
2254182007Sroberto								parse->parseio.parse_dtime.parse_ptime.fp.l_ui--;
2255182007Sroberto							}
2256182007Sroberto							if (dtemp > 1.) {
2257182007Sroberto								dtemp -= 1;
2258182007Sroberto								parse->parseio.parse_dtime.parse_ptime.fp.l_ui++;
2259182007Sroberto							}
2260282408Scy							parse->parseio.parse_dtime.parse_ptime.fp.l_uf = (uint32_t)(dtemp * FRAC);
2261182007Sroberto
2262282408Scy							parse->parseio.parse_dtime.parse_state |= PARSEB_PPS|PARSEB_S_PPS;
2263182007Sroberto#ifdef DEBUG
2264182007Sroberto							if (debug > 3)
2265182007Sroberto							{
2266182007Sroberto								printf(
2267301247Sdelphij								       "parse: local_receive: fd %ld PPSAPI seq %ld - PPS %s\n",
2268301247Sdelphij								       (long)rbufp->fd,
2269182007Sroberto								       (long)pps_info.assert_sequence + (long)pps_info.clear_sequence,
2270182007Sroberto								       lfptoa(&parse->parseio.parse_dtime.parse_ptime.fp, 6));
2271182007Sroberto							}
2272182007Sroberto#endif
2273182007Sroberto						}
2274182007Sroberto#ifdef DEBUG
2275182007Sroberto						else
2276182007Sroberto						{
2277182007Sroberto							if (debug > 3)
2278182007Sroberto							{
2279182007Sroberto								printf(
2280301247Sdelphij								       "parse: local_receive: fd %ld PPSAPI seq assert %ld, seq clear %ld - NO PPS event\n",
2281301247Sdelphij								       (long)rbufp->fd,
2282182007Sroberto								       (long)pps_info.assert_sequence, (long)pps_info.clear_sequence);
2283182007Sroberto							}
2284182007Sroberto						}
2285182007Sroberto#endif
2286182007Sroberto						parse->ppsserial = pps_info.assert_sequence + pps_info.clear_sequence;
2287182007Sroberto					}
2288182007Sroberto#ifdef DEBUG
2289182007Sroberto					else
2290182007Sroberto					{
2291182007Sroberto						if (debug > 3)
2292182007Sroberto						{
2293182007Sroberto							printf(
2294301247Sdelphij							       "parse: local_receive: fd %ld PPSAPI time_pps_fetch errno = %d\n",
2295301247Sdelphij							       (long)rbufp->fd,
2296182007Sroberto							       errno);
2297182007Sroberto						}
2298182007Sroberto					}
2299182007Sroberto#endif
2300182007Sroberto				}
2301182007Sroberto#else
230254359Sroberto#ifdef TIOCDCDTIMESTAMP
230354359Sroberto				struct timeval dcd_time;
2304282408Scy
2305182007Sroberto				if (ioctl(parse->ppsfd, TIOCDCDTIMESTAMP, &dcd_time) != -1)
230654359Sroberto				{
230754359Sroberto					l_fp tstmp;
2308282408Scy
230954359Sroberto					TVTOTS(&dcd_time, &tstmp);
231054359Sroberto					tstmp.l_ui += JAN_1970;
231154359Sroberto					L_SUB(&ts.fp, &tstmp);
231254359Sroberto					if (ts.fp.l_ui == 0)
231354359Sroberto					{
231454359Sroberto#ifdef DEBUG
231554359Sroberto						if (debug)
231654359Sroberto						{
231754359Sroberto							printf(
231854359Sroberto							       "parse: local_receive: fd %d DCDTIMESTAMP %s\n",
2319182007Sroberto							       parse->ppsfd,
232054359Sroberto							       lfptoa(&tstmp, 6));
232154359Sroberto							printf(" sigio %s\n",
232254359Sroberto							       lfptoa(&ts.fp, 6));
232354359Sroberto						}
232454359Sroberto#endif
232554359Sroberto						parse->parseio.parse_dtime.parse_ptime.fp = tstmp;
232654359Sroberto						parse->parseio.parse_dtime.parse_state |= PARSEB_PPS|PARSEB_S_PPS;
232754359Sroberto					}
232854359Sroberto				}
232954359Sroberto#else /* TIOCDCDTIMESTAMP */
233054359Sroberto#if defined(HAVE_STRUCT_PPSCLOCKEV) && (defined(HAVE_CIOGETEV) || defined(HAVE_TIOCGPPSEV))
233154359Sroberto				if (parse->flags & PARSE_PPSCLOCK)
2332182007Sroberto				  {
2333182007Sroberto				    l_fp tts;
2334182007Sroberto				    struct ppsclockev ev;
233554359Sroberto
233654359Sroberto#ifdef HAVE_CIOGETEV
2337182007Sroberto				    if (ioctl(parse->ppsfd, CIOGETEV, (caddr_t)&ev) == 0)
233854359Sroberto#endif
233954359Sroberto#ifdef HAVE_TIOCGPPSEV
2340182007Sroberto				    if (ioctl(parse->ppsfd, TIOCGPPSEV, (caddr_t)&ev) == 0)
234154359Sroberto#endif
234254359Sroberto					{
2343182007Sroberto					  if (ev.serial != parse->ppsserial)
2344182007Sroberto					    {
2345182007Sroberto					      /*
2346182007Sroberto					       * add PPS time stamp if available via ppsclock module
2347182007Sroberto					       * and not supplied already.
2348182007Sroberto					       */
2349182007Sroberto					      if (!buftvtots((const char *)&ev.tv, &tts))
235054359Sroberto						{
2351182007Sroberto						  ERR(ERR_BADDATA)
2352182007Sroberto						    msyslog(LOG_ERR,"parse: local_receive: timestamp conversion error (buftvtots) (ppsclockev.tv)");
235354359Sroberto						}
2354182007Sroberto					      else
2355182007Sroberto						{
2356182007Sroberto						  parse->parseio.parse_dtime.parse_ptime.fp = tts;
2357182007Sroberto						  parse->parseio.parse_dtime.parse_state |= PARSEB_PPS|PARSEB_S_PPS;
2358182007Sroberto						}
2359182007Sroberto					    }
2360182007Sroberto					  parse->ppsserial = ev.serial;
236154359Sroberto					}
2362182007Sroberto				  }
236354359Sroberto#endif
236454359Sroberto#endif /* TIOCDCDTIMESTAMP */
2365182007Sroberto#endif /* !HAVE_PPSAPI */
236654359Sroberto			}
236754359Sroberto			if (count)
236854359Sroberto			{	/* simulate receive */
2369362716Scy				buf = get_free_recv_buffer(TRUE);
2370182007Sroberto				if (buf != NULL) {
2371182007Sroberto					memmove((caddr_t)buf->recv_buffer,
2372182007Sroberto						(caddr_t)&parse->parseio.parse_dtime,
2373182007Sroberto						sizeof(parsetime_t));
2374182007Sroberto					buf->recv_length  = sizeof(parsetime_t);
2375182007Sroberto					buf->recv_time    = rbufp->recv_time;
2376280849Scy#ifndef HAVE_IO_COMPLETION_PORT
2377182007Sroberto					buf->srcadr       = rbufp->srcadr;
2378280849Scy#endif
2379182007Sroberto					buf->dstadr       = rbufp->dstadr;
2380182007Sroberto					buf->receiver     = rbufp->receiver;
2381182007Sroberto					buf->fd           = rbufp->fd;
2382182007Sroberto					buf->X_from_where = rbufp->X_from_where;
2383280849Scy					parse->generic->io.recvcount++;
2384280849Scy					packets_received++;
2385182007Sroberto					add_full_recv_buffer(buf);
2386280849Scy#ifdef HAVE_IO_COMPLETION_PORT
2387280849Scy					SetEvent(WaitableIoEventHandle);
2388280849Scy#endif
2389182007Sroberto				}
239054359Sroberto				parse_iodone(&parse->parseio);
239154359Sroberto			}
239254359Sroberto			else
239354359Sroberto			{
239456746Sroberto				memmove((caddr_t)rbufp->recv_buffer,
239556746Sroberto					(caddr_t)&parse->parseio.parse_dtime,
239656746Sroberto					sizeof(parsetime_t));
239756746Sroberto				parse_iodone(&parse->parseio);
239854359Sroberto				rbufp->recv_length = sizeof(parsetime_t);
239954359Sroberto				return 1; /* got something & in place return */
240054359Sroberto			}
240154359Sroberto		}
240254359Sroberto	}
240354359Sroberto	return 0;		/* nothing to pass up */
240454359Sroberto}
240554359Sroberto
240654359Sroberto/*--------------------------------------------------
240754359Sroberto * local receive
240854359Sroberto */
240954359Srobertostatic void
241054359Srobertolocal_receive(
241154359Sroberto	struct recvbuf *rbufp
241254359Sroberto	)
241354359Sroberto{
2414280849Scy	struct parseunit * parse;
241554359Sroberto	parsetime_t parsetime;
241654359Sroberto
2417280849Scy	parse = (struct parseunit *)rbufp->recv_peer->procptr->unitptr;
241854359Sroberto	if (!parse->peer)
241954359Sroberto	    return;
242054359Sroberto
242154359Sroberto	if (rbufp->recv_length != sizeof(parsetime_t))
242254359Sroberto	{
242354359Sroberto		ERR(ERR_BADIO)
242454359Sroberto			msyslog(LOG_ERR,"PARSE receiver #%d: local_receive: bad size (got %d expected %d)",
242554359Sroberto				CLK_UNIT(parse->peer), rbufp->recv_length, (int)sizeof(parsetime_t));
242654359Sroberto		parse_event(parse, CEVNT_BADREPLY);
242754359Sroberto		return;
242854359Sroberto	}
242954359Sroberto	clear_err(parse, ERR_BADIO);
2430282408Scy
243154359Sroberto	memmove((caddr_t)&parsetime,
243254359Sroberto		(caddr_t)rbufp->recv_buffer,
243354359Sroberto		sizeof(parsetime_t));
243454359Sroberto
243554359Sroberto#ifdef DEBUG
243654359Sroberto	if (debug > 3)
243754359Sroberto	  {
2438182007Sroberto	    printf("PARSE receiver #%d: status %06x, state %08x, time(fp) %lx.%08lx, stime(fp) %lx.%08lx, ptime(fp) %lx.%08lx\n",
243954359Sroberto		   CLK_UNIT(parse->peer),
244054359Sroberto		   (unsigned int)parsetime.parse_status,
244154359Sroberto		   (unsigned int)parsetime.parse_state,
2442182007Sroberto		   (unsigned long)parsetime.parse_time.fp.l_ui,
2443182007Sroberto		   (unsigned long)parsetime.parse_time.fp.l_uf,
2444182007Sroberto		   (unsigned long)parsetime.parse_stime.fp.l_ui,
2445182007Sroberto		   (unsigned long)parsetime.parse_stime.fp.l_uf,
2446182007Sroberto		   (unsigned long)parsetime.parse_ptime.fp.l_ui,
2447182007Sroberto		   (unsigned long)parsetime.parse_ptime.fp.l_uf);
244854359Sroberto	  }
244954359Sroberto#endif
245054359Sroberto
245154359Sroberto	parse_process(parse, &parsetime);
245254359Sroberto}
245354359Sroberto
245454359Sroberto/*--------------------------------------------------
245554359Sroberto * init_iobinding - find and initialize lower layers
245654359Sroberto */
245754359Srobertostatic bind_t *
245854359Srobertoinit_iobinding(
245954359Sroberto	struct parseunit *parse
246054359Sroberto	)
246154359Sroberto{
246254359Sroberto  bind_t *b = io_bindings;
246354359Sroberto
246454359Sroberto	while (b->bd_description != (char *)0)
246554359Sroberto	{
246654359Sroberto		if ((*b->bd_init)(parse))
246754359Sroberto		{
246854359Sroberto			return b;
246954359Sroberto		}
247054359Sroberto		b++;
247154359Sroberto	}
247254359Sroberto	return (bind_t *)0;
247354359Sroberto}
247454359Sroberto
247554359Sroberto/**===========================================================================
247654359Sroberto ** support routines
247754359Sroberto **/
247854359Sroberto
2479280849Scystatic NTP_PRINTF(4, 5) char *
2480280849Scyap(char *buffer, size_t len, char *pos, const char *fmt, ...)
2481280849Scy{
2482280849Scy	va_list va;
2483280849Scy	int l;
2484280849Scy	size_t rem = len - (pos - buffer);
2485280849Scy
2486280849Scy	if (rem == 0)
2487280849Scy		return pos;
2488280849Scy
2489280849Scy	va_start(va, fmt);
2490280849Scy	l = vsnprintf(pos, rem, fmt, va);
2491280849Scy	va_end(va);
2492280849Scy
2493280849Scy	if (l != -1) {
2494280849Scy		rem--;
2495280849Scy		if (rem >= (size_t)l)
2496280849Scy			pos += l;
2497280849Scy		else
2498280849Scy			pos += rem;
2499280849Scy	}
2500280849Scy
2501280849Scy	return pos;
2502280849Scy}
2503280849Scy
250454359Sroberto/*--------------------------------------------------
250554359Sroberto * convert a flag field to a string
250654359Sroberto */
250754359Srobertostatic char *
250854359Srobertoparsestate(
250954359Sroberto	u_long lstate,
2510182007Sroberto	char *buffer,
2511182007Sroberto	int size
251254359Sroberto	)
251354359Sroberto{
251454359Sroberto	static struct bits
251554359Sroberto	{
251654359Sroberto		u_long      bit;
251754359Sroberto		const char *name;
251854359Sroberto	} flagstrings[] =
251954359Sroberto	  {
252056746Sroberto		  { PARSEB_ANNOUNCE,   "DST SWITCH WARNING" },
252156746Sroberto		  { PARSEB_POWERUP,    "NOT SYNCHRONIZED" },
252256746Sroberto		  { PARSEB_NOSYNC,     "TIME CODE NOT CONFIRMED" },
252356746Sroberto		  { PARSEB_DST,        "DST" },
252456746Sroberto		  { PARSEB_UTC,        "UTC DISPLAY" },
252556746Sroberto		  { PARSEB_LEAPADD,    "LEAP ADD WARNING" },
252656746Sroberto		  { PARSEB_LEAPDEL,    "LEAP DELETE WARNING" },
252754359Sroberto		  { PARSEB_LEAPSECOND, "LEAP SECOND" },
2528282408Scy		  { PARSEB_CALLBIT,    "CALL BIT" },
252956746Sroberto		  { PARSEB_TIMECODE,   "TIME CODE" },
253056746Sroberto		  { PARSEB_PPS,        "PPS" },
253156746Sroberto		  { PARSEB_POSITION,   "POSITION" },
2532280849Scy		  { 0,		       NULL }
253354359Sroberto	  };
253454359Sroberto
253554359Sroberto	static struct sbits
253654359Sroberto	{
253754359Sroberto		u_long      bit;
253854359Sroberto		const char *name;
253954359Sroberto	} sflagstrings[] =
254054359Sroberto	  {
254154359Sroberto		  { PARSEB_S_LEAP,     "LEAP INDICATION" },
254254359Sroberto		  { PARSEB_S_PPS,      "PPS SIGNAL" },
2543285169Scy		  { PARSEB_S_CALLBIT,  "CALLBIT" },
254454359Sroberto		  { PARSEB_S_POSITION, "POSITION" },
2545280849Scy		  { 0,		       NULL }
254654359Sroberto	  };
254754359Sroberto	int i;
2548182007Sroberto	char *s, *t;
254954359Sroberto
255054359Sroberto	*buffer = '\0';
2551182007Sroberto	s = t = buffer;
255254359Sroberto
255354359Sroberto	i = 0;
255454359Sroberto	while (flagstrings[i].bit)
255554359Sroberto	{
255654359Sroberto		if (flagstrings[i].bit & lstate)
255754359Sroberto		{
2558182007Sroberto			if (s != t)
2559280849Scy				t = ap(buffer, size, t, "; ");
2560280849Scy			t = ap(buffer, size, t, "%s", flagstrings[i].name);
256154359Sroberto		}
256254359Sroberto		i++;
256354359Sroberto	}
256454359Sroberto
2565285169Scy	if (lstate & (PARSEB_S_LEAP|PARSEB_S_CALLBIT|PARSEB_S_PPS|PARSEB_S_POSITION))
256654359Sroberto	{
2567182007Sroberto		if (s != t)
2568280849Scy			t = ap(buffer, size, t, "; ");
256954359Sroberto
2570280849Scy		t = ap(buffer, size, t, "(");
257154359Sroberto
2572280849Scy		s = t;
257354359Sroberto
257454359Sroberto		i = 0;
257554359Sroberto		while (sflagstrings[i].bit)
257654359Sroberto		{
257754359Sroberto			if (sflagstrings[i].bit & lstate)
257854359Sroberto			{
257954359Sroberto				if (t != s)
258054359Sroberto				{
2581280849Scy					t = ap(buffer, size, t, "; ");
258254359Sroberto				}
2583282408Scy
2584280849Scy				t = ap(buffer, size, t, "%s",
2585280849Scy				    sflagstrings[i].name);
258654359Sroberto			}
258754359Sroberto			i++;
258854359Sroberto		}
2589280849Scy		t = ap(buffer, size, t, ")");
2590289764Sglebius		/* t is unused here, but if we don't track it and
2591289764Sglebius		 * need it later, that's a bug waiting to happen.
2592289764Sglebius		 */
259354359Sroberto	}
259454359Sroberto	return buffer;
259554359Sroberto}
259654359Sroberto
259754359Sroberto/*--------------------------------------------------
259854359Sroberto * convert a status flag field to a string
259954359Sroberto */
260054359Srobertostatic char *
260154359Srobertoparsestatus(
260254359Sroberto	u_long lstate,
2603182007Sroberto	char *buffer,
2604182007Sroberto	int size
260554359Sroberto	)
260654359Sroberto{
260754359Sroberto	static struct bits
260854359Sroberto	{
260954359Sroberto		u_long      bit;
261054359Sroberto		const char *name;
261154359Sroberto	} flagstrings[] =
261254359Sroberto	  {
261354359Sroberto		  { CVT_OK,      "CONVERSION SUCCESSFUL" },
261454359Sroberto		  { CVT_NONE,    "NO CONVERSION" },
261554359Sroberto		  { CVT_FAIL,    "CONVERSION FAILED" },
261654359Sroberto		  { CVT_BADFMT,  "ILLEGAL FORMAT" },
261754359Sroberto		  { CVT_BADDATE, "DATE ILLEGAL" },
261854359Sroberto		  { CVT_BADTIME, "TIME ILLEGAL" },
261954359Sroberto		  { CVT_ADDITIONAL, "ADDITIONAL DATA" },
2620280849Scy		  { 0,		 NULL }
262154359Sroberto	  };
262254359Sroberto	int i;
2623280849Scy	char *t;
262454359Sroberto
2625280849Scy	t = buffer;
262654359Sroberto	*buffer = '\0';
262754359Sroberto
262854359Sroberto	i = 0;
262954359Sroberto	while (flagstrings[i].bit)
263054359Sroberto	{
263154359Sroberto		if (flagstrings[i].bit & lstate)
263254359Sroberto		{
2633280849Scy			if (t != buffer)
2634280849Scy				t = ap(buffer, size, t, "; ");
2635280849Scy			t = ap(buffer, size, t, "%s", flagstrings[i].name);
263654359Sroberto		}
263754359Sroberto		i++;
263854359Sroberto	}
263954359Sroberto
264054359Sroberto	return buffer;
264154359Sroberto}
264254359Sroberto
264354359Sroberto/*--------------------------------------------------
264454359Sroberto * convert a clock status flag field to a string
264554359Sroberto */
264654359Srobertostatic const char *
264754359Srobertoclockstatus(
264854359Sroberto	u_long lstate
264954359Sroberto	)
265054359Sroberto{
265154359Sroberto	static char buffer[20];
265254359Sroberto	static struct status
265354359Sroberto	{
265454359Sroberto		u_long      value;
265554359Sroberto		const char *name;
265654359Sroberto	} flagstrings[] =
265754359Sroberto	  {
265854359Sroberto		  { CEVNT_NOMINAL, "NOMINAL" },
265954359Sroberto		  { CEVNT_TIMEOUT, "NO RESPONSE" },
266054359Sroberto		  { CEVNT_BADREPLY,"BAD FORMAT" },
266154359Sroberto		  { CEVNT_FAULT,   "FAULT" },
266254359Sroberto		  { CEVNT_PROP,    "PROPAGATION DELAY" },
266354359Sroberto		  { CEVNT_BADDATE, "ILLEGAL DATE" },
266454359Sroberto		  { CEVNT_BADTIME, "ILLEGAL TIME" },
2665280849Scy		  { (unsigned)~0L, NULL }
266654359Sroberto	  };
266754359Sroberto	int i;
266854359Sroberto
266954359Sroberto	i = 0;
2670280849Scy	while (flagstrings[i].value != (u_int)~0)
267154359Sroberto	{
267254359Sroberto		if (flagstrings[i].value == lstate)
267354359Sroberto		{
267454359Sroberto			return flagstrings[i].name;
267554359Sroberto		}
267654359Sroberto		i++;
267754359Sroberto	}
267854359Sroberto
2679182007Sroberto	snprintf(buffer, sizeof(buffer), "unknown #%ld", (u_long)lstate);
268054359Sroberto
268154359Sroberto	return buffer;
268254359Sroberto}
268354359Sroberto
268454359Sroberto
268554359Sroberto/*--------------------------------------------------
268654359Sroberto * l_mktime - make representation of a relative time
268754359Sroberto */
268854359Srobertostatic char *
268954359Srobertol_mktime(
269054359Sroberto	u_long delta
269154359Sroberto	)
269254359Sroberto{
269354359Sroberto	u_long tmp, m, s;
269454359Sroberto	static char buffer[40];
2695182007Sroberto	char *t;
269654359Sroberto
269754359Sroberto	buffer[0] = '\0';
2698280849Scy	t = buffer;
269954359Sroberto
270054359Sroberto	if ((tmp = delta / (60*60*24)) != 0)
270154359Sroberto	{
2702280849Scy		t = ap(buffer, sizeof(buffer), t, "%ldd+", (u_long)tmp);
270354359Sroberto		delta -= tmp * 60*60*24;
270454359Sroberto	}
270554359Sroberto
270654359Sroberto	s = delta % 60;
270754359Sroberto	delta /= 60;
270854359Sroberto	m = delta % 60;
270954359Sroberto	delta /= 60;
271054359Sroberto
2711280849Scy	t = ap(buffer, sizeof(buffer), t, "%02d:%02d:%02d",
2712280849Scy	     (int)delta, (int)m, (int)s);
271354359Sroberto
271454359Sroberto	return buffer;
271554359Sroberto}
271654359Sroberto
271754359Sroberto
271854359Sroberto/*--------------------------------------------------
271954359Sroberto * parse_statistics - list summary of clock states
272054359Sroberto */
272154359Srobertostatic void
272254359Srobertoparse_statistics(
272354359Sroberto	struct parseunit *parse
272454359Sroberto	)
272554359Sroberto{
272654359Sroberto	int i;
272754359Sroberto
272854359Sroberto	NLOG(NLOG_CLOCKSTATIST) /* conditional if clause for conditional syslog */
272954359Sroberto		{
273054359Sroberto			msyslog(LOG_INFO, "PARSE receiver #%d: running time: %s",
273154359Sroberto				CLK_UNIT(parse->peer),
273254359Sroberto				l_mktime(current_time - parse->generic->timestarted));
273354359Sroberto
273454359Sroberto			msyslog(LOG_INFO, "PARSE receiver #%d: current status: %s",
273554359Sroberto				CLK_UNIT(parse->peer),
273654359Sroberto				clockstatus(parse->generic->currentstatus));
273754359Sroberto
273854359Sroberto			for (i = 0; i <= CEVNT_MAX; i++)
273954359Sroberto			{
274054359Sroberto				u_long s_time;
274154359Sroberto				u_long percent, d = current_time - parse->generic->timestarted;
274254359Sroberto
274354359Sroberto				percent = s_time = PARSE_STATETIME(parse, i);
274454359Sroberto
274554359Sroberto				while (((u_long)(~0) / 10000) < percent)
274654359Sroberto				{
274754359Sroberto					percent /= 10;
274854359Sroberto					d       /= 10;
274954359Sroberto				}
275054359Sroberto
275154359Sroberto				if (d)
275254359Sroberto				    percent = (percent * 10000) / d;
275354359Sroberto				else
275454359Sroberto				    percent = 10000;
275554359Sroberto
275654359Sroberto				if (s_time)
275754359Sroberto				    msyslog(LOG_INFO, "PARSE receiver #%d: state %18s: %13s (%3ld.%02ld%%)",
275854359Sroberto					    CLK_UNIT(parse->peer),
275954359Sroberto					    clockstatus((unsigned int)i),
276054359Sroberto					    l_mktime(s_time),
276154359Sroberto					    percent / 100, percent % 100);
276254359Sroberto			}
276354359Sroberto		}
276454359Sroberto}
276554359Sroberto
276654359Sroberto/*--------------------------------------------------
276754359Sroberto * cparse_statistics - wrapper for statistics call
276854359Sroberto */
276954359Srobertostatic void
277054359Srobertocparse_statistics(
2771182007Sroberto        struct parseunit *parse
277254359Sroberto	)
277354359Sroberto{
277454359Sroberto	if (parse->laststatistic + PARSESTATISTICS < current_time)
277554359Sroberto		parse_statistics(parse);
277654359Sroberto	parse->laststatistic = current_time;
277754359Sroberto}
277854359Sroberto
277954359Sroberto/**===========================================================================
278054359Sroberto ** ntp interface routines
278154359Sroberto **/
278254359Sroberto
278354359Sroberto/*--------------------------------------------------
278454359Sroberto * parse_shutdown - shut down a PARSE clock
278554359Sroberto */
278654359Srobertostatic void
278754359Srobertoparse_shutdown(
278854359Sroberto	int unit,
278954359Sroberto	struct peer *peer
279054359Sroberto	)
279154359Sroberto{
2792280849Scy	struct parseunit *parse = NULL;
279354359Sroberto
2794182007Sroberto	if (peer && peer->procptr)
2795280849Scy		parse = peer->procptr->unitptr;
2796182007Sroberto
2797182007Sroberto	if (!parse)
279854359Sroberto	{
2799182007Sroberto		/* nothing to clean up */
280054359Sroberto		return;
280154359Sroberto	}
280254359Sroberto
2803280849Scy	if (!parse->peer)
2804182007Sroberto	{
2805182007Sroberto		msyslog(LOG_INFO, "PARSE receiver #%d: INTERNAL ERROR - unit already inactive - shutdown ignored", unit);
2806182007Sroberto		return;
2807182007Sroberto	}
2808182007Sroberto
2809182007Sroberto#ifdef HAVE_PPSAPI
2810182007Sroberto	if (parse->flags & PARSE_PPSCLOCK)
2811182007Sroberto	{
2812280849Scy		(void)time_pps_destroy(parse->atom.handle);
2813182007Sroberto	}
2814182007Sroberto#endif
2815182007Sroberto	if (parse->generic->io.fd != parse->ppsfd && parse->ppsfd != -1)
2816280849Scy		(void)closeserial(parse->ppsfd);  /* close separate PPS source */
2817182007Sroberto
281854359Sroberto	/*
281954359Sroberto	 * print statistics a last time and
282054359Sroberto	 * stop statistics machine
282154359Sroberto	 */
282254359Sroberto	parse_statistics(parse);
282354359Sroberto
282454359Sroberto	if (parse->parse_type->cl_end)
282554359Sroberto	{
282654359Sroberto		parse->parse_type->cl_end(parse);
282754359Sroberto	}
2828282408Scy
2829182007Sroberto	/*
2830182007Sroberto	 * cleanup before leaving this world
2831182007Sroberto	 */
283254359Sroberto	if (parse->binding)
283354359Sroberto	    PARSE_END(parse);
283454359Sroberto
283554359Sroberto	/*
283654359Sroberto	 * Tell the I/O module to turn us off.  We're history.
283754359Sroberto	 */
283854359Sroberto	io_closeclock(&parse->generic->io);
283954359Sroberto
284054359Sroberto	free_varlist(parse->kv);
2841282408Scy
284254359Sroberto	NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */
284354359Sroberto		msyslog(LOG_INFO, "PARSE receiver #%d: reference clock \"%s\" removed",
284454359Sroberto			CLK_UNIT(parse->peer), parse->parse_type->cl_description);
284554359Sroberto
284654359Sroberto	parse->peer = (struct peer *)0; /* unused now */
2847182007Sroberto	peer->procptr->unitptr = (caddr_t)0;
284854359Sroberto	free(parse);
284954359Sroberto}
285054359Sroberto
2851182007Sroberto#ifdef HAVE_PPSAPI
2852182007Sroberto/*----------------------------------------
2853182007Sroberto * set up HARDPPS via PPSAPI
2854182007Sroberto */
2855182007Srobertostatic void
2856182007Srobertoparse_hardpps(
2857182007Sroberto	      struct parseunit *parse,
2858182007Sroberto	      int mode
2859182007Sroberto	      )
2860182007Sroberto{
2861182007Sroberto        if (parse->hardppsstate == mode)
2862182007Sroberto	        return;
2863182007Sroberto
2864182007Sroberto	if (CLK_PPS(parse->peer) && (parse->flags & PARSE_PPSKERNEL)) {
2865182007Sroberto		int	i = 0;
2866182007Sroberto
2867282408Scy		if (mode == PARSE_HARDPPS_ENABLE)
2868182007Sroberto		        {
2869182007Sroberto			        if (parse->flags & PARSE_CLEAR)
2870182007Sroberto				        i = PPS_CAPTURECLEAR;
2871182007Sroberto				else
2872182007Sroberto				        i = PPS_CAPTUREASSERT;
2873182007Sroberto			}
2874282408Scy
2875280849Scy		if (time_pps_kcbind(parse->atom.handle, PPS_KC_HARDPPS, i,
2876182007Sroberto		    PPS_TSFMT_TSPEC) < 0) {
2877182007Sroberto		        msyslog(LOG_ERR, "PARSE receiver #%d: time_pps_kcbind failed: %m",
2878182007Sroberto				CLK_UNIT(parse->peer));
2879182007Sroberto		} else {
2880182007Sroberto		        NLOG(NLOG_CLOCKINFO)
2881182007Sroberto		                msyslog(LOG_INFO, "PARSE receiver #%d: kernel PPS synchronisation %sabled",
2882182007Sroberto					CLK_UNIT(parse->peer), (mode == PARSE_HARDPPS_ENABLE) ? "en" : "dis");
2883182007Sroberto			/*
2884182007Sroberto			 * tell the rest, that we have a kernel PPS source, iff we ever enable HARDPPS
2885182007Sroberto			 */
2886182007Sroberto			if (mode == PARSE_HARDPPS_ENABLE)
2887280849Scy			        hardpps_enable = 1;
2888182007Sroberto		}
2889182007Sroberto	}
2890182007Sroberto
2891182007Sroberto	parse->hardppsstate = mode;
2892182007Sroberto}
2893182007Sroberto
2894182007Sroberto/*----------------------------------------
2895182007Sroberto * set up PPS via PPSAPI
2896182007Sroberto */
2897182007Srobertostatic int
2898182007Srobertoparse_ppsapi(
2899182007Sroberto	     struct parseunit *parse
2900182007Sroberto	)
2901182007Sroberto{
2902280849Scy	int cap, mode_ppsoffset;
2903280849Scy	const char *cp;
2904182007Sroberto
2905282408Scy	parse->flags &= (u_char) (~PARSE_PPSCLOCK);
2906282408Scy
2907280849Scy	/*
2908280849Scy	 * collect PPSAPI offset capability - should move into generic handling
2909280849Scy	 */
2910280849Scy	if (time_pps_getcap(parse->atom.handle, &cap) < 0) {
2911182007Sroberto		msyslog(LOG_ERR, "PARSE receiver #%d: parse_ppsapi: time_pps_getcap failed: %m",
2912182007Sroberto			CLK_UNIT(parse->peer));
2913282408Scy
2914182007Sroberto		return 0;
2915182007Sroberto	}
2916182007Sroberto
2917280849Scy	/*
2918280849Scy	 * initialize generic PPSAPI interface
2919280849Scy	 *
2920280849Scy	 * we leave out CLK_FLAG3 as time_pps_kcbind()
2921280849Scy	 * is handled here for now. Ideally this should also
2922280849Scy	 * be part of the generic PPSAPI interface
2923280849Scy	 */
2924280849Scy	if (!refclock_params(parse->flags & (CLK_FLAG1|CLK_FLAG2|CLK_FLAG4), &parse->atom))
2925182007Sroberto		return 0;
2926182007Sroberto
2927182007Sroberto	/* nb. only turn things on, if someone else has turned something
2928182007Sroberto	 *	on before we get here, leave it alone!
2929182007Sroberto	 */
2930182007Sroberto
2931182007Sroberto	if (parse->flags & PARSE_CLEAR) {
2932182007Sroberto		cp = "CLEAR";
2933280849Scy		mode_ppsoffset = PPS_OFFSETCLEAR;
2934182007Sroberto	} else {
2935182007Sroberto		cp = "ASSERT";
2936280849Scy		mode_ppsoffset = PPS_OFFSETASSERT;
2937182007Sroberto	}
2938182007Sroberto
2939182007Sroberto	msyslog(LOG_INFO, "PARSE receiver #%d: initializing PPS to %s",
2940182007Sroberto		CLK_UNIT(parse->peer), cp);
2941182007Sroberto
2942280849Scy	if (!(mode_ppsoffset & cap)) {
2943182007Sroberto	  msyslog(LOG_WARNING, "PARSE receiver #%d: Cannot set PPS_%sCLEAR, this will increase jitter (PPS API capabilities=0x%x)",
2944182007Sroberto		  CLK_UNIT(parse->peer), cp, cap);
2945280849Scy		mode_ppsoffset = 0;
2946182007Sroberto	} else {
2947282408Scy		if (mode_ppsoffset == PPS_OFFSETCLEAR)
2948282408Scy			{
2949282408Scy				parse->atom.pps_params.clear_offset.tv_sec = (time_t)(-parse->ppsphaseadjust);
2950282408Scy				parse->atom.pps_params.clear_offset.tv_nsec = (long)(-1e9*(parse->ppsphaseadjust - (double)(long)parse->ppsphaseadjust));
2951182007Sroberto			}
2952282408Scy
2953280849Scy		if (mode_ppsoffset == PPS_OFFSETASSERT)
2954282408Scy			{
2955282408Scy				parse->atom.pps_params.assert_offset.tv_sec = (time_t)(-parse->ppsphaseadjust);
2956282408Scy				parse->atom.pps_params.assert_offset.tv_nsec = (long)(-1e9*(parse->ppsphaseadjust - (double)(long)parse->ppsphaseadjust));
2957182007Sroberto			}
2958182007Sroberto	}
2959282408Scy
2960280849Scy	parse->atom.pps_params.mode |= mode_ppsoffset;
2961182007Sroberto
2962280849Scy	if (time_pps_setparams(parse->atom.handle, &parse->atom.pps_params) < 0) {
2963182007Sroberto	  msyslog(LOG_ERR, "PARSE receiver #%d: FAILED set PPS parameters: %m",
2964182007Sroberto		  CLK_UNIT(parse->peer));
2965182007Sroberto		return 0;
2966182007Sroberto	}
2967182007Sroberto
2968182007Sroberto	parse->flags |= PARSE_PPSCLOCK;
2969182007Sroberto	return 1;
2970182007Sroberto}
2971182007Sroberto#else
2972182007Sroberto#define parse_hardpps(_PARSE_, _MODE_) /* empty */
2973182007Sroberto#endif
2974182007Sroberto
297554359Sroberto/*--------------------------------------------------
297654359Sroberto * parse_start - open the PARSE devices and initialize data for processing
297754359Sroberto */
297854359Srobertostatic int
297954359Srobertoparse_start(
298054359Sroberto	int sysunit,
298154359Sroberto	struct peer *peer
298254359Sroberto	)
298354359Sroberto{
298454359Sroberto	u_int unit;
298554359Sroberto	int fd232;
298654359Sroberto#ifdef HAVE_TERMIOS
298754359Sroberto	struct termios tio;		/* NEEDED FOR A LONG TIME ! */
298854359Sroberto#endif
298954359Sroberto#ifdef HAVE_SYSV_TTYS
299054359Sroberto	struct termio tio;		/* NEEDED FOR A LONG TIME ! */
299154359Sroberto#endif
299254359Sroberto	struct parseunit * parse;
299354359Sroberto	char parsedev[sizeof(PARSEDEVICE)+20];
2994182007Sroberto	char parseppsdev[sizeof(PARSEPPSDEVICE)+20];
299554359Sroberto	parsectl_t tmp_ctl;
299654359Sroberto	u_int type;
299754359Sroberto
2998182007Sroberto	/*
2999182007Sroberto	 * get out Copyright information once
3000182007Sroberto	 */
3001182007Sroberto	if (!notice)
3002182007Sroberto        {
3003182007Sroberto		NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */
3004285169Scy			msyslog(LOG_INFO, "NTP PARSE support: Copyright (c) 1989-2015, Frank Kardel");
3005182007Sroberto		notice = 1;
3006182007Sroberto	}
3007182007Sroberto
300854359Sroberto	type = CLK_TYPE(peer);
300954359Sroberto	unit = CLK_UNIT(peer);
301054359Sroberto
3011280849Scy	if ((type == (u_int)~0) || (parse_clockinfo[type].cl_description == (char *)0))
301254359Sroberto	{
301354359Sroberto		msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: unsupported clock type %d (max %d)",
301454359Sroberto			unit, CLK_REALTYPE(peer), ncltypes-1);
301554359Sroberto		return 0;
301654359Sroberto	}
301754359Sroberto
301854359Sroberto	/*
301954359Sroberto	 * Unit okay, attempt to open the device.
302054359Sroberto	 */
3021182007Sroberto	(void) snprintf(parsedev, sizeof(parsedev), PARSEDEVICE, unit);
3022182007Sroberto	(void) snprintf(parseppsdev, sizeof(parsedev), PARSEPPSDEVICE, unit);
302354359Sroberto
302454359Sroberto#ifndef O_NOCTTY
302554359Sroberto#define O_NOCTTY 0
302654359Sroberto#endif
3027280849Scy#ifndef O_NONBLOCK
3028280849Scy#define O_NONBLOCK 0
302954359Sroberto#endif
303054359Sroberto
3031280849Scy	fd232 = tty_open(parsedev, O_RDWR | O_NOCTTY | O_NONBLOCK, 0777);
3032280849Scy
303354359Sroberto	if (fd232 == -1)
303454359Sroberto	{
303554359Sroberto		msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: open of %s failed: %m", unit, parsedev);
303654359Sroberto		return 0;
303754359Sroberto	}
303854359Sroberto
3039280849Scy	parse = emalloc_zero(sizeof(*parse));
304054359Sroberto
304154359Sroberto	parse->generic = peer->procptr;	 /* link up */
304254359Sroberto	parse->generic->unitptr = (caddr_t)parse; /* link down */
304354359Sroberto
304454359Sroberto	/*
304554359Sroberto	 * Set up the structures
304654359Sroberto	 */
304754359Sroberto	parse->generic->timestarted    = current_time;
304854359Sroberto	parse->lastchange     = current_time;
304954359Sroberto
305054359Sroberto	parse->flags          = 0;
305154359Sroberto	parse->pollneeddata   = 0;
305254359Sroberto	parse->laststatistic  = current_time;
305354359Sroberto	parse->lastformat     = (unsigned short)~0;	/* assume no format known */
3054182007Sroberto	parse->timedata.parse_status = (unsigned short)~0;	/* be sure to mark initial status change */
305554359Sroberto	parse->lastmissed     = 0;	/* assume got everything */
305654359Sroberto	parse->ppsserial      = 0;
3057182007Sroberto	parse->ppsfd	      = -1;
305854359Sroberto	parse->localdata      = (void *)0;
305954359Sroberto	parse->localstate     = 0;
306054359Sroberto	parse->kv             = (struct ctl_var *)0;
306154359Sroberto
306254359Sroberto	clear_err(parse, ERR_ALL);
3063282408Scy
306454359Sroberto	parse->parse_type     = &parse_clockinfo[type];
3065282408Scy
3066182007Sroberto	parse->maxunsync      = parse->parse_type->cl_maxunsync;
3067182007Sroberto
306854359Sroberto	parse->generic->fudgetime1 = parse->parse_type->cl_basedelay;
306954359Sroberto
307054359Sroberto	parse->generic->fudgetime2 = 0.0;
3071182007Sroberto	parse->ppsphaseadjust = parse->generic->fudgetime2;
3072358659Scy	parse->generic->fudgeminjitter = 0.0;
307354359Sroberto
3074182007Sroberto	parse->generic->clockdesc  = parse->parse_type->cl_description;
307554359Sroberto
307654359Sroberto	peer->rootdelay       = parse->parse_type->cl_rootdelay;
307754359Sroberto	peer->sstclktype      = parse->parse_type->cl_type;
307854359Sroberto	peer->precision       = sys_precision;
3079282408Scy
308054359Sroberto	peer->stratum         = STRATUM_REFCLOCK;
3081182007Sroberto
308254359Sroberto	if (peer->stratum <= 1)
308354359Sroberto	    memmove((char *)&parse->generic->refid, parse->parse_type->cl_id, 4);
308454359Sroberto	else
308554359Sroberto	    parse->generic->refid = htonl(PARSEHSREFID);
3086282408Scy
308754359Sroberto	parse->generic->io.fd = fd232;
3088282408Scy
308954359Sroberto	parse->peer = peer;		/* marks it also as busy */
309054359Sroberto
309154359Sroberto	/*
309254359Sroberto	 * configure terminal line
309354359Sroberto	 */
309454359Sroberto	if (TTY_GETATTR(fd232, &tio) == -1)
309554359Sroberto	{
309654359Sroberto		msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: tcgetattr(%d, &tio): %m", unit, fd232);
309754359Sroberto		parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
309854359Sroberto		return 0;
309954359Sroberto	}
310054359Sroberto	else
310154359Sroberto	{
310254359Sroberto#ifndef _PC_VDISABLE
310354359Sroberto		memset((char *)tio.c_cc, 0, sizeof(tio.c_cc));
310454359Sroberto#else
310554359Sroberto		int disablec;
310654359Sroberto		errno = 0;		/* pathconf can deliver -1 without changing errno ! */
310754359Sroberto
310854359Sroberto		disablec = fpathconf(parse->generic->io.fd, _PC_VDISABLE);
310954359Sroberto		if (disablec == -1 && errno)
311054359Sroberto		{
311154359Sroberto			msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: fpathconf(fd, _PC_VDISABLE): %m", CLK_UNIT(parse->peer));
311254359Sroberto			memset((char *)tio.c_cc, 0, sizeof(tio.c_cc)); /* best guess */
311354359Sroberto		}
311454359Sroberto		else
311554359Sroberto		    if (disablec != -1)
311654359Sroberto			memset((char *)tio.c_cc, disablec, sizeof(tio.c_cc));
311754359Sroberto#endif
311854359Sroberto
311954359Sroberto#if defined (VMIN) || defined(VTIME)
312054359Sroberto		if ((parse_clockinfo[type].cl_lflag & ICANON) == 0)
312154359Sroberto		{
312254359Sroberto#ifdef VMIN
312354359Sroberto			tio.c_cc[VMIN]   = 1;
312454359Sroberto#endif
312554359Sroberto#ifdef VTIME
312654359Sroberto			tio.c_cc[VTIME]  = 0;
312754359Sroberto#endif
312854359Sroberto		}
312954359Sroberto#endif
313054359Sroberto
3131282408Scy		tio.c_cflag = (tcflag_t) parse_clockinfo[type].cl_cflag;
3132282408Scy		tio.c_iflag = (tcflag_t) parse_clockinfo[type].cl_iflag;
3133282408Scy		tio.c_oflag = (tcflag_t) parse_clockinfo[type].cl_oflag;
3134282408Scy		tio.c_lflag = (tcflag_t) parse_clockinfo[type].cl_lflag;
313554359Sroberto
3136282408Scy
313754359Sroberto#ifdef HAVE_TERMIOS
3138282408Scy		if ((cfsetospeed(&tio, (speed_t) parse_clockinfo[type].cl_speed) == -1) ||
3139282408Scy		    (cfsetispeed(&tio, (speed_t) parse_clockinfo[type].cl_speed) == -1))
314054359Sroberto		{
314154359Sroberto			msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: tcset{i,o}speed(&tio, speed): %m", unit);
314254359Sroberto			parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
314354359Sroberto			return 0;
314454359Sroberto		}
314554359Sroberto#else
314654359Sroberto		tio.c_cflag     |= parse_clockinfo[type].cl_speed;
314754359Sroberto#endif
314854359Sroberto
3149182007Sroberto		/*
3150182007Sroberto		 * set up pps device
3151182007Sroberto		 * if the PARSEPPSDEVICE can be opened that will be used
3152182007Sroberto		 * for PPS else PARSEDEVICE will be used
3153182007Sroberto		 */
3154280849Scy		parse->ppsfd = tty_open(parseppsdev, O_RDWR | O_NOCTTY | O_NONBLOCK, 0777);
3155182007Sroberto
3156182007Sroberto		if (parse->ppsfd == -1)
3157182007Sroberto		{
3158182007Sroberto			parse->ppsfd = fd232;
3159182007Sroberto		}
3160182007Sroberto
3161182007Sroberto/*
3162182007Sroberto * Linux PPS - the old way
3163182007Sroberto */
316454359Sroberto#if defined(HAVE_TIO_SERIAL_STUFF)		/* Linux hack: define PPS interface */
316554359Sroberto		{
3166182007Sroberto			struct serial_struct	ss;
3167182007Sroberto			if (ioctl(parse->ppsfd, TIOCGSERIAL, &ss) < 0 ||
3168182007Sroberto			    (
316954359Sroberto#ifdef ASYNC_LOW_LATENCY
3170182007Sroberto			     ss.flags |= ASYNC_LOW_LATENCY,
317154359Sroberto#endif
3172182007Sroberto#ifndef HAVE_PPSAPI
317354359Sroberto#ifdef ASYNC_PPS_CD_NEG
3174182007Sroberto			     ss.flags |= ASYNC_PPS_CD_NEG,
317554359Sroberto#endif
3176182007Sroberto#endif
3177182007Sroberto			     ioctl(parse->ppsfd, TIOCSSERIAL, &ss)) < 0) {
3178182007Sroberto				msyslog(LOG_NOTICE, "refclock_parse: TIOCSSERIAL fd %d, %m", parse->ppsfd);
3179182007Sroberto				msyslog(LOG_NOTICE,
3180182007Sroberto					"refclock_parse: optional PPS processing not available");
3181182007Sroberto			} else {
3182182007Sroberto				parse->flags    |= PARSE_PPSCLOCK;
3183182007Sroberto#ifdef ASYNC_PPS_CD_NEG
3184182007Sroberto				NLOG(NLOG_CLOCKINFO)
3185182007Sroberto				  msyslog(LOG_INFO,
3186182007Sroberto					  "refclock_parse: PPS detection on");
3187182007Sroberto#endif
3188182007Sroberto			}
318954359Sroberto		}
319054359Sroberto#endif
3191182007Sroberto
3192182007Sroberto/*
3193182007Sroberto * SUN the Solaris way
3194182007Sroberto */
319554359Sroberto#ifdef HAVE_TIOCSPPS			/* SUN PPS support */
319654359Sroberto		if (CLK_PPS(parse->peer))
3197182007Sroberto		    {
3198182007Sroberto			int i = 1;
3199282408Scy
3200182007Sroberto			if (ioctl(parse->ppsfd, TIOCSPPS, (caddr_t)&i) == 0)
3201182007Sroberto			    {
3202182007Sroberto				parse->flags |= PARSE_PPSCLOCK;
3203182007Sroberto			    }
3204182007Sroberto		    }
320554359Sroberto#endif
320654359Sroberto
3207182007Sroberto/*
3208182007Sroberto * PPS via PPSAPI
3209182007Sroberto */
3210182007Sroberto#if defined(HAVE_PPSAPI)
3211182007Sroberto		parse->hardppsstate = PARSE_HARDPPS_DISABLE;
3212182007Sroberto		if (CLK_PPS(parse->peer))
3213182007Sroberto		{
3214280849Scy		  if (!refclock_ppsapi(parse->ppsfd, &parse->atom))
3215182007Sroberto		    {
3216182007Sroberto		      msyslog(LOG_NOTICE, "PARSE receiver #%d: parse_start: could not set up PPS: %m", CLK_UNIT(parse->peer));
3217182007Sroberto		    }
3218182007Sroberto		  else
3219182007Sroberto		    {
3220182007Sroberto		      parse_ppsapi(parse);
3221182007Sroberto		    }
3222182007Sroberto		}
3223182007Sroberto#endif
3224182007Sroberto
322554359Sroberto		if (TTY_SETATTR(fd232, &tio) == -1)
322654359Sroberto		{
322754359Sroberto			msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: tcsetattr(%d, &tio): %m", unit, fd232);
322854359Sroberto			parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
322954359Sroberto			return 0;
323054359Sroberto		}
323154359Sroberto	}
323254359Sroberto
323354359Sroberto	/*
3234182007Sroberto	 * pick correct input machine
323554359Sroberto	 */
3236280849Scy	parse->generic->io.srcclock = peer;
323754359Sroberto	parse->generic->io.datalen = 0;
3238282408Scy
323954359Sroberto	parse->binding = init_iobinding(parse);
324054359Sroberto
324154359Sroberto	if (parse->binding == (bind_t *)0)
324254359Sroberto		{
324354359Sroberto			msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: io sub system initialisation failed.", CLK_UNIT(parse->peer));
324454359Sroberto			parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
324554359Sroberto			return 0;			/* well, ok - special initialisation broke */
3246280849Scy		}
324754359Sroberto
3248182007Sroberto	parse->generic->io.clock_recv = parse->binding->bd_receive; /* pick correct receive routine */
3249182007Sroberto	parse->generic->io.io_input   = parse->binding->bd_io_input; /* pick correct input routine */
3250182007Sroberto
325154359Sroberto	/*
325254359Sroberto	 * as we always(?) get 8 bit chars we want to be
325354359Sroberto	 * sure, that the upper bits are zero for less
325454359Sroberto	 * than 8 bit I/O - so we pass that information on.
325554359Sroberto	 * note that there can be only one bit count format
325654359Sroberto	 * per file descriptor
325754359Sroberto	 */
325854359Sroberto
325954359Sroberto	switch (tio.c_cflag & CSIZE)
326054359Sroberto	{
326154359Sroberto	    case CS5:
326254359Sroberto		tmp_ctl.parsesetcs.parse_cs = PARSE_IO_CS5;
326354359Sroberto		break;
326454359Sroberto
326554359Sroberto	    case CS6:
326654359Sroberto		tmp_ctl.parsesetcs.parse_cs = PARSE_IO_CS6;
326754359Sroberto		break;
326854359Sroberto
326954359Sroberto	    case CS7:
327054359Sroberto		tmp_ctl.parsesetcs.parse_cs = PARSE_IO_CS7;
327154359Sroberto		break;
327254359Sroberto
327354359Sroberto	    case CS8:
327454359Sroberto		tmp_ctl.parsesetcs.parse_cs = PARSE_IO_CS8;
327554359Sroberto		break;
327654359Sroberto	}
327754359Sroberto
327854359Sroberto	if (!PARSE_SETCS(parse, &tmp_ctl))
327954359Sroberto	{
328054359Sroberto		msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: parse_setcs() FAILED.", unit);
328154359Sroberto		parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
328254359Sroberto		return 0;			/* well, ok - special initialisation broke */
328354359Sroberto	}
3284282408Scy
3285280849Scy	strlcpy(tmp_ctl.parseformat.parse_buffer, parse->parse_type->cl_format, sizeof(tmp_ctl.parseformat.parse_buffer));
3286282408Scy	tmp_ctl.parseformat.parse_count = (u_short) strlen(tmp_ctl.parseformat.parse_buffer);
328754359Sroberto
328854359Sroberto	if (!PARSE_SETFMT(parse, &tmp_ctl))
328954359Sroberto	{
329054359Sroberto		msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: parse_setfmt() FAILED.", unit);
329154359Sroberto		parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
329254359Sroberto		return 0;			/* well, ok - special initialisation broke */
329354359Sroberto	}
3294282408Scy
329554359Sroberto	/*
329654359Sroberto	 * get rid of all IO accumulated so far
329754359Sroberto	 */
329854359Sroberto#ifdef HAVE_TERMIOS
329954359Sroberto	(void) tcflush(parse->generic->io.fd, TCIOFLUSH);
330054359Sroberto#else
3301182007Sroberto#if defined(TCFLSH) && defined(TCIOFLUSH)
330254359Sroberto	{
330354359Sroberto		int flshcmd = TCIOFLUSH;
330454359Sroberto
330554359Sroberto		(void) ioctl(parse->generic->io.fd, TCFLSH, (caddr_t)&flshcmd);
330654359Sroberto	}
330754359Sroberto#endif
330854359Sroberto#endif
330956746Sroberto
331054359Sroberto	/*
331154359Sroberto	 * try to do any special initializations
331254359Sroberto	 */
331354359Sroberto	if (parse->parse_type->cl_init)
331454359Sroberto		{
331554359Sroberto			if (parse->parse_type->cl_init(parse))
331654359Sroberto				{
331754359Sroberto					parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
331854359Sroberto					return 0;		/* well, ok - special initialisation broke */
331954359Sroberto				}
332054359Sroberto		}
3321282408Scy
332254359Sroberto	/*
3323182007Sroberto	 * Insert in async io device list.
332454359Sroberto	 */
3325182007Sroberto	if (!io_addclock(&parse->generic->io))
332654359Sroberto        {
3327182007Sroberto		msyslog(LOG_ERR,
3328182007Sroberto			"PARSE receiver #%d: parse_start: addclock %s fails (ABORT - clock type requires async io)", CLK_UNIT(parse->peer), parsedev);
3329182007Sroberto		parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
3330182007Sroberto		return 0;
333154359Sroberto	}
333254359Sroberto
333354359Sroberto	/*
333454359Sroberto	 * print out configuration
333554359Sroberto	 */
333654359Sroberto	NLOG(NLOG_CLOCKINFO)
333754359Sroberto		{
333854359Sroberto			/* conditional if clause for conditional syslog */
3339182007Sroberto			msyslog(LOG_INFO, "PARSE receiver #%d: reference clock \"%s\" (I/O device %s, PPS device %s) added",
334054359Sroberto				CLK_UNIT(parse->peer),
3341182007Sroberto				parse->parse_type->cl_description, parsedev,
3342182007Sroberto				(parse->ppsfd != parse->generic->io.fd) ? parseppsdev : parsedev);
334354359Sroberto
3344182007Sroberto			msyslog(LOG_INFO, "PARSE receiver #%d: Stratum %d, trust time %s, precision %d",
334554359Sroberto				CLK_UNIT(parse->peer),
3346182007Sroberto				parse->peer->stratum,
3347182007Sroberto				l_mktime(parse->maxunsync), parse->peer->precision);
334854359Sroberto
3349182007Sroberto			msyslog(LOG_INFO, "PARSE receiver #%d: rootdelay %.6f s, phase adjustment %.6f s, PPS phase adjustment %.6f s, %s IO handling",
335054359Sroberto				CLK_UNIT(parse->peer),
335154359Sroberto				parse->parse_type->cl_rootdelay,
335254359Sroberto				parse->generic->fudgetime1,
3353182007Sroberto				parse->ppsphaseadjust,
3354182007Sroberto                                parse->binding->bd_description);
335554359Sroberto
3356182007Sroberto			msyslog(LOG_INFO, "PARSE receiver #%d: Format recognition: %s", CLK_UNIT(parse->peer),
335754359Sroberto				parse->parse_type->cl_format);
3358182007Sroberto                        msyslog(LOG_INFO, "PARSE receiver #%d: %sPPS support%s", CLK_UNIT(parse->peer),
3359182007Sroberto				CLK_PPS(parse->peer) ? "" : "NO ",
3360182007Sroberto				CLK_PPS(parse->peer) ?
3361182007Sroberto#ifdef PPS_METHOD
3362182007Sroberto				" (implementation " PPS_METHOD ")"
3363182007Sroberto#else
3364182007Sroberto				""
336554359Sroberto#endif
3366182007Sroberto				: ""
3367182007Sroberto				);
336854359Sroberto		}
336954359Sroberto
337054359Sroberto	return 1;
337154359Sroberto}
337254359Sroberto
337354359Sroberto/*--------------------------------------------------
3374182007Sroberto * parse_ctl - process changes on flags/time values
3375182007Sroberto */
3376182007Srobertostatic void
3377182007Srobertoparse_ctl(
3378182007Sroberto	    struct parseunit *parse,
3379280849Scy	    const struct refclockstat *in
3380182007Sroberto	    )
3381182007Sroberto{
3382182007Sroberto        if (in)
3383182007Sroberto	{
3384182007Sroberto		if (in->haveflags & (CLK_HAVEFLAG1|CLK_HAVEFLAG2|CLK_HAVEFLAG3|CLK_HAVEFLAG4))
3385182007Sroberto		{
3386282408Scy		  u_char mask = CLK_FLAG1|CLK_FLAG2|CLK_FLAG3|CLK_FLAG4;
3387282408Scy		  parse->flags = (parse->flags & (u_char)(~mask)) | (in->flags & mask);
3388182007Sroberto#if defined(HAVE_PPSAPI)
3389182007Sroberto		  if (CLK_PPS(parse->peer))
3390182007Sroberto		    {
3391182007Sroberto		      parse_ppsapi(parse);
3392182007Sroberto		    }
3393182007Sroberto#endif
3394182007Sroberto		}
3395282408Scy
3396182007Sroberto		if (in->haveflags & CLK_HAVETIME1)
3397182007Sroberto                {
3398182007Sroberto		  parse->generic->fudgetime1 = in->fudgetime1;
3399182007Sroberto		  msyslog(LOG_INFO, "PARSE receiver #%d: new phase adjustment %.6f s",
3400182007Sroberto			  CLK_UNIT(parse->peer),
3401182007Sroberto			  parse->generic->fudgetime1);
3402182007Sroberto		}
3403282408Scy
3404182007Sroberto		if (in->haveflags & CLK_HAVETIME2)
3405182007Sroberto                {
3406182007Sroberto		  parse->generic->fudgetime2 = in->fudgetime2;
3407282408Scy		  if (parse->flags & PARSE_TRUSTTIME)
3408182007Sroberto		    {
3409182007Sroberto		      parse->maxunsync = (u_long)ABS(in->fudgetime2);
3410182007Sroberto		      msyslog(LOG_INFO, "PARSE receiver #%d: new trust time %s",
3411182007Sroberto			      CLK_UNIT(parse->peer),
3412182007Sroberto			      l_mktime(parse->maxunsync));
3413182007Sroberto		    }
3414182007Sroberto		  else
3415182007Sroberto		    {
3416182007Sroberto		      parse->ppsphaseadjust = in->fudgetime2;
3417182007Sroberto		      msyslog(LOG_INFO, "PARSE receiver #%d: new PPS phase adjustment %.6f s",
3418182007Sroberto			  CLK_UNIT(parse->peer),
3419182007Sroberto			      parse->ppsphaseadjust);
3420182007Sroberto#if defined(HAVE_PPSAPI)
3421182007Sroberto		      if (CLK_PPS(parse->peer))
3422182007Sroberto		      {
3423182007Sroberto			      parse_ppsapi(parse);
3424182007Sroberto		      }
3425182007Sroberto#endif
3426182007Sroberto		    }
3427182007Sroberto		}
3428358659Scy
3429358659Scy		parse->generic->fudgeminjitter = in->fudgeminjitter;
3430182007Sroberto	}
3431182007Sroberto}
3432182007Sroberto
3433182007Sroberto/*--------------------------------------------------
343454359Sroberto * parse_poll - called by the transmit procedure
343554359Sroberto */
343654359Srobertostatic void
343754359Srobertoparse_poll(
343854359Sroberto	int unit,
343954359Sroberto	struct peer *peer
344054359Sroberto	)
344154359Sroberto{
3442280849Scy	struct parseunit *parse = peer->procptr->unitptr;
344354359Sroberto
344454359Sroberto	if (peer != parse->peer)
344554359Sroberto	{
344654359Sroberto		msyslog(LOG_ERR,
344754359Sroberto			"PARSE receiver #%d: poll: INTERNAL: peer incorrect",
344854359Sroberto			unit);
344954359Sroberto		return;
345054359Sroberto	}
345154359Sroberto
345254359Sroberto	/*
345354359Sroberto	 * Update clock stat counters
345454359Sroberto	 */
345554359Sroberto	parse->generic->polls++;
345654359Sroberto
3457282408Scy	if (parse->pollneeddata &&
3458280849Scy	    ((int)(current_time - parse->pollneeddata) > (1<<(max(min(parse->peer->hpoll, parse->peer->ppoll), parse->peer->minpoll)))))
345954359Sroberto	{
346054359Sroberto		/*
346156746Sroberto		 * start worrying when exceeding a poll inteval
346254359Sroberto		 * bad news - didn't get a response last time
346354359Sroberto		 */
346454359Sroberto		parse->lastmissed = current_time;
346554359Sroberto		parse_event(parse, CEVNT_TIMEOUT);
3466282408Scy
346754359Sroberto		ERR(ERR_NODATA)
3468182007Sroberto			msyslog(LOG_WARNING, "PARSE receiver #%d: no data from device within poll interval (check receiver / wiring)", CLK_UNIT(parse->peer));
346954359Sroberto	}
347054359Sroberto
347154359Sroberto	/*
347254359Sroberto	 * we just mark that we want the next sample for the clock filter
347354359Sroberto	 */
347456746Sroberto	parse->pollneeddata = current_time;
347554359Sroberto
347654359Sroberto	if (parse->parse_type->cl_poll)
347754359Sroberto	{
347854359Sroberto		parse->parse_type->cl_poll(parse);
347954359Sroberto	}
348054359Sroberto
348154359Sroberto	cparse_statistics(parse);
348254359Sroberto
348354359Sroberto	return;
348454359Sroberto}
348554359Sroberto
348654359Sroberto#define LEN_STATES 300		/* length of state string */
348754359Sroberto
348854359Sroberto/*--------------------------------------------------
348954359Sroberto * parse_control - set fudge factors, return statistics
349054359Sroberto */
349154359Srobertostatic void
349254359Srobertoparse_control(
349354359Sroberto	int unit,
3494280849Scy	const struct refclockstat *in,
349554359Sroberto	struct refclockstat *out,
349654359Sroberto	struct peer *peer
349754359Sroberto	)
349854359Sroberto{
3499280849Scy	struct parseunit *parse = peer->procptr->unitptr;
350054359Sroberto	parsectl_t tmpctl;
350154359Sroberto
350254359Sroberto	static char outstatus[400];	/* status output buffer */
350354359Sroberto
350454359Sroberto	if (out)
350554359Sroberto	{
350654359Sroberto		out->lencode       = 0;
350754359Sroberto		out->p_lastcode    = 0;
350854359Sroberto		out->kv_list       = (struct ctl_var *)0;
350954359Sroberto	}
351054359Sroberto
351154359Sroberto	if (!parse || !parse->peer)
351254359Sroberto	{
351354359Sroberto		msyslog(LOG_ERR, "PARSE receiver #%d: parse_control: unit invalid (UNIT INACTIVE)",
351454359Sroberto			unit);
351554359Sroberto		return;
351654359Sroberto	}
351754359Sroberto
351854359Sroberto	unit = CLK_UNIT(parse->peer);
351954359Sroberto
3520182007Sroberto	/*
3521182007Sroberto	 * handle changes
3522182007Sroberto	 */
3523182007Sroberto	parse_ctl(parse, in);
3524282408Scy
3525182007Sroberto	/*
3526182007Sroberto	 * supply data
3527182007Sroberto	 */
352854359Sroberto	if (out)
352954359Sroberto	{
353054359Sroberto		u_long sum = 0;
3531182007Sroberto		char *tt, *start;
353254359Sroberto		int i;
353354359Sroberto
353454359Sroberto		outstatus[0] = '\0';
353554359Sroberto
353654359Sroberto		out->type       = REFCLK_PARSE;
353754359Sroberto
353854359Sroberto		/*
3539182007Sroberto		 * keep fudgetime2 in sync with TRUSTTIME/MAXUNSYNC flag1
3540182007Sroberto		 */
3541182007Sroberto		parse->generic->fudgetime2 = (parse->flags & PARSE_TRUSTTIME) ? (double)parse->maxunsync : parse->ppsphaseadjust;
3542182007Sroberto
3543182007Sroberto		/*
354454359Sroberto		 * figure out skew between PPS and RS232 - just for informational
3545182007Sroberto		 * purposes
354654359Sroberto		 */
3547182007Sroberto		if (PARSE_SYNC(parse->timedata.parse_state))
354854359Sroberto		{
3549182007Sroberto			if (PARSE_PPS(parse->timedata.parse_state) && PARSE_TIMECODE(parse->timedata.parse_state))
355054359Sroberto			{
355154359Sroberto				l_fp off;
355254359Sroberto
355354359Sroberto				/*
355454359Sroberto				 * we have a PPS and RS232 signal - calculate the skew
355554359Sroberto				 * WARNING: assumes on TIMECODE == PULSE (timecode after pulse)
355654359Sroberto				 */
3557182007Sroberto				off = parse->timedata.parse_stime.fp;
3558182007Sroberto				L_SUB(&off, &parse->timedata.parse_ptime.fp); /* true offset */
355954359Sroberto				tt = add_var(&out->kv_list, 80, RO);
3560182007Sroberto				snprintf(tt, 80, "refclock_ppsskew=%s", lfptoms(&off, 6));
356154359Sroberto			}
356254359Sroberto		}
356354359Sroberto
3564182007Sroberto		if (PARSE_PPS(parse->timedata.parse_state))
356554359Sroberto		{
356654359Sroberto			tt = add_var(&out->kv_list, 80, RO|DEF);
3567182007Sroberto			snprintf(tt, 80, "refclock_ppstime=\"%s\"", gmprettydate(&parse->timedata.parse_ptime.fp));
356854359Sroberto		}
356954359Sroberto
3570182007Sroberto		start = tt = add_var(&out->kv_list, 128, RO|DEF);
3571280849Scy		tt = ap(start, 128, tt, "refclock_time=\"");
357254359Sroberto
3573182007Sroberto		if (parse->timedata.parse_time.fp.l_ui == 0)
357454359Sroberto		{
3575280849Scy			tt = ap(start, 128, tt, "<UNDEFINED>\"");
357654359Sroberto		}
357754359Sroberto		else
357854359Sroberto		{
3579280849Scy			tt = ap(start, 128, tt, "%s\"",
3580280849Scy			    gmprettydate(&parse->timedata.parse_time.fp));
358154359Sroberto		}
358254359Sroberto
358354359Sroberto		if (!PARSE_GETTIMECODE(parse, &tmpctl))
358454359Sroberto		{
358554359Sroberto			ERR(ERR_INTERNAL)
358654359Sroberto				msyslog(LOG_ERR, "PARSE receiver #%d: parse_control: parse_timecode() FAILED", unit);
358754359Sroberto		}
358854359Sroberto		else
358954359Sroberto		{
3590182007Sroberto			start = tt = add_var(&out->kv_list, 512, RO|DEF);
3591280849Scy			tt = ap(start, 512, tt, "refclock_status=\"");
359254359Sroberto
359354359Sroberto			/*
359454359Sroberto			 * copy PPS flags from last read transaction (informational only)
359554359Sroberto			 */
3596182007Sroberto			tmpctl.parsegettc.parse_state |= parse->timedata.parse_state &
359754359Sroberto				(PARSEB_PPS|PARSEB_S_PPS);
359854359Sroberto
3599280849Scy			(void)parsestate(tmpctl.parsegettc.parse_state, tt, BUFFER_SIZES(start, tt, 512));
360054359Sroberto
3601280849Scy			tt += strlen(tt);
360254359Sroberto
3603280849Scy			tt = ap(start, 512, tt, "\"");
3604280849Scy
360554359Sroberto			if (tmpctl.parsegettc.parse_count)
360654359Sroberto			    mkascii(outstatus+strlen(outstatus), (int)(sizeof(outstatus)- strlen(outstatus) - 1),
3607182007Sroberto				    tmpctl.parsegettc.parse_buffer, (unsigned)(tmpctl.parsegettc.parse_count));
360854359Sroberto
360954359Sroberto		}
3610282408Scy
361154359Sroberto		tmpctl.parseformat.parse_format = tmpctl.parsegettc.parse_format;
3612282408Scy
361354359Sroberto		if (!PARSE_GETFMT(parse, &tmpctl))
361454359Sroberto		{
361554359Sroberto			ERR(ERR_INTERNAL)
361654359Sroberto				msyslog(LOG_ERR, "PARSE receiver #%d: parse_control: parse_getfmt() FAILED", unit);
361754359Sroberto		}
361854359Sroberto		else
361954359Sroberto		{
3620330106Sdelphij			int count = tmpctl.parseformat.parse_count;
3621330106Sdelphij			if (count)
3622330106Sdelphij				--count;
362354359Sroberto
3624280849Scy			start = tt = add_var(&out->kv_list, 80, RO|DEF);
3625280849Scy			tt = ap(start, 80, tt, "refclock_format=\"");
3626280849Scy
3627280849Scy			if (count > 0) {
3628282408Scy				tt = ap(start, 80, tt, "%*.*s",
3629280849Scy			        	count,
3630280849Scy			        	count,
3631280849Scy			        	tmpctl.parseformat.parse_buffer);
3632280849Scy			}
3633280849Scy
3634280849Scy			tt = ap(start, 80, tt, "\"");
363554359Sroberto		}
363654359Sroberto
363754359Sroberto		/*
363854359Sroberto		 * gather state statistics
363954359Sroberto		 */
364054359Sroberto
364154359Sroberto		start = tt = add_var(&out->kv_list, LEN_STATES, RO|DEF);
3642280849Scy		tt = ap(start, LEN_STATES, tt, "refclock_states=\"");
364354359Sroberto
364454359Sroberto		for (i = 0; i <= CEVNT_MAX; i++)
364554359Sroberto		{
364654359Sroberto			u_long s_time;
364754359Sroberto			u_long d = current_time - parse->generic->timestarted;
364854359Sroberto			u_long percent;
364954359Sroberto
365054359Sroberto			percent = s_time = PARSE_STATETIME(parse, i);
365154359Sroberto
365254359Sroberto			while (((u_long)(~0) / 10000) < percent)
365354359Sroberto			{
365454359Sroberto				percent /= 10;
365554359Sroberto				d       /= 10;
365654359Sroberto			}
3657282408Scy
365854359Sroberto			if (d)
365954359Sroberto			    percent = (percent * 10000) / d;
366054359Sroberto			else
366154359Sroberto			    percent = 10000;
366254359Sroberto
366354359Sroberto			if (s_time)
366454359Sroberto			{
366554359Sroberto				char item[80];
366654359Sroberto				int count;
3667282408Scy
3668182007Sroberto				snprintf(item, 80, "%s%s%s: %s (%d.%02d%%)",
366954359Sroberto					sum ? "; " : "",
367054359Sroberto					(parse->generic->currentstatus == i) ? "*" : "",
367154359Sroberto					clockstatus((unsigned int)i),
367254359Sroberto					l_mktime(s_time),
367354359Sroberto					(int)(percent / 100), (int)(percent % 100));
3674282408Scy				if ((count = (int) strlen(item)) < (LEN_STATES - 40 - (tt - start)))
367554359Sroberto					{
3676280849Scy						tt = ap(start, LEN_STATES, tt,
3677280849Scy						    "%s", item);
367854359Sroberto					}
367954359Sroberto				sum += s_time;
368054359Sroberto			}
368154359Sroberto		}
3682282408Scy
3683316068Sdelphij		ap(start, LEN_STATES, tt, "; running time: %s\"", l_mktime(sum));
3684282408Scy
368554359Sroberto		tt = add_var(&out->kv_list, 32, RO);
3686182007Sroberto		snprintf(tt, 32,  "refclock_id=\"%s\"", parse->parse_type->cl_id);
3687282408Scy
368854359Sroberto		tt = add_var(&out->kv_list, 80, RO);
3689182007Sroberto		snprintf(tt, 80,  "refclock_iomode=\"%s\"", parse->binding->bd_description);
369054359Sroberto
369154359Sroberto		tt = add_var(&out->kv_list, 128, RO);
3692182007Sroberto		snprintf(tt, 128, "refclock_driver_version=\"%s\"", rcsid);
3693282408Scy
369454359Sroberto		{
369554359Sroberto			struct ctl_var *k;
3696282408Scy
369754359Sroberto			k = parse->kv;
369854359Sroberto			while (k && !(k->flags & EOV))
369954359Sroberto			{
370054359Sroberto				set_var(&out->kv_list, k->text, strlen(k->text)+1, k->flags);
370154359Sroberto				k++;
370254359Sroberto			}
370354359Sroberto		}
3704282408Scy
3705282408Scy		out->lencode       = (u_short) strlen(outstatus);
370654359Sroberto		out->p_lastcode    = outstatus;
370754359Sroberto	}
370854359Sroberto}
370954359Sroberto
371054359Sroberto/**===========================================================================
371154359Sroberto ** processing routines
371254359Sroberto **/
371354359Sroberto
371454359Sroberto/*--------------------------------------------------
371554359Sroberto * event handling - note that nominal events will also be posted
3716182007Sroberto * keep track of state dwelling times
371754359Sroberto */
371854359Srobertostatic void
371954359Srobertoparse_event(
372054359Sroberto	struct parseunit *parse,
372154359Sroberto	int event
372254359Sroberto	)
372354359Sroberto{
372454359Sroberto	if (parse->generic->currentstatus != (u_char) event)
372554359Sroberto	{
372654359Sroberto		parse->statetime[parse->generic->currentstatus] += current_time - parse->lastchange;
372754359Sroberto		parse->lastchange              = current_time;
372854359Sroberto
372954359Sroberto		if (parse->parse_type->cl_event)
373054359Sroberto		    parse->parse_type->cl_event(parse, event);
3731280849Scy
3732182007Sroberto		if (event == CEVNT_NOMINAL)
373354359Sroberto		{
373454359Sroberto			NLOG(NLOG_CLOCKSTATUS)
373554359Sroberto				msyslog(LOG_INFO, "PARSE receiver #%d: SYNCHRONIZED",
373654359Sroberto					CLK_UNIT(parse->peer));
373754359Sroberto		}
373854359Sroberto
3739182007Sroberto		refclock_report(parse->peer, event);
374054359Sroberto	}
374154359Sroberto}
374254359Sroberto
374354359Sroberto/*--------------------------------------------------
374454359Sroberto * process a PARSE time sample
374554359Sroberto */
374654359Srobertostatic void
374754359Srobertoparse_process(
374854359Sroberto	struct parseunit *parse,
374954359Sroberto	parsetime_t      *parsetime
375054359Sroberto	)
375154359Sroberto{
375254359Sroberto	l_fp off, rectime, reftime;
375354359Sroberto	double fudge;
3754282408Scy
3755280849Scy	/* silence warning: 'off.Ul_i.Xl_i' may be used uninitialized in this function */
3756280849Scy	ZERO(off);
3757280849Scy
375854359Sroberto	/*
375954359Sroberto	 * check for changes in conversion status
376054359Sroberto	 * (only one for each new status !)
376154359Sroberto	 */
376254359Sroberto	if (((parsetime->parse_status & CVT_MASK) != CVT_OK) &&
376354359Sroberto	    ((parsetime->parse_status & CVT_MASK) != CVT_NONE) &&
3764182007Sroberto	    (parse->timedata.parse_status != parsetime->parse_status))
376554359Sroberto	{
376654359Sroberto		char buffer[400];
3767282408Scy
376854359Sroberto		NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */
376954359Sroberto			msyslog(LOG_WARNING, "PARSE receiver #%d: conversion status \"%s\"",
3770182007Sroberto				CLK_UNIT(parse->peer), parsestatus(parsetime->parse_status, buffer, sizeof(buffer)));
3771282408Scy
377254359Sroberto		if ((parsetime->parse_status & CVT_MASK) == CVT_FAIL)
377354359Sroberto		{
377454359Sroberto			/*
377554359Sroberto			 * tell more about the story - list time code
377654359Sroberto			 * there is a slight change for a race condition and
377754359Sroberto			 * the time code might be overwritten by the next packet
377854359Sroberto			 */
377954359Sroberto			parsectl_t tmpctl;
3780282408Scy
378154359Sroberto			if (!PARSE_GETTIMECODE(parse, &tmpctl))
378254359Sroberto			{
378354359Sroberto				ERR(ERR_INTERNAL)
378454359Sroberto					msyslog(LOG_ERR, "PARSE receiver #%d: parse_process: parse_timecode() FAILED", CLK_UNIT(parse->peer));
378554359Sroberto			}
378654359Sroberto			else
378754359Sroberto			{
3788330106Sdelphij				unsigned int count = tmpctl.parsegettc.parse_count;
3789330106Sdelphij				if (count)
3790330106Sdelphij					--count;
379154359Sroberto				ERR(ERR_BADDATA)
3792330106Sdelphij				    msyslog(LOG_WARNING, "PARSE receiver #%d: FAILED TIMECODE: \"%s\" (check receiver configuration / wiring)",
3793330106Sdelphij					    CLK_UNIT(parse->peer),
3794330106Sdelphij					    mkascii(buffer, sizeof(buffer),
3795330106Sdelphij						    tmpctl.parsegettc.parse_buffer, count));
379654359Sroberto			}
3797285169Scy			/* copy status to show only changes in case of failures */
3798285169Scy			parse->timedata.parse_status = parsetime->parse_status;
379954359Sroberto		}
380054359Sroberto	}
380154359Sroberto
380254359Sroberto	/*
380354359Sroberto	 * examine status and post appropriate events
380454359Sroberto	 */
380554359Sroberto	if ((parsetime->parse_status & CVT_MASK) != CVT_OK)
380654359Sroberto	{
380754359Sroberto		/*
380854359Sroberto		 * got bad data - tell the rest of the system
380954359Sroberto		 */
381054359Sroberto		switch (parsetime->parse_status & CVT_MASK)
381154359Sroberto		{
381254359Sroberto		case CVT_NONE:
381354359Sroberto			if ((parsetime->parse_status & CVT_ADDITIONAL) &&
381454359Sroberto			    parse->parse_type->cl_message)
381554359Sroberto				parse->parse_type->cl_message(parse, parsetime);
3816182007Sroberto			/*
3817182007Sroberto			 * save PPS information that comes piggyback
3818182007Sroberto			 */
3819182007Sroberto			if (PARSE_PPS(parsetime->parse_state))
3820182007Sroberto			  {
3821182007Sroberto			    parse->timedata.parse_state |= PARSEB_PPS|PARSEB_S_PPS;
3822182007Sroberto			    parse->timedata.parse_ptime  = parsetime->parse_ptime;
3823182007Sroberto			  }
382454359Sroberto			break; 		/* well, still waiting - timeout is handled at higher levels */
3825282408Scy
382654359Sroberto		case CVT_FAIL:
382754359Sroberto			if (parsetime->parse_status & CVT_BADFMT)
382854359Sroberto			{
382954359Sroberto				parse_event(parse, CEVNT_BADREPLY);
383054359Sroberto			}
383154359Sroberto			else
383254359Sroberto				if (parsetime->parse_status & CVT_BADDATE)
383354359Sroberto				{
383454359Sroberto					parse_event(parse, CEVNT_BADDATE);
383554359Sroberto				}
383654359Sroberto				else
383754359Sroberto					if (parsetime->parse_status & CVT_BADTIME)
383854359Sroberto					{
383954359Sroberto						parse_event(parse, CEVNT_BADTIME);
384054359Sroberto					}
384154359Sroberto					else
384254359Sroberto					{
384354359Sroberto						parse_event(parse, CEVNT_BADREPLY); /* for the lack of something better */
384454359Sroberto					}
384554359Sroberto		}
384654359Sroberto		return;			/* skip the rest - useless */
384754359Sroberto	}
384854359Sroberto
384954359Sroberto	/*
385054359Sroberto	 * check for format changes
385154359Sroberto	 * (in case somebody has swapped clocks 8-)
385254359Sroberto	 */
385354359Sroberto	if (parse->lastformat != parsetime->parse_format)
385454359Sroberto	{
385554359Sroberto		parsectl_t tmpctl;
3856282408Scy
385754359Sroberto		tmpctl.parseformat.parse_format = parsetime->parse_format;
385854359Sroberto
385954359Sroberto		if (!PARSE_GETFMT(parse, &tmpctl))
386054359Sroberto		{
386154359Sroberto			ERR(ERR_INTERNAL)
386254359Sroberto				msyslog(LOG_ERR, "PARSE receiver #%d: parse_getfmt() FAILED", CLK_UNIT(parse->peer));
386354359Sroberto		}
386454359Sroberto		else
386554359Sroberto		{
386654359Sroberto			NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */
386754359Sroberto				msyslog(LOG_INFO, "PARSE receiver #%d: packet format \"%s\"",
386854359Sroberto					CLK_UNIT(parse->peer), tmpctl.parseformat.parse_buffer);
386954359Sroberto		}
387054359Sroberto		parse->lastformat = parsetime->parse_format;
387154359Sroberto	}
387254359Sroberto
387354359Sroberto	/*
387454359Sroberto	 * now, any changes ?
387554359Sroberto	 */
3876182007Sroberto	if ((parse->timedata.parse_state ^ parsetime->parse_state) &
3877182007Sroberto	    ~(unsigned)(PARSEB_PPS|PARSEB_S_PPS))
387854359Sroberto	{
387954359Sroberto		char tmp1[200];
388054359Sroberto		char tmp2[200];
388154359Sroberto		/*
3882182007Sroberto		 * something happend - except for PPS events
388354359Sroberto		 */
3884282408Scy
3885182007Sroberto		(void) parsestate(parsetime->parse_state, tmp1, sizeof(tmp1));
3886182007Sroberto		(void) parsestate(parse->timedata.parse_state, tmp2, sizeof(tmp2));
3887282408Scy
388854359Sroberto		NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */
388954359Sroberto			msyslog(LOG_INFO,"PARSE receiver #%d: STATE CHANGE: %s -> %s",
389054359Sroberto				CLK_UNIT(parse->peer), tmp2, tmp1);
389154359Sroberto	}
389254359Sroberto
389354359Sroberto	/*
3894182007Sroberto	 * carry on PPS information if still usable
3895182007Sroberto	 */
3896182007Sroberto	if (PARSE_PPS(parse->timedata.parse_state) && !PARSE_PPS(parsetime->parse_state))
3897182007Sroberto        {
3898182007Sroberto	        parsetime->parse_state |= PARSEB_PPS|PARSEB_S_PPS;
3899182007Sroberto		parsetime->parse_ptime  = parse->timedata.parse_ptime;
3900182007Sroberto	}
3901182007Sroberto
3902182007Sroberto	/*
390354359Sroberto	 * remember for future
390454359Sroberto	 */
3905182007Sroberto	parse->timedata = *parsetime;
390654359Sroberto
390754359Sroberto	/*
390854359Sroberto	 * check to see, whether the clock did a complete powerup or lost PZF signal
390954359Sroberto	 * and post correct events for current condition
391054359Sroberto	 */
391154359Sroberto	if (PARSE_POWERUP(parsetime->parse_state))
391254359Sroberto	{
391354359Sroberto		/*
391454359Sroberto		 * this is bad, as we have completely lost synchronisation
391554359Sroberto		 * well this is a problem with the receiver here
391654359Sroberto		 * for PARSE Meinberg DCF77 receivers the lost synchronisation
391754359Sroberto		 * is true as it is the powerup state and the time is taken
391854359Sroberto		 * from a crude real time clock chip
3919280849Scy		 * for the PZF/GPS series this is only partly true, as
392054359Sroberto		 * PARSE_POWERUP only means that the pseudo random
392154359Sroberto		 * phase shift sequence cannot be found. this is only
392254359Sroberto		 * bad, if we have never seen the clock in the SYNC
392354359Sroberto		 * state, where the PHASE and EPOCH are correct.
392454359Sroberto		 * for reporting events the above business does not
392554359Sroberto		 * really matter, but we can use the time code
392654359Sroberto		 * even in the POWERUP state after having seen
392754359Sroberto		 * the clock in the synchronized state (PZF class
392854359Sroberto		 * receivers) unless we have had a telegram disruption
392954359Sroberto		 * after having seen the clock in the SYNC state. we
393054359Sroberto		 * thus require having seen the clock in SYNC state
393154359Sroberto		 * *after* having missed telegrams (noresponse) from
393254359Sroberto		 * the clock. one problem remains: we might use erroneously
393354359Sroberto		 * POWERUP data if the disruption is shorter than 1 polling
393454359Sroberto		 * interval. fortunately powerdowns last usually longer than 64
393554359Sroberto		 * seconds and the receiver is at least 2 minutes in the
393654359Sroberto		 * POWERUP or NOSYNC state before switching to SYNC
3937280849Scy		 * for GPS receivers this can mean antenna problems and other causes.
3938280849Scy		 * the additional grace period can be enables by a clock
3939280849Scy		 * mode having the PARSE_F_POWERUPTRUST flag in cl_flag set.
394054359Sroberto		 */
394154359Sroberto		parse_event(parse, CEVNT_FAULT);
394254359Sroberto		NLOG(NLOG_CLOCKSTATUS)
394354359Sroberto			ERR(ERR_BADSTATUS)
3944280849Scy			msyslog(LOG_ERR,"PARSE receiver #%d: NOT SYNCHRONIZED/RECEIVER PROBLEMS",
394554359Sroberto				CLK_UNIT(parse->peer));
394654359Sroberto	}
394754359Sroberto	else
394854359Sroberto	{
394954359Sroberto		/*
395054359Sroberto		 * we have two states left
395154359Sroberto		 *
395254359Sroberto		 * SYNC:
395354359Sroberto		 *  this state means that the EPOCH (timecode) and PHASE
395454359Sroberto		 *  information has be read correctly (at least two
395554359Sroberto		 *  successive PARSE timecodes were received correctly)
395654359Sroberto		 *  this is the best possible state - full trust
395754359Sroberto		 *
395854359Sroberto		 * NOSYNC:
395954359Sroberto		 *  The clock should be on phase with respect to the second
396054359Sroberto		 *  signal, but the timecode has not been received correctly within
396154359Sroberto		 *  at least the last two minutes. this is a sort of half baked state
396254359Sroberto		 *  for PARSE Meinberg DCF77 clocks this is bad news (clock running
396354359Sroberto		 *  without timecode confirmation)
396454359Sroberto		 *  PZF 535 has also no time confirmation, but the phase should be
396554359Sroberto		 *  very precise as the PZF signal can be decoded
396654359Sroberto		 */
396754359Sroberto
396854359Sroberto		if (PARSE_SYNC(parsetime->parse_state))
396954359Sroberto		{
397054359Sroberto			/*
397154359Sroberto			 * currently completely synchronized - best possible state
397254359Sroberto			 */
397354359Sroberto			parse->lastsync = current_time;
397454359Sroberto			clear_err(parse, ERR_BADSTATUS);
397554359Sroberto		}
397654359Sroberto		else
397754359Sroberto		{
397854359Sroberto			/*
397954359Sroberto			 * we have had some problems receiving the time code
398054359Sroberto			 */
398154359Sroberto			parse_event(parse, CEVNT_PROP);
398254359Sroberto			NLOG(NLOG_CLOCKSTATUS)
398354359Sroberto				ERR(ERR_BADSTATUS)
398454359Sroberto				msyslog(LOG_ERR,"PARSE receiver #%d: TIMECODE NOT CONFIRMED",
398554359Sroberto					CLK_UNIT(parse->peer));
398654359Sroberto		}
398754359Sroberto	}
398854359Sroberto
398954359Sroberto	fudge = parse->generic->fudgetime1; /* standard RS232 Fudgefactor */
3990282408Scy
399154359Sroberto	if (PARSE_TIMECODE(parsetime->parse_state))
399254359Sroberto	{
399354359Sroberto		rectime = parsetime->parse_stime.fp;
399454359Sroberto		off = reftime = parsetime->parse_time.fp;
3995282408Scy
399654359Sroberto		L_SUB(&off, &rectime); /* prepare for PPS adjustments logic */
399754359Sroberto
399854359Sroberto#ifdef DEBUG
399954359Sroberto		if (debug > 3)
400054359Sroberto			printf("PARSE receiver #%d: Reftime %s, Recvtime %s - initial offset %s\n",
400154359Sroberto			       CLK_UNIT(parse->peer),
400254359Sroberto			       prettydate(&reftime),
400354359Sroberto			       prettydate(&rectime),
400454359Sroberto			       lfptoa(&off,6));
400554359Sroberto#endif
400654359Sroberto	}
400754359Sroberto
400854359Sroberto	if (PARSE_PPS(parsetime->parse_state) && CLK_PPS(parse->peer))
400954359Sroberto	{
401054359Sroberto		l_fp offset;
4011182007Sroberto		double ppsphaseadjust = parse->ppsphaseadjust;
401254359Sroberto
4013182007Sroberto#ifdef HAVE_PPSAPI
401454359Sroberto		/*
4015182007Sroberto		 * set fudge = 0.0 if already included in PPS time stamps
4016182007Sroberto		 */
4017280849Scy		if (parse->atom.pps_params.mode & (PPS_OFFSETCLEAR|PPS_OFFSETASSERT))
4018182007Sroberto		        {
4019182007Sroberto			        ppsphaseadjust = 0.0;
4020182007Sroberto			}
4021182007Sroberto#endif
4022182007Sroberto
4023182007Sroberto		/*
402454359Sroberto		 * we have a PPS signal - much better than the RS232 stuff (we hope)
402554359Sroberto		 */
402654359Sroberto		offset = parsetime->parse_ptime.fp;
402754359Sroberto
402854359Sroberto#ifdef DEBUG
402954359Sroberto		if (debug > 3)
403054359Sroberto			printf("PARSE receiver #%d: PPStime %s\n",
403154359Sroberto				CLK_UNIT(parse->peer),
403254359Sroberto				prettydate(&offset));
403354359Sroberto#endif
403454359Sroberto		if (PARSE_TIMECODE(parsetime->parse_state))
403554359Sroberto		{
4036280849Scy			if (M_ISGEQ(off.l_i, off.l_uf, -1, 0x80000000) &&
4037280849Scy			    M_ISGEQ(0, 0x7fffffff, off.l_i, off.l_uf))
403854359Sroberto			{
4039182007Sroberto				fudge = ppsphaseadjust; /* pick PPS fudge factor */
4040282408Scy
404154359Sroberto				/*
404254359Sroberto				 * RS232 offsets within [-0.5..0.5[ - take PPS offsets
404354359Sroberto				 */
404454359Sroberto
404554359Sroberto				if (parse->parse_type->cl_flags & PARSE_F_PPSONSECOND)
404654359Sroberto				{
404754359Sroberto					reftime = off = offset;
4048280849Scy					if (reftime.l_uf & 0x80000000)
404954359Sroberto						reftime.l_ui++;
405054359Sroberto					reftime.l_uf = 0;
405156746Sroberto
4052282408Scy
405354359Sroberto					/*
405454359Sroberto					 * implied on second offset
405554359Sroberto					 */
405654359Sroberto					off.l_uf = ~off.l_uf; /* map [0.5..1[ -> [-0.5..0[ */
4057280849Scy					off.l_i = (off.l_uf & 0x80000000) ? -1 : 0; /* sign extend */
405854359Sroberto				}
405954359Sroberto				else
406054359Sroberto				{
406154359Sroberto					/*
406254359Sroberto					 * time code describes pulse
406354359Sroberto					 */
406454359Sroberto					reftime = off = parsetime->parse_time.fp;
406554359Sroberto
406654359Sroberto					L_SUB(&off, &offset); /* true offset */
406754359Sroberto				}
406854359Sroberto			}
406954359Sroberto			/*
407054359Sroberto			 * take RS232 offset when PPS when out of bounds
407154359Sroberto			 */
407254359Sroberto		}
407354359Sroberto		else
407454359Sroberto		{
4075182007Sroberto			fudge = ppsphaseadjust; /* pick PPS fudge factor */
407654359Sroberto			/*
407754359Sroberto			 * Well, no time code to guide us - assume on second pulse
407854359Sroberto			 * and pray, that we are within [-0.5..0.5[
407954359Sroberto			 */
408054359Sroberto			off = offset;
408154359Sroberto			reftime = offset;
4082280849Scy			if (reftime.l_uf & 0x80000000)
408354359Sroberto				reftime.l_ui++;
408454359Sroberto			reftime.l_uf = 0;
408554359Sroberto			/*
408654359Sroberto			 * implied on second offset
408754359Sroberto			 */
408854359Sroberto			off.l_uf = ~off.l_uf; /* map [0.5..1[ -> [-0.5..0[ */
4089280849Scy			off.l_i = (off.l_uf & 0x80000000) ? -1 : 0; /* sign extend */
409054359Sroberto		}
409154359Sroberto	}
409254359Sroberto	else
409354359Sroberto	{
409454359Sroberto		if (!PARSE_TIMECODE(parsetime->parse_state))
409554359Sroberto		{
409654359Sroberto			/*
409754359Sroberto			 * Well, no PPS, no TIMECODE, no more work ...
409854359Sroberto			 */
409954359Sroberto			if ((parsetime->parse_status & CVT_ADDITIONAL) &&
410054359Sroberto			    parse->parse_type->cl_message)
410154359Sroberto				parse->parse_type->cl_message(parse, parsetime);
410254359Sroberto			return;
410354359Sroberto		}
410454359Sroberto	}
410554359Sroberto
410654359Sroberto#ifdef DEBUG
410754359Sroberto	if (debug > 3)
410854359Sroberto		printf("PARSE receiver #%d: Reftime %s, Recvtime %s - final offset %s\n",
410954359Sroberto			CLK_UNIT(parse->peer),
411054359Sroberto			prettydate(&reftime),
411154359Sroberto			prettydate(&rectime),
411254359Sroberto			lfptoa(&off,6));
411354359Sroberto#endif
411454359Sroberto
411554359Sroberto
411654359Sroberto	rectime = reftime;
411754359Sroberto	L_SUB(&rectime, &off);	/* just to keep the ntp interface happy */
4118282408Scy
411954359Sroberto#ifdef DEBUG
412054359Sroberto	if (debug > 3)
412154359Sroberto		printf("PARSE receiver #%d: calculated Reftime %s, Recvtime %s\n",
412254359Sroberto			CLK_UNIT(parse->peer),
412354359Sroberto			prettydate(&reftime),
412454359Sroberto			prettydate(&rectime));
412554359Sroberto#endif
412654359Sroberto
412754359Sroberto	if ((parsetime->parse_status & CVT_ADDITIONAL) &&
412854359Sroberto	    parse->parse_type->cl_message)
412954359Sroberto		parse->parse_type->cl_message(parse, parsetime);
413054359Sroberto
413154359Sroberto	if (PARSE_SYNC(parsetime->parse_state))
413254359Sroberto	{
413354359Sroberto		/*
413454359Sroberto		 * log OK status
413554359Sroberto		 */
413654359Sroberto		parse_event(parse, CEVNT_NOMINAL);
413754359Sroberto	}
413854359Sroberto
413954359Sroberto	clear_err(parse, ERR_BADIO);
414054359Sroberto	clear_err(parse, ERR_BADDATA);
414154359Sroberto	clear_err(parse, ERR_NODATA);
414254359Sroberto	clear_err(parse, ERR_INTERNAL);
4143282408Scy
414454359Sroberto	/*
414554359Sroberto	 * and now stick it into the clock machine
414654359Sroberto	 * samples are only valid iff lastsync is not too old and
414754359Sroberto	 * we have seen the clock in sync at least once
414854359Sroberto	 * after the last time we didn't see an expected data telegram
4149182007Sroberto	 * at startup being not in sync is also bad just like
4150282408Scy	 * POWERUP state unless PARSE_F_POWERUPTRUST is set
415154359Sroberto	 * see the clock states section above for more reasoning
415254359Sroberto	 */
4153280849Scy	if (((current_time - parse->lastsync) > parse->maxunsync)           ||
4154280849Scy	    (parse->lastsync < parse->lastmissed)                           ||
4155182007Sroberto	    ((parse->lastsync == 0) && !PARSE_SYNC(parsetime->parse_state)) ||
4156280849Scy	    (((parse->parse_type->cl_flags & PARSE_F_POWERUPTRUST) == 0) &&
4157280849Scy	     PARSE_POWERUP(parsetime->parse_state)))
415854359Sroberto	{
415954359Sroberto		parse->generic->leap = LEAP_NOTINSYNC;
4160182007Sroberto		parse->lastsync = 0;	/* wait for full sync again */
416154359Sroberto	}
416254359Sroberto	else
416354359Sroberto	{
416454359Sroberto		if (PARSE_LEAPADD(parsetime->parse_state))
416554359Sroberto		{
416654359Sroberto			/*
416754359Sroberto			 * we pick this state also for time code that pass leap warnings
416854359Sroberto			 * without direction information (as earth is currently slowing
416954359Sroberto			 * down).
417054359Sroberto			 */
417154359Sroberto			parse->generic->leap = (parse->flags & PARSE_LEAP_DELETE) ? LEAP_DELSECOND : LEAP_ADDSECOND;
417254359Sroberto		}
417354359Sroberto		else
417454359Sroberto		    if (PARSE_LEAPDEL(parsetime->parse_state))
417554359Sroberto		    {
417654359Sroberto			    parse->generic->leap = LEAP_DELSECOND;
417754359Sroberto		    }
417854359Sroberto		    else
417954359Sroberto		    {
418054359Sroberto			    parse->generic->leap = LEAP_NOWARNING;
418154359Sroberto		    }
418254359Sroberto	}
4183182007Sroberto
4184182007Sroberto	if (parse->generic->leap != LEAP_NOTINSYNC)
4185182007Sroberto	{
4186182007Sroberto	        /*
4187182007Sroberto		 * only good/trusted samples are interesting
4188182007Sroberto		 */
4189182007Sroberto#ifdef DEBUG
4190282408Scy	        if (debug > 2)
4191282408Scy			{
4192282408Scy				       printf("PARSE receiver #%d: refclock_process_offset(reftime=%s, rectime=%s, Fudge=%f)\n",
4193182007Sroberto				       CLK_UNIT(parse->peer),
4194182007Sroberto				       prettydate(&reftime),
4195182007Sroberto				       prettydate(&rectime),
4196182007Sroberto				       fudge);
4197182007Sroberto			}
4198182007Sroberto#endif
4199182007Sroberto		parse->generic->lastref = reftime;
4200282408Scy
4201182007Sroberto		refclock_process_offset(parse->generic, reftime, rectime, fudge);
4202182007Sroberto
4203280849Scy#ifdef HAVE_PPSAPI
4204182007Sroberto		/*
4205182007Sroberto		 * pass PPS information on to PPS clock
4206182007Sroberto		 */
4207182007Sroberto		if (PARSE_PPS(parsetime->parse_state) && CLK_PPS(parse->peer))
4208282408Scy			{
4209282408Scy				parse->peer->flags |= (FLAG_PPS | FLAG_TSTAMP_PPS);
4210182007Sroberto				parse_hardpps(parse, PARSE_HARDPPS_ENABLE);
4211182007Sroberto			}
4212280849Scy#endif
4213182007Sroberto	} else {
4214282408Scy		parse_hardpps(parse, PARSE_HARDPPS_DISABLE);
4215282408Scy		parse->peer->flags &= ~(FLAG_PPS | FLAG_TSTAMP_PPS);
4216182007Sroberto	}
4217182007Sroberto
421854359Sroberto	/*
4219282408Scy	 * ready, unless the machine wants a sample or
4220182007Sroberto	 * we are in fast startup mode (peer->dist > MAXDISTANCE)
422154359Sroberto	 */
4222182007Sroberto	if (!parse->pollneeddata && parse->peer->disp <= MAXDISTANCE)
422354359Sroberto	    return;
422454359Sroberto
422554359Sroberto	parse->pollneeddata = 0;
422654359Sroberto
4227182007Sroberto	parse->timedata.parse_state &= ~(unsigned)(PARSEB_PPS|PARSEB_S_PPS);
4228182007Sroberto
422954359Sroberto	refclock_receive(parse->peer);
423054359Sroberto}
4231282408Scy
423254359Sroberto/**===========================================================================
423354359Sroberto ** special code for special clocks
423454359Sroberto **/
423554359Sroberto
423654359Srobertostatic void
423754359Srobertomk_utcinfo(
4238316068Sdelphij	   char *t,  /* pointer to the output string buffer */
4239316068Sdelphij	   uint16_t wnt,
4240316068Sdelphij	   uint16_t wnlsf,
424154359Sroberto	   int dn,
424254359Sroberto	   int dtls,
4243182007Sroberto	   int dtlsf,
4244316068Sdelphij	   int size  /* size of the output string buffer */
424554359Sroberto	   )
424654359Sroberto{
4247282408Scy	/*
4248282408Scy	 * The week number transmitted by the GPS satellites for the leap date
4249282408Scy	 * is truncated to 8 bits only. If the nearest leap second date is off
4250282408Scy	 * the current date by more than +/- 128 weeks then conversion to a
4251282408Scy	 * calendar date is ambiguous. On the other hand, if a leap second is
4252282408Scy	 * currently being announced (i.e. dtlsf != dtls) then the week number
4253282408Scy	 * wnlsf is close enough, and we can unambiguously determine the date
4254282408Scy	 * for which the leap second is scheduled.
4255282408Scy	 */
4256282408Scy	if ( dtlsf != dtls )
4257282408Scy	{
4258282408Scy		time_t t_ls;
4259282408Scy		struct tm *tm;
4260316068Sdelphij		int nc;
4261282408Scy
4262344884Scy		wnlsf = basedate_expand_gpsweek(wnlsf);
4263316068Sdelphij		/* 'wnt' not used here: would need the same treatment as 'wnlsf */
4264282408Scy
4265282408Scy		t_ls = (time_t) wnlsf * SECSPERWEEK
4266282408Scy			+ (time_t) dn * SECSPERDAY
4267282408Scy			+ GPS_SEC_BIAS - 1;
4268282408Scy
4269282408Scy		tm = gmtime( &t_ls );
4270316068Sdelphij		if (tm == NULL)  /* gmtime() failed */
4271282408Scy		{
4272282408Scy			snprintf( t, size, "** (gmtime() failed in mk_utcinfo())" );
4273282408Scy			return;
4274282408Scy		}
4275282408Scy
4276316068Sdelphij		nc = snprintf( t, size, "UTC offset transition from %is to %is due to leap second %s",
4277282408Scy				dtls, dtlsf, ( dtls < dtlsf ) ? "insertion" : "deletion" );
4278316068Sdelphij		if (nc < 0)
4279316068Sdelphij			nc = strlen(t);
4280316068Sdelphij		else if (nc > size)
4281316068Sdelphij			nc = size;
4282316068Sdelphij
4283316068Sdelphij		snprintf( t + nc, size - nc, " at UTC midnight at the end of %s, %04i-%02i-%02i",
4284282408Scy				daynames[tm->tm_wday], tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday );
4285282408Scy	}
4286282408Scy	else
4287316068Sdelphij	{
4288282408Scy		snprintf( t, size, "UTC offset parameter: %is, no leap second announced.\n", dtls );
4289316068Sdelphij	}
4290282408Scy
429154359Sroberto}
429254359Sroberto
429354359Sroberto#ifdef CLOCK_MEINBERG
429454359Sroberto/**===========================================================================
4295282408Scy ** Meinberg GPS receiver support
429654359Sroberto **/
429754359Sroberto
429854359Sroberto/*------------------------------------------------------------
4299282408Scy * gps16x_message - process messages from Meinberg GPS receiver
430054359Sroberto */
430154359Srobertostatic void
430254359Srobertogps16x_message(
430354359Sroberto	       struct parseunit *parse,
430454359Sroberto	       parsetime_t      *parsetime
430554359Sroberto	       )
430654359Sroberto{
4307182007Sroberto	if (parse->timedata.parse_msglen && parsetime->parse_msg[0] == SOH)
430854359Sroberto	{
430954359Sroberto		GPS_MSG_HDR header;
431054359Sroberto		unsigned char *bufp = (unsigned char *)parsetime->parse_msg + 1;
4311282408Scy
431254359Sroberto#ifdef DEBUG
431354359Sroberto		if (debug > 2)
431454359Sroberto		{
431554359Sroberto			char msgbuffer[600];
4316282408Scy
431754359Sroberto			mkreadable(msgbuffer, sizeof(msgbuffer), (char *)parsetime->parse_msg, parsetime->parse_msglen, 1);
431854359Sroberto			printf("PARSE receiver #%d: received message (%d bytes) >%s<\n",
431954359Sroberto				CLK_UNIT(parse->peer),
432054359Sroberto				parsetime->parse_msglen,
432154359Sroberto				msgbuffer);
432254359Sroberto		}
432354359Sroberto#endif
432454359Sroberto		get_mbg_header(&bufp, &header);
4325282408Scy		if (header.hdr_csum == mbg_csum(parsetime->parse_msg + 1, 6) &&
4326282408Scy		    (header.len == 0 ||
4327282408Scy		     (header.len < sizeof(parsetime->parse_msg) &&
4328282408Scy		      header.data_csum == mbg_csum(bufp, header.len))))
432954359Sroberto		{
433054359Sroberto			/*
433154359Sroberto			 * clean message
433254359Sroberto			 */
4333282408Scy			switch (header.cmd)
433454359Sroberto			{
433554359Sroberto			case GPS_SW_REV:
433654359Sroberto				{
433754359Sroberto					char buffer[64];
433854359Sroberto					SW_REV gps_sw_rev;
4339282408Scy
434054359Sroberto					get_mbg_sw_rev(&bufp, &gps_sw_rev);
4341182007Sroberto					snprintf(buffer, sizeof(buffer), "meinberg_gps_version=\"%x.%02x%s%s\"",
434254359Sroberto						(gps_sw_rev.code >> 8) & 0xFF,
434354359Sroberto						gps_sw_rev.code & 0xFF,
434454359Sroberto						gps_sw_rev.name[0] ? " " : "",
434554359Sroberto						gps_sw_rev.name);
4346182007Sroberto					set_var(&parse->kv, buffer, strlen(buffer)+1, RO|DEF);
434754359Sroberto				}
434854359Sroberto			break;
434954359Sroberto
4350282408Scy			case GPS_BVAR_STAT:
435154359Sroberto				{
435254359Sroberto					static struct state
435354359Sroberto					{
4354282408Scy						BVAR_STAT flag; /* status flag */
4355282408Scy						const char *string; /* bit name */
435654359Sroberto					} states[] =
435754359Sroberto					  {
4358282408Scy						  { BVAR_CFGH_INVALID,     "Configuration/Health" },
4359282408Scy						  { BVAR_ALM_NOT_COMPLETE, "Almanachs" },
4360282408Scy						  { BVAR_UTC_INVALID,      "UTC Correction" },
4361282408Scy						  { BVAR_IONO_INVALID,     "Ionospheric Correction" },
4362282408Scy						  { BVAR_RCVR_POS_INVALID, "Receiver Position" },
4363282408Scy						  { 0, "" }
436454359Sroberto					  };
4365282408Scy					BVAR_STAT status;
436654359Sroberto					struct state *s = states;
436754359Sroberto					char buffer[512];
436854359Sroberto					char *p, *b;
4369282408Scy
4370282408Scy					status = (BVAR_STAT) get_lsb_short(&bufp);
4371280849Scy					p = b = buffer;
4372280849Scy					p = ap(buffer, sizeof(buffer), p,
4373280849Scy					    "meinberg_gps_status=\"[0x%04x] ",
4374280849Scy					    status);
4375282408Scy
437654359Sroberto					if (status)
437754359Sroberto					{
4378282408Scy						p = ap(buffer, sizeof(buffer), p, "incomplete buffered data: ");
4379280849Scy						b = p;
438054359Sroberto						while (s->flag)
438154359Sroberto						{
438254359Sroberto							if (status & s->flag)
438354359Sroberto							{
438454359Sroberto								if (p != b)
438554359Sroberto								{
4386280849Scy									p = ap(buffer, sizeof(buffer), p, ", ");
438754359Sroberto								}
4388282408Scy
4389280849Scy								p = ap(buffer, sizeof(buffer), p, "%s", (const char *)s->string);
439054359Sroberto							}
439154359Sroberto							s++;
439254359Sroberto						}
4393280849Scy						p = ap(buffer, sizeof(buffer), p, "\"");
439454359Sroberto					}
439554359Sroberto					else
439654359Sroberto					{
4397282408Scy						p = ap(buffer, sizeof(buffer), p, "<all buffered data complete>\"");
439854359Sroberto					}
4399282408Scy
4400182007Sroberto					set_var(&parse->kv, buffer, strlen(buffer)+1, RO|DEF);
440154359Sroberto				}
440254359Sroberto			break;
440354359Sroberto
440454359Sroberto			case GPS_POS_XYZ:
440554359Sroberto				{
440654359Sroberto					XYZ xyz;
440754359Sroberto					char buffer[256];
4408282408Scy
440954359Sroberto					get_mbg_xyz(&bufp, xyz);
4410182007Sroberto					snprintf(buffer, sizeof(buffer), "gps_position(XYZ)=\"%s m, %s m, %s m\"",
441154359Sroberto						mfptoa(xyz[XP].l_ui, xyz[XP].l_uf, 1),
441254359Sroberto						mfptoa(xyz[YP].l_ui, xyz[YP].l_uf, 1),
441354359Sroberto						mfptoa(xyz[ZP].l_ui, xyz[ZP].l_uf, 1));
4414282408Scy
441554359Sroberto					set_var(&parse->kv, buffer, sizeof(buffer), RO|DEF);
441654359Sroberto				}
441754359Sroberto			break;
4418282408Scy
441954359Sroberto			case GPS_POS_LLA:
442054359Sroberto				{
442154359Sroberto					LLA lla;
442254359Sroberto					char buffer[256];
4423282408Scy
442454359Sroberto					get_mbg_lla(&bufp, lla);
4425282408Scy
4426182007Sroberto					snprintf(buffer, sizeof(buffer), "gps_position(LLA)=\"%s deg, %s deg, %s m\"",
442754359Sroberto						mfptoa(lla[LAT].l_ui, lla[LAT].l_uf, 4),
4428282408Scy						mfptoa(lla[LON].l_ui, lla[LON].l_uf, 4),
442954359Sroberto						mfptoa(lla[ALT].l_ui, lla[ALT].l_uf, 1));
4430282408Scy
443154359Sroberto					set_var(&parse->kv, buffer, sizeof(buffer), RO|DEF);
443254359Sroberto				}
443354359Sroberto			break;
4434282408Scy
443554359Sroberto			case GPS_TZDL:
443654359Sroberto				break;
4437282408Scy
443854359Sroberto			case GPS_PORT_PARM:
443954359Sroberto				break;
4440282408Scy
444154359Sroberto			case GPS_SYNTH:
444254359Sroberto				break;
4443282408Scy
444454359Sroberto			case GPS_ANT_INFO:
444554359Sroberto				{
444654359Sroberto					ANT_INFO antinfo;
4447182007Sroberto					char buffer[512];
4448280849Scy					char *p, *q;
4449282408Scy
445054359Sroberto					get_mbg_antinfo(&bufp, &antinfo);
4451280849Scy					p = buffer;
4452280849Scy					p = ap(buffer, sizeof(buffer), p, "meinberg_antenna_status=\"");
445354359Sroberto					switch (antinfo.status)
445454359Sroberto					{
4455282408Scy					case ANT_INVALID: // No other fields valid since antenna has not yet been disconnected
4456280849Scy						p = ap(buffer, sizeof(buffer),
4457280849Scy						    p, "<OK>");
445854359Sroberto						break;
4459282408Scy
4460282408Scy					case ANT_DISCONN: // Antenna is disconnected, tm_reconn and delta_t not yet set
4461280849Scy						q = ap(buffer, sizeof(buffer),
4462280849Scy						    p, "DISCONNECTED since ");
446354359Sroberto						NLOG(NLOG_CLOCKSTATUS)
446454359Sroberto							ERR(ERR_BADSTATUS)
446554359Sroberto							msyslog(LOG_ERR,"PARSE receiver #%d: ANTENNA FAILURE: %s",
446654359Sroberto								CLK_UNIT(parse->peer), p);
4467282408Scy
4468280849Scy						p = q;
4469282408Scy						mbg_tm_str(&p, &antinfo.tm_disconn, BUFFER_SIZE(buffer, p), 0);
447054359Sroberto						*p = '\0';
447154359Sroberto						break;
4472282408Scy
4473282408Scy					case ANT_RECONN: // Antenna had been disconnect, but receiver sync. after reconnect, so all fields valid
4474280849Scy						p = ap(buffer, sizeof(buffer),
4475282408Scy						    p, "SYNC AFTER RECONNECT on ");
4476282408Scy						mbg_tm_str(&p, &antinfo.tm_reconn, BUFFER_SIZE(buffer, p), 0);
4477280849Scy						p = ap(buffer, sizeof(buffer),
4478282408Scy							p, ", clock offset at reconnect %c%ld.%07ld s, disconnect time ",
447954359Sroberto							(antinfo.delta_t < 0) ? '-' : '+',
4480282408Scy							(long) ABS(antinfo.delta_t) / 10000,
4481282408Scy							(long) ABS(antinfo.delta_t) % 10000);
4482282408Scy						mbg_tm_str(&p, &antinfo.tm_disconn, BUFFER_SIZE(buffer, p), 0);
448354359Sroberto						*p = '\0';
448454359Sroberto						break;
4485282408Scy
448654359Sroberto					default:
4487280849Scy						p = ap(buffer, sizeof(buffer),
4488280849Scy						    p, "bad status 0x%04x",
4489280849Scy						    antinfo.status);
449054359Sroberto						break;
449154359Sroberto					}
4492282408Scy
4493280849Scy					p = ap(buffer, sizeof(buffer), p, "\"");
4494282408Scy
4495280849Scy					set_var(&parse->kv, buffer, sizeof(buffer), RO|DEF);
449654359Sroberto				}
449754359Sroberto			break;
4498282408Scy
449954359Sroberto			case GPS_UCAP:
450054359Sroberto				break;
4501282408Scy
450254359Sroberto			case GPS_CFGH:
450354359Sroberto				{
450454359Sroberto					CFGH cfgh;
4505182007Sroberto					char buffer[512];
4506182007Sroberto					char *p;
4507282408Scy
450854359Sroberto					get_mbg_cfgh(&bufp, &cfgh);
450954359Sroberto					if (cfgh.valid)
451054359Sroberto					{
4511282408Scy						const char *cp;
4512282408Scy						uint16_t tmp_val;
451354359Sroberto						int i;
4514282408Scy
451554359Sroberto						p = buffer;
4516280849Scy						p = ap(buffer, sizeof(buffer),
4517280849Scy						    p, "gps_tot_51=\"");
4518182007Sroberto						mbg_tgps_str(&p, &cfgh.tot_51, BUFFER_SIZE(buffer, p));
4519280849Scy						p = ap(buffer, sizeof(buffer),
4520280849Scy						    p, "\"");
4521282408Scy						set_var(&parse->kv, buffer, sizeof(buffer), RO|COND_DEF);
4522282408Scy
452354359Sroberto						p = buffer;
4524280849Scy						p = ap(buffer, sizeof(buffer),
4525280849Scy						    p, "gps_tot_63=\"");
4526182007Sroberto						mbg_tgps_str(&p, &cfgh.tot_63, BUFFER_SIZE(buffer, p));
4527280849Scy						p = ap(buffer, sizeof(buffer),
4528280849Scy						    p, "\"");
4529282408Scy						set_var(&parse->kv, buffer, sizeof(buffer), RO|COND_DEF);
4530282408Scy
453154359Sroberto						p = buffer;
4532280849Scy						p = ap(buffer, sizeof(buffer),
4533280849Scy						    p, "gps_t0a=\"");
4534182007Sroberto						mbg_tgps_str(&p, &cfgh.t0a, BUFFER_SIZE(buffer, p));
4535280849Scy						p = ap(buffer, sizeof(buffer),
4536280849Scy						    p, "\"");
4537282408Scy						set_var(&parse->kv, buffer, sizeof(buffer), RO|COND_DEF);
4538282408Scy
4539282408Scy						for (i = 0; i < N_SVNO_GPS; i++)
454054359Sroberto						{
454154359Sroberto							p = buffer;
4542282408Scy							p = ap(buffer, sizeof(buffer), p, "sv_info[%d]=\"PRN%d", i, i + N_SVNO_GPS);
4543282408Scy
4544282408Scy							tmp_val = cfgh.health[i];  /* a 6 bit SV health code */
4545282408Scy							p = ap(buffer, sizeof(buffer), p, "; health=0x%02x (", tmp_val);
4546282408Scy							/* "All Ones" has a special meaning" */
4547282408Scy							if (tmp_val == 0x3F) /* satellite is unusable or doesn't even exist */
4548282408Scy								cp = "SV UNAVAILABLE";
4549282408Scy							else {
4550282408Scy								/* The MSB contains a summary of the 3 MSBs of the 8 bit health code,
4551282408Scy								 * indicating if the data sent by the satellite is OK or not. */
4552282408Scy								p = ap(buffer, sizeof(buffer), p, "DATA %s, ", (tmp_val & 0x20) ? "BAD" : "OK" );
4553282408Scy
4554282408Scy								/* The 5 LSBs contain the status of the different signals sent by the satellite. */
4555282408Scy								switch (tmp_val & 0x1F)
4556282408Scy								{
4557282408Scy									case 0x00: cp = "SIGNAL OK";              break;
4558282408Scy									/* codes 0x01 through 0x1B indicate that one or more
4559282408Scy									 * specific signal components are weak or dead.
4560282408Scy									 * We don't decode this here in detail. */
4561282408Scy									case 0x1C: cp = "SV IS TEMP OUT";         break;
4562282408Scy									case 0x1D: cp = "SV WILL BE TEMP OUT";    break;
4563282408Scy									default:   cp = "TRANSMISSION PROBLEMS";  break;
4564282408Scy								}
456554359Sroberto							}
4566282408Scy							p = ap(buffer, sizeof(buffer), p, "%s)", cp );
4567282408Scy
4568282408Scy							tmp_val = cfgh.cfg[i];  /* a 4 bit SV configuration/type code */
4569282408Scy							p = ap(buffer, sizeof(buffer), p, "; cfg=0x%02x (", tmp_val);
4570282408Scy							switch (tmp_val & 0x7)
457154359Sroberto							{
4572282408Scy								case 0x00:  cp = "(reserved)";        break;
4573282408Scy								case 0x01:  cp = "BLOCK II/IIA/IIR";  break;
4574282408Scy								case 0x02:  cp = "BLOCK IIR-M";       break;
4575282408Scy								case 0x03:  cp = "BLOCK IIF";         break;
4576282408Scy								case 0x04:  cp = "BLOCK III";         break;
4577282408Scy								default:   cp = "unknown SV type";   break;
457854359Sroberto							}
4579282408Scy							p = ap(buffer, sizeof(buffer), p, "%s", cp );
4580282408Scy							if (tmp_val & 0x08)  /* A-S is on, P-code is encrypted */
4581282408Scy								p = ap( buffer, sizeof(buffer), p, ", A-S on" );
4582282408Scy
4583282408Scy							p = ap(buffer, sizeof(buffer), p, ")\"");
4584282408Scy							set_var(&parse->kv, buffer, sizeof(buffer), RO|COND_DEF);
458554359Sroberto						}
458654359Sroberto					}
458754359Sroberto				}
458854359Sroberto			break;
4589282408Scy
459054359Sroberto			case GPS_ALM:
459154359Sroberto				break;
4592282408Scy
459354359Sroberto			case GPS_EPH:
459454359Sroberto				break;
4595282408Scy
459654359Sroberto			case GPS_UTC:
459754359Sroberto				{
459854359Sroberto					UTC utc;
459954359Sroberto					char buffer[512];
460054359Sroberto					char *p;
4601282408Scy
460254359Sroberto					p = buffer;
4603282408Scy
460454359Sroberto					get_mbg_utc(&bufp, &utc);
4605282408Scy
460654359Sroberto					if (utc.valid)
460754359Sroberto					{
4608280849Scy						p = ap(buffer, sizeof(buffer), p, "gps_utc_correction=\"");
4609280849Scy						mk_utcinfo(p, utc.t0t.wn, utc.WNlsf, utc.DNt, utc.delta_tls, utc.delta_tlsf, BUFFER_SIZE(buffer, p));
461054359Sroberto						p += strlen(p);
4611280849Scy						p = ap(buffer, sizeof(buffer), p, "\"");
461254359Sroberto					}
461354359Sroberto					else
461454359Sroberto					{
4615280849Scy						p = ap(buffer, sizeof(buffer), p, "gps_utc_correction=\"<NO UTC DATA>\"");
461654359Sroberto					}
4617280849Scy					set_var(&parse->kv, buffer, sizeof(buffer), RO|DEF);
461854359Sroberto				}
461954359Sroberto			break;
4620282408Scy
462154359Sroberto			case GPS_IONO:
462254359Sroberto				break;
4623282408Scy
462454359Sroberto			case GPS_ASCII_MSG:
462554359Sroberto				{
462654359Sroberto					ASCII_MSG gps_ascii_msg;
462754359Sroberto					char buffer[128];
4628282408Scy
462954359Sroberto					get_mbg_ascii_msg(&bufp, &gps_ascii_msg);
4630282408Scy
463154359Sroberto					if (gps_ascii_msg.valid)
463254359Sroberto						{
463354359Sroberto							char buffer1[128];
463454359Sroberto							mkreadable(buffer1, sizeof(buffer1), gps_ascii_msg.s, strlen(gps_ascii_msg.s), (int)0);
4635282408Scy
4636182007Sroberto							snprintf(buffer, sizeof(buffer), "gps_message=\"%s\"", buffer1);
463754359Sroberto						}
463854359Sroberto					else
4639280849Scy						snprintf(buffer, sizeof(buffer), "gps_message=<NONE>");
4640282408Scy
4641280849Scy					set_var(&parse->kv, buffer, sizeof(buffer), RO|DEF);
464254359Sroberto				}
4643282408Scy
464454359Sroberto			break;
4645282408Scy
464654359Sroberto			default:
464754359Sroberto				break;
464854359Sroberto			}
464954359Sroberto		}
465054359Sroberto		else
465154359Sroberto		{
4652282408Scy			msyslog(LOG_DEBUG, "PARSE receiver #%d: gps16x_message: message checksum error: hdr_csum = 0x%x (expected 0x%x), "
4653282408Scy			                   "data_len = %d, data_csum = 0x%x (expected 0x%x)",
465454359Sroberto				CLK_UNIT(parse->peer),
4655282408Scy				header.hdr_csum, mbg_csum(parsetime->parse_msg + 1, 6),
4656282408Scy				header.len,
4657282408Scy				header.data_csum, mbg_csum(bufp, (unsigned)((header.len < sizeof(parsetime->parse_msg)) ? header.len : 0)));
465854359Sroberto		}
465954359Sroberto	}
4660282408Scy
466154359Sroberto	return;
466254359Sroberto}
466354359Sroberto
466454359Sroberto/*------------------------------------------------------------
466554359Sroberto * gps16x_poll - query the reciver peridically
466654359Sroberto */
466754359Srobertostatic void
466854359Srobertogps16x_poll(
466954359Sroberto	    struct peer *peer
467054359Sroberto	    )
467154359Sroberto{
4672280849Scy	struct parseunit *parse = peer->procptr->unitptr;
4673282408Scy
4674282408Scy	static GPS_MSG_HDR sequence[] =
467554359Sroberto	{
467654359Sroberto		{ GPS_SW_REV,          0, 0, 0 },
4677282408Scy		{ GPS_BVAR_STAT,       0, 0, 0 },
467854359Sroberto		{ GPS_UTC,             0, 0, 0 },
467954359Sroberto		{ GPS_ASCII_MSG,       0, 0, 0 },
468054359Sroberto		{ GPS_ANT_INFO,        0, 0, 0 },
468154359Sroberto		{ GPS_CFGH,            0, 0, 0 },
468254359Sroberto		{ GPS_POS_XYZ,         0, 0, 0 },
468354359Sroberto		{ GPS_POS_LLA,         0, 0, 0 },
468454359Sroberto		{ (unsigned short)~0,  0, 0, 0 }
468554359Sroberto	};
4686280849Scy
468754359Sroberto	int rtc;
468854359Sroberto	unsigned char cmd_buffer[64];
468954359Sroberto	unsigned char *outp = cmd_buffer;
469054359Sroberto	GPS_MSG_HDR *header;
4691282408Scy
469254359Sroberto	if (((poll_info_t *)parse->parse_type->cl_data)->rate)
469354359Sroberto	{
4694280849Scy		parse->peer->procptr->nextaction = current_time + ((poll_info_t *)parse->parse_type->cl_data)->rate;
469554359Sroberto	}
469654359Sroberto
4697282408Scy	if (sequence[parse->localstate].cmd == (unsigned short)~0)
469854359Sroberto		parse->localstate = 0;
4699282408Scy
470054359Sroberto	header = sequence + parse->localstate++;
4701282408Scy
470254359Sroberto	*outp++ = SOH;		/* start command */
4703282408Scy
470454359Sroberto	put_mbg_header(&outp, header);
470554359Sroberto	outp = cmd_buffer + 1;
4706282408Scy
4707282408Scy	header->hdr_csum = (short)mbg_csum(outp, 6);
470854359Sroberto	put_mbg_header(&outp, header);
4709282408Scy
471054359Sroberto#ifdef DEBUG
471154359Sroberto	if (debug > 2)
471254359Sroberto	{
471354359Sroberto		char buffer[128];
4714282408Scy
471554359Sroberto		mkreadable(buffer, sizeof(buffer), (char *)cmd_buffer, (unsigned)(outp - cmd_buffer), 1);
471654359Sroberto		printf("PARSE receiver #%d: transmitted message #%ld (%d bytes) >%s<\n",
471754359Sroberto		       CLK_UNIT(parse->peer),
471854359Sroberto		       parse->localstate - 1,
471954359Sroberto		       (int)(outp - cmd_buffer),
4720282408Scy		       buffer);
472154359Sroberto	}
472254359Sroberto#endif
4723282408Scy
4724282408Scy	rtc = (int) write(parse->generic->io.fd, cmd_buffer, (unsigned long)(outp - cmd_buffer));
4725282408Scy
472654359Sroberto	if (rtc < 0)
472754359Sroberto	{
472854359Sroberto		ERR(ERR_BADIO)
472954359Sroberto			msyslog(LOG_ERR, "PARSE receiver #%d: gps16x_poll: failed to send cmd to clock: %m", CLK_UNIT(parse->peer));
473054359Sroberto	}
473154359Sroberto	else
473254359Sroberto	if (rtc != outp - cmd_buffer)
473354359Sroberto	{
473454359Sroberto		ERR(ERR_BADIO)
473554359Sroberto			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));
473654359Sroberto	}
473754359Sroberto
473854359Sroberto	clear_err(parse, ERR_BADIO);
473954359Sroberto	return;
474054359Sroberto}
474154359Sroberto
474254359Sroberto/*--------------------------------------------------
474354359Sroberto * init routine - setup timer
474454359Sroberto */
474554359Srobertostatic int
474654359Srobertogps16x_poll_init(
474754359Sroberto	struct parseunit *parse
474854359Sroberto	)
474954359Sroberto{
475054359Sroberto	if (((poll_info_t *)parse->parse_type->cl_data)->rate)
475154359Sroberto	{
4752280849Scy		parse->peer->procptr->action = gps16x_poll;
475354359Sroberto		gps16x_poll(parse->peer);
475454359Sroberto	}
475554359Sroberto
475654359Sroberto	return 0;
475754359Sroberto}
475854359Sroberto
475954359Sroberto#else
476054359Srobertostatic void
476154359Srobertogps16x_message(
476254359Sroberto	       struct parseunit *parse,
476354359Sroberto	       parsetime_t      *parsetime
476454359Sroberto	       )
476554359Sroberto{}
476654359Srobertostatic int
476754359Srobertogps16x_poll_init(
476854359Sroberto	struct parseunit *parse
476954359Sroberto	)
477054359Sroberto{
477154359Sroberto	return 1;
477254359Sroberto}
477354359Sroberto#endif /* CLOCK_MEINBERG */
4774282408Scy
477554359Sroberto/**===========================================================================
477654359Sroberto ** clock polling support
477754359Sroberto **/
477854359Sroberto
477954359Sroberto/*--------------------------------------------------
478054359Sroberto * direct poll routine
478154359Sroberto */
478254359Srobertostatic void
478354359Srobertopoll_dpoll(
478454359Sroberto	struct parseunit *parse
478554359Sroberto	)
478654359Sroberto{
4787282408Scy	long rtc;
478854359Sroberto	const char *ps = ((poll_info_t *)parse->parse_type->cl_data)->string;
4789282408Scy	long ct = ((poll_info_t *)parse->parse_type->cl_data)->count;
479054359Sroberto
4791282408Scy	rtc = write(parse->generic->io.fd, ps, ct);
479254359Sroberto	if (rtc < 0)
479354359Sroberto	{
479454359Sroberto		ERR(ERR_BADIO)
479554359Sroberto			msyslog(LOG_ERR, "PARSE receiver #%d: poll_dpoll: failed to send cmd to clock: %m", CLK_UNIT(parse->peer));
479654359Sroberto	}
479754359Sroberto	else
479854359Sroberto	    if (rtc != ct)
479954359Sroberto	    {
480054359Sroberto		    ERR(ERR_BADIO)
4801282408Scy			    msyslog(LOG_ERR, "PARSE receiver #%d: poll_dpoll: failed to send cmd incomplete (%ld of %ld bytes sent)", CLK_UNIT(parse->peer), rtc, ct);
480254359Sroberto	    }
480354359Sroberto	clear_err(parse, ERR_BADIO);
480454359Sroberto}
480554359Sroberto
480654359Sroberto/*--------------------------------------------------
480754359Sroberto * periodic poll routine
480854359Sroberto */
480954359Srobertostatic void
481054359Srobertopoll_poll(
481154359Sroberto	struct peer *peer
481254359Sroberto	)
481354359Sroberto{
4814280849Scy	struct parseunit *parse = peer->procptr->unitptr;
4815282408Scy
481654359Sroberto	if (parse->parse_type->cl_poll)
481754359Sroberto		parse->parse_type->cl_poll(parse);
481854359Sroberto
481954359Sroberto	if (((poll_info_t *)parse->parse_type->cl_data)->rate)
482054359Sroberto	{
4821280849Scy		parse->peer->procptr->nextaction = current_time + ((poll_info_t *)parse->parse_type->cl_data)->rate;
482254359Sroberto	}
482354359Sroberto}
482454359Sroberto
482554359Sroberto/*--------------------------------------------------
482654359Sroberto * init routine - setup timer
482754359Sroberto */
482854359Srobertostatic int
482954359Srobertopoll_init(
483054359Sroberto	struct parseunit *parse
483154359Sroberto	)
483254359Sroberto{
483354359Sroberto	if (((poll_info_t *)parse->parse_type->cl_data)->rate)
483454359Sroberto	{
4835280849Scy		parse->peer->procptr->action = poll_poll;
483654359Sroberto		poll_poll(parse->peer);
483754359Sroberto	}
483854359Sroberto
483954359Sroberto	return 0;
484054359Sroberto}
4841282408Scy
484254359Sroberto/**===========================================================================
484354359Sroberto ** Trimble support
484454359Sroberto **/
484554359Sroberto
484654359Sroberto/*-------------------------------------------------------------
484754359Sroberto * trimble TAIP init routine - setup EOL and then do poll_init.
484854359Sroberto */
484954359Srobertostatic int
485054359Srobertotrimbletaip_init(
485154359Sroberto	struct parseunit *parse
485254359Sroberto	)
485354359Sroberto{
485454359Sroberto#ifdef HAVE_TERMIOS
485554359Sroberto	struct termios tio;
485654359Sroberto#endif
485754359Sroberto#ifdef HAVE_SYSV_TTYS
485854359Sroberto	struct termio tio;
485954359Sroberto#endif
486054359Sroberto	/*
486154359Sroberto	 * configure terminal line for trimble receiver
486254359Sroberto	 */
486354359Sroberto	if (TTY_GETATTR(parse->generic->io.fd, &tio) == -1)
486454359Sroberto	{
486554359Sroberto		msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_init: tcgetattr(fd, &tio): %m", CLK_UNIT(parse->peer));
486654359Sroberto		return 0;
486754359Sroberto	}
486854359Sroberto	else
486954359Sroberto	{
487054359Sroberto		tio.c_cc[VEOL] = TRIMBLETAIP_EOL;
4871282408Scy
487254359Sroberto		if (TTY_SETATTR(parse->generic->io.fd, &tio) == -1)
487354359Sroberto		{
487454359Sroberto			msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_init: tcsetattr(fd, &tio): %m", CLK_UNIT(parse->peer));
487554359Sroberto			return 0;
487654359Sroberto		}
487754359Sroberto	}
487854359Sroberto	return poll_init(parse);
487954359Sroberto}
488054359Sroberto
488154359Sroberto/*--------------------------------------------------
488254359Sroberto * trimble TAIP event routine - reset receiver upon data format trouble
488354359Sroberto */
488454359Srobertostatic const char *taipinit[] = {
488554359Sroberto	">FPV00000000<",
488654359Sroberto	">SRM;ID_FLAG=F;CS_FLAG=T;EC_FLAG=F;FR_FLAG=T;CR_FLAG=F<",
488754359Sroberto	">FTM00020001<",
488854359Sroberto	(char *)0
488954359Sroberto};
4890282408Scy
489154359Srobertostatic void
489254359Srobertotrimbletaip_event(
489354359Sroberto	struct parseunit *parse,
489454359Sroberto	int event
489554359Sroberto	)
489654359Sroberto{
489754359Sroberto	switch (event)
489854359Sroberto	{
489954359Sroberto	    case CEVNT_BADREPLY:	/* reset on garbled input */
490054359Sroberto	    case CEVNT_TIMEOUT:		/* reset on no input */
490154359Sroberto		    {
490254359Sroberto			    const char **iv;
490354359Sroberto
490454359Sroberto			    iv = taipinit;
490554359Sroberto			    while (*iv)
490654359Sroberto			    {
4907282408Scy				    int rtc = (int) write(parse->generic->io.fd, *iv, strlen(*iv));
490854359Sroberto				    if (rtc < 0)
490954359Sroberto				    {
491054359Sroberto					    msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_event: failed to send cmd to clock: %m", CLK_UNIT(parse->peer));
491154359Sroberto					    return;
491254359Sroberto				    }
491354359Sroberto				    else
491454359Sroberto				    {
4915280849Scy					    if (rtc != (int)strlen(*iv))
491654359Sroberto					    {
491754359Sroberto						    msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_event: failed to send cmd incomplete (%d of %d bytes sent)",
491854359Sroberto							    CLK_UNIT(parse->peer), rtc, (int)strlen(*iv));
491954359Sroberto						    return;
492054359Sroberto					    }
492154359Sroberto				    }
492254359Sroberto				    iv++;
492354359Sroberto			    }
492454359Sroberto
492554359Sroberto			    NLOG(NLOG_CLOCKINFO)
492654359Sroberto				    ERR(ERR_BADIO)
492754359Sroberto				    msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_event: RECEIVER INITIALIZED",
492854359Sroberto					    CLK_UNIT(parse->peer));
492954359Sroberto		    }
493054359Sroberto		    break;
493154359Sroberto
493254359Sroberto	    default:			/* ignore */
493354359Sroberto		break;
493454359Sroberto	}
493554359Sroberto}
493654359Sroberto
493754359Sroberto/*
493854359Sroberto * This driver supports the Trimble SVee Six Plus GPS receiver module.
493954359Sroberto * It should support other Trimble receivers which use the Trimble Standard
494054359Sroberto * Interface Protocol (see below).
494154359Sroberto *
494254359Sroberto * The module has a serial I/O port for command/data and a 1 pulse-per-second
494354359Sroberto * output, about 1 microsecond wide. The leading edge of the pulse is
494454359Sroberto * coincident with the change of the GPS second. This is the same as
494554359Sroberto * the change of the UTC second +/- ~1 microsecond. Some other clocks
494654359Sroberto * specifically use a feature in the data message as a timing reference, but
494754359Sroberto * the SVee Six Plus does not do this. In fact there is considerable jitter
494854359Sroberto * on the timing of the messages, so this driver only supports the use
494954359Sroberto * of the PPS pulse for accurate timing. Where it is determined that
495054359Sroberto * the offset is way off, when first starting up ntpd for example,
495154359Sroberto * the timing of the data stream is used until the offset becomes low enough
495256746Sroberto * (|offset| < CLOCK_MAX), at which point the pps offset is used.
495354359Sroberto *
495454359Sroberto * It can use either option for receiving PPS information - the 'ppsclock'
495554359Sroberto * stream pushed onto the serial data interface to timestamp the Carrier
495654359Sroberto * Detect interrupts, where the 1PPS connects to the CD line. This only
495754359Sroberto * works on SunOS 4.1.x currently. To select this, define PPSPPS in
495854359Sroberto * Config.local. The other option is to use a pulse-stretcher/level-converter
495954359Sroberto * to convert the PPS pulse into a RS232 start pulse & feed this into another
496054359Sroberto * tty port. To use this option, define PPSCLK in Config.local. The pps input,
496154359Sroberto * by whichever method, is handled in ntp_loopfilter.c
496254359Sroberto *
496354359Sroberto * The receiver uses a serial message protocol called Trimble Standard
496454359Sroberto * Interface Protocol (it can support others but this driver only supports
496554359Sroberto * TSIP). Messages in this protocol have the following form:
496654359Sroberto *
496754359Sroberto * <DLE><id> ... <data> ... <DLE><ETX>
496854359Sroberto *
496954359Sroberto * Any bytes within the <data> portion of value 10 hex (<DLE>) are doubled
497054359Sroberto * on transmission and compressed back to one on reception. Otherwise
497154359Sroberto * the values of data bytes can be anything. The serial interface is RS-422
497254359Sroberto * asynchronous using 9600 baud, 8 data bits with odd party (**note** 9 bits
497354359Sroberto * in total!), and 1 stop bit. The protocol supports byte, integer, single,
497454359Sroberto * and double datatypes. Integers are two bytes, sent most significant first.
497554359Sroberto * Singles are IEEE754 single precision floating point numbers (4 byte) sent
497654359Sroberto * sign & exponent first. Doubles are IEEE754 double precision floating point
497754359Sroberto * numbers (8 byte) sent sign & exponent first.
497854359Sroberto * The receiver supports a large set of messages, only a small subset of
497954359Sroberto * which are used here. From driver to receiver the following are used:
498054359Sroberto *
498154359Sroberto *  ID    Description
498254359Sroberto *
498354359Sroberto *  21    Request current time
498454359Sroberto *  22    Mode Select
498554359Sroberto *  2C    Set/Request operating parameters
498654359Sroberto *  2F    Request UTC info
498754359Sroberto *  35    Set/Request I/O options
498854359Sroberto
498954359Sroberto * From receiver to driver the following are recognised:
499054359Sroberto *
499154359Sroberto *  ID    Description
499254359Sroberto *
499354359Sroberto *  41    GPS Time
499454359Sroberto *  44    Satellite selection, PDOP, mode
499554359Sroberto *  46    Receiver health
499654359Sroberto *  4B    Machine code/status
499754359Sroberto *  4C    Report operating parameters (debug only)
499854359Sroberto *  4F    UTC correction data (used to get leap second warnings)
499954359Sroberto *  55    I/O options (debug only)
500054359Sroberto *
500154359Sroberto * All others are accepted but ignored.
500254359Sroberto *
500354359Sroberto */
500454359Sroberto
500554359Sroberto#define PI		3.1415926535898	/* lots of sig figs */
500654359Sroberto#define D2R		PI/180.0
500754359Sroberto
500854359Sroberto/*-------------------------------------------------------------------
500954359Sroberto * sendcmd, sendbyte, sendetx, sendflt, sendint implement the command
501054359Sroberto * interface to the receiver.
501154359Sroberto *
501254359Sroberto * CAVEAT: the sendflt, sendint routines are byte order dependend and
501354359Sroberto * float implementation dependend - these must be converted to portable
501454359Sroberto * versions !
501554359Sroberto *
501654359Sroberto * CURRENT LIMITATION: float implementation. This runs only on systems
501754359Sroberto * with IEEE754 floats as native floats
501854359Sroberto */
501954359Sroberto
502054359Srobertotypedef struct trimble
502154359Sroberto{
502254359Sroberto	u_long last_msg;	/* last message received */
5023182007Sroberto	u_long last_reset;	/* last time a reset was issued */
502454359Sroberto	u_char qtracking;	/* query tracking status */
502554359Sroberto	u_long ctrack;		/* current tracking set */
502654359Sroberto	u_long ltrack;		/* last tracking set */
502754359Sroberto} trimble_t;
502854359Sroberto
502954359Srobertounion uval {
503054359Sroberto	u_char  bd[8];
503154359Sroberto	int     iv;
503254359Sroberto	float   fv;
503354359Sroberto	double  dv;
503454359Sroberto};
5035282408Scy
503654359Srobertostruct txbuf
503754359Sroberto{
503854359Sroberto	short idx;			/* index to first unused byte */
503954359Sroberto	u_char *txt;			/* pointer to actual data buffer */
504054359Sroberto};
504154359Sroberto
5042282408Scyvoid	sendcmd		(struct txbuf *buf, int c);
5043282408Scyvoid	sendbyte	(struct txbuf *buf, int b);
5044282408Scyvoid	sendetx		(struct txbuf *buf, struct parseunit *parse);
5045282408Scyvoid	sendint		(struct txbuf *buf, int a);
5046282408Scyvoid	sendflt		(struct txbuf *buf, double a);
5047282408Scy
504854359Srobertovoid
504954359Srobertosendcmd(
505054359Sroberto	struct txbuf *buf,
505154359Sroberto	int c
505254359Sroberto	)
505354359Sroberto{
505454359Sroberto	buf->txt[0] = DLE;
505554359Sroberto	buf->txt[1] = (u_char)c;
505654359Sroberto	buf->idx = 2;
505754359Sroberto}
505854359Sroberto
5059282408Scyvoid	sendcmd		(struct txbuf *buf, int c);
5060282408Scyvoid	sendbyte	(struct txbuf *buf, int b);
5061282408Scyvoid	sendetx		(struct txbuf *buf, struct parseunit *parse);
5062282408Scyvoid	sendint		(struct txbuf *buf, int a);
5063282408Scyvoid	sendflt		(struct txbuf *buf, double a);
5064282408Scy
506554359Srobertovoid
506654359Srobertosendbyte(
506754359Sroberto	struct txbuf *buf,
506854359Sroberto	int b
506954359Sroberto	)
507054359Sroberto{
507154359Sroberto	if (b == DLE)
507254359Sroberto	    buf->txt[buf->idx++] = DLE;
507354359Sroberto	buf->txt[buf->idx++] = (u_char)b;
507454359Sroberto}
507554359Sroberto
507654359Srobertovoid
507754359Srobertosendetx(
507854359Sroberto	struct txbuf *buf,
507954359Sroberto	struct parseunit *parse
508054359Sroberto	)
508154359Sroberto{
508254359Sroberto	buf->txt[buf->idx++] = DLE;
508354359Sroberto	buf->txt[buf->idx++] = ETX;
508454359Sroberto
508554359Sroberto	if (write(parse->generic->io.fd, buf->txt, (unsigned long)buf->idx) != buf->idx)
508654359Sroberto	{
508754359Sroberto		ERR(ERR_BADIO)
508854359Sroberto			msyslog(LOG_ERR, "PARSE receiver #%d: sendetx: failed to send cmd to clock: %m", CLK_UNIT(parse->peer));
508954359Sroberto	}
509054359Sroberto	else
509154359Sroberto	{
509254359Sroberto#ifdef DEBUG
509354359Sroberto	  if (debug > 2)
509454359Sroberto	  {
509554359Sroberto		  char buffer[256];
5096282408Scy
509754359Sroberto		  mkreadable(buffer, sizeof(buffer), (char *)buf->txt, (unsigned)buf->idx, 1);
509854359Sroberto		  printf("PARSE receiver #%d: transmitted message (%d bytes) >%s<\n",
509954359Sroberto			 CLK_UNIT(parse->peer),
5100282408Scy			 buf->idx, buffer);
510154359Sroberto	  }
510254359Sroberto#endif
510354359Sroberto		clear_err(parse, ERR_BADIO);
510454359Sroberto	}
510554359Sroberto}
510654359Sroberto
5107282408Scyvoid
510854359Srobertosendint(
510954359Sroberto	struct txbuf *buf,
511054359Sroberto	int a
511154359Sroberto	)
511254359Sroberto{
511354359Sroberto	/* send 16bit int, msbyte first */
511454359Sroberto	sendbyte(buf, (u_char)((a>>8) & 0xff));
511554359Sroberto	sendbyte(buf, (u_char)(a & 0xff));
511654359Sroberto}
511754359Sroberto
511854359Srobertovoid
511954359Srobertosendflt(
512054359Sroberto	struct txbuf *buf,
512154359Sroberto	double a
512254359Sroberto	)
512354359Sroberto{
512454359Sroberto	int i;
512554359Sroberto	union uval uval;
512654359Sroberto
5127282408Scy	uval.fv = (float) a;
512854359Sroberto#ifdef WORDS_BIGENDIAN
512954359Sroberto	for (i=0; i<=3; i++)
513054359Sroberto#else
513154359Sroberto	    for (i=3; i>=0; i--)
513254359Sroberto#endif
513354359Sroberto		sendbyte(buf, uval.bd[i]);
513454359Sroberto}
513554359Sroberto
513654359Sroberto#define TRIM_POS_OPT	0x13	/* output position with high precision */
513754359Sroberto#define TRIM_TIME_OPT	0x03	/* use UTC time stamps, on second */
513854359Sroberto
513954359Sroberto/*--------------------------------------------------
514054359Sroberto * trimble TSIP setup routine
514154359Sroberto */
514254359Srobertostatic int
514354359Srobertotrimbletsip_setup(
514454359Sroberto		  struct parseunit *parse,
514554359Sroberto		  const char *reason
514656746Sroberto		  )
514754359Sroberto{
514854359Sroberto	u_char buffer[256];
514954359Sroberto	struct txbuf buf;
5150182007Sroberto	trimble_t *t = parse->localdata;
515154359Sroberto
5152182007Sroberto	if (t && t->last_reset &&
5153182007Sroberto	    ((t->last_reset + TRIMBLE_RESET_HOLDOFF) > current_time)) {
5154182007Sroberto		return 1;	/* not yet */
5155182007Sroberto	}
5156182007Sroberto
5157182007Sroberto	if (t)
5158182007Sroberto		t->last_reset = current_time;
5159282408Scy
516054359Sroberto	buf.txt = buffer;
5161282408Scy
516254359Sroberto	sendcmd(&buf, CMD_CVERSION);	/* request software versions */
516356746Sroberto	sendetx(&buf, parse);
5164282408Scy
516554359Sroberto	sendcmd(&buf, CMD_COPERPARAM);	/* set operating parameters */
516656746Sroberto	sendbyte(&buf, 4);	/* static */
516756746Sroberto	sendflt(&buf, 5.0*D2R);	/* elevation angle mask = 10 deg XXX */
516856746Sroberto	sendflt(&buf, 4.0);	/* s/n ratio mask = 6 XXX */
516956746Sroberto	sendflt(&buf, 12.0);	/* PDOP mask = 12 */
517056746Sroberto	sendflt(&buf, 8.0);	/* PDOP switch level = 8 */
517156746Sroberto	sendetx(&buf, parse);
5172282408Scy
517354359Sroberto	sendcmd(&buf, CMD_CMODESEL);	/* fix mode select */
5174182007Sroberto	sendbyte(&buf, 1);	/* time transfer mode */
517556746Sroberto	sendetx(&buf, parse);
5176282408Scy
517754359Sroberto	sendcmd(&buf, CMD_CMESSAGE);	/* request system message */
517856746Sroberto	sendetx(&buf, parse);
5179282408Scy
518054359Sroberto	sendcmd(&buf, CMD_CSUPER);	/* superpacket fix */
518156746Sroberto	sendbyte(&buf, 0x2);	/* binary mode */
518256746Sroberto	sendetx(&buf, parse);
5183282408Scy
518454359Sroberto	sendcmd(&buf, CMD_CIOOPTIONS);	/* set I/O options */
518554359Sroberto	sendbyte(&buf, TRIM_POS_OPT);	/* position output */
518654359Sroberto	sendbyte(&buf, 0x00);	/* no velocity output */
518754359Sroberto	sendbyte(&buf, TRIM_TIME_OPT);	/* UTC, compute on seconds */
518854359Sroberto	sendbyte(&buf, 0x00);	/* no raw measurements */
518956746Sroberto	sendetx(&buf, parse);
5190282408Scy
519154359Sroberto	sendcmd(&buf, CMD_CUTCPARAM);	/* request UTC correction data */
519254359Sroberto	sendetx(&buf, parse);
519354359Sroberto
519454359Sroberto	NLOG(NLOG_CLOCKINFO)
519554359Sroberto		ERR(ERR_BADIO)
519654359Sroberto		msyslog(LOG_ERR, "PARSE receiver #%d: trimbletsip_setup: RECEIVER RE-INITIALIZED (%s)", CLK_UNIT(parse->peer), reason);
519754359Sroberto
519854359Sroberto	return 0;
519954359Sroberto}
520054359Sroberto
520154359Sroberto/*--------------------------------------------------
520254359Sroberto * TRIMBLE TSIP check routine
520354359Sroberto */
520454359Srobertostatic void
520554359Srobertotrimble_check(
520654359Sroberto	      struct peer *peer
520754359Sroberto	      )
520854359Sroberto{
5209280849Scy	struct parseunit *parse = peer->procptr->unitptr;
521054359Sroberto	trimble_t *t = parse->localdata;
521154359Sroberto	u_char buffer[256];
521254359Sroberto	struct txbuf buf;
521354359Sroberto	buf.txt = buffer;
5214282408Scy
521554359Sroberto	if (t)
521654359Sroberto	{
521754359Sroberto		if (current_time > t->last_msg + TRIMBLETSIP_IDLE_TIME)
521854359Sroberto			(void)trimbletsip_setup(parse, "message timeout");
521954359Sroberto	}
5220182007Sroberto
522154359Sroberto	poll_poll(parse->peer);	/* emit query string and re-arm timer */
5222282408Scy
5223182007Sroberto	if (t && t->qtracking)
522454359Sroberto	{
522554359Sroberto		u_long oldsats = t->ltrack & ~t->ctrack;
5226282408Scy
522754359Sroberto		t->qtracking = 0;
522854359Sroberto		t->ltrack = t->ctrack;
5229282408Scy
523054359Sroberto		if (oldsats)
523154359Sroberto		{
523254359Sroberto			int i;
5233282408Scy
5234182007Sroberto			for (i = 0; oldsats; i++) {
523554359Sroberto				if (oldsats & (1 << i))
523654359Sroberto					{
523754359Sroberto						sendcmd(&buf, CMD_CSTATTRACK);
523854359Sroberto						sendbyte(&buf, i+1);	/* old sat */
523954359Sroberto						sendetx(&buf, parse);
524054359Sroberto					}
5241182007Sroberto				oldsats &= ~(1 << i);
5242182007Sroberto			}
524354359Sroberto		}
5244282408Scy
524554359Sroberto		sendcmd(&buf, CMD_CSTATTRACK);
524654359Sroberto		sendbyte(&buf, 0x00);	/* current tracking set */
524754359Sroberto		sendetx(&buf, parse);
524854359Sroberto	}
524954359Sroberto}
525054359Sroberto
525154359Sroberto/*--------------------------------------------------
525254359Sroberto * TRIMBLE TSIP end routine
525354359Sroberto */
525454359Srobertostatic void
525554359Srobertotrimbletsip_end(
525654359Sroberto	      struct parseunit *parse
525754359Sroberto	      )
525854359Sroberto{	trimble_t *t = parse->localdata;
5259282408Scy
526054359Sroberto	if (t)
526154359Sroberto	{
526254359Sroberto		free(t);
5263280849Scy		parse->localdata = NULL;
526454359Sroberto	}
5265280849Scy	parse->peer->procptr->nextaction = 0;
5266280849Scy	parse->peer->procptr->action = NULL;
526754359Sroberto}
526854359Sroberto
526954359Sroberto/*--------------------------------------------------
527054359Sroberto * TRIMBLE TSIP init routine
527154359Sroberto */
527254359Srobertostatic int
527354359Srobertotrimbletsip_init(
527454359Sroberto	struct parseunit *parse
527554359Sroberto	)
527654359Sroberto{
527754359Sroberto#if defined(VEOL) || defined(VEOL2)
527854359Sroberto#ifdef HAVE_TERMIOS
527954359Sroberto	struct termios tio;		/* NEEDED FOR A LONG TIME ! */
528054359Sroberto#endif
528154359Sroberto#ifdef HAVE_SYSV_TTYS
528254359Sroberto	struct termio tio;		/* NEEDED FOR A LONG TIME ! */
528354359Sroberto#endif
528454359Sroberto	/*
528554359Sroberto	 * allocate local data area
528654359Sroberto	 */
528754359Sroberto	if (!parse->localdata)
528854359Sroberto	{
528954359Sroberto		trimble_t *t;
5290282408Scy
529154359Sroberto		t = (trimble_t *)(parse->localdata = emalloc(sizeof(trimble_t)));
5292282408Scy
529354359Sroberto		if (t)
529454359Sroberto		{
529554359Sroberto			memset((char *)t, 0, sizeof(trimble_t));
529654359Sroberto			t->last_msg = current_time;
529754359Sroberto		}
529854359Sroberto	}
529954359Sroberto
5300280849Scy	parse->peer->procptr->action     = trimble_check;
5301280849Scy	parse->peer->procptr->nextaction = current_time;
530254359Sroberto
530354359Sroberto	/*
530454359Sroberto	 * configure terminal line for ICANON mode with VEOL characters
530554359Sroberto	 */
530654359Sroberto	if (TTY_GETATTR(parse->generic->io.fd, &tio) == -1)
530754359Sroberto	{
530854359Sroberto		msyslog(LOG_ERR, "PARSE receiver #%d: trimbletsip_init: tcgetattr(%d, &tio): %m", CLK_UNIT(parse->peer), parse->generic->io.fd);
530954359Sroberto		return 0;
531054359Sroberto	}
531154359Sroberto	else
531254359Sroberto	{
531354359Sroberto		if ((parse_clockinfo[CLK_TYPE(parse->peer)].cl_lflag & ICANON))
531454359Sroberto		{
531554359Sroberto#ifdef VEOL
531654359Sroberto			tio.c_cc[VEOL]  = ETX;
531754359Sroberto#endif
531854359Sroberto#ifdef VEOL2
531954359Sroberto			tio.c_cc[VEOL2]  = DLE;
532054359Sroberto#endif
532156746Sroberto		}
532254359Sroberto
532354359Sroberto		if (TTY_SETATTR(parse->generic->io.fd, &tio) == -1)
532454359Sroberto		{
532554359Sroberto			msyslog(LOG_ERR, "PARSE receiver #%d: trimbletsip_init: tcsetattr(%d, &tio): %m", CLK_UNIT(parse->peer), parse->generic->io.fd);
532654359Sroberto			return 0;
532754359Sroberto		}
532854359Sroberto	}
532954359Sroberto#endif
533054359Sroberto	return trimbletsip_setup(parse, "initial startup");
533154359Sroberto}
533254359Sroberto
533354359Sroberto/*------------------------------------------------------------
533454359Sroberto * trimbletsip_event - handle Trimble events
533554359Sroberto * simple evente handler - attempt to re-initialize receiver
533654359Sroberto */
533754359Srobertostatic void
533854359Srobertotrimbletsip_event(
533954359Sroberto	struct parseunit *parse,
534054359Sroberto	int event
534154359Sroberto	)
534254359Sroberto{
534354359Sroberto	switch (event)
534454359Sroberto	{
534554359Sroberto	    case CEVNT_BADREPLY:	/* reset on garbled input */
534654359Sroberto	    case CEVNT_TIMEOUT:		/* reset on no input */
534754359Sroberto		    (void)trimbletsip_setup(parse, "event BAD_REPLY/TIMEOUT");
534854359Sroberto		    break;
534954359Sroberto
535054359Sroberto	    default:			/* ignore */
535154359Sroberto		break;
535254359Sroberto	}
535354359Sroberto}
535454359Sroberto
535554359Sroberto/*
535654359Sroberto * getflt, getint convert fields in the incoming data into the
535754359Sroberto * appropriate type of item
535854359Sroberto *
535954359Sroberto * CAVEAT: these routines are currently definitely byte order dependent
536054359Sroberto * and assume Representation(float) == IEEE754
536154359Sroberto * These functions MUST be converted to portable versions (especially
536254359Sroberto * converting the float representation into ntp_fp formats in order
536354359Sroberto * to avoid floating point operations at all!
536454359Sroberto */
536554359Sroberto
536654359Srobertostatic float
536754359Srobertogetflt(
536854359Sroberto	u_char *bp
536954359Sroberto	)
537054359Sroberto{
537154359Sroberto	union uval uval;
5372282408Scy
537354359Sroberto#ifdef WORDS_BIGENDIAN
537454359Sroberto	uval.bd[0] = *bp++;
537554359Sroberto	uval.bd[1] = *bp++;
537654359Sroberto	uval.bd[2] = *bp++;
537754359Sroberto	uval.bd[3] = *bp;
537854359Sroberto#else  /* ! WORDS_BIGENDIAN */
537954359Sroberto	uval.bd[3] = *bp++;
538054359Sroberto	uval.bd[2] = *bp++;
538154359Sroberto	uval.bd[1] = *bp++;
538254359Sroberto	uval.bd[0] = *bp;
538354359Sroberto#endif /* ! WORDS_BIGENDIAN */
538454359Sroberto	return uval.fv;
538554359Sroberto}
538654359Sroberto
538754359Srobertostatic double
538854359Srobertogetdbl(
538954359Sroberto	u_char *bp
539054359Sroberto	)
539154359Sroberto{
539254359Sroberto	union uval uval;
5393282408Scy
539454359Sroberto#ifdef WORDS_BIGENDIAN
539554359Sroberto	uval.bd[0] = *bp++;
539654359Sroberto	uval.bd[1] = *bp++;
539754359Sroberto	uval.bd[2] = *bp++;
539854359Sroberto	uval.bd[3] = *bp++;
539954359Sroberto	uval.bd[4] = *bp++;
540054359Sroberto	uval.bd[5] = *bp++;
540154359Sroberto	uval.bd[6] = *bp++;
540254359Sroberto	uval.bd[7] = *bp;
540354359Sroberto#else  /* ! WORDS_BIGENDIAN */
540454359Sroberto	uval.bd[7] = *bp++;
540554359Sroberto	uval.bd[6] = *bp++;
540654359Sroberto	uval.bd[5] = *bp++;
540754359Sroberto	uval.bd[4] = *bp++;
540854359Sroberto	uval.bd[3] = *bp++;
540954359Sroberto	uval.bd[2] = *bp++;
541054359Sroberto	uval.bd[1] = *bp++;
541154359Sroberto	uval.bd[0] = *bp;
541254359Sroberto#endif /* ! WORDS_BIGENDIAN */
541354359Sroberto	return uval.dv;
541454359Sroberto}
541554359Sroberto
541654359Srobertostatic int
541754359Srobertogetshort(
541854359Sroberto	 unsigned char *p
541954359Sroberto	 )
542054359Sroberto{
5421282408Scy	return (int) get_msb_short(&p);
542254359Sroberto}
542354359Sroberto
542454359Sroberto/*--------------------------------------------------
542554359Sroberto * trimbletsip_message - process trimble messages
542654359Sroberto */
542754359Sroberto#define RTOD (180.0 / 3.1415926535898)
542854359Sroberto#define mb(_X_) (buffer[2+(_X_)]) /* shortcut for buffer access */
542954359Sroberto
543054359Srobertostatic void
543154359Srobertotrimbletsip_message(
543254359Sroberto		    struct parseunit *parse,
543354359Sroberto		    parsetime_t      *parsetime
543454359Sroberto		    )
543554359Sroberto{
543654359Sroberto	unsigned char *buffer = parsetime->parse_msg;
543754359Sroberto	unsigned int   size   = parsetime->parse_msglen;
5438282408Scy
543954359Sroberto	if ((size < 4) ||
544054359Sroberto	    (buffer[0]      != DLE) ||
544154359Sroberto	    (buffer[size-1] != ETX) ||
544254359Sroberto	    (buffer[size-2] != DLE))
544354359Sroberto	{
544454359Sroberto#ifdef DEBUG
544554359Sroberto		if (debug > 2) {
5446280849Scy			size_t i;
544754359Sroberto
544854359Sroberto			printf("TRIMBLE BAD packet, size %d:\n	", size);
544954359Sroberto			for (i = 0; i < size; i++) {
545054359Sroberto				printf ("%2.2x, ", buffer[i]&0xff);
545154359Sroberto				if (i%16 == 15) printf("\n\t");
545254359Sroberto			}
545354359Sroberto			printf("\n");
545454359Sroberto		}
545554359Sroberto#endif
545654359Sroberto		return;
545754359Sroberto	}
545854359Sroberto	else
545954359Sroberto	{
5460282408Scy		u_short var_flag;
546154359Sroberto		trimble_t *tr = parse->localdata;
546254359Sroberto		unsigned int cmd = buffer[1];
546354359Sroberto		char pbuffer[200];
546454359Sroberto		char *t = pbuffer;
546554359Sroberto		cmd_info_t *s;
5466282408Scy
546754359Sroberto#ifdef DEBUG
546854359Sroberto		if (debug > 3) {
5469280849Scy			size_t i;
547054359Sroberto
547154359Sroberto			printf("TRIMBLE packet 0x%02x, size %d:\n	", cmd, size);
547254359Sroberto			for (i = 0; i < size; i++) {
547354359Sroberto				printf ("%2.2x, ", buffer[i]&0xff);
547454359Sroberto				if (i%16 == 15) printf("\n\t");
547554359Sroberto			}
547654359Sroberto			printf("\n");
547754359Sroberto		}
547854359Sroberto#endif
547954359Sroberto
548054359Sroberto		if (tr)
548154359Sroberto			tr->last_msg = current_time;
5482282408Scy
548354359Sroberto		s = trimble_convert(cmd, trimble_rcmds);
5484282408Scy
548554359Sroberto		if (s)
548654359Sroberto		{
5487280849Scy			t = ap(pbuffer, sizeof(pbuffer), t, "%s=\"", s->varname);
548854359Sroberto		}
548954359Sroberto		else
549054359Sroberto		{
5491182007Sroberto			DPRINTF(1, ("TRIMBLE UNKNOWN COMMAND 0x%02x\n", cmd));
549254359Sroberto			return;
549354359Sroberto		}
549454359Sroberto
5495282408Scy		var_flag = (u_short) s->varmode;
549654359Sroberto
549754359Sroberto		switch(cmd)
549854359Sroberto		{
549954359Sroberto		case CMD_RCURTIME:
5500280849Scy			t = ap(pbuffer, sizeof(pbuffer), t, "%f, %d, %f",
5501182007Sroberto				 getflt((unsigned char *)&mb(0)), getshort((unsigned char *)&mb(4)),
5502182007Sroberto				 getflt((unsigned char *)&mb(6)));
550354359Sroberto			break;
5504282408Scy
550554359Sroberto		case CMD_RBEST4:
5506280849Scy			t = ap(pbuffer, sizeof(pbuffer), t, "mode: ");
550754359Sroberto			switch (mb(0) & 0xF)
550854359Sroberto			{
550954359Sroberto			default:
5510280849Scy				t = ap(pbuffer, sizeof(pbuffer), t,
5511280849Scy				    "0x%x", mb(0) & 0x7);
551254359Sroberto				break;
551354359Sroberto
551454359Sroberto			case 1:
5515280849Scy				t = ap(pbuffer, sizeof(pbuffer), t, "0D");
551654359Sroberto				break;
5517282408Scy
551854359Sroberto			case 3:
5519280849Scy				t = ap(pbuffer, sizeof(pbuffer), t, "2D");
552054359Sroberto				break;
5521282408Scy
552254359Sroberto			case 4:
5523280849Scy				t = ap(pbuffer, sizeof(pbuffer), t, "3D");
552454359Sroberto				break;
552554359Sroberto			}
552654359Sroberto			if (mb(0) & 0x10)
5527280849Scy				t = ap(pbuffer, sizeof(pbuffer), t, "-MANUAL, ");
552854359Sroberto			else
5529280849Scy				t = ap(pbuffer, sizeof(pbuffer), t, "-AUTO, ");
5530282408Scy
5531280849Scy			t = ap(pbuffer, sizeof(pbuffer), t, "satellites %02d %02d %02d %02d, PDOP %.2f, HDOP %.2f, VDOP %.2f, TDOP %.2f",
553254359Sroberto				mb(1), mb(2), mb(3), mb(4),
553354359Sroberto				getflt((unsigned char *)&mb(5)),
553454359Sroberto				getflt((unsigned char *)&mb(9)),
553554359Sroberto				getflt((unsigned char *)&mb(13)),
553654359Sroberto				getflt((unsigned char *)&mb(17)));
553754359Sroberto
553854359Sroberto			break;
5539282408Scy
554054359Sroberto		case CMD_RVERSION:
5541280849Scy			t = ap(pbuffer, sizeof(pbuffer), t, "%d.%d (%d/%d/%d)",
554254359Sroberto				mb(0)&0xff, mb(1)&0xff, 1900+(mb(4)&0xff), mb(2)&0xff, mb(3)&0xff);
554354359Sroberto			break;
5544282408Scy
554554359Sroberto		case CMD_RRECVHEALTH:
554654359Sroberto		{
554754359Sroberto			static const char *msgs[] =
554854359Sroberto			{
554954359Sroberto				"Battery backup failed",
555054359Sroberto				"Signal processor error",
555154359Sroberto				"Alignment error, channel or chip 1",
555254359Sroberto				"Alignment error, channel or chip 2",
555354359Sroberto				"Antenna feed line fault",
555454359Sroberto				"Excessive ref freq. error",
555554359Sroberto				"<BIT 6>",
555654359Sroberto				"<BIT 7>"
555754359Sroberto			};
5558282408Scy
555954359Sroberto			int i, bits;
5560282408Scy
556154359Sroberto			switch (mb(0) & 0xFF)
556254359Sroberto			{
556354359Sroberto			default:
5564280849Scy				t = ap(pbuffer, sizeof(pbuffer), t, "illegal value 0x%02x", mb(0) & 0xFF);
556554359Sroberto				break;
556654359Sroberto			case 0x00:
5567280849Scy				t = ap(pbuffer, sizeof(pbuffer), t, "doing position fixes");
556854359Sroberto				break;
556954359Sroberto			case 0x01:
5570280849Scy				t = ap(pbuffer, sizeof(pbuffer), t, "no GPS time yet");
557154359Sroberto				break;
557254359Sroberto			case 0x03:
5573280849Scy				t = ap(pbuffer, sizeof(pbuffer), t, "PDOP too high");
557454359Sroberto				break;
557554359Sroberto			case 0x08:
5576280849Scy				t = ap(pbuffer, sizeof(pbuffer), t, "no usable satellites");
557754359Sroberto				break;
557854359Sroberto			case 0x09:
5579280849Scy				t = ap(pbuffer, sizeof(pbuffer), t, "only ONE usable satellite");
558054359Sroberto				break;
558154359Sroberto			case 0x0A:
5582280849Scy				t = ap(pbuffer, sizeof(pbuffer), t, "only TWO usable satellites");
558354359Sroberto				break;
558454359Sroberto			case 0x0B:
5585280849Scy				t = ap(pbuffer, sizeof(pbuffer), t, "only THREE usable satellites");
558654359Sroberto				break;
558754359Sroberto			case 0x0C:
5588280849Scy				t = ap(pbuffer, sizeof(pbuffer), t, "the chosen satellite is unusable");
558954359Sroberto				break;
559054359Sroberto			}
559154359Sroberto
559254359Sroberto			bits = mb(1) & 0xFF;
5593282408Scy
559454359Sroberto			for (i = 0; i < 8; i++)
559554359Sroberto				if (bits & (0x1<<i))
559654359Sroberto				{
5597280849Scy					t = ap(pbuffer, sizeof(pbuffer), t, ", %s", msgs[i]);
559854359Sroberto				}
559954359Sroberto		}
560054359Sroberto		break;
5601282408Scy
560254359Sroberto		case CMD_RMESSAGE:
5603182007Sroberto			mkreadable(t, (int)BUFFER_SIZE(pbuffer, t), (char *)&mb(0), (unsigned)(size - 2 - (&mb(0) - buffer)), 0);
560454359Sroberto			break;
5605282408Scy
560654359Sroberto		case CMD_RMACHSTAT:
560754359Sroberto		{
560854359Sroberto			static const char *msgs[] =
560954359Sroberto			{
561054359Sroberto				"Synthesizer Fault",
561154359Sroberto				"Battery Powered Time Clock Fault",
561254359Sroberto				"A-to-D Converter Fault",
561354359Sroberto				"The almanac stored in the receiver is not complete and current",
561454359Sroberto				"<BIT 4>",
561554359Sroberto				"<BIT 5",
561654359Sroberto				"<BIT 6>",
561754359Sroberto				"<BIT 7>"
561854359Sroberto			};
5619282408Scy
562054359Sroberto			int i, bits;
562154359Sroberto
5622280849Scy			t = ap(pbuffer, sizeof(pbuffer), t, "machine id 0x%02x", mb(0) & 0xFF);
562354359Sroberto			bits = mb(1) & 0xFF;
5624282408Scy
562554359Sroberto			for (i = 0; i < 8; i++)
562654359Sroberto				if (bits & (0x1<<i))
562754359Sroberto				{
5628280849Scy					t = ap(pbuffer, sizeof(pbuffer), t, ", %s", msgs[i]);
562954359Sroberto				}
563054359Sroberto
5631280849Scy			t = ap(pbuffer, sizeof(pbuffer), t, ", Superpackets %ssupported", (mb(2) & 0xFF) ? "" :"un" );
563254359Sroberto		}
563354359Sroberto		break;
5634282408Scy
563554359Sroberto		case CMD_ROPERPARAM:
5636280849Scy			t = ap(pbuffer, sizeof(pbuffer), t, "%2x %.1f %.1f %.1f %.1f",
563754359Sroberto				mb(0), getflt((unsigned char *)&mb(1)), getflt((unsigned char *)&mb(5)),
563854359Sroberto				getflt((unsigned char *)&mb(9)), getflt((unsigned char *)&mb(13)));
563954359Sroberto			break;
5640282408Scy
564154359Sroberto		case CMD_RUTCPARAM:
564254359Sroberto		{
564354359Sroberto			float t0t = getflt((unsigned char *)&mb(14));
5644282408Scy			short wnt = (short) getshort((unsigned char *)&mb(18));
5645282408Scy			short dtls = (short) getshort((unsigned char *)&mb(12));
5646282408Scy			short wnlsf = (short) getshort((unsigned char *)&mb(20));
5647282408Scy			short dn = (short) getshort((unsigned char *)&mb(22));
5648282408Scy			short dtlsf = (short) getshort((unsigned char *)&mb(24));
564954359Sroberto
565054359Sroberto			if ((int)t0t != 0)
5651280849Scy			{
5652280849Scy				mk_utcinfo(t, wnt, wnlsf, dn, dtls, dtlsf, BUFFER_SIZE(pbuffer, t));
5653280849Scy			}
565454359Sroberto			else
5655280849Scy			{
5656280849Scy			        t = ap(pbuffer, sizeof(pbuffer), t, "<NO UTC DATA>");
5657280849Scy			}
565854359Sroberto		}
565954359Sroberto		break;
566054359Sroberto
566154359Sroberto		case CMD_RSAT1BIAS:
5662280849Scy			t = ap(pbuffer, sizeof(pbuffer), t, "%.1fm %.2fm/s at %.1fs",
566354359Sroberto				getflt(&mb(0)), getflt(&mb(4)), getflt(&mb(8)));
566454359Sroberto			break;
566554359Sroberto
566654359Sroberto		case CMD_RIOOPTIONS:
566754359Sroberto		{
5668280849Scy			t = ap(pbuffer, sizeof(pbuffer), t, "%02x %02x %02x %02x",
566954359Sroberto				mb(0), mb(1), mb(2), mb(3));
567054359Sroberto			if (mb(0) != TRIM_POS_OPT ||
567154359Sroberto			    mb(2) != TRIM_TIME_OPT)
567254359Sroberto			{
567354359Sroberto				(void)trimbletsip_setup(parse, "bad io options");
567454359Sroberto			}
567554359Sroberto		}
567654359Sroberto		break;
5677282408Scy
567854359Sroberto		case CMD_RSPOSXYZ:
567954359Sroberto		{
568054359Sroberto			double x = getflt((unsigned char *)&mb(0));
568154359Sroberto			double y = getflt((unsigned char *)&mb(4));
568254359Sroberto			double z = getflt((unsigned char *)&mb(8));
568354359Sroberto			double f = getflt((unsigned char *)&mb(12));
5684282408Scy
568554359Sroberto			if (f > 0.0)
5686280849Scy			  t = ap(pbuffer, sizeof(pbuffer), t, "x= %.1fm, y= %.1fm, z= %.1fm, time_of_fix= %f sec",
568754359Sroberto				  x, y, z,
568854359Sroberto				  f);
568954359Sroberto			else
5690280849Scy				return;
569154359Sroberto		}
569254359Sroberto		break;
569354359Sroberto
569454359Sroberto		case CMD_RSLLAPOS:
569554359Sroberto		{
569654359Sroberto			double lat = getflt((unsigned char *)&mb(0));
569754359Sroberto			double lng = getflt((unsigned char *)&mb(4));
569854359Sroberto			double f   = getflt((unsigned char *)&mb(12));
5699282408Scy
570054359Sroberto			if (f > 0.0)
5701280849Scy			  t = ap(pbuffer, sizeof(pbuffer), t, "lat %f %c, long %f %c, alt %.2fm",
570254359Sroberto				  ((lat < 0.0) ? (-lat) : (lat))*RTOD, (lat < 0.0 ? 'S' : 'N'),
570354359Sroberto				  ((lng < 0.0) ? (-lng) : (lng))*RTOD, (lng < 0.0 ? 'W' : 'E'),
570454359Sroberto				  getflt((unsigned char *)&mb(8)));
570554359Sroberto			else
5706280849Scy				return;
570754359Sroberto		}
570854359Sroberto		break;
570954359Sroberto
571054359Sroberto		case CMD_RDOUBLEXYZ:
571154359Sroberto		{
571254359Sroberto			double x = getdbl((unsigned char *)&mb(0));
571354359Sroberto			double y = getdbl((unsigned char *)&mb(8));
571454359Sroberto			double z = getdbl((unsigned char *)&mb(16));
5715280849Scy			t = ap(pbuffer, sizeof(pbuffer), t, "x= %.1fm, y= %.1fm, z= %.1fm",
571654359Sroberto				x, y, z);
571754359Sroberto		}
571854359Sroberto		break;
5719282408Scy
572054359Sroberto		case CMD_RDOUBLELLA:
572154359Sroberto		{
572254359Sroberto			double lat = getdbl((unsigned char *)&mb(0));
572354359Sroberto			double lng = getdbl((unsigned char *)&mb(8));
5724280849Scy			t = ap(pbuffer, sizeof(pbuffer), t, "lat %f %c, lon %f %c, alt %.2fm",
572554359Sroberto				((lat < 0.0) ? (-lat) : (lat))*RTOD, (lat < 0.0 ? 'S' : 'N'),
572654359Sroberto				((lng < 0.0) ? (-lng) : (lng))*RTOD, (lng < 0.0 ? 'W' : 'E'),
572754359Sroberto				getdbl((unsigned char *)&mb(16)));
572854359Sroberto		}
572954359Sroberto		break;
573054359Sroberto
573154359Sroberto		case CMD_RALLINVIEW:
573254359Sroberto		{
573354359Sroberto			int i, sats;
5734282408Scy
5735280849Scy			t = ap(pbuffer, sizeof(pbuffer), t, "mode: ");
573654359Sroberto			switch (mb(0) & 0x7)
573754359Sroberto			{
573854359Sroberto			default:
5739280849Scy				t = ap(pbuffer, sizeof(pbuffer), t, "0x%x", mb(0) & 0x7);
574054359Sroberto				break;
574154359Sroberto
574254359Sroberto			case 3:
5743280849Scy				t = ap(pbuffer, sizeof(pbuffer), t, "2D");
574454359Sroberto				break;
5745282408Scy
574654359Sroberto			case 4:
5747280849Scy				t = ap(pbuffer, sizeof(pbuffer), t, "3D");
574854359Sroberto				break;
574954359Sroberto			}
575054359Sroberto			if (mb(0) & 0x8)
5751280849Scy				t = ap(pbuffer, sizeof(pbuffer), t, "-MANUAL, ");
575254359Sroberto			else
5753280849Scy				t = ap(pbuffer, sizeof(pbuffer), t, "-AUTO, ");
5754282408Scy
575554359Sroberto			sats = (mb(0)>>4) & 0xF;
5756282408Scy
5757280849Scy			t = ap(pbuffer, sizeof(pbuffer), t, "PDOP %.2f, HDOP %.2f, VDOP %.2f, TDOP %.2f, %d satellite%s in view: ",
575854359Sroberto				getflt((unsigned char *)&mb(1)),
575954359Sroberto				getflt((unsigned char *)&mb(5)),
576054359Sroberto				getflt((unsigned char *)&mb(9)),
576154359Sroberto				getflt((unsigned char *)&mb(13)),
576254359Sroberto				sats, (sats == 1) ? "" : "s");
576354359Sroberto
576454359Sroberto			for (i=0; i < sats; i++)
576554359Sroberto			{
5766280849Scy				t = ap(pbuffer, sizeof(pbuffer), t, "%s%02d", i ? ", " : "", mb(17+i));
576754359Sroberto				if (tr)
576854359Sroberto					tr->ctrack |= (1 << (mb(17+i)-1));
576954359Sroberto			}
577054359Sroberto
577154359Sroberto			if (tr)
5772280849Scy			{	/* mark for tracking status query */
577354359Sroberto				tr->qtracking = 1;
577454359Sroberto			}
577554359Sroberto		}
577654359Sroberto		break;
5777282408Scy
577854359Sroberto		case CMD_RSTATTRACK:
577954359Sroberto		{
5780280849Scy			t = ap(pbuffer, sizeof(pbuffer), t-2, "[%02d]=\"", mb(0)); /* add index to var name */
578154359Sroberto			if (getflt((unsigned char *)&mb(4)) < 0.0)
578254359Sroberto			{
5783280849Scy				t = ap(pbuffer, sizeof(pbuffer), t, "<NO MEASUREMENTS>");
5784282408Scy				var_flag &= (u_short)(~DEF);
578554359Sroberto			}
578654359Sroberto			else
5787282408Scy			{
5788280849Scy				t = ap(pbuffer, sizeof(pbuffer), t, "ch=%d, acq=%s, eph=%d, signal_level= %5.2f, elevation= %5.2f, azimuth= %6.2f",
578954359Sroberto					(mb(1) & 0xFF)>>3,
579054359Sroberto					mb(2) ? ((mb(2) == 1) ? "ACQ" : "SRCH") : "NEVER",
579154359Sroberto					mb(3),
579254359Sroberto					getflt((unsigned char *)&mb(4)),
579354359Sroberto					getflt((unsigned char *)&mb(12)) * RTOD,
579454359Sroberto					getflt((unsigned char *)&mb(16)) * RTOD);
579554359Sroberto				if (mb(20))
579654359Sroberto				{
5797282408Scy					var_flag &= (u_short)(~DEF);
5798280849Scy					t = ap(pbuffer, sizeof(pbuffer), t, ", OLD");
579954359Sroberto				}
580054359Sroberto				if (mb(22))
580154359Sroberto				{
580254359Sroberto					if (mb(22) == 1)
5803280849Scy						t = ap(pbuffer, sizeof(pbuffer), t, ", BAD PARITY");
580454359Sroberto					else
580554359Sroberto						if (mb(22) == 2)
5806280849Scy							t = ap(pbuffer, sizeof(pbuffer), t, ", BAD EPH HEALTH");
580754359Sroberto				}
580854359Sroberto				if (mb(23))
5809280849Scy					t = ap(pbuffer, sizeof(pbuffer), t, ", collecting data");
581054359Sroberto			}
581154359Sroberto		}
581254359Sroberto		break;
5813282408Scy
581454359Sroberto		default:
5815280849Scy			t = ap(pbuffer, sizeof(pbuffer), t, "<UNDECODED>");
581654359Sroberto			break;
581754359Sroberto		}
5818182007Sroberto
5819282408Scy		t = ap(pbuffer, sizeof(pbuffer), t, "\"");
582054359Sroberto		set_var(&parse->kv, pbuffer, sizeof(pbuffer), var_flag);
582154359Sroberto	}
582254359Sroberto}
582354359Sroberto
5824282408Scy
582554359Sroberto/**============================================================
582654359Sroberto ** RAWDCF support
582754359Sroberto **/
582854359Sroberto
582954359Sroberto/*--------------------------------------------------
583056746Sroberto * rawdcf_init_1 - set up modem lines for RAWDCF receivers
583156746Sroberto * SET DTR line
583254359Sroberto */
583354359Sroberto#if defined(TIOCMSET) && (defined(TIOCM_DTR) || defined(CIOCM_DTR))
583454359Srobertostatic int
583556746Srobertorawdcf_init_1(
583654359Sroberto	struct parseunit *parse
583754359Sroberto	)
583854359Sroberto{
583982498Sroberto	/* fixed 2000 for using with Linux by Wolfram Pienkoss <wp@bszh.de> */
584054359Sroberto	/*
584154359Sroberto	 * You can use the RS232 to supply the power for a DCF77 receiver.
584254359Sroberto	 * Here a voltage between the DTR and the RTS line is used. Unfortunately
584354359Sroberto	 * the name has changed from CIOCM_DTR to TIOCM_DTR recently.
584454359Sroberto	 */
584582498Sroberto	int sl232;
584682498Sroberto
584782498Sroberto	if (ioctl(parse->generic->io.fd, TIOCMGET, (caddr_t)&sl232) == -1)
584882498Sroberto	{
584982498Sroberto		msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_1: WARNING: ioctl(fd, TIOCMGET, [C|T]IOCM_DTR): %m", CLK_UNIT(parse->peer));
585082498Sroberto		return 0;
585182498Sroberto	}
585282498Sroberto
585354359Sroberto#ifdef TIOCM_DTR
585482498Sroberto	sl232 = (sl232 & ~TIOCM_RTS) | TIOCM_DTR;	/* turn on DTR, clear RTS for power supply */
585554359Sroberto#else
585682498Sroberto	sl232 = (sl232 & ~CIOCM_RTS) | CIOCM_DTR;	/* turn on DTR, clear RTS for power supply */
585754359Sroberto#endif
585854359Sroberto
585954359Sroberto	if (ioctl(parse->generic->io.fd, TIOCMSET, (caddr_t)&sl232) == -1)
586054359Sroberto	{
586156746Sroberto		msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_1: WARNING: ioctl(fd, TIOCMSET, [C|T]IOCM_DTR): %m", CLK_UNIT(parse->peer));
586254359Sroberto	}
586354359Sroberto	return 0;
586454359Sroberto}
586554359Sroberto#else
586654359Srobertostatic int
5867132451Srobertorawdcfdtr_init_1(
586854359Sroberto	struct parseunit *parse
586954359Sroberto	)
587054359Sroberto{
587156746Sroberto	msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_1: WARNING: OS interface incapable of setting DTR to power DCF modules", CLK_UNIT(parse->peer));
587254359Sroberto	return 0;
587354359Sroberto}
587454359Sroberto#endif  /* DTR initialisation type */
587554359Sroberto
587654359Sroberto/*--------------------------------------------------
587756746Sroberto * rawdcf_init_2 - set up modem lines for RAWDCF receivers
587856746Sroberto * CLR DTR line, SET RTS line
587954359Sroberto */
588056746Sroberto#if defined(TIOCMSET) &&  (defined(TIOCM_RTS) || defined(CIOCM_RTS))
588154359Srobertostatic int
588256746Srobertorawdcf_init_2(
588354359Sroberto	struct parseunit *parse
588454359Sroberto	)
588554359Sroberto{
588682498Sroberto	/* fixed 2000 for using with Linux by Wolfram Pienkoss <wp@bszh.de> */
588754359Sroberto	/*
588854359Sroberto	 * You can use the RS232 to supply the power for a DCF77 receiver.
588956746Sroberto	 * Here a voltage between the DTR and the RTS line is used. Unfortunately
589056746Sroberto	 * the name has changed from CIOCM_DTR to TIOCM_DTR recently.
589154359Sroberto	 */
589282498Sroberto	int sl232;
589382498Sroberto
589482498Sroberto	if (ioctl(parse->generic->io.fd, TIOCMGET, (caddr_t)&sl232) == -1)
589582498Sroberto	{
589682498Sroberto		msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_2: WARNING: ioctl(fd, TIOCMGET, [C|T]IOCM_RTS): %m", CLK_UNIT(parse->peer));
589782498Sroberto		return 0;
589882498Sroberto	}
589982498Sroberto
590054359Sroberto#ifdef TIOCM_RTS
590182498Sroberto	sl232 = (sl232 & ~TIOCM_DTR) | TIOCM_RTS;	/* turn on RTS, clear DTR for power supply */
590254359Sroberto#else
590382498Sroberto	sl232 = (sl232 & ~CIOCM_DTR) | CIOCM_RTS;	/* turn on RTS, clear DTR for power supply */
590454359Sroberto#endif
590554359Sroberto
590654359Sroberto	if (ioctl(parse->generic->io.fd, TIOCMSET, (caddr_t)&sl232) == -1)
590754359Sroberto	{
590856746Sroberto		msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_2: WARNING: ioctl(fd, TIOCMSET, [C|T]IOCM_RTS): %m", CLK_UNIT(parse->peer));
590954359Sroberto	}
591054359Sroberto	return 0;
591154359Sroberto}
591254359Sroberto#else
591354359Srobertostatic int
591456746Srobertorawdcf_init_2(
591554359Sroberto	struct parseunit *parse
591654359Sroberto	)
591754359Sroberto{
591856746Sroberto	msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_2: WARNING: OS interface incapable of setting RTS to power DCF modules", CLK_UNIT(parse->peer));
591954359Sroberto	return 0;
592054359Sroberto}
592156746Sroberto#endif  /* DTR initialisation type */
592254359Sroberto
592354359Sroberto#else	/* defined(REFCLOCK) && defined(PARSE) */
5924280849ScyNONEMPTY_TRANSLATION_UNIT
592554359Sroberto#endif	/* defined(REFCLOCK) && defined(PARSE) */
592654359Sroberto
592754359Sroberto/*
592854359Sroberto * History:
592954359Sroberto *
593054359Sroberto * refclock_parse.c,v
5931280849Scy * Revision 4.81  2009/05/01 10:15:29  kardel
5932280849Scy * use new refclock_ppsapi interface
5933280849Scy *
5934182007Sroberto * Revision 4.80  2007/08/11 12:06:29  kardel
5935182007Sroberto * update comments wrt/ to PPS
5936182007Sroberto *
5937182007Sroberto * Revision 4.79  2007/08/11 11:52:23  kardel
5938182007Sroberto * - terminate io bindings before io_closeclock() will close our file descriptor
5939182007Sroberto *
5940182007Sroberto * Revision 4.78  2006/12/22 20:08:27  kardel
5941182007Sroberto * Bug 746 (RFE): add configuration for Expert mouseCLOCK USB v2.0 as mode 19
5942182007Sroberto *
5943182007Sroberto * Revision 4.77  2006/08/05 07:44:49  kardel
5944182007Sroberto * support optionally separate PPS devices via /dev/refclockpps-{0..3}
5945182007Sroberto *
5946182007Sroberto * Revision 4.76  2006/06/22 18:40:47  kardel
5947182007Sroberto * clean up signedness (gcc 4)
5948182007Sroberto *
5949182007Sroberto * Revision 4.75  2006/06/22 16:58:10  kardel
5950182007Sroberto * Bug #632: call parse_ppsapi() in parse_ctl() when updating
5951182007Sroberto * the PPS offset. Fix sign of offset passed to kernel.
5952182007Sroberto *
5953182007Sroberto * Revision 4.74  2006/06/18 21:18:37  kardel
5954182007Sroberto * NetBSD Coverity CID 3796: possible NULL deref
5955182007Sroberto *
5956182007Sroberto * Revision 4.73  2006/05/26 14:23:46  kardel
5957182007Sroberto * cleanup of copyright info
5958182007Sroberto *
5959182007Sroberto * Revision 4.72  2006/05/26 14:19:43  kardel
5960182007Sroberto * cleanup of ioctl cruft
5961182007Sroberto *
5962182007Sroberto * Revision 4.71  2006/05/26 14:15:57  kardel
5963182007Sroberto * delay adding refclock to async refclock io after all initializations
5964182007Sroberto *
5965182007Sroberto * Revision 4.70  2006/05/25 18:20:50  kardel
5966182007Sroberto * bug #619
5967182007Sroberto * terminate parse io engine after de-registering
5968182007Sroberto * from refclock io engine
5969182007Sroberto *
5970182007Sroberto * Revision 4.69  2006/05/25 17:28:02  kardel
5971182007Sroberto * complete refclock io structure initialization *before* inserting it into the
5972182007Sroberto * refclock input machine (avoids null pointer deref) (bug #619)
5973182007Sroberto *
5974182007Sroberto * Revision 4.68  2006/05/01 17:02:51  kardel
5975182007Sroberto * copy receiver method also for newlwy created receive buffers
5976182007Sroberto *
5977182007Sroberto * Revision 4.67  2006/05/01 14:37:29  kardel
5978182007Sroberto * If an input buffer parses into more than one message do insert the
5979182007Sroberto * parsed message in a new input buffer instead of processing it
5980182007Sroberto * directly. This avoids deed complicated processing in signal
5981182007Sroberto * handling.
5982182007Sroberto *
5983182007Sroberto * Revision 4.66  2006/03/18 00:45:30  kardel
5984182007Sroberto * coverity fixes found in NetBSD coverity scan
5985182007Sroberto *
5986182007Sroberto * Revision 4.65  2006/01/26 06:08:33  kardel
5987182007Sroberto * output errno on PPS setup failure
5988182007Sroberto *
5989182007Sroberto * Revision 4.64  2005/11/09 20:44:47  kardel
5990182007Sroberto * utilize full PPS timestamp resolution from PPS API
5991182007Sroberto *
5992182007Sroberto * Revision 4.63  2005/10/07 22:10:25  kardel
5993182007Sroberto * bounded buffer implementation
5994182007Sroberto *
5995182007Sroberto * Revision 4.62.2.2  2005/09/25 10:20:16  kardel
5996182007Sroberto * avoid unexpected buffer overflows due to sprintf("%f") on strange floats:
5997182007Sroberto * replace almost all str* and *printf functions be their buffer bounded
5998182007Sroberto * counterparts
5999182007Sroberto *
6000182007Sroberto * Revision 4.62.2.1  2005/08/27 16:19:27  kardel
6001182007Sroberto * limit re-set rate of trimble clocks
6002182007Sroberto *
6003182007Sroberto * Revision 4.62  2005/08/06 17:40:00  kardel
6004182007Sroberto * cleanup size handling wrt/ to buffer boundaries
6005182007Sroberto *
6006182007Sroberto * Revision 4.61  2005/07/27 21:16:19  kardel
6007182007Sroberto * fix a long (> 11 years) misconfiguration wrt/ Meinberg cflag factory
6008182007Sroberto * default setup. CSTOPB was missing for the 7E2 default data format of
6009182007Sroberto * the DCF77 clocks.
6010182007Sroberto *
6011182007Sroberto * Revision 4.60  2005/07/17 21:14:44  kardel
6012182007Sroberto * change contents of version string to include the RCS/CVS Id
6013182007Sroberto *
6014182007Sroberto * Revision 4.59  2005/07/06 06:56:38  kardel
6015182007Sroberto * syntax error
6016182007Sroberto *
6017182007Sroberto * Revision 4.58  2005/07/04 13:10:40  kardel
6018182007Sroberto * fix bug 455: tripping over NULL pointer on cleanup
6019182007Sroberto * fix shadow storage logic for ppsphaseadjust and trustime wrt/ time2
6020182007Sroberto * fix compiler warnings for some platforms wrt/ printf formatstrings and
6021182007Sroberto *     varying structure element sizes
6022182007Sroberto * reorder assignment in binding to avoid tripping over NULL pointers
6023182007Sroberto *
6024182007Sroberto * Revision 4.57  2005/06/25 09:25:19  kardel
6025182007Sroberto * sort out log output sequence
6026182007Sroberto *
6027182007Sroberto * Revision 4.56  2005/06/14 21:47:27  kardel
6028182007Sroberto * collect samples only if samples are ok (sync or trusted flywheel)
6029182007Sroberto * propagate pps phase adjustment value to kernel via PPSAPI to help HARDPPS
6030182007Sroberto * en- and dis-able HARDPPS in correlation to receiver sync state
6031182007Sroberto *
6032182007Sroberto * Revision 4.55  2005/06/02 21:28:31  kardel
6033182007Sroberto * clarify trust logic
6034182007Sroberto *
6035182007Sroberto * Revision 4.54  2005/06/02 17:06:49  kardel
6036182007Sroberto * change status reporting to use fixed refclock_report()
6037182007Sroberto *
6038182007Sroberto * Revision 4.53  2005/06/02 16:33:31  kardel
6039182007Sroberto * fix acceptance of clocks unsync clocks right at start
6040182007Sroberto *
6041182007Sroberto * Revision 4.52  2005/05/26 21:55:06  kardel
6042182007Sroberto * cleanup status reporting
6043182007Sroberto *
6044182007Sroberto * Revision 4.51  2005/05/26 19:19:14  kardel
6045182007Sroberto * implement fast refclock startup
6046182007Sroberto *
6047182007Sroberto * Revision 4.50  2005/04/16 20:51:35  kardel
6048280849Scy * set hardpps_enable = 1 when binding a kernel PPS source
6049182007Sroberto *
6050182007Sroberto * Revision 4.49  2005/04/16 17:29:26  kardel
6051182007Sroberto * add non polling clock type 18 for just listenning to Meinberg clocks
6052182007Sroberto *
6053182007Sroberto * Revision 4.48  2005/04/16 16:22:27  kardel
6054182007Sroberto * bk sync 20050415 ntp-dev
6055182007Sroberto *
6056182007Sroberto * Revision 4.47  2004/11/29 10:42:48  kardel
6057182007Sroberto * bk sync ntp-dev 20041129
6058182007Sroberto *
6059182007Sroberto * Revision 4.46  2004/11/29 10:26:29  kardel
6060182007Sroberto * keep fudgetime2 in sync with trusttime/ppsphaseadjust depending in flag1
6061182007Sroberto *
6062182007Sroberto * Revision 4.45  2004/11/14 20:53:20  kardel
6063182007Sroberto * clear PPS flags after using them
6064182007Sroberto *
6065182007Sroberto * Revision 4.44  2004/11/14 15:29:41  kardel
6066182007Sroberto * support PPSAPI, upgrade Copyright to Berkeley style
6067182007Sroberto *
6068182007Sroberto * Revision 4.43  2001/05/26 22:53:16  kardel
6069182007Sroberto * 20010526 reconcilation
6070182007Sroberto *
6071182007Sroberto * Revision 4.42  2000/05/14 15:31:51  kardel
6072182007Sroberto * PPSAPI && RAWDCF modemline support
6073182007Sroberto *
6074182007Sroberto * Revision 4.41  2000/04/09 19:50:45  kardel
6075182007Sroberto * fixed rawdcfdtr_init() -> rawdcf_init_1
6076182007Sroberto *
6077182007Sroberto * Revision 4.40  2000/04/09 15:27:55  kardel
6078182007Sroberto * modem line fiddle in rawdcf_init_2
6079182007Sroberto *
6080182007Sroberto * Revision 4.39  2000/03/18 09:16:55  kardel
6081182007Sroberto * PPSAPI integration
6082182007Sroberto *
6083182007Sroberto * Revision 4.38  2000/03/05 20:25:06  kardel
6084182007Sroberto * support PPSAPI
6085182007Sroberto *
6086182007Sroberto * Revision 4.37  2000/03/05 20:11:14  kardel
6087182007Sroberto * 4.0.99g reconcilation
6088182007Sroberto *
608956746Sroberto * Revision 4.36  1999/11/28 17:18:20  kardel
609056746Sroberto * disabled burst mode
609156746Sroberto *
609256746Sroberto * Revision 4.35  1999/11/28 09:14:14  kardel
609356746Sroberto * RECON_4_0_98F
609456746Sroberto *
609556746Sroberto * Revision 4.34  1999/05/14 06:08:05  kardel
609656746Sroberto * store current_time in a suitable container (u_long)
609756746Sroberto *
609856746Sroberto * Revision 4.33  1999/05/13 21:48:38  kardel
609956746Sroberto * double the no response timeout interval
610056746Sroberto *
610156746Sroberto * Revision 4.32  1999/05/13 20:09:13  kardel
610256746Sroberto * complain only about missing polls after a full poll interval
610356746Sroberto *
610456746Sroberto * Revision 4.31  1999/05/13 19:59:32  kardel
610556746Sroberto * add clock type 16 for RTS set DTR clr in RAWDCF
610656746Sroberto *
610756746Sroberto * Revision 4.30  1999/02/28 20:36:43  kardel
610856746Sroberto * fixed printf fmt
610956746Sroberto *
611054359Sroberto * Revision 4.29  1999/02/28 19:58:23  kardel
611154359Sroberto * updated copyright information
611254359Sroberto *
611354359Sroberto * Revision 4.28  1999/02/28 19:01:50  kardel
611454359Sroberto * improved debug out on sent Meinberg messages
611554359Sroberto *
611654359Sroberto * Revision 4.27  1999/02/28 18:05:55  kardel
611754359Sroberto * no linux/ppsclock.h stuff
611854359Sroberto *
611954359Sroberto * Revision 4.26  1999/02/28 15:27:27  kardel
612054359Sroberto * wharton clock integration
612154359Sroberto *
612254359Sroberto * Revision 4.25  1999/02/28 14:04:46  kardel
612354359Sroberto * added missing double quotes to UTC information string
612454359Sroberto *
612554359Sroberto * Revision 4.24  1999/02/28 12:06:50  kardel
612654359Sroberto * (parse_control): using gmprettydate instead of prettydate()
612754359Sroberto * (mk_utcinfo): new function for formatting GPS derived UTC information
612854359Sroberto * (gps16x_message): changed to use mk_utcinfo()
612954359Sroberto * (trimbletsip_message): changed to use mk_utcinfo()
613054359Sroberto * ignoring position information in unsynchronized mode
613154359Sroberto * (parse_start): augument linux support for optional ASYNC_LOW_LATENCY
613254359Sroberto *
613354359Sroberto * Revision 4.23  1999/02/23 19:47:53  kardel
613454359Sroberto * fixed #endifs
613554359Sroberto * (stream_receive): fixed formats
613654359Sroberto *
613754359Sroberto * Revision 4.22  1999/02/22 06:21:02  kardel
613854359Sroberto * use new autoconfig symbols
613954359Sroberto *
614054359Sroberto * Revision 4.21  1999/02/21 12:18:13  kardel
614154359Sroberto * 4.91f reconcilation
614254359Sroberto *
614354359Sroberto * Revision 4.20  1999/02/21 10:53:36  kardel
614454359Sroberto * initial Linux PPSkit version
614554359Sroberto *
614654359Sroberto * Revision 4.19  1999/02/07 09:10:45  kardel
614754359Sroberto * clarify STREAMS mitigation rules in comment
614854359Sroberto *
614954359Sroberto * Revision 4.18  1998/12/20 23:45:34  kardel
615054359Sroberto * fix types and warnings
615154359Sroberto *
615254359Sroberto * Revision 4.17  1998/11/15 21:24:51  kardel
615354359Sroberto * cannot access mbg_ routines when CLOCK_MEINBERG
615454359Sroberto * is not defined
615554359Sroberto *
615654359Sroberto * Revision 4.16  1998/11/15 20:28:17  kardel
615754359Sroberto * Release 4.0.73e13 reconcilation
615854359Sroberto *
615954359Sroberto * Revision 4.15  1998/08/22 21:56:08  kardel
616054359Sroberto * fixed IO handling for non-STREAM IO
616154359Sroberto *
616254359Sroberto * Revision 4.14  1998/08/16 19:00:48  kardel
616354359Sroberto * (gps16x_message): reduced UTC parameter information (dropped A0,A1)
616454359Sroberto * made uval a local variable (killed one of the last globals)
616554359Sroberto * (sendetx): added logging of messages when in debug mode
616654359Sroberto * (trimble_check): added periodic checks to facilitate re-initialization
616754359Sroberto * (trimbletsip_init): made use of EOL character if in non-kernel operation
616854359Sroberto * (trimbletsip_message): extended message interpretation
616954359Sroberto * (getdbl): fixed data conversion
617054359Sroberto *
617154359Sroberto * Revision 4.13  1998/08/09 22:29:13  kardel
617254359Sroberto * Trimble TSIP support
617354359Sroberto *
617454359Sroberto * Revision 4.12  1998/07/11 10:05:34  kardel
617554359Sroberto * Release 4.0.73d reconcilation
617654359Sroberto *
617754359Sroberto * Revision 4.11  1998/06/14 21:09:42  kardel
617854359Sroberto * Sun acc cleanup
617954359Sroberto *
618054359Sroberto * Revision 4.10  1998/06/13 12:36:45  kardel
618154359Sroberto * signed/unsigned, name clashes
618254359Sroberto *
618354359Sroberto * Revision 4.9  1998/06/12 15:30:00  kardel
618454359Sroberto * prototype fixes
618554359Sroberto *
618654359Sroberto * Revision 4.8  1998/06/12 11:19:42  kardel
618754359Sroberto * added direct input processing routine for refclocks in
618854359Sroberto * order to avaiod that single character io gobbles up all
618954359Sroberto * receive buffers and drops input data. (Problem started
619054359Sroberto * with fast machines so a character a buffer was possible
619154359Sroberto * one of the few cases where faster machines break existing
619254359Sroberto * allocation algorithms)
619354359Sroberto *
619454359Sroberto * Revision 4.7  1998/06/06 18:35:20  kardel
619554359Sroberto * (parse_start): added BURST mode initialisation
619654359Sroberto *
619754359Sroberto * Revision 4.6  1998/05/27 06:12:46  kardel
619854359Sroberto * RAWDCF_BASEDELAY default added
619954359Sroberto * old comment removed
620054359Sroberto * casts for ioctl()
620154359Sroberto *
620254359Sroberto * Revision 4.5  1998/05/25 22:05:09  kardel
620354359Sroberto * RAWDCF_SETDTR option removed
620454359Sroberto * clock type 14 attempts to set DTR for
620554359Sroberto * power supply of RAWDCF receivers
620654359Sroberto *
620754359Sroberto * Revision 4.4  1998/05/24 16:20:47  kardel
620854359Sroberto * updated comments referencing Meinberg clocks
620954359Sroberto * added RAWDCF clock with DTR set option as type 14
621054359Sroberto *
621154359Sroberto * Revision 4.3  1998/05/24 10:48:33  kardel
621254359Sroberto * calibrated CONRAD RAWDCF default fudge factor
621354359Sroberto *
621454359Sroberto * Revision 4.2  1998/05/24 09:59:35  kardel
621554359Sroberto * corrected version information (ntpq support)
621654359Sroberto *
621754359Sroberto * Revision 4.1  1998/05/24 09:52:31  kardel
621854359Sroberto * use fixed format only (new IO model)
621954359Sroberto * output debug to stdout instead of msyslog()
622054359Sroberto * don't include >"< in ASCII output in order not to confuse
622154359Sroberto * ntpq parsing
622254359Sroberto *
622354359Sroberto * Revision 4.0  1998/04/10 19:52:11  kardel
622454359Sroberto * Start 4.0 release version numbering
622554359Sroberto *
622654359Sroberto * Revision 1.2  1998/04/10 19:28:04  kardel
622754359Sroberto * initial NTP VERSION 4 integration of PARSE with GPS166 binary support
622854359Sroberto * derived from 3.105.1.2 from V3 tree
622954359Sroberto *
623054359Sroberto * Revision information 3.1 - 3.105 from log deleted 1998/04/10 kardel
623154359Sroberto *
623254359Sroberto */
6233