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