154359Sroberto/*
2290000Sglebius * /src/NTP/REPOSITORY/ntp4-dev/ntpd/refclock_parse.c,v 4.81 2009/05/01 10:15:29 kardel RELEASE_20090105_A
354359Sroberto *
4290000Sglebius * 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 *
18290000Sglebius * Copyright (c) 1995-2015 by Frank Kardel <kardel <AT> ntp.org>
19290000Sglebius * 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
51290000Sglebius#include "ntp_types.h"
52290000Sglebius
5354359Sroberto#if defined(REFCLOCK) && defined(CLOCK_PARSE)
5454359Sroberto
5554359Sroberto/*
5654359Sroberto * This driver currently provides the support for
57290000Sglebius *   - Meinberg receiver DCF77 PZF535 (TCXO version)        (DCF)
58290000Sglebius *   - Meinberg receiver DCF77 PZF535 (OCXO version)        (DCF)
59290000Sglebius *   - 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)
66290000Sglebius *   - WHARTON 400A Series clock                            (DCF)
6754359Sroberto *
68290000Sglebius *   - Meinberg GPS receivers                               (GPS)
6954359Sroberto *   - Trimble (TSIP and TAIP protocol)                     (GPS)
7054359Sroberto *
7154359Sroberto *   - RCC8000 MSF Receiver                                 (MSF)
72290000Sglebius *   - VARITEXT clock                                       (MSF)
7354359Sroberto */
7454359Sroberto
7554359Sroberto/*
7654359Sroberto * Meinberg receivers are usually connected via a
77290000Sglebius * 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:
83290000Sglebius *      output time code every second
84290000Sglebius *      Baud rate 9600 7E2S
8554359Sroberto *
86290000Sglebius * 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
94290000Sglebius * oldest GPS receiver, GPS16x. For newer receiver types
95290000Sglebius * the output string format can be configured at the device,
96290000Sglebius * 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"
103290000Sglebius#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
127290000Sglebius# 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"
149290000Sglebius# 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
161290000Sglebius# define BUFFER_SIZE(_BUF, _PTR)       ((int)((_BUF) + sizeof(_BUF) - (_PTR)))
162290000Sglebius# 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 */
167290000Sglebius#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
186290000Sglebius/*
187290000Sglebius * COND_DEF can be conditionally defined as DEF or 0. If defined as DEF
188290000Sglebius * then some more parse-specific variables are flagged to be printed with
189290000Sglebius * "ntpq -c cv <assid>". This can be lengthy, so by default COND_DEF
190290000Sglebius * should be defined as 0.
191290000Sglebius */
192290000Sglebius#if 0
193290000Sglebius# define COND_DEF   DEF   // enable this for testing
194290000Sglebius#else
195290000Sglebius# define COND_DEF   0     // enable this by default
196290000Sglebius#endif
197290000Sglebius
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
209290000Sglebiusstatic 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
215290000Sglebiusstatic	int	parse_start	(int, struct peer *);
216290000Sglebiusstatic	void	parse_shutdown	(int, struct peer *);
217290000Sglebiusstatic	void	parse_poll	(int, struct peer *);
218290000Sglebiusstatic	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 */
252290000Sglebius  int	(*bd_init)     (struct parseunit *);			/* initialize */
253290000Sglebius  void	(*bd_end)      (struct parseunit *);			/* end */
254290000Sglebius  int   (*bd_setcs)    (struct parseunit *, parsectl_t *);	/* set character size */
255290000Sglebius  int	(*bd_disable)  (struct parseunit *);			/* disable */
256290000Sglebius  int	(*bd_enable)   (struct parseunit *);			/* enable */
257290000Sglebius  int	(*bd_getfmt)   (struct parseunit *, parsectl_t *);	/* get format */
258290000Sglebius  int	(*bd_setfmt)   (struct parseunit *, parsectl_t *);	/* setfmt */
259290000Sglebius  int	(*bd_timecode) (struct parseunit *, parsectl_t *);	/* get time code */
260290000Sglebius  void	(*bd_receive)  (struct recvbuf *);			/* receive operation */
261290000Sglebius  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/*
273290000Sglebius * special handling flags
27454359Sroberto */
275290000Sglebius#define PARSE_F_PPSONSECOND	0x00000001 /* PPS pulses are on second */
276290000Sglebius#define PARSE_F_POWERUPTRUST	0x00000100 /* POWERUP state ist trusted for */
277290000Sglebius                                           /* 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 */
399290000Sglebius
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 */
426290000Sglebius	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
442290000Sglebiusstatic	void	poll_dpoll	(struct parseunit *);
443290000Sglebiusstatic	void	poll_poll	(struct peer *);
444290000Sglebiusstatic	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
467290000Sglebius#define NOCLOCK_ROOTDELAY       0.0
468290000Sglebius#define NOCLOCK_BASEDELAY       0.0
469290000Sglebius#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
475290000Sglebius#define NOCLOCK_ID              "TILT"
476290000Sglebius#define NOCLOCK_POLL            NO_POLL
477290000Sglebius#define NOCLOCK_INIT            NO_INIT
478290000Sglebius#define NOCLOCK_END             NO_END
479290000Sglebius#define NOCLOCK_DATA            NO_LCLDATA
480290000Sglebius#define NOCLOCK_FORMAT          ""
481290000Sglebius#define NOCLOCK_TYPE            CTL_SST_TS_UNSPEC
482290000Sglebius#define NOCLOCK_SAMPLES         0
483290000Sglebius#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/*
553290000Sglebius * Meinberg GPS receivers
55454359Sroberto */
555290000Sglebiusstatic	void	gps16x_message	 (struct parseunit *, parsetime_t *);
556290000Sglebiusstatic  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) */
560290000Sglebius#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 */
696290000Sglebiusstatic	int	rawdcf_init_1	(struct parseunit *);
69756746Sroberto#define RAWDCFDTRSET_DESCRIPTION	"RAW DCF77 CODE (DTR SET/RTS CLR)"
698290000Sglebius#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 */
705290000Sglebiusstatic	int	rawdcf_init_2	(struct parseunit *);
70656746Sroberto#define RAWDCFDTRCLRRTSSET_DESCRIPTION	"RAW DCF77 CODE (DTR CLR/RTS SET)"
707290000Sglebius#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 };
721290000Sglebiusstatic	int	trimbletaip_init	(struct parseunit *);
722290000Sglebiusstatic	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) };
728290000Sglebiusstatic	int	trimbletsip_init	(struct parseunit *);
729290000Sglebiusstatic	void	trimbletsip_end   	(struct parseunit *);
730290000Sglebiusstatic	void	trimbletsip_message	(struct parseunit *, parsetime_t *);
731290000Sglebiusstatic	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
762290000Sglebius#define TRIMBLETAIP_EVENT	    trimbletaip_event
76354359Sroberto
764290000Sglebius#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/*
821290000Sglebius * 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
876290000Sglebius/*
877290000Sglebius * SEL240x Satellite Sychronized Clock
878290000Sglebius */
879290000Sglebius#define SEL240X_POLLRATE	0 /* only true direct polling */
880290000Sglebius#define SEL240X_POLLCMD		"BUB8"
881290000Sglebius#define SEL240X_CMDSIZE		4
882290000Sglebius
883290000Sglebiusstatic poll_info_t sel240x_pollinfo = { SEL240X_POLLRATE,
884290000Sglebius	                                SEL240X_POLLCMD,
885290000Sglebius					SEL240X_CMDSIZE };
886290000Sglebius#define SEL240X_FLAGS		(PARSE_F_PPSONSECOND)
887290000Sglebius#define SEL240X_POLL		poll_dpoll
888290000Sglebius#define SEL240X_INIT		poll_init
889290000Sglebius#define SEL240X_END		0
890290000Sglebius#define SEL240X_DATA            ((void *)(&sel240x_pollinfo))
891290000Sglebius#define SEL240X_ROOTDELAY	0.0
892290000Sglebius#define SEL240X_BASEDELAY	0.0
893290000Sglebius#define SEL240X_ID		GPS_ID
894290000Sglebius#define SEL240X_DESCRIPTION	"SEL240x Satellite Synchronized Clock"
895290000Sglebius#define SEL240X_FORMAT		"SEL B8"
896290000Sglebius#define SEL240X_MAXUNSYNC	60*60*12 /* only trust clock for 12 hours */
897290000Sglebius#define SEL240X_SPEED		(B9600)
898290000Sglebius#define SEL240X_CFLAG		(CS8|CREAD|CLOCAL)
899290000Sglebius#define SEL240X_IFLAG		(IGNBRK|IGNPAR)
900290000Sglebius#define SEL240X_OFLAG		(0)
901290000Sglebius#define SEL240X_LFLAG		(0)
902290000Sglebius#define SEL240X_SAMPLES		5
903290000Sglebius#define SEL240X_KEEP		3
904290000Sglebius
90554359Srobertostatic struct parse_clockinfo
90654359Sroberto{
907290000Sglebius	u_long  cl_flags;		/* operation flags (PPS interpretation, trust handling) */
908290000Sglebius  void  (*cl_poll)    (struct parseunit *);			/* active poll routine */
909290000Sglebius  int   (*cl_init)    (struct parseunit *);			/* active poll init routine */
910290000Sglebius  void  (*cl_event)   (struct parseunit *, int);		/* special event handling (e.g. reset clock) */
911290000Sglebius  void  (*cl_end)     (struct parseunit *);			/* active poll end routine */
912290000Sglebius  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,
1217290000Sglebius		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	},
1401290000Sglebius	{				/* mode 20, like mode 14 but driven by 75 baud */
1402290000Sglebius		RAWDCF_FLAGS,
1403290000Sglebius		NO_POLL,
1404290000Sglebius		RAWDCFDTRSET_INIT,
1405290000Sglebius		NO_EVENT,
1406290000Sglebius		NO_END,
1407290000Sglebius		NO_MESSAGE,
1408290000Sglebius		NO_LCLDATA,
1409290000Sglebius		RAWDCF_ROOTDELAY,
1410290000Sglebius		RAWDCF_BASEDELAY,
1411290000Sglebius		DCF_A_ID,
1412290000Sglebius		RAWDCFDTRSET75_DESCRIPTION,
1413290000Sglebius		RAWDCF_FORMAT,
1414290000Sglebius		DCF_TYPE,
1415290000Sglebius		RAWDCF_MAXUNSYNC,
1416290000Sglebius		B75,
1417290000Sglebius		RAWDCF_CFLAG,
1418290000Sglebius		RAWDCF_IFLAG,
1419290000Sglebius		RAWDCF_OFLAG,
1420290000Sglebius		RAWDCF_LFLAG,
1421290000Sglebius		RAWDCF_SAMPLES,
1422290000Sglebius		RAWDCF_KEEP
1423290000Sglebius	},
1424290000Sglebius	{				/* mode 21, like mode 16 but driven by 75 baud
1425290000Sglebius					 - RAWDCF RTS set, DTR clr */
1426290000Sglebius		RAWDCF_FLAGS,
1427290000Sglebius		NO_POLL,
1428290000Sglebius		RAWDCFDTRCLRRTSSET_INIT,
1429290000Sglebius		NO_EVENT,
1430290000Sglebius		NO_END,
1431290000Sglebius		NO_MESSAGE,
1432290000Sglebius		NO_LCLDATA,
1433290000Sglebius		RAWDCF_ROOTDELAY,
1434290000Sglebius		RAWDCF_BASEDELAY,
1435290000Sglebius		DCF_A_ID,
1436290000Sglebius		RAWDCFDTRCLRRTSSET75_DESCRIPTION,
1437290000Sglebius		RAWDCF_FORMAT,
1438290000Sglebius		DCF_TYPE,
1439290000Sglebius		RAWDCF_MAXUNSYNC,
1440290000Sglebius		B75,
1441290000Sglebius		RAWDCF_CFLAG,
1442290000Sglebius		RAWDCF_IFLAG,
1443290000Sglebius		RAWDCF_OFLAG,
1444290000Sglebius		RAWDCF_LFLAG,
1445290000Sglebius		RAWDCF_SAMPLES,
1446290000Sglebius		RAWDCF_KEEP
1447290000Sglebius	},
1448290000Sglebius	{				/* mode 22 - like 2 with POWERUP trust */
1449290000Sglebius		MBG_FLAGS | PARSE_F_POWERUPTRUST,
1450290000Sglebius		NO_POLL,
1451290000Sglebius		NO_INIT,
1452290000Sglebius		NO_EVENT,
1453290000Sglebius		NO_END,
1454290000Sglebius		NO_MESSAGE,
1455290000Sglebius		NO_LCLDATA,
1456290000Sglebius		DCFUA31_ROOTDELAY,
1457290000Sglebius		DCFUA31_BASEDELAY,
1458290000Sglebius		DCF_A_ID,
1459290000Sglebius		DCFUA31_DESCRIPTION,
1460290000Sglebius		DCFUA31_FORMAT,
1461290000Sglebius		DCF_TYPE,
1462290000Sglebius		DCFUA31_MAXUNSYNC,
1463290000Sglebius		DCFUA31_SPEED,
1464290000Sglebius		DCFUA31_CFLAG,
1465290000Sglebius		DCFUA31_IFLAG,
1466290000Sglebius		DCFUA31_OFLAG,
1467290000Sglebius		DCFUA31_LFLAG,
1468290000Sglebius		DCFUA31_SAMPLES,
1469290000Sglebius		DCFUA31_KEEP
1470290000Sglebius	},
1471290000Sglebius	{				/* mode 23 - like 7 with POWERUP trust */
1472290000Sglebius		MBG_FLAGS | PARSE_F_POWERUPTRUST,
1473290000Sglebius		GPS16X_POLL,
1474290000Sglebius		GPS16X_INIT,
1475290000Sglebius		NO_EVENT,
1476290000Sglebius		GPS16X_END,
1477290000Sglebius		GPS16X_MESSAGE,
1478290000Sglebius		GPS16X_DATA,
1479290000Sglebius		GPS16X_ROOTDELAY,
1480290000Sglebius		GPS16X_BASEDELAY,
1481290000Sglebius		GPS16X_ID,
1482290000Sglebius		GPS16X_DESCRIPTION,
1483290000Sglebius		GPS16X_FORMAT,
1484290000Sglebius		GPS_TYPE,
1485290000Sglebius		GPS16X_MAXUNSYNC,
1486290000Sglebius		GPS16X_SPEED,
1487290000Sglebius		GPS16X_CFLAG,
1488290000Sglebius		GPS16X_IFLAG,
1489290000Sglebius		GPS16X_OFLAG,
1490290000Sglebius		GPS16X_LFLAG,
1491290000Sglebius		GPS16X_SAMPLES,
1492290000Sglebius		GPS16X_KEEP
1493290000Sglebius	},
1494290000Sglebius	{				/* mode 24 */
1495290000Sglebius		SEL240X_FLAGS,
1496290000Sglebius		SEL240X_POLL,
1497290000Sglebius		SEL240X_INIT,
1498290000Sglebius		NO_EVENT,
1499290000Sglebius		SEL240X_END,
1500290000Sglebius		NO_MESSAGE,
1501290000Sglebius		SEL240X_DATA,
1502290000Sglebius		SEL240X_ROOTDELAY,
1503290000Sglebius		SEL240X_BASEDELAY,
1504290000Sglebius		SEL240X_ID,
1505290000Sglebius		SEL240X_DESCRIPTION,
1506290000Sglebius		SEL240X_FORMAT,
1507290000Sglebius		GPS_TYPE,
1508290000Sglebius		SEL240X_MAXUNSYNC,
1509290000Sglebius		SEL240X_SPEED,
1510290000Sglebius		SEL240X_CFLAG,
1511290000Sglebius		SEL240X_IFLAG,
1512290000Sglebius		SEL240X_OFLAG,
1513290000Sglebius		SEL240X_LFLAG,
1514290000Sglebius		SEL240X_SAMPLES,
1515290000Sglebius		SEL240X_KEEP
1516290000Sglebius	},
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
1537290000Sglebiusstatic void parse_event   (struct parseunit *, int);
1538290000Sglebiusstatic void parse_process (struct parseunit *, parsetime_t *);
1539290000Sglebiusstatic void clear_err     (struct parseunit *, u_long);
1540290000Sglebiusstatic int  list_err      (struct parseunit *, u_long);
1541290000Sglebiusstatic 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	{
1554290000Sglebius		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++;
1593290000Sglebius
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	}
1617290000Sglebius
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,
1633293894Sglebius	size_t blen,
163454359Sroberto	const char  *src,
1635293894Sglebius	size_t srclen,
163654359Sroberto	int hex
163754359Sroberto	)
163854359Sroberto{
1639290000Sglebius	static const char ellipsis[] = "...";
164054359Sroberto	char *b    = buffer;
1641290000Sglebius	char *endb = NULL;
164254359Sroberto
164354359Sroberto	if (blen < 4)
1644290000Sglebius		return NULL;		/* don't bother with mini buffers */
164554359Sroberto
1646290000Sglebius	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 " */
1655290000Sglebius		    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				{
1675290000Sglebius					memcpy(buffer, "\\\\", 2);
167654359Sroberto					buffer += 2;
167754359Sroberto					blen   -= 2;
167854359Sroberto					src++;
167954359Sroberto				}
168054359Sroberto				else
168154359Sroberto				{
1682290000Sglebius					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 ... */
1689290000Sglebius			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
1721290000Sglebiusstatic int  ppsclock_init   (struct parseunit *);
1722290000Sglebiusstatic int  stream_init     (struct parseunit *);
1723290000Sglebiusstatic void stream_end      (struct parseunit *);
1724290000Sglebiusstatic int  stream_enable   (struct parseunit *);
1725290000Sglebiusstatic int  stream_disable  (struct parseunit *);
1726290000Sglebiusstatic int  stream_setcs    (struct parseunit *, parsectl_t *);
1727290000Sglebiusstatic int  stream_getfmt   (struct parseunit *, parsectl_t *);
1728290000Sglebiusstatic int  stream_setfmt   (struct parseunit *, parsectl_t *);
1729290000Sglebiusstatic int  stream_timecode (struct parseunit *, parsectl_t *);
1730290000Sglebiusstatic void stream_receive  (struct recvbuf *);
173154359Sroberto#endif
173254359Sroberto
1733290000Sglebiusstatic int  local_init     (struct parseunit *);
1734290000Sglebiusstatic void local_end      (struct parseunit *);
1735290000Sglebiusstatic int  local_nop      (struct parseunit *);
1736290000Sglebiusstatic int  local_setcs    (struct parseunit *, parsectl_t *);
1737290000Sglebiusstatic int  local_getfmt   (struct parseunit *, parsectl_t *);
1738290000Sglebiusstatic int  local_setfmt   (struct parseunit *, parsectl_t *);
1739290000Sglebiusstatic int  local_timecode (struct parseunit *, parsectl_t *);
1740290000Sglebiusstatic void local_receive  (struct recvbuf *);
1741290000Sglebiusstatic int  local_input    (struct recvbuf *);
1742290000Sglebius
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,
1788290000Sglebius		NULL,
1789290000Sglebius		NULL,
1790290000Sglebius		NULL,
1791290000Sglebius		NULL,
1792290000Sglebius		NULL,
1793290000Sglebius		NULL,
1794290000Sglebius		NULL,
1795290000Sglebius		NULL,
1796290000Sglebius		NULL,
1797290000Sglebius		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";
1813290000Sglebius
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;
1902290000Sglebius
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;
1925290000Sglebius
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;
1949290000Sglebius
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;
1974290000Sglebius
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;
1997290000Sglebius
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;
2022290000Sglebius
202354359Sroberto	strioc.ic_cmd     = PARSEIOC_TIMECODE;
202454359Sroberto	strioc.ic_timout  = 0;
202554359Sroberto	strioc.ic_dp      = (char *)tcl;
202654359Sroberto	strioc.ic_len     = sizeof (*tcl);
2027290000Sglebius
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{
2046290000Sglebius	struct parseunit * parse;
204754359Sroberto	parsetime_t parsetime;
204854359Sroberto
2049290000Sglebius	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);
2062290000Sglebius
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
2088290000Sglebius	parsetime.parse_stime.fp = tval_stamp_to_lfp(parsetime.parse_stime.tv);
208954359Sroberto
209054359Sroberto	if (PARSE_TIMECODE(parsetime.parse_state))
209154359Sroberto	{
2092290000Sglebius		parsetime.parse_time.fp = tval_stamp_to_lfp(parsetime.parse_time.tv);
209354359Sroberto	}
209454359Sroberto
209554359Sroberto	if (PARSE_PPS(parsetime.parse_state))
2096290000Sglebius	{
2097290000Sglebius		parsetime.parse_ptime.fp = tval_stamp_to_lfp(parsetime.parse_ptime.tv);
2098290000Sglebius	}
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{
2195290000Sglebius	struct parseunit * parse;
2196290000Sglebius
219754359Sroberto	int count;
219854359Sroberto	unsigned char *s;
219954359Sroberto	timestamp_t ts;
220054359Sroberto
2201290000Sglebius	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;
2228290000Sglebius
2229182007Sroberto					pps_timeout.tv_sec  = 0;
2230182007Sroberto					pps_timeout.tv_nsec = 0;
2231182007Sroberto
2232290000Sglebius					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
2249290000Sglebius							parse->parseio.parse_dtime.parse_ptime.fp.l_ui = (uint32_t) (pts.tv_sec + JAN_1970);
2250182007Sroberto
2251290000Sglebius							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							}
2260290000Sglebius							parse->parseio.parse_dtime.parse_ptime.fp.l_uf = (uint32_t)(dtemp * FRAC);
2261182007Sroberto
2262290000Sglebius							parse->parseio.parse_dtime.parse_state |= PARSEB_PPS|PARSEB_S_PPS;
2263182007Sroberto#ifdef DEBUG
2264182007Sroberto							if (debug > 3)
2265182007Sroberto							{
2266182007Sroberto								printf(
2267301301Sdelphij								       "parse: local_receive: fd %ld PPSAPI seq %ld - PPS %s\n",
2268301301Sdelphij								       (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(
2280301301Sdelphij								       "parse: local_receive: fd %ld PPSAPI seq assert %ld, seq clear %ld - NO PPS event\n",
2281301301Sdelphij								       (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(
2294301301Sdelphij							       "parse: local_receive: fd %ld PPSAPI time_pps_fetch errno = %d\n",
2295301301Sdelphij							       (long)rbufp->fd,
2296182007Sroberto							       errno);
2297182007Sroberto						}
2298182007Sroberto					}
2299182007Sroberto#endif
2300182007Sroberto				}
2301182007Sroberto#else
230254359Sroberto#ifdef TIOCDCDTIMESTAMP
230354359Sroberto				struct timeval dcd_time;
2304290000Sglebius
2305182007Sroberto				if (ioctl(parse->ppsfd, TIOCDCDTIMESTAMP, &dcd_time) != -1)
230654359Sroberto				{
230754359Sroberto					l_fp tstmp;
2308290000Sglebius
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 */
2369182007Sroberto				buf = get_free_recv_buffer();
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;
2376290000Sglebius#ifndef HAVE_IO_COMPLETION_PORT
2377182007Sroberto					buf->srcadr       = rbufp->srcadr;
2378290000Sglebius#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;
2383290000Sglebius					parse->generic->io.recvcount++;
2384290000Sglebius					packets_received++;
2385182007Sroberto					add_full_recv_buffer(buf);
2386290000Sglebius#ifdef HAVE_IO_COMPLETION_PORT
2387290000Sglebius					SetEvent(WaitableIoEventHandle);
2388290000Sglebius#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{
2414290000Sglebius	struct parseunit * parse;
241554359Sroberto	parsetime_t parsetime;
241654359Sroberto
2417290000Sglebius	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);
2430290000Sglebius
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
2479290000Sglebiusstatic NTP_PRINTF(4, 5) char *
2480290000Sglebiusap(char *buffer, size_t len, char *pos, const char *fmt, ...)
2481290000Sglebius{
2482290000Sglebius	va_list va;
2483290000Sglebius	int l;
2484290000Sglebius	size_t rem = len - (pos - buffer);
2485290000Sglebius
2486290000Sglebius	if (rem == 0)
2487290000Sglebius		return pos;
2488290000Sglebius
2489290000Sglebius	va_start(va, fmt);
2490290000Sglebius	l = vsnprintf(pos, rem, fmt, va);
2491290000Sglebius	va_end(va);
2492290000Sglebius
2493290000Sglebius	if (l != -1) {
2494290000Sglebius		rem--;
2495290000Sglebius		if (rem >= (size_t)l)
2496290000Sglebius			pos += l;
2497290000Sglebius		else
2498290000Sglebius			pos += rem;
2499290000Sglebius	}
2500290000Sglebius
2501290000Sglebius	return pos;
2502290000Sglebius}
2503290000Sglebius
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" },
2528290000Sglebius		  { PARSEB_CALLBIT,    "CALL BIT" },
252956746Sroberto		  { PARSEB_TIMECODE,   "TIME CODE" },
253056746Sroberto		  { PARSEB_PPS,        "PPS" },
253156746Sroberto		  { PARSEB_POSITION,   "POSITION" },
2532290000Sglebius		  { 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" },
2543290000Sglebius		  { PARSEB_S_CALLBIT,  "CALLBIT" },
254454359Sroberto		  { PARSEB_S_POSITION, "POSITION" },
2545290000Sglebius		  { 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)
2559290000Sglebius				t = ap(buffer, size, t, "; ");
2560290000Sglebius			t = ap(buffer, size, t, "%s", flagstrings[i].name);
256154359Sroberto		}
256254359Sroberto		i++;
256354359Sroberto	}
256454359Sroberto
2565290000Sglebius	if (lstate & (PARSEB_S_LEAP|PARSEB_S_CALLBIT|PARSEB_S_PPS|PARSEB_S_POSITION))
256654359Sroberto	{
2567182007Sroberto		if (s != t)
2568290000Sglebius			t = ap(buffer, size, t, "; ");
256954359Sroberto
2570290000Sglebius		t = ap(buffer, size, t, "(");
257154359Sroberto
2572290000Sglebius		s = t;
257354359Sroberto
257454359Sroberto		i = 0;
257554359Sroberto		while (sflagstrings[i].bit)
257654359Sroberto		{
257754359Sroberto			if (sflagstrings[i].bit & lstate)
257854359Sroberto			{
257954359Sroberto				if (t != s)
258054359Sroberto				{
2581290000Sglebius					t = ap(buffer, size, t, "; ");
258254359Sroberto				}
2583290000Sglebius
2584290000Sglebius				t = ap(buffer, size, t, "%s",
2585290000Sglebius				    sflagstrings[i].name);
258654359Sroberto			}
258754359Sroberto			i++;
258854359Sroberto		}
2589290000Sglebius		t = ap(buffer, size, t, ")");
2590290000Sglebius		/* t is unused here, but if we don't track it and
2591290000Sglebius		 * need it later, that's a bug waiting to happen.
2592290000Sglebius		 */
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" },
2620290000Sglebius		  { 0,		 NULL }
262154359Sroberto	  };
262254359Sroberto	int i;
2623290000Sglebius	char *t;
262454359Sroberto
2625290000Sglebius	t = buffer;
262654359Sroberto	*buffer = '\0';
262754359Sroberto
262854359Sroberto	i = 0;
262954359Sroberto	while (flagstrings[i].bit)
263054359Sroberto	{
263154359Sroberto		if (flagstrings[i].bit & lstate)
263254359Sroberto		{
2633290000Sglebius			if (t != buffer)
2634290000Sglebius				t = ap(buffer, size, t, "; ");
2635290000Sglebius			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" },
2665290000Sglebius		  { (unsigned)~0L, NULL }
266654359Sroberto	  };
266754359Sroberto	int i;
266854359Sroberto
266954359Sroberto	i = 0;
2670290000Sglebius	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';
2698290000Sglebius	t = buffer;
269954359Sroberto
270054359Sroberto	if ((tmp = delta / (60*60*24)) != 0)
270154359Sroberto	{
2702290000Sglebius		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
2711290000Sglebius	t = ap(buffer, sizeof(buffer), t, "%02d:%02d:%02d",
2712290000Sglebius	     (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{
2792290000Sglebius	struct parseunit *parse = NULL;
279354359Sroberto
2794182007Sroberto	if (peer && peer->procptr)
2795290000Sglebius		parse = peer->procptr->unitptr;
2796182007Sroberto
2797182007Sroberto	if (!parse)
279854359Sroberto	{
2799182007Sroberto		/* nothing to clean up */
280054359Sroberto		return;
280154359Sroberto	}
280254359Sroberto
2803290000Sglebius	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	{
2812290000Sglebius		(void)time_pps_destroy(parse->atom.handle);
2813182007Sroberto	}
2814182007Sroberto#endif
2815182007Sroberto	if (parse->generic->io.fd != parse->ppsfd && parse->ppsfd != -1)
2816290000Sglebius		(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	}
2828290000Sglebius
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);
2841290000Sglebius
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
2867290000Sglebius		if (mode == PARSE_HARDPPS_ENABLE)
2868182007Sroberto		        {
2869182007Sroberto			        if (parse->flags & PARSE_CLEAR)
2870182007Sroberto				        i = PPS_CAPTURECLEAR;
2871182007Sroberto				else
2872182007Sroberto				        i = PPS_CAPTUREASSERT;
2873182007Sroberto			}
2874290000Sglebius
2875290000Sglebius		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)
2887290000Sglebius			        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{
2902290000Sglebius	int cap, mode_ppsoffset;
2903290000Sglebius	const char *cp;
2904182007Sroberto
2905290000Sglebius	parse->flags &= (u_char) (~PARSE_PPSCLOCK);
2906290000Sglebius
2907290000Sglebius	/*
2908290000Sglebius	 * collect PPSAPI offset capability - should move into generic handling
2909290000Sglebius	 */
2910290000Sglebius	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));
2913290000Sglebius
2914182007Sroberto		return 0;
2915182007Sroberto	}
2916182007Sroberto
2917290000Sglebius	/*
2918290000Sglebius	 * initialize generic PPSAPI interface
2919290000Sglebius	 *
2920290000Sglebius	 * we leave out CLK_FLAG3 as time_pps_kcbind()
2921290000Sglebius	 * is handled here for now. Ideally this should also
2922290000Sglebius	 * be part of the generic PPSAPI interface
2923290000Sglebius	 */
2924290000Sglebius	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";
2933290000Sglebius		mode_ppsoffset = PPS_OFFSETCLEAR;
2934182007Sroberto	} else {
2935182007Sroberto		cp = "ASSERT";
2936290000Sglebius		mode_ppsoffset = PPS_OFFSETASSERT;
2937182007Sroberto	}
2938182007Sroberto
2939182007Sroberto	msyslog(LOG_INFO, "PARSE receiver #%d: initializing PPS to %s",
2940182007Sroberto		CLK_UNIT(parse->peer), cp);
2941182007Sroberto
2942290000Sglebius	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);
2945290000Sglebius		mode_ppsoffset = 0;
2946182007Sroberto	} else {
2947290000Sglebius		if (mode_ppsoffset == PPS_OFFSETCLEAR)
2948290000Sglebius			{
2949290000Sglebius				parse->atom.pps_params.clear_offset.tv_sec = (time_t)(-parse->ppsphaseadjust);
2950290000Sglebius				parse->atom.pps_params.clear_offset.tv_nsec = (long)(-1e9*(parse->ppsphaseadjust - (double)(long)parse->ppsphaseadjust));
2951182007Sroberto			}
2952290000Sglebius
2953290000Sglebius		if (mode_ppsoffset == PPS_OFFSETASSERT)
2954290000Sglebius			{
2955290000Sglebius				parse->atom.pps_params.assert_offset.tv_sec = (time_t)(-parse->ppsphaseadjust);
2956290000Sglebius				parse->atom.pps_params.assert_offset.tv_nsec = (long)(-1e9*(parse->ppsphaseadjust - (double)(long)parse->ppsphaseadjust));
2957182007Sroberto			}
2958182007Sroberto	}
2959182007Sroberto
2960290000Sglebius	parse->atom.pps_params.mode |= mode_ppsoffset;
2961182007Sroberto
2962290000Sglebius	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 */
3004290000Sglebius			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
3011290000Sglebius	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
3027290000Sglebius#ifndef O_NONBLOCK
3028290000Sglebius#define O_NONBLOCK 0
302954359Sroberto#endif
303054359Sroberto
3031290000Sglebius	fd232 = tty_open(parsedev, O_RDWR | O_NOCTTY | O_NONBLOCK, 0777);
3032290000Sglebius
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
3039290000Sglebius	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);
3063290000Sglebius
306454359Sroberto	parse->parse_type     = &parse_clockinfo[type];
3065290000Sglebius
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;
307254359Sroberto
3073182007Sroberto	parse->generic->clockdesc  = parse->parse_type->cl_description;
307454359Sroberto
307554359Sroberto	peer->rootdelay       = parse->parse_type->cl_rootdelay;
307654359Sroberto	peer->sstclktype      = parse->parse_type->cl_type;
307754359Sroberto	peer->precision       = sys_precision;
3078290000Sglebius
307954359Sroberto	peer->stratum         = STRATUM_REFCLOCK;
3080182007Sroberto
308154359Sroberto	if (peer->stratum <= 1)
308254359Sroberto	    memmove((char *)&parse->generic->refid, parse->parse_type->cl_id, 4);
308354359Sroberto	else
308454359Sroberto	    parse->generic->refid = htonl(PARSEHSREFID);
3085290000Sglebius
308654359Sroberto	parse->generic->io.fd = fd232;
3087290000Sglebius
308854359Sroberto	parse->peer = peer;		/* marks it also as busy */
308954359Sroberto
309054359Sroberto	/*
309154359Sroberto	 * configure terminal line
309254359Sroberto	 */
309354359Sroberto	if (TTY_GETATTR(fd232, &tio) == -1)
309454359Sroberto	{
309554359Sroberto		msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: tcgetattr(%d, &tio): %m", unit, fd232);
309654359Sroberto		parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
309754359Sroberto		return 0;
309854359Sroberto	}
309954359Sroberto	else
310054359Sroberto	{
310154359Sroberto#ifndef _PC_VDISABLE
310254359Sroberto		memset((char *)tio.c_cc, 0, sizeof(tio.c_cc));
310354359Sroberto#else
310454359Sroberto		int disablec;
310554359Sroberto		errno = 0;		/* pathconf can deliver -1 without changing errno ! */
310654359Sroberto
310754359Sroberto		disablec = fpathconf(parse->generic->io.fd, _PC_VDISABLE);
310854359Sroberto		if (disablec == -1 && errno)
310954359Sroberto		{
311054359Sroberto			msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: fpathconf(fd, _PC_VDISABLE): %m", CLK_UNIT(parse->peer));
311154359Sroberto			memset((char *)tio.c_cc, 0, sizeof(tio.c_cc)); /* best guess */
311254359Sroberto		}
311354359Sroberto		else
311454359Sroberto		    if (disablec != -1)
311554359Sroberto			memset((char *)tio.c_cc, disablec, sizeof(tio.c_cc));
311654359Sroberto#endif
311754359Sroberto
311854359Sroberto#if defined (VMIN) || defined(VTIME)
311954359Sroberto		if ((parse_clockinfo[type].cl_lflag & ICANON) == 0)
312054359Sroberto		{
312154359Sroberto#ifdef VMIN
312254359Sroberto			tio.c_cc[VMIN]   = 1;
312354359Sroberto#endif
312454359Sroberto#ifdef VTIME
312554359Sroberto			tio.c_cc[VTIME]  = 0;
312654359Sroberto#endif
312754359Sroberto		}
312854359Sroberto#endif
312954359Sroberto
3130290000Sglebius		tio.c_cflag = (tcflag_t) parse_clockinfo[type].cl_cflag;
3131290000Sglebius		tio.c_iflag = (tcflag_t) parse_clockinfo[type].cl_iflag;
3132290000Sglebius		tio.c_oflag = (tcflag_t) parse_clockinfo[type].cl_oflag;
3133290000Sglebius		tio.c_lflag = (tcflag_t) parse_clockinfo[type].cl_lflag;
313454359Sroberto
3135290000Sglebius
313654359Sroberto#ifdef HAVE_TERMIOS
3137290000Sglebius		if ((cfsetospeed(&tio, (speed_t) parse_clockinfo[type].cl_speed) == -1) ||
3138290000Sglebius		    (cfsetispeed(&tio, (speed_t) parse_clockinfo[type].cl_speed) == -1))
313954359Sroberto		{
314054359Sroberto			msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: tcset{i,o}speed(&tio, speed): %m", unit);
314154359Sroberto			parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
314254359Sroberto			return 0;
314354359Sroberto		}
314454359Sroberto#else
314554359Sroberto		tio.c_cflag     |= parse_clockinfo[type].cl_speed;
314654359Sroberto#endif
314754359Sroberto
3148182007Sroberto		/*
3149182007Sroberto		 * set up pps device
3150182007Sroberto		 * if the PARSEPPSDEVICE can be opened that will be used
3151182007Sroberto		 * for PPS else PARSEDEVICE will be used
3152182007Sroberto		 */
3153290000Sglebius		parse->ppsfd = tty_open(parseppsdev, O_RDWR | O_NOCTTY | O_NONBLOCK, 0777);
3154182007Sroberto
3155182007Sroberto		if (parse->ppsfd == -1)
3156182007Sroberto		{
3157182007Sroberto			parse->ppsfd = fd232;
3158182007Sroberto		}
3159182007Sroberto
3160182007Sroberto/*
3161182007Sroberto * Linux PPS - the old way
3162182007Sroberto */
316354359Sroberto#if defined(HAVE_TIO_SERIAL_STUFF)		/* Linux hack: define PPS interface */
316454359Sroberto		{
3165182007Sroberto			struct serial_struct	ss;
3166182007Sroberto			if (ioctl(parse->ppsfd, TIOCGSERIAL, &ss) < 0 ||
3167182007Sroberto			    (
316854359Sroberto#ifdef ASYNC_LOW_LATENCY
3169182007Sroberto			     ss.flags |= ASYNC_LOW_LATENCY,
317054359Sroberto#endif
3171182007Sroberto#ifndef HAVE_PPSAPI
317254359Sroberto#ifdef ASYNC_PPS_CD_NEG
3173182007Sroberto			     ss.flags |= ASYNC_PPS_CD_NEG,
317454359Sroberto#endif
3175182007Sroberto#endif
3176182007Sroberto			     ioctl(parse->ppsfd, TIOCSSERIAL, &ss)) < 0) {
3177182007Sroberto				msyslog(LOG_NOTICE, "refclock_parse: TIOCSSERIAL fd %d, %m", parse->ppsfd);
3178182007Sroberto				msyslog(LOG_NOTICE,
3179182007Sroberto					"refclock_parse: optional PPS processing not available");
3180182007Sroberto			} else {
3181182007Sroberto				parse->flags    |= PARSE_PPSCLOCK;
3182182007Sroberto#ifdef ASYNC_PPS_CD_NEG
3183182007Sroberto				NLOG(NLOG_CLOCKINFO)
3184182007Sroberto				  msyslog(LOG_INFO,
3185182007Sroberto					  "refclock_parse: PPS detection on");
3186182007Sroberto#endif
3187182007Sroberto			}
318854359Sroberto		}
318954359Sroberto#endif
3190182007Sroberto
3191182007Sroberto/*
3192182007Sroberto * SUN the Solaris way
3193182007Sroberto */
319454359Sroberto#ifdef HAVE_TIOCSPPS			/* SUN PPS support */
319554359Sroberto		if (CLK_PPS(parse->peer))
3196182007Sroberto		    {
3197182007Sroberto			int i = 1;
3198290000Sglebius
3199182007Sroberto			if (ioctl(parse->ppsfd, TIOCSPPS, (caddr_t)&i) == 0)
3200182007Sroberto			    {
3201182007Sroberto				parse->flags |= PARSE_PPSCLOCK;
3202182007Sroberto			    }
3203182007Sroberto		    }
320454359Sroberto#endif
320554359Sroberto
3206182007Sroberto/*
3207182007Sroberto * PPS via PPSAPI
3208182007Sroberto */
3209182007Sroberto#if defined(HAVE_PPSAPI)
3210182007Sroberto		parse->hardppsstate = PARSE_HARDPPS_DISABLE;
3211182007Sroberto		if (CLK_PPS(parse->peer))
3212182007Sroberto		{
3213290000Sglebius		  if (!refclock_ppsapi(parse->ppsfd, &parse->atom))
3214182007Sroberto		    {
3215182007Sroberto		      msyslog(LOG_NOTICE, "PARSE receiver #%d: parse_start: could not set up PPS: %m", CLK_UNIT(parse->peer));
3216182007Sroberto		    }
3217182007Sroberto		  else
3218182007Sroberto		    {
3219182007Sroberto		      parse_ppsapi(parse);
3220182007Sroberto		    }
3221182007Sroberto		}
3222182007Sroberto#endif
3223182007Sroberto
322454359Sroberto		if (TTY_SETATTR(fd232, &tio) == -1)
322554359Sroberto		{
322654359Sroberto			msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: tcsetattr(%d, &tio): %m", unit, fd232);
322754359Sroberto			parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
322854359Sroberto			return 0;
322954359Sroberto		}
323054359Sroberto	}
323154359Sroberto
323254359Sroberto	/*
3233182007Sroberto	 * pick correct input machine
323454359Sroberto	 */
3235290000Sglebius	parse->generic->io.srcclock = peer;
323654359Sroberto	parse->generic->io.datalen = 0;
3237290000Sglebius
323854359Sroberto	parse->binding = init_iobinding(parse);
323954359Sroberto
324054359Sroberto	if (parse->binding == (bind_t *)0)
324154359Sroberto		{
324254359Sroberto			msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: io sub system initialisation failed.", CLK_UNIT(parse->peer));
324354359Sroberto			parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
324454359Sroberto			return 0;			/* well, ok - special initialisation broke */
3245290000Sglebius		}
324654359Sroberto
3247182007Sroberto	parse->generic->io.clock_recv = parse->binding->bd_receive; /* pick correct receive routine */
3248182007Sroberto	parse->generic->io.io_input   = parse->binding->bd_io_input; /* pick correct input routine */
3249182007Sroberto
325054359Sroberto	/*
325154359Sroberto	 * as we always(?) get 8 bit chars we want to be
325254359Sroberto	 * sure, that the upper bits are zero for less
325354359Sroberto	 * than 8 bit I/O - so we pass that information on.
325454359Sroberto	 * note that there can be only one bit count format
325554359Sroberto	 * per file descriptor
325654359Sroberto	 */
325754359Sroberto
325854359Sroberto	switch (tio.c_cflag & CSIZE)
325954359Sroberto	{
326054359Sroberto	    case CS5:
326154359Sroberto		tmp_ctl.parsesetcs.parse_cs = PARSE_IO_CS5;
326254359Sroberto		break;
326354359Sroberto
326454359Sroberto	    case CS6:
326554359Sroberto		tmp_ctl.parsesetcs.parse_cs = PARSE_IO_CS6;
326654359Sroberto		break;
326754359Sroberto
326854359Sroberto	    case CS7:
326954359Sroberto		tmp_ctl.parsesetcs.parse_cs = PARSE_IO_CS7;
327054359Sroberto		break;
327154359Sroberto
327254359Sroberto	    case CS8:
327354359Sroberto		tmp_ctl.parsesetcs.parse_cs = PARSE_IO_CS8;
327454359Sroberto		break;
327554359Sroberto	}
327654359Sroberto
327754359Sroberto	if (!PARSE_SETCS(parse, &tmp_ctl))
327854359Sroberto	{
327954359Sroberto		msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: parse_setcs() FAILED.", unit);
328054359Sroberto		parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
328154359Sroberto		return 0;			/* well, ok - special initialisation broke */
328254359Sroberto	}
328354359Sroberto
3284290000Sglebius	strlcpy(tmp_ctl.parseformat.parse_buffer, parse->parse_type->cl_format, sizeof(tmp_ctl.parseformat.parse_buffer));
3285290000Sglebius	tmp_ctl.parseformat.parse_count = (u_short) strlen(tmp_ctl.parseformat.parse_buffer);
3286290000Sglebius
328754359Sroberto	if (!PARSE_SETFMT(parse, &tmp_ctl))
328854359Sroberto	{
328954359Sroberto		msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: parse_setfmt() FAILED.", unit);
329054359Sroberto		parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
329154359Sroberto		return 0;			/* well, ok - special initialisation broke */
329254359Sroberto	}
3293290000Sglebius
329454359Sroberto	/*
329554359Sroberto	 * get rid of all IO accumulated so far
329654359Sroberto	 */
329754359Sroberto#ifdef HAVE_TERMIOS
329854359Sroberto	(void) tcflush(parse->generic->io.fd, TCIOFLUSH);
329954359Sroberto#else
3300182007Sroberto#if defined(TCFLSH) && defined(TCIOFLUSH)
330154359Sroberto	{
330254359Sroberto		int flshcmd = TCIOFLUSH;
330354359Sroberto
330454359Sroberto		(void) ioctl(parse->generic->io.fd, TCFLSH, (caddr_t)&flshcmd);
330554359Sroberto	}
330654359Sroberto#endif
330754359Sroberto#endif
330856746Sroberto
330954359Sroberto	/*
331054359Sroberto	 * try to do any special initializations
331154359Sroberto	 */
331254359Sroberto	if (parse->parse_type->cl_init)
331354359Sroberto		{
331454359Sroberto			if (parse->parse_type->cl_init(parse))
331554359Sroberto				{
331654359Sroberto					parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
331754359Sroberto					return 0;		/* well, ok - special initialisation broke */
331854359Sroberto				}
331954359Sroberto		}
3320290000Sglebius
332154359Sroberto	/*
3322182007Sroberto	 * Insert in async io device list.
332354359Sroberto	 */
3324182007Sroberto	if (!io_addclock(&parse->generic->io))
332554359Sroberto        {
3326182007Sroberto		msyslog(LOG_ERR,
3327182007Sroberto			"PARSE receiver #%d: parse_start: addclock %s fails (ABORT - clock type requires async io)", CLK_UNIT(parse->peer), parsedev);
3328182007Sroberto		parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
3329182007Sroberto		return 0;
333054359Sroberto	}
333154359Sroberto
333254359Sroberto	/*
333354359Sroberto	 * print out configuration
333454359Sroberto	 */
333554359Sroberto	NLOG(NLOG_CLOCKINFO)
333654359Sroberto		{
333754359Sroberto			/* conditional if clause for conditional syslog */
3338182007Sroberto			msyslog(LOG_INFO, "PARSE receiver #%d: reference clock \"%s\" (I/O device %s, PPS device %s) added",
333954359Sroberto				CLK_UNIT(parse->peer),
3340182007Sroberto				parse->parse_type->cl_description, parsedev,
3341182007Sroberto				(parse->ppsfd != parse->generic->io.fd) ? parseppsdev : parsedev);
334254359Sroberto
3343182007Sroberto			msyslog(LOG_INFO, "PARSE receiver #%d: Stratum %d, trust time %s, precision %d",
334454359Sroberto				CLK_UNIT(parse->peer),
3345182007Sroberto				parse->peer->stratum,
3346182007Sroberto				l_mktime(parse->maxunsync), parse->peer->precision);
334754359Sroberto
3348182007Sroberto			msyslog(LOG_INFO, "PARSE receiver #%d: rootdelay %.6f s, phase adjustment %.6f s, PPS phase adjustment %.6f s, %s IO handling",
334954359Sroberto				CLK_UNIT(parse->peer),
335054359Sroberto				parse->parse_type->cl_rootdelay,
335154359Sroberto				parse->generic->fudgetime1,
3352182007Sroberto				parse->ppsphaseadjust,
3353182007Sroberto                                parse->binding->bd_description);
335454359Sroberto
3355182007Sroberto			msyslog(LOG_INFO, "PARSE receiver #%d: Format recognition: %s", CLK_UNIT(parse->peer),
335654359Sroberto				parse->parse_type->cl_format);
3357182007Sroberto                        msyslog(LOG_INFO, "PARSE receiver #%d: %sPPS support%s", CLK_UNIT(parse->peer),
3358182007Sroberto				CLK_PPS(parse->peer) ? "" : "NO ",
3359182007Sroberto				CLK_PPS(parse->peer) ?
3360182007Sroberto#ifdef PPS_METHOD
3361182007Sroberto				" (implementation " PPS_METHOD ")"
3362182007Sroberto#else
3363182007Sroberto				""
336454359Sroberto#endif
3365182007Sroberto				: ""
3366182007Sroberto				);
336754359Sroberto		}
336854359Sroberto
336954359Sroberto	return 1;
337054359Sroberto}
337154359Sroberto
337254359Sroberto/*--------------------------------------------------
3373182007Sroberto * parse_ctl - process changes on flags/time values
3374182007Sroberto */
3375182007Srobertostatic void
3376182007Srobertoparse_ctl(
3377182007Sroberto	    struct parseunit *parse,
3378290000Sglebius	    const struct refclockstat *in
3379182007Sroberto	    )
3380182007Sroberto{
3381182007Sroberto        if (in)
3382182007Sroberto	{
3383182007Sroberto		if (in->haveflags & (CLK_HAVEFLAG1|CLK_HAVEFLAG2|CLK_HAVEFLAG3|CLK_HAVEFLAG4))
3384182007Sroberto		{
3385290000Sglebius		  u_char mask = CLK_FLAG1|CLK_FLAG2|CLK_FLAG3|CLK_FLAG4;
3386290000Sglebius		  parse->flags = (parse->flags & (u_char)(~mask)) | (in->flags & mask);
3387182007Sroberto#if defined(HAVE_PPSAPI)
3388182007Sroberto		  if (CLK_PPS(parse->peer))
3389182007Sroberto		    {
3390182007Sroberto		      parse_ppsapi(parse);
3391182007Sroberto		    }
3392182007Sroberto#endif
3393182007Sroberto		}
3394290000Sglebius
3395182007Sroberto		if (in->haveflags & CLK_HAVETIME1)
3396182007Sroberto                {
3397182007Sroberto		  parse->generic->fudgetime1 = in->fudgetime1;
3398182007Sroberto		  msyslog(LOG_INFO, "PARSE receiver #%d: new phase adjustment %.6f s",
3399182007Sroberto			  CLK_UNIT(parse->peer),
3400182007Sroberto			  parse->generic->fudgetime1);
3401182007Sroberto		}
3402290000Sglebius
3403182007Sroberto		if (in->haveflags & CLK_HAVETIME2)
3404182007Sroberto                {
3405182007Sroberto		  parse->generic->fudgetime2 = in->fudgetime2;
3406290000Sglebius		  if (parse->flags & PARSE_TRUSTTIME)
3407182007Sroberto		    {
3408182007Sroberto		      parse->maxunsync = (u_long)ABS(in->fudgetime2);
3409182007Sroberto		      msyslog(LOG_INFO, "PARSE receiver #%d: new trust time %s",
3410182007Sroberto			      CLK_UNIT(parse->peer),
3411182007Sroberto			      l_mktime(parse->maxunsync));
3412182007Sroberto		    }
3413182007Sroberto		  else
3414182007Sroberto		    {
3415182007Sroberto		      parse->ppsphaseadjust = in->fudgetime2;
3416182007Sroberto		      msyslog(LOG_INFO, "PARSE receiver #%d: new PPS phase adjustment %.6f s",
3417182007Sroberto			  CLK_UNIT(parse->peer),
3418182007Sroberto			      parse->ppsphaseadjust);
3419182007Sroberto#if defined(HAVE_PPSAPI)
3420182007Sroberto		      if (CLK_PPS(parse->peer))
3421182007Sroberto		      {
3422182007Sroberto			      parse_ppsapi(parse);
3423182007Sroberto		      }
3424182007Sroberto#endif
3425182007Sroberto		    }
3426182007Sroberto		}
3427182007Sroberto	}
3428182007Sroberto}
3429182007Sroberto
3430182007Sroberto/*--------------------------------------------------
343154359Sroberto * parse_poll - called by the transmit procedure
343254359Sroberto */
343354359Srobertostatic void
343454359Srobertoparse_poll(
343554359Sroberto	int unit,
343654359Sroberto	struct peer *peer
343754359Sroberto	)
343854359Sroberto{
3439290000Sglebius	struct parseunit *parse = peer->procptr->unitptr;
344054359Sroberto
344154359Sroberto	if (peer != parse->peer)
344254359Sroberto	{
344354359Sroberto		msyslog(LOG_ERR,
344454359Sroberto			"PARSE receiver #%d: poll: INTERNAL: peer incorrect",
344554359Sroberto			unit);
344654359Sroberto		return;
344754359Sroberto	}
344854359Sroberto
344954359Sroberto	/*
345054359Sroberto	 * Update clock stat counters
345154359Sroberto	 */
345254359Sroberto	parse->generic->polls++;
345354359Sroberto
3454290000Sglebius	if (parse->pollneeddata &&
3455290000Sglebius	    ((int)(current_time - parse->pollneeddata) > (1<<(max(min(parse->peer->hpoll, parse->peer->ppoll), parse->peer->minpoll)))))
345654359Sroberto	{
345754359Sroberto		/*
345856746Sroberto		 * start worrying when exceeding a poll inteval
345954359Sroberto		 * bad news - didn't get a response last time
346054359Sroberto		 */
346154359Sroberto		parse->lastmissed = current_time;
346254359Sroberto		parse_event(parse, CEVNT_TIMEOUT);
3463290000Sglebius
346454359Sroberto		ERR(ERR_NODATA)
3465182007Sroberto			msyslog(LOG_WARNING, "PARSE receiver #%d: no data from device within poll interval (check receiver / wiring)", CLK_UNIT(parse->peer));
346654359Sroberto	}
346754359Sroberto
346854359Sroberto	/*
346954359Sroberto	 * we just mark that we want the next sample for the clock filter
347054359Sroberto	 */
347156746Sroberto	parse->pollneeddata = current_time;
347254359Sroberto
347354359Sroberto	if (parse->parse_type->cl_poll)
347454359Sroberto	{
347554359Sroberto		parse->parse_type->cl_poll(parse);
347654359Sroberto	}
347754359Sroberto
347854359Sroberto	cparse_statistics(parse);
347954359Sroberto
348054359Sroberto	return;
348154359Sroberto}
348254359Sroberto
348354359Sroberto#define LEN_STATES 300		/* length of state string */
348454359Sroberto
348554359Sroberto/*--------------------------------------------------
348654359Sroberto * parse_control - set fudge factors, return statistics
348754359Sroberto */
348854359Srobertostatic void
348954359Srobertoparse_control(
349054359Sroberto	int unit,
3491290000Sglebius	const struct refclockstat *in,
349254359Sroberto	struct refclockstat *out,
349354359Sroberto	struct peer *peer
349454359Sroberto	)
349554359Sroberto{
3496290000Sglebius	struct parseunit *parse = peer->procptr->unitptr;
349754359Sroberto	parsectl_t tmpctl;
349854359Sroberto
349954359Sroberto	static char outstatus[400];	/* status output buffer */
350054359Sroberto
350154359Sroberto	if (out)
350254359Sroberto	{
350354359Sroberto		out->lencode       = 0;
350454359Sroberto		out->p_lastcode    = 0;
350554359Sroberto		out->kv_list       = (struct ctl_var *)0;
350654359Sroberto	}
350754359Sroberto
350854359Sroberto	if (!parse || !parse->peer)
350954359Sroberto	{
351054359Sroberto		msyslog(LOG_ERR, "PARSE receiver #%d: parse_control: unit invalid (UNIT INACTIVE)",
351154359Sroberto			unit);
351254359Sroberto		return;
351354359Sroberto	}
351454359Sroberto
351554359Sroberto	unit = CLK_UNIT(parse->peer);
351654359Sroberto
3517182007Sroberto	/*
3518182007Sroberto	 * handle changes
3519182007Sroberto	 */
3520182007Sroberto	parse_ctl(parse, in);
3521290000Sglebius
3522182007Sroberto	/*
3523182007Sroberto	 * supply data
3524182007Sroberto	 */
352554359Sroberto	if (out)
352654359Sroberto	{
352754359Sroberto		u_long sum = 0;
3528182007Sroberto		char *tt, *start;
352954359Sroberto		int i;
353054359Sroberto
353154359Sroberto		outstatus[0] = '\0';
353254359Sroberto
353354359Sroberto		out->type       = REFCLK_PARSE;
353454359Sroberto
353554359Sroberto		/*
3536182007Sroberto		 * keep fudgetime2 in sync with TRUSTTIME/MAXUNSYNC flag1
3537182007Sroberto		 */
3538182007Sroberto		parse->generic->fudgetime2 = (parse->flags & PARSE_TRUSTTIME) ? (double)parse->maxunsync : parse->ppsphaseadjust;
3539182007Sroberto
3540182007Sroberto		/*
354154359Sroberto		 * figure out skew between PPS and RS232 - just for informational
3542182007Sroberto		 * purposes
354354359Sroberto		 */
3544182007Sroberto		if (PARSE_SYNC(parse->timedata.parse_state))
354554359Sroberto		{
3546182007Sroberto			if (PARSE_PPS(parse->timedata.parse_state) && PARSE_TIMECODE(parse->timedata.parse_state))
354754359Sroberto			{
354854359Sroberto				l_fp off;
354954359Sroberto
355054359Sroberto				/*
355154359Sroberto				 * we have a PPS and RS232 signal - calculate the skew
355254359Sroberto				 * WARNING: assumes on TIMECODE == PULSE (timecode after pulse)
355354359Sroberto				 */
3554182007Sroberto				off = parse->timedata.parse_stime.fp;
3555182007Sroberto				L_SUB(&off, &parse->timedata.parse_ptime.fp); /* true offset */
355654359Sroberto				tt = add_var(&out->kv_list, 80, RO);
3557182007Sroberto				snprintf(tt, 80, "refclock_ppsskew=%s", lfptoms(&off, 6));
355854359Sroberto			}
355954359Sroberto		}
356054359Sroberto
3561182007Sroberto		if (PARSE_PPS(parse->timedata.parse_state))
356254359Sroberto		{
356354359Sroberto			tt = add_var(&out->kv_list, 80, RO|DEF);
3564182007Sroberto			snprintf(tt, 80, "refclock_ppstime=\"%s\"", gmprettydate(&parse->timedata.parse_ptime.fp));
356554359Sroberto		}
356654359Sroberto
3567182007Sroberto		start = tt = add_var(&out->kv_list, 128, RO|DEF);
3568290000Sglebius		tt = ap(start, 128, tt, "refclock_time=\"");
356954359Sroberto
3570182007Sroberto		if (parse->timedata.parse_time.fp.l_ui == 0)
357154359Sroberto		{
3572290000Sglebius			tt = ap(start, 128, tt, "<UNDEFINED>\"");
357354359Sroberto		}
357454359Sroberto		else
357554359Sroberto		{
3576290000Sglebius			tt = ap(start, 128, tt, "%s\"",
3577290000Sglebius			    gmprettydate(&parse->timedata.parse_time.fp));
357854359Sroberto		}
357954359Sroberto
358054359Sroberto		if (!PARSE_GETTIMECODE(parse, &tmpctl))
358154359Sroberto		{
358254359Sroberto			ERR(ERR_INTERNAL)
358354359Sroberto				msyslog(LOG_ERR, "PARSE receiver #%d: parse_control: parse_timecode() FAILED", unit);
358454359Sroberto		}
358554359Sroberto		else
358654359Sroberto		{
3587182007Sroberto			start = tt = add_var(&out->kv_list, 512, RO|DEF);
3588290000Sglebius			tt = ap(start, 512, tt, "refclock_status=\"");
358954359Sroberto
359054359Sroberto			/*
359154359Sroberto			 * copy PPS flags from last read transaction (informational only)
359254359Sroberto			 */
3593182007Sroberto			tmpctl.parsegettc.parse_state |= parse->timedata.parse_state &
359454359Sroberto				(PARSEB_PPS|PARSEB_S_PPS);
359554359Sroberto
3596290000Sglebius			(void)parsestate(tmpctl.parsegettc.parse_state, tt, BUFFER_SIZES(start, tt, 512));
359754359Sroberto
3598290000Sglebius			tt += strlen(tt);
359954359Sroberto
3600290000Sglebius			tt = ap(start, 512, tt, "\"");
3601290000Sglebius
360254359Sroberto			if (tmpctl.parsegettc.parse_count)
360354359Sroberto			    mkascii(outstatus+strlen(outstatus), (int)(sizeof(outstatus)- strlen(outstatus) - 1),
3604182007Sroberto				    tmpctl.parsegettc.parse_buffer, (unsigned)(tmpctl.parsegettc.parse_count));
360554359Sroberto
360654359Sroberto		}
3607290000Sglebius
360854359Sroberto		tmpctl.parseformat.parse_format = tmpctl.parsegettc.parse_format;
3609290000Sglebius
361054359Sroberto		if (!PARSE_GETFMT(parse, &tmpctl))
361154359Sroberto		{
361254359Sroberto			ERR(ERR_INTERNAL)
361354359Sroberto				msyslog(LOG_ERR, "PARSE receiver #%d: parse_control: parse_getfmt() FAILED", unit);
361454359Sroberto		}
361554359Sroberto		else
361654359Sroberto		{
3617290000Sglebius			int count = tmpctl.parseformat.parse_count - 1;
361854359Sroberto
3619290000Sglebius			start = tt = add_var(&out->kv_list, 80, RO|DEF);
3620290000Sglebius			tt = ap(start, 80, tt, "refclock_format=\"");
3621290000Sglebius
3622290000Sglebius			if (count > 0) {
3623290000Sglebius				tt = ap(start, 80, tt, "%*.*s",
3624290000Sglebius			        	count,
3625290000Sglebius			        	count,
3626290000Sglebius			        	tmpctl.parseformat.parse_buffer);
3627290000Sglebius			}
3628290000Sglebius
3629290000Sglebius			tt = ap(start, 80, tt, "\"");
363054359Sroberto		}
363154359Sroberto
363254359Sroberto		/*
363354359Sroberto		 * gather state statistics
363454359Sroberto		 */
363554359Sroberto
363654359Sroberto		start = tt = add_var(&out->kv_list, LEN_STATES, RO|DEF);
3637290000Sglebius		tt = ap(start, LEN_STATES, tt, "refclock_states=\"");
363854359Sroberto
363954359Sroberto		for (i = 0; i <= CEVNT_MAX; i++)
364054359Sroberto		{
364154359Sroberto			u_long s_time;
364254359Sroberto			u_long d = current_time - parse->generic->timestarted;
364354359Sroberto			u_long percent;
364454359Sroberto
364554359Sroberto			percent = s_time = PARSE_STATETIME(parse, i);
364654359Sroberto
364754359Sroberto			while (((u_long)(~0) / 10000) < percent)
364854359Sroberto			{
364954359Sroberto				percent /= 10;
365054359Sroberto				d       /= 10;
365154359Sroberto			}
3652290000Sglebius
365354359Sroberto			if (d)
365454359Sroberto			    percent = (percent * 10000) / d;
365554359Sroberto			else
365654359Sroberto			    percent = 10000;
365754359Sroberto
365854359Sroberto			if (s_time)
365954359Sroberto			{
366054359Sroberto				char item[80];
366154359Sroberto				int count;
3662290000Sglebius
3663182007Sroberto				snprintf(item, 80, "%s%s%s: %s (%d.%02d%%)",
366454359Sroberto					sum ? "; " : "",
366554359Sroberto					(parse->generic->currentstatus == i) ? "*" : "",
366654359Sroberto					clockstatus((unsigned int)i),
366754359Sroberto					l_mktime(s_time),
366854359Sroberto					(int)(percent / 100), (int)(percent % 100));
3669290000Sglebius				if ((count = (int) strlen(item)) < (LEN_STATES - 40 - (tt - start)))
367054359Sroberto					{
3671290000Sglebius						tt = ap(start, LEN_STATES, tt,
3672290000Sglebius						    "%s", item);
367354359Sroberto					}
367454359Sroberto				sum += s_time;
367554359Sroberto			}
367654359Sroberto		}
3677290000Sglebius
3678290000Sglebius		tt = ap(start, LEN_STATES, tt,
3679290000Sglebius		    "; running time: %s\"", l_mktime(sum));
3680290000Sglebius
368154359Sroberto		tt = add_var(&out->kv_list, 32, RO);
3682182007Sroberto		snprintf(tt, 32,  "refclock_id=\"%s\"", parse->parse_type->cl_id);
3683290000Sglebius
368454359Sroberto		tt = add_var(&out->kv_list, 80, RO);
3685182007Sroberto		snprintf(tt, 80,  "refclock_iomode=\"%s\"", parse->binding->bd_description);
368654359Sroberto
368754359Sroberto		tt = add_var(&out->kv_list, 128, RO);
3688182007Sroberto		snprintf(tt, 128, "refclock_driver_version=\"%s\"", rcsid);
3689290000Sglebius
369054359Sroberto		{
369154359Sroberto			struct ctl_var *k;
3692290000Sglebius
369354359Sroberto			k = parse->kv;
369454359Sroberto			while (k && !(k->flags & EOV))
369554359Sroberto			{
369654359Sroberto				set_var(&out->kv_list, k->text, strlen(k->text)+1, k->flags);
369754359Sroberto				k++;
369854359Sroberto			}
369954359Sroberto		}
3700290000Sglebius
3701290000Sglebius		out->lencode       = (u_short) strlen(outstatus);
370254359Sroberto		out->p_lastcode    = outstatus;
370354359Sroberto	}
370454359Sroberto}
370554359Sroberto
370654359Sroberto/**===========================================================================
370754359Sroberto ** processing routines
370854359Sroberto **/
370954359Sroberto
371054359Sroberto/*--------------------------------------------------
371154359Sroberto * event handling - note that nominal events will also be posted
3712182007Sroberto * keep track of state dwelling times
371354359Sroberto */
371454359Srobertostatic void
371554359Srobertoparse_event(
371654359Sroberto	struct parseunit *parse,
371754359Sroberto	int event
371854359Sroberto	)
371954359Sroberto{
372054359Sroberto	if (parse->generic->currentstatus != (u_char) event)
372154359Sroberto	{
372254359Sroberto		parse->statetime[parse->generic->currentstatus] += current_time - parse->lastchange;
372354359Sroberto		parse->lastchange              = current_time;
372454359Sroberto
372554359Sroberto		if (parse->parse_type->cl_event)
372654359Sroberto		    parse->parse_type->cl_event(parse, event);
3727290000Sglebius
3728182007Sroberto		if (event == CEVNT_NOMINAL)
372954359Sroberto		{
373054359Sroberto			NLOG(NLOG_CLOCKSTATUS)
373154359Sroberto				msyslog(LOG_INFO, "PARSE receiver #%d: SYNCHRONIZED",
373254359Sroberto					CLK_UNIT(parse->peer));
373354359Sroberto		}
373454359Sroberto
3735182007Sroberto		refclock_report(parse->peer, event);
373654359Sroberto	}
373754359Sroberto}
373854359Sroberto
373954359Sroberto/*--------------------------------------------------
374054359Sroberto * process a PARSE time sample
374154359Sroberto */
374254359Srobertostatic void
374354359Srobertoparse_process(
374454359Sroberto	struct parseunit *parse,
374554359Sroberto	parsetime_t      *parsetime
374654359Sroberto	)
374754359Sroberto{
374854359Sroberto	l_fp off, rectime, reftime;
374954359Sroberto	double fudge;
3750290000Sglebius
3751290000Sglebius	/* silence warning: 'off.Ul_i.Xl_i' may be used uninitialized in this function */
3752290000Sglebius	ZERO(off);
3753290000Sglebius
375454359Sroberto	/*
375554359Sroberto	 * check for changes in conversion status
375654359Sroberto	 * (only one for each new status !)
375754359Sroberto	 */
375854359Sroberto	if (((parsetime->parse_status & CVT_MASK) != CVT_OK) &&
375954359Sroberto	    ((parsetime->parse_status & CVT_MASK) != CVT_NONE) &&
3760182007Sroberto	    (parse->timedata.parse_status != parsetime->parse_status))
376154359Sroberto	{
376254359Sroberto		char buffer[400];
3763290000Sglebius
376454359Sroberto		NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */
376554359Sroberto			msyslog(LOG_WARNING, "PARSE receiver #%d: conversion status \"%s\"",
3766182007Sroberto				CLK_UNIT(parse->peer), parsestatus(parsetime->parse_status, buffer, sizeof(buffer)));
3767290000Sglebius
376854359Sroberto		if ((parsetime->parse_status & CVT_MASK) == CVT_FAIL)
376954359Sroberto		{
377054359Sroberto			/*
377154359Sroberto			 * tell more about the story - list time code
377254359Sroberto			 * there is a slight change for a race condition and
377354359Sroberto			 * the time code might be overwritten by the next packet
377454359Sroberto			 */
377554359Sroberto			parsectl_t tmpctl;
3776290000Sglebius
377754359Sroberto			if (!PARSE_GETTIMECODE(parse, &tmpctl))
377854359Sroberto			{
377954359Sroberto				ERR(ERR_INTERNAL)
378054359Sroberto					msyslog(LOG_ERR, "PARSE receiver #%d: parse_process: parse_timecode() FAILED", CLK_UNIT(parse->peer));
378154359Sroberto			}
378254359Sroberto			else
378354359Sroberto			{
378454359Sroberto				ERR(ERR_BADDATA)
3785182007Sroberto					msyslog(LOG_WARNING, "PARSE receiver #%d: FAILED TIMECODE: \"%s\" (check receiver configuration / wiring)",
378654359Sroberto						CLK_UNIT(parse->peer), mkascii(buffer, sizeof buffer, tmpctl.parsegettc.parse_buffer, (unsigned)(tmpctl.parsegettc.parse_count - 1)));
378754359Sroberto			}
3788290000Sglebius			/* copy status to show only changes in case of failures */
3789290000Sglebius			parse->timedata.parse_status = parsetime->parse_status;
379054359Sroberto		}
379154359Sroberto	}
379254359Sroberto
379354359Sroberto	/*
379454359Sroberto	 * examine status and post appropriate events
379554359Sroberto	 */
379654359Sroberto	if ((parsetime->parse_status & CVT_MASK) != CVT_OK)
379754359Sroberto	{
379854359Sroberto		/*
379954359Sroberto		 * got bad data - tell the rest of the system
380054359Sroberto		 */
380154359Sroberto		switch (parsetime->parse_status & CVT_MASK)
380254359Sroberto		{
380354359Sroberto		case CVT_NONE:
380454359Sroberto			if ((parsetime->parse_status & CVT_ADDITIONAL) &&
380554359Sroberto			    parse->parse_type->cl_message)
380654359Sroberto				parse->parse_type->cl_message(parse, parsetime);
3807182007Sroberto			/*
3808182007Sroberto			 * save PPS information that comes piggyback
3809182007Sroberto			 */
3810182007Sroberto			if (PARSE_PPS(parsetime->parse_state))
3811182007Sroberto			  {
3812182007Sroberto			    parse->timedata.parse_state |= PARSEB_PPS|PARSEB_S_PPS;
3813182007Sroberto			    parse->timedata.parse_ptime  = parsetime->parse_ptime;
3814182007Sroberto			  }
381554359Sroberto			break; 		/* well, still waiting - timeout is handled at higher levels */
3816290000Sglebius
381754359Sroberto		case CVT_FAIL:
381854359Sroberto			if (parsetime->parse_status & CVT_BADFMT)
381954359Sroberto			{
382054359Sroberto				parse_event(parse, CEVNT_BADREPLY);
382154359Sroberto			}
382254359Sroberto			else
382354359Sroberto				if (parsetime->parse_status & CVT_BADDATE)
382454359Sroberto				{
382554359Sroberto					parse_event(parse, CEVNT_BADDATE);
382654359Sroberto				}
382754359Sroberto				else
382854359Sroberto					if (parsetime->parse_status & CVT_BADTIME)
382954359Sroberto					{
383054359Sroberto						parse_event(parse, CEVNT_BADTIME);
383154359Sroberto					}
383254359Sroberto					else
383354359Sroberto					{
383454359Sroberto						parse_event(parse, CEVNT_BADREPLY); /* for the lack of something better */
383554359Sroberto					}
383654359Sroberto		}
383754359Sroberto		return;			/* skip the rest - useless */
383854359Sroberto	}
383954359Sroberto
384054359Sroberto	/*
384154359Sroberto	 * check for format changes
384254359Sroberto	 * (in case somebody has swapped clocks 8-)
384354359Sroberto	 */
384454359Sroberto	if (parse->lastformat != parsetime->parse_format)
384554359Sroberto	{
384654359Sroberto		parsectl_t tmpctl;
3847290000Sglebius
384854359Sroberto		tmpctl.parseformat.parse_format = parsetime->parse_format;
384954359Sroberto
385054359Sroberto		if (!PARSE_GETFMT(parse, &tmpctl))
385154359Sroberto		{
385254359Sroberto			ERR(ERR_INTERNAL)
385354359Sroberto				msyslog(LOG_ERR, "PARSE receiver #%d: parse_getfmt() FAILED", CLK_UNIT(parse->peer));
385454359Sroberto		}
385554359Sroberto		else
385654359Sroberto		{
385754359Sroberto			NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */
385854359Sroberto				msyslog(LOG_INFO, "PARSE receiver #%d: packet format \"%s\"",
385954359Sroberto					CLK_UNIT(parse->peer), tmpctl.parseformat.parse_buffer);
386054359Sroberto		}
386154359Sroberto		parse->lastformat = parsetime->parse_format;
386254359Sroberto	}
386354359Sroberto
386454359Sroberto	/*
386554359Sroberto	 * now, any changes ?
386654359Sroberto	 */
3867182007Sroberto	if ((parse->timedata.parse_state ^ parsetime->parse_state) &
3868182007Sroberto	    ~(unsigned)(PARSEB_PPS|PARSEB_S_PPS))
386954359Sroberto	{
387054359Sroberto		char tmp1[200];
387154359Sroberto		char tmp2[200];
387254359Sroberto		/*
3873182007Sroberto		 * something happend - except for PPS events
387454359Sroberto		 */
3875290000Sglebius
3876182007Sroberto		(void) parsestate(parsetime->parse_state, tmp1, sizeof(tmp1));
3877182007Sroberto		(void) parsestate(parse->timedata.parse_state, tmp2, sizeof(tmp2));
3878290000Sglebius
387954359Sroberto		NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */
388054359Sroberto			msyslog(LOG_INFO,"PARSE receiver #%d: STATE CHANGE: %s -> %s",
388154359Sroberto				CLK_UNIT(parse->peer), tmp2, tmp1);
388254359Sroberto	}
388354359Sroberto
388454359Sroberto	/*
3885182007Sroberto	 * carry on PPS information if still usable
3886182007Sroberto	 */
3887182007Sroberto	if (PARSE_PPS(parse->timedata.parse_state) && !PARSE_PPS(parsetime->parse_state))
3888182007Sroberto        {
3889182007Sroberto	        parsetime->parse_state |= PARSEB_PPS|PARSEB_S_PPS;
3890182007Sroberto		parsetime->parse_ptime  = parse->timedata.parse_ptime;
3891182007Sroberto	}
3892182007Sroberto
3893182007Sroberto	/*
389454359Sroberto	 * remember for future
389554359Sroberto	 */
3896182007Sroberto	parse->timedata = *parsetime;
389754359Sroberto
389854359Sroberto	/*
389954359Sroberto	 * check to see, whether the clock did a complete powerup or lost PZF signal
390054359Sroberto	 * and post correct events for current condition
390154359Sroberto	 */
390254359Sroberto	if (PARSE_POWERUP(parsetime->parse_state))
390354359Sroberto	{
390454359Sroberto		/*
390554359Sroberto		 * this is bad, as we have completely lost synchronisation
390654359Sroberto		 * well this is a problem with the receiver here
390754359Sroberto		 * for PARSE Meinberg DCF77 receivers the lost synchronisation
390854359Sroberto		 * is true as it is the powerup state and the time is taken
390954359Sroberto		 * from a crude real time clock chip
3910290000Sglebius		 * for the PZF/GPS series this is only partly true, as
391154359Sroberto		 * PARSE_POWERUP only means that the pseudo random
391254359Sroberto		 * phase shift sequence cannot be found. this is only
391354359Sroberto		 * bad, if we have never seen the clock in the SYNC
391454359Sroberto		 * state, where the PHASE and EPOCH are correct.
391554359Sroberto		 * for reporting events the above business does not
391654359Sroberto		 * really matter, but we can use the time code
391754359Sroberto		 * even in the POWERUP state after having seen
391854359Sroberto		 * the clock in the synchronized state (PZF class
391954359Sroberto		 * receivers) unless we have had a telegram disruption
392054359Sroberto		 * after having seen the clock in the SYNC state. we
392154359Sroberto		 * thus require having seen the clock in SYNC state
392254359Sroberto		 * *after* having missed telegrams (noresponse) from
392354359Sroberto		 * the clock. one problem remains: we might use erroneously
392454359Sroberto		 * POWERUP data if the disruption is shorter than 1 polling
392554359Sroberto		 * interval. fortunately powerdowns last usually longer than 64
392654359Sroberto		 * seconds and the receiver is at least 2 minutes in the
392754359Sroberto		 * POWERUP or NOSYNC state before switching to SYNC
3928290000Sglebius		 * for GPS receivers this can mean antenna problems and other causes.
3929290000Sglebius		 * the additional grace period can be enables by a clock
3930290000Sglebius		 * mode having the PARSE_F_POWERUPTRUST flag in cl_flag set.
393154359Sroberto		 */
393254359Sroberto		parse_event(parse, CEVNT_FAULT);
393354359Sroberto		NLOG(NLOG_CLOCKSTATUS)
393454359Sroberto			ERR(ERR_BADSTATUS)
3935290000Sglebius			msyslog(LOG_ERR,"PARSE receiver #%d: NOT SYNCHRONIZED/RECEIVER PROBLEMS",
393654359Sroberto				CLK_UNIT(parse->peer));
393754359Sroberto	}
393854359Sroberto	else
393954359Sroberto	{
394054359Sroberto		/*
394154359Sroberto		 * we have two states left
394254359Sroberto		 *
394354359Sroberto		 * SYNC:
394454359Sroberto		 *  this state means that the EPOCH (timecode) and PHASE
394554359Sroberto		 *  information has be read correctly (at least two
394654359Sroberto		 *  successive PARSE timecodes were received correctly)
394754359Sroberto		 *  this is the best possible state - full trust
394854359Sroberto		 *
394954359Sroberto		 * NOSYNC:
395054359Sroberto		 *  The clock should be on phase with respect to the second
395154359Sroberto		 *  signal, but the timecode has not been received correctly within
395254359Sroberto		 *  at least the last two minutes. this is a sort of half baked state
395354359Sroberto		 *  for PARSE Meinberg DCF77 clocks this is bad news (clock running
395454359Sroberto		 *  without timecode confirmation)
395554359Sroberto		 *  PZF 535 has also no time confirmation, but the phase should be
395654359Sroberto		 *  very precise as the PZF signal can be decoded
395754359Sroberto		 */
395854359Sroberto
395954359Sroberto		if (PARSE_SYNC(parsetime->parse_state))
396054359Sroberto		{
396154359Sroberto			/*
396254359Sroberto			 * currently completely synchronized - best possible state
396354359Sroberto			 */
396454359Sroberto			parse->lastsync = current_time;
396554359Sroberto			clear_err(parse, ERR_BADSTATUS);
396654359Sroberto		}
396754359Sroberto		else
396854359Sroberto		{
396954359Sroberto			/*
397054359Sroberto			 * we have had some problems receiving the time code
397154359Sroberto			 */
397254359Sroberto			parse_event(parse, CEVNT_PROP);
397354359Sroberto			NLOG(NLOG_CLOCKSTATUS)
397454359Sroberto				ERR(ERR_BADSTATUS)
397554359Sroberto				msyslog(LOG_ERR,"PARSE receiver #%d: TIMECODE NOT CONFIRMED",
397654359Sroberto					CLK_UNIT(parse->peer));
397754359Sroberto		}
397854359Sroberto	}
397954359Sroberto
398054359Sroberto	fudge = parse->generic->fudgetime1; /* standard RS232 Fudgefactor */
3981290000Sglebius
398254359Sroberto	if (PARSE_TIMECODE(parsetime->parse_state))
398354359Sroberto	{
398454359Sroberto		rectime = parsetime->parse_stime.fp;
398554359Sroberto		off = reftime = parsetime->parse_time.fp;
3986290000Sglebius
398754359Sroberto		L_SUB(&off, &rectime); /* prepare for PPS adjustments logic */
398854359Sroberto
398954359Sroberto#ifdef DEBUG
399054359Sroberto		if (debug > 3)
399154359Sroberto			printf("PARSE receiver #%d: Reftime %s, Recvtime %s - initial offset %s\n",
399254359Sroberto			       CLK_UNIT(parse->peer),
399354359Sroberto			       prettydate(&reftime),
399454359Sroberto			       prettydate(&rectime),
399554359Sroberto			       lfptoa(&off,6));
399654359Sroberto#endif
399754359Sroberto	}
399854359Sroberto
399954359Sroberto	if (PARSE_PPS(parsetime->parse_state) && CLK_PPS(parse->peer))
400054359Sroberto	{
400154359Sroberto		l_fp offset;
4002182007Sroberto		double ppsphaseadjust = parse->ppsphaseadjust;
400354359Sroberto
4004182007Sroberto#ifdef HAVE_PPSAPI
400554359Sroberto		/*
4006182007Sroberto		 * set fudge = 0.0 if already included in PPS time stamps
4007182007Sroberto		 */
4008290000Sglebius		if (parse->atom.pps_params.mode & (PPS_OFFSETCLEAR|PPS_OFFSETASSERT))
4009182007Sroberto		        {
4010182007Sroberto			        ppsphaseadjust = 0.0;
4011182007Sroberto			}
4012182007Sroberto#endif
4013182007Sroberto
4014182007Sroberto		/*
401554359Sroberto		 * we have a PPS signal - much better than the RS232 stuff (we hope)
401654359Sroberto		 */
401754359Sroberto		offset = parsetime->parse_ptime.fp;
401854359Sroberto
401954359Sroberto#ifdef DEBUG
402054359Sroberto		if (debug > 3)
402154359Sroberto			printf("PARSE receiver #%d: PPStime %s\n",
402254359Sroberto				CLK_UNIT(parse->peer),
402354359Sroberto				prettydate(&offset));
402454359Sroberto#endif
402554359Sroberto		if (PARSE_TIMECODE(parsetime->parse_state))
402654359Sroberto		{
4027290000Sglebius			if (M_ISGEQ(off.l_i, off.l_uf, -1, 0x80000000) &&
4028290000Sglebius			    M_ISGEQ(0, 0x7fffffff, off.l_i, off.l_uf))
402954359Sroberto			{
4030182007Sroberto				fudge = ppsphaseadjust; /* pick PPS fudge factor */
4031290000Sglebius
403254359Sroberto				/*
403354359Sroberto				 * RS232 offsets within [-0.5..0.5[ - take PPS offsets
403454359Sroberto				 */
403554359Sroberto
403654359Sroberto				if (parse->parse_type->cl_flags & PARSE_F_PPSONSECOND)
403754359Sroberto				{
403854359Sroberto					reftime = off = offset;
4039290000Sglebius					if (reftime.l_uf & 0x80000000)
404054359Sroberto						reftime.l_ui++;
404154359Sroberto					reftime.l_uf = 0;
404256746Sroberto
4043290000Sglebius
404454359Sroberto					/*
404554359Sroberto					 * implied on second offset
404654359Sroberto					 */
404754359Sroberto					off.l_uf = ~off.l_uf; /* map [0.5..1[ -> [-0.5..0[ */
4048290000Sglebius					off.l_i = (off.l_uf & 0x80000000) ? -1 : 0; /* sign extend */
404954359Sroberto				}
405054359Sroberto				else
405154359Sroberto				{
405254359Sroberto					/*
405354359Sroberto					 * time code describes pulse
405454359Sroberto					 */
405554359Sroberto					reftime = off = parsetime->parse_time.fp;
405654359Sroberto
405754359Sroberto					L_SUB(&off, &offset); /* true offset */
405854359Sroberto				}
405954359Sroberto			}
406054359Sroberto			/*
406154359Sroberto			 * take RS232 offset when PPS when out of bounds
406254359Sroberto			 */
406354359Sroberto		}
406454359Sroberto		else
406554359Sroberto		{
4066182007Sroberto			fudge = ppsphaseadjust; /* pick PPS fudge factor */
406754359Sroberto			/*
406854359Sroberto			 * Well, no time code to guide us - assume on second pulse
406954359Sroberto			 * and pray, that we are within [-0.5..0.5[
407054359Sroberto			 */
407154359Sroberto			off = offset;
407254359Sroberto			reftime = offset;
4073290000Sglebius			if (reftime.l_uf & 0x80000000)
407454359Sroberto				reftime.l_ui++;
407554359Sroberto			reftime.l_uf = 0;
407654359Sroberto			/*
407754359Sroberto			 * implied on second offset
407854359Sroberto			 */
407954359Sroberto			off.l_uf = ~off.l_uf; /* map [0.5..1[ -> [-0.5..0[ */
4080290000Sglebius			off.l_i = (off.l_uf & 0x80000000) ? -1 : 0; /* sign extend */
408154359Sroberto		}
408254359Sroberto	}
408354359Sroberto	else
408454359Sroberto	{
408554359Sroberto		if (!PARSE_TIMECODE(parsetime->parse_state))
408654359Sroberto		{
408754359Sroberto			/*
408854359Sroberto			 * Well, no PPS, no TIMECODE, no more work ...
408954359Sroberto			 */
409054359Sroberto			if ((parsetime->parse_status & CVT_ADDITIONAL) &&
409154359Sroberto			    parse->parse_type->cl_message)
409254359Sroberto				parse->parse_type->cl_message(parse, parsetime);
409354359Sroberto			return;
409454359Sroberto		}
409554359Sroberto	}
409654359Sroberto
409754359Sroberto#ifdef DEBUG
409854359Sroberto	if (debug > 3)
409954359Sroberto		printf("PARSE receiver #%d: Reftime %s, Recvtime %s - final offset %s\n",
410054359Sroberto			CLK_UNIT(parse->peer),
410154359Sroberto			prettydate(&reftime),
410254359Sroberto			prettydate(&rectime),
410354359Sroberto			lfptoa(&off,6));
410454359Sroberto#endif
410554359Sroberto
410654359Sroberto
410754359Sroberto	rectime = reftime;
410854359Sroberto	L_SUB(&rectime, &off);	/* just to keep the ntp interface happy */
4109290000Sglebius
411054359Sroberto#ifdef DEBUG
411154359Sroberto	if (debug > 3)
411254359Sroberto		printf("PARSE receiver #%d: calculated Reftime %s, Recvtime %s\n",
411354359Sroberto			CLK_UNIT(parse->peer),
411454359Sroberto			prettydate(&reftime),
411554359Sroberto			prettydate(&rectime));
411654359Sroberto#endif
411754359Sroberto
411854359Sroberto	if ((parsetime->parse_status & CVT_ADDITIONAL) &&
411954359Sroberto	    parse->parse_type->cl_message)
412054359Sroberto		parse->parse_type->cl_message(parse, parsetime);
412154359Sroberto
412254359Sroberto	if (PARSE_SYNC(parsetime->parse_state))
412354359Sroberto	{
412454359Sroberto		/*
412554359Sroberto		 * log OK status
412654359Sroberto		 */
412754359Sroberto		parse_event(parse, CEVNT_NOMINAL);
412854359Sroberto	}
412954359Sroberto
413054359Sroberto	clear_err(parse, ERR_BADIO);
413154359Sroberto	clear_err(parse, ERR_BADDATA);
413254359Sroberto	clear_err(parse, ERR_NODATA);
413354359Sroberto	clear_err(parse, ERR_INTERNAL);
4134290000Sglebius
413554359Sroberto	/*
413654359Sroberto	 * and now stick it into the clock machine
413754359Sroberto	 * samples are only valid iff lastsync is not too old and
413854359Sroberto	 * we have seen the clock in sync at least once
413954359Sroberto	 * after the last time we didn't see an expected data telegram
4140182007Sroberto	 * at startup being not in sync is also bad just like
4141290000Sglebius	 * POWERUP state unless PARSE_F_POWERUPTRUST is set
414254359Sroberto	 * see the clock states section above for more reasoning
414354359Sroberto	 */
4144290000Sglebius	if (((current_time - parse->lastsync) > parse->maxunsync)           ||
4145290000Sglebius	    (parse->lastsync < parse->lastmissed)                           ||
4146182007Sroberto	    ((parse->lastsync == 0) && !PARSE_SYNC(parsetime->parse_state)) ||
4147290000Sglebius	    (((parse->parse_type->cl_flags & PARSE_F_POWERUPTRUST) == 0) &&
4148290000Sglebius	     PARSE_POWERUP(parsetime->parse_state)))
414954359Sroberto	{
415054359Sroberto		parse->generic->leap = LEAP_NOTINSYNC;
4151182007Sroberto		parse->lastsync = 0;	/* wait for full sync again */
415254359Sroberto	}
415354359Sroberto	else
415454359Sroberto	{
415554359Sroberto		if (PARSE_LEAPADD(parsetime->parse_state))
415654359Sroberto		{
415754359Sroberto			/*
415854359Sroberto			 * we pick this state also for time code that pass leap warnings
415954359Sroberto			 * without direction information (as earth is currently slowing
416054359Sroberto			 * down).
416154359Sroberto			 */
416254359Sroberto			parse->generic->leap = (parse->flags & PARSE_LEAP_DELETE) ? LEAP_DELSECOND : LEAP_ADDSECOND;
416354359Sroberto		}
416454359Sroberto		else
416554359Sroberto		    if (PARSE_LEAPDEL(parsetime->parse_state))
416654359Sroberto		    {
416754359Sroberto			    parse->generic->leap = LEAP_DELSECOND;
416854359Sroberto		    }
416954359Sroberto		    else
417054359Sroberto		    {
417154359Sroberto			    parse->generic->leap = LEAP_NOWARNING;
417254359Sroberto		    }
417354359Sroberto	}
4174182007Sroberto
4175182007Sroberto	if (parse->generic->leap != LEAP_NOTINSYNC)
4176182007Sroberto	{
4177182007Sroberto	        /*
4178182007Sroberto		 * only good/trusted samples are interesting
4179182007Sroberto		 */
4180182007Sroberto#ifdef DEBUG
4181290000Sglebius	        if (debug > 2)
4182290000Sglebius			{
4183290000Sglebius				       printf("PARSE receiver #%d: refclock_process_offset(reftime=%s, rectime=%s, Fudge=%f)\n",
4184182007Sroberto				       CLK_UNIT(parse->peer),
4185182007Sroberto				       prettydate(&reftime),
4186182007Sroberto				       prettydate(&rectime),
4187182007Sroberto				       fudge);
4188182007Sroberto			}
4189182007Sroberto#endif
4190182007Sroberto		parse->generic->lastref = reftime;
4191290000Sglebius
4192182007Sroberto		refclock_process_offset(parse->generic, reftime, rectime, fudge);
4193182007Sroberto
4194290000Sglebius#ifdef HAVE_PPSAPI
4195182007Sroberto		/*
4196182007Sroberto		 * pass PPS information on to PPS clock
4197182007Sroberto		 */
4198182007Sroberto		if (PARSE_PPS(parsetime->parse_state) && CLK_PPS(parse->peer))
4199290000Sglebius			{
4200290000Sglebius				parse->peer->flags |= (FLAG_PPS | FLAG_TSTAMP_PPS);
4201182007Sroberto				parse_hardpps(parse, PARSE_HARDPPS_ENABLE);
4202182007Sroberto			}
4203290000Sglebius#endif
4204182007Sroberto	} else {
4205290000Sglebius		parse_hardpps(parse, PARSE_HARDPPS_DISABLE);
4206290000Sglebius		parse->peer->flags &= ~(FLAG_PPS | FLAG_TSTAMP_PPS);
4207182007Sroberto	}
4208182007Sroberto
420954359Sroberto	/*
4210290000Sglebius	 * ready, unless the machine wants a sample or
4211182007Sroberto	 * we are in fast startup mode (peer->dist > MAXDISTANCE)
421254359Sroberto	 */
4213182007Sroberto	if (!parse->pollneeddata && parse->peer->disp <= MAXDISTANCE)
421454359Sroberto	    return;
421554359Sroberto
421654359Sroberto	parse->pollneeddata = 0;
421754359Sroberto
4218182007Sroberto	parse->timedata.parse_state &= ~(unsigned)(PARSEB_PPS|PARSEB_S_PPS);
4219182007Sroberto
422054359Sroberto	refclock_receive(parse->peer);
422154359Sroberto}
4222290000Sglebius
422354359Sroberto/**===========================================================================
422454359Sroberto ** special code for special clocks
422554359Sroberto **/
422654359Sroberto
422754359Srobertostatic void
422854359Srobertomk_utcinfo(
4229290000Sglebius	   char *t,  // pointer to the output string buffer
423054359Sroberto	   int wnt,
423154359Sroberto	   int wnlsf,
423254359Sroberto	   int dn,
423354359Sroberto	   int dtls,
4234182007Sroberto	   int dtlsf,
4235290000Sglebius	   int size  // size of the output string buffer
423654359Sroberto	   )
423754359Sroberto{
4238290000Sglebius	/*
4239290000Sglebius	 * The week number transmitted by the GPS satellites for the leap date
4240290000Sglebius	 * is truncated to 8 bits only. If the nearest leap second date is off
4241290000Sglebius	 * the current date by more than +/- 128 weeks then conversion to a
4242290000Sglebius	 * calendar date is ambiguous. On the other hand, if a leap second is
4243290000Sglebius	 * currently being announced (i.e. dtlsf != dtls) then the week number
4244290000Sglebius	 * wnlsf is close enough, and we can unambiguously determine the date
4245290000Sglebius	 * for which the leap second is scheduled.
4246290000Sglebius	 */
4247290000Sglebius	if ( dtlsf != dtls )
4248290000Sglebius	{
4249290000Sglebius		time_t t_ls;
4250290000Sglebius		struct tm *tm;
4251290000Sglebius		int n = 0;
4252290000Sglebius
4253290000Sglebius		if (wnlsf < GPSWRAP)
4254290000Sglebius			wnlsf += GPSWEEKS;
4255290000Sglebius
4256290000Sglebius		if (wnt < GPSWRAP)
4257290000Sglebius			wnt += GPSWEEKS;
4258290000Sglebius
4259290000Sglebius		t_ls = (time_t) wnlsf * SECSPERWEEK
4260290000Sglebius			+ (time_t) dn * SECSPERDAY
4261290000Sglebius			+ GPS_SEC_BIAS - 1;
4262290000Sglebius
4263290000Sglebius		tm = gmtime( &t_ls );
4264290000Sglebius		if (tm == NULL)  // gmtime() failed
4265290000Sglebius		{
4266290000Sglebius			snprintf( t, size, "** (gmtime() failed in mk_utcinfo())" );
4267290000Sglebius			return;
4268290000Sglebius		}
4269290000Sglebius
4270290000Sglebius		n += snprintf( t, size, "UTC offset transition from %is to %is due to leap second %s",
4271290000Sglebius				dtls, dtlsf, ( dtls < dtlsf ) ? "insertion" : "deletion" );
4272290000Sglebius		n += snprintf( t + n, size - n, " at UTC midnight at the end of %s, %04i-%02i-%02i",
4273290000Sglebius				daynames[tm->tm_wday], tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday );
4274290000Sglebius	}
4275290000Sglebius	else
4276290000Sglebius		snprintf( t, size, "UTC offset parameter: %is, no leap second announced.\n", dtls );
4277290000Sglebius
427854359Sroberto}
427954359Sroberto
428054359Sroberto#ifdef CLOCK_MEINBERG
428154359Sroberto/**===========================================================================
4282290000Sglebius ** Meinberg GPS receiver support
428354359Sroberto **/
428454359Sroberto
428554359Sroberto/*------------------------------------------------------------
4286290000Sglebius * gps16x_message - process messages from Meinberg GPS receiver
428754359Sroberto */
428854359Srobertostatic void
428954359Srobertogps16x_message(
429054359Sroberto	       struct parseunit *parse,
429154359Sroberto	       parsetime_t      *parsetime
429254359Sroberto	       )
429354359Sroberto{
4294182007Sroberto	if (parse->timedata.parse_msglen && parsetime->parse_msg[0] == SOH)
429554359Sroberto	{
429654359Sroberto		GPS_MSG_HDR header;
429754359Sroberto		unsigned char *bufp = (unsigned char *)parsetime->parse_msg + 1;
4298290000Sglebius
429954359Sroberto#ifdef DEBUG
430054359Sroberto		if (debug > 2)
430154359Sroberto		{
430254359Sroberto			char msgbuffer[600];
4303290000Sglebius
430454359Sroberto			mkreadable(msgbuffer, sizeof(msgbuffer), (char *)parsetime->parse_msg, parsetime->parse_msglen, 1);
430554359Sroberto			printf("PARSE receiver #%d: received message (%d bytes) >%s<\n",
430654359Sroberto				CLK_UNIT(parse->peer),
430754359Sroberto				parsetime->parse_msglen,
430854359Sroberto				msgbuffer);
430954359Sroberto		}
431054359Sroberto#endif
431154359Sroberto		get_mbg_header(&bufp, &header);
4312290000Sglebius		if (header.hdr_csum == mbg_csum(parsetime->parse_msg + 1, 6) &&
4313290000Sglebius		    (header.len == 0 ||
4314290000Sglebius		     (header.len < sizeof(parsetime->parse_msg) &&
4315290000Sglebius		      header.data_csum == mbg_csum(bufp, header.len))))
431654359Sroberto		{
431754359Sroberto			/*
431854359Sroberto			 * clean message
431954359Sroberto			 */
4320290000Sglebius			switch (header.cmd)
432154359Sroberto			{
432254359Sroberto			case GPS_SW_REV:
432354359Sroberto				{
432454359Sroberto					char buffer[64];
432554359Sroberto					SW_REV gps_sw_rev;
4326290000Sglebius
432754359Sroberto					get_mbg_sw_rev(&bufp, &gps_sw_rev);
4328182007Sroberto					snprintf(buffer, sizeof(buffer), "meinberg_gps_version=\"%x.%02x%s%s\"",
432954359Sroberto						(gps_sw_rev.code >> 8) & 0xFF,
433054359Sroberto						gps_sw_rev.code & 0xFF,
433154359Sroberto						gps_sw_rev.name[0] ? " " : "",
433254359Sroberto						gps_sw_rev.name);
4333182007Sroberto					set_var(&parse->kv, buffer, strlen(buffer)+1, RO|DEF);
433454359Sroberto				}
433554359Sroberto			break;
433654359Sroberto
4337290000Sglebius			case GPS_BVAR_STAT:
433854359Sroberto				{
433954359Sroberto					static struct state
434054359Sroberto					{
4341290000Sglebius						BVAR_STAT flag; /* status flag */
4342290000Sglebius						const char *string; /* bit name */
434354359Sroberto					} states[] =
434454359Sroberto					  {
4345290000Sglebius						  { BVAR_CFGH_INVALID,     "Configuration/Health" },
4346290000Sglebius						  { BVAR_ALM_NOT_COMPLETE, "Almanachs" },
4347290000Sglebius						  { BVAR_UTC_INVALID,      "UTC Correction" },
4348290000Sglebius						  { BVAR_IONO_INVALID,     "Ionospheric Correction" },
4349290000Sglebius						  { BVAR_RCVR_POS_INVALID, "Receiver Position" },
4350290000Sglebius						  { 0, "" }
435154359Sroberto					  };
4352290000Sglebius					BVAR_STAT status;
435354359Sroberto					struct state *s = states;
435454359Sroberto					char buffer[512];
435554359Sroberto					char *p, *b;
4356290000Sglebius
4357290000Sglebius					status = (BVAR_STAT) get_lsb_short(&bufp);
4358290000Sglebius					p = b = buffer;
4359290000Sglebius					p = ap(buffer, sizeof(buffer), p,
4360290000Sglebius					    "meinberg_gps_status=\"[0x%04x] ",
4361290000Sglebius					    status);
4362290000Sglebius
436354359Sroberto					if (status)
436454359Sroberto					{
4365290000Sglebius						p = ap(buffer, sizeof(buffer), p, "incomplete buffered data: ");
4366290000Sglebius						b = p;
436754359Sroberto						while (s->flag)
436854359Sroberto						{
436954359Sroberto							if (status & s->flag)
437054359Sroberto							{
437154359Sroberto								if (p != b)
437254359Sroberto								{
4373290000Sglebius									p = ap(buffer, sizeof(buffer), p, ", ");
437454359Sroberto								}
4375290000Sglebius
4376290000Sglebius								p = ap(buffer, sizeof(buffer), p, "%s", (const char *)s->string);
437754359Sroberto							}
437854359Sroberto							s++;
437954359Sroberto						}
4380290000Sglebius						p = ap(buffer, sizeof(buffer), p, "\"");
438154359Sroberto					}
438254359Sroberto					else
438354359Sroberto					{
4384290000Sglebius						p = ap(buffer, sizeof(buffer), p, "<all buffered data complete>\"");
438554359Sroberto					}
4386290000Sglebius
4387182007Sroberto					set_var(&parse->kv, buffer, strlen(buffer)+1, RO|DEF);
438854359Sroberto				}
438954359Sroberto			break;
439054359Sroberto
439154359Sroberto			case GPS_POS_XYZ:
439254359Sroberto				{
439354359Sroberto					XYZ xyz;
439454359Sroberto					char buffer[256];
4395290000Sglebius
439654359Sroberto					get_mbg_xyz(&bufp, xyz);
4397182007Sroberto					snprintf(buffer, sizeof(buffer), "gps_position(XYZ)=\"%s m, %s m, %s m\"",
439854359Sroberto						mfptoa(xyz[XP].l_ui, xyz[XP].l_uf, 1),
439954359Sroberto						mfptoa(xyz[YP].l_ui, xyz[YP].l_uf, 1),
440054359Sroberto						mfptoa(xyz[ZP].l_ui, xyz[ZP].l_uf, 1));
4401290000Sglebius
440254359Sroberto					set_var(&parse->kv, buffer, sizeof(buffer), RO|DEF);
440354359Sroberto				}
440454359Sroberto			break;
4405290000Sglebius
440654359Sroberto			case GPS_POS_LLA:
440754359Sroberto				{
440854359Sroberto					LLA lla;
440954359Sroberto					char buffer[256];
4410290000Sglebius
441154359Sroberto					get_mbg_lla(&bufp, lla);
4412290000Sglebius
4413182007Sroberto					snprintf(buffer, sizeof(buffer), "gps_position(LLA)=\"%s deg, %s deg, %s m\"",
441454359Sroberto						mfptoa(lla[LAT].l_ui, lla[LAT].l_uf, 4),
4415290000Sglebius						mfptoa(lla[LON].l_ui, lla[LON].l_uf, 4),
441654359Sroberto						mfptoa(lla[ALT].l_ui, lla[ALT].l_uf, 1));
4417290000Sglebius
441854359Sroberto					set_var(&parse->kv, buffer, sizeof(buffer), RO|DEF);
441954359Sroberto				}
442054359Sroberto			break;
4421290000Sglebius
442254359Sroberto			case GPS_TZDL:
442354359Sroberto				break;
4424290000Sglebius
442554359Sroberto			case GPS_PORT_PARM:
442654359Sroberto				break;
4427290000Sglebius
442854359Sroberto			case GPS_SYNTH:
442954359Sroberto				break;
4430290000Sglebius
443154359Sroberto			case GPS_ANT_INFO:
443254359Sroberto				{
443354359Sroberto					ANT_INFO antinfo;
4434182007Sroberto					char buffer[512];
4435290000Sglebius					char *p, *q;
4436290000Sglebius
443754359Sroberto					get_mbg_antinfo(&bufp, &antinfo);
4438290000Sglebius					p = buffer;
4439290000Sglebius					p = ap(buffer, sizeof(buffer), p, "meinberg_antenna_status=\"");
444054359Sroberto					switch (antinfo.status)
444154359Sroberto					{
4442290000Sglebius					case ANT_INVALID: // No other fields valid since antenna has not yet been disconnected
4443290000Sglebius						p = ap(buffer, sizeof(buffer),
4444290000Sglebius						    p, "<OK>");
444554359Sroberto						break;
4446290000Sglebius
4447290000Sglebius					case ANT_DISCONN: // Antenna is disconnected, tm_reconn and delta_t not yet set
4448290000Sglebius						q = ap(buffer, sizeof(buffer),
4449290000Sglebius						    p, "DISCONNECTED since ");
445054359Sroberto						NLOG(NLOG_CLOCKSTATUS)
445154359Sroberto							ERR(ERR_BADSTATUS)
445254359Sroberto							msyslog(LOG_ERR,"PARSE receiver #%d: ANTENNA FAILURE: %s",
445354359Sroberto								CLK_UNIT(parse->peer), p);
4454290000Sglebius
4455290000Sglebius						p = q;
4456290000Sglebius						mbg_tm_str(&p, &antinfo.tm_disconn, BUFFER_SIZE(buffer, p), 0);
445754359Sroberto						*p = '\0';
445854359Sroberto						break;
4459290000Sglebius
4460290000Sglebius					case ANT_RECONN: // Antenna had been disconnect, but receiver sync. after reconnect, so all fields valid
4461290000Sglebius						p = ap(buffer, sizeof(buffer),
4462290000Sglebius						    p, "SYNC AFTER RECONNECT on ");
4463290000Sglebius						mbg_tm_str(&p, &antinfo.tm_reconn, BUFFER_SIZE(buffer, p), 0);
4464290000Sglebius						p = ap(buffer, sizeof(buffer),
4465290000Sglebius							p, ", clock offset at reconnect %c%ld.%07ld s, disconnect time ",
446654359Sroberto							(antinfo.delta_t < 0) ? '-' : '+',
4467290000Sglebius							(long) ABS(antinfo.delta_t) / 10000,
4468290000Sglebius							(long) ABS(antinfo.delta_t) % 10000);
4469290000Sglebius						mbg_tm_str(&p, &antinfo.tm_disconn, BUFFER_SIZE(buffer, p), 0);
447054359Sroberto						*p = '\0';
447154359Sroberto						break;
4472290000Sglebius
447354359Sroberto					default:
4474290000Sglebius						p = ap(buffer, sizeof(buffer),
4475290000Sglebius						    p, "bad status 0x%04x",
4476290000Sglebius						    antinfo.status);
447754359Sroberto						break;
447854359Sroberto					}
4479290000Sglebius
4480290000Sglebius					p = ap(buffer, sizeof(buffer), p, "\"");
4481290000Sglebius
4482290000Sglebius					set_var(&parse->kv, buffer, sizeof(buffer), RO|DEF);
448354359Sroberto				}
448454359Sroberto			break;
4485290000Sglebius
448654359Sroberto			case GPS_UCAP:
448754359Sroberto				break;
4488290000Sglebius
448954359Sroberto			case GPS_CFGH:
449054359Sroberto				{
449154359Sroberto					CFGH cfgh;
4492182007Sroberto					char buffer[512];
4493182007Sroberto					char *p;
4494290000Sglebius
449554359Sroberto					get_mbg_cfgh(&bufp, &cfgh);
449654359Sroberto					if (cfgh.valid)
449754359Sroberto					{
4498290000Sglebius						const char *cp;
4499290000Sglebius						uint16_t tmp_val;
450054359Sroberto						int i;
4501290000Sglebius
450254359Sroberto						p = buffer;
4503290000Sglebius						p = ap(buffer, sizeof(buffer),
4504290000Sglebius						    p, "gps_tot_51=\"");
4505182007Sroberto						mbg_tgps_str(&p, &cfgh.tot_51, BUFFER_SIZE(buffer, p));
4506290000Sglebius						p = ap(buffer, sizeof(buffer),
4507290000Sglebius						    p, "\"");
4508290000Sglebius						set_var(&parse->kv, buffer, sizeof(buffer), RO|COND_DEF);
4509290000Sglebius
451054359Sroberto						p = buffer;
4511290000Sglebius						p = ap(buffer, sizeof(buffer),
4512290000Sglebius						    p, "gps_tot_63=\"");
4513182007Sroberto						mbg_tgps_str(&p, &cfgh.tot_63, BUFFER_SIZE(buffer, p));
4514290000Sglebius						p = ap(buffer, sizeof(buffer),
4515290000Sglebius						    p, "\"");
4516290000Sglebius						set_var(&parse->kv, buffer, sizeof(buffer), RO|COND_DEF);
4517290000Sglebius
451854359Sroberto						p = buffer;
4519290000Sglebius						p = ap(buffer, sizeof(buffer),
4520290000Sglebius						    p, "gps_t0a=\"");
4521182007Sroberto						mbg_tgps_str(&p, &cfgh.t0a, BUFFER_SIZE(buffer, p));
4522290000Sglebius						p = ap(buffer, sizeof(buffer),
4523290000Sglebius						    p, "\"");
4524290000Sglebius						set_var(&parse->kv, buffer, sizeof(buffer), RO|COND_DEF);
4525290000Sglebius
4526290000Sglebius						for (i = 0; i < N_SVNO_GPS; i++)
452754359Sroberto						{
452854359Sroberto							p = buffer;
4529290000Sglebius							p = ap(buffer, sizeof(buffer), p, "sv_info[%d]=\"PRN%d", i, i + N_SVNO_GPS);
4530290000Sglebius
4531290000Sglebius							tmp_val = cfgh.health[i];  /* a 6 bit SV health code */
4532290000Sglebius							p = ap(buffer, sizeof(buffer), p, "; health=0x%02x (", tmp_val);
4533290000Sglebius							/* "All Ones" has a special meaning" */
4534290000Sglebius							if (tmp_val == 0x3F) /* satellite is unusable or doesn't even exist */
4535290000Sglebius								cp = "SV UNAVAILABLE";
4536290000Sglebius							else {
4537290000Sglebius								/* The MSB contains a summary of the 3 MSBs of the 8 bit health code,
4538290000Sglebius								 * indicating if the data sent by the satellite is OK or not. */
4539290000Sglebius								p = ap(buffer, sizeof(buffer), p, "DATA %s, ", (tmp_val & 0x20) ? "BAD" : "OK" );
4540290000Sglebius
4541290000Sglebius								/* The 5 LSBs contain the status of the different signals sent by the satellite. */
4542290000Sglebius								switch (tmp_val & 0x1F)
4543290000Sglebius								{
4544290000Sglebius									case 0x00: cp = "SIGNAL OK";              break;
4545290000Sglebius									/* codes 0x01 through 0x1B indicate that one or more
4546290000Sglebius									 * specific signal components are weak or dead.
4547290000Sglebius									 * We don't decode this here in detail. */
4548290000Sglebius									case 0x1C: cp = "SV IS TEMP OUT";         break;
4549290000Sglebius									case 0x1D: cp = "SV WILL BE TEMP OUT";    break;
4550290000Sglebius									default:   cp = "TRANSMISSION PROBLEMS";  break;
4551290000Sglebius								}
455254359Sroberto							}
4553290000Sglebius							p = ap(buffer, sizeof(buffer), p, "%s)", cp );
4554290000Sglebius
4555290000Sglebius							tmp_val = cfgh.cfg[i];  /* a 4 bit SV configuration/type code */
4556290000Sglebius							p = ap(buffer, sizeof(buffer), p, "; cfg=0x%02x (", tmp_val);
4557290000Sglebius							switch (tmp_val & 0x7)
455854359Sroberto							{
4559290000Sglebius								case 0x00:  cp = "(reserved)";        break;
4560290000Sglebius								case 0x01:  cp = "BLOCK II/IIA/IIR";  break;
4561290000Sglebius								case 0x02:  cp = "BLOCK IIR-M";       break;
4562290000Sglebius								case 0x03:  cp = "BLOCK IIF";         break;
4563290000Sglebius								case 0x04:  cp = "BLOCK III";         break;
4564290000Sglebius								default:   cp = "unknown SV type";   break;
456554359Sroberto							}
4566290000Sglebius							p = ap(buffer, sizeof(buffer), p, "%s", cp );
4567290000Sglebius							if (tmp_val & 0x08)  /* A-S is on, P-code is encrypted */
4568290000Sglebius								p = ap( buffer, sizeof(buffer), p, ", A-S on" );
4569290000Sglebius
4570290000Sglebius							p = ap(buffer, sizeof(buffer), p, ")\"");
4571290000Sglebius							set_var(&parse->kv, buffer, sizeof(buffer), RO|COND_DEF);
457254359Sroberto						}
457354359Sroberto					}
457454359Sroberto				}
457554359Sroberto			break;
4576290000Sglebius
457754359Sroberto			case GPS_ALM:
457854359Sroberto				break;
4579290000Sglebius
458054359Sroberto			case GPS_EPH:
458154359Sroberto				break;
4582290000Sglebius
458354359Sroberto			case GPS_UTC:
458454359Sroberto				{
458554359Sroberto					UTC utc;
458654359Sroberto					char buffer[512];
458754359Sroberto					char *p;
4588290000Sglebius
458954359Sroberto					p = buffer;
4590290000Sglebius
459154359Sroberto					get_mbg_utc(&bufp, &utc);
4592290000Sglebius
459354359Sroberto					if (utc.valid)
459454359Sroberto					{
4595290000Sglebius						p = ap(buffer, sizeof(buffer), p, "gps_utc_correction=\"");
4596290000Sglebius						mk_utcinfo(p, utc.t0t.wn, utc.WNlsf, utc.DNt, utc.delta_tls, utc.delta_tlsf, BUFFER_SIZE(buffer, p));
459754359Sroberto						p += strlen(p);
4598290000Sglebius						p = ap(buffer, sizeof(buffer), p, "\"");
459954359Sroberto					}
460054359Sroberto					else
460154359Sroberto					{
4602290000Sglebius						p = ap(buffer, sizeof(buffer), p, "gps_utc_correction=\"<NO UTC DATA>\"");
460354359Sroberto					}
4604290000Sglebius					set_var(&parse->kv, buffer, sizeof(buffer), RO|DEF);
460554359Sroberto				}
460654359Sroberto			break;
4607290000Sglebius
460854359Sroberto			case GPS_IONO:
460954359Sroberto				break;
4610290000Sglebius
461154359Sroberto			case GPS_ASCII_MSG:
461254359Sroberto				{
461354359Sroberto					ASCII_MSG gps_ascii_msg;
461454359Sroberto					char buffer[128];
4615290000Sglebius
461654359Sroberto					get_mbg_ascii_msg(&bufp, &gps_ascii_msg);
4617290000Sglebius
461854359Sroberto					if (gps_ascii_msg.valid)
461954359Sroberto						{
462054359Sroberto							char buffer1[128];
462154359Sroberto							mkreadable(buffer1, sizeof(buffer1), gps_ascii_msg.s, strlen(gps_ascii_msg.s), (int)0);
4622290000Sglebius
4623182007Sroberto							snprintf(buffer, sizeof(buffer), "gps_message=\"%s\"", buffer1);
462454359Sroberto						}
462554359Sroberto					else
4626290000Sglebius						snprintf(buffer, sizeof(buffer), "gps_message=<NONE>");
4627290000Sglebius
4628290000Sglebius					set_var(&parse->kv, buffer, sizeof(buffer), RO|DEF);
462954359Sroberto				}
4630290000Sglebius
463154359Sroberto			break;
4632290000Sglebius
463354359Sroberto			default:
463454359Sroberto				break;
463554359Sroberto			}
463654359Sroberto		}
463754359Sroberto		else
463854359Sroberto		{
4639290000Sglebius			msyslog(LOG_DEBUG, "PARSE receiver #%d: gps16x_message: message checksum error: hdr_csum = 0x%x (expected 0x%x), "
4640290000Sglebius			                   "data_len = %d, data_csum = 0x%x (expected 0x%x)",
464154359Sroberto				CLK_UNIT(parse->peer),
4642290000Sglebius				header.hdr_csum, mbg_csum(parsetime->parse_msg + 1, 6),
4643290000Sglebius				header.len,
4644290000Sglebius				header.data_csum, mbg_csum(bufp, (unsigned)((header.len < sizeof(parsetime->parse_msg)) ? header.len : 0)));
464554359Sroberto		}
464654359Sroberto	}
4647290000Sglebius
464854359Sroberto	return;
464954359Sroberto}
465054359Sroberto
465154359Sroberto/*------------------------------------------------------------
465254359Sroberto * gps16x_poll - query the reciver peridically
465354359Sroberto */
465454359Srobertostatic void
465554359Srobertogps16x_poll(
465654359Sroberto	    struct peer *peer
465754359Sroberto	    )
465854359Sroberto{
4659290000Sglebius	struct parseunit *parse = peer->procptr->unitptr;
4660290000Sglebius
4661290000Sglebius	static GPS_MSG_HDR sequence[] =
466254359Sroberto	{
466354359Sroberto		{ GPS_SW_REV,          0, 0, 0 },
4664290000Sglebius		{ GPS_BVAR_STAT,       0, 0, 0 },
466554359Sroberto		{ GPS_UTC,             0, 0, 0 },
466654359Sroberto		{ GPS_ASCII_MSG,       0, 0, 0 },
466754359Sroberto		{ GPS_ANT_INFO,        0, 0, 0 },
466854359Sroberto		{ GPS_CFGH,            0, 0, 0 },
466954359Sroberto		{ GPS_POS_XYZ,         0, 0, 0 },
467054359Sroberto		{ GPS_POS_LLA,         0, 0, 0 },
467154359Sroberto		{ (unsigned short)~0,  0, 0, 0 }
467254359Sroberto	};
4673290000Sglebius
467454359Sroberto	int rtc;
467554359Sroberto	unsigned char cmd_buffer[64];
467654359Sroberto	unsigned char *outp = cmd_buffer;
467754359Sroberto	GPS_MSG_HDR *header;
4678290000Sglebius
467954359Sroberto	if (((poll_info_t *)parse->parse_type->cl_data)->rate)
468054359Sroberto	{
4681290000Sglebius		parse->peer->procptr->nextaction = current_time + ((poll_info_t *)parse->parse_type->cl_data)->rate;
468254359Sroberto	}
468354359Sroberto
4684290000Sglebius	if (sequence[parse->localstate].cmd == (unsigned short)~0)
468554359Sroberto		parse->localstate = 0;
4686290000Sglebius
468754359Sroberto	header = sequence + parse->localstate++;
4688290000Sglebius
468954359Sroberto	*outp++ = SOH;		/* start command */
4690290000Sglebius
469154359Sroberto	put_mbg_header(&outp, header);
469254359Sroberto	outp = cmd_buffer + 1;
4693290000Sglebius
4694290000Sglebius	header->hdr_csum = (short)mbg_csum(outp, 6);
469554359Sroberto	put_mbg_header(&outp, header);
4696290000Sglebius
469754359Sroberto#ifdef DEBUG
469854359Sroberto	if (debug > 2)
469954359Sroberto	{
470054359Sroberto		char buffer[128];
4701290000Sglebius
470254359Sroberto		mkreadable(buffer, sizeof(buffer), (char *)cmd_buffer, (unsigned)(outp - cmd_buffer), 1);
470354359Sroberto		printf("PARSE receiver #%d: transmitted message #%ld (%d bytes) >%s<\n",
470454359Sroberto		       CLK_UNIT(parse->peer),
470554359Sroberto		       parse->localstate - 1,
470654359Sroberto		       (int)(outp - cmd_buffer),
4707290000Sglebius		       buffer);
470854359Sroberto	}
470954359Sroberto#endif
4710290000Sglebius
4711290000Sglebius	rtc = (int) write(parse->generic->io.fd, cmd_buffer, (unsigned long)(outp - cmd_buffer));
4712290000Sglebius
471354359Sroberto	if (rtc < 0)
471454359Sroberto	{
471554359Sroberto		ERR(ERR_BADIO)
471654359Sroberto			msyslog(LOG_ERR, "PARSE receiver #%d: gps16x_poll: failed to send cmd to clock: %m", CLK_UNIT(parse->peer));
471754359Sroberto	}
471854359Sroberto	else
471954359Sroberto	if (rtc != outp - cmd_buffer)
472054359Sroberto	{
472154359Sroberto		ERR(ERR_BADIO)
472254359Sroberto			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));
472354359Sroberto	}
472454359Sroberto
472554359Sroberto	clear_err(parse, ERR_BADIO);
472654359Sroberto	return;
472754359Sroberto}
472854359Sroberto
472954359Sroberto/*--------------------------------------------------
473054359Sroberto * init routine - setup timer
473154359Sroberto */
473254359Srobertostatic int
473354359Srobertogps16x_poll_init(
473454359Sroberto	struct parseunit *parse
473554359Sroberto	)
473654359Sroberto{
473754359Sroberto	if (((poll_info_t *)parse->parse_type->cl_data)->rate)
473854359Sroberto	{
4739290000Sglebius		parse->peer->procptr->action = gps16x_poll;
474054359Sroberto		gps16x_poll(parse->peer);
474154359Sroberto	}
474254359Sroberto
474354359Sroberto	return 0;
474454359Sroberto}
474554359Sroberto
474654359Sroberto#else
474754359Srobertostatic void
474854359Srobertogps16x_message(
474954359Sroberto	       struct parseunit *parse,
475054359Sroberto	       parsetime_t      *parsetime
475154359Sroberto	       )
475254359Sroberto{}
475354359Srobertostatic int
475454359Srobertogps16x_poll_init(
475554359Sroberto	struct parseunit *parse
475654359Sroberto	)
475754359Sroberto{
475854359Sroberto	return 1;
475954359Sroberto}
476054359Sroberto#endif /* CLOCK_MEINBERG */
4761290000Sglebius
476254359Sroberto/**===========================================================================
476354359Sroberto ** clock polling support
476454359Sroberto **/
476554359Sroberto
476654359Sroberto/*--------------------------------------------------
476754359Sroberto * direct poll routine
476854359Sroberto */
476954359Srobertostatic void
477054359Srobertopoll_dpoll(
477154359Sroberto	struct parseunit *parse
477254359Sroberto	)
477354359Sroberto{
4774290000Sglebius	long rtc;
477554359Sroberto	const char *ps = ((poll_info_t *)parse->parse_type->cl_data)->string;
4776290000Sglebius	long ct = ((poll_info_t *)parse->parse_type->cl_data)->count;
477754359Sroberto
4778290000Sglebius	rtc = write(parse->generic->io.fd, ps, ct);
477954359Sroberto	if (rtc < 0)
478054359Sroberto	{
478154359Sroberto		ERR(ERR_BADIO)
478254359Sroberto			msyslog(LOG_ERR, "PARSE receiver #%d: poll_dpoll: failed to send cmd to clock: %m", CLK_UNIT(parse->peer));
478354359Sroberto	}
478454359Sroberto	else
478554359Sroberto	    if (rtc != ct)
478654359Sroberto	    {
478754359Sroberto		    ERR(ERR_BADIO)
4788290000Sglebius			    msyslog(LOG_ERR, "PARSE receiver #%d: poll_dpoll: failed to send cmd incomplete (%ld of %ld bytes sent)", CLK_UNIT(parse->peer), rtc, ct);
478954359Sroberto	    }
479054359Sroberto	clear_err(parse, ERR_BADIO);
479154359Sroberto}
479254359Sroberto
479354359Sroberto/*--------------------------------------------------
479454359Sroberto * periodic poll routine
479554359Sroberto */
479654359Srobertostatic void
479754359Srobertopoll_poll(
479854359Sroberto	struct peer *peer
479954359Sroberto	)
480054359Sroberto{
4801290000Sglebius	struct parseunit *parse = peer->procptr->unitptr;
4802290000Sglebius
480354359Sroberto	if (parse->parse_type->cl_poll)
480454359Sroberto		parse->parse_type->cl_poll(parse);
480554359Sroberto
480654359Sroberto	if (((poll_info_t *)parse->parse_type->cl_data)->rate)
480754359Sroberto	{
4808290000Sglebius		parse->peer->procptr->nextaction = current_time + ((poll_info_t *)parse->parse_type->cl_data)->rate;
480954359Sroberto	}
481054359Sroberto}
481154359Sroberto
481254359Sroberto/*--------------------------------------------------
481354359Sroberto * init routine - setup timer
481454359Sroberto */
481554359Srobertostatic int
481654359Srobertopoll_init(
481754359Sroberto	struct parseunit *parse
481854359Sroberto	)
481954359Sroberto{
482054359Sroberto	if (((poll_info_t *)parse->parse_type->cl_data)->rate)
482154359Sroberto	{
4822290000Sglebius		parse->peer->procptr->action = poll_poll;
482354359Sroberto		poll_poll(parse->peer);
482454359Sroberto	}
482554359Sroberto
482654359Sroberto	return 0;
482754359Sroberto}
4828290000Sglebius
482954359Sroberto/**===========================================================================
483054359Sroberto ** Trimble support
483154359Sroberto **/
483254359Sroberto
483354359Sroberto/*-------------------------------------------------------------
483454359Sroberto * trimble TAIP init routine - setup EOL and then do poll_init.
483554359Sroberto */
483654359Srobertostatic int
483754359Srobertotrimbletaip_init(
483854359Sroberto	struct parseunit *parse
483954359Sroberto	)
484054359Sroberto{
484154359Sroberto#ifdef HAVE_TERMIOS
484254359Sroberto	struct termios tio;
484354359Sroberto#endif
484454359Sroberto#ifdef HAVE_SYSV_TTYS
484554359Sroberto	struct termio tio;
484654359Sroberto#endif
484754359Sroberto	/*
484854359Sroberto	 * configure terminal line for trimble receiver
484954359Sroberto	 */
485054359Sroberto	if (TTY_GETATTR(parse->generic->io.fd, &tio) == -1)
485154359Sroberto	{
485254359Sroberto		msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_init: tcgetattr(fd, &tio): %m", CLK_UNIT(parse->peer));
485354359Sroberto		return 0;
485454359Sroberto	}
485554359Sroberto	else
485654359Sroberto	{
485754359Sroberto		tio.c_cc[VEOL] = TRIMBLETAIP_EOL;
4858290000Sglebius
485954359Sroberto		if (TTY_SETATTR(parse->generic->io.fd, &tio) == -1)
486054359Sroberto		{
486154359Sroberto			msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_init: tcsetattr(fd, &tio): %m", CLK_UNIT(parse->peer));
486254359Sroberto			return 0;
486354359Sroberto		}
486454359Sroberto	}
486554359Sroberto	return poll_init(parse);
486654359Sroberto}
486754359Sroberto
486854359Sroberto/*--------------------------------------------------
486954359Sroberto * trimble TAIP event routine - reset receiver upon data format trouble
487054359Sroberto */
487154359Srobertostatic const char *taipinit[] = {
487254359Sroberto	">FPV00000000<",
487354359Sroberto	">SRM;ID_FLAG=F;CS_FLAG=T;EC_FLAG=F;FR_FLAG=T;CR_FLAG=F<",
487454359Sroberto	">FTM00020001<",
487554359Sroberto	(char *)0
487654359Sroberto};
4877290000Sglebius
487854359Srobertostatic void
487954359Srobertotrimbletaip_event(
488054359Sroberto	struct parseunit *parse,
488154359Sroberto	int event
488254359Sroberto	)
488354359Sroberto{
488454359Sroberto	switch (event)
488554359Sroberto	{
488654359Sroberto	    case CEVNT_BADREPLY:	/* reset on garbled input */
488754359Sroberto	    case CEVNT_TIMEOUT:		/* reset on no input */
488854359Sroberto		    {
488954359Sroberto			    const char **iv;
489054359Sroberto
489154359Sroberto			    iv = taipinit;
489254359Sroberto			    while (*iv)
489354359Sroberto			    {
4894290000Sglebius				    int rtc = (int) write(parse->generic->io.fd, *iv, strlen(*iv));
489554359Sroberto				    if (rtc < 0)
489654359Sroberto				    {
489754359Sroberto					    msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_event: failed to send cmd to clock: %m", CLK_UNIT(parse->peer));
489854359Sroberto					    return;
489954359Sroberto				    }
490054359Sroberto				    else
490154359Sroberto				    {
4902290000Sglebius					    if (rtc != (int)strlen(*iv))
490354359Sroberto					    {
490454359Sroberto						    msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_event: failed to send cmd incomplete (%d of %d bytes sent)",
490554359Sroberto							    CLK_UNIT(parse->peer), rtc, (int)strlen(*iv));
490654359Sroberto						    return;
490754359Sroberto					    }
490854359Sroberto				    }
490954359Sroberto				    iv++;
491054359Sroberto			    }
491154359Sroberto
491254359Sroberto			    NLOG(NLOG_CLOCKINFO)
491354359Sroberto				    ERR(ERR_BADIO)
491454359Sroberto				    msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_event: RECEIVER INITIALIZED",
491554359Sroberto					    CLK_UNIT(parse->peer));
491654359Sroberto		    }
491754359Sroberto		    break;
491854359Sroberto
491954359Sroberto	    default:			/* ignore */
492054359Sroberto		break;
492154359Sroberto	}
492254359Sroberto}
492354359Sroberto
492454359Sroberto/*
492554359Sroberto * This driver supports the Trimble SVee Six Plus GPS receiver module.
492654359Sroberto * It should support other Trimble receivers which use the Trimble Standard
492754359Sroberto * Interface Protocol (see below).
492854359Sroberto *
492954359Sroberto * The module has a serial I/O port for command/data and a 1 pulse-per-second
493054359Sroberto * output, about 1 microsecond wide. The leading edge of the pulse is
493154359Sroberto * coincident with the change of the GPS second. This is the same as
493254359Sroberto * the change of the UTC second +/- ~1 microsecond. Some other clocks
493354359Sroberto * specifically use a feature in the data message as a timing reference, but
493454359Sroberto * the SVee Six Plus does not do this. In fact there is considerable jitter
493554359Sroberto * on the timing of the messages, so this driver only supports the use
493654359Sroberto * of the PPS pulse for accurate timing. Where it is determined that
493754359Sroberto * the offset is way off, when first starting up ntpd for example,
493854359Sroberto * the timing of the data stream is used until the offset becomes low enough
493956746Sroberto * (|offset| < CLOCK_MAX), at which point the pps offset is used.
494054359Sroberto *
494154359Sroberto * It can use either option for receiving PPS information - the 'ppsclock'
494254359Sroberto * stream pushed onto the serial data interface to timestamp the Carrier
494354359Sroberto * Detect interrupts, where the 1PPS connects to the CD line. This only
494454359Sroberto * works on SunOS 4.1.x currently. To select this, define PPSPPS in
494554359Sroberto * Config.local. The other option is to use a pulse-stretcher/level-converter
494654359Sroberto * to convert the PPS pulse into a RS232 start pulse & feed this into another
494754359Sroberto * tty port. To use this option, define PPSCLK in Config.local. The pps input,
494854359Sroberto * by whichever method, is handled in ntp_loopfilter.c
494954359Sroberto *
495054359Sroberto * The receiver uses a serial message protocol called Trimble Standard
495154359Sroberto * Interface Protocol (it can support others but this driver only supports
495254359Sroberto * TSIP). Messages in this protocol have the following form:
495354359Sroberto *
495454359Sroberto * <DLE><id> ... <data> ... <DLE><ETX>
495554359Sroberto *
495654359Sroberto * Any bytes within the <data> portion of value 10 hex (<DLE>) are doubled
495754359Sroberto * on transmission and compressed back to one on reception. Otherwise
495854359Sroberto * the values of data bytes can be anything. The serial interface is RS-422
495954359Sroberto * asynchronous using 9600 baud, 8 data bits with odd party (**note** 9 bits
496054359Sroberto * in total!), and 1 stop bit. The protocol supports byte, integer, single,
496154359Sroberto * and double datatypes. Integers are two bytes, sent most significant first.
496254359Sroberto * Singles are IEEE754 single precision floating point numbers (4 byte) sent
496354359Sroberto * sign & exponent first. Doubles are IEEE754 double precision floating point
496454359Sroberto * numbers (8 byte) sent sign & exponent first.
496554359Sroberto * The receiver supports a large set of messages, only a small subset of
496654359Sroberto * which are used here. From driver to receiver the following are used:
496754359Sroberto *
496854359Sroberto *  ID    Description
496954359Sroberto *
497054359Sroberto *  21    Request current time
497154359Sroberto *  22    Mode Select
497254359Sroberto *  2C    Set/Request operating parameters
497354359Sroberto *  2F    Request UTC info
497454359Sroberto *  35    Set/Request I/O options
497554359Sroberto
497654359Sroberto * From receiver to driver the following are recognised:
497754359Sroberto *
497854359Sroberto *  ID    Description
497954359Sroberto *
498054359Sroberto *  41    GPS Time
498154359Sroberto *  44    Satellite selection, PDOP, mode
498254359Sroberto *  46    Receiver health
498354359Sroberto *  4B    Machine code/status
498454359Sroberto *  4C    Report operating parameters (debug only)
498554359Sroberto *  4F    UTC correction data (used to get leap second warnings)
498654359Sroberto *  55    I/O options (debug only)
498754359Sroberto *
498854359Sroberto * All others are accepted but ignored.
498954359Sroberto *
499054359Sroberto */
499154359Sroberto
499254359Sroberto#define PI		3.1415926535898	/* lots of sig figs */
499354359Sroberto#define D2R		PI/180.0
499454359Sroberto
499554359Sroberto/*-------------------------------------------------------------------
499654359Sroberto * sendcmd, sendbyte, sendetx, sendflt, sendint implement the command
499754359Sroberto * interface to the receiver.
499854359Sroberto *
499954359Sroberto * CAVEAT: the sendflt, sendint routines are byte order dependend and
500054359Sroberto * float implementation dependend - these must be converted to portable
500154359Sroberto * versions !
500254359Sroberto *
500354359Sroberto * CURRENT LIMITATION: float implementation. This runs only on systems
500454359Sroberto * with IEEE754 floats as native floats
500554359Sroberto */
500654359Sroberto
500754359Srobertotypedef struct trimble
500854359Sroberto{
500954359Sroberto	u_long last_msg;	/* last message received */
5010182007Sroberto	u_long last_reset;	/* last time a reset was issued */
501154359Sroberto	u_char qtracking;	/* query tracking status */
501254359Sroberto	u_long ctrack;		/* current tracking set */
501354359Sroberto	u_long ltrack;		/* last tracking set */
501454359Sroberto} trimble_t;
501554359Sroberto
501654359Srobertounion uval {
501754359Sroberto	u_char  bd[8];
501854359Sroberto	int     iv;
501954359Sroberto	float   fv;
502054359Sroberto	double  dv;
502154359Sroberto};
5022290000Sglebius
502354359Srobertostruct txbuf
502454359Sroberto{
502554359Sroberto	short idx;			/* index to first unused byte */
502654359Sroberto	u_char *txt;			/* pointer to actual data buffer */
502754359Sroberto};
502854359Sroberto
5029290000Sglebiusvoid	sendcmd		(struct txbuf *buf, int c);
5030290000Sglebiusvoid	sendbyte	(struct txbuf *buf, int b);
5031290000Sglebiusvoid	sendetx		(struct txbuf *buf, struct parseunit *parse);
5032290000Sglebiusvoid	sendint		(struct txbuf *buf, int a);
5033290000Sglebiusvoid	sendflt		(struct txbuf *buf, double a);
5034290000Sglebius
503554359Srobertovoid
503654359Srobertosendcmd(
503754359Sroberto	struct txbuf *buf,
503854359Sroberto	int c
503954359Sroberto	)
504054359Sroberto{
504154359Sroberto	buf->txt[0] = DLE;
504254359Sroberto	buf->txt[1] = (u_char)c;
504354359Sroberto	buf->idx = 2;
504454359Sroberto}
504554359Sroberto
5046290000Sglebiusvoid	sendcmd		(struct txbuf *buf, int c);
5047290000Sglebiusvoid	sendbyte	(struct txbuf *buf, int b);
5048290000Sglebiusvoid	sendetx		(struct txbuf *buf, struct parseunit *parse);
5049290000Sglebiusvoid	sendint		(struct txbuf *buf, int a);
5050290000Sglebiusvoid	sendflt		(struct txbuf *buf, double a);
5051290000Sglebius
505254359Srobertovoid
505354359Srobertosendbyte(
505454359Sroberto	struct txbuf *buf,
505554359Sroberto	int b
505654359Sroberto	)
505754359Sroberto{
505854359Sroberto	if (b == DLE)
505954359Sroberto	    buf->txt[buf->idx++] = DLE;
506054359Sroberto	buf->txt[buf->idx++] = (u_char)b;
506154359Sroberto}
506254359Sroberto
506354359Srobertovoid
506454359Srobertosendetx(
506554359Sroberto	struct txbuf *buf,
506654359Sroberto	struct parseunit *parse
506754359Sroberto	)
506854359Sroberto{
506954359Sroberto	buf->txt[buf->idx++] = DLE;
507054359Sroberto	buf->txt[buf->idx++] = ETX;
507154359Sroberto
507254359Sroberto	if (write(parse->generic->io.fd, buf->txt, (unsigned long)buf->idx) != buf->idx)
507354359Sroberto	{
507454359Sroberto		ERR(ERR_BADIO)
507554359Sroberto			msyslog(LOG_ERR, "PARSE receiver #%d: sendetx: failed to send cmd to clock: %m", CLK_UNIT(parse->peer));
507654359Sroberto	}
507754359Sroberto	else
507854359Sroberto	{
507954359Sroberto#ifdef DEBUG
508054359Sroberto	  if (debug > 2)
508154359Sroberto	  {
508254359Sroberto		  char buffer[256];
5083290000Sglebius
508454359Sroberto		  mkreadable(buffer, sizeof(buffer), (char *)buf->txt, (unsigned)buf->idx, 1);
508554359Sroberto		  printf("PARSE receiver #%d: transmitted message (%d bytes) >%s<\n",
508654359Sroberto			 CLK_UNIT(parse->peer),
5087290000Sglebius			 buf->idx, buffer);
508854359Sroberto	  }
508954359Sroberto#endif
509054359Sroberto		clear_err(parse, ERR_BADIO);
509154359Sroberto	}
509254359Sroberto}
509354359Sroberto
5094290000Sglebiusvoid
509554359Srobertosendint(
509654359Sroberto	struct txbuf *buf,
509754359Sroberto	int a
509854359Sroberto	)
509954359Sroberto{
510054359Sroberto	/* send 16bit int, msbyte first */
510154359Sroberto	sendbyte(buf, (u_char)((a>>8) & 0xff));
510254359Sroberto	sendbyte(buf, (u_char)(a & 0xff));
510354359Sroberto}
510454359Sroberto
510554359Srobertovoid
510654359Srobertosendflt(
510754359Sroberto	struct txbuf *buf,
510854359Sroberto	double a
510954359Sroberto	)
511054359Sroberto{
511154359Sroberto	int i;
511254359Sroberto	union uval uval;
511354359Sroberto
5114290000Sglebius	uval.fv = (float) a;
511554359Sroberto#ifdef WORDS_BIGENDIAN
511654359Sroberto	for (i=0; i<=3; i++)
511754359Sroberto#else
511854359Sroberto	    for (i=3; i>=0; i--)
511954359Sroberto#endif
512054359Sroberto		sendbyte(buf, uval.bd[i]);
512154359Sroberto}
512254359Sroberto
512354359Sroberto#define TRIM_POS_OPT	0x13	/* output position with high precision */
512454359Sroberto#define TRIM_TIME_OPT	0x03	/* use UTC time stamps, on second */
512554359Sroberto
512654359Sroberto/*--------------------------------------------------
512754359Sroberto * trimble TSIP setup routine
512854359Sroberto */
512954359Srobertostatic int
513054359Srobertotrimbletsip_setup(
513154359Sroberto		  struct parseunit *parse,
513254359Sroberto		  const char *reason
513356746Sroberto		  )
513454359Sroberto{
513554359Sroberto	u_char buffer[256];
513654359Sroberto	struct txbuf buf;
5137182007Sroberto	trimble_t *t = parse->localdata;
513854359Sroberto
5139182007Sroberto	if (t && t->last_reset &&
5140182007Sroberto	    ((t->last_reset + TRIMBLE_RESET_HOLDOFF) > current_time)) {
5141182007Sroberto		return 1;	/* not yet */
5142182007Sroberto	}
5143182007Sroberto
5144182007Sroberto	if (t)
5145182007Sroberto		t->last_reset = current_time;
5146290000Sglebius
514754359Sroberto	buf.txt = buffer;
5148290000Sglebius
514954359Sroberto	sendcmd(&buf, CMD_CVERSION);	/* request software versions */
515056746Sroberto	sendetx(&buf, parse);
5151290000Sglebius
515254359Sroberto	sendcmd(&buf, CMD_COPERPARAM);	/* set operating parameters */
515356746Sroberto	sendbyte(&buf, 4);	/* static */
515456746Sroberto	sendflt(&buf, 5.0*D2R);	/* elevation angle mask = 10 deg XXX */
515556746Sroberto	sendflt(&buf, 4.0);	/* s/n ratio mask = 6 XXX */
515656746Sroberto	sendflt(&buf, 12.0);	/* PDOP mask = 12 */
515756746Sroberto	sendflt(&buf, 8.0);	/* PDOP switch level = 8 */
515856746Sroberto	sendetx(&buf, parse);
5159290000Sglebius
516054359Sroberto	sendcmd(&buf, CMD_CMODESEL);	/* fix mode select */
5161182007Sroberto	sendbyte(&buf, 1);	/* time transfer mode */
516256746Sroberto	sendetx(&buf, parse);
5163290000Sglebius
516454359Sroberto	sendcmd(&buf, CMD_CMESSAGE);	/* request system message */
516556746Sroberto	sendetx(&buf, parse);
5166290000Sglebius
516754359Sroberto	sendcmd(&buf, CMD_CSUPER);	/* superpacket fix */
516856746Sroberto	sendbyte(&buf, 0x2);	/* binary mode */
516956746Sroberto	sendetx(&buf, parse);
5170290000Sglebius
517154359Sroberto	sendcmd(&buf, CMD_CIOOPTIONS);	/* set I/O options */
517254359Sroberto	sendbyte(&buf, TRIM_POS_OPT);	/* position output */
517354359Sroberto	sendbyte(&buf, 0x00);	/* no velocity output */
517454359Sroberto	sendbyte(&buf, TRIM_TIME_OPT);	/* UTC, compute on seconds */
517554359Sroberto	sendbyte(&buf, 0x00);	/* no raw measurements */
517656746Sroberto	sendetx(&buf, parse);
5177290000Sglebius
517854359Sroberto	sendcmd(&buf, CMD_CUTCPARAM);	/* request UTC correction data */
517954359Sroberto	sendetx(&buf, parse);
518054359Sroberto
518154359Sroberto	NLOG(NLOG_CLOCKINFO)
518254359Sroberto		ERR(ERR_BADIO)
518354359Sroberto		msyslog(LOG_ERR, "PARSE receiver #%d: trimbletsip_setup: RECEIVER RE-INITIALIZED (%s)", CLK_UNIT(parse->peer), reason);
518454359Sroberto
518554359Sroberto	return 0;
518654359Sroberto}
518754359Sroberto
518854359Sroberto/*--------------------------------------------------
518954359Sroberto * TRIMBLE TSIP check routine
519054359Sroberto */
519154359Srobertostatic void
519254359Srobertotrimble_check(
519354359Sroberto	      struct peer *peer
519454359Sroberto	      )
519554359Sroberto{
5196290000Sglebius	struct parseunit *parse = peer->procptr->unitptr;
519754359Sroberto	trimble_t *t = parse->localdata;
519854359Sroberto	u_char buffer[256];
519954359Sroberto	struct txbuf buf;
520054359Sroberto	buf.txt = buffer;
5201290000Sglebius
520254359Sroberto	if (t)
520354359Sroberto	{
520454359Sroberto		if (current_time > t->last_msg + TRIMBLETSIP_IDLE_TIME)
520554359Sroberto			(void)trimbletsip_setup(parse, "message timeout");
520654359Sroberto	}
5207182007Sroberto
520854359Sroberto	poll_poll(parse->peer);	/* emit query string and re-arm timer */
5209290000Sglebius
5210182007Sroberto	if (t && t->qtracking)
521154359Sroberto	{
521254359Sroberto		u_long oldsats = t->ltrack & ~t->ctrack;
5213290000Sglebius
521454359Sroberto		t->qtracking = 0;
521554359Sroberto		t->ltrack = t->ctrack;
5216290000Sglebius
521754359Sroberto		if (oldsats)
521854359Sroberto		{
521954359Sroberto			int i;
5220290000Sglebius
5221182007Sroberto			for (i = 0; oldsats; i++) {
522254359Sroberto				if (oldsats & (1 << i))
522354359Sroberto					{
522454359Sroberto						sendcmd(&buf, CMD_CSTATTRACK);
522554359Sroberto						sendbyte(&buf, i+1);	/* old sat */
522654359Sroberto						sendetx(&buf, parse);
522754359Sroberto					}
5228182007Sroberto				oldsats &= ~(1 << i);
5229182007Sroberto			}
523054359Sroberto		}
5231290000Sglebius
523254359Sroberto		sendcmd(&buf, CMD_CSTATTRACK);
523354359Sroberto		sendbyte(&buf, 0x00);	/* current tracking set */
523454359Sroberto		sendetx(&buf, parse);
523554359Sroberto	}
523654359Sroberto}
523754359Sroberto
523854359Sroberto/*--------------------------------------------------
523954359Sroberto * TRIMBLE TSIP end routine
524054359Sroberto */
524154359Srobertostatic void
524254359Srobertotrimbletsip_end(
524354359Sroberto	      struct parseunit *parse
524454359Sroberto	      )
524554359Sroberto{	trimble_t *t = parse->localdata;
5246290000Sglebius
524754359Sroberto	if (t)
524854359Sroberto	{
524954359Sroberto		free(t);
5250290000Sglebius		parse->localdata = NULL;
525154359Sroberto	}
5252290000Sglebius	parse->peer->procptr->nextaction = 0;
5253290000Sglebius	parse->peer->procptr->action = NULL;
525454359Sroberto}
525554359Sroberto
525654359Sroberto/*--------------------------------------------------
525754359Sroberto * TRIMBLE TSIP init routine
525854359Sroberto */
525954359Srobertostatic int
526054359Srobertotrimbletsip_init(
526154359Sroberto	struct parseunit *parse
526254359Sroberto	)
526354359Sroberto{
526454359Sroberto#if defined(VEOL) || defined(VEOL2)
526554359Sroberto#ifdef HAVE_TERMIOS
526654359Sroberto	struct termios tio;		/* NEEDED FOR A LONG TIME ! */
526754359Sroberto#endif
526854359Sroberto#ifdef HAVE_SYSV_TTYS
526954359Sroberto	struct termio tio;		/* NEEDED FOR A LONG TIME ! */
527054359Sroberto#endif
527154359Sroberto	/*
527254359Sroberto	 * allocate local data area
527354359Sroberto	 */
527454359Sroberto	if (!parse->localdata)
527554359Sroberto	{
527654359Sroberto		trimble_t *t;
5277290000Sglebius
527854359Sroberto		t = (trimble_t *)(parse->localdata = emalloc(sizeof(trimble_t)));
5279290000Sglebius
528054359Sroberto		if (t)
528154359Sroberto		{
528254359Sroberto			memset((char *)t, 0, sizeof(trimble_t));
528354359Sroberto			t->last_msg = current_time;
528454359Sroberto		}
528554359Sroberto	}
528654359Sroberto
5287290000Sglebius	parse->peer->procptr->action     = trimble_check;
5288290000Sglebius	parse->peer->procptr->nextaction = current_time;
528954359Sroberto
529054359Sroberto	/*
529154359Sroberto	 * configure terminal line for ICANON mode with VEOL characters
529254359Sroberto	 */
529354359Sroberto	if (TTY_GETATTR(parse->generic->io.fd, &tio) == -1)
529454359Sroberto	{
529554359Sroberto		msyslog(LOG_ERR, "PARSE receiver #%d: trimbletsip_init: tcgetattr(%d, &tio): %m", CLK_UNIT(parse->peer), parse->generic->io.fd);
529654359Sroberto		return 0;
529754359Sroberto	}
529854359Sroberto	else
529954359Sroberto	{
530054359Sroberto		if ((parse_clockinfo[CLK_TYPE(parse->peer)].cl_lflag & ICANON))
530154359Sroberto		{
530254359Sroberto#ifdef VEOL
530354359Sroberto			tio.c_cc[VEOL]  = ETX;
530454359Sroberto#endif
530554359Sroberto#ifdef VEOL2
530654359Sroberto			tio.c_cc[VEOL2]  = DLE;
530754359Sroberto#endif
530856746Sroberto		}
530954359Sroberto
531054359Sroberto		if (TTY_SETATTR(parse->generic->io.fd, &tio) == -1)
531154359Sroberto		{
531254359Sroberto			msyslog(LOG_ERR, "PARSE receiver #%d: trimbletsip_init: tcsetattr(%d, &tio): %m", CLK_UNIT(parse->peer), parse->generic->io.fd);
531354359Sroberto			return 0;
531454359Sroberto		}
531554359Sroberto	}
531654359Sroberto#endif
531754359Sroberto	return trimbletsip_setup(parse, "initial startup");
531854359Sroberto}
531954359Sroberto
532054359Sroberto/*------------------------------------------------------------
532154359Sroberto * trimbletsip_event - handle Trimble events
532254359Sroberto * simple evente handler - attempt to re-initialize receiver
532354359Sroberto */
532454359Srobertostatic void
532554359Srobertotrimbletsip_event(
532654359Sroberto	struct parseunit *parse,
532754359Sroberto	int event
532854359Sroberto	)
532954359Sroberto{
533054359Sroberto	switch (event)
533154359Sroberto	{
533254359Sroberto	    case CEVNT_BADREPLY:	/* reset on garbled input */
533354359Sroberto	    case CEVNT_TIMEOUT:		/* reset on no input */
533454359Sroberto		    (void)trimbletsip_setup(parse, "event BAD_REPLY/TIMEOUT");
533554359Sroberto		    break;
533654359Sroberto
533754359Sroberto	    default:			/* ignore */
533854359Sroberto		break;
533954359Sroberto	}
534054359Sroberto}
534154359Sroberto
534254359Sroberto/*
534354359Sroberto * getflt, getint convert fields in the incoming data into the
534454359Sroberto * appropriate type of item
534554359Sroberto *
534654359Sroberto * CAVEAT: these routines are currently definitely byte order dependent
534754359Sroberto * and assume Representation(float) == IEEE754
534854359Sroberto * These functions MUST be converted to portable versions (especially
534954359Sroberto * converting the float representation into ntp_fp formats in order
535054359Sroberto * to avoid floating point operations at all!
535154359Sroberto */
535254359Sroberto
535354359Srobertostatic float
535454359Srobertogetflt(
535554359Sroberto	u_char *bp
535654359Sroberto	)
535754359Sroberto{
535854359Sroberto	union uval uval;
5359290000Sglebius
536054359Sroberto#ifdef WORDS_BIGENDIAN
536154359Sroberto	uval.bd[0] = *bp++;
536254359Sroberto	uval.bd[1] = *bp++;
536354359Sroberto	uval.bd[2] = *bp++;
536454359Sroberto	uval.bd[3] = *bp;
536554359Sroberto#else  /* ! WORDS_BIGENDIAN */
536654359Sroberto	uval.bd[3] = *bp++;
536754359Sroberto	uval.bd[2] = *bp++;
536854359Sroberto	uval.bd[1] = *bp++;
536954359Sroberto	uval.bd[0] = *bp;
537054359Sroberto#endif /* ! WORDS_BIGENDIAN */
537154359Sroberto	return uval.fv;
537254359Sroberto}
537354359Sroberto
537454359Srobertostatic double
537554359Srobertogetdbl(
537654359Sroberto	u_char *bp
537754359Sroberto	)
537854359Sroberto{
537954359Sroberto	union uval uval;
5380290000Sglebius
538154359Sroberto#ifdef WORDS_BIGENDIAN
538254359Sroberto	uval.bd[0] = *bp++;
538354359Sroberto	uval.bd[1] = *bp++;
538454359Sroberto	uval.bd[2] = *bp++;
538554359Sroberto	uval.bd[3] = *bp++;
538654359Sroberto	uval.bd[4] = *bp++;
538754359Sroberto	uval.bd[5] = *bp++;
538854359Sroberto	uval.bd[6] = *bp++;
538954359Sroberto	uval.bd[7] = *bp;
539054359Sroberto#else  /* ! WORDS_BIGENDIAN */
539154359Sroberto	uval.bd[7] = *bp++;
539254359Sroberto	uval.bd[6] = *bp++;
539354359Sroberto	uval.bd[5] = *bp++;
539454359Sroberto	uval.bd[4] = *bp++;
539554359Sroberto	uval.bd[3] = *bp++;
539654359Sroberto	uval.bd[2] = *bp++;
539754359Sroberto	uval.bd[1] = *bp++;
539854359Sroberto	uval.bd[0] = *bp;
539954359Sroberto#endif /* ! WORDS_BIGENDIAN */
540054359Sroberto	return uval.dv;
540154359Sroberto}
540254359Sroberto
540354359Srobertostatic int
540454359Srobertogetshort(
540554359Sroberto	 unsigned char *p
540654359Sroberto	 )
540754359Sroberto{
5408290000Sglebius	return (int) get_msb_short(&p);
540954359Sroberto}
541054359Sroberto
541154359Sroberto/*--------------------------------------------------
541254359Sroberto * trimbletsip_message - process trimble messages
541354359Sroberto */
541454359Sroberto#define RTOD (180.0 / 3.1415926535898)
541554359Sroberto#define mb(_X_) (buffer[2+(_X_)]) /* shortcut for buffer access */
541654359Sroberto
541754359Srobertostatic void
541854359Srobertotrimbletsip_message(
541954359Sroberto		    struct parseunit *parse,
542054359Sroberto		    parsetime_t      *parsetime
542154359Sroberto		    )
542254359Sroberto{
542354359Sroberto	unsigned char *buffer = parsetime->parse_msg;
542454359Sroberto	unsigned int   size   = parsetime->parse_msglen;
5425290000Sglebius
542654359Sroberto	if ((size < 4) ||
542754359Sroberto	    (buffer[0]      != DLE) ||
542854359Sroberto	    (buffer[size-1] != ETX) ||
542954359Sroberto	    (buffer[size-2] != DLE))
543054359Sroberto	{
543154359Sroberto#ifdef DEBUG
543254359Sroberto		if (debug > 2) {
5433290000Sglebius			size_t i;
543454359Sroberto
543554359Sroberto			printf("TRIMBLE BAD packet, size %d:\n	", size);
543654359Sroberto			for (i = 0; i < size; i++) {
543754359Sroberto				printf ("%2.2x, ", buffer[i]&0xff);
543854359Sroberto				if (i%16 == 15) printf("\n\t");
543954359Sroberto			}
544054359Sroberto			printf("\n");
544154359Sroberto		}
544254359Sroberto#endif
544354359Sroberto		return;
544454359Sroberto	}
544554359Sroberto	else
544654359Sroberto	{
5447290000Sglebius		u_short var_flag;
544854359Sroberto		trimble_t *tr = parse->localdata;
544954359Sroberto		unsigned int cmd = buffer[1];
545054359Sroberto		char pbuffer[200];
545154359Sroberto		char *t = pbuffer;
545254359Sroberto		cmd_info_t *s;
5453290000Sglebius
545454359Sroberto#ifdef DEBUG
545554359Sroberto		if (debug > 3) {
5456290000Sglebius			size_t i;
545754359Sroberto
545854359Sroberto			printf("TRIMBLE packet 0x%02x, size %d:\n	", cmd, size);
545954359Sroberto			for (i = 0; i < size; i++) {
546054359Sroberto				printf ("%2.2x, ", buffer[i]&0xff);
546154359Sroberto				if (i%16 == 15) printf("\n\t");
546254359Sroberto			}
546354359Sroberto			printf("\n");
546454359Sroberto		}
546554359Sroberto#endif
546654359Sroberto
546754359Sroberto		if (tr)
546854359Sroberto			tr->last_msg = current_time;
5469290000Sglebius
547054359Sroberto		s = trimble_convert(cmd, trimble_rcmds);
5471290000Sglebius
547254359Sroberto		if (s)
547354359Sroberto		{
5474290000Sglebius			t = ap(pbuffer, sizeof(pbuffer), t, "%s=\"", s->varname);
547554359Sroberto		}
547654359Sroberto		else
547754359Sroberto		{
5478182007Sroberto			DPRINTF(1, ("TRIMBLE UNKNOWN COMMAND 0x%02x\n", cmd));
547954359Sroberto			return;
548054359Sroberto		}
548154359Sroberto
5482290000Sglebius		var_flag = (u_short) s->varmode;
548354359Sroberto
548454359Sroberto		switch(cmd)
548554359Sroberto		{
548654359Sroberto		case CMD_RCURTIME:
5487290000Sglebius			t = ap(pbuffer, sizeof(pbuffer), t, "%f, %d, %f",
5488182007Sroberto				 getflt((unsigned char *)&mb(0)), getshort((unsigned char *)&mb(4)),
5489182007Sroberto				 getflt((unsigned char *)&mb(6)));
549054359Sroberto			break;
5491290000Sglebius
549254359Sroberto		case CMD_RBEST4:
5493290000Sglebius			t = ap(pbuffer, sizeof(pbuffer), t, "mode: ");
549454359Sroberto			switch (mb(0) & 0xF)
549554359Sroberto			{
549654359Sroberto			default:
5497290000Sglebius				t = ap(pbuffer, sizeof(pbuffer), t,
5498290000Sglebius				    "0x%x", mb(0) & 0x7);
549954359Sroberto				break;
550054359Sroberto
550154359Sroberto			case 1:
5502290000Sglebius				t = ap(pbuffer, sizeof(pbuffer), t, "0D");
550354359Sroberto				break;
5504290000Sglebius
550554359Sroberto			case 3:
5506290000Sglebius				t = ap(pbuffer, sizeof(pbuffer), t, "2D");
550754359Sroberto				break;
5508290000Sglebius
550954359Sroberto			case 4:
5510290000Sglebius				t = ap(pbuffer, sizeof(pbuffer), t, "3D");
551154359Sroberto				break;
551254359Sroberto			}
551354359Sroberto			if (mb(0) & 0x10)
5514290000Sglebius				t = ap(pbuffer, sizeof(pbuffer), t, "-MANUAL, ");
551554359Sroberto			else
5516290000Sglebius				t = ap(pbuffer, sizeof(pbuffer), t, "-AUTO, ");
5517290000Sglebius
5518290000Sglebius			t = ap(pbuffer, sizeof(pbuffer), t, "satellites %02d %02d %02d %02d, PDOP %.2f, HDOP %.2f, VDOP %.2f, TDOP %.2f",
551954359Sroberto				mb(1), mb(2), mb(3), mb(4),
552054359Sroberto				getflt((unsigned char *)&mb(5)),
552154359Sroberto				getflt((unsigned char *)&mb(9)),
552254359Sroberto				getflt((unsigned char *)&mb(13)),
552354359Sroberto				getflt((unsigned char *)&mb(17)));
552454359Sroberto
552554359Sroberto			break;
5526290000Sglebius
552754359Sroberto		case CMD_RVERSION:
5528290000Sglebius			t = ap(pbuffer, sizeof(pbuffer), t, "%d.%d (%d/%d/%d)",
552954359Sroberto				mb(0)&0xff, mb(1)&0xff, 1900+(mb(4)&0xff), mb(2)&0xff, mb(3)&0xff);
553054359Sroberto			break;
5531290000Sglebius
553254359Sroberto		case CMD_RRECVHEALTH:
553354359Sroberto		{
553454359Sroberto			static const char *msgs[] =
553554359Sroberto			{
553654359Sroberto				"Battery backup failed",
553754359Sroberto				"Signal processor error",
553854359Sroberto				"Alignment error, channel or chip 1",
553954359Sroberto				"Alignment error, channel or chip 2",
554054359Sroberto				"Antenna feed line fault",
554154359Sroberto				"Excessive ref freq. error",
554254359Sroberto				"<BIT 6>",
554354359Sroberto				"<BIT 7>"
554454359Sroberto			};
5545290000Sglebius
554654359Sroberto			int i, bits;
5547290000Sglebius
554854359Sroberto			switch (mb(0) & 0xFF)
554954359Sroberto			{
555054359Sroberto			default:
5551290000Sglebius				t = ap(pbuffer, sizeof(pbuffer), t, "illegal value 0x%02x", mb(0) & 0xFF);
555254359Sroberto				break;
555354359Sroberto			case 0x00:
5554290000Sglebius				t = ap(pbuffer, sizeof(pbuffer), t, "doing position fixes");
555554359Sroberto				break;
555654359Sroberto			case 0x01:
5557290000Sglebius				t = ap(pbuffer, sizeof(pbuffer), t, "no GPS time yet");
555854359Sroberto				break;
555954359Sroberto			case 0x03:
5560290000Sglebius				t = ap(pbuffer, sizeof(pbuffer), t, "PDOP too high");
556154359Sroberto				break;
556254359Sroberto			case 0x08:
5563290000Sglebius				t = ap(pbuffer, sizeof(pbuffer), t, "no usable satellites");
556454359Sroberto				break;
556554359Sroberto			case 0x09:
5566290000Sglebius				t = ap(pbuffer, sizeof(pbuffer), t, "only ONE usable satellite");
556754359Sroberto				break;
556854359Sroberto			case 0x0A:
5569290000Sglebius				t = ap(pbuffer, sizeof(pbuffer), t, "only TWO usable satellites");
557054359Sroberto				break;
557154359Sroberto			case 0x0B:
5572290000Sglebius				t = ap(pbuffer, sizeof(pbuffer), t, "only THREE usable satellites");
557354359Sroberto				break;
557454359Sroberto			case 0x0C:
5575290000Sglebius				t = ap(pbuffer, sizeof(pbuffer), t, "the chosen satellite is unusable");
557654359Sroberto				break;
557754359Sroberto			}
557854359Sroberto
5579290000Sglebius			bits = mb(1) & 0xFF;
558054359Sroberto
558154359Sroberto			for (i = 0; i < 8; i++)
558254359Sroberto				if (bits & (0x1<<i))
558354359Sroberto				{
5584290000Sglebius					t = ap(pbuffer, sizeof(pbuffer), t, ", %s", msgs[i]);
558554359Sroberto				}
558654359Sroberto		}
558754359Sroberto		break;
5588290000Sglebius
558954359Sroberto		case CMD_RMESSAGE:
5590182007Sroberto			mkreadable(t, (int)BUFFER_SIZE(pbuffer, t), (char *)&mb(0), (unsigned)(size - 2 - (&mb(0) - buffer)), 0);
559154359Sroberto			break;
5592290000Sglebius
559354359Sroberto		case CMD_RMACHSTAT:
559454359Sroberto		{
559554359Sroberto			static const char *msgs[] =
559654359Sroberto			{
559754359Sroberto				"Synthesizer Fault",
559854359Sroberto				"Battery Powered Time Clock Fault",
559954359Sroberto				"A-to-D Converter Fault",
560054359Sroberto				"The almanac stored in the receiver is not complete and current",
560154359Sroberto				"<BIT 4>",
560254359Sroberto				"<BIT 5",
560354359Sroberto				"<BIT 6>",
560454359Sroberto				"<BIT 7>"
560554359Sroberto			};
5606290000Sglebius
560754359Sroberto			int i, bits;
560854359Sroberto
5609290000Sglebius			t = ap(pbuffer, sizeof(pbuffer), t, "machine id 0x%02x", mb(0) & 0xFF);
561054359Sroberto			bits = mb(1) & 0xFF;
5611290000Sglebius
561254359Sroberto			for (i = 0; i < 8; i++)
561354359Sroberto				if (bits & (0x1<<i))
561454359Sroberto				{
5615290000Sglebius					t = ap(pbuffer, sizeof(pbuffer), t, ", %s", msgs[i]);
561654359Sroberto				}
561754359Sroberto
5618290000Sglebius			t = ap(pbuffer, sizeof(pbuffer), t, ", Superpackets %ssupported", (mb(2) & 0xFF) ? "" :"un" );
561954359Sroberto		}
562054359Sroberto		break;
5621290000Sglebius
562254359Sroberto		case CMD_ROPERPARAM:
5623290000Sglebius			t = ap(pbuffer, sizeof(pbuffer), t, "%2x %.1f %.1f %.1f %.1f",
562454359Sroberto				mb(0), getflt((unsigned char *)&mb(1)), getflt((unsigned char *)&mb(5)),
562554359Sroberto				getflt((unsigned char *)&mb(9)), getflt((unsigned char *)&mb(13)));
562654359Sroberto			break;
5627290000Sglebius
562854359Sroberto		case CMD_RUTCPARAM:
562954359Sroberto		{
563054359Sroberto			float t0t = getflt((unsigned char *)&mb(14));
5631290000Sglebius			short wnt = (short) getshort((unsigned char *)&mb(18));
5632290000Sglebius			short dtls = (short) getshort((unsigned char *)&mb(12));
5633290000Sglebius			short wnlsf = (short) getshort((unsigned char *)&mb(20));
5634290000Sglebius			short dn = (short) getshort((unsigned char *)&mb(22));
5635290000Sglebius			short dtlsf = (short) getshort((unsigned char *)&mb(24));
563654359Sroberto
563754359Sroberto			if ((int)t0t != 0)
5638290000Sglebius			{
5639290000Sglebius				mk_utcinfo(t, wnt, wnlsf, dn, dtls, dtlsf, BUFFER_SIZE(pbuffer, t));
5640290000Sglebius			}
564154359Sroberto			else
5642290000Sglebius			{
5643290000Sglebius			        t = ap(pbuffer, sizeof(pbuffer), t, "<NO UTC DATA>");
5644290000Sglebius			}
564554359Sroberto		}
564654359Sroberto		break;
564754359Sroberto
564854359Sroberto		case CMD_RSAT1BIAS:
5649290000Sglebius			t = ap(pbuffer, sizeof(pbuffer), t, "%.1fm %.2fm/s at %.1fs",
565054359Sroberto				getflt(&mb(0)), getflt(&mb(4)), getflt(&mb(8)));
565154359Sroberto			break;
565254359Sroberto
565354359Sroberto		case CMD_RIOOPTIONS:
565454359Sroberto		{
5655290000Sglebius			t = ap(pbuffer, sizeof(pbuffer), t, "%02x %02x %02x %02x",
565654359Sroberto				mb(0), mb(1), mb(2), mb(3));
565754359Sroberto			if (mb(0) != TRIM_POS_OPT ||
565854359Sroberto			    mb(2) != TRIM_TIME_OPT)
565954359Sroberto			{
566054359Sroberto				(void)trimbletsip_setup(parse, "bad io options");
566154359Sroberto			}
566254359Sroberto		}
566354359Sroberto		break;
5664290000Sglebius
566554359Sroberto		case CMD_RSPOSXYZ:
566654359Sroberto		{
566754359Sroberto			double x = getflt((unsigned char *)&mb(0));
566854359Sroberto			double y = getflt((unsigned char *)&mb(4));
566954359Sroberto			double z = getflt((unsigned char *)&mb(8));
567054359Sroberto			double f = getflt((unsigned char *)&mb(12));
5671290000Sglebius
567254359Sroberto			if (f > 0.0)
5673290000Sglebius			  t = ap(pbuffer, sizeof(pbuffer), t, "x= %.1fm, y= %.1fm, z= %.1fm, time_of_fix= %f sec",
567454359Sroberto				  x, y, z,
567554359Sroberto				  f);
567654359Sroberto			else
5677290000Sglebius				return;
567854359Sroberto		}
567954359Sroberto		break;
568054359Sroberto
568154359Sroberto		case CMD_RSLLAPOS:
568254359Sroberto		{
568354359Sroberto			double lat = getflt((unsigned char *)&mb(0));
568454359Sroberto			double lng = getflt((unsigned char *)&mb(4));
568554359Sroberto			double f   = getflt((unsigned char *)&mb(12));
5686290000Sglebius
568754359Sroberto			if (f > 0.0)
5688290000Sglebius			  t = ap(pbuffer, sizeof(pbuffer), t, "lat %f %c, long %f %c, alt %.2fm",
568954359Sroberto				  ((lat < 0.0) ? (-lat) : (lat))*RTOD, (lat < 0.0 ? 'S' : 'N'),
569054359Sroberto				  ((lng < 0.0) ? (-lng) : (lng))*RTOD, (lng < 0.0 ? 'W' : 'E'),
569154359Sroberto				  getflt((unsigned char *)&mb(8)));
569254359Sroberto			else
5693290000Sglebius				return;
569454359Sroberto		}
569554359Sroberto		break;
569654359Sroberto
569754359Sroberto		case CMD_RDOUBLEXYZ:
569854359Sroberto		{
569954359Sroberto			double x = getdbl((unsigned char *)&mb(0));
570054359Sroberto			double y = getdbl((unsigned char *)&mb(8));
570154359Sroberto			double z = getdbl((unsigned char *)&mb(16));
5702290000Sglebius			t = ap(pbuffer, sizeof(pbuffer), t, "x= %.1fm, y= %.1fm, z= %.1fm",
570354359Sroberto				x, y, z);
570454359Sroberto		}
570554359Sroberto		break;
5706290000Sglebius
570754359Sroberto		case CMD_RDOUBLELLA:
570854359Sroberto		{
570954359Sroberto			double lat = getdbl((unsigned char *)&mb(0));
571054359Sroberto			double lng = getdbl((unsigned char *)&mb(8));
5711290000Sglebius			t = ap(pbuffer, sizeof(pbuffer), t, "lat %f %c, lon %f %c, alt %.2fm",
571254359Sroberto				((lat < 0.0) ? (-lat) : (lat))*RTOD, (lat < 0.0 ? 'S' : 'N'),
571354359Sroberto				((lng < 0.0) ? (-lng) : (lng))*RTOD, (lng < 0.0 ? 'W' : 'E'),
571454359Sroberto				getdbl((unsigned char *)&mb(16)));
571554359Sroberto		}
571654359Sroberto		break;
571754359Sroberto
571854359Sroberto		case CMD_RALLINVIEW:
571954359Sroberto		{
572054359Sroberto			int i, sats;
5721290000Sglebius
5722290000Sglebius			t = ap(pbuffer, sizeof(pbuffer), t, "mode: ");
572354359Sroberto			switch (mb(0) & 0x7)
572454359Sroberto			{
572554359Sroberto			default:
5726290000Sglebius				t = ap(pbuffer, sizeof(pbuffer), t, "0x%x", mb(0) & 0x7);
572754359Sroberto				break;
572854359Sroberto
572954359Sroberto			case 3:
5730290000Sglebius				t = ap(pbuffer, sizeof(pbuffer), t, "2D");
573154359Sroberto				break;
5732290000Sglebius
573354359Sroberto			case 4:
5734290000Sglebius				t = ap(pbuffer, sizeof(pbuffer), t, "3D");
573554359Sroberto				break;
573654359Sroberto			}
573754359Sroberto			if (mb(0) & 0x8)
5738290000Sglebius				t = ap(pbuffer, sizeof(pbuffer), t, "-MANUAL, ");
573954359Sroberto			else
5740290000Sglebius				t = ap(pbuffer, sizeof(pbuffer), t, "-AUTO, ");
5741290000Sglebius
574254359Sroberto			sats = (mb(0)>>4) & 0xF;
5743290000Sglebius
5744290000Sglebius			t = ap(pbuffer, sizeof(pbuffer), t, "PDOP %.2f, HDOP %.2f, VDOP %.2f, TDOP %.2f, %d satellite%s in view: ",
574554359Sroberto				getflt((unsigned char *)&mb(1)),
574654359Sroberto				getflt((unsigned char *)&mb(5)),
574754359Sroberto				getflt((unsigned char *)&mb(9)),
574854359Sroberto				getflt((unsigned char *)&mb(13)),
574954359Sroberto				sats, (sats == 1) ? "" : "s");
575054359Sroberto
575154359Sroberto			for (i=0; i < sats; i++)
575254359Sroberto			{
5753290000Sglebius				t = ap(pbuffer, sizeof(pbuffer), t, "%s%02d", i ? ", " : "", mb(17+i));
575454359Sroberto				if (tr)
575554359Sroberto					tr->ctrack |= (1 << (mb(17+i)-1));
575654359Sroberto			}
575754359Sroberto
575854359Sroberto			if (tr)
5759290000Sglebius			{	/* mark for tracking status query */
576054359Sroberto				tr->qtracking = 1;
576154359Sroberto			}
576254359Sroberto		}
576354359Sroberto		break;
5764290000Sglebius
576554359Sroberto		case CMD_RSTATTRACK:
576654359Sroberto		{
5767290000Sglebius			t = ap(pbuffer, sizeof(pbuffer), t-2, "[%02d]=\"", mb(0)); /* add index to var name */
576854359Sroberto			if (getflt((unsigned char *)&mb(4)) < 0.0)
576954359Sroberto			{
5770290000Sglebius				t = ap(pbuffer, sizeof(pbuffer), t, "<NO MEASUREMENTS>");
5771290000Sglebius				var_flag &= (u_short)(~DEF);
577254359Sroberto			}
577354359Sroberto			else
5774290000Sglebius			{
5775290000Sglebius				t = ap(pbuffer, sizeof(pbuffer), t, "ch=%d, acq=%s, eph=%d, signal_level= %5.2f, elevation= %5.2f, azimuth= %6.2f",
577654359Sroberto					(mb(1) & 0xFF)>>3,
577754359Sroberto					mb(2) ? ((mb(2) == 1) ? "ACQ" : "SRCH") : "NEVER",
577854359Sroberto					mb(3),
577954359Sroberto					getflt((unsigned char *)&mb(4)),
578054359Sroberto					getflt((unsigned char *)&mb(12)) * RTOD,
578154359Sroberto					getflt((unsigned char *)&mb(16)) * RTOD);
578254359Sroberto				if (mb(20))
578354359Sroberto				{
5784290000Sglebius					var_flag &= (u_short)(~DEF);
5785290000Sglebius					t = ap(pbuffer, sizeof(pbuffer), t, ", OLD");
578654359Sroberto				}
578754359Sroberto				if (mb(22))
578854359Sroberto				{
578954359Sroberto					if (mb(22) == 1)
5790290000Sglebius						t = ap(pbuffer, sizeof(pbuffer), t, ", BAD PARITY");
579154359Sroberto					else
579254359Sroberto						if (mb(22) == 2)
5793290000Sglebius							t = ap(pbuffer, sizeof(pbuffer), t, ", BAD EPH HEALTH");
579454359Sroberto				}
579554359Sroberto				if (mb(23))
5796290000Sglebius					t = ap(pbuffer, sizeof(pbuffer), t, ", collecting data");
579754359Sroberto			}
579854359Sroberto		}
579954359Sroberto		break;
5800290000Sglebius
580154359Sroberto		default:
5802290000Sglebius			t = ap(pbuffer, sizeof(pbuffer), t, "<UNDECODED>");
580354359Sroberto			break;
580454359Sroberto		}
5805182007Sroberto
5806290000Sglebius		t = ap(pbuffer, sizeof(pbuffer), t, "\"");
580754359Sroberto		set_var(&parse->kv, pbuffer, sizeof(pbuffer), var_flag);
580854359Sroberto	}
580954359Sroberto}
581054359Sroberto
5811290000Sglebius
581254359Sroberto/**============================================================
581354359Sroberto ** RAWDCF support
581454359Sroberto **/
581554359Sroberto
581654359Sroberto/*--------------------------------------------------
581756746Sroberto * rawdcf_init_1 - set up modem lines for RAWDCF receivers
581856746Sroberto * SET DTR line
581954359Sroberto */
582054359Sroberto#if defined(TIOCMSET) && (defined(TIOCM_DTR) || defined(CIOCM_DTR))
582154359Srobertostatic int
582256746Srobertorawdcf_init_1(
582354359Sroberto	struct parseunit *parse
582454359Sroberto	)
582554359Sroberto{
582682498Sroberto	/* fixed 2000 for using with Linux by Wolfram Pienkoss <wp@bszh.de> */
582754359Sroberto	/*
582854359Sroberto	 * You can use the RS232 to supply the power for a DCF77 receiver.
582954359Sroberto	 * Here a voltage between the DTR and the RTS line is used. Unfortunately
583054359Sroberto	 * the name has changed from CIOCM_DTR to TIOCM_DTR recently.
583154359Sroberto	 */
583282498Sroberto	int sl232;
583382498Sroberto
583482498Sroberto	if (ioctl(parse->generic->io.fd, TIOCMGET, (caddr_t)&sl232) == -1)
583582498Sroberto	{
583682498Sroberto		msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_1: WARNING: ioctl(fd, TIOCMGET, [C|T]IOCM_DTR): %m", CLK_UNIT(parse->peer));
583782498Sroberto		return 0;
583882498Sroberto	}
583982498Sroberto
584054359Sroberto#ifdef TIOCM_DTR
584182498Sroberto	sl232 = (sl232 & ~TIOCM_RTS) | TIOCM_DTR;	/* turn on DTR, clear RTS for power supply */
584254359Sroberto#else
584382498Sroberto	sl232 = (sl232 & ~CIOCM_RTS) | CIOCM_DTR;	/* turn on DTR, clear RTS for power supply */
584454359Sroberto#endif
584554359Sroberto
584654359Sroberto	if (ioctl(parse->generic->io.fd, TIOCMSET, (caddr_t)&sl232) == -1)
584754359Sroberto	{
584856746Sroberto		msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_1: WARNING: ioctl(fd, TIOCMSET, [C|T]IOCM_DTR): %m", CLK_UNIT(parse->peer));
584954359Sroberto	}
585054359Sroberto	return 0;
585154359Sroberto}
585254359Sroberto#else
585354359Srobertostatic int
5854132451Srobertorawdcfdtr_init_1(
585554359Sroberto	struct parseunit *parse
585654359Sroberto	)
585754359Sroberto{
585856746Sroberto	msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_1: WARNING: OS interface incapable of setting DTR to power DCF modules", CLK_UNIT(parse->peer));
585954359Sroberto	return 0;
586054359Sroberto}
586154359Sroberto#endif  /* DTR initialisation type */
586254359Sroberto
586354359Sroberto/*--------------------------------------------------
586456746Sroberto * rawdcf_init_2 - set up modem lines for RAWDCF receivers
586556746Sroberto * CLR DTR line, SET RTS line
586654359Sroberto */
586756746Sroberto#if defined(TIOCMSET) &&  (defined(TIOCM_RTS) || defined(CIOCM_RTS))
586854359Srobertostatic int
586956746Srobertorawdcf_init_2(
587054359Sroberto	struct parseunit *parse
587154359Sroberto	)
587254359Sroberto{
587382498Sroberto	/* fixed 2000 for using with Linux by Wolfram Pienkoss <wp@bszh.de> */
587454359Sroberto	/*
587554359Sroberto	 * You can use the RS232 to supply the power for a DCF77 receiver.
587656746Sroberto	 * Here a voltage between the DTR and the RTS line is used. Unfortunately
587756746Sroberto	 * the name has changed from CIOCM_DTR to TIOCM_DTR recently.
587854359Sroberto	 */
587982498Sroberto	int sl232;
588082498Sroberto
588182498Sroberto	if (ioctl(parse->generic->io.fd, TIOCMGET, (caddr_t)&sl232) == -1)
588282498Sroberto	{
588382498Sroberto		msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_2: WARNING: ioctl(fd, TIOCMGET, [C|T]IOCM_RTS): %m", CLK_UNIT(parse->peer));
588482498Sroberto		return 0;
588582498Sroberto	}
588682498Sroberto
588754359Sroberto#ifdef TIOCM_RTS
588882498Sroberto	sl232 = (sl232 & ~TIOCM_DTR) | TIOCM_RTS;	/* turn on RTS, clear DTR for power supply */
588954359Sroberto#else
589082498Sroberto	sl232 = (sl232 & ~CIOCM_DTR) | CIOCM_RTS;	/* turn on RTS, clear DTR for power supply */
589154359Sroberto#endif
589254359Sroberto
589354359Sroberto	if (ioctl(parse->generic->io.fd, TIOCMSET, (caddr_t)&sl232) == -1)
589454359Sroberto	{
589556746Sroberto		msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_2: WARNING: ioctl(fd, TIOCMSET, [C|T]IOCM_RTS): %m", CLK_UNIT(parse->peer));
589654359Sroberto	}
589754359Sroberto	return 0;
589854359Sroberto}
589954359Sroberto#else
590054359Srobertostatic int
590156746Srobertorawdcf_init_2(
590254359Sroberto	struct parseunit *parse
590354359Sroberto	)
590454359Sroberto{
590556746Sroberto	msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_2: WARNING: OS interface incapable of setting RTS to power DCF modules", CLK_UNIT(parse->peer));
590654359Sroberto	return 0;
590754359Sroberto}
590856746Sroberto#endif  /* DTR initialisation type */
590954359Sroberto
591054359Sroberto#else	/* defined(REFCLOCK) && defined(PARSE) */
5911290000SglebiusNONEMPTY_TRANSLATION_UNIT
591254359Sroberto#endif	/* defined(REFCLOCK) && defined(PARSE) */
591354359Sroberto
591454359Sroberto/*
591554359Sroberto * History:
591654359Sroberto *
591754359Sroberto * refclock_parse.c,v
5918290000Sglebius * Revision 4.81  2009/05/01 10:15:29  kardel
5919290000Sglebius * use new refclock_ppsapi interface
5920290000Sglebius *
5921182007Sroberto * Revision 4.80  2007/08/11 12:06:29  kardel
5922182007Sroberto * update comments wrt/ to PPS
5923182007Sroberto *
5924182007Sroberto * Revision 4.79  2007/08/11 11:52:23  kardel
5925182007Sroberto * - terminate io bindings before io_closeclock() will close our file descriptor
5926182007Sroberto *
5927182007Sroberto * Revision 4.78  2006/12/22 20:08:27  kardel
5928182007Sroberto * Bug 746 (RFE): add configuration for Expert mouseCLOCK USB v2.0 as mode 19
5929182007Sroberto *
5930182007Sroberto * Revision 4.77  2006/08/05 07:44:49  kardel
5931182007Sroberto * support optionally separate PPS devices via /dev/refclockpps-{0..3}
5932182007Sroberto *
5933182007Sroberto * Revision 4.76  2006/06/22 18:40:47  kardel
5934182007Sroberto * clean up signedness (gcc 4)
5935182007Sroberto *
5936182007Sroberto * Revision 4.75  2006/06/22 16:58:10  kardel
5937182007Sroberto * Bug #632: call parse_ppsapi() in parse_ctl() when updating
5938182007Sroberto * the PPS offset. Fix sign of offset passed to kernel.
5939182007Sroberto *
5940182007Sroberto * Revision 4.74  2006/06/18 21:18:37  kardel
5941182007Sroberto * NetBSD Coverity CID 3796: possible NULL deref
5942182007Sroberto *
5943182007Sroberto * Revision 4.73  2006/05/26 14:23:46  kardel
5944182007Sroberto * cleanup of copyright info
5945182007Sroberto *
5946182007Sroberto * Revision 4.72  2006/05/26 14:19:43  kardel
5947182007Sroberto * cleanup of ioctl cruft
5948182007Sroberto *
5949182007Sroberto * Revision 4.71  2006/05/26 14:15:57  kardel
5950182007Sroberto * delay adding refclock to async refclock io after all initializations
5951182007Sroberto *
5952182007Sroberto * Revision 4.70  2006/05/25 18:20:50  kardel
5953182007Sroberto * bug #619
5954182007Sroberto * terminate parse io engine after de-registering
5955182007Sroberto * from refclock io engine
5956182007Sroberto *
5957182007Sroberto * Revision 4.69  2006/05/25 17:28:02  kardel
5958182007Sroberto * complete refclock io structure initialization *before* inserting it into the
5959182007Sroberto * refclock input machine (avoids null pointer deref) (bug #619)
5960182007Sroberto *
5961182007Sroberto * Revision 4.68  2006/05/01 17:02:51  kardel
5962182007Sroberto * copy receiver method also for newlwy created receive buffers
5963182007Sroberto *
5964182007Sroberto * Revision 4.67  2006/05/01 14:37:29  kardel
5965182007Sroberto * If an input buffer parses into more than one message do insert the
5966182007Sroberto * parsed message in a new input buffer instead of processing it
5967182007Sroberto * directly. This avoids deed complicated processing in signal
5968182007Sroberto * handling.
5969182007Sroberto *
5970182007Sroberto * Revision 4.66  2006/03/18 00:45:30  kardel
5971182007Sroberto * coverity fixes found in NetBSD coverity scan
5972182007Sroberto *
5973182007Sroberto * Revision 4.65  2006/01/26 06:08:33  kardel
5974182007Sroberto * output errno on PPS setup failure
5975182007Sroberto *
5976182007Sroberto * Revision 4.64  2005/11/09 20:44:47  kardel
5977182007Sroberto * utilize full PPS timestamp resolution from PPS API
5978182007Sroberto *
5979182007Sroberto * Revision 4.63  2005/10/07 22:10:25  kardel
5980182007Sroberto * bounded buffer implementation
5981182007Sroberto *
5982182007Sroberto * Revision 4.62.2.2  2005/09/25 10:20:16  kardel
5983182007Sroberto * avoid unexpected buffer overflows due to sprintf("%f") on strange floats:
5984182007Sroberto * replace almost all str* and *printf functions be their buffer bounded
5985182007Sroberto * counterparts
5986182007Sroberto *
5987182007Sroberto * Revision 4.62.2.1  2005/08/27 16:19:27  kardel
5988182007Sroberto * limit re-set rate of trimble clocks
5989182007Sroberto *
5990182007Sroberto * Revision 4.62  2005/08/06 17:40:00  kardel
5991182007Sroberto * cleanup size handling wrt/ to buffer boundaries
5992182007Sroberto *
5993182007Sroberto * Revision 4.61  2005/07/27 21:16:19  kardel
5994182007Sroberto * fix a long (> 11 years) misconfiguration wrt/ Meinberg cflag factory
5995182007Sroberto * default setup. CSTOPB was missing for the 7E2 default data format of
5996182007Sroberto * the DCF77 clocks.
5997182007Sroberto *
5998182007Sroberto * Revision 4.60  2005/07/17 21:14:44  kardel
5999182007Sroberto * change contents of version string to include the RCS/CVS Id
6000182007Sroberto *
6001182007Sroberto * Revision 4.59  2005/07/06 06:56:38  kardel
6002182007Sroberto * syntax error
6003182007Sroberto *
6004182007Sroberto * Revision 4.58  2005/07/04 13:10:40  kardel
6005182007Sroberto * fix bug 455: tripping over NULL pointer on cleanup
6006182007Sroberto * fix shadow storage logic for ppsphaseadjust and trustime wrt/ time2
6007182007Sroberto * fix compiler warnings for some platforms wrt/ printf formatstrings and
6008182007Sroberto *     varying structure element sizes
6009182007Sroberto * reorder assignment in binding to avoid tripping over NULL pointers
6010182007Sroberto *
6011182007Sroberto * Revision 4.57  2005/06/25 09:25:19  kardel
6012182007Sroberto * sort out log output sequence
6013182007Sroberto *
6014182007Sroberto * Revision 4.56  2005/06/14 21:47:27  kardel
6015182007Sroberto * collect samples only if samples are ok (sync or trusted flywheel)
6016182007Sroberto * propagate pps phase adjustment value to kernel via PPSAPI to help HARDPPS
6017182007Sroberto * en- and dis-able HARDPPS in correlation to receiver sync state
6018182007Sroberto *
6019182007Sroberto * Revision 4.55  2005/06/02 21:28:31  kardel
6020182007Sroberto * clarify trust logic
6021182007Sroberto *
6022182007Sroberto * Revision 4.54  2005/06/02 17:06:49  kardel
6023182007Sroberto * change status reporting to use fixed refclock_report()
6024182007Sroberto *
6025182007Sroberto * Revision 4.53  2005/06/02 16:33:31  kardel
6026182007Sroberto * fix acceptance of clocks unsync clocks right at start
6027182007Sroberto *
6028182007Sroberto * Revision 4.52  2005/05/26 21:55:06  kardel
6029182007Sroberto * cleanup status reporting
6030182007Sroberto *
6031182007Sroberto * Revision 4.51  2005/05/26 19:19:14  kardel
6032182007Sroberto * implement fast refclock startup
6033182007Sroberto *
6034182007Sroberto * Revision 4.50  2005/04/16 20:51:35  kardel
6035290000Sglebius * set hardpps_enable = 1 when binding a kernel PPS source
6036182007Sroberto *
6037182007Sroberto * Revision 4.49  2005/04/16 17:29:26  kardel
6038182007Sroberto * add non polling clock type 18 for just listenning to Meinberg clocks
6039182007Sroberto *
6040182007Sroberto * Revision 4.48  2005/04/16 16:22:27  kardel
6041182007Sroberto * bk sync 20050415 ntp-dev
6042182007Sroberto *
6043182007Sroberto * Revision 4.47  2004/11/29 10:42:48  kardel
6044182007Sroberto * bk sync ntp-dev 20041129
6045182007Sroberto *
6046182007Sroberto * Revision 4.46  2004/11/29 10:26:29  kardel
6047182007Sroberto * keep fudgetime2 in sync with trusttime/ppsphaseadjust depending in flag1
6048182007Sroberto *
6049182007Sroberto * Revision 4.45  2004/11/14 20:53:20  kardel
6050182007Sroberto * clear PPS flags after using them
6051182007Sroberto *
6052182007Sroberto * Revision 4.44  2004/11/14 15:29:41  kardel
6053182007Sroberto * support PPSAPI, upgrade Copyright to Berkeley style
6054182007Sroberto *
6055182007Sroberto * Revision 4.43  2001/05/26 22:53:16  kardel
6056182007Sroberto * 20010526 reconcilation
6057182007Sroberto *
6058182007Sroberto * Revision 4.42  2000/05/14 15:31:51  kardel
6059182007Sroberto * PPSAPI && RAWDCF modemline support
6060182007Sroberto *
6061182007Sroberto * Revision 4.41  2000/04/09 19:50:45  kardel
6062182007Sroberto * fixed rawdcfdtr_init() -> rawdcf_init_1
6063182007Sroberto *
6064182007Sroberto * Revision 4.40  2000/04/09 15:27:55  kardel
6065182007Sroberto * modem line fiddle in rawdcf_init_2
6066182007Sroberto *
6067182007Sroberto * Revision 4.39  2000/03/18 09:16:55  kardel
6068182007Sroberto * PPSAPI integration
6069182007Sroberto *
6070182007Sroberto * Revision 4.38  2000/03/05 20:25:06  kardel
6071182007Sroberto * support PPSAPI
6072182007Sroberto *
6073182007Sroberto * Revision 4.37  2000/03/05 20:11:14  kardel
6074182007Sroberto * 4.0.99g reconcilation
6075182007Sroberto *
607656746Sroberto * Revision 4.36  1999/11/28 17:18:20  kardel
607756746Sroberto * disabled burst mode
607856746Sroberto *
607956746Sroberto * Revision 4.35  1999/11/28 09:14:14  kardel
608056746Sroberto * RECON_4_0_98F
608156746Sroberto *
608256746Sroberto * Revision 4.34  1999/05/14 06:08:05  kardel
608356746Sroberto * store current_time in a suitable container (u_long)
608456746Sroberto *
608556746Sroberto * Revision 4.33  1999/05/13 21:48:38  kardel
608656746Sroberto * double the no response timeout interval
608756746Sroberto *
608856746Sroberto * Revision 4.32  1999/05/13 20:09:13  kardel
608956746Sroberto * complain only about missing polls after a full poll interval
609056746Sroberto *
609156746Sroberto * Revision 4.31  1999/05/13 19:59:32  kardel
609256746Sroberto * add clock type 16 for RTS set DTR clr in RAWDCF
609356746Sroberto *
609456746Sroberto * Revision 4.30  1999/02/28 20:36:43  kardel
609556746Sroberto * fixed printf fmt
609656746Sroberto *
609754359Sroberto * Revision 4.29  1999/02/28 19:58:23  kardel
609854359Sroberto * updated copyright information
609954359Sroberto *
610054359Sroberto * Revision 4.28  1999/02/28 19:01:50  kardel
610154359Sroberto * improved debug out on sent Meinberg messages
610254359Sroberto *
610354359Sroberto * Revision 4.27  1999/02/28 18:05:55  kardel
610454359Sroberto * no linux/ppsclock.h stuff
610554359Sroberto *
610654359Sroberto * Revision 4.26  1999/02/28 15:27:27  kardel
610754359Sroberto * wharton clock integration
610854359Sroberto *
610954359Sroberto * Revision 4.25  1999/02/28 14:04:46  kardel
611054359Sroberto * added missing double quotes to UTC information string
611154359Sroberto *
611254359Sroberto * Revision 4.24  1999/02/28 12:06:50  kardel
611354359Sroberto * (parse_control): using gmprettydate instead of prettydate()
611454359Sroberto * (mk_utcinfo): new function for formatting GPS derived UTC information
611554359Sroberto * (gps16x_message): changed to use mk_utcinfo()
611654359Sroberto * (trimbletsip_message): changed to use mk_utcinfo()
611754359Sroberto * ignoring position information in unsynchronized mode
611854359Sroberto * (parse_start): augument linux support for optional ASYNC_LOW_LATENCY
611954359Sroberto *
612054359Sroberto * Revision 4.23  1999/02/23 19:47:53  kardel
612154359Sroberto * fixed #endifs
612254359Sroberto * (stream_receive): fixed formats
612354359Sroberto *
612454359Sroberto * Revision 4.22  1999/02/22 06:21:02  kardel
612554359Sroberto * use new autoconfig symbols
612654359Sroberto *
612754359Sroberto * Revision 4.21  1999/02/21 12:18:13  kardel
612854359Sroberto * 4.91f reconcilation
612954359Sroberto *
613054359Sroberto * Revision 4.20  1999/02/21 10:53:36  kardel
613154359Sroberto * initial Linux PPSkit version
613254359Sroberto *
613354359Sroberto * Revision 4.19  1999/02/07 09:10:45  kardel
613454359Sroberto * clarify STREAMS mitigation rules in comment
613554359Sroberto *
613654359Sroberto * Revision 4.18  1998/12/20 23:45:34  kardel
613754359Sroberto * fix types and warnings
613854359Sroberto *
613954359Sroberto * Revision 4.17  1998/11/15 21:24:51  kardel
614054359Sroberto * cannot access mbg_ routines when CLOCK_MEINBERG
614154359Sroberto * is not defined
614254359Sroberto *
614354359Sroberto * Revision 4.16  1998/11/15 20:28:17  kardel
614454359Sroberto * Release 4.0.73e13 reconcilation
614554359Sroberto *
614654359Sroberto * Revision 4.15  1998/08/22 21:56:08  kardel
614754359Sroberto * fixed IO handling for non-STREAM IO
614854359Sroberto *
614954359Sroberto * Revision 4.14  1998/08/16 19:00:48  kardel
615054359Sroberto * (gps16x_message): reduced UTC parameter information (dropped A0,A1)
615154359Sroberto * made uval a local variable (killed one of the last globals)
615254359Sroberto * (sendetx): added logging of messages when in debug mode
615354359Sroberto * (trimble_check): added periodic checks to facilitate re-initialization
615454359Sroberto * (trimbletsip_init): made use of EOL character if in non-kernel operation
615554359Sroberto * (trimbletsip_message): extended message interpretation
615654359Sroberto * (getdbl): fixed data conversion
615754359Sroberto *
615854359Sroberto * Revision 4.13  1998/08/09 22:29:13  kardel
615954359Sroberto * Trimble TSIP support
616054359Sroberto *
616154359Sroberto * Revision 4.12  1998/07/11 10:05:34  kardel
616254359Sroberto * Release 4.0.73d reconcilation
616354359Sroberto *
616454359Sroberto * Revision 4.11  1998/06/14 21:09:42  kardel
616554359Sroberto * Sun acc cleanup
616654359Sroberto *
616754359Sroberto * Revision 4.10  1998/06/13 12:36:45  kardel
616854359Sroberto * signed/unsigned, name clashes
616954359Sroberto *
617054359Sroberto * Revision 4.9  1998/06/12 15:30:00  kardel
617154359Sroberto * prototype fixes
617254359Sroberto *
617354359Sroberto * Revision 4.8  1998/06/12 11:19:42  kardel
617454359Sroberto * added direct input processing routine for refclocks in
617554359Sroberto * order to avaiod that single character io gobbles up all
617654359Sroberto * receive buffers and drops input data. (Problem started
617754359Sroberto * with fast machines so a character a buffer was possible
617854359Sroberto * one of the few cases where faster machines break existing
617954359Sroberto * allocation algorithms)
618054359Sroberto *
618154359Sroberto * Revision 4.7  1998/06/06 18:35:20  kardel
618254359Sroberto * (parse_start): added BURST mode initialisation
618354359Sroberto *
618454359Sroberto * Revision 4.6  1998/05/27 06:12:46  kardel
618554359Sroberto * RAWDCF_BASEDELAY default added
618654359Sroberto * old comment removed
618754359Sroberto * casts for ioctl()
618854359Sroberto *
618954359Sroberto * Revision 4.5  1998/05/25 22:05:09  kardel
619054359Sroberto * RAWDCF_SETDTR option removed
619154359Sroberto * clock type 14 attempts to set DTR for
619254359Sroberto * power supply of RAWDCF receivers
619354359Sroberto *
619454359Sroberto * Revision 4.4  1998/05/24 16:20:47  kardel
619554359Sroberto * updated comments referencing Meinberg clocks
619654359Sroberto * added RAWDCF clock with DTR set option as type 14
619754359Sroberto *
619854359Sroberto * Revision 4.3  1998/05/24 10:48:33  kardel
619954359Sroberto * calibrated CONRAD RAWDCF default fudge factor
620054359Sroberto *
620154359Sroberto * Revision 4.2  1998/05/24 09:59:35  kardel
620254359Sroberto * corrected version information (ntpq support)
620354359Sroberto *
620454359Sroberto * Revision 4.1  1998/05/24 09:52:31  kardel
620554359Sroberto * use fixed format only (new IO model)
620654359Sroberto * output debug to stdout instead of msyslog()
620754359Sroberto * don't include >"< in ASCII output in order not to confuse
620854359Sroberto * ntpq parsing
620954359Sroberto *
621054359Sroberto * Revision 4.0  1998/04/10 19:52:11  kardel
621154359Sroberto * Start 4.0 release version numbering
621254359Sroberto *
621354359Sroberto * Revision 1.2  1998/04/10 19:28:04  kardel
621454359Sroberto * initial NTP VERSION 4 integration of PARSE with GPS166 binary support
621554359Sroberto * derived from 3.105.1.2 from V3 tree
621654359Sroberto *
621754359Sroberto * Revision information 3.1 - 3.105 from log deleted 1998/04/10 kardel
621854359Sroberto *
621954359Sroberto */
6220