xref: /netbsd-src/external/bsd/ntp/dist/ntpd/refclock_parse.c (revision 7788a0781fe6ff2cce37368b4578a7ade0850cb1)
1 /*	$NetBSD: refclock_parse.c,v 1.9 2012/08/12 07:22:24 christos 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 
194 static 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 
200 static	int	parse_start	(int, struct peer *);
201 static	void	parse_shutdown	(int, struct peer *);
202 static	void	parse_poll	(int, struct peer *);
203 static	void	parse_control	(int, struct refclockstat *, struct refclockstat *, struct peer *);
204 
205 struct	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 
232 struct parseunit;		/* to keep inquiring minds happy */
233 
234 typedef 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 
291 struct errorregression
292 {
293 	u_long err_count;	/* number of repititions per class */
294 	u_long err_delay;	/* minimum delay between messages */
295 };
296 
297 static struct errorregression
298 err_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 
306 static struct errorregression
307 err_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 
315 static struct errorregression
316 err_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 
324 static struct errorregression
325 err_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 
333 static struct errorregression
334 err_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 
342 static struct errorregression
343 err_internal[] =		/* really bad things - basically coding/OS errors */
344 {
345 	{ 0,       0 },		/* output all messages immediately */
346 };
347 
348 static struct errorregression *
349 err_tbl[] =
350 {
351 	err_baddata,
352 	err_nodata,
353 	err_badio,
354 	err_badstatus,
355 	err_badevent,
356 	err_internal
357 };
358 
359 struct 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 
372 struct 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 
427 static	void	poll_dpoll	(struct parseunit *);
428 static	void	poll_poll	(struct peer *);
429 static	int	poll_init	(struct parseunit *);
430 
431 typedef 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  */
540 static	void	gps16x_message	 (struct parseunit *, parsetime_t *);
541 static  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 
559 static 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 
601 static 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  */
681 static	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  */
690 static	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 
705 static poll_info_t trimbletaip_pollinfo = { TRIM_POLLRATE, TRIM_TAIPPOLLCMD, TRIM_TAIPCMDSIZE };
706 static	int	trimbletaip_init	(struct parseunit *);
707 static	void	trimbletaip_event	(struct parseunit *, int);
708 
709 /* query time & UTC correction data */
710 static char tsipquery[] = { DLE, 0x21, DLE, ETX, DLE, 0x2F, DLE, ETX };
711 
712 static poll_info_t trimbletsip_pollinfo = { TRIM_POLLRATE, tsipquery, sizeof(tsipquery) };
713 static	int	trimbletsip_init	(struct parseunit *);
714 static	void	trimbletsip_end   	(struct parseunit *);
715 static	void	trimbletsip_message	(struct parseunit *, parsetime_t *);
716 static	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 
785 static 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 
861 static 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 
1452 static 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 
1466 static 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 
1470 static void parse_event   (struct parseunit *, int);
1471 static void parse_process (struct parseunit *, parsetime_t *);
1472 static void clear_err     (struct parseunit *, u_long);
1473 static int  list_err      (struct parseunit *, u_long);
1474 static char * l_mktime    (u_long);
1475 
1476 /**===========================================================================
1477  ** implementation error message regression module
1478  **/
1479 static void
1480 clear_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 
1508 static int
1509 list_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 
1563 static char *
1564 mkreadable(
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  */
1633 static char *
1634 mkascii(
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
1653 static int  ppsclock_init   (struct parseunit *);
1654 static int  stream_init     (struct parseunit *);
1655 static void stream_end      (struct parseunit *);
1656 static int  stream_enable   (struct parseunit *);
1657 static int  stream_disable  (struct parseunit *);
1658 static int  stream_setcs    (struct parseunit *, parsectl_t *);
1659 static int  stream_getfmt   (struct parseunit *, parsectl_t *);
1660 static int  stream_setfmt   (struct parseunit *, parsectl_t *);
1661 static int  stream_timecode (struct parseunit *, parsectl_t *);
1662 static void stream_receive  (struct recvbuf *);
1663 #endif
1664 
1665 static int  local_init     (struct parseunit *);
1666 static void local_end      (struct parseunit *);
1667 static int  local_nop      (struct parseunit *);
1668 static int  local_setcs    (struct parseunit *, parsectl_t *);
1669 static int  local_getfmt   (struct parseunit *, parsectl_t *);
1670 static int  local_setfmt   (struct parseunit *, parsectl_t *);
1671 static int  local_timecode (struct parseunit *, parsectl_t *);
1672 static void local_receive  (struct recvbuf *);
1673 static int  local_input    (struct recvbuf *);
1674 
1675 static 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  */
1761 static int
1762 ppsclock_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  */
1796 static int
1797 stream_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  */
1838 static void
1839 stream_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  */
1850 static int
1851 stream_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  */
1874 static int
1875 stream_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  */
1898 static int
1899 stream_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  */
1922 static int
1923 stream_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  */
1945 static int
1946 stream_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  */
1970 static int
1971 stream_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  */
1996 static void
1997 stream_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  */
2059 static int
2060 local_init(
2061 	struct parseunit *parse
2062 	)
2063 {
2064 	return parse_ioinit(&parse->parseio);
2065 }
2066 
2067 /*--------------------------------------------------
2068  * local end
2069  */
2070 static void
2071 local_end(
2072 	struct parseunit *parse
2073 	)
2074 {
2075 	parse_ioend(&parse->parseio);
2076 }
2077 
2078 
2079 /*--------------------------------------------------
2080  * local nop
2081  */
2082 static int
2083 local_nop(
2084 	struct parseunit *parse
2085 	)
2086 {
2087 	return 1;
2088 }
2089 
2090 /*--------------------------------------------------
2091  * local setcs
2092  */
2093 static int
2094 local_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  */
2105 static int
2106 local_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  */
2117 static int
2118 local_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  */
2129 static int
2130 local_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  */
2142 static int
2143 local_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  */
2352 static void
2353 local_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  */
2399 static bind_t *
2400 init_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 static char *
2422 ap(char *buffer, size_t len, char *pos, const char *fmt, ...)
2423 {
2424 	va_list va;
2425 	int l;
2426 	size_t rem = len - (pos - buffer);
2427 
2428 	if (rem == 0)
2429 		return pos;
2430 
2431 	va_start(va, fmt);
2432 	l = vsnprintf(pos, rem, fmt, va);
2433 	va_end(va);
2434 
2435 	if (l != -1) {
2436 		rem--;
2437 		if (rem >= (size_t)l)
2438 			pos += l;
2439 		else
2440 			pos += rem;
2441 	}
2442 
2443 	return pos;
2444 }
2445 
2446 /*--------------------------------------------------
2447  * convert a flag field to a string
2448  */
2449 static char *
2450 parsestate(
2451 	u_long lstate,
2452 	char *buffer,
2453 	int size
2454 	)
2455 {
2456 	static struct bits
2457 	{
2458 		u_long      bit;
2459 		const char *name;
2460 	} flagstrings[] =
2461 	  {
2462 		  { PARSEB_ANNOUNCE,   "DST SWITCH WARNING" },
2463 		  { PARSEB_POWERUP,    "NOT SYNCHRONIZED" },
2464 		  { PARSEB_NOSYNC,     "TIME CODE NOT CONFIRMED" },
2465 		  { PARSEB_DST,        "DST" },
2466 		  { PARSEB_UTC,        "UTC DISPLAY" },
2467 		  { PARSEB_LEAPADD,    "LEAP ADD WARNING" },
2468 		  { PARSEB_LEAPDEL,    "LEAP DELETE WARNING" },
2469 		  { PARSEB_LEAPSECOND, "LEAP SECOND" },
2470 		  { PARSEB_ALTERNATE,  "ALTERNATE ANTENNA" },
2471 		  { PARSEB_TIMECODE,   "TIME CODE" },
2472 		  { PARSEB_PPS,        "PPS" },
2473 		  { PARSEB_POSITION,   "POSITION" },
2474 		  { 0,		       NULL }
2475 	  };
2476 
2477 	static struct sbits
2478 	{
2479 		u_long      bit;
2480 		const char *name;
2481 	} sflagstrings[] =
2482 	  {
2483 		  { PARSEB_S_LEAP,     "LEAP INDICATION" },
2484 		  { PARSEB_S_PPS,      "PPS SIGNAL" },
2485 		  { PARSEB_S_ANTENNA,  "ANTENNA" },
2486 		  { PARSEB_S_POSITION, "POSITION" },
2487 		  { 0,		       NULL }
2488 	  };
2489 	int i;
2490 	char *s, *t;
2491 
2492 	s = t = buffer;
2493 
2494 	i = 0;
2495 	while (flagstrings[i].bit)
2496 	{
2497 		if (flagstrings[i].bit & lstate)
2498 		{
2499 			if (s != t)
2500 				t = ap(buffer, size, t, "; ");
2501 			t = ap(buffer, size, t, "%s", flagstrings[i].name);
2502 		}
2503 		i++;
2504 	}
2505 
2506 	if (lstate & (PARSEB_S_LEAP|PARSEB_S_ANTENNA|PARSEB_S_PPS|PARSEB_S_POSITION))
2507 	{
2508 		if (s != t)
2509 			t = ap(buffer, size, t, "; ");
2510 
2511 		t = ap(buffer, size, t, "(");
2512 
2513 		s = t;
2514 
2515 		i = 0;
2516 		while (sflagstrings[i].bit)
2517 		{
2518 			if (sflagstrings[i].bit & lstate)
2519 			{
2520 				if (t != s)
2521 				{
2522 					t = ap(buffer, size, t, "; ");
2523 				}
2524 
2525 				t = ap(buffer, size, t, "%s",
2526 				    sflagstrings[i].name);
2527 			}
2528 			i++;
2529 		}
2530 		t = ap(buffer, size, t, ")");
2531 	}
2532 	return buffer;
2533 }
2534 
2535 /*--------------------------------------------------
2536  * convert a status flag field to a string
2537  */
2538 static char *
2539 parsestatus(
2540 	u_long lstate,
2541 	char *buffer,
2542 	int size
2543 	)
2544 {
2545 	static struct bits
2546 	{
2547 		u_long      bit;
2548 		const char *name;
2549 	} flagstrings[] =
2550 	  {
2551 		  { CVT_OK,      "CONVERSION SUCCESSFUL" },
2552 		  { CVT_NONE,    "NO CONVERSION" },
2553 		  { CVT_FAIL,    "CONVERSION FAILED" },
2554 		  { CVT_BADFMT,  "ILLEGAL FORMAT" },
2555 		  { CVT_BADDATE, "DATE ILLEGAL" },
2556 		  { CVT_BADTIME, "TIME ILLEGAL" },
2557 		  { CVT_ADDITIONAL, "ADDITIONAL DATA" },
2558 		  { 0,		 NULL }
2559 	  };
2560 	int i;
2561 	char *t;
2562 
2563 	t = buffer;
2564 	*buffer = '\0';
2565 
2566 	i = 0;
2567 	while (flagstrings[i].bit)
2568 	{
2569 		if (flagstrings[i].bit & lstate)
2570 		{
2571 			if (t == buffer)
2572 				t = ap(buffer, size, t, "; ");
2573 			t = ap(buffer, size, t, "%s", flagstrings[i].name);
2574 		}
2575 		i++;
2576 	}
2577 
2578 	return buffer;
2579 }
2580 
2581 /*--------------------------------------------------
2582  * convert a clock status flag field to a string
2583  */
2584 static const char *
2585 clockstatus(
2586 	u_long lstate
2587 	)
2588 {
2589 	static char buffer[20];
2590 	static struct status
2591 	{
2592 		u_long      value;
2593 		const char *name;
2594 	} flagstrings[] =
2595 	  {
2596 		  { CEVNT_NOMINAL, "NOMINAL" },
2597 		  { CEVNT_TIMEOUT, "NO RESPONSE" },
2598 		  { CEVNT_BADREPLY,"BAD FORMAT" },
2599 		  { CEVNT_FAULT,   "FAULT" },
2600 		  { CEVNT_PROP,    "PROPAGATION DELAY" },
2601 		  { CEVNT_BADDATE, "ILLEGAL DATE" },
2602 		  { CEVNT_BADTIME, "ILLEGAL TIME" },
2603 		  { (unsigned)~0L, NULL }
2604 	  };
2605 	int i;
2606 
2607 	i = 0;
2608 	while (flagstrings[i].value != (u_int)~0)
2609 	{
2610 		if (flagstrings[i].value == lstate)
2611 		{
2612 			return flagstrings[i].name;
2613 		}
2614 		i++;
2615 	}
2616 
2617 	snprintf(buffer, sizeof(buffer), "unknown #%ld", (u_long)lstate);
2618 
2619 	return buffer;
2620 }
2621 
2622 
2623 /*--------------------------------------------------
2624  * l_mktime - make representation of a relative time
2625  */
2626 static char *
2627 l_mktime(
2628 	u_long delta
2629 	)
2630 {
2631 	u_long tmp, m, s;
2632 	static char buffer[40];
2633 	char *t;
2634 
2635 	buffer[0] = '\0';
2636 	t = buffer;
2637 
2638 	if ((tmp = delta / (60*60*24)) != 0)
2639 	{
2640 		t = ap(buffer, sizeof(buffer), t, "%ldd+", (u_long)tmp);
2641 		delta -= tmp * 60*60*24;
2642 	}
2643 
2644 	s = delta % 60;
2645 	delta /= 60;
2646 	m = delta % 60;
2647 	delta /= 60;
2648 
2649 	t = ap(buffer, sizeof(buffer), t, "%02d:%02d:%02d",
2650 	     (int)delta, (int)m, (int)s);
2651 
2652 	return buffer;
2653 }
2654 
2655 
2656 /*--------------------------------------------------
2657  * parse_statistics - list summary of clock states
2658  */
2659 static void
2660 parse_statistics(
2661 	struct parseunit *parse
2662 	)
2663 {
2664 	int i;
2665 
2666 	NLOG(NLOG_CLOCKSTATIST) /* conditional if clause for conditional syslog */
2667 		{
2668 			msyslog(LOG_INFO, "PARSE receiver #%d: running time: %s",
2669 				CLK_UNIT(parse->peer),
2670 				l_mktime(current_time - parse->generic->timestarted));
2671 
2672 			msyslog(LOG_INFO, "PARSE receiver #%d: current status: %s",
2673 				CLK_UNIT(parse->peer),
2674 				clockstatus(parse->generic->currentstatus));
2675 
2676 			for (i = 0; i <= CEVNT_MAX; i++)
2677 			{
2678 				u_long s_time;
2679 				u_long percent, d = current_time - parse->generic->timestarted;
2680 
2681 				percent = s_time = PARSE_STATETIME(parse, i);
2682 
2683 				while (((u_long)(~0) / 10000) < percent)
2684 				{
2685 					percent /= 10;
2686 					d       /= 10;
2687 				}
2688 
2689 				if (d)
2690 				    percent = (percent * 10000) / d;
2691 				else
2692 				    percent = 10000;
2693 
2694 				if (s_time)
2695 				    msyslog(LOG_INFO, "PARSE receiver #%d: state %18s: %13s (%3ld.%02ld%%)",
2696 					    CLK_UNIT(parse->peer),
2697 					    clockstatus((unsigned int)i),
2698 					    l_mktime(s_time),
2699 					    percent / 100, percent % 100);
2700 			}
2701 		}
2702 }
2703 
2704 /*--------------------------------------------------
2705  * cparse_statistics - wrapper for statistics call
2706  */
2707 static void
2708 cparse_statistics(
2709         struct parseunit *parse
2710 	)
2711 {
2712 	if (parse->laststatistic + PARSESTATISTICS < current_time)
2713 		parse_statistics(parse);
2714 	parse->laststatistic = current_time;
2715 }
2716 
2717 /**===========================================================================
2718  ** ntp interface routines
2719  **/
2720 
2721 /*--------------------------------------------------
2722  * parse_shutdown - shut down a PARSE clock
2723  */
2724 static void
2725 parse_shutdown(
2726 	int unit,
2727 	struct peer *peer
2728 	)
2729 {
2730 	struct parseunit *parse = (struct parseunit *)0;
2731 
2732 	if (peer && peer->procptr)
2733 		parse = (struct parseunit *)peer->procptr->unitptr;
2734 
2735 	if (!parse)
2736 	{
2737 		/* nothing to clean up */
2738 		return;
2739 	}
2740 
2741         if (!parse->peer)
2742 	{
2743 		msyslog(LOG_INFO, "PARSE receiver #%d: INTERNAL ERROR - unit already inactive - shutdown ignored", unit);
2744 		return;
2745 	}
2746 
2747 #ifdef HAVE_PPSAPI
2748 	if (parse->flags & PARSE_PPSCLOCK)
2749 	{
2750 		(void)time_pps_destroy(parse->atom.handle);
2751 	}
2752 #endif
2753 	if (parse->generic->io.fd != parse->ppsfd && parse->ppsfd != -1)
2754 		(void)close(parse->ppsfd);  /* close separate PPS source */
2755 
2756 	/*
2757 	 * print statistics a last time and
2758 	 * stop statistics machine
2759 	 */
2760 	parse_statistics(parse);
2761 
2762 	if (parse->parse_type->cl_end)
2763 	{
2764 		parse->parse_type->cl_end(parse);
2765 	}
2766 
2767 	/*
2768 	 * cleanup before leaving this world
2769 	 */
2770 	if (parse->binding)
2771 	    PARSE_END(parse);
2772 
2773 	/*
2774 	 * Tell the I/O module to turn us off.  We're history.
2775 	 */
2776 	io_closeclock(&parse->generic->io);
2777 
2778 	free_varlist(parse->kv);
2779 
2780 	NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */
2781 		msyslog(LOG_INFO, "PARSE receiver #%d: reference clock \"%s\" removed",
2782 			CLK_UNIT(parse->peer), parse->parse_type->cl_description);
2783 
2784 	parse->peer = (struct peer *)0; /* unused now */
2785 	peer->procptr->unitptr = (caddr_t)0;
2786 	free(parse);
2787 }
2788 
2789 #ifdef HAVE_PPSAPI
2790 /*----------------------------------------
2791  * set up HARDPPS via PPSAPI
2792  */
2793 static void
2794 parse_hardpps(
2795 	      struct parseunit *parse,
2796 	      int mode
2797 	      )
2798 {
2799         if (parse->hardppsstate == mode)
2800 	        return;
2801 
2802 	if (CLK_PPS(parse->peer) && (parse->flags & PARSE_PPSKERNEL)) {
2803 		int	i = 0;
2804 
2805 		if (mode == PARSE_HARDPPS_ENABLE)
2806 		        {
2807 			        if (parse->flags & PARSE_CLEAR)
2808 				        i = PPS_CAPTURECLEAR;
2809 				else
2810 				        i = PPS_CAPTUREASSERT;
2811 			}
2812 
2813 		if (time_pps_kcbind(parse->atom.handle, PPS_KC_HARDPPS, i,
2814 		    PPS_TSFMT_TSPEC) < 0) {
2815 		        msyslog(LOG_ERR, "PARSE receiver #%d: time_pps_kcbind failed: %m",
2816 				CLK_UNIT(parse->peer));
2817 		} else {
2818 		        NLOG(NLOG_CLOCKINFO)
2819 		                msyslog(LOG_INFO, "PARSE receiver #%d: kernel PPS synchronisation %sabled",
2820 					CLK_UNIT(parse->peer), (mode == PARSE_HARDPPS_ENABLE) ? "en" : "dis");
2821 			/*
2822 			 * tell the rest, that we have a kernel PPS source, iff we ever enable HARDPPS
2823 			 */
2824 			if (mode == PARSE_HARDPPS_ENABLE)
2825 			        pps_enable = 1;
2826 		}
2827 	}
2828 
2829 	parse->hardppsstate = mode;
2830 }
2831 
2832 /*----------------------------------------
2833  * set up PPS via PPSAPI
2834  */
2835 static int
2836 parse_ppsapi(
2837 	     struct parseunit *parse
2838 	)
2839 {
2840 	int cap, mode_ppsoffset;
2841 	const char *cp;
2842 
2843 	parse->flags &= ~PARSE_PPSCLOCK;
2844 
2845 	/*
2846 	 * collect PPSAPI offset capability - should move into generic handling
2847 	 */
2848 	if (time_pps_getcap(parse->atom.handle, &cap) < 0) {
2849 		msyslog(LOG_ERR, "PARSE receiver #%d: parse_ppsapi: time_pps_getcap failed: %m",
2850 			CLK_UNIT(parse->peer));
2851 
2852 		return 0;
2853 	}
2854 
2855 	/*
2856 	 * initialize generic PPSAPI interface
2857 	 *
2858 	 * we leave out CLK_FLAG3 as time_pps_kcbind()
2859 	 * is handled here for now. Ideally this should also
2860 	 * be part of the generic PPSAPI interface
2861 	 */
2862 	if (!refclock_params(parse->flags & (CLK_FLAG1|CLK_FLAG2|CLK_FLAG4), &parse->atom))
2863 		return 0;
2864 
2865 	/* nb. only turn things on, if someone else has turned something
2866 	 *	on before we get here, leave it alone!
2867 	 */
2868 
2869 	if (parse->flags & PARSE_CLEAR) {
2870 		cp = "CLEAR";
2871 		mode_ppsoffset = PPS_OFFSETCLEAR;
2872 	} else {
2873 		cp = "ASSERT";
2874 		mode_ppsoffset = PPS_OFFSETASSERT;
2875 	}
2876 
2877 	msyslog(LOG_INFO, "PARSE receiver #%d: initializing PPS to %s",
2878 		CLK_UNIT(parse->peer), cp);
2879 
2880 	if (!(mode_ppsoffset & cap)) {
2881 	  msyslog(LOG_WARNING, "PARSE receiver #%d: Cannot set PPS_%sCLEAR, this will increase jitter (PPS API capabilities=0x%x)",
2882 		  CLK_UNIT(parse->peer), cp, cap);
2883 		mode_ppsoffset = 0;
2884 	} else {
2885 	        if (mode_ppsoffset == PPS_OFFSETCLEAR)
2886 		        {
2887 			        parse->atom.pps_params.clear_offset.tv_sec = -parse->ppsphaseadjust;
2888 			        parse->atom.pps_params.clear_offset.tv_nsec = -1e9*(parse->ppsphaseadjust - (long)parse->ppsphaseadjust);
2889 			}
2890 
2891 		if (mode_ppsoffset == PPS_OFFSETASSERT)
2892 	                {
2893 		                parse->atom.pps_params.assert_offset.tv_sec = -parse->ppsphaseadjust;
2894 				parse->atom.pps_params.assert_offset.tv_nsec = -1e9*(parse->ppsphaseadjust - (long)parse->ppsphaseadjust);
2895 			}
2896 	}
2897 
2898 	parse->atom.pps_params.mode |= mode_ppsoffset;
2899 
2900 	if (time_pps_setparams(parse->atom.handle, &parse->atom.pps_params) < 0) {
2901 	  msyslog(LOG_ERR, "PARSE receiver #%d: FAILED set PPS parameters: %m",
2902 		  CLK_UNIT(parse->peer));
2903 		return 0;
2904 	}
2905 
2906 	parse->flags |= PARSE_PPSCLOCK;
2907 	return 1;
2908 }
2909 #else
2910 #define parse_hardpps(_PARSE_, _MODE_) /* empty */
2911 #endif
2912 
2913 /*--------------------------------------------------
2914  * parse_start - open the PARSE devices and initialize data for processing
2915  */
2916 static int
2917 parse_start(
2918 	int sysunit,
2919 	struct peer *peer
2920 	)
2921 {
2922 	u_int unit;
2923 	int fd232;
2924 #ifdef HAVE_TERMIOS
2925 	struct termios tio;		/* NEEDED FOR A LONG TIME ! */
2926 #endif
2927 #ifdef HAVE_SYSV_TTYS
2928 	struct termio tio;		/* NEEDED FOR A LONG TIME ! */
2929 #endif
2930 	struct parseunit * parse;
2931 	char parsedev[sizeof(PARSEDEVICE)+20];
2932 	char parseppsdev[sizeof(PARSEPPSDEVICE)+20];
2933 	parsectl_t tmp_ctl;
2934 	u_int type;
2935 
2936 	/*
2937 	 * get out Copyright information once
2938 	 */
2939 	if (!notice)
2940         {
2941 		NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */
2942 			msyslog(LOG_INFO, "NTP PARSE support: Copyright (c) 1989-2009, Frank Kardel");
2943 		notice = 1;
2944 	}
2945 
2946 	type = CLK_TYPE(peer);
2947 	unit = CLK_UNIT(peer);
2948 
2949 	if ((type == (u_int)~0) || (parse_clockinfo[type].cl_description == (char *)0))
2950 	{
2951 		msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: unsupported clock type %d (max %d)",
2952 			unit, CLK_REALTYPE(peer), ncltypes-1);
2953 		return 0;
2954 	}
2955 
2956 	/*
2957 	 * Unit okay, attempt to open the device.
2958 	 */
2959 	(void) snprintf(parsedev, sizeof(parsedev), PARSEDEVICE, unit);
2960 	(void) snprintf(parseppsdev, sizeof(parsedev), PARSEPPSDEVICE, unit);
2961 
2962 #ifndef O_NOCTTY
2963 #define O_NOCTTY 0
2964 #endif
2965 
2966 	fd232 = open(parsedev, O_RDWR | O_NOCTTY
2967 #ifdef O_NONBLOCK
2968 		     | O_NONBLOCK
2969 #endif
2970 		     , 0777);
2971 
2972 	if (fd232 == -1)
2973 	{
2974 		msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: open of %s failed: %m", unit, parsedev);
2975 		return 0;
2976 	}
2977 
2978 	parse = (struct parseunit *)emalloc(sizeof(struct parseunit));
2979 
2980 	memset((char *)parse, 0, sizeof(struct parseunit));
2981 
2982 	parse->generic = peer->procptr;	 /* link up */
2983 	parse->generic->unitptr = (caddr_t)parse; /* link down */
2984 
2985 	/*
2986 	 * Set up the structures
2987 	 */
2988 	parse->generic->timestarted    = current_time;
2989 	parse->lastchange     = current_time;
2990 
2991 	parse->flags          = 0;
2992 	parse->pollneeddata   = 0;
2993 	parse->laststatistic  = current_time;
2994 	parse->lastformat     = (unsigned short)~0;	/* assume no format known */
2995 	parse->timedata.parse_status = (unsigned short)~0;	/* be sure to mark initial status change */
2996 	parse->lastmissed     = 0;	/* assume got everything */
2997 	parse->ppsserial      = 0;
2998 	parse->ppsfd	      = -1;
2999 	parse->localdata      = (void *)0;
3000 	parse->localstate     = 0;
3001 	parse->kv             = (struct ctl_var *)0;
3002 
3003 	clear_err(parse, ERR_ALL);
3004 
3005 	parse->parse_type     = &parse_clockinfo[type];
3006 
3007 	parse->maxunsync      = parse->parse_type->cl_maxunsync;
3008 
3009 	parse->generic->fudgetime1 = parse->parse_type->cl_basedelay;
3010 
3011 	parse->generic->fudgetime2 = 0.0;
3012 	parse->ppsphaseadjust = parse->generic->fudgetime2;
3013 
3014 	parse->generic->clockdesc  = parse->parse_type->cl_description;
3015 
3016 	peer->rootdelay       = parse->parse_type->cl_rootdelay;
3017 	peer->sstclktype      = parse->parse_type->cl_type;
3018 	peer->precision       = sys_precision;
3019 
3020 	peer->stratum         = STRATUM_REFCLOCK;
3021 
3022 	if (peer->stratum <= 1)
3023 	    memmove((char *)&parse->generic->refid, parse->parse_type->cl_id, 4);
3024 	else
3025 	    parse->generic->refid = htonl(PARSEHSREFID);
3026 
3027 	parse->generic->io.fd = fd232;
3028 
3029 	parse->peer = peer;		/* marks it also as busy */
3030 
3031 	/*
3032 	 * configure terminal line
3033 	 */
3034 	if (TTY_GETATTR(fd232, &tio) == -1)
3035 	{
3036 		msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: tcgetattr(%d, &tio): %m", unit, fd232);
3037 		parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
3038 		return 0;
3039 	}
3040 	else
3041 	{
3042 #ifndef _PC_VDISABLE
3043 		memset((char *)tio.c_cc, 0, sizeof(tio.c_cc));
3044 #else
3045 		int disablec;
3046 		errno = 0;		/* pathconf can deliver -1 without changing errno ! */
3047 
3048 		disablec = fpathconf(parse->generic->io.fd, _PC_VDISABLE);
3049 		if (disablec == -1 && errno)
3050 		{
3051 			msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: fpathconf(fd, _PC_VDISABLE): %m", CLK_UNIT(parse->peer));
3052 			memset((char *)tio.c_cc, 0, sizeof(tio.c_cc)); /* best guess */
3053 		}
3054 		else
3055 		    if (disablec != -1)
3056 			memset((char *)tio.c_cc, disablec, sizeof(tio.c_cc));
3057 #endif
3058 
3059 #if defined (VMIN) || defined(VTIME)
3060 		if ((parse_clockinfo[type].cl_lflag & ICANON) == 0)
3061 		{
3062 #ifdef VMIN
3063 			tio.c_cc[VMIN]   = 1;
3064 #endif
3065 #ifdef VTIME
3066 			tio.c_cc[VTIME]  = 0;
3067 #endif
3068 		}
3069 #endif
3070 
3071 		tio.c_cflag = parse_clockinfo[type].cl_cflag;
3072 		tio.c_iflag = parse_clockinfo[type].cl_iflag;
3073 		tio.c_oflag = parse_clockinfo[type].cl_oflag;
3074 		tio.c_lflag = parse_clockinfo[type].cl_lflag;
3075 
3076 
3077 #ifdef HAVE_TERMIOS
3078 		if ((cfsetospeed(&tio, parse_clockinfo[type].cl_speed) == -1) ||
3079 		    (cfsetispeed(&tio, parse_clockinfo[type].cl_speed) == -1))
3080 		{
3081 			msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: tcset{i,o}speed(&tio, speed): %m", unit);
3082 			parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
3083 			return 0;
3084 		}
3085 #else
3086 		tio.c_cflag     |= parse_clockinfo[type].cl_speed;
3087 #endif
3088 
3089 		/*
3090 		 * set up pps device
3091 		 * if the PARSEPPSDEVICE can be opened that will be used
3092 		 * for PPS else PARSEDEVICE will be used
3093 		 */
3094 		parse->ppsfd = open(parseppsdev, O_RDWR | O_NOCTTY
3095 #ifdef O_NONBLOCK
3096 				    | O_NONBLOCK
3097 #endif
3098 				    , 0777);
3099 
3100 		if (parse->ppsfd == -1)
3101 		{
3102 			parse->ppsfd = fd232;
3103 		}
3104 
3105 /*
3106  * Linux PPS - the old way
3107  */
3108 #if defined(HAVE_TIO_SERIAL_STUFF)		/* Linux hack: define PPS interface */
3109 		{
3110 			struct serial_struct	ss;
3111 			if (ioctl(parse->ppsfd, TIOCGSERIAL, &ss) < 0 ||
3112 			    (
3113 #ifdef ASYNC_LOW_LATENCY
3114 			     ss.flags |= ASYNC_LOW_LATENCY,
3115 #endif
3116 #ifndef HAVE_PPSAPI
3117 #ifdef ASYNC_PPS_CD_NEG
3118 			     ss.flags |= ASYNC_PPS_CD_NEG,
3119 #endif
3120 #endif
3121 			     ioctl(parse->ppsfd, TIOCSSERIAL, &ss)) < 0) {
3122 				msyslog(LOG_NOTICE, "refclock_parse: TIOCSSERIAL fd %d, %m", parse->ppsfd);
3123 				msyslog(LOG_NOTICE,
3124 					"refclock_parse: optional PPS processing not available");
3125 			} else {
3126 				parse->flags    |= PARSE_PPSCLOCK;
3127 #ifdef ASYNC_PPS_CD_NEG
3128 				NLOG(NLOG_CLOCKINFO)
3129 				  msyslog(LOG_INFO,
3130 					  "refclock_parse: PPS detection on");
3131 #endif
3132 			}
3133 		}
3134 #endif
3135 
3136 /*
3137  * SUN the Solaris way
3138  */
3139 #ifdef HAVE_TIOCSPPS			/* SUN PPS support */
3140 		if (CLK_PPS(parse->peer))
3141 		    {
3142 			int i = 1;
3143 
3144 			if (ioctl(parse->ppsfd, TIOCSPPS, (caddr_t)&i) == 0)
3145 			    {
3146 				parse->flags |= PARSE_PPSCLOCK;
3147 			    }
3148 		    }
3149 #endif
3150 
3151 /*
3152  * PPS via PPSAPI
3153  */
3154 #if defined(HAVE_PPSAPI)
3155 		parse->hardppsstate = PARSE_HARDPPS_DISABLE;
3156 		if (CLK_PPS(parse->peer))
3157 		{
3158 		  if (!refclock_ppsapi(parse->ppsfd, &parse->atom))
3159 		    {
3160 		      msyslog(LOG_NOTICE, "PARSE receiver #%d: parse_start: could not set up PPS: %m", CLK_UNIT(parse->peer));
3161 		    }
3162 		  else
3163 		    {
3164 		      parse_ppsapi(parse);
3165 		    }
3166 		}
3167 #endif
3168 
3169 		if (TTY_SETATTR(fd232, &tio) == -1)
3170 		{
3171 			msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: tcsetattr(%d, &tio): %m", unit, fd232);
3172 			parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
3173 			return 0;
3174 		}
3175 	}
3176 
3177 	/*
3178 	 * pick correct input machine
3179 	 */
3180 	parse->generic->io.srcclock = (caddr_t)parse;
3181 	parse->generic->io.datalen = 0;
3182 
3183 	parse->binding = init_iobinding(parse);
3184 
3185 	if (parse->binding == (bind_t *)0)
3186 		{
3187 			msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: io sub system initialisation failed.", CLK_UNIT(parse->peer));
3188 			parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
3189 			return 0;			/* well, ok - special initialisation broke */
3190 		}
3191 
3192 	parse->generic->io.clock_recv = parse->binding->bd_receive; /* pick correct receive routine */
3193 	parse->generic->io.io_input   = parse->binding->bd_io_input; /* pick correct input routine */
3194 
3195 	/*
3196 	 * as we always(?) get 8 bit chars we want to be
3197 	 * sure, that the upper bits are zero for less
3198 	 * than 8 bit I/O - so we pass that information on.
3199 	 * note that there can be only one bit count format
3200 	 * per file descriptor
3201 	 */
3202 
3203 	switch (tio.c_cflag & CSIZE)
3204 	{
3205 	    case CS5:
3206 		tmp_ctl.parsesetcs.parse_cs = PARSE_IO_CS5;
3207 		break;
3208 
3209 	    case CS6:
3210 		tmp_ctl.parsesetcs.parse_cs = PARSE_IO_CS6;
3211 		break;
3212 
3213 	    case CS7:
3214 		tmp_ctl.parsesetcs.parse_cs = PARSE_IO_CS7;
3215 		break;
3216 
3217 	    case CS8:
3218 		tmp_ctl.parsesetcs.parse_cs = PARSE_IO_CS8;
3219 		break;
3220 	}
3221 
3222 	if (!PARSE_SETCS(parse, &tmp_ctl))
3223 	{
3224 		msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: parse_setcs() FAILED.", unit);
3225 		parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
3226 		return 0;			/* well, ok - special initialisation broke */
3227 	}
3228 
3229 	strlcpy(tmp_ctl.parseformat.parse_buffer, parse->parse_type->cl_format, sizeof(tmp_ctl.parseformat.parse_buffer));
3230 	tmp_ctl.parseformat.parse_count = strlen(tmp_ctl.parseformat.parse_buffer);
3231 
3232 	if (!PARSE_SETFMT(parse, &tmp_ctl))
3233 	{
3234 		msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: parse_setfmt() FAILED.", unit);
3235 		parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
3236 		return 0;			/* well, ok - special initialisation broke */
3237 	}
3238 
3239 	/*
3240 	 * get rid of all IO accumulated so far
3241 	 */
3242 #ifdef HAVE_TERMIOS
3243 	(void) tcflush(parse->generic->io.fd, TCIOFLUSH);
3244 #else
3245 #if defined(TCFLSH) && defined(TCIOFLUSH)
3246 	{
3247 		int flshcmd = TCIOFLUSH;
3248 
3249 		(void) ioctl(parse->generic->io.fd, TCFLSH, (caddr_t)&flshcmd);
3250 	}
3251 #endif
3252 #endif
3253 
3254 	/*
3255 	 * try to do any special initializations
3256 	 */
3257 	if (parse->parse_type->cl_init)
3258 		{
3259 			if (parse->parse_type->cl_init(parse))
3260 				{
3261 					parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
3262 					return 0;		/* well, ok - special initialisation broke */
3263 				}
3264 		}
3265 
3266 	/*
3267 	 * Insert in async io device list.
3268 	 */
3269 	if (!io_addclock(&parse->generic->io))
3270         {
3271 		msyslog(LOG_ERR,
3272 			"PARSE receiver #%d: parse_start: addclock %s fails (ABORT - clock type requires async io)", CLK_UNIT(parse->peer), parsedev);
3273 		parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
3274 		return 0;
3275 	}
3276 
3277 	/*
3278 	 * print out configuration
3279 	 */
3280 	NLOG(NLOG_CLOCKINFO)
3281 		{
3282 			/* conditional if clause for conditional syslog */
3283 			msyslog(LOG_INFO, "PARSE receiver #%d: reference clock \"%s\" (I/O device %s, PPS device %s) added",
3284 				CLK_UNIT(parse->peer),
3285 				parse->parse_type->cl_description, parsedev,
3286 				(parse->ppsfd != parse->generic->io.fd) ? parseppsdev : parsedev);
3287 
3288 			msyslog(LOG_INFO, "PARSE receiver #%d: Stratum %d, trust time %s, precision %d",
3289 				CLK_UNIT(parse->peer),
3290 				parse->peer->stratum,
3291 				l_mktime(parse->maxunsync), parse->peer->precision);
3292 
3293 			msyslog(LOG_INFO, "PARSE receiver #%d: rootdelay %.6f s, phase adjustment %.6f s, PPS phase adjustment %.6f s, %s IO handling",
3294 				CLK_UNIT(parse->peer),
3295 				parse->parse_type->cl_rootdelay,
3296 				parse->generic->fudgetime1,
3297 				parse->ppsphaseadjust,
3298                                 parse->binding->bd_description);
3299 
3300 			msyslog(LOG_INFO, "PARSE receiver #%d: Format recognition: %s", CLK_UNIT(parse->peer),
3301 				parse->parse_type->cl_format);
3302                         msyslog(LOG_INFO, "PARSE receiver #%d: %sPPS support%s", CLK_UNIT(parse->peer),
3303 				CLK_PPS(parse->peer) ? "" : "NO ",
3304 				CLK_PPS(parse->peer) ?
3305 #ifdef PPS_METHOD
3306 				" (implementation " PPS_METHOD ")"
3307 #else
3308 				""
3309 #endif
3310 				: ""
3311 				);
3312 		}
3313 
3314 	return 1;
3315 }
3316 
3317 /*--------------------------------------------------
3318  * parse_ctl - process changes on flags/time values
3319  */
3320 static void
3321 parse_ctl(
3322 	    struct parseunit *parse,
3323 	    struct refclockstat *in
3324 	    )
3325 {
3326         if (in)
3327 	{
3328 		if (in->haveflags & (CLK_HAVEFLAG1|CLK_HAVEFLAG2|CLK_HAVEFLAG3|CLK_HAVEFLAG4))
3329 		{
3330 		  parse->flags = (parse->flags & ~(CLK_FLAG1|CLK_FLAG2|CLK_FLAG3|CLK_FLAG4)) |
3331 		    (in->flags & (CLK_FLAG1|CLK_FLAG2|CLK_FLAG3|CLK_FLAG4));
3332 #if defined(HAVE_PPSAPI)
3333 		  if (CLK_PPS(parse->peer))
3334 		    {
3335 		      parse_ppsapi(parse);
3336 		    }
3337 #endif
3338 		}
3339 
3340 		if (in->haveflags & CLK_HAVETIME1)
3341                 {
3342 		  parse->generic->fudgetime1 = in->fudgetime1;
3343 		  msyslog(LOG_INFO, "PARSE receiver #%d: new phase adjustment %.6f s",
3344 			  CLK_UNIT(parse->peer),
3345 			  parse->generic->fudgetime1);
3346 		}
3347 
3348 		if (in->haveflags & CLK_HAVETIME2)
3349                 {
3350 		  parse->generic->fudgetime2 = in->fudgetime2;
3351 		  if (parse->flags & PARSE_TRUSTTIME)
3352 		    {
3353 		      parse->maxunsync = (u_long)ABS(in->fudgetime2);
3354 		      msyslog(LOG_INFO, "PARSE receiver #%d: new trust time %s",
3355 			      CLK_UNIT(parse->peer),
3356 			      l_mktime(parse->maxunsync));
3357 		    }
3358 		  else
3359 		    {
3360 		      parse->ppsphaseadjust = in->fudgetime2;
3361 		      msyslog(LOG_INFO, "PARSE receiver #%d: new PPS phase adjustment %.6f s",
3362 			  CLK_UNIT(parse->peer),
3363 			      parse->ppsphaseadjust);
3364 #if defined(HAVE_PPSAPI)
3365 		      if (CLK_PPS(parse->peer))
3366 		      {
3367 			      parse_ppsapi(parse);
3368 		      }
3369 #endif
3370 		    }
3371 		}
3372 	}
3373 }
3374 
3375 /*--------------------------------------------------
3376  * parse_poll - called by the transmit procedure
3377  */
3378 static void
3379 parse_poll(
3380 	int unit,
3381 	struct peer *peer
3382 	)
3383 {
3384 	struct parseunit *parse = (struct parseunit *)peer->procptr->unitptr;
3385 
3386 	if (peer != parse->peer)
3387 	{
3388 		msyslog(LOG_ERR,
3389 			"PARSE receiver #%d: poll: INTERNAL: peer incorrect",
3390 			unit);
3391 		return;
3392 	}
3393 
3394 	/*
3395 	 * Update clock stat counters
3396 	 */
3397 	parse->generic->polls++;
3398 
3399 	if (parse->pollneeddata &&
3400 	    ((int)(current_time - parse->pollneeddata) > (1<<(max(min(parse->peer->hpoll, parse->peer->ppoll), parse->peer->minpoll)))))
3401 	{
3402 		/*
3403 		 * start worrying when exceeding a poll inteval
3404 		 * bad news - didn't get a response last time
3405 		 */
3406 		parse->lastmissed = current_time;
3407 		parse_event(parse, CEVNT_TIMEOUT);
3408 
3409 		ERR(ERR_NODATA)
3410 			msyslog(LOG_WARNING, "PARSE receiver #%d: no data from device within poll interval (check receiver / wiring)", CLK_UNIT(parse->peer));
3411 	}
3412 
3413 	/*
3414 	 * we just mark that we want the next sample for the clock filter
3415 	 */
3416 	parse->pollneeddata = current_time;
3417 
3418 	if (parse->parse_type->cl_poll)
3419 	{
3420 		parse->parse_type->cl_poll(parse);
3421 	}
3422 
3423 	cparse_statistics(parse);
3424 
3425 	return;
3426 }
3427 
3428 #define LEN_STATES 300		/* length of state string */
3429 
3430 /*--------------------------------------------------
3431  * parse_control - set fudge factors, return statistics
3432  */
3433 static void
3434 parse_control(
3435 	int unit,
3436 	struct refclockstat *in,
3437 	struct refclockstat *out,
3438 	struct peer *peer
3439 	)
3440 {
3441         struct parseunit *parse = (struct parseunit *)peer->procptr->unitptr;
3442 	parsectl_t tmpctl;
3443 
3444 	static char outstatus[400];	/* status output buffer */
3445 
3446 	if (out)
3447 	{
3448 		out->lencode       = 0;
3449 		out->p_lastcode    = 0;
3450 		out->kv_list       = (struct ctl_var *)0;
3451 	}
3452 
3453 	if (!parse || !parse->peer)
3454 	{
3455 		msyslog(LOG_ERR, "PARSE receiver #%d: parse_control: unit invalid (UNIT INACTIVE)",
3456 			unit);
3457 		return;
3458 	}
3459 
3460 	unit = CLK_UNIT(parse->peer);
3461 
3462 	/*
3463 	 * handle changes
3464 	 */
3465 	parse_ctl(parse, in);
3466 
3467 	/*
3468 	 * supply data
3469 	 */
3470 	if (out)
3471 	{
3472 		u_long sum = 0;
3473 		char *tt, *start;
3474 		int i;
3475 
3476 		outstatus[0] = '\0';
3477 
3478 		out->type       = REFCLK_PARSE;
3479 
3480 		/*
3481 		 * keep fudgetime2 in sync with TRUSTTIME/MAXUNSYNC flag1
3482 		 */
3483 		parse->generic->fudgetime2 = (parse->flags & PARSE_TRUSTTIME) ? (double)parse->maxunsync : parse->ppsphaseadjust;
3484 
3485 		/*
3486 		 * figure out skew between PPS and RS232 - just for informational
3487 		 * purposes
3488 		 */
3489 		if (PARSE_SYNC(parse->timedata.parse_state))
3490 		{
3491 			if (PARSE_PPS(parse->timedata.parse_state) && PARSE_TIMECODE(parse->timedata.parse_state))
3492 			{
3493 				l_fp off;
3494 
3495 				/*
3496 				 * we have a PPS and RS232 signal - calculate the skew
3497 				 * WARNING: assumes on TIMECODE == PULSE (timecode after pulse)
3498 				 */
3499 				off = parse->timedata.parse_stime.fp;
3500 				L_SUB(&off, &parse->timedata.parse_ptime.fp); /* true offset */
3501 				tt = add_var(&out->kv_list, 80, RO);
3502 				snprintf(tt, 80, "refclock_ppsskew=%s", lfptoms(&off, 6));
3503 			}
3504 		}
3505 
3506 		if (PARSE_PPS(parse->timedata.parse_state))
3507 		{
3508 			tt = add_var(&out->kv_list, 80, RO|DEF);
3509 			snprintf(tt, 80, "refclock_ppstime=\"%s\"", gmprettydate(&parse->timedata.parse_ptime.fp));
3510 		}
3511 
3512 		start = tt = add_var(&out->kv_list, 128, RO|DEF);
3513 		tt = ap(start, 128, tt, "refclock_time=\"");
3514 
3515 		if (parse->timedata.parse_time.fp.l_ui == 0)
3516 		{
3517 			tt = ap(start, 128, tt, "<UNDEFINED>\"");
3518 		}
3519 		else
3520 		{
3521 			tt = ap(start, 128, tt, "%s\"",
3522 			    gmprettydate(&parse->timedata.parse_time.fp));
3523 		}
3524 
3525 		if (!PARSE_GETTIMECODE(parse, &tmpctl))
3526 		{
3527 			ERR(ERR_INTERNAL)
3528 				msyslog(LOG_ERR, "PARSE receiver #%d: parse_control: parse_timecode() FAILED", unit);
3529 		}
3530 		else
3531 		{
3532 			start = tt = add_var(&out->kv_list, 512, RO|DEF);
3533 			tt = ap(start, 512, tt, "refclock_status=\"");
3534 
3535 			/*
3536 			 * copy PPS flags from last read transaction (informational only)
3537 			 */
3538 			tmpctl.parsegettc.parse_state |= parse->timedata.parse_state &
3539 				(PARSEB_PPS|PARSEB_S_PPS);
3540 
3541 			(void)parsestate(tmpctl.parsegettc.parse_state, tt, BUFFER_SIZES(start, tt, 512));
3542 
3543 			tt += strlen(tt);
3544 
3545 			tt = ap(start, 512, tt, "\"");
3546 
3547 			if (tmpctl.parsegettc.parse_count)
3548 			    mkascii(outstatus+strlen(outstatus), (int)(sizeof(outstatus)- strlen(outstatus) - 1),
3549 				    tmpctl.parsegettc.parse_buffer, (unsigned)(tmpctl.parsegettc.parse_count));
3550 
3551 		}
3552 
3553 		tmpctl.parseformat.parse_format = tmpctl.parsegettc.parse_format;
3554 
3555 		if (!PARSE_GETFMT(parse, &tmpctl))
3556 		{
3557 			ERR(ERR_INTERNAL)
3558 				msyslog(LOG_ERR, "PARSE receiver #%d: parse_control: parse_getfmt() FAILED", unit);
3559 		}
3560 		else
3561 		{
3562 			int count = tmpctl.parseformat.parse_count - 1;
3563 
3564 			start = tt = add_var(&out->kv_list, 80, RO|DEF);
3565 			tt = ap(start, 80, tt, "refclock_format=\"");
3566 
3567 			if (count > 0) {
3568 				tt = ap(start, 80, tt, "%*.*s",
3569 			        	count,
3570 			        	count,
3571 			        	tmpctl.parseformat.parse_buffer);
3572 			}
3573 
3574 			tt = ap(start, 80, tt, "\"");
3575 		}
3576 
3577 		/*
3578 		 * gather state statistics
3579 		 */
3580 
3581 		start = tt = add_var(&out->kv_list, LEN_STATES, RO|DEF);
3582 		tt = ap(start, LEN_STATES, tt, "refclock_states=\"");
3583 
3584 		for (i = 0; i <= CEVNT_MAX; i++)
3585 		{
3586 			u_long s_time;
3587 			u_long d = current_time - parse->generic->timestarted;
3588 			u_long percent;
3589 
3590 			percent = s_time = PARSE_STATETIME(parse, i);
3591 
3592 			while (((u_long)(~0) / 10000) < percent)
3593 			{
3594 				percent /= 10;
3595 				d       /= 10;
3596 			}
3597 
3598 			if (d)
3599 			    percent = (percent * 10000) / d;
3600 			else
3601 			    percent = 10000;
3602 
3603 			if (s_time)
3604 			{
3605 				char item[80];
3606 				int count;
3607 
3608 				snprintf(item, 80, "%s%s%s: %s (%d.%02d%%)",
3609 					sum ? "; " : "",
3610 					(parse->generic->currentstatus == i) ? "*" : "",
3611 					clockstatus((unsigned int)i),
3612 					l_mktime(s_time),
3613 					(int)(percent / 100), (int)(percent % 100));
3614 				if ((count = strlen(item)) < (LEN_STATES - 40 - (tt - start)))
3615 					{
3616 						tt = ap(start, LEN_STATES, tt,
3617 						    "%s", item);
3618 					}
3619 				sum += s_time;
3620 			}
3621 		}
3622 
3623 		tt = ap(start, LEN_STATES, tt,
3624 		    "; running time: %s\"", l_mktime(sum));
3625 
3626 		tt = add_var(&out->kv_list, 32, RO);
3627 		snprintf(tt, 32,  "refclock_id=\"%s\"", parse->parse_type->cl_id);
3628 
3629 		tt = add_var(&out->kv_list, 80, RO);
3630 		snprintf(tt, 80,  "refclock_iomode=\"%s\"", parse->binding->bd_description);
3631 
3632 		tt = add_var(&out->kv_list, 128, RO);
3633 		snprintf(tt, 128, "refclock_driver_version=\"%s\"", rcsid);
3634 
3635 		{
3636 			struct ctl_var *k;
3637 
3638 			k = parse->kv;
3639 			while (k && !(k->flags & EOV))
3640 			{
3641 				set_var(&out->kv_list, k->text, strlen(k->text)+1, k->flags);
3642 				k++;
3643 			}
3644 		}
3645 
3646 		out->lencode       = strlen(outstatus);
3647 		out->p_lastcode    = outstatus;
3648 	}
3649 }
3650 
3651 /**===========================================================================
3652  ** processing routines
3653  **/
3654 
3655 /*--------------------------------------------------
3656  * event handling - note that nominal events will also be posted
3657  * keep track of state dwelling times
3658  */
3659 static void
3660 parse_event(
3661 	struct parseunit *parse,
3662 	int event
3663 	)
3664 {
3665 	if (parse->generic->currentstatus != (u_char) event)
3666 	{
3667 		parse->statetime[parse->generic->currentstatus] += current_time - parse->lastchange;
3668 		parse->lastchange              = current_time;
3669 
3670 		if (parse->parse_type->cl_event)
3671 		    parse->parse_type->cl_event(parse, event);
3672 
3673 		if (event == CEVNT_NOMINAL)
3674 		{
3675 			NLOG(NLOG_CLOCKSTATUS)
3676 				msyslog(LOG_INFO, "PARSE receiver #%d: SYNCHRONIZED",
3677 					CLK_UNIT(parse->peer));
3678 		}
3679 
3680 		refclock_report(parse->peer, event);
3681 	}
3682 }
3683 
3684 /*--------------------------------------------------
3685  * process a PARSE time sample
3686  */
3687 static void
3688 parse_process(
3689 	struct parseunit *parse,
3690 	parsetime_t      *parsetime
3691 	)
3692 {
3693 	l_fp off, rectime, reftime;
3694 	double fudge;
3695 
3696 	/*
3697 	 * check for changes in conversion status
3698 	 * (only one for each new status !)
3699 	 */
3700 	if (((parsetime->parse_status & CVT_MASK) != CVT_OK) &&
3701 	    ((parsetime->parse_status & CVT_MASK) != CVT_NONE) &&
3702 	    (parse->timedata.parse_status != parsetime->parse_status))
3703 	{
3704 		char buffer[400];
3705 
3706 		NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */
3707 			msyslog(LOG_WARNING, "PARSE receiver #%d: conversion status \"%s\"",
3708 				CLK_UNIT(parse->peer), parsestatus(parsetime->parse_status, buffer, sizeof(buffer)));
3709 
3710 		if ((parsetime->parse_status & CVT_MASK) == CVT_FAIL)
3711 		{
3712 			/*
3713 			 * tell more about the story - list time code
3714 			 * there is a slight change for a race condition and
3715 			 * the time code might be overwritten by the next packet
3716 			 */
3717 			parsectl_t tmpctl;
3718 
3719 			if (!PARSE_GETTIMECODE(parse, &tmpctl))
3720 			{
3721 				ERR(ERR_INTERNAL)
3722 					msyslog(LOG_ERR, "PARSE receiver #%d: parse_process: parse_timecode() FAILED", CLK_UNIT(parse->peer));
3723 			}
3724 			else
3725 			{
3726 				ERR(ERR_BADDATA)
3727 					msyslog(LOG_WARNING, "PARSE receiver #%d: FAILED TIMECODE: \"%s\" (check receiver configuration / wiring)",
3728 						CLK_UNIT(parse->peer), mkascii(buffer, sizeof buffer, tmpctl.parsegettc.parse_buffer, (unsigned)(tmpctl.parsegettc.parse_count - 1)));
3729 			}
3730 		}
3731 	}
3732 
3733 	/*
3734 	 * examine status and post appropriate events
3735 	 */
3736 	if ((parsetime->parse_status & CVT_MASK) != CVT_OK)
3737 	{
3738 		/*
3739 		 * got bad data - tell the rest of the system
3740 		 */
3741 		switch (parsetime->parse_status & CVT_MASK)
3742 		{
3743 		case CVT_NONE:
3744 			if ((parsetime->parse_status & CVT_ADDITIONAL) &&
3745 			    parse->parse_type->cl_message)
3746 				parse->parse_type->cl_message(parse, parsetime);
3747 			/*
3748 			 * save PPS information that comes piggyback
3749 			 */
3750 			if (PARSE_PPS(parsetime->parse_state))
3751 			  {
3752 			    parse->timedata.parse_state |= PARSEB_PPS|PARSEB_S_PPS;
3753 			    parse->timedata.parse_ptime  = parsetime->parse_ptime;
3754 			  }
3755 			break; 		/* well, still waiting - timeout is handled at higher levels */
3756 
3757 		case CVT_FAIL:
3758 			if (parsetime->parse_status & CVT_BADFMT)
3759 			{
3760 				parse_event(parse, CEVNT_BADREPLY);
3761 			}
3762 			else
3763 				if (parsetime->parse_status & CVT_BADDATE)
3764 				{
3765 					parse_event(parse, CEVNT_BADDATE);
3766 				}
3767 				else
3768 					if (parsetime->parse_status & CVT_BADTIME)
3769 					{
3770 						parse_event(parse, CEVNT_BADTIME);
3771 					}
3772 					else
3773 					{
3774 						parse_event(parse, CEVNT_BADREPLY); /* for the lack of something better */
3775 					}
3776 		}
3777 		return;			/* skip the rest - useless */
3778 	}
3779 
3780 	/*
3781 	 * check for format changes
3782 	 * (in case somebody has swapped clocks 8-)
3783 	 */
3784 	if (parse->lastformat != parsetime->parse_format)
3785 	{
3786 		parsectl_t tmpctl;
3787 
3788 		tmpctl.parseformat.parse_format = parsetime->parse_format;
3789 
3790 		if (!PARSE_GETFMT(parse, &tmpctl))
3791 		{
3792 			ERR(ERR_INTERNAL)
3793 				msyslog(LOG_ERR, "PARSE receiver #%d: parse_getfmt() FAILED", CLK_UNIT(parse->peer));
3794 		}
3795 		else
3796 		{
3797 			NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */
3798 				msyslog(LOG_INFO, "PARSE receiver #%d: packet format \"%s\"",
3799 					CLK_UNIT(parse->peer), tmpctl.parseformat.parse_buffer);
3800 		}
3801 		parse->lastformat = parsetime->parse_format;
3802 	}
3803 
3804 	/*
3805 	 * now, any changes ?
3806 	 */
3807 	if ((parse->timedata.parse_state ^ parsetime->parse_state) &
3808 	    ~(unsigned)(PARSEB_PPS|PARSEB_S_PPS))
3809 	{
3810 		char tmp1[200];
3811 		char tmp2[200];
3812 		/*
3813 		 * something happend - except for PPS events
3814 		 */
3815 
3816 		(void) parsestate(parsetime->parse_state, tmp1, sizeof(tmp1));
3817 		(void) parsestate(parse->timedata.parse_state, tmp2, sizeof(tmp2));
3818 
3819 		NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */
3820 			msyslog(LOG_INFO,"PARSE receiver #%d: STATE CHANGE: %s -> %s",
3821 				CLK_UNIT(parse->peer), tmp2, tmp1);
3822 	}
3823 
3824 	/*
3825 	 * carry on PPS information if still usable
3826 	 */
3827 	if (PARSE_PPS(parse->timedata.parse_state) && !PARSE_PPS(parsetime->parse_state))
3828         {
3829 	        parsetime->parse_state |= PARSEB_PPS|PARSEB_S_PPS;
3830 		parsetime->parse_ptime  = parse->timedata.parse_ptime;
3831 	}
3832 
3833 	/*
3834 	 * remember for future
3835 	 */
3836 	parse->timedata = *parsetime;
3837 
3838 	/*
3839 	 * check to see, whether the clock did a complete powerup or lost PZF signal
3840 	 * and post correct events for current condition
3841 	 */
3842 	if (PARSE_POWERUP(parsetime->parse_state))
3843 	{
3844 		/*
3845 		 * this is bad, as we have completely lost synchronisation
3846 		 * well this is a problem with the receiver here
3847 		 * for PARSE Meinberg DCF77 receivers the lost synchronisation
3848 		 * is true as it is the powerup state and the time is taken
3849 		 * from a crude real time clock chip
3850 		 * for the PZF/GPS series this is only partly true, as
3851 		 * PARSE_POWERUP only means that the pseudo random
3852 		 * phase shift sequence cannot be found. this is only
3853 		 * bad, if we have never seen the clock in the SYNC
3854 		 * state, where the PHASE and EPOCH are correct.
3855 		 * for reporting events the above business does not
3856 		 * really matter, but we can use the time code
3857 		 * even in the POWERUP state after having seen
3858 		 * the clock in the synchronized state (PZF class
3859 		 * receivers) unless we have had a telegram disruption
3860 		 * after having seen the clock in the SYNC state. we
3861 		 * thus require having seen the clock in SYNC state
3862 		 * *after* having missed telegrams (noresponse) from
3863 		 * the clock. one problem remains: we might use erroneously
3864 		 * POWERUP data if the disruption is shorter than 1 polling
3865 		 * interval. fortunately powerdowns last usually longer than 64
3866 		 * seconds and the receiver is at least 2 minutes in the
3867 		 * POWERUP or NOSYNC state before switching to SYNC
3868 		 * for GPS receivers this can mean antenna problems and other causes.
3869 		 * the additional grace period can be enables by a clock
3870 		 * mode having the PARSE_F_POWERUPTRUST flag in cl_flag set.
3871 		 */
3872 		parse_event(parse, CEVNT_FAULT);
3873 		NLOG(NLOG_CLOCKSTATUS)
3874 			ERR(ERR_BADSTATUS)
3875 			msyslog(LOG_ERR,"PARSE receiver #%d: NOT SYNCHRONIZED/RECEIVER PROBLEMS",
3876 				CLK_UNIT(parse->peer));
3877 	}
3878 	else
3879 	{
3880 		/*
3881 		 * we have two states left
3882 		 *
3883 		 * SYNC:
3884 		 *  this state means that the EPOCH (timecode) and PHASE
3885 		 *  information has be read correctly (at least two
3886 		 *  successive PARSE timecodes were received correctly)
3887 		 *  this is the best possible state - full trust
3888 		 *
3889 		 * NOSYNC:
3890 		 *  The clock should be on phase with respect to the second
3891 		 *  signal, but the timecode has not been received correctly within
3892 		 *  at least the last two minutes. this is a sort of half baked state
3893 		 *  for PARSE Meinberg DCF77 clocks this is bad news (clock running
3894 		 *  without timecode confirmation)
3895 		 *  PZF 535 has also no time confirmation, but the phase should be
3896 		 *  very precise as the PZF signal can be decoded
3897 		 */
3898 
3899 		if (PARSE_SYNC(parsetime->parse_state))
3900 		{
3901 			/*
3902 			 * currently completely synchronized - best possible state
3903 			 */
3904 			parse->lastsync = current_time;
3905 			clear_err(parse, ERR_BADSTATUS);
3906 		}
3907 		else
3908 		{
3909 			/*
3910 			 * we have had some problems receiving the time code
3911 			 */
3912 			parse_event(parse, CEVNT_PROP);
3913 			NLOG(NLOG_CLOCKSTATUS)
3914 				ERR(ERR_BADSTATUS)
3915 				msyslog(LOG_ERR,"PARSE receiver #%d: TIMECODE NOT CONFIRMED",
3916 					CLK_UNIT(parse->peer));
3917 		}
3918 	}
3919 
3920 	fudge = parse->generic->fudgetime1; /* standard RS232 Fudgefactor */
3921 
3922 	if (PARSE_TIMECODE(parsetime->parse_state))
3923 	{
3924 		rectime = parsetime->parse_stime.fp;
3925 		off = reftime = parsetime->parse_time.fp;
3926 
3927 		L_SUB(&off, &rectime); /* prepare for PPS adjustments logic */
3928 
3929 #ifdef DEBUG
3930 		if (debug > 3)
3931 			printf("PARSE receiver #%d: Reftime %s, Recvtime %s - initial offset %s\n",
3932 			       CLK_UNIT(parse->peer),
3933 			       prettydate(&reftime),
3934 			       prettydate(&rectime),
3935 			       lfptoa(&off,6));
3936 #endif
3937 	}
3938 
3939 	if (PARSE_PPS(parsetime->parse_state) && CLK_PPS(parse->peer))
3940 	{
3941 		l_fp offset;
3942 		double ppsphaseadjust = parse->ppsphaseadjust;
3943 
3944 #ifdef HAVE_PPSAPI
3945 		/*
3946 		 * set fudge = 0.0 if already included in PPS time stamps
3947 		 */
3948 		if (parse->atom.pps_params.mode & (PPS_OFFSETCLEAR|PPS_OFFSETASSERT))
3949 		        {
3950 			        ppsphaseadjust = 0.0;
3951 			}
3952 #endif
3953 
3954 		/*
3955 		 * we have a PPS signal - much better than the RS232 stuff (we hope)
3956 		 */
3957 		offset = parsetime->parse_ptime.fp;
3958 
3959 #ifdef DEBUG
3960 		if (debug > 3)
3961 			printf("PARSE receiver #%d: PPStime %s\n",
3962 				CLK_UNIT(parse->peer),
3963 				prettydate(&offset));
3964 #endif
3965 		if (PARSE_TIMECODE(parsetime->parse_state))
3966 		{
3967 			if (M_ISGEQ(off.l_i, off.l_f, -1, 0x80000000) &&
3968 			    M_ISGEQ(0, 0x7fffffff, off.l_i, off.l_f))
3969 			{
3970 				fudge = ppsphaseadjust; /* pick PPS fudge factor */
3971 
3972 				/*
3973 				 * RS232 offsets within [-0.5..0.5[ - take PPS offsets
3974 				 */
3975 
3976 				if (parse->parse_type->cl_flags & PARSE_F_PPSONSECOND)
3977 				{
3978 					reftime = off = offset;
3979 					if (reftime.l_uf & (unsigned)0x80000000)
3980 						reftime.l_ui++;
3981 					reftime.l_uf = 0;
3982 
3983 
3984 					/*
3985 					 * implied on second offset
3986 					 */
3987 					off.l_uf = ~off.l_uf; /* map [0.5..1[ -> [-0.5..0[ */
3988 					off.l_ui = (off.l_f < 0) ? ~0 : 0; /* sign extend */
3989 				}
3990 				else
3991 				{
3992 					/*
3993 					 * time code describes pulse
3994 					 */
3995 					reftime = off = parsetime->parse_time.fp;
3996 
3997 					L_SUB(&off, &offset); /* true offset */
3998 				}
3999 			}
4000 			/*
4001 			 * take RS232 offset when PPS when out of bounds
4002 			 */
4003 		}
4004 		else
4005 		{
4006 			fudge = ppsphaseadjust; /* pick PPS fudge factor */
4007 			/*
4008 			 * Well, no time code to guide us - assume on second pulse
4009 			 * and pray, that we are within [-0.5..0.5[
4010 			 */
4011 			off = offset;
4012 			reftime = offset;
4013 			if (reftime.l_uf & (unsigned)0x80000000)
4014 				reftime.l_ui++;
4015 			reftime.l_uf = 0;
4016 			/*
4017 			 * implied on second offset
4018 			 */
4019 			off.l_uf = ~off.l_uf; /* map [0.5..1[ -> [-0.5..0[ */
4020 			off.l_ui = (off.l_f < 0) ? ~0 : 0; /* sign extend */
4021 		}
4022 	}
4023 	else
4024 	{
4025 		if (!PARSE_TIMECODE(parsetime->parse_state))
4026 		{
4027 			/*
4028 			 * Well, no PPS, no TIMECODE, no more work ...
4029 			 */
4030 			if ((parsetime->parse_status & CVT_ADDITIONAL) &&
4031 			    parse->parse_type->cl_message)
4032 				parse->parse_type->cl_message(parse, parsetime);
4033 			return;
4034 		}
4035 	}
4036 
4037 #ifdef DEBUG
4038 	if (debug > 3)
4039 		printf("PARSE receiver #%d: Reftime %s, Recvtime %s - final offset %s\n",
4040 			CLK_UNIT(parse->peer),
4041 			prettydate(&reftime),
4042 			prettydate(&rectime),
4043 			lfptoa(&off,6));
4044 #endif
4045 
4046 
4047 	rectime = reftime;
4048 	L_SUB(&rectime, &off);	/* just to keep the ntp interface happy */
4049 
4050 #ifdef DEBUG
4051 	if (debug > 3)
4052 		printf("PARSE receiver #%d: calculated Reftime %s, Recvtime %s\n",
4053 			CLK_UNIT(parse->peer),
4054 			prettydate(&reftime),
4055 			prettydate(&rectime));
4056 #endif
4057 
4058 	if ((parsetime->parse_status & CVT_ADDITIONAL) &&
4059 	    parse->parse_type->cl_message)
4060 		parse->parse_type->cl_message(parse, parsetime);
4061 
4062 	if (PARSE_SYNC(parsetime->parse_state))
4063 	{
4064 		/*
4065 		 * log OK status
4066 		 */
4067 		parse_event(parse, CEVNT_NOMINAL);
4068 	}
4069 
4070 	clear_err(parse, ERR_BADIO);
4071 	clear_err(parse, ERR_BADDATA);
4072 	clear_err(parse, ERR_NODATA);
4073 	clear_err(parse, ERR_INTERNAL);
4074 
4075 	/*
4076 	 * and now stick it into the clock machine
4077 	 * samples are only valid iff lastsync is not too old and
4078 	 * we have seen the clock in sync at least once
4079 	 * after the last time we didn't see an expected data telegram
4080 	 * at startup being not in sync is also bad just like
4081 	 * POWERUP state unless PARSE_F_POWERUPTRUST is set
4082 	 * see the clock states section above for more reasoning
4083 	 */
4084 	if (((current_time - parse->lastsync) > parse->maxunsync)           ||
4085 	    (parse->lastsync < parse->lastmissed)                           ||
4086 	    ((parse->lastsync == 0) && !PARSE_SYNC(parsetime->parse_state)) ||
4087 	    (((parse->parse_type->cl_flags & PARSE_F_POWERUPTRUST) == 0) &&
4088 	     PARSE_POWERUP(parsetime->parse_state)))
4089 	{
4090 		parse->generic->leap = LEAP_NOTINSYNC;
4091 		parse->lastsync = 0;	/* wait for full sync again */
4092 	}
4093 	else
4094 	{
4095 		if (PARSE_LEAPADD(parsetime->parse_state))
4096 		{
4097 			/*
4098 			 * we pick this state also for time code that pass leap warnings
4099 			 * without direction information (as earth is currently slowing
4100 			 * down).
4101 			 */
4102 			parse->generic->leap = (parse->flags & PARSE_LEAP_DELETE) ? LEAP_DELSECOND : LEAP_ADDSECOND;
4103 		}
4104 		else
4105 		    if (PARSE_LEAPDEL(parsetime->parse_state))
4106 		    {
4107 			    parse->generic->leap = LEAP_DELSECOND;
4108 		    }
4109 		    else
4110 		    {
4111 			    parse->generic->leap = LEAP_NOWARNING;
4112 		    }
4113 	}
4114 
4115 	if (parse->generic->leap != LEAP_NOTINSYNC)
4116 	{
4117 	        /*
4118 		 * only good/trusted samples are interesting
4119 		 */
4120 #ifdef DEBUG
4121 	        if (debug > 2)
4122 		        {
4123 			        printf("PARSE receiver #%d: refclock_process_offset(reftime=%s, rectime=%s, Fudge=%f)\n",
4124 				       CLK_UNIT(parse->peer),
4125 				       prettydate(&reftime),
4126 				       prettydate(&rectime),
4127 				       fudge);
4128 			}
4129 #endif
4130 		parse->generic->lastref = reftime;
4131 
4132 		refclock_process_offset(parse->generic, reftime, rectime, fudge);
4133 
4134 #ifdef HAVE_PPSAPI
4135 		/*
4136 		 * pass PPS information on to PPS clock
4137 		 */
4138 		if (PARSE_PPS(parsetime->parse_state) && CLK_PPS(parse->peer))
4139 		        {
4140 			  /* refclock_pps includes fudgetime1 - we keep the RS232 offset in there :-( */
4141 			        double savedtime1 = parse->generic->fudgetime1;
4142 
4143 				parse->generic->fudgetime1 = fudge;
4144 
4145 				if (refclock_pps(parse->peer, &parse->atom,
4146 						 parse->flags & (CLK_FLAG1|CLK_FLAG2|CLK_FLAG3|CLK_FLAG4))) {
4147 					parse->peer->flags |= FLAG_PPS;
4148 				} else {
4149 					parse->peer->flags &= ~FLAG_PPS;
4150 				}
4151 
4152 				parse->generic->fudgetime1 = savedtime1;
4153 
4154 				parse_hardpps(parse, PARSE_HARDPPS_ENABLE);
4155 			}
4156 #endif
4157 	} else {
4158 	        parse_hardpps(parse, PARSE_HARDPPS_DISABLE);
4159 		parse->peer->flags &= ~FLAG_PPS;
4160 	}
4161 
4162 	/*
4163 	 * ready, unless the machine wants a sample or
4164 	 * we are in fast startup mode (peer->dist > MAXDISTANCE)
4165 	 */
4166 	if (!parse->pollneeddata && parse->peer->disp <= MAXDISTANCE)
4167 	    return;
4168 
4169 	parse->pollneeddata = 0;
4170 
4171 	parse->timedata.parse_state &= ~(unsigned)(PARSEB_PPS|PARSEB_S_PPS);
4172 
4173 	refclock_receive(parse->peer);
4174 }
4175 
4176 /**===========================================================================
4177  ** special code for special clocks
4178  **/
4179 
4180 static void
4181 mk_utcinfo(
4182 	   char *t,
4183 	   int wnt,
4184 	   int wnlsf,
4185 	   int dn,
4186 	   int dtls,
4187 	   int dtlsf,
4188 	   int size
4189 	   )
4190 {
4191   l_fp leapdate;
4192   char *start = t;
4193 
4194   snprintf(t, size, "current correction %d sec", dtls);
4195   t += strlen(t);
4196 
4197   if (wnlsf < 990)
4198     wnlsf += 1024;
4199 
4200   if (wnt < 990)
4201     wnt += 1024;
4202 
4203   gpstolfp((unsigned short)wnlsf, (unsigned short)dn, 0, &leapdate);
4204 
4205   if ((dtlsf != dtls) &&
4206       ((wnlsf - wnt) < 52))
4207     {
4208 	    snprintf(t, BUFFER_SIZES(start, t, size), ", next correction %d sec on %s, new GPS-UTC offset %d",
4209 	      dtlsf - dtls, gmprettydate(&leapdate), dtlsf);
4210     }
4211   else
4212     {
4213 	    snprintf(t, BUFFER_SIZES(start, t, size), ", last correction on %s",
4214 	      gmprettydate(&leapdate));
4215     }
4216 }
4217 
4218 #ifdef CLOCK_MEINBERG
4219 /**===========================================================================
4220  ** Meinberg GPS166/GPS167 support
4221  **/
4222 
4223 /*------------------------------------------------------------
4224  * gps16x_message - process GPS16x messages
4225  */
4226 static void
4227 gps16x_message(
4228 	       struct parseunit *parse,
4229 	       parsetime_t      *parsetime
4230 	       )
4231 {
4232 	if (parse->timedata.parse_msglen && parsetime->parse_msg[0] == SOH)
4233 	{
4234 		GPS_MSG_HDR header;
4235 		unsigned char *bufp = (unsigned char *)parsetime->parse_msg + 1;
4236 
4237 #ifdef DEBUG
4238 		if (debug > 2)
4239 		{
4240 			char msgbuffer[600];
4241 
4242 			mkreadable(msgbuffer, sizeof(msgbuffer), (char *)parsetime->parse_msg, parsetime->parse_msglen, 1);
4243 			printf("PARSE receiver #%d: received message (%d bytes) >%s<\n",
4244 				CLK_UNIT(parse->peer),
4245 				parsetime->parse_msglen,
4246 				msgbuffer);
4247 		}
4248 #endif
4249 		get_mbg_header(&bufp, &header);
4250 		if (header.gps_hdr_csum == mbg_csum(parsetime->parse_msg + 1, 6) &&
4251 		    (header.gps_len == 0 ||
4252 		     (header.gps_len < sizeof(parsetime->parse_msg) &&
4253 		      header.gps_data_csum == mbg_csum(bufp, header.gps_len))))
4254 		{
4255 			/*
4256 			 * clean message
4257 			 */
4258 			switch (header.gps_cmd)
4259 			{
4260 			case GPS_SW_REV:
4261 				{
4262 					char buffer[64];
4263 					SW_REV gps_sw_rev;
4264 
4265 					get_mbg_sw_rev(&bufp, &gps_sw_rev);
4266 					snprintf(buffer, sizeof(buffer), "meinberg_gps_version=\"%x.%02x%s%s\"",
4267 						(gps_sw_rev.code >> 8) & 0xFF,
4268 						gps_sw_rev.code & 0xFF,
4269 						gps_sw_rev.name[0] ? " " : "",
4270 						gps_sw_rev.name);
4271 					set_var(&parse->kv, buffer, strlen(buffer)+1, RO|DEF);
4272 				}
4273 			break;
4274 
4275 			case GPS_STAT:
4276 				{
4277 					static struct state
4278 					{
4279 						unsigned short flag; /* status flag */
4280 						unsigned const char *string; /* bit name */
4281 					} states[] =
4282 					  {
4283 						  { TM_ANT_DISCONN, (const unsigned char *)"ANTENNA FAULTY" },
4284 						  { TM_SYN_FLAG,    (const unsigned char *)"NO SYNC SIGNAL" },
4285 						  { TM_NO_SYNC,     (const unsigned char *)"NO SYNC POWERUP" },
4286 						  { TM_NO_POS,      (const unsigned char *)"NO POSITION" },
4287 						  { 0, (const unsigned char *)"" }
4288 					  };
4289 					unsigned short status;
4290 					struct state *s = states;
4291 					char buffer[512];
4292 					char *p, *b;
4293 
4294 					status = get_lsb_short(&bufp);
4295 					p = b = buffer;
4296 					p = ap(buffer, sizeof(buffer), p,
4297 					    "meinberg_gps_status=\"[0x%04x] ",
4298 					    status);
4299 
4300 					if (status)
4301 					{
4302 						b = p;
4303 						while (s->flag)
4304 						{
4305 							if (status & s->flag)
4306 							{
4307 								if (p != b)
4308 								{
4309 									p = ap(buffer, sizeof(buffer), p, ", ");
4310 								}
4311 
4312 								p = ap(buffer, sizeof(buffer), p, "%s", (const char *)s->string);
4313 							}
4314 							s++;
4315 						}
4316 						p = ap(buffer, sizeof(buffer), p, "\"");
4317 					}
4318 					else
4319 					{
4320 						p = ap(buffer, sizeof(buffer), p, "<OK>\"");
4321 					}
4322 
4323 					set_var(&parse->kv, buffer, strlen(buffer)+1, RO|DEF);
4324 				}
4325 			break;
4326 
4327 			case GPS_POS_XYZ:
4328 				{
4329 					XYZ xyz;
4330 					char buffer[256];
4331 
4332 					get_mbg_xyz(&bufp, xyz);
4333 					snprintf(buffer, sizeof(buffer), "gps_position(XYZ)=\"%s m, %s m, %s m\"",
4334 						mfptoa(xyz[XP].l_ui, xyz[XP].l_uf, 1),
4335 						mfptoa(xyz[YP].l_ui, xyz[YP].l_uf, 1),
4336 						mfptoa(xyz[ZP].l_ui, xyz[ZP].l_uf, 1));
4337 
4338 					set_var(&parse->kv, buffer, sizeof(buffer), RO|DEF);
4339 				}
4340 			break;
4341 
4342 			case GPS_POS_LLA:
4343 				{
4344 					LLA lla;
4345 					char buffer[256];
4346 
4347 					get_mbg_lla(&bufp, lla);
4348 
4349 					snprintf(buffer, sizeof(buffer), "gps_position(LLA)=\"%s deg, %s deg, %s m\"",
4350 						mfptoa(lla[LAT].l_ui, lla[LAT].l_uf, 4),
4351 						mfptoa(lla[LON].l_ui, lla[LON].l_uf, 4),
4352 						mfptoa(lla[ALT].l_ui, lla[ALT].l_uf, 1));
4353 
4354 					set_var(&parse->kv, buffer, sizeof(buffer), RO|DEF);
4355 				}
4356 			break;
4357 
4358 			case GPS_TZDL:
4359 				break;
4360 
4361 			case GPS_PORT_PARM:
4362 				break;
4363 
4364 			case GPS_SYNTH:
4365 				break;
4366 
4367 			case GPS_ANT_INFO:
4368 				{
4369 					ANT_INFO antinfo;
4370 					char buffer[512];
4371 					char *p, *q;
4372 
4373 					get_mbg_antinfo(&bufp, &antinfo);
4374 					p = buffer;
4375 					p = ap(buffer, sizeof(buffer), p, "meinberg_antenna_status=\"");
4376 					switch (antinfo.status)
4377 					{
4378 					case ANT_INVALID:
4379 						p = ap(buffer, sizeof(buffer),
4380 						    p, "<OK>");
4381 						break;
4382 
4383 					case ANT_DISCONN:
4384 						q = ap(buffer, sizeof(buffer),
4385 						    p, "DISCONNECTED since ");
4386 						NLOG(NLOG_CLOCKSTATUS)
4387 							ERR(ERR_BADSTATUS)
4388 							msyslog(LOG_ERR,"PARSE receiver #%d: ANTENNA FAILURE: %s",
4389 								CLK_UNIT(parse->peer), p);
4390 
4391 						p = q;
4392 						mbg_tm_str(&p, &antinfo.tm_disconn, BUFFER_SIZE(buffer, p));
4393 						*p = '\0';
4394 						break;
4395 
4396 					case ANT_RECONN:
4397 						p = ap(buffer, sizeof(buffer),
4398 						    p, "RECONNECTED on ");
4399 						mbg_tm_str(&p, &antinfo.tm_reconn, BUFFER_SIZE(buffer, p));
4400 						p = ap(buffer, sizeof(buffer),
4401 							p, ", reconnect clockoffset %c%ld.%07ld s, disconnect time ",
4402 							(antinfo.delta_t < 0) ? '-' : '+',
4403 							ABS(antinfo.delta_t) / 10000,
4404 							ABS(antinfo.delta_t) % 10000);
4405 						mbg_tm_str(&p, &antinfo.tm_disconn, BUFFER_SIZE(buffer, p));
4406 						*p = '\0';
4407 						break;
4408 
4409 					default:
4410 						p = ap(buffer, sizeof(buffer),
4411 						    p, "bad status 0x%04x",
4412 						    antinfo.status);
4413 						break;
4414 					}
4415 
4416 					p = ap(buffer, sizeof(buffer), p, "\"");
4417 
4418 					set_var(&parse->kv, buffer, sizeof(buffer), RO|DEF);
4419 				}
4420 			break;
4421 
4422 			case GPS_UCAP:
4423 				break;
4424 
4425 			case GPS_CFGH:
4426 				{
4427 					CFGH cfgh;
4428 					char buffer[512];
4429 					char *p;
4430 
4431 					get_mbg_cfgh(&bufp, &cfgh);
4432 					if (cfgh.valid)
4433 					{
4434 						int i;
4435 
4436 						p = buffer;
4437 						p = ap(buffer, sizeof(buffer),
4438 						    p, "gps_tot_51=\"");
4439 						mbg_tgps_str(&p, &cfgh.tot_51, BUFFER_SIZE(buffer, p));
4440 						p = ap(buffer, sizeof(buffer),
4441 						    p, "\"");
4442 						set_var(&parse->kv, buffer, sizeof(buffer), RO);
4443 
4444 						p = buffer;
4445 						p = ap(buffer, sizeof(buffer),
4446 						    p, "gps_tot_63=\"");
4447 						mbg_tgps_str(&p, &cfgh.tot_63, BUFFER_SIZE(buffer, p));
4448 						p = ap(buffer, sizeof(buffer),
4449 						    p, "\"");
4450 						set_var(&parse->kv, buffer, sizeof(buffer), RO);
4451 
4452 						p = buffer;
4453 						p = ap(buffer, sizeof(buffer),
4454 						    p, "gps_t0a=\"");
4455 						mbg_tgps_str(&p, &cfgh.t0a, BUFFER_SIZE(buffer, p));
4456 						p = ap(buffer, sizeof(buffer),
4457 						    p, "\"");
4458 						set_var(&parse->kv, buffer, sizeof(buffer), RO);
4459 
4460 						for (i = MIN_SVNO; i < MAX_SVNO; i++)
4461 						{
4462 							p = buffer;
4463 							p = ap(buffer, sizeof(buffer), p, "gps_cfg[%d]=\"[0x%x] ", i, cfgh.cfg[i]);
4464 							switch (cfgh.cfg[i] & 0x7)
4465 							{
4466 							case 0:
4467 								p = ap(buffer, sizeof(buffer), p, "BLOCK I");
4468 								break;
4469 							case 1:
4470 								p = ap(buffer, sizeof(buffer), p, "BLOCK II");
4471 								break;
4472 							default:
4473 								p = ap(buffer, sizeof(buffer), p, "bad CFG");
4474 								break;
4475 							}
4476 							p = ap(buffer, sizeof(buffer), p, "\"");
4477 							set_var(&parse->kv, buffer, sizeof(buffer), RO);
4478 
4479 							p = buffer;
4480 							p = ap(buffer, sizeof(buffer), p, "gps_health[%d]=\"[0x%x] ", i, cfgh.health[i]);
4481 							switch ((cfgh.health[i] >> 5) & 0x7 )
4482 							{
4483 							case 0:
4484 								p = ap(buffer, sizeof(buffer), p, "OK;");
4485 								break;
4486 							case 1:
4487 								p = ap(buffer, sizeof(buffer), p, "PARITY;");
4488 								break;
4489 							case 2:
4490 								p = ap(buffer, sizeof(buffer), p, "TLM/HOW;");
4491 								break;
4492 							case 3:
4493 								p = ap(buffer, sizeof(buffer), p, "Z-COUNT;");
4494 								break;
4495 							case 4:
4496 								p = ap(buffer, sizeof(buffer), p, "SUBFRAME 1,2,3;");
4497 								break;
4498 							case 5:
4499 								p = ap(buffer, sizeof(buffer), p, "SUBFRAME 4,5;");
4500 								break;
4501 							case 6:
4502 								p = ap(buffer, sizeof(buffer), p, "UPLOAD BAD;");
4503 								break;
4504 							case 7:
4505 								p = ap(buffer, sizeof(buffer), p, "DATA BAD;");
4506 								break;
4507 							}
4508 
4509 							switch (cfgh.health[i] & 0x1F)
4510 							{
4511 							case 0:
4512 								p = ap(buffer, sizeof(buffer), p, "SIGNAL OK");
4513 								break;
4514 							case 0x1C:
4515 								p = ap(buffer, sizeof(buffer), p, "SV TEMP OUT");
4516 								break;
4517 							case 0x1D:
4518 								p = ap(buffer, sizeof(buffer), p, "SV WILL BE TEMP OUT");
4519 								break;
4520 							case 0x1E:
4521 								break;
4522 							case 0x1F:
4523 								p = ap(buffer, sizeof(buffer), p, "MULTIPLE ERRS");
4524 								break;
4525 							default:
4526 								p = ap(buffer, sizeof(buffer), p, "TRANSMISSION PROBLEMS");
4527 								break;
4528 							}
4529 
4530 							p = ap(buffer, sizeof(buffer), p, "\"");
4531 							set_var(&parse->kv, buffer, sizeof(buffer), RO);
4532 						}
4533 					}
4534 				}
4535 			break;
4536 
4537 			case GPS_ALM:
4538 				break;
4539 
4540 			case GPS_EPH:
4541 				break;
4542 
4543 			case GPS_UTC:
4544 				{
4545 					UTC utc;
4546 					char buffer[512];
4547 					char *p;
4548 
4549 					p = buffer;
4550 
4551 					get_mbg_utc(&bufp, &utc);
4552 
4553 					if (utc.valid)
4554 					{
4555 						p = ap(buffer, sizeof(buffer), p, "gps_utc_correction=\"");
4556 						mk_utcinfo(p, utc.t0t.wn, utc.WNlsf, utc.DNt, utc.delta_tls, utc.delta_tlsf, BUFFER_SIZE(buffer, p));
4557 						p += strlen(p);
4558 						p = ap(buffer, sizeof(buffer), p, "\"");
4559 					}
4560 					else
4561 					{
4562 						p = ap(buffer, sizeof(buffer), p, "gps_utc_correction=\"<NO UTC DATA>\"");
4563 					}
4564 					set_var(&parse->kv, buffer, sizeof(buffer), RO|DEF);
4565 				}
4566 			break;
4567 
4568 			case GPS_IONO:
4569 				break;
4570 
4571 			case GPS_ASCII_MSG:
4572 				{
4573 					ASCII_MSG gps_ascii_msg;
4574 					char buffer[128];
4575 
4576 					get_mbg_ascii_msg(&bufp, &gps_ascii_msg);
4577 
4578 					if (gps_ascii_msg.valid)
4579 						{
4580 							char buffer1[128];
4581 							mkreadable(buffer1, sizeof(buffer1), gps_ascii_msg.s, strlen(gps_ascii_msg.s), (int)0);
4582 
4583 							snprintf(buffer, sizeof(buffer), "gps_message=\"%s\"", buffer1);
4584 						}
4585 					else
4586 						snprintf(buffer, sizeof(buffer), "gps_message=<NONE>");
4587 
4588 					set_var(&parse->kv, buffer, sizeof(buffer), RO|DEF);
4589 				}
4590 
4591 			break;
4592 
4593 			default:
4594 				break;
4595 			}
4596 		}
4597 		else
4598 		{
4599 			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)",
4600 				CLK_UNIT(parse->peer),
4601 				header.gps_hdr_csum, mbg_csum(parsetime->parse_msg + 1, 6),
4602 				header.gps_len,
4603 				header.gps_data_csum, mbg_csum(bufp, (unsigned)((header.gps_len < sizeof(parsetime->parse_msg)) ? header.gps_len : 0)));
4604 		}
4605 	}
4606 
4607 	return;
4608 }
4609 
4610 /*------------------------------------------------------------
4611  * gps16x_poll - query the reciver peridically
4612  */
4613 static void
4614 gps16x_poll(
4615 	    struct peer *peer
4616 	    )
4617 {
4618 	struct parseunit *parse = (struct parseunit *)peer->procptr->unitptr;
4619 
4620 	static GPS_MSG_HDR sequence[] =
4621 	{
4622 		{ GPS_SW_REV,          0, 0, 0 },
4623 		{ GPS_STAT,            0, 0, 0 },
4624 		{ GPS_UTC,             0, 0, 0 },
4625 		{ GPS_ASCII_MSG,       0, 0, 0 },
4626 		{ GPS_ANT_INFO,        0, 0, 0 },
4627 		{ GPS_CFGH,            0, 0, 0 },
4628 		{ GPS_POS_XYZ,         0, 0, 0 },
4629 		{ GPS_POS_LLA,         0, 0, 0 },
4630 		{ (unsigned short)~0,  0, 0, 0 }
4631 	};
4632 
4633 	int rtc;
4634 	unsigned char cmd_buffer[64];
4635 	unsigned char *outp = cmd_buffer;
4636 	GPS_MSG_HDR *header;
4637 
4638 	if (((poll_info_t *)parse->parse_type->cl_data)->rate)
4639 	{
4640 		parse->peer->nextaction = current_time + ((poll_info_t *)parse->parse_type->cl_data)->rate;
4641 	}
4642 
4643 	if (sequence[parse->localstate].gps_cmd == (unsigned short)~0)
4644 		parse->localstate = 0;
4645 
4646 	header = sequence + parse->localstate++;
4647 
4648 	*outp++ = SOH;		/* start command */
4649 
4650 	put_mbg_header(&outp, header);
4651 	outp = cmd_buffer + 1;
4652 
4653 	header->gps_hdr_csum = (short)mbg_csum(outp, 6);
4654 	put_mbg_header(&outp, header);
4655 
4656 #ifdef DEBUG
4657 	if (debug > 2)
4658 	{
4659 		char buffer[128];
4660 
4661 		mkreadable(buffer, sizeof(buffer), (char *)cmd_buffer, (unsigned)(outp - cmd_buffer), 1);
4662 		printf("PARSE receiver #%d: transmitted message #%ld (%d bytes) >%s<\n",
4663 		       CLK_UNIT(parse->peer),
4664 		       parse->localstate - 1,
4665 		       (int)(outp - cmd_buffer),
4666 		       buffer);
4667 	}
4668 #endif
4669 
4670 	rtc = write(parse->generic->io.fd, cmd_buffer, (unsigned long)(outp - cmd_buffer));
4671 
4672 	if (rtc < 0)
4673 	{
4674 		ERR(ERR_BADIO)
4675 			msyslog(LOG_ERR, "PARSE receiver #%d: gps16x_poll: failed to send cmd to clock: %m", CLK_UNIT(parse->peer));
4676 	}
4677 	else
4678 	if (rtc != outp - cmd_buffer)
4679 	{
4680 		ERR(ERR_BADIO)
4681 			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));
4682 	}
4683 
4684 	clear_err(parse, ERR_BADIO);
4685 	return;
4686 }
4687 
4688 /*--------------------------------------------------
4689  * init routine - setup timer
4690  */
4691 static int
4692 gps16x_poll_init(
4693 	struct parseunit *parse
4694 	)
4695 {
4696 	if (((poll_info_t *)parse->parse_type->cl_data)->rate)
4697 	{
4698 		parse->peer->action = gps16x_poll;
4699 		gps16x_poll(parse->peer);
4700 	}
4701 
4702 	return 0;
4703 }
4704 
4705 #else
4706 static void
4707 gps16x_message(
4708 	       struct parseunit *parse,
4709 	       parsetime_t      *parsetime
4710 	       )
4711 {}
4712 static int
4713 gps16x_poll_init(
4714 	struct parseunit *parse
4715 	)
4716 {
4717 	return 1;
4718 }
4719 #endif /* CLOCK_MEINBERG */
4720 
4721 /**===========================================================================
4722  ** clock polling support
4723  **/
4724 
4725 /*--------------------------------------------------
4726  * direct poll routine
4727  */
4728 static void
4729 poll_dpoll(
4730 	struct parseunit *parse
4731 	)
4732 {
4733 	int rtc;
4734 	const char *ps = ((poll_info_t *)parse->parse_type->cl_data)->string;
4735 	int   ct = ((poll_info_t *)parse->parse_type->cl_data)->count;
4736 
4737 	rtc = write(parse->generic->io.fd, ps, (unsigned long)ct);
4738 	if (rtc < 0)
4739 	{
4740 		ERR(ERR_BADIO)
4741 			msyslog(LOG_ERR, "PARSE receiver #%d: poll_dpoll: failed to send cmd to clock: %m", CLK_UNIT(parse->peer));
4742 	}
4743 	else
4744 	    if (rtc != ct)
4745 	    {
4746 		    ERR(ERR_BADIO)
4747 			    msyslog(LOG_ERR, "PARSE receiver #%d: poll_dpoll: failed to send cmd incomplete (%d of %d bytes sent)", CLK_UNIT(parse->peer), rtc, ct);
4748 	    }
4749 	clear_err(parse, ERR_BADIO);
4750 }
4751 
4752 /*--------------------------------------------------
4753  * periodic poll routine
4754  */
4755 static void
4756 poll_poll(
4757 	struct peer *peer
4758 	)
4759 {
4760 	struct parseunit *parse = (struct parseunit *)peer->procptr->unitptr;
4761 
4762 	if (parse->parse_type->cl_poll)
4763 		parse->parse_type->cl_poll(parse);
4764 
4765 	if (((poll_info_t *)parse->parse_type->cl_data)->rate)
4766 	{
4767 		parse->peer->nextaction = current_time + ((poll_info_t *)parse->parse_type->cl_data)->rate;
4768 	}
4769 }
4770 
4771 /*--------------------------------------------------
4772  * init routine - setup timer
4773  */
4774 static int
4775 poll_init(
4776 	struct parseunit *parse
4777 	)
4778 {
4779 	if (((poll_info_t *)parse->parse_type->cl_data)->rate)
4780 	{
4781 		parse->peer->action = poll_poll;
4782 		poll_poll(parse->peer);
4783 	}
4784 
4785 	return 0;
4786 }
4787 
4788 /**===========================================================================
4789  ** Trimble support
4790  **/
4791 
4792 /*-------------------------------------------------------------
4793  * trimble TAIP init routine - setup EOL and then do poll_init.
4794  */
4795 static int
4796 trimbletaip_init(
4797 	struct parseunit *parse
4798 	)
4799 {
4800 #ifdef HAVE_TERMIOS
4801 	struct termios tio;
4802 #endif
4803 #ifdef HAVE_SYSV_TTYS
4804 	struct termio tio;
4805 #endif
4806 	/*
4807 	 * configure terminal line for trimble receiver
4808 	 */
4809 	if (TTY_GETATTR(parse->generic->io.fd, &tio) == -1)
4810 	{
4811 		msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_init: tcgetattr(fd, &tio): %m", CLK_UNIT(parse->peer));
4812 		return 0;
4813 	}
4814 	else
4815 	{
4816 		tio.c_cc[VEOL] = TRIMBLETAIP_EOL;
4817 
4818 		if (TTY_SETATTR(parse->generic->io.fd, &tio) == -1)
4819 		{
4820 			msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_init: tcsetattr(fd, &tio): %m", CLK_UNIT(parse->peer));
4821 			return 0;
4822 		}
4823 	}
4824 	return poll_init(parse);
4825 }
4826 
4827 /*--------------------------------------------------
4828  * trimble TAIP event routine - reset receiver upon data format trouble
4829  */
4830 static const char *taipinit[] = {
4831 	">FPV00000000<",
4832 	">SRM;ID_FLAG=F;CS_FLAG=T;EC_FLAG=F;FR_FLAG=T;CR_FLAG=F<",
4833 	">FTM00020001<",
4834 	(char *)0
4835 };
4836 
4837 static void
4838 trimbletaip_event(
4839 	struct parseunit *parse,
4840 	int event
4841 	)
4842 {
4843 	switch (event)
4844 	{
4845 	    case CEVNT_BADREPLY:	/* reset on garbled input */
4846 	    case CEVNT_TIMEOUT:		/* reset on no input */
4847 		    {
4848 			    const char **iv;
4849 
4850 			    iv = taipinit;
4851 			    while (*iv)
4852 			    {
4853 				    int rtc = write(parse->generic->io.fd, *iv, strlen(*iv));
4854 				    if (rtc < 0)
4855 				    {
4856 					    msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_event: failed to send cmd to clock: %m", CLK_UNIT(parse->peer));
4857 					    return;
4858 				    }
4859 				    else
4860 				    {
4861 					    if (rtc != (int)strlen(*iv))
4862 					    {
4863 						    msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_event: failed to send cmd incomplete (%d of %d bytes sent)",
4864 							    CLK_UNIT(parse->peer), rtc, (int)strlen(*iv));
4865 						    return;
4866 					    }
4867 				    }
4868 				    iv++;
4869 			    }
4870 
4871 			    NLOG(NLOG_CLOCKINFO)
4872 				    ERR(ERR_BADIO)
4873 				    msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_event: RECEIVER INITIALIZED",
4874 					    CLK_UNIT(parse->peer));
4875 		    }
4876 		    break;
4877 
4878 	    default:			/* ignore */
4879 		break;
4880 	}
4881 }
4882 
4883 /*
4884  * This driver supports the Trimble SVee Six Plus GPS receiver module.
4885  * It should support other Trimble receivers which use the Trimble Standard
4886  * Interface Protocol (see below).
4887  *
4888  * The module has a serial I/O port for command/data and a 1 pulse-per-second
4889  * output, about 1 microsecond wide. The leading edge of the pulse is
4890  * coincident with the change of the GPS second. This is the same as
4891  * the change of the UTC second +/- ~1 microsecond. Some other clocks
4892  * specifically use a feature in the data message as a timing reference, but
4893  * the SVee Six Plus does not do this. In fact there is considerable jitter
4894  * on the timing of the messages, so this driver only supports the use
4895  * of the PPS pulse for accurate timing. Where it is determined that
4896  * the offset is way off, when first starting up ntpd for example,
4897  * the timing of the data stream is used until the offset becomes low enough
4898  * (|offset| < CLOCK_MAX), at which point the pps offset is used.
4899  *
4900  * It can use either option for receiving PPS information - the 'ppsclock'
4901  * stream pushed onto the serial data interface to timestamp the Carrier
4902  * Detect interrupts, where the 1PPS connects to the CD line. This only
4903  * works on SunOS 4.1.x currently. To select this, define PPSPPS in
4904  * Config.local. The other option is to use a pulse-stretcher/level-converter
4905  * to convert the PPS pulse into a RS232 start pulse & feed this into another
4906  * tty port. To use this option, define PPSCLK in Config.local. The pps input,
4907  * by whichever method, is handled in ntp_loopfilter.c
4908  *
4909  * The receiver uses a serial message protocol called Trimble Standard
4910  * Interface Protocol (it can support others but this driver only supports
4911  * TSIP). Messages in this protocol have the following form:
4912  *
4913  * <DLE><id> ... <data> ... <DLE><ETX>
4914  *
4915  * Any bytes within the <data> portion of value 10 hex (<DLE>) are doubled
4916  * on transmission and compressed back to one on reception. Otherwise
4917  * the values of data bytes can be anything. The serial interface is RS-422
4918  * asynchronous using 9600 baud, 8 data bits with odd party (**note** 9 bits
4919  * in total!), and 1 stop bit. The protocol supports byte, integer, single,
4920  * and double datatypes. Integers are two bytes, sent most significant first.
4921  * Singles are IEEE754 single precision floating point numbers (4 byte) sent
4922  * sign & exponent first. Doubles are IEEE754 double precision floating point
4923  * numbers (8 byte) sent sign & exponent first.
4924  * The receiver supports a large set of messages, only a small subset of
4925  * which are used here. From driver to receiver the following are used:
4926  *
4927  *  ID    Description
4928  *
4929  *  21    Request current time
4930  *  22    Mode Select
4931  *  2C    Set/Request operating parameters
4932  *  2F    Request UTC info
4933  *  35    Set/Request I/O options
4934 
4935  * From receiver to driver the following are recognised:
4936  *
4937  *  ID    Description
4938  *
4939  *  41    GPS Time
4940  *  44    Satellite selection, PDOP, mode
4941  *  46    Receiver health
4942  *  4B    Machine code/status
4943  *  4C    Report operating parameters (debug only)
4944  *  4F    UTC correction data (used to get leap second warnings)
4945  *  55    I/O options (debug only)
4946  *
4947  * All others are accepted but ignored.
4948  *
4949  */
4950 
4951 #define PI		3.1415926535898	/* lots of sig figs */
4952 #define D2R		PI/180.0
4953 
4954 /*-------------------------------------------------------------------
4955  * sendcmd, sendbyte, sendetx, sendflt, sendint implement the command
4956  * interface to the receiver.
4957  *
4958  * CAVEAT: the sendflt, sendint routines are byte order dependend and
4959  * float implementation dependend - these must be converted to portable
4960  * versions !
4961  *
4962  * CURRENT LIMITATION: float implementation. This runs only on systems
4963  * with IEEE754 floats as native floats
4964  */
4965 
4966 typedef struct trimble
4967 {
4968 	u_long last_msg;	/* last message received */
4969 	u_long last_reset;	/* last time a reset was issued */
4970 	u_char qtracking;	/* query tracking status */
4971 	u_long ctrack;		/* current tracking set */
4972 	u_long ltrack;		/* last tracking set */
4973 } trimble_t;
4974 
4975 union uval {
4976 	u_char  bd[8];
4977 	int     iv;
4978 	float   fv;
4979 	double  dv;
4980 };
4981 
4982 struct txbuf
4983 {
4984 	short idx;			/* index to first unused byte */
4985 	u_char *txt;			/* pointer to actual data buffer */
4986 };
4987 
4988 void	sendcmd		(struct txbuf *buf, int c);
4989 void	sendbyte	(struct txbuf *buf, int b);
4990 void	sendetx		(struct txbuf *buf, struct parseunit *parse);
4991 void	sendint		(struct txbuf *buf, int a);
4992 void	sendflt		(struct txbuf *buf, double a);
4993 
4994 void
4995 sendcmd(
4996 	struct txbuf *buf,
4997 	int c
4998 	)
4999 {
5000 	buf->txt[0] = DLE;
5001 	buf->txt[1] = (u_char)c;
5002 	buf->idx = 2;
5003 }
5004 
5005 void	sendcmd		(struct txbuf *buf, int c);
5006 void	sendbyte	(struct txbuf *buf, int b);
5007 void	sendetx		(struct txbuf *buf, struct parseunit *parse);
5008 void	sendint		(struct txbuf *buf, int a);
5009 void	sendflt		(struct txbuf *buf, double a);
5010 
5011 void
5012 sendbyte(
5013 	struct txbuf *buf,
5014 	int b
5015 	)
5016 {
5017 	if (b == DLE)
5018 	    buf->txt[buf->idx++] = DLE;
5019 	buf->txt[buf->idx++] = (u_char)b;
5020 }
5021 
5022 void
5023 sendetx(
5024 	struct txbuf *buf,
5025 	struct parseunit *parse
5026 	)
5027 {
5028 	buf->txt[buf->idx++] = DLE;
5029 	buf->txt[buf->idx++] = ETX;
5030 
5031 	if (write(parse->generic->io.fd, buf->txt, (unsigned long)buf->idx) != buf->idx)
5032 	{
5033 		ERR(ERR_BADIO)
5034 			msyslog(LOG_ERR, "PARSE receiver #%d: sendetx: failed to send cmd to clock: %m", CLK_UNIT(parse->peer));
5035 	}
5036 	else
5037 	{
5038 #ifdef DEBUG
5039 	  if (debug > 2)
5040 	  {
5041 		  char buffer[256];
5042 
5043 		  mkreadable(buffer, sizeof(buffer), (char *)buf->txt, (unsigned)buf->idx, 1);
5044 		  printf("PARSE receiver #%d: transmitted message (%d bytes) >%s<\n",
5045 			 CLK_UNIT(parse->peer),
5046 			 buf->idx, buffer);
5047 	  }
5048 #endif
5049 		clear_err(parse, ERR_BADIO);
5050 	}
5051 }
5052 
5053 void
5054 sendint(
5055 	struct txbuf *buf,
5056 	int a
5057 	)
5058 {
5059 	/* send 16bit int, msbyte first */
5060 	sendbyte(buf, (u_char)((a>>8) & 0xff));
5061 	sendbyte(buf, (u_char)(a & 0xff));
5062 }
5063 
5064 void
5065 sendflt(
5066 	struct txbuf *buf,
5067 	double a
5068 	)
5069 {
5070 	int i;
5071 	union uval uval;
5072 
5073 	uval.fv = a;
5074 #ifdef WORDS_BIGENDIAN
5075 	for (i=0; i<=3; i++)
5076 #else
5077 	    for (i=3; i>=0; i--)
5078 #endif
5079 		sendbyte(buf, uval.bd[i]);
5080 }
5081 
5082 #define TRIM_POS_OPT	0x13	/* output position with high precision */
5083 #define TRIM_TIME_OPT	0x03	/* use UTC time stamps, on second */
5084 
5085 /*--------------------------------------------------
5086  * trimble TSIP setup routine
5087  */
5088 static int
5089 trimbletsip_setup(
5090 		  struct parseunit *parse,
5091 		  const char *reason
5092 		  )
5093 {
5094 	u_char buffer[256];
5095 	struct txbuf buf;
5096 	trimble_t *t = parse->localdata;
5097 
5098 	if (t && t->last_reset &&
5099 	    ((t->last_reset + TRIMBLE_RESET_HOLDOFF) > current_time)) {
5100 		return 1;	/* not yet */
5101 	}
5102 
5103 	if (t)
5104 		t->last_reset = current_time;
5105 
5106 	buf.txt = buffer;
5107 
5108 	sendcmd(&buf, CMD_CVERSION);	/* request software versions */
5109 	sendetx(&buf, parse);
5110 
5111 	sendcmd(&buf, CMD_COPERPARAM);	/* set operating parameters */
5112 	sendbyte(&buf, 4);	/* static */
5113 	sendflt(&buf, 5.0*D2R);	/* elevation angle mask = 10 deg XXX */
5114 	sendflt(&buf, 4.0);	/* s/n ratio mask = 6 XXX */
5115 	sendflt(&buf, 12.0);	/* PDOP mask = 12 */
5116 	sendflt(&buf, 8.0);	/* PDOP switch level = 8 */
5117 	sendetx(&buf, parse);
5118 
5119 	sendcmd(&buf, CMD_CMODESEL);	/* fix mode select */
5120 	sendbyte(&buf, 1);	/* time transfer mode */
5121 	sendetx(&buf, parse);
5122 
5123 	sendcmd(&buf, CMD_CMESSAGE);	/* request system message */
5124 	sendetx(&buf, parse);
5125 
5126 	sendcmd(&buf, CMD_CSUPER);	/* superpacket fix */
5127 	sendbyte(&buf, 0x2);	/* binary mode */
5128 	sendetx(&buf, parse);
5129 
5130 	sendcmd(&buf, CMD_CIOOPTIONS);	/* set I/O options */
5131 	sendbyte(&buf, TRIM_POS_OPT);	/* position output */
5132 	sendbyte(&buf, 0x00);	/* no velocity output */
5133 	sendbyte(&buf, TRIM_TIME_OPT);	/* UTC, compute on seconds */
5134 	sendbyte(&buf, 0x00);	/* no raw measurements */
5135 	sendetx(&buf, parse);
5136 
5137 	sendcmd(&buf, CMD_CUTCPARAM);	/* request UTC correction data */
5138 	sendetx(&buf, parse);
5139 
5140 	NLOG(NLOG_CLOCKINFO)
5141 		ERR(ERR_BADIO)
5142 		msyslog(LOG_ERR, "PARSE receiver #%d: trimbletsip_setup: RECEIVER RE-INITIALIZED (%s)", CLK_UNIT(parse->peer), reason);
5143 
5144 	return 0;
5145 }
5146 
5147 /*--------------------------------------------------
5148  * TRIMBLE TSIP check routine
5149  */
5150 static void
5151 trimble_check(
5152 	      struct peer *peer
5153 	      )
5154 {
5155 	struct parseunit *parse = (struct parseunit *)peer->procptr->unitptr;
5156 	trimble_t *t = parse->localdata;
5157 	u_char buffer[256];
5158 	struct txbuf buf;
5159 	buf.txt = buffer;
5160 
5161 	if (t)
5162 	{
5163 		if (current_time > t->last_msg + TRIMBLETSIP_IDLE_TIME)
5164 			(void)trimbletsip_setup(parse, "message timeout");
5165 	}
5166 
5167 	poll_poll(parse->peer);	/* emit query string and re-arm timer */
5168 
5169 	if (t && t->qtracking)
5170 	{
5171 		u_long oldsats = t->ltrack & ~t->ctrack;
5172 
5173 		t->qtracking = 0;
5174 		t->ltrack = t->ctrack;
5175 
5176 		if (oldsats)
5177 		{
5178 			int i;
5179 
5180 			for (i = 0; oldsats; i++) {
5181 				if (oldsats & (1 << i))
5182 					{
5183 						sendcmd(&buf, CMD_CSTATTRACK);
5184 						sendbyte(&buf, i+1);	/* old sat */
5185 						sendetx(&buf, parse);
5186 					}
5187 				oldsats &= ~(1 << i);
5188 			}
5189 		}
5190 
5191 		sendcmd(&buf, CMD_CSTATTRACK);
5192 		sendbyte(&buf, 0x00);	/* current tracking set */
5193 		sendetx(&buf, parse);
5194 	}
5195 }
5196 
5197 /*--------------------------------------------------
5198  * TRIMBLE TSIP end routine
5199  */
5200 static void
5201 trimbletsip_end(
5202 	      struct parseunit *parse
5203 	      )
5204 {	trimble_t *t = parse->localdata;
5205 
5206 	if (t)
5207 	{
5208 		free(t);
5209 		parse->localdata = (void *)0;
5210 	}
5211 	parse->peer->nextaction = 0;
5212 	parse->peer->action = (void (*) (struct peer *))0;
5213 }
5214 
5215 /*--------------------------------------------------
5216  * TRIMBLE TSIP init routine
5217  */
5218 static int
5219 trimbletsip_init(
5220 	struct parseunit *parse
5221 	)
5222 {
5223 #if defined(VEOL) || defined(VEOL2)
5224 #ifdef HAVE_TERMIOS
5225 	struct termios tio;		/* NEEDED FOR A LONG TIME ! */
5226 #endif
5227 #ifdef HAVE_SYSV_TTYS
5228 	struct termio tio;		/* NEEDED FOR A LONG TIME ! */
5229 #endif
5230 	/*
5231 	 * allocate local data area
5232 	 */
5233 	if (!parse->localdata)
5234 	{
5235 		trimble_t *t;
5236 
5237 		t = (trimble_t *)(parse->localdata = emalloc(sizeof(trimble_t)));
5238 
5239 		if (t)
5240 		{
5241 			memset((char *)t, 0, sizeof(trimble_t));
5242 			t->last_msg = current_time;
5243 		}
5244 	}
5245 
5246 	parse->peer->action     = trimble_check;
5247 	parse->peer->nextaction = current_time;
5248 
5249 	/*
5250 	 * configure terminal line for ICANON mode with VEOL characters
5251 	 */
5252 	if (TTY_GETATTR(parse->generic->io.fd, &tio) == -1)
5253 	{
5254 		msyslog(LOG_ERR, "PARSE receiver #%d: trimbletsip_init: tcgetattr(%d, &tio): %m", CLK_UNIT(parse->peer), parse->generic->io.fd);
5255 		return 0;
5256 	}
5257 	else
5258 	{
5259 		if ((parse_clockinfo[CLK_TYPE(parse->peer)].cl_lflag & ICANON))
5260 		{
5261 #ifdef VEOL
5262 			tio.c_cc[VEOL]  = ETX;
5263 #endif
5264 #ifdef VEOL2
5265 			tio.c_cc[VEOL2]  = DLE;
5266 #endif
5267 		}
5268 
5269 		if (TTY_SETATTR(parse->generic->io.fd, &tio) == -1)
5270 		{
5271 			msyslog(LOG_ERR, "PARSE receiver #%d: trimbletsip_init: tcsetattr(%d, &tio): %m", CLK_UNIT(parse->peer), parse->generic->io.fd);
5272 			return 0;
5273 		}
5274 	}
5275 #endif
5276 	return trimbletsip_setup(parse, "initial startup");
5277 }
5278 
5279 /*------------------------------------------------------------
5280  * trimbletsip_event - handle Trimble events
5281  * simple evente handler - attempt to re-initialize receiver
5282  */
5283 static void
5284 trimbletsip_event(
5285 	struct parseunit *parse,
5286 	int event
5287 	)
5288 {
5289 	switch (event)
5290 	{
5291 	    case CEVNT_BADREPLY:	/* reset on garbled input */
5292 	    case CEVNT_TIMEOUT:		/* reset on no input */
5293 		    (void)trimbletsip_setup(parse, "event BAD_REPLY/TIMEOUT");
5294 		    break;
5295 
5296 	    default:			/* ignore */
5297 		break;
5298 	}
5299 }
5300 
5301 /*
5302  * getflt, getint convert fields in the incoming data into the
5303  * appropriate type of item
5304  *
5305  * CAVEAT: these routines are currently definitely byte order dependent
5306  * and assume Representation(float) == IEEE754
5307  * These functions MUST be converted to portable versions (especially
5308  * converting the float representation into ntp_fp formats in order
5309  * to avoid floating point operations at all!
5310  */
5311 
5312 static float
5313 getflt(
5314 	u_char *bp
5315 	)
5316 {
5317 	union uval uval;
5318 
5319 #ifdef WORDS_BIGENDIAN
5320 	uval.bd[0] = *bp++;
5321 	uval.bd[1] = *bp++;
5322 	uval.bd[2] = *bp++;
5323 	uval.bd[3] = *bp;
5324 #else  /* ! WORDS_BIGENDIAN */
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.fv;
5331 }
5332 
5333 static double
5334 getdbl(
5335 	u_char *bp
5336 	)
5337 {
5338 	union uval uval;
5339 
5340 #ifdef WORDS_BIGENDIAN
5341 	uval.bd[0] = *bp++;
5342 	uval.bd[1] = *bp++;
5343 	uval.bd[2] = *bp++;
5344 	uval.bd[3] = *bp++;
5345 	uval.bd[4] = *bp++;
5346 	uval.bd[5] = *bp++;
5347 	uval.bd[6] = *bp++;
5348 	uval.bd[7] = *bp;
5349 #else  /* ! WORDS_BIGENDIAN */
5350 	uval.bd[7] = *bp++;
5351 	uval.bd[6] = *bp++;
5352 	uval.bd[5] = *bp++;
5353 	uval.bd[4] = *bp++;
5354 	uval.bd[3] = *bp++;
5355 	uval.bd[2] = *bp++;
5356 	uval.bd[1] = *bp++;
5357 	uval.bd[0] = *bp;
5358 #endif /* ! WORDS_BIGENDIAN */
5359 	return uval.dv;
5360 }
5361 
5362 static int
5363 getshort(
5364 	 unsigned char *p
5365 	 )
5366 {
5367 	return get_msb_short(&p);
5368 }
5369 
5370 /*--------------------------------------------------
5371  * trimbletsip_message - process trimble messages
5372  */
5373 #define RTOD (180.0 / 3.1415926535898)
5374 #define mb(_X_) (buffer[2+(_X_)]) /* shortcut for buffer access */
5375 
5376 static void
5377 trimbletsip_message(
5378 		    struct parseunit *parse,
5379 		    parsetime_t      *parsetime
5380 		    )
5381 {
5382 	unsigned char *buffer = parsetime->parse_msg;
5383 	unsigned int   size   = parsetime->parse_msglen;
5384 
5385 	if ((size < 4) ||
5386 	    (buffer[0]      != DLE) ||
5387 	    (buffer[size-1] != ETX) ||
5388 	    (buffer[size-2] != DLE))
5389 	{
5390 #ifdef DEBUG
5391 		if (debug > 2) {
5392 			size_t i;
5393 
5394 			printf("TRIMBLE BAD packet, size %d:\n	", size);
5395 			for (i = 0; i < size; i++) {
5396 				printf ("%2.2x, ", buffer[i]&0xff);
5397 				if (i%16 == 15) printf("\n\t");
5398 			}
5399 			printf("\n");
5400 		}
5401 #endif
5402 		return;
5403 	}
5404 	else
5405 	{
5406 		int var_flag;
5407 		trimble_t *tr = parse->localdata;
5408 		unsigned int cmd = buffer[1];
5409 		char pbuffer[200];
5410 		char *t = pbuffer;
5411 		cmd_info_t *s;
5412 
5413 #ifdef DEBUG
5414 		if (debug > 3) {
5415 			size_t i;
5416 
5417 			printf("TRIMBLE packet 0x%02x, size %d:\n	", cmd, size);
5418 			for (i = 0; i < size; i++) {
5419 				printf ("%2.2x, ", buffer[i]&0xff);
5420 				if (i%16 == 15) printf("\n\t");
5421 			}
5422 			printf("\n");
5423 		}
5424 #endif
5425 
5426 		if (tr)
5427 			tr->last_msg = current_time;
5428 
5429 		s = trimble_convert(cmd, trimble_rcmds);
5430 
5431 		if (s)
5432 		{
5433 			t = ap(pbuffer, sizeof(pbuffer), t, "%s=\"", s->varname);
5434 		}
5435 		else
5436 		{
5437 			DPRINTF(1, ("TRIMBLE UNKNOWN COMMAND 0x%02x\n", cmd));
5438 			return;
5439 		}
5440 
5441 		var_flag = s->varmode;
5442 
5443 		switch(cmd)
5444 		{
5445 		case CMD_RCURTIME:
5446 			t = ap(pbuffer, sizeof(pbuffer), t, "%f, %d, %f",
5447 				 getflt((unsigned char *)&mb(0)), getshort((unsigned char *)&mb(4)),
5448 				 getflt((unsigned char *)&mb(6)));
5449 			break;
5450 
5451 		case CMD_RBEST4:
5452 			t = ap(pbuffer, sizeof(pbuffer), t, "mode: ");
5453 			switch (mb(0) & 0xF)
5454 			{
5455 			default:
5456 				t = ap(pbuffer, sizeof(pbuffer), t,
5457 				    "0x%x", mb(0) & 0x7);
5458 				break;
5459 
5460 			case 1:
5461 				t = ap(pbuffer, sizeof(pbuffer), t, "0D");
5462 				break;
5463 
5464 			case 3:
5465 				t = ap(pbuffer, sizeof(pbuffer), t, "2D");
5466 				break;
5467 
5468 			case 4:
5469 				t = ap(pbuffer, sizeof(pbuffer), t, "3D");
5470 				break;
5471 			}
5472 			if (mb(0) & 0x10)
5473 				t = ap(pbuffer, sizeof(pbuffer), t, "-MANUAL, ");
5474 			else
5475 				t = ap(pbuffer, sizeof(pbuffer), t, "-AUTO, ");
5476 
5477 			t = ap(pbuffer, sizeof(pbuffer), t, "satellites %02d %02d %02d %02d, PDOP %.2f, HDOP %.2f, VDOP %.2f, TDOP %.2f",
5478 				mb(1), mb(2), mb(3), mb(4),
5479 				getflt((unsigned char *)&mb(5)),
5480 				getflt((unsigned char *)&mb(9)),
5481 				getflt((unsigned char *)&mb(13)),
5482 				getflt((unsigned char *)&mb(17)));
5483 
5484 			break;
5485 
5486 		case CMD_RVERSION:
5487 			t = ap(pbuffer, sizeof(pbuffer), t, "%d.%d (%d/%d/%d)",
5488 				mb(0)&0xff, mb(1)&0xff, 1900+(mb(4)&0xff), mb(2)&0xff, mb(3)&0xff);
5489 			break;
5490 
5491 		case CMD_RRECVHEALTH:
5492 		{
5493 			static const char *msgs[] =
5494 			{
5495 				"Battery backup failed",
5496 				"Signal processor error",
5497 				"Alignment error, channel or chip 1",
5498 				"Alignment error, channel or chip 2",
5499 				"Antenna feed line fault",
5500 				"Excessive ref freq. error",
5501 				"<BIT 6>",
5502 				"<BIT 7>"
5503 			};
5504 
5505 			int i, bits;
5506 
5507 			switch (mb(0) & 0xFF)
5508 			{
5509 			default:
5510 				t = ap(pbuffer, sizeof(pbuffer), t, "illegal value 0x%02x", mb(0) & 0xFF);
5511 				break;
5512 			case 0x00:
5513 				t = ap(pbuffer, sizeof(pbuffer), t, "doing position fixes", BUFFER_SIZE(pbuffer, t));
5514 				break;
5515 			case 0x01:
5516 				t = ap(pbuffer, sizeof(pbuffer), t, "no GPS time yet", BUFFER_SIZE(pbuffer, t));
5517 				break;
5518 			case 0x03:
5519 				t = ap(pbuffer, sizeof(pbuffer), t, "PDOP too high", BUFFER_SIZE(pbuffer, t));
5520 				break;
5521 			case 0x08:
5522 				t = ap(pbuffer, sizeof(pbuffer), t, "no usable satellites", BUFFER_SIZE(pbuffer, t));
5523 				break;
5524 			case 0x09:
5525 				t = ap(pbuffer, sizeof(pbuffer), t, "only ONE usable satellite", BUFFER_SIZE(pbuffer, t));
5526 				break;
5527 			case 0x0A:
5528 				t = ap(pbuffer, sizeof(pbuffer), t, "only TWO usable satellites", BUFFER_SIZE(pbuffer, t));
5529 				break;
5530 			case 0x0B:
5531 				t = ap(pbuffer, sizeof(pbuffer), t, "only THREE usable satellites", BUFFER_SIZE(pbuffer, t));
5532 				break;
5533 			case 0x0C:
5534 				t = ap(pbuffer, sizeof(pbuffer), t, "the chosen satellite is unusable", BUFFER_SIZE(pbuffer, t));
5535 				break;
5536 			}
5537 
5538 			bits = mb(1) & 0xFF;
5539 
5540 			for (i = 0; i < 8; i++)
5541 				if (bits & (0x1<<i))
5542 				{
5543 					t = ap(pbuffer, sizeof(pbuffer), t, ", %s", msgs[i]);
5544 				}
5545 		}
5546 		break;
5547 
5548 		case CMD_RMESSAGE:
5549 			mkreadable(t, (int)BUFFER_SIZE(pbuffer, t), (char *)&mb(0), (unsigned)(size - 2 - (&mb(0) - buffer)), 0);
5550 			break;
5551 
5552 		case CMD_RMACHSTAT:
5553 		{
5554 			static const char *msgs[] =
5555 			{
5556 				"Synthesizer Fault",
5557 				"Battery Powered Time Clock Fault",
5558 				"A-to-D Converter Fault",
5559 				"The almanac stored in the receiver is not complete and current",
5560 				"<BIT 4>",
5561 				"<BIT 5",
5562 				"<BIT 6>",
5563 				"<BIT 7>"
5564 			};
5565 
5566 			int i, bits;
5567 
5568 			t = ap(pbuffer, sizeof(pbuffer), t, "machine id 0x%02x", mb(0) & 0xFF);
5569 			bits = mb(1) & 0xFF;
5570 
5571 			for (i = 0; i < 8; i++)
5572 				if (bits & (0x1<<i))
5573 				{
5574 					t = ap(pbuffer, sizeof(pbuffer), t, ", %s", msgs[i]);
5575 				}
5576 
5577 			t = ap(pbuffer, sizeof(pbuffer), t, ", Superpackets %ssupported", (mb(2) & 0xFF) ? "" :"un" );
5578 		}
5579 		break;
5580 
5581 		case CMD_ROPERPARAM:
5582 			t = ap(pbuffer, sizeof(pbuffer), t, "%2x %.1f %.1f %.1f %.1f",
5583 				mb(0), getflt((unsigned char *)&mb(1)), getflt((unsigned char *)&mb(5)),
5584 				getflt((unsigned char *)&mb(9)), getflt((unsigned char *)&mb(13)));
5585 			break;
5586 
5587 		case CMD_RUTCPARAM:
5588 		{
5589 			float t0t = getflt((unsigned char *)&mb(14));
5590 			short wnt = getshort((unsigned char *)&mb(18));
5591 			short dtls = getshort((unsigned char *)&mb(12));
5592 			short wnlsf = getshort((unsigned char *)&mb(20));
5593 			short dn = getshort((unsigned char *)&mb(22));
5594 			short dtlsf = getshort((unsigned char *)&mb(24));
5595 
5596 			if ((int)t0t != 0)
5597 			  {
5598 				  mk_utcinfo(t, wnt, wnlsf, dn, dtls, dtlsf, BUFFER_SIZE(pbuffer, t));
5599 			  }
5600 			else
5601 			  {
5602 			    t = ap(pbuffer, sizeof(pbuffer), t, "<NO UTC DATA>");
5603 			  }
5604 		}
5605 		break;
5606 
5607 		case CMD_RSAT1BIAS:
5608 			t = ap(pbuffer, sizeof(pbuffer), t, "%.1fm %.2fm/s at %.1fs",
5609 				getflt(&mb(0)), getflt(&mb(4)), getflt(&mb(8)));
5610 			break;
5611 
5612 		case CMD_RIOOPTIONS:
5613 		{
5614 			t = ap(pbuffer, sizeof(pbuffer), t, "%02x %02x %02x %02x",
5615 				mb(0), mb(1), mb(2), mb(3));
5616 			if (mb(0) != TRIM_POS_OPT ||
5617 			    mb(2) != TRIM_TIME_OPT)
5618 			{
5619 				(void)trimbletsip_setup(parse, "bad io options");
5620 			}
5621 		}
5622 		break;
5623 
5624 		case CMD_RSPOSXYZ:
5625 		{
5626 			double x = getflt((unsigned char *)&mb(0));
5627 			double y = getflt((unsigned char *)&mb(4));
5628 			double z = getflt((unsigned char *)&mb(8));
5629 			double f = getflt((unsigned char *)&mb(12));
5630 
5631 			if (f > 0.0)
5632 			  t = ap(pbuffer, sizeof(pbuffer), t, "x= %.1fm, y= %.1fm, z= %.1fm, time_of_fix= %f sec",
5633 				  x, y, z,
5634 				  f);
5635 			else
5636 			  return;
5637 		}
5638 		break;
5639 
5640 		case CMD_RSLLAPOS:
5641 		{
5642 			double lat = getflt((unsigned char *)&mb(0));
5643 			double lng = getflt((unsigned char *)&mb(4));
5644 			double f   = getflt((unsigned char *)&mb(12));
5645 
5646 			if (f > 0.0)
5647 			  t = ap(pbuffer, sizeof(pbuffer), t, "lat %f %c, long %f %c, alt %.2fm",
5648 				  ((lat < 0.0) ? (-lat) : (lat))*RTOD, (lat < 0.0 ? 'S' : 'N'),
5649 				  ((lng < 0.0) ? (-lng) : (lng))*RTOD, (lng < 0.0 ? 'W' : 'E'),
5650 				  getflt((unsigned char *)&mb(8)));
5651 			else
5652 			  return;
5653 		}
5654 		break;
5655 
5656 		case CMD_RDOUBLEXYZ:
5657 		{
5658 			double x = getdbl((unsigned char *)&mb(0));
5659 			double y = getdbl((unsigned char *)&mb(8));
5660 			double z = getdbl((unsigned char *)&mb(16));
5661 			t = ap(pbuffer, sizeof(pbuffer), t, "x= %.1fm, y= %.1fm, z= %.1fm",
5662 				x, y, z);
5663 		}
5664 		break;
5665 
5666 		case CMD_RDOUBLELLA:
5667 		{
5668 			double lat = getdbl((unsigned char *)&mb(0));
5669 			double lng = getdbl((unsigned char *)&mb(8));
5670 			t = ap(pbuffer, sizeof(pbuffer), t, "lat %f %c, lon %f %c, alt %.2fm",
5671 				((lat < 0.0) ? (-lat) : (lat))*RTOD, (lat < 0.0 ? 'S' : 'N'),
5672 				((lng < 0.0) ? (-lng) : (lng))*RTOD, (lng < 0.0 ? 'W' : 'E'),
5673 				getdbl((unsigned char *)&mb(16)));
5674 		}
5675 		break;
5676 
5677 		case CMD_RALLINVIEW:
5678 		{
5679 			int i, sats;
5680 
5681 			t = ap(pbuffer, sizeof(pbuffer), t, "mode: ");
5682 			switch (mb(0) & 0x7)
5683 			{
5684 			default:
5685 				t = ap(pbuffer, sizeof(pbuffer), t, "0x%x", mb(0) & 0x7);
5686 				break;
5687 
5688 			case 3:
5689 				t = ap(pbuffer, sizeof(pbuffer), t, "2D");
5690 				break;
5691 
5692 			case 4:
5693 				t = ap(pbuffer, sizeof(pbuffer), t, "3D");
5694 				break;
5695 			}
5696 			if (mb(0) & 0x8)
5697 				t = ap(pbuffer, sizeof(pbuffer), t, "-MANUAL, ");
5698 			else
5699 				t = ap(pbuffer, sizeof(pbuffer), t, "-AUTO, ");
5700 
5701 			sats = (mb(0)>>4) & 0xF;
5702 
5703 			t = ap(pbuffer, sizeof(pbuffer), t, "PDOP %.2f, HDOP %.2f, VDOP %.2f, TDOP %.2f, %d satellite%s in view: ",
5704 				getflt((unsigned char *)&mb(1)),
5705 				getflt((unsigned char *)&mb(5)),
5706 				getflt((unsigned char *)&mb(9)),
5707 				getflt((unsigned char *)&mb(13)),
5708 				sats, (sats == 1) ? "" : "s");
5709 
5710 			for (i=0; i < sats; i++)
5711 			{
5712 				t = ap(pbuffer, sizeof(pbuffer), t, "%s%02d", i ? ", " : "", mb(17+i));
5713 				if (tr)
5714 					tr->ctrack |= (1 << (mb(17+i)-1));
5715 			}
5716 
5717 			if (tr)
5718                         { /* mark for tracking status query */
5719 				tr->qtracking = 1;
5720 			}
5721 		}
5722 		break;
5723 
5724 		case CMD_RSTATTRACK:
5725 		{
5726 			t = ap(pbuffer, sizeof(pbuffer), t-2, "[%02d]=\"", mb(0)); /* add index to var name */
5727 			if (getflt((unsigned char *)&mb(4)) < 0.0)
5728 			{
5729 				t = ap(pbuffer, sizeof(pbuffer), t, "<NO MEASUREMENTS>");
5730 				var_flag &= ~DEF;
5731 			}
5732 			else
5733 			{
5734 				t = ap(pbuffer, sizeof(pbuffer), t, "ch=%d, acq=%s, eph=%d, signal_level= %5.2f, elevation= %5.2f, azimuth= %6.2f",
5735 					(mb(1) & 0xFF)>>3,
5736 					mb(2) ? ((mb(2) == 1) ? "ACQ" : "SRCH") : "NEVER",
5737 					mb(3),
5738 					getflt((unsigned char *)&mb(4)),
5739 					getflt((unsigned char *)&mb(12)) * RTOD,
5740 					getflt((unsigned char *)&mb(16)) * RTOD);
5741 				if (mb(20))
5742 				{
5743 					var_flag &= ~DEF;
5744 					t = ap(pbuffer, sizeof(pbuffer), t, ", OLD");
5745 				}
5746 				if (mb(22))
5747 				{
5748 					if (mb(22) == 1)
5749 						t = ap(pbuffer, sizeof(pbuffer), t, ", BAD PARITY");
5750 					else
5751 						if (mb(22) == 2)
5752 							t = ap(pbuffer, sizeof(pbuffer), t, ", BAD EPH HEALTH");
5753 				}
5754 				if (mb(23))
5755 					t = ap(pbuffer, sizeof(pbuffer), t, ", collecting data");
5756 			}
5757 		}
5758 		break;
5759 
5760 		default:
5761 			t = ap(pbuffer, sizeof(pbuffer), t, "<UNDECODED>");
5762 			break;
5763 		}
5764 
5765 		t = ap(pbuffer, sizeof(pbuffer), t,"\"");
5766 		set_var(&parse->kv, pbuffer, sizeof(pbuffer), var_flag);
5767 	}
5768 }
5769 
5770 
5771 /**============================================================
5772  ** RAWDCF support
5773  **/
5774 
5775 /*--------------------------------------------------
5776  * rawdcf_init_1 - set up modem lines for RAWDCF receivers
5777  * SET DTR line
5778  */
5779 #if defined(TIOCMSET) && (defined(TIOCM_DTR) || defined(CIOCM_DTR))
5780 static int
5781 rawdcf_init_1(
5782 	struct parseunit *parse
5783 	)
5784 {
5785 	/* fixed 2000 for using with Linux by Wolfram Pienkoss <wp@bszh.de> */
5786 	/*
5787 	 * You can use the RS232 to supply the power for a DCF77 receiver.
5788 	 * Here a voltage between the DTR and the RTS line is used. Unfortunately
5789 	 * the name has changed from CIOCM_DTR to TIOCM_DTR recently.
5790 	 */
5791 	int sl232;
5792 
5793 	if (ioctl(parse->generic->io.fd, TIOCMGET, (caddr_t)&sl232) == -1)
5794 	{
5795 		msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_1: WARNING: ioctl(fd, TIOCMGET, [C|T]IOCM_DTR): %m", CLK_UNIT(parse->peer));
5796 		return 0;
5797 	}
5798 
5799 #ifdef TIOCM_DTR
5800 	sl232 = (sl232 & ~TIOCM_RTS) | TIOCM_DTR;	/* turn on DTR, clear RTS for power supply */
5801 #else
5802 	sl232 = (sl232 & ~CIOCM_RTS) | CIOCM_DTR;	/* turn on DTR, clear RTS for power supply */
5803 #endif
5804 
5805 	if (ioctl(parse->generic->io.fd, TIOCMSET, (caddr_t)&sl232) == -1)
5806 	{
5807 		msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_1: WARNING: ioctl(fd, TIOCMSET, [C|T]IOCM_DTR): %m", CLK_UNIT(parse->peer));
5808 	}
5809 	return 0;
5810 }
5811 #else
5812 static int
5813 rawdcfdtr_init_1(
5814 	struct parseunit *parse
5815 	)
5816 {
5817 	msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_1: WARNING: OS interface incapable of setting DTR to power DCF modules", CLK_UNIT(parse->peer));
5818 	return 0;
5819 }
5820 #endif  /* DTR initialisation type */
5821 
5822 /*--------------------------------------------------
5823  * rawdcf_init_2 - set up modem lines for RAWDCF receivers
5824  * CLR DTR line, SET RTS line
5825  */
5826 #if defined(TIOCMSET) &&  (defined(TIOCM_RTS) || defined(CIOCM_RTS))
5827 static int
5828 rawdcf_init_2(
5829 	struct parseunit *parse
5830 	)
5831 {
5832 	/* fixed 2000 for using with Linux by Wolfram Pienkoss <wp@bszh.de> */
5833 	/*
5834 	 * You can use the RS232 to supply the power for a DCF77 receiver.
5835 	 * Here a voltage between the DTR and the RTS line is used. Unfortunately
5836 	 * the name has changed from CIOCM_DTR to TIOCM_DTR recently.
5837 	 */
5838 	int sl232;
5839 
5840 	if (ioctl(parse->generic->io.fd, TIOCMGET, (caddr_t)&sl232) == -1)
5841 	{
5842 		msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_2: WARNING: ioctl(fd, TIOCMGET, [C|T]IOCM_RTS): %m", CLK_UNIT(parse->peer));
5843 		return 0;
5844 	}
5845 
5846 #ifdef TIOCM_RTS
5847 	sl232 = (sl232 & ~TIOCM_DTR) | TIOCM_RTS;	/* turn on RTS, clear DTR for power supply */
5848 #else
5849 	sl232 = (sl232 & ~CIOCM_DTR) | CIOCM_RTS;	/* turn on RTS, clear DTR for power supply */
5850 #endif
5851 
5852 	if (ioctl(parse->generic->io.fd, TIOCMSET, (caddr_t)&sl232) == -1)
5853 	{
5854 		msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_2: WARNING: ioctl(fd, TIOCMSET, [C|T]IOCM_RTS): %m", CLK_UNIT(parse->peer));
5855 	}
5856 	return 0;
5857 }
5858 #else
5859 static int
5860 rawdcf_init_2(
5861 	struct parseunit *parse
5862 	)
5863 {
5864 	msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_2: WARNING: OS interface incapable of setting RTS to power DCF modules", CLK_UNIT(parse->peer));
5865 	return 0;
5866 }
5867 #endif  /* DTR initialisation type */
5868 
5869 #else	/* defined(REFCLOCK) && defined(PARSE) */
5870 int refclock_parse_bs;
5871 #endif	/* defined(REFCLOCK) && defined(PARSE) */
5872 
5873 /*
5874  * History:
5875  *
5876  * refclock_parse.c,v
5877  * Revision 4.81  2009/05/01 10:15:29  kardel
5878  * use new refclock_ppsapi interface
5879  *
5880  * Revision 4.80  2007/08/11 12:06:29  kardel
5881  * update comments wrt/ to PPS
5882  *
5883  * Revision 4.79  2007/08/11 11:52:23  kardel
5884  * - terminate io bindings before io_closeclock() will close our file descriptor
5885  *
5886  * Revision 4.78  2006/12/22 20:08:27  kardel
5887  * Bug 746 (RFE): add configuration for Expert mouseCLOCK USB v2.0 as mode 19
5888  *
5889  * Revision 4.77  2006/08/05 07:44:49  kardel
5890  * support optionally separate PPS devices via /dev/refclockpps-{0..3}
5891  *
5892  * Revision 4.76  2006/06/22 18:40:47  kardel
5893  * clean up signedness (gcc 4)
5894  *
5895  * Revision 4.75  2006/06/22 16:58:10  kardel
5896  * Bug #632: call parse_ppsapi() in parse_ctl() when updating
5897  * the PPS offset. Fix sign of offset passed to kernel.
5898  *
5899  * Revision 4.74  2006/06/18 21:18:37  kardel
5900  * NetBSD Coverity CID 3796: possible NULL deref
5901  *
5902  * Revision 4.73  2006/05/26 14:23:46  kardel
5903  * cleanup of copyright info
5904  *
5905  * Revision 4.72  2006/05/26 14:19:43  kardel
5906  * cleanup of ioctl cruft
5907  *
5908  * Revision 4.71  2006/05/26 14:15:57  kardel
5909  * delay adding refclock to async refclock io after all initializations
5910  *
5911  * Revision 4.70  2006/05/25 18:20:50  kardel
5912  * bug #619
5913  * terminate parse io engine after de-registering
5914  * from refclock io engine
5915  *
5916  * Revision 4.69  2006/05/25 17:28:02  kardel
5917  * complete refclock io structure initialization *before* inserting it into the
5918  * refclock input machine (avoids null pointer deref) (bug #619)
5919  *
5920  * Revision 4.68  2006/05/01 17:02:51  kardel
5921  * copy receiver method also for newlwy created receive buffers
5922  *
5923  * Revision 4.67  2006/05/01 14:37:29  kardel
5924  * If an input buffer parses into more than one message do insert the
5925  * parsed message in a new input buffer instead of processing it
5926  * directly. This avoids deed complicated processing in signal
5927  * handling.
5928  *
5929  * Revision 4.66  2006/03/18 00:45:30  kardel
5930  * coverity fixes found in NetBSD coverity scan
5931  *
5932  * Revision 4.65  2006/01/26 06:08:33  kardel
5933  * output errno on PPS setup failure
5934  *
5935  * Revision 4.64  2005/11/09 20:44:47  kardel
5936  * utilize full PPS timestamp resolution from PPS API
5937  *
5938  * Revision 4.63  2005/10/07 22:10:25  kardel
5939  * bounded buffer implementation
5940  *
5941  * Revision 4.62.2.2  2005/09/25 10:20:16  kardel
5942  * avoid unexpected buffer overflows due to sprintf("%f") on strange floats:
5943  * replace almost all str* and *printf functions be their buffer bounded
5944  * counterparts
5945  *
5946  * Revision 4.62.2.1  2005/08/27 16:19:27  kardel
5947  * limit re-set rate of trimble clocks
5948  *
5949  * Revision 4.62  2005/08/06 17:40:00  kardel
5950  * cleanup size handling wrt/ to buffer boundaries
5951  *
5952  * Revision 4.61  2005/07/27 21:16:19  kardel
5953  * fix a long (> 11 years) misconfiguration wrt/ Meinberg cflag factory
5954  * default setup. CSTOPB was missing for the 7E2 default data format of
5955  * the DCF77 clocks.
5956  *
5957  * Revision 4.60  2005/07/17 21:14:44  kardel
5958  * change contents of version string to include the RCS/CVS Id
5959  *
5960  * Revision 4.59  2005/07/06 06:56:38  kardel
5961  * syntax error
5962  *
5963  * Revision 4.58  2005/07/04 13:10:40  kardel
5964  * fix bug 455: tripping over NULL pointer on cleanup
5965  * fix shadow storage logic for ppsphaseadjust and trustime wrt/ time2
5966  * fix compiler warnings for some platforms wrt/ printf formatstrings and
5967  *     varying structure element sizes
5968  * reorder assignment in binding to avoid tripping over NULL pointers
5969  *
5970  * Revision 4.57  2005/06/25 09:25:19  kardel
5971  * sort out log output sequence
5972  *
5973  * Revision 4.56  2005/06/14 21:47:27  kardel
5974  * collect samples only if samples are ok (sync or trusted flywheel)
5975  * propagate pps phase adjustment value to kernel via PPSAPI to help HARDPPS
5976  * en- and dis-able HARDPPS in correlation to receiver sync state
5977  *
5978  * Revision 4.55  2005/06/02 21:28:31  kardel
5979  * clarify trust logic
5980  *
5981  * Revision 4.54  2005/06/02 17:06:49  kardel
5982  * change status reporting to use fixed refclock_report()
5983  *
5984  * Revision 4.53  2005/06/02 16:33:31  kardel
5985  * fix acceptance of clocks unsync clocks right at start
5986  *
5987  * Revision 4.52  2005/05/26 21:55:06  kardel
5988  * cleanup status reporting
5989  *
5990  * Revision 4.51  2005/05/26 19:19:14  kardel
5991  * implement fast refclock startup
5992  *
5993  * Revision 4.50  2005/04/16 20:51:35  kardel
5994  * set pps_enable = 1 when binding a kernel PPS source
5995  *
5996  * Revision 4.49  2005/04/16 17:29:26  kardel
5997  * add non polling clock type 18 for just listenning to Meinberg clocks
5998  *
5999  * Revision 4.48  2005/04/16 16:22:27  kardel
6000  * bk sync 20050415 ntp-dev
6001  *
6002  * Revision 4.47  2004/11/29 10:42:48  kardel
6003  * bk sync ntp-dev 20041129
6004  *
6005  * Revision 4.46  2004/11/29 10:26:29  kardel
6006  * keep fudgetime2 in sync with trusttime/ppsphaseadjust depending in flag1
6007  *
6008  * Revision 4.45  2004/11/14 20:53:20  kardel
6009  * clear PPS flags after using them
6010  *
6011  * Revision 4.44  2004/11/14 15:29:41  kardel
6012  * support PPSAPI, upgrade Copyright to Berkeley style
6013  *
6014  * Revision 4.43  2001/05/26 22:53:16  kardel
6015  * 20010526 reconcilation
6016  *
6017  * Revision 4.42  2000/05/14 15:31:51  kardel
6018  * PPSAPI && RAWDCF modemline support
6019  *
6020  * Revision 4.41  2000/04/09 19:50:45  kardel
6021  * fixed rawdcfdtr_init() -> rawdcf_init_1
6022  *
6023  * Revision 4.40  2000/04/09 15:27:55  kardel
6024  * modem line fiddle in rawdcf_init_2
6025  *
6026  * Revision 4.39  2000/03/18 09:16:55  kardel
6027  * PPSAPI integration
6028  *
6029  * Revision 4.38  2000/03/05 20:25:06  kardel
6030  * support PPSAPI
6031  *
6032  * Revision 4.37  2000/03/05 20:11:14  kardel
6033  * 4.0.99g reconcilation
6034  *
6035  * Revision 4.36  1999/11/28 17:18:20  kardel
6036  * disabled burst mode
6037  *
6038  * Revision 4.35  1999/11/28 09:14:14  kardel
6039  * RECON_4_0_98F
6040  *
6041  * Revision 4.34  1999/05/14 06:08:05  kardel
6042  * store current_time in a suitable container (u_long)
6043  *
6044  * Revision 4.33  1999/05/13 21:48:38  kardel
6045  * double the no response timeout interval
6046  *
6047  * Revision 4.32  1999/05/13 20:09:13  kardel
6048  * complain only about missing polls after a full poll interval
6049  *
6050  * Revision 4.31  1999/05/13 19:59:32  kardel
6051  * add clock type 16 for RTS set DTR clr in RAWDCF
6052  *
6053  * Revision 4.30  1999/02/28 20:36:43  kardel
6054  * fixed printf fmt
6055  *
6056  * Revision 4.29  1999/02/28 19:58:23  kardel
6057  * updated copyright information
6058  *
6059  * Revision 4.28  1999/02/28 19:01:50  kardel
6060  * improved debug out on sent Meinberg messages
6061  *
6062  * Revision 4.27  1999/02/28 18:05:55  kardel
6063  * no linux/ppsclock.h stuff
6064  *
6065  * Revision 4.26  1999/02/28 15:27:27  kardel
6066  * wharton clock integration
6067  *
6068  * Revision 4.25  1999/02/28 14:04:46  kardel
6069  * added missing double quotes to UTC information string
6070  *
6071  * Revision 4.24  1999/02/28 12:06:50  kardel
6072  * (parse_control): using gmprettydate instead of prettydate()
6073  * (mk_utcinfo): new function for formatting GPS derived UTC information
6074  * (gps16x_message): changed to use mk_utcinfo()
6075  * (trimbletsip_message): changed to use mk_utcinfo()
6076  * ignoring position information in unsynchronized mode
6077  * (parse_start): augument linux support for optional ASYNC_LOW_LATENCY
6078  *
6079  * Revision 4.23  1999/02/23 19:47:53  kardel
6080  * fixed #endifs
6081  * (stream_receive): fixed formats
6082  *
6083  * Revision 4.22  1999/02/22 06:21:02  kardel
6084  * use new autoconfig symbols
6085  *
6086  * Revision 4.21  1999/02/21 12:18:13  kardel
6087  * 4.91f reconcilation
6088  *
6089  * Revision 4.20  1999/02/21 10:53:36  kardel
6090  * initial Linux PPSkit version
6091  *
6092  * Revision 4.19  1999/02/07 09:10:45  kardel
6093  * clarify STREAMS mitigation rules in comment
6094  *
6095  * Revision 4.18  1998/12/20 23:45:34  kardel
6096  * fix types and warnings
6097  *
6098  * Revision 4.17  1998/11/15 21:24:51  kardel
6099  * cannot access mbg_ routines when CLOCK_MEINBERG
6100  * is not defined
6101  *
6102  * Revision 4.16  1998/11/15 20:28:17  kardel
6103  * Release 4.0.73e13 reconcilation
6104  *
6105  * Revision 4.15  1998/08/22 21:56:08  kardel
6106  * fixed IO handling for non-STREAM IO
6107  *
6108  * Revision 4.14  1998/08/16 19:00:48  kardel
6109  * (gps16x_message): reduced UTC parameter information (dropped A0,A1)
6110  * made uval a local variable (killed one of the last globals)
6111  * (sendetx): added logging of messages when in debug mode
6112  * (trimble_check): added periodic checks to facilitate re-initialization
6113  * (trimbletsip_init): made use of EOL character if in non-kernel operation
6114  * (trimbletsip_message): extended message interpretation
6115  * (getdbl): fixed data conversion
6116  *
6117  * Revision 4.13  1998/08/09 22:29:13  kardel
6118  * Trimble TSIP support
6119  *
6120  * Revision 4.12  1998/07/11 10:05:34  kardel
6121  * Release 4.0.73d reconcilation
6122  *
6123  * Revision 4.11  1998/06/14 21:09:42  kardel
6124  * Sun acc cleanup
6125  *
6126  * Revision 4.10  1998/06/13 12:36:45  kardel
6127  * signed/unsigned, name clashes
6128  *
6129  * Revision 4.9  1998/06/12 15:30:00  kardel
6130  * prototype fixes
6131  *
6132  * Revision 4.8  1998/06/12 11:19:42  kardel
6133  * added direct input processing routine for refclocks in
6134  * order to avaiod that single character io gobbles up all
6135  * receive buffers and drops input data. (Problem started
6136  * with fast machines so a character a buffer was possible
6137  * one of the few cases where faster machines break existing
6138  * allocation algorithms)
6139  *
6140  * Revision 4.7  1998/06/06 18:35:20  kardel
6141  * (parse_start): added BURST mode initialisation
6142  *
6143  * Revision 4.6  1998/05/27 06:12:46  kardel
6144  * RAWDCF_BASEDELAY default added
6145  * old comment removed
6146  * casts for ioctl()
6147  *
6148  * Revision 4.5  1998/05/25 22:05:09  kardel
6149  * RAWDCF_SETDTR option removed
6150  * clock type 14 attempts to set DTR for
6151  * power supply of RAWDCF receivers
6152  *
6153  * Revision 4.4  1998/05/24 16:20:47  kardel
6154  * updated comments referencing Meinberg clocks
6155  * added RAWDCF clock with DTR set option as type 14
6156  *
6157  * Revision 4.3  1998/05/24 10:48:33  kardel
6158  * calibrated CONRAD RAWDCF default fudge factor
6159  *
6160  * Revision 4.2  1998/05/24 09:59:35  kardel
6161  * corrected version information (ntpq support)
6162  *
6163  * Revision 4.1  1998/05/24 09:52:31  kardel
6164  * use fixed format only (new IO model)
6165  * output debug to stdout instead of msyslog()
6166  * don't include >"< in ASCII output in order not to confuse
6167  * ntpq parsing
6168  *
6169  * Revision 4.0  1998/04/10 19:52:11  kardel
6170  * Start 4.0 release version numbering
6171  *
6172  * Revision 1.2  1998/04/10 19:28:04  kardel
6173  * initial NTP VERSION 4 integration of PARSE with GPS166 binary support
6174  * derived from 3.105.1.2 from V3 tree
6175  *
6176  * Revision information 3.1 - 3.105 from log deleted 1998/04/10 kardel
6177  *
6178  */
6179