1/*
2 * /src/NTP/REPOSITORY/ntp4-dev/ntpd/refclock_parse.c,v 4.81 2009/05/01 10:15:29 kardel RELEASE_20090105_A
3 *
4 * refclock_parse.c,v 4.81 2009/05/01 10:15:29 kardel RELEASE_20090105_A
5 *
6 * generic reference clock driver for several DCF/GPS/MSF/... receivers
7 *
8 * PPS notes:
9 *   On systems that support PPSAPI (RFC2783) PPSAPI is the
10 *   preferred interface.
11 *
12 *   Optionally make use of a STREAMS module for input processing where
13 *   available and configured. This STREAMS module reduces the time
14 *   stamp latency for serial and PPS events.
15 *   Currently the STREAMS module is only available for Suns running
16 *   SunOS 4.x and SunOS5.x.
17 *
18 * Copyright (c) 1995-2009 by Frank Kardel <kardel <AT> ntp.org>
19 * Copyright (c) 1989-1994 by Frank Kardel, Friedrich-Alexander Universit�t Erlangen-N�rnberg, Germany
20 *
21 * Redistribution and use in source and binary forms, with or without
22 * modification, are permitted provided that the following conditions
23 * are met:
24 * 1. Redistributions of source code must retain the above copyright
25 *    notice, this list of conditions and the following disclaimer.
26 * 2. Redistributions in binary form must reproduce the above copyright
27 *    notice, this list of conditions and the following disclaimer in the
28 *    documentation and/or other materials provided with the distribution.
29 * 3. Neither the name of the author nor the names of its contributors
30 *    may be used to endorse or promote products derived from this software
31 *    without specific prior written permission.
32 *
33 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
34 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
35 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
36 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
37 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
38 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
39 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
40 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
41 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
42 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
43 * SUCH DAMAGE.
44 *
45 */
46
47#ifdef HAVE_CONFIG_H
48# include "config.h"
49#endif
50
51#if defined(REFCLOCK) && defined(CLOCK_PARSE)
52
53/*
54 * This driver currently provides the support for
55 *   - Meinberg receiver DCF77 PZF 535 (TCXO version)       (DCF)
56 *   - Meinberg receiver DCF77 PZF 535 (OCXO version)       (DCF)
57 *   - Meinberg receiver DCF77 PZF 509                      (DCF)
58 *   - Meinberg receiver DCF77 AM receivers (e.g. C51)      (DCF)
59 *   - IGEL CLOCK                                           (DCF)
60 *   - ELV DCF7000                                          (DCF)
61 *   - Schmid clock                                         (DCF)
62 *   - Conrad DCF77 receiver module                         (DCF)
63 *   - FAU DCF77 NTP receiver (TimeBrick)                   (DCF)
64 *   - WHARTON 400A Series clock			    (DCF)
65 *
66 *   - Meinberg GPS166/GPS167                               (GPS)
67 *   - Trimble (TSIP and TAIP protocol)                     (GPS)
68 *
69 *   - RCC8000 MSF Receiver                                 (MSF)
70 *   - VARITEXT clock					    (MSF)
71 */
72
73/*
74 * Meinberg receivers are usually connected via a
75 * 9600 baud serial line
76 *
77 * The Meinberg GPS receivers also have a special NTP time stamp
78 * format. The firmware release is Uni-Erlangen.
79 *
80 * Meinberg generic receiver setup:
81 *	output time code every second
82 *	Baud rate 9600 7E2S
83 *
84 * Meinberg GPS16x setup:
85 *      output time code every second
86 *      Baudrate 19200 8N1
87 *
88 * This software supports the standard data formats used
89 * in Meinberg receivers.
90 *
91 * Special software versions are only sensible for the
92 * GPS 16x family of receivers.
93 *
94 * Meinberg can be reached via: http://www.meinberg.de/
95 */
96
97#include "ntpd.h"
98#include "ntp_refclock.h"
99#include "ntp_unixtime.h"	/* includes <sys/time.h> */
100#include "ntp_control.h"
101#include "ntp_string.h"
102
103#include <stdio.h>
104#include <ctype.h>
105#ifndef TM_IN_SYS_TIME
106# include <time.h>
107#endif
108
109#ifdef HAVE_UNISTD_H
110# include <unistd.h>
111#endif
112
113#if !defined(STREAM) && !defined(HAVE_SYSV_TTYS) && !defined(HAVE_BSD_TTYS) && !defined(HAVE_TERMIOS)
114# include "Bletch:  Define one of {STREAM,HAVE_SYSV_TTYS,HAVE_TERMIOS}"
115#endif
116
117#ifdef STREAM
118# include <sys/stream.h>
119# include <sys/stropts.h>
120#endif
121
122#ifdef HAVE_TERMIOS
123# define TTY_GETATTR(_FD_, _ARG_) tcgetattr((_FD_), (_ARG_))
124# define TTY_SETATTR(_FD_, _ARG_) tcsetattr((_FD_), TCSANOW, (_ARG_))
125# undef HAVE_SYSV_TTYS
126#endif
127
128#ifdef HAVE_SYSV_TTYS
129# define TTY_GETATTR(_FD_, _ARG_) ioctl((_FD_), TCGETA, (_ARG_))
130# define TTY_SETATTR(_FD_, _ARG_) ioctl((_FD_), TCSETAW, (_ARG_))
131#endif
132
133#ifdef HAVE_BSD_TTYS
134/* #error CURRENTLY NO BSD TTY SUPPORT */
135# include "Bletch: BSD TTY not currently supported"
136#endif
137
138#ifdef HAVE_SYS_IOCTL_H
139# include <sys/ioctl.h>
140#endif
141
142#ifdef HAVE_PPSAPI
143# include "ppsapi_timepps.h"
144# include "refclock_atom.h"
145#endif
146
147#ifdef PPS
148# ifdef HAVE_SYS_PPSCLOCK_H
149#  include <sys/ppsclock.h>
150# endif
151# ifdef HAVE_TIO_SERIAL_STUFF
152#  include <linux/serial.h>
153# endif
154#endif
155
156#define BUFFER_SIZE(_BUF, _PTR) ((_BUF) + sizeof(_BUF) - (_PTR))
157#define BUFFER_SIZES(_BUF, _PTR, _SZ) ((_BUF) + (_SZ) - (_PTR))
158
159/*
160 * document type of PPS interfacing - copy of ifdef mechanism in local_input()
161 */
162#undef PPS_METHOD
163
164#ifdef HAVE_PPSAPI
165#define PPS_METHOD "PPS API"
166#else
167#ifdef TIOCDCDTIMESTAMP
168#define PPS_METHOD "TIOCDCDTIMESTAMP"
169#else /* TIOCDCDTIMESTAMP */
170#if defined(HAVE_STRUCT_PPSCLOCKEV) && (defined(HAVE_CIOGETEV) || defined(HAVE_TIOCGPPSEV))
171#ifdef HAVE_CIOGETEV
172#define PPS_METHOD "CIOGETEV"
173#endif
174#ifdef HAVE_TIOCGPPSEV
175#define PPS_METHOD "TIOCGPPSEV"
176#endif
177#endif
178#endif /* TIOCDCDTIMESTAMP */
179#endif /* HAVE_PPSAPI */
180
181#include "ntp_io.h"
182#include "ntp_stdlib.h"
183
184#include "parse.h"
185#include "mbg_gps166.h"
186#include "trimble.h"
187#include "binio.h"
188#include "ascii.h"
189#include "ieee754io.h"
190#include "recvbuff.h"
191
192static char rcsid[] = "refclock_parse.c,v 4.81 2009/05/01 10:15:29 kardel RELEASE_20090105_A";
193
194/**===========================================================================
195 ** external interface to ntp mechanism
196 **/
197
198static	int	parse_start	(int, struct peer *);
199static	void	parse_shutdown	(int, struct peer *);
200static	void	parse_poll	(int, struct peer *);
201static	void	parse_control	(int, struct refclockstat *, struct refclockstat *, struct peer *);
202
203struct	refclock refclock_parse = {
204	parse_start,
205	parse_shutdown,
206	parse_poll,
207	parse_control,
208	noentry,
209	noentry,
210	NOFLAGS
211};
212
213/*
214 * Definitions
215 */
216#define	MAXUNITS	4	/* maximum number of "PARSE" units permitted */
217#define PARSEDEVICE	"/dev/refclock-%d" /* device to open %d is unit number */
218#define PARSEPPSDEVICE	"/dev/refclockpps-%d" /* optional pps device to open %d is unit number */
219
220#undef ABS
221#define ABS(_X_) (((_X_) < 0) ? -(_X_) : (_X_))
222
223#define PARSE_HARDPPS_DISABLE 0
224#define PARSE_HARDPPS_ENABLE  1
225
226/**===========================================================================
227 ** function vector for dynamically binding io handling mechanism
228 **/
229
230struct parseunit;		/* to keep inquiring minds happy */
231
232typedef struct bind
233{
234  const char *bd_description;	                                /* name of type of binding */
235  int	(*bd_init)     (struct parseunit *);			/* initialize */
236  void	(*bd_end)      (struct parseunit *);			/* end */
237  int   (*bd_setcs)    (struct parseunit *, parsectl_t *);	/* set character size */
238  int	(*bd_disable)  (struct parseunit *);			/* disable */
239  int	(*bd_enable)   (struct parseunit *);			/* enable */
240  int	(*bd_getfmt)   (struct parseunit *, parsectl_t *);	/* get format */
241  int	(*bd_setfmt)   (struct parseunit *, parsectl_t *);	/* setfmt */
242  int	(*bd_timecode) (struct parseunit *, parsectl_t *);	/* get time code */
243  void	(*bd_receive)  (struct recvbuf *);			/* receive operation */
244  int	(*bd_io_input) (struct recvbuf *);			/* input operation */
245} bind_t;
246
247#define PARSE_END(_X_)			(*(_X_)->binding->bd_end)(_X_)
248#define PARSE_SETCS(_X_, _CS_)		(*(_X_)->binding->bd_setcs)(_X_, _CS_)
249#define PARSE_ENABLE(_X_)		(*(_X_)->binding->bd_enable)(_X_)
250#define PARSE_DISABLE(_X_)		(*(_X_)->binding->bd_disable)(_X_)
251#define PARSE_GETFMT(_X_, _DCT_)	(*(_X_)->binding->bd_getfmt)(_X_, _DCT_)
252#define PARSE_SETFMT(_X_, _DCT_)	(*(_X_)->binding->bd_setfmt)(_X_, _DCT_)
253#define PARSE_GETTIMECODE(_X_, _DCT_)	(*(_X_)->binding->bd_timecode)(_X_, _DCT_)
254
255/*
256 * io modes
257 */
258#define PARSE_F_PPSPPS		0x0001 /* use loopfilter PPS code (CIOGETEV) */
259#define PARSE_F_PPSONSECOND	0x0002 /* PPS pulses are on second */
260
261
262/**===========================================================================
263 ** error message regression handling
264 **
265 ** there are quite a few errors that can occur in rapid succession such as
266 ** noisy input data or no data at all. in order to reduce the amount of
267 ** syslog messages in such case, we are using a backoff algorithm. We limit
268 ** the number of error messages of a certain class to 1 per time unit. if a
269 ** configurable number of messages is displayed that way, we move on to the
270 ** next time unit / count for that class. a count of messages that have been
271 ** suppressed is held and displayed whenever a corresponding message is
272 ** displayed. the time units for a message class will also be displayed.
273 ** whenever an error condition clears we reset the error message state,
274 ** thus we would still generate much output on pathological conditions
275 ** where the system oscillates between OK and NOT OK states. coping
276 ** with that condition is currently considered too complicated.
277 **/
278
279#define ERR_ALL	        (unsigned)~0	/* "all" errors */
280#define ERR_BADDATA	(unsigned)0	/* unusable input data/conversion errors */
281#define ERR_NODATA	(unsigned)1	/* no input data */
282#define ERR_BADIO	(unsigned)2	/* read/write/select errors */
283#define ERR_BADSTATUS	(unsigned)3	/* unsync states */
284#define ERR_BADEVENT	(unsigned)4	/* non nominal events */
285#define ERR_INTERNAL	(unsigned)5	/* internal error */
286#define ERR_CNT		(unsigned)(ERR_INTERNAL+1)
287
288#define ERR(_X_)	if (list_err(parse, (_X_)))
289
290struct errorregression
291{
292	u_long err_count;	/* number of repititions per class */
293	u_long err_delay;	/* minimum delay between messages */
294};
295
296static struct errorregression
297err_baddata[] =			/* error messages for bad input data */
298{
299	{ 1,       0 },		/* output first message immediately */
300	{ 5,      60 },		/* output next five messages in 60 second intervals */
301	{ 3,    3600 },		/* output next 3 messages in hour intervals */
302	{ 0, 12*3600 }		/* repeat messages only every 12 hours */
303};
304
305static struct errorregression
306err_nodata[] =			/* error messages for missing input data */
307{
308	{ 1,       0 },		/* output first message immediately */
309	{ 5,      60 },		/* output next five messages in 60 second intervals */
310	{ 3,    3600 },		/* output next 3 messages in hour intervals */
311	{ 0, 12*3600 }		/* repeat messages only every 12 hours */
312};
313
314static struct errorregression
315err_badstatus[] =		/* unsynchronized state messages */
316{
317	{ 1,       0 },		/* output first message immediately */
318	{ 5,      60 },		/* output next five messages in 60 second intervals */
319	{ 3,    3600 },		/* output next 3 messages in hour intervals */
320	{ 0, 12*3600 }		/* repeat messages only every 12 hours */
321};
322
323static struct errorregression
324err_badio[] =			/* io failures (bad reads, selects, ...) */
325{
326	{ 1,       0 },		/* output first message immediately */
327	{ 5,      60 },		/* output next five messages in 60 second intervals */
328	{ 5,    3600 },		/* output next 3 messages in hour intervals */
329	{ 0, 12*3600 }		/* repeat messages only every 12 hours */
330};
331
332static struct errorregression
333err_badevent[] =		/* non nominal events */
334{
335	{ 20,      0 },		/* output first message immediately */
336	{ 6,      60 },		/* output next five messages in 60 second intervals */
337	{ 5,    3600 },		/* output next 3 messages in hour intervals */
338	{ 0, 12*3600 }		/* repeat messages only every 12 hours */
339};
340
341static struct errorregression
342err_internal[] =		/* really bad things - basically coding/OS errors */
343{
344	{ 0,       0 },		/* output all messages immediately */
345};
346
347static struct errorregression *
348err_tbl[] =
349{
350	err_baddata,
351	err_nodata,
352	err_badio,
353	err_badstatus,
354	err_badevent,
355	err_internal
356};
357
358struct errorinfo
359{
360	u_long err_started;	/* begin time (ntp) of error condition */
361	u_long err_last;	/* last time (ntp) error occurred */
362	u_long err_cnt;	/* number of error repititions */
363	u_long err_suppressed;	/* number of suppressed messages */
364	struct errorregression *err_stage; /* current error stage */
365};
366
367/**===========================================================================
368 ** refclock instance data
369 **/
370
371struct parseunit
372{
373	/*
374	 * NTP management
375	 */
376	struct peer         *peer;		/* backlink to peer structure - refclock inactive if 0  */
377	struct refclockproc *generic;		/* backlink to refclockproc structure */
378
379	/*
380	 * PARSE io
381	 */
382	bind_t	     *binding;	        /* io handling binding */
383
384	/*
385	 * parse state
386	 */
387	parse_t	      parseio;	        /* io handling structure (user level parsing) */
388
389	/*
390	 * type specific parameters
391	 */
392	struct parse_clockinfo   *parse_type;	        /* link to clock description */
393
394	/*
395	 * clock state handling/reporting
396	 */
397	u_char	      flags;	        /* flags (leap_control) */
398	u_long	      lastchange;       /* time (ntp) when last state change accured */
399	u_long	      statetime[CEVNT_MAX+1]; /* accumulated time of clock states */
400	u_long        pollneeddata; 	/* current_time(!=0) for receive sample expected in PPS mode */
401	u_short	      lastformat;       /* last format used */
402	u_long        lastsync;		/* time (ntp) when clock was last seen fully synchronized */
403        u_long        maxunsync;        /* max time in seconds a receiver is trusted after loosing synchronisation */
404        double        ppsphaseadjust;   /* phase adjustment of PPS time stamp */
405        u_long        lastmissed;       /* time (ntp) when poll didn't get data (powerup heuristic) */
406	u_long        ppsserial;        /* magic cookie for ppsclock serials (avoids stale ppsclock data) */
407	int	      ppsfd;	        /* fd to ise for PPS io */
408#ifdef HAVE_PPSAPI
409        int           hardppsstate;     /* current hard pps state */
410	struct refclock_atom atom;      /* PPSAPI structure */
411#endif
412	parsetime_t   timedata;		/* last (parse module) data */
413	void         *localdata;        /* optional local, receiver-specific data */
414        unsigned long localstate;       /* private local state */
415	struct errorinfo errors[ERR_CNT];  /* error state table for suppressing excessive error messages */
416	struct ctl_var *kv;	        /* additional pseudo variables */
417	u_long        laststatistic;    /* time when staticstics where output */
418};
419
420
421/**===========================================================================
422 ** Clockinfo section all parameter for specific clock types
423 ** includes NTP parameters, TTY parameters and IO handling parameters
424 **/
425
426static	void	poll_dpoll	(struct parseunit *);
427static	void	poll_poll	(struct peer *);
428static	int	poll_init	(struct parseunit *);
429
430typedef struct poll_info
431{
432	u_long      rate;		/* poll rate - once every "rate" seconds - 0 off */
433	const char *string;		/* string to send for polling */
434	u_long      count;		/* number of characters in string */
435} poll_info_t;
436
437#define NO_CL_FLAGS	0
438#define NO_POLL		0
439#define NO_INIT		0
440#define NO_END		0
441#define NO_EVENT	0
442#define NO_LCLDATA	0
443#define NO_MESSAGE	0
444#define NO_PPSDELAY     0
445
446#define DCF_ID		"DCF"	/* generic DCF */
447#define DCF_A_ID	"DCFa"	/* AM demodulation */
448#define DCF_P_ID	"DCFp"	/* psuedo random phase shift */
449#define GPS_ID		"GPS"	/* GPS receiver */
450
451#define	NOCLOCK_ROOTDELAY	0.0
452#define	NOCLOCK_BASEDELAY	0.0
453#define	NOCLOCK_DESCRIPTION	0
454#define NOCLOCK_MAXUNSYNC       0
455#define NOCLOCK_CFLAG           0
456#define NOCLOCK_IFLAG           0
457#define NOCLOCK_OFLAG           0
458#define NOCLOCK_LFLAG           0
459#define NOCLOCK_ID		"TILT"
460#define NOCLOCK_POLL		NO_POLL
461#define NOCLOCK_INIT		NO_INIT
462#define NOCLOCK_END		NO_END
463#define NOCLOCK_DATA		NO_LCLDATA
464#define NOCLOCK_FORMAT		""
465#define NOCLOCK_TYPE		CTL_SST_TS_UNSPEC
466#define NOCLOCK_SAMPLES		0
467#define NOCLOCK_KEEP		0
468
469#define DCF_TYPE		CTL_SST_TS_LF
470#define GPS_TYPE		CTL_SST_TS_UHF
471
472/*
473 * receiver specific constants
474 */
475#define MBG_SPEED		(B9600)
476#define MBG_CFLAG		(CS7|PARENB|CREAD|CLOCAL|HUPCL|CSTOPB)
477#define MBG_IFLAG		(IGNBRK|IGNPAR|ISTRIP)
478#define MBG_OFLAG		0
479#define MBG_LFLAG		0
480#define MBG_FLAGS               PARSE_F_PPSONSECOND
481
482/*
483 * Meinberg DCF77 receivers
484 */
485#define	DCFUA31_ROOTDELAY	0.0  /* 0 */
486#define	DCFUA31_BASEDELAY	0.010  /* 10.7421875ms: 10 ms (+/- 3 ms) */
487#define	DCFUA31_DESCRIPTION	"Meinberg DCF77 C51 or compatible"
488#define DCFUA31_MAXUNSYNC       60*30       /* only trust clock for 1/2 hour */
489#define DCFUA31_SPEED		MBG_SPEED
490#define DCFUA31_CFLAG           MBG_CFLAG
491#define DCFUA31_IFLAG           MBG_IFLAG
492#define DCFUA31_OFLAG           MBG_OFLAG
493#define DCFUA31_LFLAG           MBG_LFLAG
494#define DCFUA31_SAMPLES		5
495#define DCFUA31_KEEP		3
496#define DCFUA31_FORMAT		"Meinberg Standard"
497
498/*
499 * Meinberg DCF PZF535/TCXO (FM/PZF) receiver
500 */
501#define	DCFPZF535_ROOTDELAY	0.0
502#define	DCFPZF535_BASEDELAY	0.001968  /* 1.968ms +- 104us (oscilloscope) - relative to start (end of STX) */
503#define	DCFPZF535_DESCRIPTION	"Meinberg DCF PZF 535/509 / TCXO"
504#define DCFPZF535_MAXUNSYNC     60*60*12           /* only trust clock for 12 hours
505						    * @ 5e-8df/f we have accumulated
506						    * at most 2.16 ms (thus we move to
507						    * NTP synchronisation */
508#define DCFPZF535_SPEED		MBG_SPEED
509#define DCFPZF535_CFLAG         MBG_CFLAG
510#define DCFPZF535_IFLAG         MBG_IFLAG
511#define DCFPZF535_OFLAG         MBG_OFLAG
512#define DCFPZF535_LFLAG         MBG_LFLAG
513#define DCFPZF535_SAMPLES	       5
514#define DCFPZF535_KEEP		       3
515#define DCFPZF535_FORMAT	"Meinberg Standard"
516
517/*
518 * Meinberg DCF PZF535/OCXO receiver
519 */
520#define	DCFPZF535OCXO_ROOTDELAY	0.0
521#define	DCFPZF535OCXO_BASEDELAY	0.001968 /* 1.968ms +- 104us (oscilloscope) - relative to start (end of STX) */
522#define	DCFPZF535OCXO_DESCRIPTION "Meinberg DCF PZF 535/509 / OCXO"
523#define DCFPZF535OCXO_MAXUNSYNC     60*60*96       /* only trust clock for 4 days
524						    * @ 5e-9df/f we have accumulated
525						    * at most an error of 1.73 ms
526						    * (thus we move to NTP synchronisation) */
527#define DCFPZF535OCXO_SPEED	    MBG_SPEED
528#define DCFPZF535OCXO_CFLAG         MBG_CFLAG
529#define DCFPZF535OCXO_IFLAG         MBG_IFLAG
530#define DCFPZF535OCXO_OFLAG         MBG_OFLAG
531#define DCFPZF535OCXO_LFLAG         MBG_LFLAG
532#define DCFPZF535OCXO_SAMPLES		   5
533#define DCFPZF535OCXO_KEEP	           3
534#define DCFPZF535OCXO_FORMAT	    "Meinberg Standard"
535
536/*
537 * Meinberg GPS16X receiver
538 */
539static	void	gps16x_message	 (struct parseunit *, parsetime_t *);
540static  int     gps16x_poll_init (struct parseunit *);
541
542#define	GPS16X_ROOTDELAY	0.0         /* nothing here */
543#define	GPS16X_BASEDELAY	0.001968         /* XXX to be fixed ! 1.968ms +- 104us (oscilloscope) - relative to start (end of STX) */
544#define	GPS16X_DESCRIPTION      "Meinberg GPS16x receiver"
545#define GPS16X_MAXUNSYNC        60*60*96       /* only trust clock for 4 days
546						* @ 5e-9df/f we have accumulated
547						* at most an error of 1.73 ms
548						* (thus we move to NTP synchronisation) */
549#define GPS16X_SPEED		B19200
550#define GPS16X_CFLAG            (CS8|CREAD|CLOCAL|HUPCL)
551#define GPS16X_IFLAG            (IGNBRK|IGNPAR)
552#define GPS16X_OFLAG            MBG_OFLAG
553#define GPS16X_LFLAG            MBG_LFLAG
554#define GPS16X_POLLRATE	6
555#define GPS16X_POLLCMD	""
556#define GPS16X_CMDSIZE	0
557
558static poll_info_t gps16x_pollinfo = { GPS16X_POLLRATE, GPS16X_POLLCMD, GPS16X_CMDSIZE };
559
560#define GPS16X_INIT		gps16x_poll_init
561#define GPS16X_POLL	        0
562#define GPS16X_END		0
563#define GPS16X_DATA		((void *)(&gps16x_pollinfo))
564#define GPS16X_MESSAGE		gps16x_message
565#define GPS16X_ID		GPS_ID
566#define GPS16X_FORMAT		"Meinberg GPS Extended"
567#define GPS16X_SAMPLES		5
568#define GPS16X_KEEP		3
569
570/*
571 * ELV DCF7000 Wallclock-Receiver/Switching Clock (Kit)
572 *
573 * This is really not the hottest clock - but before you have nothing ...
574 */
575#define DCF7000_ROOTDELAY	0.0 /* 0 */
576#define DCF7000_BASEDELAY	0.405 /* slow blow */
577#define DCF7000_DESCRIPTION	"ELV DCF7000"
578#define DCF7000_MAXUNSYNC	(60*5) /* sorry - but it just was not build as a clock */
579#define DCF7000_SPEED		(B9600)
580#define DCF7000_CFLAG           (CS8|CREAD|PARENB|PARODD|CLOCAL|HUPCL)
581#define DCF7000_IFLAG		(IGNBRK)
582#define DCF7000_OFLAG		0
583#define DCF7000_LFLAG		0
584#define DCF7000_SAMPLES		5
585#define DCF7000_KEEP		3
586#define DCF7000_FORMAT		"ELV DCF7000"
587
588/*
589 * Schmid DCF Receiver Kit
590 *
591 * When the WSDCF clock is operating optimally we want the primary clock
592 * distance to come out at 300 ms.  Thus, peer.distance in the WSDCF peer
593 * structure is set to 290 ms and we compute delays which are at least
594 * 10 ms long.  The following are 290 ms and 10 ms expressed in u_fp format
595 */
596#define WS_POLLRATE	1	/* every second - watch interdependency with poll routine */
597#define WS_POLLCMD	"\163"
598#define WS_CMDSIZE	1
599
600static poll_info_t wsdcf_pollinfo = { WS_POLLRATE, WS_POLLCMD, WS_CMDSIZE };
601
602#define WSDCF_INIT		poll_init
603#define WSDCF_POLL		poll_dpoll
604#define WSDCF_END		0
605#define WSDCF_DATA		((void *)(&wsdcf_pollinfo))
606#define	WSDCF_ROOTDELAY		0.0	/* 0 */
607#define	WSDCF_BASEDELAY	 	0.010	/*  ~  10ms */
608#define WSDCF_DESCRIPTION	"WS/DCF Receiver"
609#define WSDCF_FORMAT		"Schmid"
610#define WSDCF_MAXUNSYNC		(60*60)	/* assume this beast hold at 1 h better than 2 ms XXX-must verify */
611#define WSDCF_SPEED		(B1200)
612#define WSDCF_CFLAG		(CS8|CREAD|CLOCAL)
613#define WSDCF_IFLAG		0
614#define WSDCF_OFLAG		0
615#define WSDCF_LFLAG		0
616#define WSDCF_SAMPLES		5
617#define WSDCF_KEEP		3
618
619/*
620 * RAW DCF77 - input of DCF marks via RS232 - many variants
621 */
622#define RAWDCF_FLAGS		0
623#define RAWDCF_ROOTDELAY	0.0 /* 0 */
624#define RAWDCF_BASEDELAY	0.258
625#define RAWDCF_FORMAT		"RAW DCF77 Timecode"
626#define RAWDCF_MAXUNSYNC	(0) /* sorry - its a true receiver - no signal - no time */
627#define RAWDCF_SPEED		(B50)
628#ifdef NO_PARENB_IGNPAR /* Was: defined(SYS_IRIX4) || defined(SYS_IRIX5) */
629/* somehow doesn't grok PARENB & IGNPAR (mj) */
630# define RAWDCF_CFLAG            (CS8|CREAD|CLOCAL)
631#else
632# define RAWDCF_CFLAG            (CS8|CREAD|CLOCAL|PARENB)
633#endif
634#ifdef RAWDCF_NO_IGNPAR /* Was: defined(SYS_LINUX) && defined(CLOCK_RAWDCF) */
635# define RAWDCF_IFLAG		0
636#else
637# define RAWDCF_IFLAG		(IGNPAR)
638#endif
639#define RAWDCF_OFLAG		0
640#define RAWDCF_LFLAG		0
641#define RAWDCF_SAMPLES		20
642#define RAWDCF_KEEP		12
643#define RAWDCF_INIT		0
644
645/*
646 * RAW DCF variants
647 */
648/*
649 * Conrad receiver
650 *
651 * simplest (cheapest) DCF clock - e. g. DCF77 receiver by Conrad
652 * (~40DM - roughly $30 ) followed by a level converter for RS232
653 */
654#define CONRAD_BASEDELAY	0.292 /* Conrad receiver @ 50 Baud on a Sun */
655#define CONRAD_DESCRIPTION	"RAW DCF77 CODE (Conrad DCF77 receiver module)"
656
657/* Gude Analog- und Digitalsystem GmbH 'Expert mouseCLOCK USB v2.0' */
658#define GUDE_EMC_USB_V20_SPEED            (B4800)
659#define GUDE_EMC_USB_V20_BASEDELAY        0.425 /* USB serial<->USB converter FTDI232R */
660#define GUDE_EMC_USB_V20_DESCRIPTION      "RAW DCF77 CODE (Expert mouseCLOCK USB v2.0)"
661
662/*
663 * TimeBrick receiver
664 */
665#define TIMEBRICK_BASEDELAY	0.210 /* TimeBrick @ 50 Baud on a Sun */
666#define TIMEBRICK_DESCRIPTION	"RAW DCF77 CODE (TimeBrick)"
667
668/*
669 * IGEL:clock receiver
670 */
671#define IGELCLOCK_BASEDELAY	0.258 /* IGEL:clock receiver */
672#define IGELCLOCK_DESCRIPTION	"RAW DCF77 CODE (IGEL:clock)"
673#define IGELCLOCK_SPEED		(B1200)
674#define IGELCLOCK_CFLAG		(CS8|CREAD|HUPCL|CLOCAL)
675
676/*
677 * RAWDCF receivers that need to be powered from DTR
678 * (like Expert mouse clock)
679 */
680static	int	rawdcf_init_1	(struct parseunit *);
681#define RAWDCFDTRSET_DESCRIPTION	"RAW DCF77 CODE (DTR SET/RTS CLR)"
682#define RAWDCFDTRSET_INIT 		rawdcf_init_1
683
684/*
685 * RAWDCF receivers that need to be powered from
686 * DTR CLR and RTS SET
687 */
688static	int	rawdcf_init_2	(struct parseunit *);
689#define RAWDCFDTRCLRRTSSET_DESCRIPTION	"RAW DCF77 CODE (DTR CLR/RTS SET)"
690#define RAWDCFDTRCLRRTSSET_INIT	rawdcf_init_2
691
692/*
693 * Trimble GPS receivers (TAIP and TSIP protocols)
694 */
695#ifndef TRIM_POLLRATE
696#define TRIM_POLLRATE	0	/* only true direct polling */
697#endif
698
699#define TRIM_TAIPPOLLCMD	">SRM;FR_FLAG=F;EC_FLAG=F<>QTM<"
700#define TRIM_TAIPCMDSIZE	(sizeof(TRIM_TAIPPOLLCMD)-1)
701
702static poll_info_t trimbletaip_pollinfo = { TRIM_POLLRATE, TRIM_TAIPPOLLCMD, TRIM_TAIPCMDSIZE };
703static	int	trimbletaip_init	(struct parseunit *);
704static	void	trimbletaip_event	(struct parseunit *, int);
705
706/* query time & UTC correction data */
707static char tsipquery[] = { DLE, 0x21, DLE, ETX, DLE, 0x2F, DLE, ETX };
708
709static poll_info_t trimbletsip_pollinfo = { TRIM_POLLRATE, tsipquery, sizeof(tsipquery) };
710static	int	trimbletsip_init	(struct parseunit *);
711static	void	trimbletsip_end   	(struct parseunit *);
712static	void	trimbletsip_message	(struct parseunit *, parsetime_t *);
713static	void	trimbletsip_event	(struct parseunit *, int);
714
715#define TRIMBLETSIP_IDLE_TIME	    (300) /* 5 minutes silence at most */
716#define TRIMBLE_RESET_HOLDOFF       TRIMBLETSIP_IDLE_TIME
717
718#define TRIMBLETAIP_SPEED	    (B4800)
719#define TRIMBLETAIP_CFLAG           (CS8|CREAD|CLOCAL)
720#define TRIMBLETAIP_IFLAG           (BRKINT|IGNPAR|ISTRIP|ICRNL|IXON)
721#define TRIMBLETAIP_OFLAG           (OPOST|ONLCR)
722#define TRIMBLETAIP_LFLAG           (0)
723
724#define TRIMBLETSIP_SPEED	    (B9600)
725#define TRIMBLETSIP_CFLAG           (CS8|CLOCAL|CREAD|PARENB|PARODD)
726#define TRIMBLETSIP_IFLAG           (IGNBRK)
727#define TRIMBLETSIP_OFLAG           (0)
728#define TRIMBLETSIP_LFLAG           (ICANON)
729
730#define TRIMBLETSIP_SAMPLES	    5
731#define TRIMBLETSIP_KEEP	    3
732#define TRIMBLETAIP_SAMPLES	    5
733#define TRIMBLETAIP_KEEP	    3
734
735#define TRIMBLETAIP_FLAGS	    (PARSE_F_PPSONSECOND)
736#define TRIMBLETSIP_FLAGS	    (TRIMBLETAIP_FLAGS)
737
738#define TRIMBLETAIP_POLL	    poll_dpoll
739#define TRIMBLETSIP_POLL	    poll_dpoll
740
741#define TRIMBLETAIP_INIT	    trimbletaip_init
742#define TRIMBLETSIP_INIT	    trimbletsip_init
743
744#define TRIMBLETAIP_EVENT	    trimbletaip_event
745
746#define TRIMBLETSIP_EVENT	    trimbletsip_event
747#define TRIMBLETSIP_MESSAGE	    trimbletsip_message
748
749#define TRIMBLETAIP_END		    0
750#define TRIMBLETSIP_END		    trimbletsip_end
751
752#define TRIMBLETAIP_DATA	    ((void *)(&trimbletaip_pollinfo))
753#define TRIMBLETSIP_DATA	    ((void *)(&trimbletsip_pollinfo))
754
755#define TRIMBLETAIP_ID		    GPS_ID
756#define TRIMBLETSIP_ID		    GPS_ID
757
758#define TRIMBLETAIP_FORMAT	    "Trimble TAIP"
759#define TRIMBLETSIP_FORMAT	    "Trimble TSIP"
760
761#define TRIMBLETAIP_ROOTDELAY        0x0
762#define TRIMBLETSIP_ROOTDELAY        0x0
763
764#define TRIMBLETAIP_BASEDELAY        0.0
765#define TRIMBLETSIP_BASEDELAY        0.020	/* GPS time message latency */
766
767#define TRIMBLETAIP_DESCRIPTION      "Trimble GPS (TAIP) receiver"
768#define TRIMBLETSIP_DESCRIPTION      "Trimble GPS (TSIP) receiver"
769
770#define TRIMBLETAIP_MAXUNSYNC        0
771#define TRIMBLETSIP_MAXUNSYNC        0
772
773#define TRIMBLETAIP_EOL		    '<'
774
775/*
776 * RadioCode Clocks RCC 800 receiver
777 */
778#define RCC_POLLRATE   0       /* only true direct polling */
779#define RCC_POLLCMD    "\r"
780#define RCC_CMDSIZE    1
781
782static poll_info_t rcc8000_pollinfo = { RCC_POLLRATE, RCC_POLLCMD, RCC_CMDSIZE };
783#define RCC8000_FLAGS		0
784#define RCC8000_POLL            poll_dpoll
785#define RCC8000_INIT            poll_init
786#define RCC8000_END             0
787#define RCC8000_DATA            ((void *)(&rcc8000_pollinfo))
788#define RCC8000_ROOTDELAY       0.0
789#define RCC8000_BASEDELAY       0.0
790#define RCC8000_ID              "MSF"
791#define RCC8000_DESCRIPTION     "RCC 8000 MSF Receiver"
792#define RCC8000_FORMAT          "Radiocode RCC8000"
793#define RCC8000_MAXUNSYNC       (60*60) /* should be ok for an hour */
794#define RCC8000_SPEED		(B2400)
795#define RCC8000_CFLAG           (CS8|CREAD|CLOCAL)
796#define RCC8000_IFLAG           (IGNBRK|IGNPAR)
797#define RCC8000_OFLAG           0
798#define RCC8000_LFLAG           0
799#define RCC8000_SAMPLES         5
800#define RCC8000_KEEP	        3
801
802/*
803 * Hopf Radio clock 6021 Format
804 *
805 */
806#define HOPF6021_ROOTDELAY	0.0
807#define HOPF6021_BASEDELAY	0.0
808#define HOPF6021_DESCRIPTION	"HOPF 6021"
809#define HOPF6021_FORMAT         "hopf Funkuhr 6021"
810#define HOPF6021_MAXUNSYNC	(60*60)  /* should be ok for an hour */
811#define HOPF6021_SPEED         (B9600)
812#define HOPF6021_CFLAG          (CS8|CREAD|CLOCAL)
813#define HOPF6021_IFLAG		(IGNBRK|ISTRIP)
814#define HOPF6021_OFLAG		0
815#define HOPF6021_LFLAG		0
816#define HOPF6021_FLAGS          0
817#define HOPF6021_SAMPLES        5
818#define HOPF6021_KEEP	        3
819
820/*
821 * Diem's Computime Radio Clock Receiver
822 */
823#define COMPUTIME_FLAGS       0
824#define COMPUTIME_ROOTDELAY   0.0
825#define COMPUTIME_BASEDELAY   0.0
826#define COMPUTIME_ID          DCF_ID
827#define COMPUTIME_DESCRIPTION "Diem's Computime receiver"
828#define COMPUTIME_FORMAT      "Diem's Computime Radio Clock"
829#define COMPUTIME_TYPE        DCF_TYPE
830#define COMPUTIME_MAXUNSYNC   (60*60)       /* only trust clock for 1 hour */
831#define COMPUTIME_SPEED       (B9600)
832#define COMPUTIME_CFLAG       (CSTOPB|CS7|CREAD|CLOCAL)
833#define COMPUTIME_IFLAG       (IGNBRK|IGNPAR|ISTRIP)
834#define COMPUTIME_OFLAG       0
835#define COMPUTIME_LFLAG       0
836#define COMPUTIME_SAMPLES     5
837#define COMPUTIME_KEEP        3
838
839/*
840 * Varitext Radio Clock Receiver
841 */
842#define VARITEXT_FLAGS       0
843#define VARITEXT_ROOTDELAY   0.0
844#define VARITEXT_BASEDELAY   0.0
845#define VARITEXT_ID          "MSF"
846#define VARITEXT_DESCRIPTION "Varitext receiver"
847#define VARITEXT_FORMAT      "Varitext Radio Clock"
848#define VARITEXT_TYPE        DCF_TYPE
849#define VARITEXT_MAXUNSYNC   (60*60)       /* only trust clock for 1 hour */
850#define VARITEXT_SPEED       (B9600)
851#define VARITEXT_CFLAG       (CS7|CREAD|CLOCAL|PARENB|PARODD)
852#define VARITEXT_IFLAG       (IGNPAR|IGNBRK|INPCK) /*|ISTRIP)*/
853#define VARITEXT_OFLAG       0
854#define VARITEXT_LFLAG       0
855#define VARITEXT_SAMPLES     32
856#define VARITEXT_KEEP        20
857
858static struct parse_clockinfo
859{
860	u_long  cl_flags;		/* operation flags (io modes) */
861  void  (*cl_poll)    (struct parseunit *);			/* active poll routine */
862  int   (*cl_init)    (struct parseunit *);			/* active poll init routine */
863  void  (*cl_event)   (struct parseunit *, int);		/* special event handling (e.g. reset clock) */
864  void  (*cl_end)     (struct parseunit *);			/* active poll end routine */
865  void  (*cl_message) (struct parseunit *, parsetime_t *);	/* process a lower layer message */
866	void   *cl_data;		/* local data area for "poll" mechanism */
867	double    cl_rootdelay;		/* rootdelay */
868	double    cl_basedelay;		/* current offset by which the RS232
869				time code is delayed from the actual time */
870	const char *cl_id;		/* ID code */
871	const char *cl_description;		/* device name */
872	const char *cl_format;		/* fixed format */
873	u_char  cl_type;		/* clock type (ntp control) */
874	u_long  cl_maxunsync;		/* time to trust oscillator after losing synch */
875	u_long  cl_speed;		/* terminal input & output baudrate */
876	u_long  cl_cflag;             /* terminal control flags */
877	u_long  cl_iflag;             /* terminal input flags */
878	u_long  cl_oflag;             /* terminal output flags */
879	u_long  cl_lflag;             /* terminal local flags */
880	u_long  cl_samples;	      /* samples for median filter */
881	u_long  cl_keep;              /* samples for median filter to keep */
882} parse_clockinfo[] =
883{
884	{				/* mode 0 */
885		MBG_FLAGS,
886		NO_POLL,
887		NO_INIT,
888		NO_EVENT,
889		NO_END,
890		NO_MESSAGE,
891		NO_LCLDATA,
892		DCFPZF535_ROOTDELAY,
893		DCFPZF535_BASEDELAY,
894		DCF_P_ID,
895		DCFPZF535_DESCRIPTION,
896		DCFPZF535_FORMAT,
897		DCF_TYPE,
898		DCFPZF535_MAXUNSYNC,
899		DCFPZF535_SPEED,
900		DCFPZF535_CFLAG,
901		DCFPZF535_IFLAG,
902		DCFPZF535_OFLAG,
903		DCFPZF535_LFLAG,
904		DCFPZF535_SAMPLES,
905		DCFPZF535_KEEP
906	},
907	{				/* mode 1 */
908		MBG_FLAGS,
909		NO_POLL,
910		NO_INIT,
911		NO_EVENT,
912		NO_END,
913		NO_MESSAGE,
914		NO_LCLDATA,
915		DCFPZF535OCXO_ROOTDELAY,
916		DCFPZF535OCXO_BASEDELAY,
917		DCF_P_ID,
918		DCFPZF535OCXO_DESCRIPTION,
919		DCFPZF535OCXO_FORMAT,
920		DCF_TYPE,
921		DCFPZF535OCXO_MAXUNSYNC,
922		DCFPZF535OCXO_SPEED,
923		DCFPZF535OCXO_CFLAG,
924		DCFPZF535OCXO_IFLAG,
925		DCFPZF535OCXO_OFLAG,
926		DCFPZF535OCXO_LFLAG,
927		DCFPZF535OCXO_SAMPLES,
928		DCFPZF535OCXO_KEEP
929	},
930	{				/* mode 2 */
931		MBG_FLAGS,
932		NO_POLL,
933		NO_INIT,
934		NO_EVENT,
935		NO_END,
936		NO_MESSAGE,
937		NO_LCLDATA,
938		DCFUA31_ROOTDELAY,
939		DCFUA31_BASEDELAY,
940		DCF_A_ID,
941		DCFUA31_DESCRIPTION,
942		DCFUA31_FORMAT,
943		DCF_TYPE,
944		DCFUA31_MAXUNSYNC,
945		DCFUA31_SPEED,
946		DCFUA31_CFLAG,
947		DCFUA31_IFLAG,
948		DCFUA31_OFLAG,
949		DCFUA31_LFLAG,
950		DCFUA31_SAMPLES,
951		DCFUA31_KEEP
952	},
953	{				/* mode 3 */
954		MBG_FLAGS,
955		NO_POLL,
956		NO_INIT,
957		NO_EVENT,
958		NO_END,
959		NO_MESSAGE,
960		NO_LCLDATA,
961		DCF7000_ROOTDELAY,
962		DCF7000_BASEDELAY,
963		DCF_A_ID,
964		DCF7000_DESCRIPTION,
965		DCF7000_FORMAT,
966		DCF_TYPE,
967		DCF7000_MAXUNSYNC,
968		DCF7000_SPEED,
969		DCF7000_CFLAG,
970		DCF7000_IFLAG,
971		DCF7000_OFLAG,
972		DCF7000_LFLAG,
973		DCF7000_SAMPLES,
974		DCF7000_KEEP
975	},
976	{				/* mode 4 */
977		NO_CL_FLAGS,
978		WSDCF_POLL,
979		WSDCF_INIT,
980		NO_EVENT,
981		WSDCF_END,
982		NO_MESSAGE,
983		WSDCF_DATA,
984		WSDCF_ROOTDELAY,
985		WSDCF_BASEDELAY,
986		DCF_A_ID,
987		WSDCF_DESCRIPTION,
988		WSDCF_FORMAT,
989		DCF_TYPE,
990		WSDCF_MAXUNSYNC,
991		WSDCF_SPEED,
992		WSDCF_CFLAG,
993		WSDCF_IFLAG,
994		WSDCF_OFLAG,
995		WSDCF_LFLAG,
996		WSDCF_SAMPLES,
997		WSDCF_KEEP
998	},
999	{				/* mode 5 */
1000		RAWDCF_FLAGS,
1001		NO_POLL,
1002		RAWDCF_INIT,
1003		NO_EVENT,
1004		NO_END,
1005		NO_MESSAGE,
1006		NO_LCLDATA,
1007		RAWDCF_ROOTDELAY,
1008		CONRAD_BASEDELAY,
1009		DCF_A_ID,
1010		CONRAD_DESCRIPTION,
1011		RAWDCF_FORMAT,
1012		DCF_TYPE,
1013		RAWDCF_MAXUNSYNC,
1014		RAWDCF_SPEED,
1015		RAWDCF_CFLAG,
1016		RAWDCF_IFLAG,
1017		RAWDCF_OFLAG,
1018		RAWDCF_LFLAG,
1019		RAWDCF_SAMPLES,
1020		RAWDCF_KEEP
1021	},
1022	{				/* mode 6 */
1023		RAWDCF_FLAGS,
1024		NO_POLL,
1025		RAWDCF_INIT,
1026		NO_EVENT,
1027		NO_END,
1028		NO_MESSAGE,
1029		NO_LCLDATA,
1030		RAWDCF_ROOTDELAY,
1031		TIMEBRICK_BASEDELAY,
1032		DCF_A_ID,
1033		TIMEBRICK_DESCRIPTION,
1034		RAWDCF_FORMAT,
1035		DCF_TYPE,
1036		RAWDCF_MAXUNSYNC,
1037		RAWDCF_SPEED,
1038		RAWDCF_CFLAG,
1039		RAWDCF_IFLAG,
1040		RAWDCF_OFLAG,
1041		RAWDCF_LFLAG,
1042		RAWDCF_SAMPLES,
1043		RAWDCF_KEEP
1044	},
1045	{				/* mode 7 */
1046		MBG_FLAGS,
1047		GPS16X_POLL,
1048		GPS16X_INIT,
1049		NO_EVENT,
1050		GPS16X_END,
1051		GPS16X_MESSAGE,
1052		GPS16X_DATA,
1053		GPS16X_ROOTDELAY,
1054		GPS16X_BASEDELAY,
1055		GPS16X_ID,
1056		GPS16X_DESCRIPTION,
1057		GPS16X_FORMAT,
1058		GPS_TYPE,
1059		GPS16X_MAXUNSYNC,
1060		GPS16X_SPEED,
1061		GPS16X_CFLAG,
1062		GPS16X_IFLAG,
1063		GPS16X_OFLAG,
1064		GPS16X_LFLAG,
1065		GPS16X_SAMPLES,
1066		GPS16X_KEEP
1067	},
1068	{				/* mode 8 */
1069		RAWDCF_FLAGS,
1070		NO_POLL,
1071		NO_INIT,
1072		NO_EVENT,
1073		NO_END,
1074		NO_MESSAGE,
1075		NO_LCLDATA,
1076		RAWDCF_ROOTDELAY,
1077		IGELCLOCK_BASEDELAY,
1078		DCF_A_ID,
1079		IGELCLOCK_DESCRIPTION,
1080		RAWDCF_FORMAT,
1081		DCF_TYPE,
1082		RAWDCF_MAXUNSYNC,
1083		IGELCLOCK_SPEED,
1084		IGELCLOCK_CFLAG,
1085		RAWDCF_IFLAG,
1086		RAWDCF_OFLAG,
1087		RAWDCF_LFLAG,
1088		RAWDCF_SAMPLES,
1089		RAWDCF_KEEP
1090	},
1091	{				/* mode 9 */
1092		TRIMBLETAIP_FLAGS,
1093#if TRIM_POLLRATE		/* DHD940515: Allow user config */
1094		NO_POLL,
1095#else
1096		TRIMBLETAIP_POLL,
1097#endif
1098		TRIMBLETAIP_INIT,
1099		TRIMBLETAIP_EVENT,
1100		TRIMBLETAIP_END,
1101		NO_MESSAGE,
1102		TRIMBLETAIP_DATA,
1103		TRIMBLETAIP_ROOTDELAY,
1104		TRIMBLETAIP_BASEDELAY,
1105		TRIMBLETAIP_ID,
1106		TRIMBLETAIP_DESCRIPTION,
1107		TRIMBLETAIP_FORMAT,
1108		GPS_TYPE,
1109		TRIMBLETAIP_MAXUNSYNC,
1110		TRIMBLETAIP_SPEED,
1111		TRIMBLETAIP_CFLAG,
1112		TRIMBLETAIP_IFLAG,
1113		TRIMBLETAIP_OFLAG,
1114		TRIMBLETAIP_LFLAG,
1115		TRIMBLETAIP_SAMPLES,
1116		TRIMBLETAIP_KEEP
1117	},
1118	{				/* mode 10 */
1119		TRIMBLETSIP_FLAGS,
1120#if TRIM_POLLRATE		/* DHD940515: Allow user config */
1121		NO_POLL,
1122#else
1123		TRIMBLETSIP_POLL,
1124#endif
1125		TRIMBLETSIP_INIT,
1126		TRIMBLETSIP_EVENT,
1127		TRIMBLETSIP_END,
1128		TRIMBLETSIP_MESSAGE,
1129		TRIMBLETSIP_DATA,
1130		TRIMBLETSIP_ROOTDELAY,
1131		TRIMBLETSIP_BASEDELAY,
1132		TRIMBLETSIP_ID,
1133		TRIMBLETSIP_DESCRIPTION,
1134		TRIMBLETSIP_FORMAT,
1135		GPS_TYPE,
1136		TRIMBLETSIP_MAXUNSYNC,
1137		TRIMBLETSIP_SPEED,
1138		TRIMBLETSIP_CFLAG,
1139		TRIMBLETSIP_IFLAG,
1140		TRIMBLETSIP_OFLAG,
1141		TRIMBLETSIP_LFLAG,
1142		TRIMBLETSIP_SAMPLES,
1143		TRIMBLETSIP_KEEP
1144	},
1145	{                             /* mode 11 */
1146		NO_CL_FLAGS,
1147		RCC8000_POLL,
1148		RCC8000_INIT,
1149		NO_EVENT,
1150		RCC8000_END,
1151		NO_MESSAGE,
1152		RCC8000_DATA,
1153		RCC8000_ROOTDELAY,
1154		RCC8000_BASEDELAY,
1155		RCC8000_ID,
1156		RCC8000_DESCRIPTION,
1157		RCC8000_FORMAT,
1158		DCF_TYPE,
1159		RCC8000_MAXUNSYNC,
1160		RCC8000_SPEED,
1161		RCC8000_CFLAG,
1162		RCC8000_IFLAG,
1163		RCC8000_OFLAG,
1164		RCC8000_LFLAG,
1165		RCC8000_SAMPLES,
1166		RCC8000_KEEP
1167	},
1168	{                             /* mode 12 */
1169		HOPF6021_FLAGS,
1170		NO_POLL,
1171		NO_INIT,
1172		NO_EVENT,
1173		NO_END,
1174		NO_MESSAGE,
1175		NO_LCLDATA,
1176		HOPF6021_ROOTDELAY,
1177		HOPF6021_BASEDELAY,
1178		DCF_ID,
1179		HOPF6021_DESCRIPTION,
1180		HOPF6021_FORMAT,
1181		DCF_TYPE,
1182		HOPF6021_MAXUNSYNC,
1183		HOPF6021_SPEED,
1184		HOPF6021_CFLAG,
1185		HOPF6021_IFLAG,
1186		HOPF6021_OFLAG,
1187		HOPF6021_LFLAG,
1188		HOPF6021_SAMPLES,
1189		HOPF6021_KEEP
1190	},
1191	{                            /* mode 13 */
1192		COMPUTIME_FLAGS,
1193		NO_POLL,
1194		NO_INIT,
1195		NO_EVENT,
1196		NO_END,
1197		NO_MESSAGE,
1198		NO_LCLDATA,
1199		COMPUTIME_ROOTDELAY,
1200		COMPUTIME_BASEDELAY,
1201		COMPUTIME_ID,
1202		COMPUTIME_DESCRIPTION,
1203		COMPUTIME_FORMAT,
1204		COMPUTIME_TYPE,
1205		COMPUTIME_MAXUNSYNC,
1206		COMPUTIME_SPEED,
1207		COMPUTIME_CFLAG,
1208		COMPUTIME_IFLAG,
1209		COMPUTIME_OFLAG,
1210		COMPUTIME_LFLAG,
1211		COMPUTIME_SAMPLES,
1212		COMPUTIME_KEEP
1213	},
1214	{				/* mode 14 */
1215		RAWDCF_FLAGS,
1216		NO_POLL,
1217		RAWDCFDTRSET_INIT,
1218		NO_EVENT,
1219		NO_END,
1220		NO_MESSAGE,
1221		NO_LCLDATA,
1222		RAWDCF_ROOTDELAY,
1223		RAWDCF_BASEDELAY,
1224		DCF_A_ID,
1225		RAWDCFDTRSET_DESCRIPTION,
1226		RAWDCF_FORMAT,
1227		DCF_TYPE,
1228		RAWDCF_MAXUNSYNC,
1229		RAWDCF_SPEED,
1230		RAWDCF_CFLAG,
1231		RAWDCF_IFLAG,
1232		RAWDCF_OFLAG,
1233		RAWDCF_LFLAG,
1234		RAWDCF_SAMPLES,
1235		RAWDCF_KEEP
1236	},
1237	{				/* mode 15 */
1238		0,				/* operation flags (io modes) */
1239  		NO_POLL,			/* active poll routine */
1240		NO_INIT,			/* active poll init routine */
1241  		NO_EVENT,		        /* special event handling (e.g. reset clock) */
1242  		NO_END,				/* active poll end routine */
1243  		NO_MESSAGE,			/* process a lower layer message */
1244		NO_LCLDATA,			/* local data area for "poll" mechanism */
1245		0,				/* rootdelay */
1246		11.0 /* bits */ / 9600,		/* current offset by which the RS232
1247				           	time code is delayed from the actual time */
1248		DCF_ID,				/* ID code */
1249		"WHARTON 400A Series clock",	/* device name */
1250		"WHARTON 400A Series clock Output Format 1",	/* fixed format */
1251			/* Must match a format-name in a libparse/clk_xxx.c file */
1252		DCF_TYPE,			/* clock type (ntp control) */
1253		(1*60*60),		        /* time to trust oscillator after losing synch */
1254		B9600,				/* terminal input & output baudrate */
1255		(CS8|CREAD|PARENB|CLOCAL|HUPCL),/* terminal control flags */
1256		0,				/* terminal input flags */
1257		0,				/* terminal output flags */
1258		0,				/* terminal local flags */
1259		5,				/* samples for median filter */
1260		3,				/* samples for median filter to keep */
1261	},
1262	{				/* mode 16 - RAWDCF RTS set, DTR clr */
1263		RAWDCF_FLAGS,
1264		NO_POLL,
1265		RAWDCFDTRCLRRTSSET_INIT,
1266		NO_EVENT,
1267		NO_END,
1268		NO_MESSAGE,
1269		NO_LCLDATA,
1270		RAWDCF_ROOTDELAY,
1271		RAWDCF_BASEDELAY,
1272		DCF_A_ID,
1273		RAWDCFDTRCLRRTSSET_DESCRIPTION,
1274		RAWDCF_FORMAT,
1275		DCF_TYPE,
1276		RAWDCF_MAXUNSYNC,
1277		RAWDCF_SPEED,
1278		RAWDCF_CFLAG,
1279		RAWDCF_IFLAG,
1280		RAWDCF_OFLAG,
1281		RAWDCF_LFLAG,
1282		RAWDCF_SAMPLES,
1283		RAWDCF_KEEP
1284	},
1285        {                            /* mode 17 */
1286                VARITEXT_FLAGS,
1287                NO_POLL,
1288                NO_INIT,
1289                NO_EVENT,
1290                NO_END,
1291                NO_MESSAGE,
1292                NO_LCLDATA,
1293                VARITEXT_ROOTDELAY,
1294                VARITEXT_BASEDELAY,
1295                VARITEXT_ID,
1296                VARITEXT_DESCRIPTION,
1297                VARITEXT_FORMAT,
1298                VARITEXT_TYPE,
1299                VARITEXT_MAXUNSYNC,
1300                VARITEXT_SPEED,
1301                VARITEXT_CFLAG,
1302                VARITEXT_IFLAG,
1303                VARITEXT_OFLAG,
1304                VARITEXT_LFLAG,
1305                VARITEXT_SAMPLES,
1306                VARITEXT_KEEP
1307        },
1308	{				/* mode 18 */
1309		MBG_FLAGS,
1310		NO_POLL,
1311		NO_INIT,
1312		NO_EVENT,
1313		GPS16X_END,
1314		GPS16X_MESSAGE,
1315		GPS16X_DATA,
1316		GPS16X_ROOTDELAY,
1317		GPS16X_BASEDELAY,
1318		GPS16X_ID,
1319		GPS16X_DESCRIPTION,
1320		GPS16X_FORMAT,
1321		GPS_TYPE,
1322		GPS16X_MAXUNSYNC,
1323		GPS16X_SPEED,
1324		GPS16X_CFLAG,
1325		GPS16X_IFLAG,
1326		GPS16X_OFLAG,
1327		GPS16X_LFLAG,
1328		GPS16X_SAMPLES,
1329		GPS16X_KEEP
1330	},
1331	{				/* mode 19 */
1332		RAWDCF_FLAGS,
1333		NO_POLL,
1334		RAWDCF_INIT,
1335		NO_EVENT,
1336		NO_END,
1337		NO_MESSAGE,
1338		NO_LCLDATA,
1339		RAWDCF_ROOTDELAY,
1340		GUDE_EMC_USB_V20_BASEDELAY,
1341		DCF_A_ID,
1342		GUDE_EMC_USB_V20_DESCRIPTION,
1343		RAWDCF_FORMAT,
1344		DCF_TYPE,
1345		RAWDCF_MAXUNSYNC,
1346		GUDE_EMC_USB_V20_SPEED,
1347		RAWDCF_CFLAG,
1348		RAWDCF_IFLAG,
1349		RAWDCF_OFLAG,
1350		RAWDCF_LFLAG,
1351		RAWDCF_SAMPLES,
1352		RAWDCF_KEEP
1353	},
1354};
1355
1356static int ncltypes = sizeof(parse_clockinfo) / sizeof(struct parse_clockinfo);
1357
1358#define CLK_REALTYPE(x) ((int)(((x)->ttl) & 0x7F))
1359#define CLK_TYPE(x)	((CLK_REALTYPE(x) >= ncltypes) ? ~0 : CLK_REALTYPE(x))
1360#define CLK_UNIT(x)	((int)REFCLOCKUNIT(&(x)->srcadr))
1361#define CLK_PPS(x)	(((x)->ttl) & 0x80)
1362
1363/*
1364 * Other constant stuff
1365 */
1366#define	PARSEHSREFID	0x7f7f08ff	/* 127.127.8.255 refid for hi strata */
1367
1368#define PARSESTATISTICS   (60*60)	        /* output state statistics every hour */
1369
1370static int notice = 0;
1371
1372#define PARSE_STATETIME(parse, i) ((parse->generic->currentstatus == i) ? parse->statetime[i] + current_time - parse->lastchange : parse->statetime[i])
1373
1374static void parse_event   (struct parseunit *, int);
1375static void parse_process (struct parseunit *, parsetime_t *);
1376static void clear_err     (struct parseunit *, u_long);
1377static int  list_err      (struct parseunit *, u_long);
1378static char * l_mktime    (u_long);
1379
1380/**===========================================================================
1381 ** implementation error message regression module
1382 **/
1383static void
1384clear_err(
1385	struct parseunit *parse,
1386	u_long            lstate
1387	)
1388{
1389	if (lstate == ERR_ALL)
1390	{
1391		int i;
1392
1393		for (i = 0; i < ERR_CNT; i++)
1394		{
1395			parse->errors[i].err_stage   = err_tbl[i];
1396			parse->errors[i].err_cnt     = 0;
1397			parse->errors[i].err_last    = 0;
1398			parse->errors[i].err_started = 0;
1399			parse->errors[i].err_suppressed = 0;
1400		}
1401	}
1402	else
1403	{
1404		parse->errors[lstate].err_stage   = err_tbl[lstate];
1405		parse->errors[lstate].err_cnt     = 0;
1406		parse->errors[lstate].err_last    = 0;
1407		parse->errors[lstate].err_started = 0;
1408		parse->errors[lstate].err_suppressed = 0;
1409	}
1410}
1411
1412static int
1413list_err(
1414	struct parseunit *parse,
1415	u_long            lstate
1416	)
1417{
1418	int do_it;
1419	struct errorinfo *err = &parse->errors[lstate];
1420
1421	if (err->err_started == 0)
1422	{
1423		err->err_started = current_time;
1424	}
1425
1426	do_it = (current_time - err->err_last) >= err->err_stage->err_delay;
1427
1428	if (do_it)
1429	    err->err_cnt++;
1430
1431	if (err->err_stage->err_count &&
1432	    (err->err_cnt >= err->err_stage->err_count))
1433	{
1434		err->err_stage++;
1435		err->err_cnt = 0;
1436	}
1437
1438	if (!err->err_cnt && do_it)
1439	    msyslog(LOG_INFO, "PARSE receiver #%d: interval for following error message class is at least %s",
1440		    CLK_UNIT(parse->peer), l_mktime(err->err_stage->err_delay));
1441
1442	if (!do_it)
1443	    err->err_suppressed++;
1444	else
1445	    err->err_last = current_time;
1446
1447	if (do_it && err->err_suppressed)
1448	{
1449		msyslog(LOG_INFO, "PARSE receiver #%d: %ld message%s suppressed, error condition class persists for %s",
1450			CLK_UNIT(parse->peer), err->err_suppressed, (err->err_suppressed == 1) ? " was" : "s where",
1451			l_mktime(current_time - err->err_started));
1452		err->err_suppressed = 0;
1453	}
1454
1455	return do_it;
1456}
1457
1458/*--------------------------------------------------
1459 * mkreadable - make a printable ascii string (without
1460 * embedded quotes so that the ntpq protocol isn't
1461 * fooled
1462 */
1463#ifndef isprint
1464#define isprint(_X_) (((_X_) > 0x1F) && ((_X_) < 0x7F))
1465#endif
1466
1467static char *
1468mkreadable(
1469	char  *buffer,
1470	long  blen,
1471	const char  *src,
1472	u_long  srclen,
1473	int hex
1474	)
1475{
1476	char *b    = buffer;
1477	char *endb = (char *)0;
1478
1479	if (blen < 4)
1480		return (char *)0;		/* don't bother with mini buffers */
1481
1482	endb = buffer + blen - 4;
1483
1484	blen--;			/* account for '\0' */
1485
1486	while (blen && srclen--)
1487	{
1488		if (!hex &&             /* no binary only */
1489		    (*src != '\\') &&   /* no plain \ */
1490		    (*src != '"') &&    /* no " */
1491		    isprint((int)*src))	/* only printables */
1492		{			/* they are easy... */
1493			*buffer++ = *src++;
1494			blen--;
1495		}
1496		else
1497		{
1498			if (blen < 4)
1499			{
1500				while (blen--)
1501				{
1502					*buffer++ = '.';
1503				}
1504				*buffer = '\0';
1505				return b;
1506			}
1507			else
1508			{
1509				if (*src == '\\')
1510				{
1511					strcpy(buffer,"\\\\");
1512					buffer += 2;
1513					blen   -= 2;
1514					src++;
1515				}
1516				else
1517				{
1518					sprintf(buffer, "\\x%02x", *src++);
1519					blen   -= 4;
1520					buffer += 4;
1521				}
1522			}
1523		}
1524		if (srclen && !blen && endb) /* overflow - set last chars to ... */
1525			strcpy(endb, "...");
1526	}
1527
1528	*buffer = '\0';
1529	return b;
1530}
1531
1532
1533/*--------------------------------------------------
1534 * mkascii - make a printable ascii string
1535 * assumes (unless defined better) 7-bit ASCII
1536 */
1537static char *
1538mkascii(
1539	char  *buffer,
1540	long  blen,
1541	const char  *src,
1542	u_long  srclen
1543	)
1544{
1545	return mkreadable(buffer, blen, src, srclen, 0);
1546}
1547
1548/**===========================================================================
1549 ** implementation of i/o handling methods
1550 ** (all STREAM, partial STREAM, user level)
1551 **/
1552
1553/*
1554 * define possible io handling methods
1555 */
1556#ifdef STREAM
1557static int  ppsclock_init   (struct parseunit *);
1558static int  stream_init     (struct parseunit *);
1559static void stream_end      (struct parseunit *);
1560static int  stream_enable   (struct parseunit *);
1561static int  stream_disable  (struct parseunit *);
1562static int  stream_setcs    (struct parseunit *, parsectl_t *);
1563static int  stream_getfmt   (struct parseunit *, parsectl_t *);
1564static int  stream_setfmt   (struct parseunit *, parsectl_t *);
1565static int  stream_timecode (struct parseunit *, parsectl_t *);
1566static void stream_receive  (struct recvbuf *);
1567#endif
1568
1569static int  local_init     (struct parseunit *);
1570static void local_end      (struct parseunit *);
1571static int  local_nop      (struct parseunit *);
1572static int  local_setcs    (struct parseunit *, parsectl_t *);
1573static int  local_getfmt   (struct parseunit *, parsectl_t *);
1574static int  local_setfmt   (struct parseunit *, parsectl_t *);
1575static int  local_timecode (struct parseunit *, parsectl_t *);
1576static void local_receive  (struct recvbuf *);
1577static int  local_input    (struct recvbuf *);
1578
1579static bind_t io_bindings[] =
1580{
1581#ifdef STREAM
1582	{
1583		"parse STREAM",
1584		stream_init,
1585		stream_end,
1586		stream_setcs,
1587		stream_disable,
1588		stream_enable,
1589		stream_getfmt,
1590		stream_setfmt,
1591		stream_timecode,
1592		stream_receive,
1593		0,
1594	},
1595	{
1596		"ppsclock STREAM",
1597		ppsclock_init,
1598		local_end,
1599		local_setcs,
1600		local_nop,
1601		local_nop,
1602		local_getfmt,
1603		local_setfmt,
1604		local_timecode,
1605		local_receive,
1606		local_input,
1607	},
1608#endif
1609	{
1610		"normal",
1611		local_init,
1612		local_end,
1613		local_setcs,
1614		local_nop,
1615		local_nop,
1616		local_getfmt,
1617		local_setfmt,
1618		local_timecode,
1619		local_receive,
1620		local_input,
1621	},
1622	{
1623		(char *)0,
1624	}
1625};
1626
1627#ifdef STREAM
1628
1629#define fix_ts(_X_) \
1630                        if ((&(_X_))->tv.tv_usec >= 1000000)                \
1631                          {                                                 \
1632			    (&(_X_))->tv.tv_usec -= 1000000;                \
1633			    (&(_X_))->tv.tv_sec  += 1;                      \
1634			  }
1635
1636#define cvt_ts(_X_, _Y_) \
1637                        {                                                   \
1638			  l_fp ts;				            \
1639			  fix_ts((_X_));                                    \
1640			  if (!buftvtots((const char *)&(&(_X_))->tv, &ts)) \
1641			    {                                               \
1642                              ERR(ERR_BADDATA)	 		            \
1643                                msyslog(LOG_ERR,"parse: stream_receive: timestamp conversion error (buftvtots) (%s) (%ld.%06ld) ", (_Y_), (long)(&(_X_))->tv.tv_sec, (long)(&(_X_))->tv.tv_usec);\
1644			      return;                                       \
1645			    }                                               \
1646			  else                                              \
1647			    {                                               \
1648			      (&(_X_))->fp = ts;                            \
1649			    }                                               \
1650		        }
1651
1652/*--------------------------------------------------
1653 * ppsclock STREAM init
1654 */
1655static int
1656ppsclock_init(
1657	struct parseunit *parse
1658	)
1659{
1660        static char m1[] = "ppsclocd";
1661	static char m2[] = "ppsclock";
1662
1663	/*
1664	 * now push the parse streams module
1665	 * it will ensure exclusive access to the device
1666	 */
1667	if (ioctl(parse->ppsfd, I_PUSH, (caddr_t)m1) == -1 &&
1668	    ioctl(parse->ppsfd, I_PUSH, (caddr_t)m2) == -1)
1669	{
1670		if (errno != EINVAL)
1671		{
1672			msyslog(LOG_ERR, "PARSE receiver #%d: ppsclock_init: ioctl(fd, I_PUSH, \"ppsclock\"): %m",
1673				CLK_UNIT(parse->peer));
1674		}
1675		return 0;
1676	}
1677	if (!local_init(parse))
1678	{
1679		(void)ioctl(parse->ppsfd, I_POP, (caddr_t)0);
1680		return 0;
1681	}
1682
1683	parse->flags |= PARSE_PPSCLOCK;
1684	return 1;
1685}
1686
1687/*--------------------------------------------------
1688 * parse STREAM init
1689 */
1690static int
1691stream_init(
1692	struct parseunit *parse
1693	)
1694{
1695	static char m1[] = "parse";
1696	/*
1697	 * now push the parse streams module
1698	 * to test whether it is there (neat interface 8-( )
1699	 */
1700	if (ioctl(parse->generic->io.fd, I_PUSH, (caddr_t)m1) == -1)
1701	{
1702		if (errno != EINVAL) /* accept non-existence */
1703		{
1704			msyslog(LOG_ERR, "PARSE receiver #%d: stream_init: ioctl(fd, I_PUSH, \"parse\"): %m", CLK_UNIT(parse->peer));
1705		}
1706		return 0;
1707	}
1708	else
1709	{
1710		while(ioctl(parse->generic->io.fd, I_POP, (caddr_t)0) == 0)
1711		    /* empty loop */;
1712
1713		/*
1714		 * now push it a second time after we have removed all
1715		 * module garbage
1716		 */
1717		if (ioctl(parse->generic->io.fd, I_PUSH, (caddr_t)m1) == -1)
1718		{
1719			msyslog(LOG_ERR, "PARSE receiver #%d: stream_init: ioctl(fd, I_PUSH, \"parse\"): %m", CLK_UNIT(parse->peer));
1720			return 0;
1721		}
1722		else
1723		{
1724			return 1;
1725		}
1726	}
1727}
1728
1729/*--------------------------------------------------
1730 * parse STREAM end
1731 */
1732static void
1733stream_end(
1734	struct parseunit *parse
1735	)
1736{
1737	while(ioctl(parse->generic->io.fd, I_POP, (caddr_t)0) == 0)
1738	    /* empty loop */;
1739}
1740
1741/*--------------------------------------------------
1742 * STREAM setcs
1743 */
1744static int
1745stream_setcs(
1746	struct parseunit *parse,
1747	parsectl_t  *tcl
1748	)
1749{
1750	struct strioctl strioc;
1751
1752	strioc.ic_cmd     = PARSEIOC_SETCS;
1753	strioc.ic_timout  = 0;
1754	strioc.ic_dp      = (char *)tcl;
1755	strioc.ic_len     = sizeof (*tcl);
1756
1757	if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1)
1758	{
1759		msyslog(LOG_ERR, "PARSE receiver #%d: stream_setcs: ioctl(fd, I_STR, PARSEIOC_SETCS): %m", CLK_UNIT(parse->peer));
1760		return 0;
1761	}
1762	return 1;
1763}
1764
1765/*--------------------------------------------------
1766 * STREAM enable
1767 */
1768static int
1769stream_enable(
1770	struct parseunit *parse
1771	)
1772{
1773	struct strioctl strioc;
1774
1775	strioc.ic_cmd     = PARSEIOC_ENABLE;
1776	strioc.ic_timout  = 0;
1777	strioc.ic_dp      = (char *)0;
1778	strioc.ic_len     = 0;
1779
1780	if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1)
1781	{
1782		msyslog(LOG_ERR, "PARSE receiver #%d: stream_enable: ioctl(fd, I_STR, PARSEIOC_ENABLE): %m", CLK_UNIT(parse->peer));
1783		return 0;
1784	}
1785	parse->generic->io.clock_recv = stream_receive; /* ok - parse input in kernel */
1786	return 1;
1787}
1788
1789/*--------------------------------------------------
1790 * STREAM disable
1791 */
1792static int
1793stream_disable(
1794	struct parseunit *parse
1795	)
1796{
1797	struct strioctl strioc;
1798
1799	strioc.ic_cmd     = PARSEIOC_DISABLE;
1800	strioc.ic_timout  = 0;
1801	strioc.ic_dp      = (char *)0;
1802	strioc.ic_len     = 0;
1803
1804	if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1)
1805	{
1806		msyslog(LOG_ERR, "PARSE receiver #%d: stream_disable: ioctl(fd, I_STR, PARSEIOC_DISABLE): %m", CLK_UNIT(parse->peer));
1807		return 0;
1808	}
1809	parse->generic->io.clock_recv = local_receive; /* ok - parse input in daemon */
1810	return 1;
1811}
1812
1813/*--------------------------------------------------
1814 * STREAM getfmt
1815 */
1816static int
1817stream_getfmt(
1818	struct parseunit *parse,
1819	parsectl_t  *tcl
1820	)
1821{
1822	struct strioctl strioc;
1823
1824	strioc.ic_cmd     = PARSEIOC_GETFMT;
1825	strioc.ic_timout  = 0;
1826	strioc.ic_dp      = (char *)tcl;
1827	strioc.ic_len     = sizeof (*tcl);
1828	if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1)
1829	{
1830		msyslog(LOG_ERR, "PARSE receiver #%d: ioctl(fd, I_STR, PARSEIOC_GETFMT): %m", CLK_UNIT(parse->peer));
1831		return 0;
1832	}
1833	return 1;
1834}
1835
1836/*--------------------------------------------------
1837 * STREAM setfmt
1838 */
1839static int
1840stream_setfmt(
1841	struct parseunit *parse,
1842	parsectl_t  *tcl
1843	)
1844{
1845	struct strioctl strioc;
1846
1847	strioc.ic_cmd     = PARSEIOC_SETFMT;
1848	strioc.ic_timout  = 0;
1849	strioc.ic_dp      = (char *)tcl;
1850	strioc.ic_len     = sizeof (*tcl);
1851
1852	if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1)
1853	{
1854		msyslog(LOG_ERR, "PARSE receiver #%d: stream_setfmt: ioctl(fd, I_STR, PARSEIOC_SETFMT): %m", CLK_UNIT(parse->peer));
1855		return 0;
1856	}
1857	return 1;
1858}
1859
1860
1861/*--------------------------------------------------
1862 * STREAM timecode
1863 */
1864static int
1865stream_timecode(
1866	struct parseunit *parse,
1867	parsectl_t  *tcl
1868	)
1869{
1870	struct strioctl strioc;
1871
1872	strioc.ic_cmd     = PARSEIOC_TIMECODE;
1873	strioc.ic_timout  = 0;
1874	strioc.ic_dp      = (char *)tcl;
1875	strioc.ic_len     = sizeof (*tcl);
1876
1877	if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1)
1878	{
1879		ERR(ERR_INTERNAL)
1880			msyslog(LOG_ERR, "PARSE receiver #%d: stream_timecode: ioctl(fd, I_STR, PARSEIOC_TIMECODE): %m", CLK_UNIT(parse->peer));
1881		return 0;
1882	}
1883	clear_err(parse, ERR_INTERNAL);
1884	return 1;
1885}
1886
1887/*--------------------------------------------------
1888 * STREAM receive
1889 */
1890static void
1891stream_receive(
1892	struct recvbuf *rbufp
1893	)
1894{
1895	struct parseunit *parse = (struct parseunit *)((void *)rbufp->recv_srcclock);
1896	parsetime_t parsetime;
1897
1898	if (!parse->peer)
1899	    return;
1900
1901	if (rbufp->recv_length != sizeof(parsetime_t))
1902	{
1903		ERR(ERR_BADIO)
1904			msyslog(LOG_ERR,"PARSE receiver #%d: stream_receive: bad size (got %d expected %d)",
1905				CLK_UNIT(parse->peer), rbufp->recv_length, (int)sizeof(parsetime_t));
1906		parse_event(parse, CEVNT_BADREPLY);
1907		return;
1908	}
1909	clear_err(parse, ERR_BADIO);
1910
1911	memmove((caddr_t)&parsetime,
1912		(caddr_t)rbufp->recv_buffer,
1913		sizeof(parsetime_t));
1914
1915#ifdef DEBUG
1916	if (debug > 3)
1917	  {
1918	    printf("PARSE receiver #%d: status %06x, state %08x, time %lx.%08lx, stime %lx.%08lx, ptime %lx.%08lx\n",
1919		   CLK_UNIT(parse->peer),
1920		   (unsigned int)parsetime.parse_status,
1921		   (unsigned int)parsetime.parse_state,
1922		   (unsigned long)parsetime.parse_time.tv.tv_sec,
1923		   (unsigned long)parsetime.parse_time.tv.tv_usec,
1924		   (unsigned long)parsetime.parse_stime.tv.tv_sec,
1925		   (unsigned long)parsetime.parse_stime.tv.tv_usec,
1926		   (unsigned long)parsetime.parse_ptime.tv.tv_sec,
1927		   (unsigned long)parsetime.parse_ptime.tv.tv_usec);
1928	  }
1929#endif
1930
1931	/*
1932	 * switch time stamp world - be sure to normalize small usec field
1933	 * errors.
1934	 */
1935
1936	cvt_ts(parsetime.parse_stime, "parse_stime");
1937
1938	if (PARSE_TIMECODE(parsetime.parse_state))
1939	{
1940	    cvt_ts(parsetime.parse_time, "parse_time");
1941	}
1942
1943	if (PARSE_PPS(parsetime.parse_state))
1944	    cvt_ts(parsetime.parse_ptime, "parse_ptime");
1945
1946	parse_process(parse, &parsetime);
1947}
1948#endif
1949
1950/*--------------------------------------------------
1951 * local init
1952 */
1953static int
1954local_init(
1955	struct parseunit *parse
1956	)
1957{
1958	return parse_ioinit(&parse->parseio);
1959}
1960
1961/*--------------------------------------------------
1962 * local end
1963 */
1964static void
1965local_end(
1966	struct parseunit *parse
1967	)
1968{
1969	parse_ioend(&parse->parseio);
1970}
1971
1972
1973/*--------------------------------------------------
1974 * local nop
1975 */
1976static int
1977local_nop(
1978	struct parseunit *parse
1979	)
1980{
1981	return 1;
1982}
1983
1984/*--------------------------------------------------
1985 * local setcs
1986 */
1987static int
1988local_setcs(
1989	struct parseunit *parse,
1990	parsectl_t  *tcl
1991	)
1992{
1993	return parse_setcs(tcl, &parse->parseio);
1994}
1995
1996/*--------------------------------------------------
1997 * local getfmt
1998 */
1999static int
2000local_getfmt(
2001	struct parseunit *parse,
2002	parsectl_t  *tcl
2003	)
2004{
2005	return parse_getfmt(tcl, &parse->parseio);
2006}
2007
2008/*--------------------------------------------------
2009 * local setfmt
2010 */
2011static int
2012local_setfmt(
2013	struct parseunit *parse,
2014	parsectl_t  *tcl
2015	)
2016{
2017	return parse_setfmt(tcl, &parse->parseio);
2018}
2019
2020/*--------------------------------------------------
2021 * local timecode
2022 */
2023static int
2024local_timecode(
2025	struct parseunit *parse,
2026	parsectl_t  *tcl
2027	)
2028{
2029	return parse_timecode(tcl, &parse->parseio);
2030}
2031
2032
2033/*--------------------------------------------------
2034 * local input
2035 */
2036static int
2037local_input(
2038	struct recvbuf *rbufp
2039	)
2040{
2041	struct parseunit *parse = (struct parseunit *)((void *)rbufp->recv_srcclock);
2042	int count;
2043	unsigned char *s;
2044	timestamp_t ts;
2045
2046	if (!parse->peer)
2047		return 0;
2048
2049	/*
2050	 * eat all characters, parsing then and feeding complete samples
2051	 */
2052	count = rbufp->recv_length;
2053	s = (unsigned char *)rbufp->recv_buffer;
2054	ts.fp = rbufp->recv_time;
2055
2056	while (count--)
2057	{
2058		if (parse_ioread(&parse->parseio, (unsigned int)(*s++), &ts))
2059		{
2060			struct recvbuf *buf;
2061
2062			/*
2063			 * got something good to eat
2064			 */
2065			if (!PARSE_PPS(parse->parseio.parse_dtime.parse_state))
2066			{
2067#ifdef HAVE_PPSAPI
2068				if (parse->flags & PARSE_PPSCLOCK)
2069				{
2070					struct timespec pps_timeout;
2071					pps_info_t      pps_info;
2072
2073					pps_timeout.tv_sec  = 0;
2074					pps_timeout.tv_nsec = 0;
2075
2076					if (time_pps_fetch(parse->atom.handle, PPS_TSFMT_TSPEC, &pps_info,
2077							   &pps_timeout) == 0)
2078					{
2079						if (pps_info.assert_sequence + pps_info.clear_sequence != parse->ppsserial)
2080						{
2081							double dtemp;
2082
2083						        struct timespec pts;
2084							/*
2085							 * add PPS time stamp if available via ppsclock module
2086							 * and not supplied already.
2087							 */
2088							if (parse->flags & PARSE_CLEAR)
2089							  pts = pps_info.clear_timestamp;
2090							else
2091							  pts = pps_info.assert_timestamp;
2092
2093							parse->parseio.parse_dtime.parse_ptime.fp.l_ui = pts.tv_sec + JAN_1970;
2094
2095							dtemp = pts.tv_nsec / 1e9;
2096							if (dtemp < 0.) {
2097								dtemp += 1;
2098								parse->parseio.parse_dtime.parse_ptime.fp.l_ui--;
2099							}
2100							if (dtemp > 1.) {
2101								dtemp -= 1;
2102								parse->parseio.parse_dtime.parse_ptime.fp.l_ui++;
2103							}
2104							parse->parseio.parse_dtime.parse_ptime.fp.l_uf = dtemp * FRAC;
2105
2106						        parse->parseio.parse_dtime.parse_state |= PARSEB_PPS|PARSEB_S_PPS;
2107#ifdef DEBUG
2108							if (debug > 3)
2109							{
2110								printf(
2111								       "parse: local_receive: fd %d PPSAPI seq %ld - PPS %s\n",
2112								       rbufp->fd,
2113								       (long)pps_info.assert_sequence + (long)pps_info.clear_sequence,
2114								       lfptoa(&parse->parseio.parse_dtime.parse_ptime.fp, 6));
2115							}
2116#endif
2117						}
2118#ifdef DEBUG
2119						else
2120						{
2121							if (debug > 3)
2122							{
2123								printf(
2124								       "parse: local_receive: fd %d PPSAPI seq assert %ld, seq clear %ld - NO PPS event\n",
2125								       rbufp->fd,
2126								       (long)pps_info.assert_sequence, (long)pps_info.clear_sequence);
2127							}
2128						}
2129#endif
2130						parse->ppsserial = pps_info.assert_sequence + pps_info.clear_sequence;
2131					}
2132#ifdef DEBUG
2133					else
2134					{
2135						if (debug > 3)
2136						{
2137							printf(
2138							       "parse: local_receive: fd %d PPSAPI time_pps_fetch errno = %d\n",
2139							       rbufp->fd,
2140							       errno);
2141						}
2142					}
2143#endif
2144				}
2145#else
2146#ifdef TIOCDCDTIMESTAMP
2147				struct timeval dcd_time;
2148
2149				if (ioctl(parse->ppsfd, TIOCDCDTIMESTAMP, &dcd_time) != -1)
2150				{
2151					l_fp tstmp;
2152
2153					TVTOTS(&dcd_time, &tstmp);
2154					tstmp.l_ui += JAN_1970;
2155					L_SUB(&ts.fp, &tstmp);
2156					if (ts.fp.l_ui == 0)
2157					{
2158#ifdef DEBUG
2159						if (debug)
2160						{
2161							printf(
2162							       "parse: local_receive: fd %d DCDTIMESTAMP %s\n",
2163							       parse->ppsfd,
2164							       lfptoa(&tstmp, 6));
2165							printf(" sigio %s\n",
2166							       lfptoa(&ts.fp, 6));
2167						}
2168#endif
2169						parse->parseio.parse_dtime.parse_ptime.fp = tstmp;
2170						parse->parseio.parse_dtime.parse_state |= PARSEB_PPS|PARSEB_S_PPS;
2171					}
2172				}
2173#else /* TIOCDCDTIMESTAMP */
2174#if defined(HAVE_STRUCT_PPSCLOCKEV) && (defined(HAVE_CIOGETEV) || defined(HAVE_TIOCGPPSEV))
2175				if (parse->flags & PARSE_PPSCLOCK)
2176				  {
2177				    l_fp tts;
2178				    struct ppsclockev ev;
2179
2180#ifdef HAVE_CIOGETEV
2181				    if (ioctl(parse->ppsfd, CIOGETEV, (caddr_t)&ev) == 0)
2182#endif
2183#ifdef HAVE_TIOCGPPSEV
2184				    if (ioctl(parse->ppsfd, TIOCGPPSEV, (caddr_t)&ev) == 0)
2185#endif
2186					{
2187					  if (ev.serial != parse->ppsserial)
2188					    {
2189					      /*
2190					       * add PPS time stamp if available via ppsclock module
2191					       * and not supplied already.
2192					       */
2193					      if (!buftvtots((const char *)&ev.tv, &tts))
2194						{
2195						  ERR(ERR_BADDATA)
2196						    msyslog(LOG_ERR,"parse: local_receive: timestamp conversion error (buftvtots) (ppsclockev.tv)");
2197						}
2198					      else
2199						{
2200						  parse->parseio.parse_dtime.parse_ptime.fp = tts;
2201						  parse->parseio.parse_dtime.parse_state |= PARSEB_PPS|PARSEB_S_PPS;
2202						}
2203					    }
2204					  parse->ppsserial = ev.serial;
2205					}
2206				  }
2207#endif
2208#endif /* TIOCDCDTIMESTAMP */
2209#endif /* !HAVE_PPSAPI */
2210			}
2211			if (count)
2212			{	/* simulate receive */
2213				buf = get_free_recv_buffer();
2214				if (buf != NULL) {
2215					memmove((caddr_t)buf->recv_buffer,
2216						(caddr_t)&parse->parseio.parse_dtime,
2217						sizeof(parsetime_t));
2218					buf->recv_length  = sizeof(parsetime_t);
2219					buf->recv_time    = rbufp->recv_time;
2220					buf->srcadr       = rbufp->srcadr;
2221					buf->dstadr       = rbufp->dstadr;
2222					buf->receiver     = rbufp->receiver;
2223					buf->fd           = rbufp->fd;
2224					buf->X_from_where = rbufp->X_from_where;
2225					add_full_recv_buffer(buf);
2226				}
2227				parse_iodone(&parse->parseio);
2228			}
2229			else
2230			{
2231				memmove((caddr_t)rbufp->recv_buffer,
2232					(caddr_t)&parse->parseio.parse_dtime,
2233					sizeof(parsetime_t));
2234				parse_iodone(&parse->parseio);
2235				rbufp->recv_length = sizeof(parsetime_t);
2236				return 1; /* got something & in place return */
2237			}
2238		}
2239	}
2240	return 0;		/* nothing to pass up */
2241}
2242
2243/*--------------------------------------------------
2244 * local receive
2245 */
2246static void
2247local_receive(
2248	struct recvbuf *rbufp
2249	)
2250{
2251	struct parseunit *parse = (struct parseunit *)((void *)rbufp->recv_srcclock);
2252	parsetime_t parsetime;
2253
2254	if (!parse->peer)
2255	    return;
2256
2257	if (rbufp->recv_length != sizeof(parsetime_t))
2258	{
2259		ERR(ERR_BADIO)
2260			msyslog(LOG_ERR,"PARSE receiver #%d: local_receive: bad size (got %d expected %d)",
2261				CLK_UNIT(parse->peer), rbufp->recv_length, (int)sizeof(parsetime_t));
2262		parse_event(parse, CEVNT_BADREPLY);
2263		return;
2264	}
2265	clear_err(parse, ERR_BADIO);
2266
2267	memmove((caddr_t)&parsetime,
2268		(caddr_t)rbufp->recv_buffer,
2269		sizeof(parsetime_t));
2270
2271#ifdef DEBUG
2272	if (debug > 3)
2273	  {
2274	    printf("PARSE receiver #%d: status %06x, state %08x, time(fp) %lx.%08lx, stime(fp) %lx.%08lx, ptime(fp) %lx.%08lx\n",
2275		   CLK_UNIT(parse->peer),
2276		   (unsigned int)parsetime.parse_status,
2277		   (unsigned int)parsetime.parse_state,
2278		   (unsigned long)parsetime.parse_time.fp.l_ui,
2279		   (unsigned long)parsetime.parse_time.fp.l_uf,
2280		   (unsigned long)parsetime.parse_stime.fp.l_ui,
2281		   (unsigned long)parsetime.parse_stime.fp.l_uf,
2282		   (unsigned long)parsetime.parse_ptime.fp.l_ui,
2283		   (unsigned long)parsetime.parse_ptime.fp.l_uf);
2284	  }
2285#endif
2286
2287	parse_process(parse, &parsetime);
2288}
2289
2290/*--------------------------------------------------
2291 * init_iobinding - find and initialize lower layers
2292 */
2293static bind_t *
2294init_iobinding(
2295	struct parseunit *parse
2296	)
2297{
2298  bind_t *b = io_bindings;
2299
2300	while (b->bd_description != (char *)0)
2301	{
2302		if ((*b->bd_init)(parse))
2303		{
2304			return b;
2305		}
2306		b++;
2307	}
2308	return (bind_t *)0;
2309}
2310
2311/**===========================================================================
2312 ** support routines
2313 **/
2314
2315/*--------------------------------------------------
2316 * convert a flag field to a string
2317 */
2318static char *
2319parsestate(
2320	u_long lstate,
2321	char *buffer,
2322	int size
2323	)
2324{
2325	static struct bits
2326	{
2327		u_long      bit;
2328		const char *name;
2329	} flagstrings[] =
2330	  {
2331		  { PARSEB_ANNOUNCE,   "DST SWITCH WARNING" },
2332		  { PARSEB_POWERUP,    "NOT SYNCHRONIZED" },
2333		  { PARSEB_NOSYNC,     "TIME CODE NOT CONFIRMED" },
2334		  { PARSEB_DST,        "DST" },
2335		  { PARSEB_UTC,        "UTC DISPLAY" },
2336		  { PARSEB_LEAPADD,    "LEAP ADD WARNING" },
2337		  { PARSEB_LEAPDEL,    "LEAP DELETE WARNING" },
2338		  { PARSEB_LEAPSECOND, "LEAP SECOND" },
2339		  { PARSEB_ALTERNATE,  "ALTERNATE ANTENNA" },
2340		  { PARSEB_TIMECODE,   "TIME CODE" },
2341		  { PARSEB_PPS,        "PPS" },
2342		  { PARSEB_POSITION,   "POSITION" },
2343		  { 0 }
2344	  };
2345
2346	static struct sbits
2347	{
2348		u_long      bit;
2349		const char *name;
2350	} sflagstrings[] =
2351	  {
2352		  { PARSEB_S_LEAP,     "LEAP INDICATION" },
2353		  { PARSEB_S_PPS,      "PPS SIGNAL" },
2354		  { PARSEB_S_ANTENNA,  "ANTENNA" },
2355		  { PARSEB_S_POSITION, "POSITION" },
2356		  { 0 }
2357	  };
2358	int i;
2359	char *s, *t;
2360
2361
2362	*buffer = '\0';
2363	s = t = buffer;
2364
2365	i = 0;
2366	while (flagstrings[i].bit)
2367	{
2368		if (flagstrings[i].bit & lstate)
2369		{
2370			if (s != t)
2371				strncpy(t, "; ", BUFFER_SIZES(buffer, t, size));
2372			strncat(t, flagstrings[i].name, BUFFER_SIZES(buffer, t, size));
2373			t += strlen(t);
2374		}
2375		i++;
2376	}
2377
2378	if (lstate & (PARSEB_S_LEAP|PARSEB_S_ANTENNA|PARSEB_S_PPS|PARSEB_S_POSITION))
2379	{
2380		if (s != t)
2381			strncpy(t, "; ", BUFFER_SIZES(buffer, t, size));
2382
2383		t += strlen(t);
2384
2385		strncpy(t, "(", BUFFER_SIZES(buffer, t, size));
2386
2387		s = t = t + strlen(t);
2388
2389		i = 0;
2390		while (sflagstrings[i].bit)
2391		{
2392			if (sflagstrings[i].bit & lstate)
2393			{
2394				if (t != s)
2395				{
2396					strncpy(t, "; ", BUFFER_SIZES(buffer, t, size));
2397					t += 2;
2398				}
2399
2400				strncpy(t, sflagstrings[i].name, BUFFER_SIZES(buffer, t, size));
2401				t += strlen(t);
2402			}
2403			i++;
2404		}
2405		strncpy(t, ")", BUFFER_SIZES(buffer, t, size));
2406	}
2407	return buffer;
2408}
2409
2410/*--------------------------------------------------
2411 * convert a status flag field to a string
2412 */
2413static char *
2414parsestatus(
2415	u_long lstate,
2416	char *buffer,
2417	int size
2418	)
2419{
2420	static struct bits
2421	{
2422		u_long      bit;
2423		const char *name;
2424	} flagstrings[] =
2425	  {
2426		  { CVT_OK,      "CONVERSION SUCCESSFUL" },
2427		  { CVT_NONE,    "NO CONVERSION" },
2428		  { CVT_FAIL,    "CONVERSION FAILED" },
2429		  { CVT_BADFMT,  "ILLEGAL FORMAT" },
2430		  { CVT_BADDATE, "DATE ILLEGAL" },
2431		  { CVT_BADTIME, "TIME ILLEGAL" },
2432		  { CVT_ADDITIONAL, "ADDITIONAL DATA" },
2433		  { 0 }
2434	  };
2435	int i;
2436
2437	*buffer = '\0';
2438
2439	i = 0;
2440	while (flagstrings[i].bit)
2441	{
2442		if (flagstrings[i].bit & lstate)
2443		{
2444			if (buffer[0])
2445				strncat(buffer, "; ", size);
2446			strncat(buffer, flagstrings[i].name, size);
2447		}
2448		i++;
2449	}
2450
2451	return buffer;
2452}
2453
2454/*--------------------------------------------------
2455 * convert a clock status flag field to a string
2456 */
2457static const char *
2458clockstatus(
2459	u_long lstate
2460	)
2461{
2462	static char buffer[20];
2463	static struct status
2464	{
2465		u_long      value;
2466		const char *name;
2467	} flagstrings[] =
2468	  {
2469		  { CEVNT_NOMINAL, "NOMINAL" },
2470		  { CEVNT_TIMEOUT, "NO RESPONSE" },
2471		  { CEVNT_BADREPLY,"BAD FORMAT" },
2472		  { CEVNT_FAULT,   "FAULT" },
2473		  { CEVNT_PROP,    "PROPAGATION DELAY" },
2474		  { CEVNT_BADDATE, "ILLEGAL DATE" },
2475		  { CEVNT_BADTIME, "ILLEGAL TIME" },
2476		  { (unsigned)~0L }
2477	  };
2478	int i;
2479
2480	i = 0;
2481	while (flagstrings[i].value != ~0)
2482	{
2483		if (flagstrings[i].value == lstate)
2484		{
2485			return flagstrings[i].name;
2486		}
2487		i++;
2488	}
2489
2490	snprintf(buffer, sizeof(buffer), "unknown #%ld", (u_long)lstate);
2491
2492	return buffer;
2493}
2494
2495
2496/*--------------------------------------------------
2497 * l_mktime - make representation of a relative time
2498 */
2499static char *
2500l_mktime(
2501	u_long delta
2502	)
2503{
2504	u_long tmp, m, s;
2505	static char buffer[40];
2506	char *t;
2507
2508	buffer[0] = '\0';
2509
2510	if ((tmp = delta / (60*60*24)) != 0)
2511	{
2512		snprintf(buffer, BUFFER_SIZE(buffer, buffer), "%ldd+", (u_long)tmp);
2513		delta -= tmp * 60*60*24;
2514	}
2515
2516	s = delta % 60;
2517	delta /= 60;
2518	m = delta % 60;
2519	delta /= 60;
2520
2521	t = buffer + strlen(buffer);
2522
2523	snprintf(t, BUFFER_SIZE(buffer, t), "%02d:%02d:%02d",
2524		 (int)delta, (int)m, (int)s);
2525
2526	return buffer;
2527}
2528
2529
2530/*--------------------------------------------------
2531 * parse_statistics - list summary of clock states
2532 */
2533static void
2534parse_statistics(
2535	struct parseunit *parse
2536	)
2537{
2538	int i;
2539
2540	NLOG(NLOG_CLOCKSTATIST) /* conditional if clause for conditional syslog */
2541		{
2542			msyslog(LOG_INFO, "PARSE receiver #%d: running time: %s",
2543				CLK_UNIT(parse->peer),
2544				l_mktime(current_time - parse->generic->timestarted));
2545
2546			msyslog(LOG_INFO, "PARSE receiver #%d: current status: %s",
2547				CLK_UNIT(parse->peer),
2548				clockstatus(parse->generic->currentstatus));
2549
2550			for (i = 0; i <= CEVNT_MAX; i++)
2551			{
2552				u_long s_time;
2553				u_long percent, d = current_time - parse->generic->timestarted;
2554
2555				percent = s_time = PARSE_STATETIME(parse, i);
2556
2557				while (((u_long)(~0) / 10000) < percent)
2558				{
2559					percent /= 10;
2560					d       /= 10;
2561				}
2562
2563				if (d)
2564				    percent = (percent * 10000) / d;
2565				else
2566				    percent = 10000;
2567
2568				if (s_time)
2569				    msyslog(LOG_INFO, "PARSE receiver #%d: state %18s: %13s (%3ld.%02ld%%)",
2570					    CLK_UNIT(parse->peer),
2571					    clockstatus((unsigned int)i),
2572					    l_mktime(s_time),
2573					    percent / 100, percent % 100);
2574			}
2575		}
2576}
2577
2578/*--------------------------------------------------
2579 * cparse_statistics - wrapper for statistics call
2580 */
2581static void
2582cparse_statistics(
2583        struct parseunit *parse
2584	)
2585{
2586	if (parse->laststatistic + PARSESTATISTICS < current_time)
2587		parse_statistics(parse);
2588	parse->laststatistic = current_time;
2589}
2590
2591/**===========================================================================
2592 ** ntp interface routines
2593 **/
2594
2595/*--------------------------------------------------
2596 * parse_shutdown - shut down a PARSE clock
2597 */
2598static void
2599parse_shutdown(
2600	int unit,
2601	struct peer *peer
2602	)
2603{
2604	struct parseunit *parse = (struct parseunit *)0;
2605
2606	if (peer && peer->procptr)
2607		parse = (struct parseunit *)peer->procptr->unitptr;
2608
2609	if (!parse)
2610	{
2611		/* nothing to clean up */
2612		return;
2613	}
2614
2615        if (!parse->peer)
2616	{
2617		msyslog(LOG_INFO, "PARSE receiver #%d: INTERNAL ERROR - unit already inactive - shutdown ignored", unit);
2618		return;
2619	}
2620
2621#ifdef HAVE_PPSAPI
2622	if (parse->flags & PARSE_PPSCLOCK)
2623	{
2624		(void)time_pps_destroy(parse->atom.handle);
2625	}
2626#endif
2627	if (parse->generic->io.fd != parse->ppsfd && parse->ppsfd != -1)
2628		(void)close(parse->ppsfd);  /* close separate PPS source */
2629
2630	/*
2631	 * print statistics a last time and
2632	 * stop statistics machine
2633	 */
2634	parse_statistics(parse);
2635
2636	if (parse->parse_type->cl_end)
2637	{
2638		parse->parse_type->cl_end(parse);
2639	}
2640
2641	/*
2642	 * cleanup before leaving this world
2643	 */
2644	if (parse->binding)
2645	    PARSE_END(parse);
2646
2647	/*
2648	 * Tell the I/O module to turn us off.  We're history.
2649	 */
2650	io_closeclock(&parse->generic->io);
2651
2652	free_varlist(parse->kv);
2653
2654	NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */
2655		msyslog(LOG_INFO, "PARSE receiver #%d: reference clock \"%s\" removed",
2656			CLK_UNIT(parse->peer), parse->parse_type->cl_description);
2657
2658	parse->peer = (struct peer *)0; /* unused now */
2659	peer->procptr->unitptr = (caddr_t)0;
2660	free(parse);
2661}
2662
2663#ifdef HAVE_PPSAPI
2664/*----------------------------------------
2665 * set up HARDPPS via PPSAPI
2666 */
2667static void
2668parse_hardpps(
2669	      struct parseunit *parse,
2670	      int mode
2671	      )
2672{
2673        if (parse->hardppsstate == mode)
2674	        return;
2675
2676	if (CLK_PPS(parse->peer) && (parse->flags & PARSE_PPSKERNEL)) {
2677		int	i = 0;
2678
2679		if (mode == PARSE_HARDPPS_ENABLE)
2680		        {
2681			        if (parse->flags & PARSE_CLEAR)
2682				        i = PPS_CAPTURECLEAR;
2683				else
2684				        i = PPS_CAPTUREASSERT;
2685			}
2686
2687		if (time_pps_kcbind(parse->atom.handle, PPS_KC_HARDPPS, i,
2688		    PPS_TSFMT_TSPEC) < 0) {
2689		        msyslog(LOG_ERR, "PARSE receiver #%d: time_pps_kcbind failed: %m",
2690				CLK_UNIT(parse->peer));
2691		} else {
2692		        NLOG(NLOG_CLOCKINFO)
2693		                msyslog(LOG_INFO, "PARSE receiver #%d: kernel PPS synchronisation %sabled",
2694					CLK_UNIT(parse->peer), (mode == PARSE_HARDPPS_ENABLE) ? "en" : "dis");
2695			/*
2696			 * tell the rest, that we have a kernel PPS source, iff we ever enable HARDPPS
2697			 */
2698			if (mode == PARSE_HARDPPS_ENABLE)
2699			        pps_enable = 1;
2700		}
2701	}
2702
2703	parse->hardppsstate = mode;
2704}
2705
2706/*----------------------------------------
2707 * set up PPS via PPSAPI
2708 */
2709static int
2710parse_ppsapi(
2711	     struct parseunit *parse
2712	)
2713{
2714	int cap, mode_ppsoffset;
2715	char *cp;
2716
2717	parse->flags &= ~PARSE_PPSCLOCK;
2718
2719	/*
2720	 * collect PPSAPI offset capability - should move into generic handling
2721	 */
2722	if (time_pps_getcap(parse->atom.handle, &cap) < 0) {
2723		msyslog(LOG_ERR, "PARSE receiver #%d: parse_ppsapi: time_pps_getcap failed: %m",
2724			CLK_UNIT(parse->peer));
2725
2726		return 0;
2727	}
2728
2729	/*
2730	 * initialize generic PPSAPI interface
2731	 *
2732	 * we leave out CLK_FLAG3 as time_pps_kcbind()
2733	 * is handled here for now. Ideally this should also
2734	 * be part of the generic PPSAPI interface
2735	 */
2736	if (!refclock_params(parse->flags & (CLK_FLAG1|CLK_FLAG2|CLK_FLAG4), &parse->atom))
2737		return 0;
2738
2739	/* nb. only turn things on, if someone else has turned something
2740	 *	on before we get here, leave it alone!
2741	 */
2742
2743	if (parse->flags & PARSE_CLEAR) {
2744		cp = "CLEAR";
2745		mode_ppsoffset = PPS_OFFSETCLEAR;
2746	} else {
2747		cp = "ASSERT";
2748		mode_ppsoffset = PPS_OFFSETASSERT;
2749	}
2750
2751	msyslog(LOG_INFO, "PARSE receiver #%d: initializing PPS to %s",
2752		CLK_UNIT(parse->peer), cp);
2753
2754	if (!(mode_ppsoffset & cap)) {
2755	  msyslog(LOG_WARNING, "PARSE receiver #%d: Cannot set PPS_%sCLEAR, this will increase jitter (PPS API capabilities=0x%x)",
2756		  CLK_UNIT(parse->peer), cp, cap);
2757		mode_ppsoffset = 0;
2758	} else {
2759	        if (mode_ppsoffset == PPS_OFFSETCLEAR)
2760		        {
2761			        parse->atom.pps_params.clear_offset.tv_sec = -parse->ppsphaseadjust;
2762			        parse->atom.pps_params.clear_offset.tv_nsec = -1e9*(parse->ppsphaseadjust - (long)parse->ppsphaseadjust);
2763			}
2764
2765		if (mode_ppsoffset == PPS_OFFSETASSERT)
2766	                {
2767		                parse->atom.pps_params.assert_offset.tv_sec = -parse->ppsphaseadjust;
2768				parse->atom.pps_params.assert_offset.tv_nsec = -1e9*(parse->ppsphaseadjust - (long)parse->ppsphaseadjust);
2769			}
2770	}
2771
2772	parse->atom.pps_params.mode |= mode_ppsoffset;
2773
2774	if (time_pps_setparams(parse->atom.handle, &parse->atom.pps_params) < 0) {
2775	  msyslog(LOG_ERR, "PARSE receiver #%d: FAILED set PPS parameters: %m",
2776		  CLK_UNIT(parse->peer));
2777		return 0;
2778	}
2779
2780	parse->flags |= PARSE_PPSCLOCK;
2781	return 1;
2782}
2783#else
2784#define parse_hardpps(_PARSE_, _MODE_) /* empty */
2785#endif
2786
2787/*--------------------------------------------------
2788 * parse_start - open the PARSE devices and initialize data for processing
2789 */
2790static int
2791parse_start(
2792	int sysunit,
2793	struct peer *peer
2794	)
2795{
2796	u_int unit;
2797	int fd232;
2798#ifdef HAVE_TERMIOS
2799	struct termios tio;		/* NEEDED FOR A LONG TIME ! */
2800#endif
2801#ifdef HAVE_SYSV_TTYS
2802	struct termio tio;		/* NEEDED FOR A LONG TIME ! */
2803#endif
2804	struct parseunit * parse;
2805	char parsedev[sizeof(PARSEDEVICE)+20];
2806	char parseppsdev[sizeof(PARSEPPSDEVICE)+20];
2807	parsectl_t tmp_ctl;
2808	u_int type;
2809
2810	/*
2811	 * get out Copyright information once
2812	 */
2813	if (!notice)
2814        {
2815		NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */
2816			msyslog(LOG_INFO, "NTP PARSE support: Copyright (c) 1989-2009, Frank Kardel");
2817		notice = 1;
2818	}
2819
2820	type = CLK_TYPE(peer);
2821	unit = CLK_UNIT(peer);
2822
2823	if ((type == ~0) || (parse_clockinfo[type].cl_description == (char *)0))
2824	{
2825		msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: unsupported clock type %d (max %d)",
2826			unit, CLK_REALTYPE(peer), ncltypes-1);
2827		return 0;
2828	}
2829
2830	/*
2831	 * Unit okay, attempt to open the device.
2832	 */
2833	(void) snprintf(parsedev, sizeof(parsedev), PARSEDEVICE, unit);
2834	(void) snprintf(parseppsdev, sizeof(parsedev), PARSEPPSDEVICE, unit);
2835
2836#ifndef O_NOCTTY
2837#define O_NOCTTY 0
2838#endif
2839
2840	fd232 = open(parsedev, O_RDWR | O_NOCTTY
2841#ifdef O_NONBLOCK
2842		     | O_NONBLOCK
2843#endif
2844		     , 0777);
2845
2846	if (fd232 == -1)
2847	{
2848		msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: open of %s failed: %m", unit, parsedev);
2849		return 0;
2850	}
2851
2852	parse = (struct parseunit *)emalloc(sizeof(struct parseunit));
2853
2854	memset((char *)parse, 0, sizeof(struct parseunit));
2855
2856	parse->generic = peer->procptr;	 /* link up */
2857	parse->generic->unitptr = (caddr_t)parse; /* link down */
2858
2859	/*
2860	 * Set up the structures
2861	 */
2862	parse->generic->timestarted    = current_time;
2863	parse->lastchange     = current_time;
2864
2865	parse->flags          = 0;
2866	parse->pollneeddata   = 0;
2867	parse->laststatistic  = current_time;
2868	parse->lastformat     = (unsigned short)~0;	/* assume no format known */
2869	parse->timedata.parse_status = (unsigned short)~0;	/* be sure to mark initial status change */
2870	parse->lastmissed     = 0;	/* assume got everything */
2871	parse->ppsserial      = 0;
2872	parse->ppsfd	      = -1;
2873	parse->localdata      = (void *)0;
2874	parse->localstate     = 0;
2875	parse->kv             = (struct ctl_var *)0;
2876
2877	clear_err(parse, ERR_ALL);
2878
2879	parse->parse_type     = &parse_clockinfo[type];
2880
2881	parse->maxunsync      = parse->parse_type->cl_maxunsync;
2882
2883	parse->generic->fudgetime1 = parse->parse_type->cl_basedelay;
2884
2885	parse->generic->fudgetime2 = 0.0;
2886	parse->ppsphaseadjust = parse->generic->fudgetime2;
2887
2888	parse->generic->clockdesc  = parse->parse_type->cl_description;
2889
2890	peer->rootdelay       = parse->parse_type->cl_rootdelay;
2891	peer->sstclktype      = parse->parse_type->cl_type;
2892	peer->precision       = sys_precision;
2893
2894	peer->stratum         = STRATUM_REFCLOCK;
2895
2896	if (peer->stratum <= 1)
2897	    memmove((char *)&parse->generic->refid, parse->parse_type->cl_id, 4);
2898	else
2899	    parse->generic->refid = htonl(PARSEHSREFID);
2900
2901	parse->generic->io.fd = fd232;
2902
2903	parse->peer = peer;		/* marks it also as busy */
2904
2905	/*
2906	 * configure terminal line
2907	 */
2908	if (TTY_GETATTR(fd232, &tio) == -1)
2909	{
2910		msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: tcgetattr(%d, &tio): %m", unit, fd232);
2911		parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
2912		return 0;
2913	}
2914	else
2915	{
2916#ifndef _PC_VDISABLE
2917		memset((char *)tio.c_cc, 0, sizeof(tio.c_cc));
2918#else
2919		int disablec;
2920		errno = 0;		/* pathconf can deliver -1 without changing errno ! */
2921
2922		disablec = fpathconf(parse->generic->io.fd, _PC_VDISABLE);
2923		if (disablec == -1 && errno)
2924		{
2925			msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: fpathconf(fd, _PC_VDISABLE): %m", CLK_UNIT(parse->peer));
2926			memset((char *)tio.c_cc, 0, sizeof(tio.c_cc)); /* best guess */
2927		}
2928		else
2929		    if (disablec != -1)
2930			memset((char *)tio.c_cc, disablec, sizeof(tio.c_cc));
2931#endif
2932
2933#if defined (VMIN) || defined(VTIME)
2934		if ((parse_clockinfo[type].cl_lflag & ICANON) == 0)
2935		{
2936#ifdef VMIN
2937			tio.c_cc[VMIN]   = 1;
2938#endif
2939#ifdef VTIME
2940			tio.c_cc[VTIME]  = 0;
2941#endif
2942		}
2943#endif
2944
2945		tio.c_cflag = parse_clockinfo[type].cl_cflag;
2946		tio.c_iflag = parse_clockinfo[type].cl_iflag;
2947		tio.c_oflag = parse_clockinfo[type].cl_oflag;
2948		tio.c_lflag = parse_clockinfo[type].cl_lflag;
2949
2950
2951#ifdef HAVE_TERMIOS
2952		if ((cfsetospeed(&tio, parse_clockinfo[type].cl_speed) == -1) ||
2953		    (cfsetispeed(&tio, parse_clockinfo[type].cl_speed) == -1))
2954		{
2955			msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: tcset{i,o}speed(&tio, speed): %m", unit);
2956			parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
2957			return 0;
2958		}
2959#else
2960		tio.c_cflag     |= parse_clockinfo[type].cl_speed;
2961#endif
2962
2963		/*
2964		 * set up pps device
2965		 * if the PARSEPPSDEVICE can be opened that will be used
2966		 * for PPS else PARSEDEVICE will be used
2967		 */
2968		parse->ppsfd = open(parseppsdev, O_RDWR | O_NOCTTY
2969#ifdef O_NONBLOCK
2970				    | O_NONBLOCK
2971#endif
2972				    , 0777);
2973
2974		if (parse->ppsfd == -1)
2975		{
2976			parse->ppsfd = fd232;
2977		}
2978
2979/*
2980 * Linux PPS - the old way
2981 */
2982#if defined(HAVE_TIO_SERIAL_STUFF)		/* Linux hack: define PPS interface */
2983		{
2984			struct serial_struct	ss;
2985			if (ioctl(parse->ppsfd, TIOCGSERIAL, &ss) < 0 ||
2986			    (
2987#ifdef ASYNC_LOW_LATENCY
2988			     ss.flags |= ASYNC_LOW_LATENCY,
2989#endif
2990#ifndef HAVE_PPSAPI
2991#ifdef ASYNC_PPS_CD_NEG
2992			     ss.flags |= ASYNC_PPS_CD_NEG,
2993#endif
2994#endif
2995			     ioctl(parse->ppsfd, TIOCSSERIAL, &ss)) < 0) {
2996				msyslog(LOG_NOTICE, "refclock_parse: TIOCSSERIAL fd %d, %m", parse->ppsfd);
2997				msyslog(LOG_NOTICE,
2998					"refclock_parse: optional PPS processing not available");
2999			} else {
3000				parse->flags    |= PARSE_PPSCLOCK;
3001#ifdef ASYNC_PPS_CD_NEG
3002				NLOG(NLOG_CLOCKINFO)
3003				  msyslog(LOG_INFO,
3004					  "refclock_parse: PPS detection on");
3005#endif
3006			}
3007		}
3008#endif
3009
3010/*
3011 * SUN the Solaris way
3012 */
3013#ifdef HAVE_TIOCSPPS			/* SUN PPS support */
3014		if (CLK_PPS(parse->peer))
3015		    {
3016			int i = 1;
3017
3018			if (ioctl(parse->ppsfd, TIOCSPPS, (caddr_t)&i) == 0)
3019			    {
3020				parse->flags |= PARSE_PPSCLOCK;
3021			    }
3022		    }
3023#endif
3024
3025/*
3026 * PPS via PPSAPI
3027 */
3028#if defined(HAVE_PPSAPI)
3029		parse->hardppsstate = PARSE_HARDPPS_DISABLE;
3030		if (CLK_PPS(parse->peer))
3031		{
3032		  if (!refclock_ppsapi(parse->ppsfd, &parse->atom))
3033		    {
3034		      msyslog(LOG_NOTICE, "PARSE receiver #%d: parse_start: could not set up PPS: %m", CLK_UNIT(parse->peer));
3035		    }
3036		  else
3037		    {
3038		      parse_ppsapi(parse);
3039		    }
3040		}
3041#endif
3042
3043		if (TTY_SETATTR(fd232, &tio) == -1)
3044		{
3045			msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: tcsetattr(%d, &tio): %m", unit, fd232);
3046			parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
3047			return 0;
3048		}
3049	}
3050
3051	/*
3052	 * pick correct input machine
3053	 */
3054	parse->generic->io.srcclock = (caddr_t)parse;
3055	parse->generic->io.datalen = 0;
3056
3057	parse->binding = init_iobinding(parse);
3058
3059	if (parse->binding == (bind_t *)0)
3060		{
3061			msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: io sub system initialisation failed.", CLK_UNIT(parse->peer));
3062			parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
3063			return 0;			/* well, ok - special initialisation broke */
3064		}
3065
3066	parse->generic->io.clock_recv = parse->binding->bd_receive; /* pick correct receive routine */
3067	parse->generic->io.io_input   = parse->binding->bd_io_input; /* pick correct input routine */
3068
3069	/*
3070	 * as we always(?) get 8 bit chars we want to be
3071	 * sure, that the upper bits are zero for less
3072	 * than 8 bit I/O - so we pass that information on.
3073	 * note that there can be only one bit count format
3074	 * per file descriptor
3075	 */
3076
3077	switch (tio.c_cflag & CSIZE)
3078	{
3079	    case CS5:
3080		tmp_ctl.parsesetcs.parse_cs = PARSE_IO_CS5;
3081		break;
3082
3083	    case CS6:
3084		tmp_ctl.parsesetcs.parse_cs = PARSE_IO_CS6;
3085		break;
3086
3087	    case CS7:
3088		tmp_ctl.parsesetcs.parse_cs = PARSE_IO_CS7;
3089		break;
3090
3091	    case CS8:
3092		tmp_ctl.parsesetcs.parse_cs = PARSE_IO_CS8;
3093		break;
3094	}
3095
3096	if (!PARSE_SETCS(parse, &tmp_ctl))
3097	{
3098		msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: parse_setcs() FAILED.", unit);
3099		parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
3100		return 0;			/* well, ok - special initialisation broke */
3101	}
3102
3103	strncpy(tmp_ctl.parseformat.parse_buffer, parse->parse_type->cl_format, sizeof(tmp_ctl.parseformat.parse_buffer));
3104	tmp_ctl.parseformat.parse_count = strlen(tmp_ctl.parseformat.parse_buffer);
3105
3106	if (!PARSE_SETFMT(parse, &tmp_ctl))
3107	{
3108		msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: parse_setfmt() FAILED.", unit);
3109		parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
3110		return 0;			/* well, ok - special initialisation broke */
3111	}
3112
3113	/*
3114	 * get rid of all IO accumulated so far
3115	 */
3116#ifdef HAVE_TERMIOS
3117	(void) tcflush(parse->generic->io.fd, TCIOFLUSH);
3118#else
3119#if defined(TCFLSH) && defined(TCIOFLUSH)
3120	{
3121		int flshcmd = TCIOFLUSH;
3122
3123		(void) ioctl(parse->generic->io.fd, TCFLSH, (caddr_t)&flshcmd);
3124	}
3125#endif
3126#endif
3127
3128	/*
3129	 * try to do any special initializations
3130	 */
3131	if (parse->parse_type->cl_init)
3132		{
3133			if (parse->parse_type->cl_init(parse))
3134				{
3135					parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
3136					return 0;		/* well, ok - special initialisation broke */
3137				}
3138		}
3139
3140	/*
3141	 * Insert in async io device list.
3142	 */
3143	if (!io_addclock(&parse->generic->io))
3144        {
3145		msyslog(LOG_ERR,
3146			"PARSE receiver #%d: parse_start: addclock %s fails (ABORT - clock type requires async io)", CLK_UNIT(parse->peer), parsedev);
3147		parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
3148		return 0;
3149	}
3150
3151	/*
3152	 * print out configuration
3153	 */
3154	NLOG(NLOG_CLOCKINFO)
3155		{
3156			/* conditional if clause for conditional syslog */
3157			msyslog(LOG_INFO, "PARSE receiver #%d: reference clock \"%s\" (I/O device %s, PPS device %s) added",
3158				CLK_UNIT(parse->peer),
3159				parse->parse_type->cl_description, parsedev,
3160				(parse->ppsfd != parse->generic->io.fd) ? parseppsdev : parsedev);
3161
3162			msyslog(LOG_INFO, "PARSE receiver #%d: Stratum %d, trust time %s, precision %d",
3163				CLK_UNIT(parse->peer),
3164				parse->peer->stratum,
3165				l_mktime(parse->maxunsync), parse->peer->precision);
3166
3167			msyslog(LOG_INFO, "PARSE receiver #%d: rootdelay %.6f s, phase adjustment %.6f s, PPS phase adjustment %.6f s, %s IO handling",
3168				CLK_UNIT(parse->peer),
3169				parse->parse_type->cl_rootdelay,
3170				parse->generic->fudgetime1,
3171				parse->ppsphaseadjust,
3172                                parse->binding->bd_description);
3173
3174			msyslog(LOG_INFO, "PARSE receiver #%d: Format recognition: %s", CLK_UNIT(parse->peer),
3175				parse->parse_type->cl_format);
3176                        msyslog(LOG_INFO, "PARSE receiver #%d: %sPPS support%s", CLK_UNIT(parse->peer),
3177				CLK_PPS(parse->peer) ? "" : "NO ",
3178				CLK_PPS(parse->peer) ?
3179#ifdef PPS_METHOD
3180				" (implementation " PPS_METHOD ")"
3181#else
3182				""
3183#endif
3184				: ""
3185				);
3186		}
3187
3188	return 1;
3189}
3190
3191/*--------------------------------------------------
3192 * parse_ctl - process changes on flags/time values
3193 */
3194static void
3195parse_ctl(
3196	    struct parseunit *parse,
3197	    struct refclockstat *in
3198	    )
3199{
3200        if (in)
3201	{
3202		if (in->haveflags & (CLK_HAVEFLAG1|CLK_HAVEFLAG2|CLK_HAVEFLAG3|CLK_HAVEFLAG4))
3203		{
3204		  parse->flags = (parse->flags & ~(CLK_FLAG1|CLK_FLAG2|CLK_FLAG3|CLK_FLAG4)) |
3205		    (in->flags & (CLK_FLAG1|CLK_FLAG2|CLK_FLAG3|CLK_FLAG4));
3206#if defined(HAVE_PPSAPI)
3207		  if (CLK_PPS(parse->peer))
3208		    {
3209		      parse_ppsapi(parse);
3210		    }
3211#endif
3212		}
3213
3214		if (in->haveflags & CLK_HAVETIME1)
3215                {
3216		  parse->generic->fudgetime1 = in->fudgetime1;
3217		  msyslog(LOG_INFO, "PARSE receiver #%d: new phase adjustment %.6f s",
3218			  CLK_UNIT(parse->peer),
3219			  parse->generic->fudgetime1);
3220		}
3221
3222		if (in->haveflags & CLK_HAVETIME2)
3223                {
3224		  parse->generic->fudgetime2 = in->fudgetime2;
3225		  if (parse->flags & PARSE_TRUSTTIME)
3226		    {
3227		      parse->maxunsync = (u_long)ABS(in->fudgetime2);
3228		      msyslog(LOG_INFO, "PARSE receiver #%d: new trust time %s",
3229			      CLK_UNIT(parse->peer),
3230			      l_mktime(parse->maxunsync));
3231		    }
3232		  else
3233		    {
3234		      parse->ppsphaseadjust = in->fudgetime2;
3235		      msyslog(LOG_INFO, "PARSE receiver #%d: new PPS phase adjustment %.6f s",
3236			  CLK_UNIT(parse->peer),
3237			      parse->ppsphaseadjust);
3238#if defined(HAVE_PPSAPI)
3239		      if (CLK_PPS(parse->peer))
3240		      {
3241			      parse_ppsapi(parse);
3242		      }
3243#endif
3244		    }
3245		}
3246	}
3247}
3248
3249/*--------------------------------------------------
3250 * parse_poll - called by the transmit procedure
3251 */
3252static void
3253parse_poll(
3254	int unit,
3255	struct peer *peer
3256	)
3257{
3258	struct parseunit *parse = (struct parseunit *)peer->procptr->unitptr;
3259
3260	if (peer != parse->peer)
3261	{
3262		msyslog(LOG_ERR,
3263			"PARSE receiver #%d: poll: INTERNAL: peer incorrect",
3264			unit);
3265		return;
3266	}
3267
3268	/*
3269	 * Update clock stat counters
3270	 */
3271	parse->generic->polls++;
3272
3273	if (parse->pollneeddata &&
3274	    ((current_time - parse->pollneeddata) > (1<<(max(min(parse->peer->hpoll, parse->peer->ppoll), parse->peer->minpoll)))))
3275	{
3276		/*
3277		 * start worrying when exceeding a poll inteval
3278		 * bad news - didn't get a response last time
3279		 */
3280		parse->lastmissed = current_time;
3281		parse_event(parse, CEVNT_TIMEOUT);
3282
3283		ERR(ERR_NODATA)
3284			msyslog(LOG_WARNING, "PARSE receiver #%d: no data from device within poll interval (check receiver / wiring)", CLK_UNIT(parse->peer));
3285	}
3286
3287	/*
3288	 * we just mark that we want the next sample for the clock filter
3289	 */
3290	parse->pollneeddata = current_time;
3291
3292	if (parse->parse_type->cl_poll)
3293	{
3294		parse->parse_type->cl_poll(parse);
3295	}
3296
3297	cparse_statistics(parse);
3298
3299	return;
3300}
3301
3302#define LEN_STATES 300		/* length of state string */
3303
3304/*--------------------------------------------------
3305 * parse_control - set fudge factors, return statistics
3306 */
3307static void
3308parse_control(
3309	int unit,
3310	struct refclockstat *in,
3311	struct refclockstat *out,
3312	struct peer *peer
3313	)
3314{
3315        struct parseunit *parse = (struct parseunit *)peer->procptr->unitptr;
3316	parsectl_t tmpctl;
3317
3318	static char outstatus[400];	/* status output buffer */
3319
3320	if (out)
3321	{
3322		out->lencode       = 0;
3323		out->p_lastcode    = 0;
3324		out->kv_list       = (struct ctl_var *)0;
3325	}
3326
3327	if (!parse || !parse->peer)
3328	{
3329		msyslog(LOG_ERR, "PARSE receiver #%d: parse_control: unit invalid (UNIT INACTIVE)",
3330			unit);
3331		return;
3332	}
3333
3334	unit = CLK_UNIT(parse->peer);
3335
3336	/*
3337	 * handle changes
3338	 */
3339	parse_ctl(parse, in);
3340
3341	/*
3342	 * supply data
3343	 */
3344	if (out)
3345	{
3346		u_long sum = 0;
3347		char *tt, *start;
3348		int i;
3349
3350		outstatus[0] = '\0';
3351
3352		out->type       = REFCLK_PARSE;
3353
3354		/*
3355		 * keep fudgetime2 in sync with TRUSTTIME/MAXUNSYNC flag1
3356		 */
3357		parse->generic->fudgetime2 = (parse->flags & PARSE_TRUSTTIME) ? (double)parse->maxunsync : parse->ppsphaseadjust;
3358
3359		/*
3360		 * figure out skew between PPS and RS232 - just for informational
3361		 * purposes
3362		 */
3363		if (PARSE_SYNC(parse->timedata.parse_state))
3364		{
3365			if (PARSE_PPS(parse->timedata.parse_state) && PARSE_TIMECODE(parse->timedata.parse_state))
3366			{
3367				l_fp off;
3368
3369				/*
3370				 * we have a PPS and RS232 signal - calculate the skew
3371				 * WARNING: assumes on TIMECODE == PULSE (timecode after pulse)
3372				 */
3373				off = parse->timedata.parse_stime.fp;
3374				L_SUB(&off, &parse->timedata.parse_ptime.fp); /* true offset */
3375				tt = add_var(&out->kv_list, 80, RO);
3376				snprintf(tt, 80, "refclock_ppsskew=%s", lfptoms(&off, 6));
3377			}
3378		}
3379
3380		if (PARSE_PPS(parse->timedata.parse_state))
3381		{
3382			tt = add_var(&out->kv_list, 80, RO|DEF);
3383			snprintf(tt, 80, "refclock_ppstime=\"%s\"", gmprettydate(&parse->timedata.parse_ptime.fp));
3384		}
3385
3386		start = tt = add_var(&out->kv_list, 128, RO|DEF);
3387		snprintf(tt, 128, "refclock_time=\"");
3388		tt += strlen(tt);
3389
3390		if (parse->timedata.parse_time.fp.l_ui == 0)
3391		{
3392			strncpy(tt, "<UNDEFINED>\"", BUFFER_SIZES(start, tt, 128));
3393		}
3394		else
3395		{
3396			snprintf(tt, 128, "%s\"", gmprettydate(&parse->timedata.parse_time.fp));
3397		}
3398
3399		if (!PARSE_GETTIMECODE(parse, &tmpctl))
3400		{
3401			ERR(ERR_INTERNAL)
3402				msyslog(LOG_ERR, "PARSE receiver #%d: parse_control: parse_timecode() FAILED", unit);
3403		}
3404		else
3405		{
3406			start = tt = add_var(&out->kv_list, 512, RO|DEF);
3407			snprintf(tt, 512, "refclock_status=\"");
3408			tt += strlen(tt);
3409
3410			/*
3411			 * copy PPS flags from last read transaction (informational only)
3412			 */
3413			tmpctl.parsegettc.parse_state |= parse->timedata.parse_state &
3414				(PARSEB_PPS|PARSEB_S_PPS);
3415
3416			(void) parsestate(tmpctl.parsegettc.parse_state, tt, BUFFER_SIZES(start, tt, 512));
3417
3418			strncat(tt, "\"", BUFFER_SIZES(start, tt, 512));
3419
3420			if (tmpctl.parsegettc.parse_count)
3421			    mkascii(outstatus+strlen(outstatus), (int)(sizeof(outstatus)- strlen(outstatus) - 1),
3422				    tmpctl.parsegettc.parse_buffer, (unsigned)(tmpctl.parsegettc.parse_count));
3423
3424		}
3425
3426		tmpctl.parseformat.parse_format = tmpctl.parsegettc.parse_format;
3427
3428		if (!PARSE_GETFMT(parse, &tmpctl))
3429		{
3430			ERR(ERR_INTERNAL)
3431				msyslog(LOG_ERR, "PARSE receiver #%d: parse_control: parse_getfmt() FAILED", unit);
3432		}
3433		else
3434		{
3435			tt = add_var(&out->kv_list, 80, RO|DEF);
3436			snprintf(tt, 80, "refclock_format=\"");
3437
3438			strncat(tt, tmpctl.parseformat.parse_buffer, tmpctl.parseformat.parse_count);
3439			strncat(tt,"\"", 80);
3440		}
3441
3442		/*
3443		 * gather state statistics
3444		 */
3445
3446		start = tt = add_var(&out->kv_list, LEN_STATES, RO|DEF);
3447		strncpy(tt, "refclock_states=\"", LEN_STATES);
3448		tt += strlen(tt);
3449
3450		for (i = 0; i <= CEVNT_MAX; i++)
3451		{
3452			u_long s_time;
3453			u_long d = current_time - parse->generic->timestarted;
3454			u_long percent;
3455
3456			percent = s_time = PARSE_STATETIME(parse, i);
3457
3458			while (((u_long)(~0) / 10000) < percent)
3459			{
3460				percent /= 10;
3461				d       /= 10;
3462			}
3463
3464			if (d)
3465			    percent = (percent * 10000) / d;
3466			else
3467			    percent = 10000;
3468
3469			if (s_time)
3470			{
3471				char item[80];
3472				int count;
3473
3474				snprintf(item, 80, "%s%s%s: %s (%d.%02d%%)",
3475					sum ? "; " : "",
3476					(parse->generic->currentstatus == i) ? "*" : "",
3477					clockstatus((unsigned int)i),
3478					l_mktime(s_time),
3479					(int)(percent / 100), (int)(percent % 100));
3480				if ((count = strlen(item)) < (LEN_STATES - 40 - (tt - start)))
3481					{
3482						strncpy(tt, item, BUFFER_SIZES(start, tt, LEN_STATES));
3483						tt  += count;
3484					}
3485				sum += s_time;
3486			}
3487		}
3488
3489		snprintf(tt, BUFFER_SIZES(start, tt, LEN_STATES), "; running time: %s\"", l_mktime(sum));
3490
3491		tt = add_var(&out->kv_list, 32, RO);
3492		snprintf(tt, 32,  "refclock_id=\"%s\"", parse->parse_type->cl_id);
3493
3494		tt = add_var(&out->kv_list, 80, RO);
3495		snprintf(tt, 80,  "refclock_iomode=\"%s\"", parse->binding->bd_description);
3496
3497		tt = add_var(&out->kv_list, 128, RO);
3498		snprintf(tt, 128, "refclock_driver_version=\"%s\"", rcsid);
3499
3500		{
3501			struct ctl_var *k;
3502
3503			k = parse->kv;
3504			while (k && !(k->flags & EOV))
3505			{
3506				set_var(&out->kv_list, k->text, strlen(k->text)+1, k->flags);
3507				k++;
3508			}
3509		}
3510
3511		out->lencode       = strlen(outstatus);
3512		out->p_lastcode    = outstatus;
3513	}
3514}
3515
3516/**===========================================================================
3517 ** processing routines
3518 **/
3519
3520/*--------------------------------------------------
3521 * event handling - note that nominal events will also be posted
3522 * keep track of state dwelling times
3523 */
3524static void
3525parse_event(
3526	struct parseunit *parse,
3527	int event
3528	)
3529{
3530	if (parse->generic->currentstatus != (u_char) event)
3531	{
3532		parse->statetime[parse->generic->currentstatus] += current_time - parse->lastchange;
3533		parse->lastchange              = current_time;
3534
3535		if (parse->parse_type->cl_event)
3536		    parse->parse_type->cl_event(parse, event);
3537
3538		if (event == CEVNT_NOMINAL)
3539		{
3540			NLOG(NLOG_CLOCKSTATUS)
3541				msyslog(LOG_INFO, "PARSE receiver #%d: SYNCHRONIZED",
3542					CLK_UNIT(parse->peer));
3543		}
3544
3545		refclock_report(parse->peer, event);
3546	}
3547}
3548
3549/*--------------------------------------------------
3550 * process a PARSE time sample
3551 */
3552static void
3553parse_process(
3554	struct parseunit *parse,
3555	parsetime_t      *parsetime
3556	)
3557{
3558	l_fp off, rectime, reftime;
3559	double fudge;
3560
3561	/*
3562	 * check for changes in conversion status
3563	 * (only one for each new status !)
3564	 */
3565	if (((parsetime->parse_status & CVT_MASK) != CVT_OK) &&
3566	    ((parsetime->parse_status & CVT_MASK) != CVT_NONE) &&
3567	    (parse->timedata.parse_status != parsetime->parse_status))
3568	{
3569		char buffer[400];
3570
3571		NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */
3572			msyslog(LOG_WARNING, "PARSE receiver #%d: conversion status \"%s\"",
3573				CLK_UNIT(parse->peer), parsestatus(parsetime->parse_status, buffer, sizeof(buffer)));
3574
3575		if ((parsetime->parse_status & CVT_MASK) == CVT_FAIL)
3576		{
3577			/*
3578			 * tell more about the story - list time code
3579			 * there is a slight change for a race condition and
3580			 * the time code might be overwritten by the next packet
3581			 */
3582			parsectl_t tmpctl;
3583
3584			if (!PARSE_GETTIMECODE(parse, &tmpctl))
3585			{
3586				ERR(ERR_INTERNAL)
3587					msyslog(LOG_ERR, "PARSE receiver #%d: parse_process: parse_timecode() FAILED", CLK_UNIT(parse->peer));
3588			}
3589			else
3590			{
3591				ERR(ERR_BADDATA)
3592					msyslog(LOG_WARNING, "PARSE receiver #%d: FAILED TIMECODE: \"%s\" (check receiver configuration / wiring)",
3593						CLK_UNIT(parse->peer), mkascii(buffer, sizeof buffer, tmpctl.parsegettc.parse_buffer, (unsigned)(tmpctl.parsegettc.parse_count - 1)));
3594			}
3595		}
3596	}
3597
3598	/*
3599	 * examine status and post appropriate events
3600	 */
3601	if ((parsetime->parse_status & CVT_MASK) != CVT_OK)
3602	{
3603		/*
3604		 * got bad data - tell the rest of the system
3605		 */
3606		switch (parsetime->parse_status & CVT_MASK)
3607		{
3608		case CVT_NONE:
3609			if ((parsetime->parse_status & CVT_ADDITIONAL) &&
3610			    parse->parse_type->cl_message)
3611				parse->parse_type->cl_message(parse, parsetime);
3612			/*
3613			 * save PPS information that comes piggyback
3614			 */
3615			if (PARSE_PPS(parsetime->parse_state))
3616			  {
3617			    parse->timedata.parse_state |= PARSEB_PPS|PARSEB_S_PPS;
3618			    parse->timedata.parse_ptime  = parsetime->parse_ptime;
3619			  }
3620			break; 		/* well, still waiting - timeout is handled at higher levels */
3621
3622		case CVT_FAIL:
3623			if (parsetime->parse_status & CVT_BADFMT)
3624			{
3625				parse_event(parse, CEVNT_BADREPLY);
3626			}
3627			else
3628				if (parsetime->parse_status & CVT_BADDATE)
3629				{
3630					parse_event(parse, CEVNT_BADDATE);
3631				}
3632				else
3633					if (parsetime->parse_status & CVT_BADTIME)
3634					{
3635						parse_event(parse, CEVNT_BADTIME);
3636					}
3637					else
3638					{
3639						parse_event(parse, CEVNT_BADREPLY); /* for the lack of something better */
3640					}
3641		}
3642		return;			/* skip the rest - useless */
3643	}
3644
3645	/*
3646	 * check for format changes
3647	 * (in case somebody has swapped clocks 8-)
3648	 */
3649	if (parse->lastformat != parsetime->parse_format)
3650	{
3651		parsectl_t tmpctl;
3652
3653		tmpctl.parseformat.parse_format = parsetime->parse_format;
3654
3655		if (!PARSE_GETFMT(parse, &tmpctl))
3656		{
3657			ERR(ERR_INTERNAL)
3658				msyslog(LOG_ERR, "PARSE receiver #%d: parse_getfmt() FAILED", CLK_UNIT(parse->peer));
3659		}
3660		else
3661		{
3662			NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */
3663				msyslog(LOG_INFO, "PARSE receiver #%d: packet format \"%s\"",
3664					CLK_UNIT(parse->peer), tmpctl.parseformat.parse_buffer);
3665		}
3666		parse->lastformat = parsetime->parse_format;
3667	}
3668
3669	/*
3670	 * now, any changes ?
3671	 */
3672	if ((parse->timedata.parse_state ^ parsetime->parse_state) &
3673	    ~(unsigned)(PARSEB_PPS|PARSEB_S_PPS))
3674	{
3675		char tmp1[200];
3676		char tmp2[200];
3677		/*
3678		 * something happend - except for PPS events
3679		 */
3680
3681		(void) parsestate(parsetime->parse_state, tmp1, sizeof(tmp1));
3682		(void) parsestate(parse->timedata.parse_state, tmp2, sizeof(tmp2));
3683
3684		NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */
3685			msyslog(LOG_INFO,"PARSE receiver #%d: STATE CHANGE: %s -> %s",
3686				CLK_UNIT(parse->peer), tmp2, tmp1);
3687	}
3688
3689	/*
3690	 * carry on PPS information if still usable
3691	 */
3692	if (PARSE_PPS(parse->timedata.parse_state) && !PARSE_PPS(parsetime->parse_state))
3693        {
3694	        parsetime->parse_state |= PARSEB_PPS|PARSEB_S_PPS;
3695		parsetime->parse_ptime  = parse->timedata.parse_ptime;
3696	}
3697
3698	/*
3699	 * remember for future
3700	 */
3701	parse->timedata = *parsetime;
3702
3703	/*
3704	 * check to see, whether the clock did a complete powerup or lost PZF signal
3705	 * and post correct events for current condition
3706	 */
3707	if (PARSE_POWERUP(parsetime->parse_state))
3708	{
3709		/*
3710		 * this is bad, as we have completely lost synchronisation
3711		 * well this is a problem with the receiver here
3712		 * for PARSE Meinberg DCF77 receivers the lost synchronisation
3713		 * is true as it is the powerup state and the time is taken
3714		 * from a crude real time clock chip
3715		 * for the PZF series this is only partly true, as
3716		 * PARSE_POWERUP only means that the pseudo random
3717		 * phase shift sequence cannot be found. this is only
3718		 * bad, if we have never seen the clock in the SYNC
3719		 * state, where the PHASE and EPOCH are correct.
3720		 * for reporting events the above business does not
3721		 * really matter, but we can use the time code
3722		 * even in the POWERUP state after having seen
3723		 * the clock in the synchronized state (PZF class
3724		 * receivers) unless we have had a telegram disruption
3725		 * after having seen the clock in the SYNC state. we
3726		 * thus require having seen the clock in SYNC state
3727		 * *after* having missed telegrams (noresponse) from
3728		 * the clock. one problem remains: we might use erroneously
3729		 * POWERUP data if the disruption is shorter than 1 polling
3730		 * interval. fortunately powerdowns last usually longer than 64
3731		 * seconds and the receiver is at least 2 minutes in the
3732		 * POWERUP or NOSYNC state before switching to SYNC
3733		 */
3734		parse_event(parse, CEVNT_FAULT);
3735		NLOG(NLOG_CLOCKSTATUS)
3736			ERR(ERR_BADSTATUS)
3737			msyslog(LOG_ERR,"PARSE receiver #%d: NOT SYNCHRONIZED",
3738				CLK_UNIT(parse->peer));
3739	}
3740	else
3741	{
3742		/*
3743		 * we have two states left
3744		 *
3745		 * SYNC:
3746		 *  this state means that the EPOCH (timecode) and PHASE
3747		 *  information has be read correctly (at least two
3748		 *  successive PARSE timecodes were received correctly)
3749		 *  this is the best possible state - full trust
3750		 *
3751		 * NOSYNC:
3752		 *  The clock should be on phase with respect to the second
3753		 *  signal, but the timecode has not been received correctly within
3754		 *  at least the last two minutes. this is a sort of half baked state
3755		 *  for PARSE Meinberg DCF77 clocks this is bad news (clock running
3756		 *  without timecode confirmation)
3757		 *  PZF 535 has also no time confirmation, but the phase should be
3758		 *  very precise as the PZF signal can be decoded
3759		 */
3760
3761		if (PARSE_SYNC(parsetime->parse_state))
3762		{
3763			/*
3764			 * currently completely synchronized - best possible state
3765			 */
3766			parse->lastsync = current_time;
3767			clear_err(parse, ERR_BADSTATUS);
3768		}
3769		else
3770		{
3771			/*
3772			 * we have had some problems receiving the time code
3773			 */
3774			parse_event(parse, CEVNT_PROP);
3775			NLOG(NLOG_CLOCKSTATUS)
3776				ERR(ERR_BADSTATUS)
3777				msyslog(LOG_ERR,"PARSE receiver #%d: TIMECODE NOT CONFIRMED",
3778					CLK_UNIT(parse->peer));
3779		}
3780	}
3781
3782	fudge = parse->generic->fudgetime1; /* standard RS232 Fudgefactor */
3783
3784	if (PARSE_TIMECODE(parsetime->parse_state))
3785	{
3786		rectime = parsetime->parse_stime.fp;
3787		off = reftime = parsetime->parse_time.fp;
3788
3789		L_SUB(&off, &rectime); /* prepare for PPS adjustments logic */
3790
3791#ifdef DEBUG
3792		if (debug > 3)
3793			printf("PARSE receiver #%d: Reftime %s, Recvtime %s - initial offset %s\n",
3794			       CLK_UNIT(parse->peer),
3795			       prettydate(&reftime),
3796			       prettydate(&rectime),
3797			       lfptoa(&off,6));
3798#endif
3799	}
3800
3801	if (PARSE_PPS(parsetime->parse_state) && CLK_PPS(parse->peer))
3802	{
3803		l_fp offset;
3804		double ppsphaseadjust = parse->ppsphaseadjust;
3805
3806#ifdef HAVE_PPSAPI
3807		/*
3808		 * set fudge = 0.0 if already included in PPS time stamps
3809		 */
3810		if (parse->atom.pps_params.mode & (PPS_OFFSETCLEAR|PPS_OFFSETASSERT))
3811		        {
3812			        ppsphaseadjust = 0.0;
3813			}
3814#endif
3815
3816		/*
3817		 * we have a PPS signal - much better than the RS232 stuff (we hope)
3818		 */
3819		offset = parsetime->parse_ptime.fp;
3820
3821#ifdef DEBUG
3822		if (debug > 3)
3823			printf("PARSE receiver #%d: PPStime %s\n",
3824				CLK_UNIT(parse->peer),
3825				prettydate(&offset));
3826#endif
3827		if (PARSE_TIMECODE(parsetime->parse_state))
3828		{
3829			if (M_ISGEQ(off.l_i, off.l_f, -1, 0x80000000) &&
3830			    M_ISGEQ(0, 0x7fffffff, off.l_i, off.l_f))
3831			{
3832				fudge = ppsphaseadjust; /* pick PPS fudge factor */
3833
3834				/*
3835				 * RS232 offsets within [-0.5..0.5[ - take PPS offsets
3836				 */
3837
3838				if (parse->parse_type->cl_flags & PARSE_F_PPSONSECOND)
3839				{
3840					reftime = off = offset;
3841					if (reftime.l_uf & (unsigned)0x80000000)
3842						reftime.l_ui++;
3843					reftime.l_uf = 0;
3844
3845
3846					/*
3847					 * implied on second offset
3848					 */
3849					off.l_uf = ~off.l_uf; /* map [0.5..1[ -> [-0.5..0[ */
3850					off.l_ui = (off.l_f < 0) ? ~0 : 0; /* sign extend */
3851				}
3852				else
3853				{
3854					/*
3855					 * time code describes pulse
3856					 */
3857					reftime = off = parsetime->parse_time.fp;
3858
3859					L_SUB(&off, &offset); /* true offset */
3860				}
3861			}
3862			/*
3863			 * take RS232 offset when PPS when out of bounds
3864			 */
3865		}
3866		else
3867		{
3868			fudge = ppsphaseadjust; /* pick PPS fudge factor */
3869			/*
3870			 * Well, no time code to guide us - assume on second pulse
3871			 * and pray, that we are within [-0.5..0.5[
3872			 */
3873			off = offset;
3874			reftime = offset;
3875			if (reftime.l_uf & (unsigned)0x80000000)
3876				reftime.l_ui++;
3877			reftime.l_uf = 0;
3878			/*
3879			 * implied on second offset
3880			 */
3881			off.l_uf = ~off.l_uf; /* map [0.5..1[ -> [-0.5..0[ */
3882			off.l_ui = (off.l_f < 0) ? ~0 : 0; /* sign extend */
3883		}
3884	}
3885	else
3886	{
3887		if (!PARSE_TIMECODE(parsetime->parse_state))
3888		{
3889			/*
3890			 * Well, no PPS, no TIMECODE, no more work ...
3891			 */
3892			if ((parsetime->parse_status & CVT_ADDITIONAL) &&
3893			    parse->parse_type->cl_message)
3894				parse->parse_type->cl_message(parse, parsetime);
3895			return;
3896		}
3897	}
3898
3899#ifdef DEBUG
3900	if (debug > 3)
3901		printf("PARSE receiver #%d: Reftime %s, Recvtime %s - final offset %s\n",
3902			CLK_UNIT(parse->peer),
3903			prettydate(&reftime),
3904			prettydate(&rectime),
3905			lfptoa(&off,6));
3906#endif
3907
3908
3909	rectime = reftime;
3910	L_SUB(&rectime, &off);	/* just to keep the ntp interface happy */
3911
3912#ifdef DEBUG
3913	if (debug > 3)
3914		printf("PARSE receiver #%d: calculated Reftime %s, Recvtime %s\n",
3915			CLK_UNIT(parse->peer),
3916			prettydate(&reftime),
3917			prettydate(&rectime));
3918#endif
3919
3920	if ((parsetime->parse_status & CVT_ADDITIONAL) &&
3921	    parse->parse_type->cl_message)
3922		parse->parse_type->cl_message(parse, parsetime);
3923
3924	if (PARSE_SYNC(parsetime->parse_state))
3925	{
3926		/*
3927		 * log OK status
3928		 */
3929		parse_event(parse, CEVNT_NOMINAL);
3930	}
3931
3932	clear_err(parse, ERR_BADIO);
3933	clear_err(parse, ERR_BADDATA);
3934	clear_err(parse, ERR_NODATA);
3935	clear_err(parse, ERR_INTERNAL);
3936
3937	/*
3938	 * and now stick it into the clock machine
3939	 * samples are only valid iff lastsync is not too old and
3940	 * we have seen the clock in sync at least once
3941	 * after the last time we didn't see an expected data telegram
3942	 * at startup being not in sync is also bad just like
3943	 * POWERUP state
3944	 * see the clock states section above for more reasoning
3945	 */
3946	if (((current_time - parse->lastsync) > parse->maxunsync) ||
3947	    (parse->lastsync < parse->lastmissed) ||
3948	    ((parse->lastsync == 0) && !PARSE_SYNC(parsetime->parse_state)) ||
3949	    PARSE_POWERUP(parsetime->parse_state))
3950	{
3951		parse->generic->leap = LEAP_NOTINSYNC;
3952		parse->lastsync = 0;	/* wait for full sync again */
3953	}
3954	else
3955	{
3956		if (PARSE_LEAPADD(parsetime->parse_state))
3957		{
3958			/*
3959			 * we pick this state also for time code that pass leap warnings
3960			 * without direction information (as earth is currently slowing
3961			 * down).
3962			 */
3963			parse->generic->leap = (parse->flags & PARSE_LEAP_DELETE) ? LEAP_DELSECOND : LEAP_ADDSECOND;
3964		}
3965		else
3966		    if (PARSE_LEAPDEL(parsetime->parse_state))
3967		    {
3968			    parse->generic->leap = LEAP_DELSECOND;
3969		    }
3970		    else
3971		    {
3972			    parse->generic->leap = LEAP_NOWARNING;
3973		    }
3974	}
3975
3976	if (parse->generic->leap != LEAP_NOTINSYNC)
3977	{
3978	        /*
3979		 * only good/trusted samples are interesting
3980		 */
3981#ifdef DEBUG
3982	        if (debug > 2)
3983		        {
3984			        printf("PARSE receiver #%d: refclock_process_offset(reftime=%s, rectime=%s, Fudge=%f)\n",
3985				       CLK_UNIT(parse->peer),
3986				       prettydate(&reftime),
3987				       prettydate(&rectime),
3988				       fudge);
3989			}
3990#endif
3991		parse->generic->lastref = reftime;
3992
3993		refclock_process_offset(parse->generic, reftime, rectime, fudge);
3994
3995#ifdef HAVE_PPSAPI
3996		/*
3997		 * pass PPS information on to PPS clock
3998		 */
3999		if (PARSE_PPS(parsetime->parse_state) && CLK_PPS(parse->peer))
4000		        {
4001			  /* refclock_pps includes fudgetime1 - we keep the RS232 offset in there :-( */
4002			        double savedtime1 = parse->generic->fudgetime1;
4003
4004				parse->generic->fudgetime1 = fudge;
4005
4006				if (refclock_pps(parse->peer, &parse->atom,
4007						 parse->flags & (CLK_FLAG1|CLK_FLAG2|CLK_FLAG3|CLK_FLAG4))) {
4008					parse->peer->flags |= FLAG_PPS;
4009				} else {
4010					parse->peer->flags &= ~FLAG_PPS;
4011				}
4012
4013				parse->generic->fudgetime1 = savedtime1;
4014
4015				parse_hardpps(parse, PARSE_HARDPPS_ENABLE);
4016			}
4017#endif
4018	} else {
4019	        parse_hardpps(parse, PARSE_HARDPPS_DISABLE);
4020		parse->peer->flags &= ~FLAG_PPS;
4021	}
4022
4023	/*
4024	 * ready, unless the machine wants a sample or
4025	 * we are in fast startup mode (peer->dist > MAXDISTANCE)
4026	 */
4027	if (!parse->pollneeddata && parse->peer->disp <= MAXDISTANCE)
4028	    return;
4029
4030	parse->pollneeddata = 0;
4031
4032	parse->timedata.parse_state &= ~(unsigned)(PARSEB_PPS|PARSEB_S_PPS);
4033
4034	refclock_receive(parse->peer);
4035}
4036
4037/**===========================================================================
4038 ** special code for special clocks
4039 **/
4040
4041static void
4042mk_utcinfo(
4043	   char *t,
4044	   int wnt,
4045	   int wnlsf,
4046	   int dn,
4047	   int dtls,
4048	   int dtlsf,
4049	   int size
4050	   )
4051{
4052  l_fp leapdate;
4053  char *start = t;
4054
4055  snprintf(t, size, "current correction %d sec", dtls);
4056  t += strlen(t);
4057
4058  if (wnlsf < 990)
4059    wnlsf += 1024;
4060
4061  if (wnt < 990)
4062    wnt += 1024;
4063
4064  gpstolfp((unsigned short)wnlsf, (unsigned short)dn, 0, &leapdate);
4065
4066  if ((dtlsf != dtls) &&
4067      ((wnlsf - wnt) < 52))
4068    {
4069	    snprintf(t, BUFFER_SIZES(start, t, size), ", next correction %d sec on %s, new GPS-UTC offset %d",
4070	      dtlsf - dtls, gmprettydate(&leapdate), dtlsf);
4071    }
4072  else
4073    {
4074	    snprintf(t, BUFFER_SIZES(start, t, size), ", last correction on %s",
4075	      gmprettydate(&leapdate));
4076    }
4077}
4078
4079#ifdef CLOCK_MEINBERG
4080/**===========================================================================
4081 ** Meinberg GPS166/GPS167 support
4082 **/
4083
4084/*------------------------------------------------------------
4085 * gps16x_message - process GPS16x messages
4086 */
4087static void
4088gps16x_message(
4089	       struct parseunit *parse,
4090	       parsetime_t      *parsetime
4091	       )
4092{
4093	if (parse->timedata.parse_msglen && parsetime->parse_msg[0] == SOH)
4094	{
4095		GPS_MSG_HDR header;
4096		unsigned char *bufp = (unsigned char *)parsetime->parse_msg + 1;
4097
4098#ifdef DEBUG
4099		if (debug > 2)
4100		{
4101			char msgbuffer[600];
4102
4103			mkreadable(msgbuffer, sizeof(msgbuffer), (char *)parsetime->parse_msg, parsetime->parse_msglen, 1);
4104			printf("PARSE receiver #%d: received message (%d bytes) >%s<\n",
4105				CLK_UNIT(parse->peer),
4106				parsetime->parse_msglen,
4107				msgbuffer);
4108		}
4109#endif
4110		get_mbg_header(&bufp, &header);
4111		if (header.gps_hdr_csum == mbg_csum(parsetime->parse_msg + 1, 6) &&
4112		    (header.gps_len == 0 ||
4113		     (header.gps_len < sizeof(parsetime->parse_msg) &&
4114		      header.gps_data_csum == mbg_csum(bufp, header.gps_len))))
4115		{
4116			/*
4117			 * clean message
4118			 */
4119			switch (header.gps_cmd)
4120			{
4121			case GPS_SW_REV:
4122				{
4123					char buffer[64];
4124					SW_REV gps_sw_rev;
4125
4126					get_mbg_sw_rev(&bufp, &gps_sw_rev);
4127					snprintf(buffer, sizeof(buffer), "meinberg_gps_version=\"%x.%02x%s%s\"",
4128						(gps_sw_rev.code >> 8) & 0xFF,
4129						gps_sw_rev.code & 0xFF,
4130						gps_sw_rev.name[0] ? " " : "",
4131						gps_sw_rev.name);
4132					set_var(&parse->kv, buffer, strlen(buffer)+1, RO|DEF);
4133				}
4134			break;
4135
4136			case GPS_STAT:
4137				{
4138					static struct state
4139					{
4140						unsigned short flag; /* status flag */
4141						unsigned const char *string; /* bit name */
4142					} states[] =
4143					  {
4144						  { TM_ANT_DISCONN, (const unsigned char *)"ANTENNA FAULTY" },
4145						  { TM_SYN_FLAG,    (const unsigned char *)"NO SYNC SIGNAL" },
4146						  { TM_NO_SYNC,     (const unsigned char *)"NO SYNC POWERUP" },
4147						  { TM_NO_POS,      (const unsigned char *)"NO POSITION" },
4148						  { 0, (const unsigned char *)"" }
4149					  };
4150					unsigned short status;
4151					struct state *s = states;
4152					char buffer[512];
4153					char *p, *b;
4154
4155					status = get_lsb_short(&bufp);
4156					snprintf(buffer, sizeof(buffer), "meinberg_gps_status=\"[0x%04x] ", status);
4157
4158					if (status)
4159					{
4160						p = b = buffer + strlen(buffer);
4161						while (s->flag)
4162						{
4163							if (status & s->flag)
4164							{
4165								if (p != b)
4166								{
4167									*p++ = ',';
4168									*p++ = ' ';
4169								}
4170
4171								strncat(p, (const char *)s->string, sizeof(buffer));
4172							}
4173							s++;
4174						}
4175
4176						*p++ = '"';
4177						*p   = '\0';
4178					}
4179					else
4180					{
4181						strncat(buffer, "<OK>\"", sizeof(buffer));
4182					}
4183
4184					set_var(&parse->kv, buffer, strlen(buffer)+1, RO|DEF);
4185				}
4186			break;
4187
4188			case GPS_POS_XYZ:
4189				{
4190					XYZ xyz;
4191					char buffer[256];
4192
4193					get_mbg_xyz(&bufp, xyz);
4194					snprintf(buffer, sizeof(buffer), "gps_position(XYZ)=\"%s m, %s m, %s m\"",
4195						mfptoa(xyz[XP].l_ui, xyz[XP].l_uf, 1),
4196						mfptoa(xyz[YP].l_ui, xyz[YP].l_uf, 1),
4197						mfptoa(xyz[ZP].l_ui, xyz[ZP].l_uf, 1));
4198
4199					set_var(&parse->kv, buffer, sizeof(buffer), RO|DEF);
4200				}
4201			break;
4202
4203			case GPS_POS_LLA:
4204				{
4205					LLA lla;
4206					char buffer[256];
4207
4208					get_mbg_lla(&bufp, lla);
4209
4210					snprintf(buffer, sizeof(buffer), "gps_position(LLA)=\"%s deg, %s deg, %s m\"",
4211						mfptoa(lla[LAT].l_ui, lla[LAT].l_uf, 4),
4212						mfptoa(lla[LON].l_ui, lla[LON].l_uf, 4),
4213						mfptoa(lla[ALT].l_ui, lla[ALT].l_uf, 1));
4214
4215					set_var(&parse->kv, buffer, sizeof(buffer), RO|DEF);
4216				}
4217			break;
4218
4219			case GPS_TZDL:
4220				break;
4221
4222			case GPS_PORT_PARM:
4223				break;
4224
4225			case GPS_SYNTH:
4226				break;
4227
4228			case GPS_ANT_INFO:
4229				{
4230					ANT_INFO antinfo;
4231					char buffer[512];
4232					char *p;
4233
4234					get_mbg_antinfo(&bufp, &antinfo);
4235					snprintf(buffer, sizeof(buffer), "meinberg_antenna_status=\"");
4236					p = buffer + strlen(buffer);
4237
4238					switch (antinfo.status)
4239					{
4240					case ANT_INVALID:
4241						strncat(p, "<OK>", BUFFER_SIZE(buffer, p));
4242						p += strlen(p);
4243						break;
4244
4245					case ANT_DISCONN:
4246						strncat(p, "DISCONNECTED since ", BUFFER_SIZE(buffer, p));
4247						NLOG(NLOG_CLOCKSTATUS)
4248							ERR(ERR_BADSTATUS)
4249							msyslog(LOG_ERR,"PARSE receiver #%d: ANTENNA FAILURE: %s",
4250								CLK_UNIT(parse->peer), p);
4251
4252						p += strlen(p);
4253						mbg_tm_str(&p, &antinfo.tm_disconn, BUFFER_SIZE(buffer, p));
4254						*p = '\0';
4255						break;
4256
4257					case ANT_RECONN:
4258						strncat(p, "RECONNECTED on ", BUFFER_SIZE(buffer, p));
4259						p += strlen(p);
4260						mbg_tm_str(&p, &antinfo.tm_reconn, BUFFER_SIZE(buffer, p));
4261						snprintf(p, BUFFER_SIZE(buffer, p), ", reconnect clockoffset %c%ld.%07ld s, disconnect time ",
4262							(antinfo.delta_t < 0) ? '-' : '+',
4263							ABS(antinfo.delta_t) / 10000,
4264							ABS(antinfo.delta_t) % 10000);
4265						p += strlen(p);
4266						mbg_tm_str(&p, &antinfo.tm_disconn, BUFFER_SIZE(buffer, p));
4267						*p = '\0';
4268						break;
4269
4270					default:
4271						snprintf(p, BUFFER_SIZE(buffer, p), "bad status 0x%04x", antinfo.status);
4272						p += strlen(p);
4273						break;
4274					}
4275
4276					strncat(p, "\"", BUFFER_SIZE(buffer, p));
4277
4278					set_var(&parse->kv, buffer, strlen(buffer)+1, RO|DEF);
4279				}
4280			break;
4281
4282			case GPS_UCAP:
4283				break;
4284
4285			case GPS_CFGH:
4286				{
4287					CFGH cfgh;
4288					char buffer[512];
4289					char *p;
4290
4291					get_mbg_cfgh(&bufp, &cfgh);
4292					if (cfgh.valid)
4293					{
4294						int i;
4295
4296						p = buffer;
4297						strncpy(buffer, "gps_tot_51=\"", BUFFER_SIZE(buffer, p));
4298						p += strlen(p);
4299						mbg_tgps_str(&p, &cfgh.tot_51, BUFFER_SIZE(buffer, p));
4300						strncpy(p, "\"", BUFFER_SIZE(buffer, p));
4301						set_var(&parse->kv, buffer, strlen(buffer)+1, RO);
4302
4303						p = buffer;
4304						strncpy(buffer, "gps_tot_63=\"", BUFFER_SIZE(buffer, p));
4305						p += strlen(p);
4306						mbg_tgps_str(&p, &cfgh.tot_63, BUFFER_SIZE(buffer, p));
4307						strncpy(p, "\"", BUFFER_SIZE(buffer, p));
4308						set_var(&parse->kv, buffer, strlen(buffer)+1, RO);
4309
4310						p = buffer;
4311						strncpy(buffer, "gps_t0a=\"", BUFFER_SIZE(buffer, p));
4312						p += strlen(p);
4313						mbg_tgps_str(&p, &cfgh.t0a, BUFFER_SIZE(buffer, p));
4314						strncpy(p, "\"", BUFFER_SIZE(buffer, p));
4315						set_var(&parse->kv, buffer, strlen(buffer)+1, RO);
4316
4317						for (i = MIN_SVNO; i < MAX_SVNO; i++)
4318						{
4319							p = buffer;
4320							snprintf(p, BUFFER_SIZE(buffer, p), "gps_cfg[%d]=\"[0x%x] ", i, cfgh.cfg[i]);
4321							p += strlen(p);
4322							switch (cfgh.cfg[i] & 0x7)
4323							{
4324							case 0:
4325								strncpy(p, "BLOCK I", BUFFER_SIZE(buffer, p));
4326								break;
4327							case 1:
4328								strncpy(p, "BLOCK II", BUFFER_SIZE(buffer, p));
4329								break;
4330							default:
4331								strncpy(p, "bad CFG", BUFFER_SIZE(buffer, p));
4332								break;
4333							}
4334							strncat(p, "\"", BUFFER_SIZE(buffer, p));
4335							set_var(&parse->kv, buffer, strlen(buffer)+1, RO);
4336
4337							p = buffer;
4338							snprintf(p, BUFFER_SIZE(buffer, p), "gps_health[%d]=\"[0x%x] ", i, cfgh.health[i]);
4339							p += strlen(p);
4340							switch ((cfgh.health[i] >> 5) & 0x7 )
4341							{
4342							case 0:
4343								strncpy(p, "OK;", BUFFER_SIZE(buffer, p));
4344								break;
4345							case 1:
4346								strncpy(p, "PARITY;", BUFFER_SIZE(buffer, p));
4347								break;
4348							case 2:
4349								strncpy(p, "TLM/HOW;", BUFFER_SIZE(buffer, p));
4350								break;
4351							case 3:
4352								strncpy(p, "Z-COUNT;", BUFFER_SIZE(buffer, p));
4353								break;
4354							case 4:
4355								strncpy(p, "SUBFRAME 1,2,3;", BUFFER_SIZE(buffer, p));
4356								break;
4357							case 5:
4358								strncpy(p, "SUBFRAME 4,5;", BUFFER_SIZE(buffer, p));
4359								break;
4360							case 6:
4361								strncpy(p, "UPLOAD BAD;", BUFFER_SIZE(buffer, p));
4362								break;
4363							case 7:
4364								strncpy(p, "DATA BAD;", BUFFER_SIZE(buffer, p));
4365								break;
4366							}
4367
4368							p += strlen(p);
4369
4370							switch (cfgh.health[i] & 0x1F)
4371							{
4372							case 0:
4373								strncpy(p, "SIGNAL OK", BUFFER_SIZE(buffer, p));
4374								break;
4375							case 0x1C:
4376								strncpy(p, "SV TEMP OUT", BUFFER_SIZE(buffer, p));
4377								break;
4378							case 0x1D:
4379								strncpy(p, "SV WILL BE TEMP OUT", BUFFER_SIZE(buffer, p));
4380								break;
4381							case 0x1E:
4382								break;
4383							case 0x1F:
4384								strncpy(p, "MULTIPLE ERRS", BUFFER_SIZE(buffer, p));
4385								break;
4386							default:
4387								strncpy(p, "TRANSMISSION PROBLEMS", BUFFER_SIZE(buffer, p));
4388								break;
4389							}
4390
4391							strncat(p, "\"", sizeof(buffer));
4392							set_var(&parse->kv, buffer, strlen(buffer)+1, RO);
4393						}
4394					}
4395				}
4396			break;
4397
4398			case GPS_ALM:
4399				break;
4400
4401			case GPS_EPH:
4402				break;
4403
4404			case GPS_UTC:
4405				{
4406					UTC utc;
4407					char buffer[512];
4408					char *p;
4409
4410					p = buffer;
4411
4412					get_mbg_utc(&bufp, &utc);
4413
4414					if (utc.valid)
4415					{
4416						strncpy(p, "gps_utc_correction=\"", sizeof(buffer));
4417						p += strlen(p);
4418						mk_utcinfo(p, utc.t0t.wn, utc.WNlsf, utc.DNt, utc.delta_tls, utc.delta_tlsf, BUFFER_SIZE(buffer, p));
4419						strncat(p, "\"", BUFFER_SIZE(buffer, p));
4420					}
4421					else
4422					{
4423						strncpy(p, "gps_utc_correction=\"<NO UTC DATA>\"", BUFFER_SIZE(buffer, p));
4424					}
4425					set_var(&parse->kv, buffer, strlen(buffer)+1, RO|DEF);
4426				}
4427			break;
4428
4429			case GPS_IONO:
4430				break;
4431
4432			case GPS_ASCII_MSG:
4433				{
4434					ASCII_MSG gps_ascii_msg;
4435					char buffer[128];
4436
4437					get_mbg_ascii_msg(&bufp, &gps_ascii_msg);
4438
4439					if (gps_ascii_msg.valid)
4440						{
4441							char buffer1[128];
4442							mkreadable(buffer1, sizeof(buffer1), gps_ascii_msg.s, strlen(gps_ascii_msg.s), (int)0);
4443
4444							snprintf(buffer, sizeof(buffer), "gps_message=\"%s\"", buffer1);
4445						}
4446					else
4447						strncpy(buffer, "gps_message=<NONE>", sizeof(buffer));
4448
4449					set_var(&parse->kv, buffer, strlen(buffer)+1, RO|DEF);
4450				}
4451
4452			break;
4453
4454			default:
4455				break;
4456			}
4457		}
4458		else
4459		{
4460			msyslog(LOG_DEBUG, "PARSE receiver #%d: gps16x_message: message checksum error: hdr_csum = 0x%x (expected 0x%lx), data_len = %d, data_csum = 0x%x (expected 0x%lx)",
4461				CLK_UNIT(parse->peer),
4462				header.gps_hdr_csum, mbg_csum(parsetime->parse_msg + 1, 6),
4463				header.gps_len,
4464				header.gps_data_csum, mbg_csum(bufp, (unsigned)((header.gps_len < sizeof(parsetime->parse_msg)) ? header.gps_len : 0)));
4465		}
4466	}
4467
4468	return;
4469}
4470
4471/*------------------------------------------------------------
4472 * gps16x_poll - query the reciver peridically
4473 */
4474static void
4475gps16x_poll(
4476	    struct peer *peer
4477	    )
4478{
4479	struct parseunit *parse = (struct parseunit *)peer->procptr->unitptr;
4480
4481	static GPS_MSG_HDR sequence[] =
4482	{
4483		{ GPS_SW_REV,          0, 0, 0 },
4484		{ GPS_STAT,            0, 0, 0 },
4485		{ GPS_UTC,             0, 0, 0 },
4486		{ GPS_ASCII_MSG,       0, 0, 0 },
4487		{ GPS_ANT_INFO,        0, 0, 0 },
4488		{ GPS_CFGH,            0, 0, 0 },
4489		{ GPS_POS_XYZ,         0, 0, 0 },
4490		{ GPS_POS_LLA,         0, 0, 0 },
4491		{ (unsigned short)~0,  0, 0, 0 }
4492	};
4493
4494	int rtc;
4495	unsigned char cmd_buffer[64];
4496	unsigned char *outp = cmd_buffer;
4497	GPS_MSG_HDR *header;
4498
4499	if (((poll_info_t *)parse->parse_type->cl_data)->rate)
4500	{
4501		parse->peer->nextaction = current_time + ((poll_info_t *)parse->parse_type->cl_data)->rate;
4502	}
4503
4504	if (sequence[parse->localstate].gps_cmd == (unsigned short)~0)
4505		parse->localstate = 0;
4506
4507	header = sequence + parse->localstate++;
4508
4509	*outp++ = SOH;		/* start command */
4510
4511	put_mbg_header(&outp, header);
4512	outp = cmd_buffer + 1;
4513
4514	header->gps_hdr_csum = (short)mbg_csum(outp, 6);
4515	put_mbg_header(&outp, header);
4516
4517#ifdef DEBUG
4518	if (debug > 2)
4519	{
4520		char buffer[128];
4521
4522		mkreadable(buffer, sizeof(buffer), (char *)cmd_buffer, (unsigned)(outp - cmd_buffer), 1);
4523		printf("PARSE receiver #%d: transmitted message #%ld (%d bytes) >%s<\n",
4524		       CLK_UNIT(parse->peer),
4525		       parse->localstate - 1,
4526		       (int)(outp - cmd_buffer),
4527		       buffer);
4528	}
4529#endif
4530
4531	rtc = write(parse->generic->io.fd, cmd_buffer, (unsigned long)(outp - cmd_buffer));
4532
4533	if (rtc < 0)
4534	{
4535		ERR(ERR_BADIO)
4536			msyslog(LOG_ERR, "PARSE receiver #%d: gps16x_poll: failed to send cmd to clock: %m", CLK_UNIT(parse->peer));
4537	}
4538	else
4539	if (rtc != outp - cmd_buffer)
4540	{
4541		ERR(ERR_BADIO)
4542			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));
4543	}
4544
4545	clear_err(parse, ERR_BADIO);
4546	return;
4547}
4548
4549/*--------------------------------------------------
4550 * init routine - setup timer
4551 */
4552static int
4553gps16x_poll_init(
4554	struct parseunit *parse
4555	)
4556{
4557	if (((poll_info_t *)parse->parse_type->cl_data)->rate)
4558	{
4559		parse->peer->action = gps16x_poll;
4560		gps16x_poll(parse->peer);
4561	}
4562
4563	return 0;
4564}
4565
4566#else
4567static void
4568gps16x_message(
4569	       struct parseunit *parse,
4570	       parsetime_t      *parsetime
4571	       )
4572{}
4573static int
4574gps16x_poll_init(
4575	struct parseunit *parse
4576	)
4577{
4578	return 1;
4579}
4580#endif /* CLOCK_MEINBERG */
4581
4582/**===========================================================================
4583 ** clock polling support
4584 **/
4585
4586/*--------------------------------------------------
4587 * direct poll routine
4588 */
4589static void
4590poll_dpoll(
4591	struct parseunit *parse
4592	)
4593{
4594	int rtc;
4595	const char *ps = ((poll_info_t *)parse->parse_type->cl_data)->string;
4596	int   ct = ((poll_info_t *)parse->parse_type->cl_data)->count;
4597
4598	rtc = write(parse->generic->io.fd, ps, (unsigned long)ct);
4599	if (rtc < 0)
4600	{
4601		ERR(ERR_BADIO)
4602			msyslog(LOG_ERR, "PARSE receiver #%d: poll_dpoll: failed to send cmd to clock: %m", CLK_UNIT(parse->peer));
4603	}
4604	else
4605	    if (rtc != ct)
4606	    {
4607		    ERR(ERR_BADIO)
4608			    msyslog(LOG_ERR, "PARSE receiver #%d: poll_dpoll: failed to send cmd incomplete (%d of %d bytes sent)", CLK_UNIT(parse->peer), rtc, ct);
4609	    }
4610	clear_err(parse, ERR_BADIO);
4611}
4612
4613/*--------------------------------------------------
4614 * periodic poll routine
4615 */
4616static void
4617poll_poll(
4618	struct peer *peer
4619	)
4620{
4621	struct parseunit *parse = (struct parseunit *)peer->procptr->unitptr;
4622
4623	if (parse->parse_type->cl_poll)
4624		parse->parse_type->cl_poll(parse);
4625
4626	if (((poll_info_t *)parse->parse_type->cl_data)->rate)
4627	{
4628		parse->peer->nextaction = current_time + ((poll_info_t *)parse->parse_type->cl_data)->rate;
4629	}
4630}
4631
4632/*--------------------------------------------------
4633 * init routine - setup timer
4634 */
4635static int
4636poll_init(
4637	struct parseunit *parse
4638	)
4639{
4640	if (((poll_info_t *)parse->parse_type->cl_data)->rate)
4641	{
4642		parse->peer->action = poll_poll;
4643		poll_poll(parse->peer);
4644	}
4645
4646	return 0;
4647}
4648
4649/**===========================================================================
4650 ** Trimble support
4651 **/
4652
4653/*-------------------------------------------------------------
4654 * trimble TAIP init routine - setup EOL and then do poll_init.
4655 */
4656static int
4657trimbletaip_init(
4658	struct parseunit *parse
4659	)
4660{
4661#ifdef HAVE_TERMIOS
4662	struct termios tio;
4663#endif
4664#ifdef HAVE_SYSV_TTYS
4665	struct termio tio;
4666#endif
4667	/*
4668	 * configure terminal line for trimble receiver
4669	 */
4670	if (TTY_GETATTR(parse->generic->io.fd, &tio) == -1)
4671	{
4672		msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_init: tcgetattr(fd, &tio): %m", CLK_UNIT(parse->peer));
4673		return 0;
4674	}
4675	else
4676	{
4677		tio.c_cc[VEOL] = TRIMBLETAIP_EOL;
4678
4679		if (TTY_SETATTR(parse->generic->io.fd, &tio) == -1)
4680		{
4681			msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_init: tcsetattr(fd, &tio): %m", CLK_UNIT(parse->peer));
4682			return 0;
4683		}
4684	}
4685	return poll_init(parse);
4686}
4687
4688/*--------------------------------------------------
4689 * trimble TAIP event routine - reset receiver upon data format trouble
4690 */
4691static const char *taipinit[] = {
4692	">FPV00000000<",
4693	">SRM;ID_FLAG=F;CS_FLAG=T;EC_FLAG=F;FR_FLAG=T;CR_FLAG=F<",
4694	">FTM00020001<",
4695	(char *)0
4696};
4697
4698static void
4699trimbletaip_event(
4700	struct parseunit *parse,
4701	int event
4702	)
4703{
4704	switch (event)
4705	{
4706	    case CEVNT_BADREPLY:	/* reset on garbled input */
4707	    case CEVNT_TIMEOUT:		/* reset on no input */
4708		    {
4709			    const char **iv;
4710
4711			    iv = taipinit;
4712			    while (*iv)
4713			    {
4714				    int rtc = write(parse->generic->io.fd, *iv, strlen(*iv));
4715				    if (rtc < 0)
4716				    {
4717					    msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_event: failed to send cmd to clock: %m", CLK_UNIT(parse->peer));
4718					    return;
4719				    }
4720				    else
4721				    {
4722					    if (rtc != strlen(*iv))
4723					    {
4724						    msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_event: failed to send cmd incomplete (%d of %d bytes sent)",
4725							    CLK_UNIT(parse->peer), rtc, (int)strlen(*iv));
4726						    return;
4727					    }
4728				    }
4729				    iv++;
4730			    }
4731
4732			    NLOG(NLOG_CLOCKINFO)
4733				    ERR(ERR_BADIO)
4734				    msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_event: RECEIVER INITIALIZED",
4735					    CLK_UNIT(parse->peer));
4736		    }
4737		    break;
4738
4739	    default:			/* ignore */
4740		break;
4741	}
4742}
4743
4744/*
4745 * This driver supports the Trimble SVee Six Plus GPS receiver module.
4746 * It should support other Trimble receivers which use the Trimble Standard
4747 * Interface Protocol (see below).
4748 *
4749 * The module has a serial I/O port for command/data and a 1 pulse-per-second
4750 * output, about 1 microsecond wide. The leading edge of the pulse is
4751 * coincident with the change of the GPS second. This is the same as
4752 * the change of the UTC second +/- ~1 microsecond. Some other clocks
4753 * specifically use a feature in the data message as a timing reference, but
4754 * the SVee Six Plus does not do this. In fact there is considerable jitter
4755 * on the timing of the messages, so this driver only supports the use
4756 * of the PPS pulse for accurate timing. Where it is determined that
4757 * the offset is way off, when first starting up ntpd for example,
4758 * the timing of the data stream is used until the offset becomes low enough
4759 * (|offset| < CLOCK_MAX), at which point the pps offset is used.
4760 *
4761 * It can use either option for receiving PPS information - the 'ppsclock'
4762 * stream pushed onto the serial data interface to timestamp the Carrier
4763 * Detect interrupts, where the 1PPS connects to the CD line. This only
4764 * works on SunOS 4.1.x currently. To select this, define PPSPPS in
4765 * Config.local. The other option is to use a pulse-stretcher/level-converter
4766 * to convert the PPS pulse into a RS232 start pulse & feed this into another
4767 * tty port. To use this option, define PPSCLK in Config.local. The pps input,
4768 * by whichever method, is handled in ntp_loopfilter.c
4769 *
4770 * The receiver uses a serial message protocol called Trimble Standard
4771 * Interface Protocol (it can support others but this driver only supports
4772 * TSIP). Messages in this protocol have the following form:
4773 *
4774 * <DLE><id> ... <data> ... <DLE><ETX>
4775 *
4776 * Any bytes within the <data> portion of value 10 hex (<DLE>) are doubled
4777 * on transmission and compressed back to one on reception. Otherwise
4778 * the values of data bytes can be anything. The serial interface is RS-422
4779 * asynchronous using 9600 baud, 8 data bits with odd party (**note** 9 bits
4780 * in total!), and 1 stop bit. The protocol supports byte, integer, single,
4781 * and double datatypes. Integers are two bytes, sent most significant first.
4782 * Singles are IEEE754 single precision floating point numbers (4 byte) sent
4783 * sign & exponent first. Doubles are IEEE754 double precision floating point
4784 * numbers (8 byte) sent sign & exponent first.
4785 * The receiver supports a large set of messages, only a small subset of
4786 * which are used here. From driver to receiver the following are used:
4787 *
4788 *  ID    Description
4789 *
4790 *  21    Request current time
4791 *  22    Mode Select
4792 *  2C    Set/Request operating parameters
4793 *  2F    Request UTC info
4794 *  35    Set/Request I/O options
4795
4796 * From receiver to driver the following are recognised:
4797 *
4798 *  ID    Description
4799 *
4800 *  41    GPS Time
4801 *  44    Satellite selection, PDOP, mode
4802 *  46    Receiver health
4803 *  4B    Machine code/status
4804 *  4C    Report operating parameters (debug only)
4805 *  4F    UTC correction data (used to get leap second warnings)
4806 *  55    I/O options (debug only)
4807 *
4808 * All others are accepted but ignored.
4809 *
4810 */
4811
4812#define PI		3.1415926535898	/* lots of sig figs */
4813#define D2R		PI/180.0
4814
4815/*-------------------------------------------------------------------
4816 * sendcmd, sendbyte, sendetx, sendflt, sendint implement the command
4817 * interface to the receiver.
4818 *
4819 * CAVEAT: the sendflt, sendint routines are byte order dependend and
4820 * float implementation dependend - these must be converted to portable
4821 * versions !
4822 *
4823 * CURRENT LIMITATION: float implementation. This runs only on systems
4824 * with IEEE754 floats as native floats
4825 */
4826
4827typedef struct trimble
4828{
4829	u_long last_msg;	/* last message received */
4830	u_long last_reset;	/* last time a reset was issued */
4831	u_char qtracking;	/* query tracking status */
4832	u_long ctrack;		/* current tracking set */
4833	u_long ltrack;		/* last tracking set */
4834} trimble_t;
4835
4836union uval {
4837	u_char  bd[8];
4838	int     iv;
4839	float   fv;
4840	double  dv;
4841};
4842
4843struct txbuf
4844{
4845	short idx;			/* index to first unused byte */
4846	u_char *txt;			/* pointer to actual data buffer */
4847};
4848
4849void	sendcmd		(struct txbuf *buf, int c);
4850void	sendbyte	(struct txbuf *buf, int b);
4851void	sendetx		(struct txbuf *buf, struct parseunit *parse);
4852void	sendint		(struct txbuf *buf, int a);
4853void	sendflt		(struct txbuf *buf, double a);
4854
4855void
4856sendcmd(
4857	struct txbuf *buf,
4858	int c
4859	)
4860{
4861	buf->txt[0] = DLE;
4862	buf->txt[1] = (u_char)c;
4863	buf->idx = 2;
4864}
4865
4866void	sendcmd		(struct txbuf *buf, int c);
4867void	sendbyte	(struct txbuf *buf, int b);
4868void	sendetx		(struct txbuf *buf, struct parseunit *parse);
4869void	sendint		(struct txbuf *buf, int a);
4870void	sendflt		(struct txbuf *buf, double a);
4871
4872void
4873sendbyte(
4874	struct txbuf *buf,
4875	int b
4876	)
4877{
4878	if (b == DLE)
4879	    buf->txt[buf->idx++] = DLE;
4880	buf->txt[buf->idx++] = (u_char)b;
4881}
4882
4883void
4884sendetx(
4885	struct txbuf *buf,
4886	struct parseunit *parse
4887	)
4888{
4889	buf->txt[buf->idx++] = DLE;
4890	buf->txt[buf->idx++] = ETX;
4891
4892	if (write(parse->generic->io.fd, buf->txt, (unsigned long)buf->idx) != buf->idx)
4893	{
4894		ERR(ERR_BADIO)
4895			msyslog(LOG_ERR, "PARSE receiver #%d: sendetx: failed to send cmd to clock: %m", CLK_UNIT(parse->peer));
4896	}
4897	else
4898	{
4899#ifdef DEBUG
4900	  if (debug > 2)
4901	  {
4902		  char buffer[256];
4903
4904		  mkreadable(buffer, sizeof(buffer), (char *)buf->txt, (unsigned)buf->idx, 1);
4905		  printf("PARSE receiver #%d: transmitted message (%d bytes) >%s<\n",
4906			 CLK_UNIT(parse->peer),
4907			 buf->idx, buffer);
4908	  }
4909#endif
4910		clear_err(parse, ERR_BADIO);
4911	}
4912}
4913
4914void
4915sendint(
4916	struct txbuf *buf,
4917	int a
4918	)
4919{
4920	/* send 16bit int, msbyte first */
4921	sendbyte(buf, (u_char)((a>>8) & 0xff));
4922	sendbyte(buf, (u_char)(a & 0xff));
4923}
4924
4925void
4926sendflt(
4927	struct txbuf *buf,
4928	double a
4929	)
4930{
4931	int i;
4932	union uval uval;
4933
4934	uval.fv = a;
4935#ifdef WORDS_BIGENDIAN
4936	for (i=0; i<=3; i++)
4937#else
4938	    for (i=3; i>=0; i--)
4939#endif
4940		sendbyte(buf, uval.bd[i]);
4941}
4942
4943#define TRIM_POS_OPT	0x13	/* output position with high precision */
4944#define TRIM_TIME_OPT	0x03	/* use UTC time stamps, on second */
4945
4946/*--------------------------------------------------
4947 * trimble TSIP setup routine
4948 */
4949static int
4950trimbletsip_setup(
4951		  struct parseunit *parse,
4952		  const char *reason
4953		  )
4954{
4955	u_char buffer[256];
4956	struct txbuf buf;
4957	trimble_t *t = parse->localdata;
4958
4959	if (t && t->last_reset &&
4960	    ((t->last_reset + TRIMBLE_RESET_HOLDOFF) > current_time)) {
4961		return 1;	/* not yet */
4962	}
4963
4964	if (t)
4965		t->last_reset = current_time;
4966
4967	buf.txt = buffer;
4968
4969	sendcmd(&buf, CMD_CVERSION);	/* request software versions */
4970	sendetx(&buf, parse);
4971
4972	sendcmd(&buf, CMD_COPERPARAM);	/* set operating parameters */
4973	sendbyte(&buf, 4);	/* static */
4974	sendflt(&buf, 5.0*D2R);	/* elevation angle mask = 10 deg XXX */
4975	sendflt(&buf, 4.0);	/* s/n ratio mask = 6 XXX */
4976	sendflt(&buf, 12.0);	/* PDOP mask = 12 */
4977	sendflt(&buf, 8.0);	/* PDOP switch level = 8 */
4978	sendetx(&buf, parse);
4979
4980	sendcmd(&buf, CMD_CMODESEL);	/* fix mode select */
4981	sendbyte(&buf, 1);	/* time transfer mode */
4982	sendetx(&buf, parse);
4983
4984	sendcmd(&buf, CMD_CMESSAGE);	/* request system message */
4985	sendetx(&buf, parse);
4986
4987	sendcmd(&buf, CMD_CSUPER);	/* superpacket fix */
4988	sendbyte(&buf, 0x2);	/* binary mode */
4989	sendetx(&buf, parse);
4990
4991	sendcmd(&buf, CMD_CIOOPTIONS);	/* set I/O options */
4992	sendbyte(&buf, TRIM_POS_OPT);	/* position output */
4993	sendbyte(&buf, 0x00);	/* no velocity output */
4994	sendbyte(&buf, TRIM_TIME_OPT);	/* UTC, compute on seconds */
4995	sendbyte(&buf, 0x00);	/* no raw measurements */
4996	sendetx(&buf, parse);
4997
4998	sendcmd(&buf, CMD_CUTCPARAM);	/* request UTC correction data */
4999	sendetx(&buf, parse);
5000
5001	NLOG(NLOG_CLOCKINFO)
5002		ERR(ERR_BADIO)
5003		msyslog(LOG_ERR, "PARSE receiver #%d: trimbletsip_setup: RECEIVER RE-INITIALIZED (%s)", CLK_UNIT(parse->peer), reason);
5004
5005	return 0;
5006}
5007
5008/*--------------------------------------------------
5009 * TRIMBLE TSIP check routine
5010 */
5011static void
5012trimble_check(
5013	      struct peer *peer
5014	      )
5015{
5016	struct parseunit *parse = (struct parseunit *)peer->procptr->unitptr;
5017	trimble_t *t = parse->localdata;
5018	u_char buffer[256];
5019	struct txbuf buf;
5020	buf.txt = buffer;
5021
5022	if (t)
5023	{
5024		if (current_time > t->last_msg + TRIMBLETSIP_IDLE_TIME)
5025			(void)trimbletsip_setup(parse, "message timeout");
5026	}
5027
5028	poll_poll(parse->peer);	/* emit query string and re-arm timer */
5029
5030	if (t && t->qtracking)
5031	{
5032		u_long oldsats = t->ltrack & ~t->ctrack;
5033
5034		t->qtracking = 0;
5035		t->ltrack = t->ctrack;
5036
5037		if (oldsats)
5038		{
5039			int i;
5040
5041			for (i = 0; oldsats; i++) {
5042				if (oldsats & (1 << i))
5043					{
5044						sendcmd(&buf, CMD_CSTATTRACK);
5045						sendbyte(&buf, i+1);	/* old sat */
5046						sendetx(&buf, parse);
5047					}
5048				oldsats &= ~(1 << i);
5049			}
5050		}
5051
5052		sendcmd(&buf, CMD_CSTATTRACK);
5053		sendbyte(&buf, 0x00);	/* current tracking set */
5054		sendetx(&buf, parse);
5055	}
5056}
5057
5058/*--------------------------------------------------
5059 * TRIMBLE TSIP end routine
5060 */
5061static void
5062trimbletsip_end(
5063	      struct parseunit *parse
5064	      )
5065{	trimble_t *t = parse->localdata;
5066
5067	if (t)
5068	{
5069		free(t);
5070		parse->localdata = (void *)0;
5071	}
5072	parse->peer->nextaction = 0;
5073	parse->peer->action = (void (*) (struct peer *))0;
5074}
5075
5076/*--------------------------------------------------
5077 * TRIMBLE TSIP init routine
5078 */
5079static int
5080trimbletsip_init(
5081	struct parseunit *parse
5082	)
5083{
5084#if defined(VEOL) || defined(VEOL2)
5085#ifdef HAVE_TERMIOS
5086	struct termios tio;		/* NEEDED FOR A LONG TIME ! */
5087#endif
5088#ifdef HAVE_SYSV_TTYS
5089	struct termio tio;		/* NEEDED FOR A LONG TIME ! */
5090#endif
5091	/*
5092	 * allocate local data area
5093	 */
5094	if (!parse->localdata)
5095	{
5096		trimble_t *t;
5097
5098		t = (trimble_t *)(parse->localdata = emalloc(sizeof(trimble_t)));
5099
5100		if (t)
5101		{
5102			memset((char *)t, 0, sizeof(trimble_t));
5103			t->last_msg = current_time;
5104		}
5105	}
5106
5107	parse->peer->action     = trimble_check;
5108	parse->peer->nextaction = current_time;
5109
5110	/*
5111	 * configure terminal line for ICANON mode with VEOL characters
5112	 */
5113	if (TTY_GETATTR(parse->generic->io.fd, &tio) == -1)
5114	{
5115		msyslog(LOG_ERR, "PARSE receiver #%d: trimbletsip_init: tcgetattr(%d, &tio): %m", CLK_UNIT(parse->peer), parse->generic->io.fd);
5116		return 0;
5117	}
5118	else
5119	{
5120		if ((parse_clockinfo[CLK_TYPE(parse->peer)].cl_lflag & ICANON))
5121		{
5122#ifdef VEOL
5123			tio.c_cc[VEOL]  = ETX;
5124#endif
5125#ifdef VEOL2
5126			tio.c_cc[VEOL2]  = DLE;
5127#endif
5128		}
5129
5130		if (TTY_SETATTR(parse->generic->io.fd, &tio) == -1)
5131		{
5132			msyslog(LOG_ERR, "PARSE receiver #%d: trimbletsip_init: tcsetattr(%d, &tio): %m", CLK_UNIT(parse->peer), parse->generic->io.fd);
5133			return 0;
5134		}
5135	}
5136#endif
5137	return trimbletsip_setup(parse, "initial startup");
5138}
5139
5140/*------------------------------------------------------------
5141 * trimbletsip_event - handle Trimble events
5142 * simple evente handler - attempt to re-initialize receiver
5143 */
5144static void
5145trimbletsip_event(
5146	struct parseunit *parse,
5147	int event
5148	)
5149{
5150	switch (event)
5151	{
5152	    case CEVNT_BADREPLY:	/* reset on garbled input */
5153	    case CEVNT_TIMEOUT:		/* reset on no input */
5154		    (void)trimbletsip_setup(parse, "event BAD_REPLY/TIMEOUT");
5155		    break;
5156
5157	    default:			/* ignore */
5158		break;
5159	}
5160}
5161
5162/*
5163 * getflt, getint convert fields in the incoming data into the
5164 * appropriate type of item
5165 *
5166 * CAVEAT: these routines are currently definitely byte order dependent
5167 * and assume Representation(float) == IEEE754
5168 * These functions MUST be converted to portable versions (especially
5169 * converting the float representation into ntp_fp formats in order
5170 * to avoid floating point operations at all!
5171 */
5172
5173static float
5174getflt(
5175	u_char *bp
5176	)
5177{
5178	union uval uval;
5179
5180#ifdef WORDS_BIGENDIAN
5181	uval.bd[0] = *bp++;
5182	uval.bd[1] = *bp++;
5183	uval.bd[2] = *bp++;
5184	uval.bd[3] = *bp;
5185#else  /* ! WORDS_BIGENDIAN */
5186	uval.bd[3] = *bp++;
5187	uval.bd[2] = *bp++;
5188	uval.bd[1] = *bp++;
5189	uval.bd[0] = *bp;
5190#endif /* ! WORDS_BIGENDIAN */
5191	return uval.fv;
5192}
5193
5194static double
5195getdbl(
5196	u_char *bp
5197	)
5198{
5199	union uval uval;
5200
5201#ifdef WORDS_BIGENDIAN
5202	uval.bd[0] = *bp++;
5203	uval.bd[1] = *bp++;
5204	uval.bd[2] = *bp++;
5205	uval.bd[3] = *bp++;
5206	uval.bd[4] = *bp++;
5207	uval.bd[5] = *bp++;
5208	uval.bd[6] = *bp++;
5209	uval.bd[7] = *bp;
5210#else  /* ! WORDS_BIGENDIAN */
5211	uval.bd[7] = *bp++;
5212	uval.bd[6] = *bp++;
5213	uval.bd[5] = *bp++;
5214	uval.bd[4] = *bp++;
5215	uval.bd[3] = *bp++;
5216	uval.bd[2] = *bp++;
5217	uval.bd[1] = *bp++;
5218	uval.bd[0] = *bp;
5219#endif /* ! WORDS_BIGENDIAN */
5220	return uval.dv;
5221}
5222
5223static int
5224getshort(
5225	 unsigned char *p
5226	 )
5227{
5228	return get_msb_short(&p);
5229}
5230
5231/*--------------------------------------------------
5232 * trimbletsip_message - process trimble messages
5233 */
5234#define RTOD (180.0 / 3.1415926535898)
5235#define mb(_X_) (buffer[2+(_X_)]) /* shortcut for buffer access */
5236
5237static void
5238trimbletsip_message(
5239		    struct parseunit *parse,
5240		    parsetime_t      *parsetime
5241		    )
5242{
5243	unsigned char *buffer = parsetime->parse_msg;
5244	unsigned int   size   = parsetime->parse_msglen;
5245
5246	if ((size < 4) ||
5247	    (buffer[0]      != DLE) ||
5248	    (buffer[size-1] != ETX) ||
5249	    (buffer[size-2] != DLE))
5250	{
5251#ifdef DEBUG
5252		if (debug > 2) {
5253			int i;
5254
5255			printf("TRIMBLE BAD packet, size %d:\n	", size);
5256			for (i = 0; i < size; i++) {
5257				printf ("%2.2x, ", buffer[i]&0xff);
5258				if (i%16 == 15) printf("\n\t");
5259			}
5260			printf("\n");
5261		}
5262#endif
5263		return;
5264	}
5265	else
5266	{
5267		int var_flag;
5268		trimble_t *tr = parse->localdata;
5269		unsigned int cmd = buffer[1];
5270		char pbuffer[200];
5271		char *t = pbuffer;
5272		cmd_info_t *s;
5273
5274#ifdef DEBUG
5275		if (debug > 3) {
5276			int i;
5277
5278			printf("TRIMBLE packet 0x%02x, size %d:\n	", cmd, size);
5279			for (i = 0; i < size; i++) {
5280				printf ("%2.2x, ", buffer[i]&0xff);
5281				if (i%16 == 15) printf("\n\t");
5282			}
5283			printf("\n");
5284		}
5285#endif
5286
5287		if (tr)
5288			tr->last_msg = current_time;
5289
5290		s = trimble_convert(cmd, trimble_rcmds);
5291
5292		if (s)
5293		{
5294			snprintf(t, BUFFER_SIZE(pbuffer, t), "%s=\"", s->varname);
5295		}
5296		else
5297		{
5298			DPRINTF(1, ("TRIMBLE UNKNOWN COMMAND 0x%02x\n", cmd));
5299			return;
5300		}
5301
5302		var_flag = s->varmode;
5303
5304		t += strlen(t);
5305
5306		switch(cmd)
5307		{
5308		case CMD_RCURTIME:
5309			snprintf(t, BUFFER_SIZE(pbuffer, t), "%f, %d, %f",
5310				 getflt((unsigned char *)&mb(0)), getshort((unsigned char *)&mb(4)),
5311				 getflt((unsigned char *)&mb(6)));
5312			break;
5313
5314		case CMD_RBEST4:
5315			strncpy(t, "mode: ", BUFFER_SIZE(pbuffer, t));
5316			t += strlen(t);
5317			switch (mb(0) & 0xF)
5318			{
5319			default:
5320				snprintf(t, BUFFER_SIZE(pbuffer, t), "0x%x", mb(0) & 0x7);
5321				break;
5322
5323			case 1:
5324				strncpy(t, "0D", BUFFER_SIZE(pbuffer, t));
5325				break;
5326
5327			case 3:
5328				strncpy(t, "2D", BUFFER_SIZE(pbuffer, t));
5329				break;
5330
5331			case 4:
5332				strncpy(t, "3D", BUFFER_SIZE(pbuffer, t));
5333				break;
5334			}
5335			t += strlen(t);
5336			if (mb(0) & 0x10)
5337				strncpy(t, "-MANUAL, ", BUFFER_SIZE(pbuffer, t));
5338			else
5339				strncpy(t, "-AUTO, ", BUFFER_SIZE(pbuffer, t));
5340			t += strlen(t);
5341
5342			snprintf(t, BUFFER_SIZE(pbuffer, t), "satellites %02d %02d %02d %02d, PDOP %.2f, HDOP %.2f, VDOP %.2f, TDOP %.2f",
5343				mb(1), mb(2), mb(3), mb(4),
5344				getflt((unsigned char *)&mb(5)),
5345				getflt((unsigned char *)&mb(9)),
5346				getflt((unsigned char *)&mb(13)),
5347				getflt((unsigned char *)&mb(17)));
5348
5349			break;
5350
5351		case CMD_RVERSION:
5352			snprintf(t, BUFFER_SIZE(pbuffer, t), "%d.%d (%d/%d/%d)",
5353				mb(0)&0xff, mb(1)&0xff, 1900+(mb(4)&0xff), mb(2)&0xff, mb(3)&0xff);
5354			break;
5355
5356		case CMD_RRECVHEALTH:
5357		{
5358			static const char *msgs[] =
5359			{
5360				"Battery backup failed",
5361				"Signal processor error",
5362				"Alignment error, channel or chip 1",
5363				"Alignment error, channel or chip 2",
5364				"Antenna feed line fault",
5365				"Excessive ref freq. error",
5366				"<BIT 6>",
5367				"<BIT 7>"
5368			};
5369
5370			int i, bits;
5371
5372			switch (mb(0) & 0xFF)
5373			{
5374			default:
5375				snprintf(t, BUFFER_SIZE(pbuffer, t), "illegal value 0x%02x", mb(0) & 0xFF);
5376				break;
5377			case 0x00:
5378				strncpy(t, "doing position fixes", BUFFER_SIZE(pbuffer, t));
5379				break;
5380			case 0x01:
5381				strncpy(t, "no GPS time yet", BUFFER_SIZE(pbuffer, t));
5382				break;
5383			case 0x03:
5384				strncpy(t, "PDOP too high", BUFFER_SIZE(pbuffer, t));
5385				break;
5386			case 0x08:
5387				strncpy(t, "no usable satellites", BUFFER_SIZE(pbuffer, t));
5388				break;
5389			case 0x09:
5390				strncpy(t, "only ONE usable satellite", BUFFER_SIZE(pbuffer, t));
5391				break;
5392			case 0x0A:
5393				strncpy(t, "only TWO usable satellites", BUFFER_SIZE(pbuffer, t));
5394				break;
5395			case 0x0B:
5396				strncpy(t, "only THREE usable satellites", BUFFER_SIZE(pbuffer, t));
5397				break;
5398			case 0x0C:
5399				strncpy(t, "the chosen satellite is unusable", BUFFER_SIZE(pbuffer, t));
5400				break;
5401			}
5402
5403			t += strlen(t);
5404
5405			bits = mb(1) & 0xFF;
5406
5407			for (i = 0; i < 8; i++)
5408				if (bits & (0x1<<i))
5409				{
5410					snprintf(t, BUFFER_SIZE(pbuffer, t), ", %s", msgs[i]);
5411					t += strlen(t);
5412				}
5413		}
5414		break;
5415
5416		case CMD_RMESSAGE:
5417			mkreadable(t, (int)BUFFER_SIZE(pbuffer, t), (char *)&mb(0), (unsigned)(size - 2 - (&mb(0) - buffer)), 0);
5418			break;
5419
5420		case CMD_RMACHSTAT:
5421		{
5422			static const char *msgs[] =
5423			{
5424				"Synthesizer Fault",
5425				"Battery Powered Time Clock Fault",
5426				"A-to-D Converter Fault",
5427				"The almanac stored in the receiver is not complete and current",
5428				"<BIT 4>",
5429				"<BIT 5",
5430				"<BIT 6>",
5431				"<BIT 7>"
5432			};
5433
5434			int i, bits;
5435
5436			snprintf(t, BUFFER_SIZE(pbuffer, t), "machine id 0x%02x", mb(0) & 0xFF);
5437			t += strlen(t);
5438
5439			bits = mb(1) & 0xFF;
5440
5441			for (i = 0; i < 8; i++)
5442				if (bits & (0x1<<i))
5443				{
5444					snprintf(t, BUFFER_SIZE(pbuffer, t), ", %s", msgs[i]);
5445					t += strlen(t);
5446				}
5447
5448			snprintf(t, BUFFER_SIZE(pbuffer, t), ", Superpackets %ssupported", (mb(2) & 0xFF) ? "" :"un" );
5449		}
5450		break;
5451
5452		case CMD_ROPERPARAM:
5453			snprintf(t, BUFFER_SIZE(pbuffer, t), "%2x %.1f %.1f %.1f %.1f",
5454				mb(0), getflt((unsigned char *)&mb(1)), getflt((unsigned char *)&mb(5)),
5455				getflt((unsigned char *)&mb(9)), getflt((unsigned char *)&mb(13)));
5456			break;
5457
5458		case CMD_RUTCPARAM:
5459		{
5460			float t0t = getflt((unsigned char *)&mb(14));
5461			short wnt = getshort((unsigned char *)&mb(18));
5462			short dtls = getshort((unsigned char *)&mb(12));
5463			short wnlsf = getshort((unsigned char *)&mb(20));
5464			short dn = getshort((unsigned char *)&mb(22));
5465			short dtlsf = getshort((unsigned char *)&mb(24));
5466
5467			if ((int)t0t != 0)
5468			  {
5469				  mk_utcinfo(t, wnt, wnlsf, dn, dtls, dtlsf, BUFFER_SIZE(pbuffer, t));
5470			  }
5471			else
5472			  {
5473			    strncpy(t, "<NO UTC DATA>", BUFFER_SIZE(pbuffer, t));
5474			  }
5475		}
5476		break;
5477
5478		case CMD_RSAT1BIAS:
5479			snprintf(t, BUFFER_SIZE(pbuffer, t), "%.1fm %.2fm/s at %.1fs",
5480				getflt(&mb(0)), getflt(&mb(4)), getflt(&mb(8)));
5481			break;
5482
5483		case CMD_RIOOPTIONS:
5484		{
5485			snprintf(t, BUFFER_SIZE(pbuffer, t), "%02x %02x %02x %02x",
5486				mb(0), mb(1), mb(2), mb(3));
5487			if (mb(0) != TRIM_POS_OPT ||
5488			    mb(2) != TRIM_TIME_OPT)
5489			{
5490				(void)trimbletsip_setup(parse, "bad io options");
5491			}
5492		}
5493		break;
5494
5495		case CMD_RSPOSXYZ:
5496		{
5497			double x = getflt((unsigned char *)&mb(0));
5498			double y = getflt((unsigned char *)&mb(4));
5499			double z = getflt((unsigned char *)&mb(8));
5500			double f = getflt((unsigned char *)&mb(12));
5501
5502			if (f > 0.0)
5503			  snprintf(t, BUFFER_SIZE(pbuffer, t), "x= %.1fm, y= %.1fm, z= %.1fm, time_of_fix= %f sec",
5504				  x, y, z,
5505				  f);
5506			else
5507			  return;
5508		}
5509		break;
5510
5511		case CMD_RSLLAPOS:
5512		{
5513			double lat = getflt((unsigned char *)&mb(0));
5514			double lng = getflt((unsigned char *)&mb(4));
5515			double f   = getflt((unsigned char *)&mb(12));
5516
5517			if (f > 0.0)
5518			  snprintf(t, BUFFER_SIZE(pbuffer, t), "lat %f %c, long %f %c, alt %.2fm",
5519				  ((lat < 0.0) ? (-lat) : (lat))*RTOD, (lat < 0.0 ? 'S' : 'N'),
5520				  ((lng < 0.0) ? (-lng) : (lng))*RTOD, (lng < 0.0 ? 'W' : 'E'),
5521				  getflt((unsigned char *)&mb(8)));
5522			else
5523			  return;
5524		}
5525		break;
5526
5527		case CMD_RDOUBLEXYZ:
5528		{
5529			double x = getdbl((unsigned char *)&mb(0));
5530			double y = getdbl((unsigned char *)&mb(8));
5531			double z = getdbl((unsigned char *)&mb(16));
5532			snprintf(t, BUFFER_SIZE(pbuffer, t), "x= %.1fm, y= %.1fm, z= %.1fm",
5533				x, y, z);
5534		}
5535		break;
5536
5537		case CMD_RDOUBLELLA:
5538		{
5539			double lat = getdbl((unsigned char *)&mb(0));
5540			double lng = getdbl((unsigned char *)&mb(8));
5541			snprintf(t, BUFFER_SIZE(pbuffer, t), "lat %f %c, lon %f %c, alt %.2fm",
5542				((lat < 0.0) ? (-lat) : (lat))*RTOD, (lat < 0.0 ? 'S' : 'N'),
5543				((lng < 0.0) ? (-lng) : (lng))*RTOD, (lng < 0.0 ? 'W' : 'E'),
5544				getdbl((unsigned char *)&mb(16)));
5545		}
5546		break;
5547
5548		case CMD_RALLINVIEW:
5549		{
5550			int i, sats;
5551
5552			strncpy(t, "mode: ", BUFFER_SIZE(pbuffer, t));
5553			t += strlen(t);
5554			switch (mb(0) & 0x7)
5555			{
5556			default:
5557				snprintf(t, BUFFER_SIZE(pbuffer, t), "0x%x", mb(0) & 0x7);
5558				break;
5559
5560			case 3:
5561				strncpy(t, "2D", BUFFER_SIZE(pbuffer, t));
5562				break;
5563
5564			case 4:
5565				strncpy(t, "3D", BUFFER_SIZE(pbuffer, t));
5566				break;
5567			}
5568			t += strlen(t);
5569			if (mb(0) & 0x8)
5570				strncpy(t, "-MANUAL, ", BUFFER_SIZE(pbuffer, t));
5571			else
5572				strncpy(t, "-AUTO, ", BUFFER_SIZE(pbuffer, t));
5573			t += strlen(t);
5574
5575			sats = (mb(0)>>4) & 0xF;
5576
5577			snprintf(t, BUFFER_SIZE(pbuffer, t), "PDOP %.2f, HDOP %.2f, VDOP %.2f, TDOP %.2f, %d satellite%s in view: ",
5578				getflt((unsigned char *)&mb(1)),
5579				getflt((unsigned char *)&mb(5)),
5580				getflt((unsigned char *)&mb(9)),
5581				getflt((unsigned char *)&mb(13)),
5582				sats, (sats == 1) ? "" : "s");
5583			t += strlen(t);
5584
5585			for (i=0; i < sats; i++)
5586			{
5587				snprintf(t, BUFFER_SIZE(pbuffer, t), "%s%02d", i ? ", " : "", mb(17+i));
5588				t += strlen(t);
5589				if (tr)
5590					tr->ctrack |= (1 << (mb(17+i)-1));
5591			}
5592
5593			if (tr)
5594                        { /* mark for tracking status query */
5595				tr->qtracking = 1;
5596			}
5597		}
5598		break;
5599
5600		case CMD_RSTATTRACK:
5601		{
5602			snprintf(t-2, BUFFER_SIZE(pbuffer, t-2), "[%02d]=\"", mb(0)); /* add index to var name */
5603			t += strlen(t);
5604
5605			if (getflt((unsigned char *)&mb(4)) < 0.0)
5606			{
5607				strncpy(t, "<NO MEASUREMENTS>", BUFFER_SIZE(pbuffer, t));
5608				var_flag &= ~DEF;
5609			}
5610			else
5611			{
5612				snprintf(t, BUFFER_SIZE(pbuffer, t), "ch=%d, acq=%s, eph=%d, signal_level= %5.2f, elevation= %5.2f, azimuth= %6.2f",
5613					(mb(1) & 0xFF)>>3,
5614					mb(2) ? ((mb(2) == 1) ? "ACQ" : "SRCH") : "NEVER",
5615					mb(3),
5616					getflt((unsigned char *)&mb(4)),
5617					getflt((unsigned char *)&mb(12)) * RTOD,
5618					getflt((unsigned char *)&mb(16)) * RTOD);
5619				t += strlen(t);
5620				if (mb(20))
5621				{
5622					var_flag &= ~DEF;
5623					strncpy(t, ", OLD", BUFFER_SIZE(pbuffer, t));
5624				}
5625				t += strlen(t);
5626				if (mb(22))
5627				{
5628					if (mb(22) == 1)
5629						strncpy(t, ", BAD PARITY", BUFFER_SIZE(pbuffer, t));
5630					else
5631						if (mb(22) == 2)
5632							strncpy(t, ", BAD EPH HEALTH", BUFFER_SIZE(pbuffer, t));
5633				}
5634				t += strlen(t);
5635				if (mb(23))
5636					strncpy(t, ", collecting data", BUFFER_SIZE(pbuffer, t));
5637			}
5638		}
5639		break;
5640
5641		default:
5642			strncpy(t, "<UNDECODED>", BUFFER_SIZE(pbuffer, t));
5643			break;
5644		}
5645		t += strlen(t);
5646
5647		strncpy(t,"\"", BUFFER_SIZE(pbuffer, t));
5648		set_var(&parse->kv, pbuffer, sizeof(pbuffer), var_flag);
5649	}
5650}
5651
5652
5653/**============================================================
5654 ** RAWDCF support
5655 **/
5656
5657/*--------------------------------------------------
5658 * rawdcf_init_1 - set up modem lines for RAWDCF receivers
5659 * SET DTR line
5660 */
5661#if defined(TIOCMSET) && (defined(TIOCM_DTR) || defined(CIOCM_DTR))
5662static int
5663rawdcf_init_1(
5664	struct parseunit *parse
5665	)
5666{
5667	/* fixed 2000 for using with Linux by Wolfram Pienkoss <wp@bszh.de> */
5668	/*
5669	 * You can use the RS232 to supply the power for a DCF77 receiver.
5670	 * Here a voltage between the DTR and the RTS line is used. Unfortunately
5671	 * the name has changed from CIOCM_DTR to TIOCM_DTR recently.
5672	 */
5673	int sl232;
5674
5675	if (ioctl(parse->generic->io.fd, TIOCMGET, (caddr_t)&sl232) == -1)
5676	{
5677		msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_1: WARNING: ioctl(fd, TIOCMGET, [C|T]IOCM_DTR): %m", CLK_UNIT(parse->peer));
5678		return 0;
5679	}
5680
5681#ifdef TIOCM_DTR
5682	sl232 = (sl232 & ~TIOCM_RTS) | TIOCM_DTR;	/* turn on DTR, clear RTS for power supply */
5683#else
5684	sl232 = (sl232 & ~CIOCM_RTS) | CIOCM_DTR;	/* turn on DTR, clear RTS for power supply */
5685#endif
5686
5687	if (ioctl(parse->generic->io.fd, TIOCMSET, (caddr_t)&sl232) == -1)
5688	{
5689		msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_1: WARNING: ioctl(fd, TIOCMSET, [C|T]IOCM_DTR): %m", CLK_UNIT(parse->peer));
5690	}
5691	return 0;
5692}
5693#else
5694static int
5695rawdcfdtr_init_1(
5696	struct parseunit *parse
5697	)
5698{
5699	msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_1: WARNING: OS interface incapable of setting DTR to power DCF modules", CLK_UNIT(parse->peer));
5700	return 0;
5701}
5702#endif  /* DTR initialisation type */
5703
5704/*--------------------------------------------------
5705 * rawdcf_init_2 - set up modem lines for RAWDCF receivers
5706 * CLR DTR line, SET RTS line
5707 */
5708#if defined(TIOCMSET) &&  (defined(TIOCM_RTS) || defined(CIOCM_RTS))
5709static int
5710rawdcf_init_2(
5711	struct parseunit *parse
5712	)
5713{
5714	/* fixed 2000 for using with Linux by Wolfram Pienkoss <wp@bszh.de> */
5715	/*
5716	 * You can use the RS232 to supply the power for a DCF77 receiver.
5717	 * Here a voltage between the DTR and the RTS line is used. Unfortunately
5718	 * the name has changed from CIOCM_DTR to TIOCM_DTR recently.
5719	 */
5720	int sl232;
5721
5722	if (ioctl(parse->generic->io.fd, TIOCMGET, (caddr_t)&sl232) == -1)
5723	{
5724		msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_2: WARNING: ioctl(fd, TIOCMGET, [C|T]IOCM_RTS): %m", CLK_UNIT(parse->peer));
5725		return 0;
5726	}
5727
5728#ifdef TIOCM_RTS
5729	sl232 = (sl232 & ~TIOCM_DTR) | TIOCM_RTS;	/* turn on RTS, clear DTR for power supply */
5730#else
5731	sl232 = (sl232 & ~CIOCM_DTR) | CIOCM_RTS;	/* turn on RTS, clear DTR for power supply */
5732#endif
5733
5734	if (ioctl(parse->generic->io.fd, TIOCMSET, (caddr_t)&sl232) == -1)
5735	{
5736		msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_2: WARNING: ioctl(fd, TIOCMSET, [C|T]IOCM_RTS): %m", CLK_UNIT(parse->peer));
5737	}
5738	return 0;
5739}
5740#else
5741static int
5742rawdcf_init_2(
5743	struct parseunit *parse
5744	)
5745{
5746	msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_2: WARNING: OS interface incapable of setting RTS to power DCF modules", CLK_UNIT(parse->peer));
5747	return 0;
5748}
5749#endif  /* DTR initialisation type */
5750
5751#else	/* defined(REFCLOCK) && defined(PARSE) */
5752int refclock_parse_bs;
5753#endif	/* defined(REFCLOCK) && defined(PARSE) */
5754
5755/*
5756 * History:
5757 *
5758 * refclock_parse.c,v
5759 * Revision 4.81  2009/05/01 10:15:29  kardel
5760 * use new refclock_ppsapi interface
5761 *
5762 * Revision 4.80  2007/08/11 12:06:29  kardel
5763 * update comments wrt/ to PPS
5764 *
5765 * Revision 4.79  2007/08/11 11:52:23  kardel
5766 * - terminate io bindings before io_closeclock() will close our file descriptor
5767 *
5768 * Revision 4.78  2006/12/22 20:08:27  kardel
5769 * Bug 746 (RFE): add configuration for Expert mouseCLOCK USB v2.0 as mode 19
5770 *
5771 * Revision 4.77  2006/08/05 07:44:49  kardel
5772 * support optionally separate PPS devices via /dev/refclockpps-{0..3}
5773 *
5774 * Revision 4.76  2006/06/22 18:40:47  kardel
5775 * clean up signedness (gcc 4)
5776 *
5777 * Revision 4.75  2006/06/22 16:58:10  kardel
5778 * Bug #632: call parse_ppsapi() in parse_ctl() when updating
5779 * the PPS offset. Fix sign of offset passed to kernel.
5780 *
5781 * Revision 4.74  2006/06/18 21:18:37  kardel
5782 * NetBSD Coverity CID 3796: possible NULL deref
5783 *
5784 * Revision 4.73  2006/05/26 14:23:46  kardel
5785 * cleanup of copyright info
5786 *
5787 * Revision 4.72  2006/05/26 14:19:43  kardel
5788 * cleanup of ioctl cruft
5789 *
5790 * Revision 4.71  2006/05/26 14:15:57  kardel
5791 * delay adding refclock to async refclock io after all initializations
5792 *
5793 * Revision 4.70  2006/05/25 18:20:50  kardel
5794 * bug #619
5795 * terminate parse io engine after de-registering
5796 * from refclock io engine
5797 *
5798 * Revision 4.69  2006/05/25 17:28:02  kardel
5799 * complete refclock io structure initialization *before* inserting it into the
5800 * refclock input machine (avoids null pointer deref) (bug #619)
5801 *
5802 * Revision 4.68  2006/05/01 17:02:51  kardel
5803 * copy receiver method also for newlwy created receive buffers
5804 *
5805 * Revision 4.67  2006/05/01 14:37:29  kardel
5806 * If an input buffer parses into more than one message do insert the
5807 * parsed message in a new input buffer instead of processing it
5808 * directly. This avoids deed complicated processing in signal
5809 * handling.
5810 *
5811 * Revision 4.66  2006/03/18 00:45:30  kardel
5812 * coverity fixes found in NetBSD coverity scan
5813 *
5814 * Revision 4.65  2006/01/26 06:08:33  kardel
5815 * output errno on PPS setup failure
5816 *
5817 * Revision 4.64  2005/11/09 20:44:47  kardel
5818 * utilize full PPS timestamp resolution from PPS API
5819 *
5820 * Revision 4.63  2005/10/07 22:10:25  kardel
5821 * bounded buffer implementation
5822 *
5823 * Revision 4.62.2.2  2005/09/25 10:20:16  kardel
5824 * avoid unexpected buffer overflows due to sprintf("%f") on strange floats:
5825 * replace almost all str* and *printf functions be their buffer bounded
5826 * counterparts
5827 *
5828 * Revision 4.62.2.1  2005/08/27 16:19:27  kardel
5829 * limit re-set rate of trimble clocks
5830 *
5831 * Revision 4.62  2005/08/06 17:40:00  kardel
5832 * cleanup size handling wrt/ to buffer boundaries
5833 *
5834 * Revision 4.61  2005/07/27 21:16:19  kardel
5835 * fix a long (> 11 years) misconfiguration wrt/ Meinberg cflag factory
5836 * default setup. CSTOPB was missing for the 7E2 default data format of
5837 * the DCF77 clocks.
5838 *
5839 * Revision 4.60  2005/07/17 21:14:44  kardel
5840 * change contents of version string to include the RCS/CVS Id
5841 *
5842 * Revision 4.59  2005/07/06 06:56:38  kardel
5843 * syntax error
5844 *
5845 * Revision 4.58  2005/07/04 13:10:40  kardel
5846 * fix bug 455: tripping over NULL pointer on cleanup
5847 * fix shadow storage logic for ppsphaseadjust and trustime wrt/ time2
5848 * fix compiler warnings for some platforms wrt/ printf formatstrings and
5849 *     varying structure element sizes
5850 * reorder assignment in binding to avoid tripping over NULL pointers
5851 *
5852 * Revision 4.57  2005/06/25 09:25:19  kardel
5853 * sort out log output sequence
5854 *
5855 * Revision 4.56  2005/06/14 21:47:27  kardel
5856 * collect samples only if samples are ok (sync or trusted flywheel)
5857 * propagate pps phase adjustment value to kernel via PPSAPI to help HARDPPS
5858 * en- and dis-able HARDPPS in correlation to receiver sync state
5859 *
5860 * Revision 4.55  2005/06/02 21:28:31  kardel
5861 * clarify trust logic
5862 *
5863 * Revision 4.54  2005/06/02 17:06:49  kardel
5864 * change status reporting to use fixed refclock_report()
5865 *
5866 * Revision 4.53  2005/06/02 16:33:31  kardel
5867 * fix acceptance of clocks unsync clocks right at start
5868 *
5869 * Revision 4.52  2005/05/26 21:55:06  kardel
5870 * cleanup status reporting
5871 *
5872 * Revision 4.51  2005/05/26 19:19:14  kardel
5873 * implement fast refclock startup
5874 *
5875 * Revision 4.50  2005/04/16 20:51:35  kardel
5876 * set pps_enable = 1 when binding a kernel PPS source
5877 *
5878 * Revision 4.49  2005/04/16 17:29:26  kardel
5879 * add non polling clock type 18 for just listenning to Meinberg clocks
5880 *
5881 * Revision 4.48  2005/04/16 16:22:27  kardel
5882 * bk sync 20050415 ntp-dev
5883 *
5884 * Revision 4.47  2004/11/29 10:42:48  kardel
5885 * bk sync ntp-dev 20041129
5886 *
5887 * Revision 4.46  2004/11/29 10:26:29  kardel
5888 * keep fudgetime2 in sync with trusttime/ppsphaseadjust depending in flag1
5889 *
5890 * Revision 4.45  2004/11/14 20:53:20  kardel
5891 * clear PPS flags after using them
5892 *
5893 * Revision 4.44  2004/11/14 15:29:41  kardel
5894 * support PPSAPI, upgrade Copyright to Berkeley style
5895 *
5896 * Revision 4.43  2001/05/26 22:53:16  kardel
5897 * 20010526 reconcilation
5898 *
5899 * Revision 4.42  2000/05/14 15:31:51  kardel
5900 * PPSAPI && RAWDCF modemline support
5901 *
5902 * Revision 4.41  2000/04/09 19:50:45  kardel
5903 * fixed rawdcfdtr_init() -> rawdcf_init_1
5904 *
5905 * Revision 4.40  2000/04/09 15:27:55  kardel
5906 * modem line fiddle in rawdcf_init_2
5907 *
5908 * Revision 4.39  2000/03/18 09:16:55  kardel
5909 * PPSAPI integration
5910 *
5911 * Revision 4.38  2000/03/05 20:25:06  kardel
5912 * support PPSAPI
5913 *
5914 * Revision 4.37  2000/03/05 20:11:14  kardel
5915 * 4.0.99g reconcilation
5916 *
5917 * Revision 4.36  1999/11/28 17:18:20  kardel
5918 * disabled burst mode
5919 *
5920 * Revision 4.35  1999/11/28 09:14:14  kardel
5921 * RECON_4_0_98F
5922 *
5923 * Revision 4.34  1999/05/14 06:08:05  kardel
5924 * store current_time in a suitable container (u_long)
5925 *
5926 * Revision 4.33  1999/05/13 21:48:38  kardel
5927 * double the no response timeout interval
5928 *
5929 * Revision 4.32  1999/05/13 20:09:13  kardel
5930 * complain only about missing polls after a full poll interval
5931 *
5932 * Revision 4.31  1999/05/13 19:59:32  kardel
5933 * add clock type 16 for RTS set DTR clr in RAWDCF
5934 *
5935 * Revision 4.30  1999/02/28 20:36:43  kardel
5936 * fixed printf fmt
5937 *
5938 * Revision 4.29  1999/02/28 19:58:23  kardel
5939 * updated copyright information
5940 *
5941 * Revision 4.28  1999/02/28 19:01:50  kardel
5942 * improved debug out on sent Meinberg messages
5943 *
5944 * Revision 4.27  1999/02/28 18:05:55  kardel
5945 * no linux/ppsclock.h stuff
5946 *
5947 * Revision 4.26  1999/02/28 15:27:27  kardel
5948 * wharton clock integration
5949 *
5950 * Revision 4.25  1999/02/28 14:04:46  kardel
5951 * added missing double quotes to UTC information string
5952 *
5953 * Revision 4.24  1999/02/28 12:06:50  kardel
5954 * (parse_control): using gmprettydate instead of prettydate()
5955 * (mk_utcinfo): new function for formatting GPS derived UTC information
5956 * (gps16x_message): changed to use mk_utcinfo()
5957 * (trimbletsip_message): changed to use mk_utcinfo()
5958 * ignoring position information in unsynchronized mode
5959 * (parse_start): augument linux support for optional ASYNC_LOW_LATENCY
5960 *
5961 * Revision 4.23  1999/02/23 19:47:53  kardel
5962 * fixed #endifs
5963 * (stream_receive): fixed formats
5964 *
5965 * Revision 4.22  1999/02/22 06:21:02  kardel
5966 * use new autoconfig symbols
5967 *
5968 * Revision 4.21  1999/02/21 12:18:13  kardel
5969 * 4.91f reconcilation
5970 *
5971 * Revision 4.20  1999/02/21 10:53:36  kardel
5972 * initial Linux PPSkit version
5973 *
5974 * Revision 4.19  1999/02/07 09:10:45  kardel
5975 * clarify STREAMS mitigation rules in comment
5976 *
5977 * Revision 4.18  1998/12/20 23:45:34  kardel
5978 * fix types and warnings
5979 *
5980 * Revision 4.17  1998/11/15 21:24:51  kardel
5981 * cannot access mbg_ routines when CLOCK_MEINBERG
5982 * is not defined
5983 *
5984 * Revision 4.16  1998/11/15 20:28:17  kardel
5985 * Release 4.0.73e13 reconcilation
5986 *
5987 * Revision 4.15  1998/08/22 21:56:08  kardel
5988 * fixed IO handling for non-STREAM IO
5989 *
5990 * Revision 4.14  1998/08/16 19:00:48  kardel
5991 * (gps16x_message): reduced UTC parameter information (dropped A0,A1)
5992 * made uval a local variable (killed one of the last globals)
5993 * (sendetx): added logging of messages when in debug mode
5994 * (trimble_check): added periodic checks to facilitate re-initialization
5995 * (trimbletsip_init): made use of EOL character if in non-kernel operation
5996 * (trimbletsip_message): extended message interpretation
5997 * (getdbl): fixed data conversion
5998 *
5999 * Revision 4.13  1998/08/09 22:29:13  kardel
6000 * Trimble TSIP support
6001 *
6002 * Revision 4.12  1998/07/11 10:05:34  kardel
6003 * Release 4.0.73d reconcilation
6004 *
6005 * Revision 4.11  1998/06/14 21:09:42  kardel
6006 * Sun acc cleanup
6007 *
6008 * Revision 4.10  1998/06/13 12:36:45  kardel
6009 * signed/unsigned, name clashes
6010 *
6011 * Revision 4.9  1998/06/12 15:30:00  kardel
6012 * prototype fixes
6013 *
6014 * Revision 4.8  1998/06/12 11:19:42  kardel
6015 * added direct input processing routine for refclocks in
6016 * order to avaiod that single character io gobbles up all
6017 * receive buffers and drops input data. (Problem started
6018 * with fast machines so a character a buffer was possible
6019 * one of the few cases where faster machines break existing
6020 * allocation algorithms)
6021 *
6022 * Revision 4.7  1998/06/06 18:35:20  kardel
6023 * (parse_start): added BURST mode initialisation
6024 *
6025 * Revision 4.6  1998/05/27 06:12:46  kardel
6026 * RAWDCF_BASEDELAY default added
6027 * old comment removed
6028 * casts for ioctl()
6029 *
6030 * Revision 4.5  1998/05/25 22:05:09  kardel
6031 * RAWDCF_SETDTR option removed
6032 * clock type 14 attempts to set DTR for
6033 * power supply of RAWDCF receivers
6034 *
6035 * Revision 4.4  1998/05/24 16:20:47  kardel
6036 * updated comments referencing Meinberg clocks
6037 * added RAWDCF clock with DTR set option as type 14
6038 *
6039 * Revision 4.3  1998/05/24 10:48:33  kardel
6040 * calibrated CONRAD RAWDCF default fudge factor
6041 *
6042 * Revision 4.2  1998/05/24 09:59:35  kardel
6043 * corrected version information (ntpq support)
6044 *
6045 * Revision 4.1  1998/05/24 09:52:31  kardel
6046 * use fixed format only (new IO model)
6047 * output debug to stdout instead of msyslog()
6048 * don't include >"< in ASCII output in order not to confuse
6049 * ntpq parsing
6050 *
6051 * Revision 4.0  1998/04/10 19:52:11  kardel
6052 * Start 4.0 release version numbering
6053 *
6054 * Revision 1.2  1998/04/10 19:28:04  kardel
6055 * initial NTP VERSION 4 integration of PARSE with GPS166 binary support
6056 * derived from 3.105.1.2 from V3 tree
6057 *
6058 * Revision information 3.1 - 3.105 from log deleted 1998/04/10 kardel
6059 *
6060 */
6061