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