xref: /freebsd/contrib/ntp/ntpd/refclock_parse.c (revision 9c2daa00)
1 /*
2  * /src/NTP/ntp-4/ntpd/refclock_parse.c,v 4.36 1999/11/28 17:18:20 kardel RELEASE_19991128_A
3  *
4  * refclock_parse.c,v 4.36 1999/11/28 17:18:20 kardel RELEASE_19991128_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.36 1999/11/28 17:18:20 kardel RELEASE_19991128_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_long        pollneeddata; 	/* current_time(!=0) 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	rawdcf_init_1	P((struct parseunit *));
613 #define RAWDCFDTRSET_DESCRIPTION	"RAW DCF77 CODE (DTR SET/RTS CLR)"
614 #define RAWDCFDTRSET_INIT 		rawdcf_init_1
615 
616 /*
617  * RAWDCF receivers that need to be powered from
618  * DTR CLR and RTS SET
619  */
620 static	int	rawdcf_init_2	P((struct parseunit *));
621 #define RAWDCFDTRCLRRTSSET_DESCRIPTION	"RAW DCF77 CODE (DTR CLR/RTS SET)"
622 #define RAWDCFDTRCLRRTSSET_INIT	rawdcf_init_2
623 
624 /*
625  * Trimble GPS receivers (TAIP and TSIP protocols)
626  */
627 #ifndef TRIM_POLLRATE
628 #define TRIM_POLLRATE	0	/* only true direct polling */
629 #endif
630 
631 #define TRIM_TAIPPOLLCMD	">SRM;FR_FLAG=F;EC_FLAG=F<>QTM<"
632 #define TRIM_TAIPCMDSIZE	(sizeof(TRIM_TAIPPOLLCMD)-1)
633 
634 static poll_info_t trimbletaip_pollinfo = { TRIM_POLLRATE, TRIM_TAIPPOLLCMD, TRIM_TAIPCMDSIZE };
635 static	int	trimbletaip_init	P((struct parseunit *));
636 static	void	trimbletaip_event	P((struct parseunit *, int));
637 
638 /* query time & UTC correction data */
639 static char tsipquery[] = { DLE, 0x21, DLE, ETX, DLE, 0x2F, DLE, ETX };
640 
641 static poll_info_t trimbletsip_pollinfo = { TRIM_POLLRATE, tsipquery, sizeof(tsipquery) };
642 static	int	trimbletsip_init	P((struct parseunit *));
643 static	void	trimbletsip_end   	P((struct parseunit *));
644 static	void	trimbletsip_message	P((struct parseunit *, parsetime_t *));
645 static	void	trimbletsip_event	P((struct parseunit *, int));
646 
647 #define TRIMBLETSIP_IDLE_TIME	    (300) /* 5 minutes silence at most */
648 
649 #define TRIMBLETAIP_SPEED	    (B4800)
650 #define TRIMBLETAIP_CFLAG           (CS8|CREAD|CLOCAL)
651 #define TRIMBLETAIP_IFLAG           (BRKINT|IGNPAR|ISTRIP|ICRNL|IXON)
652 #define TRIMBLETAIP_OFLAG           (OPOST|ONLCR)
653 #define TRIMBLETAIP_LFLAG           (0)
654 
655 #define TRIMBLETSIP_SPEED	    (B9600)
656 #define TRIMBLETSIP_CFLAG           (CS8|CLOCAL|CREAD|PARENB|PARODD)
657 #define TRIMBLETSIP_IFLAG           (IGNBRK)
658 #define TRIMBLETSIP_OFLAG           (0)
659 #define TRIMBLETSIP_LFLAG           (ICANON)
660 
661 #define TRIMBLETSIP_SAMPLES	    5
662 #define TRIMBLETSIP_KEEP	    3
663 #define TRIMBLETAIP_SAMPLES	    5
664 #define TRIMBLETAIP_KEEP	    3
665 
666 #define TRIMBLETAIP_FLAGS	    (PARSE_F_PPSONSECOND)
667 #define TRIMBLETSIP_FLAGS	    (TRIMBLETAIP_FLAGS)
668 
669 #define TRIMBLETAIP_POLL	    poll_dpoll
670 #define TRIMBLETSIP_POLL	    poll_dpoll
671 
672 #define TRIMBLETAIP_INIT	    trimbletaip_init
673 #define TRIMBLETSIP_INIT	    trimbletsip_init
674 
675 #define TRIMBLETAIP_EVENT	    trimbletaip_event
676 
677 #define TRIMBLETSIP_EVENT	    trimbletsip_event
678 #define TRIMBLETSIP_MESSAGE	    trimbletsip_message
679 
680 #define TRIMBLETAIP_END		    0
681 #define TRIMBLETSIP_END		    trimbletsip_end
682 
683 #define TRIMBLETAIP_DATA	    ((void *)(&trimbletaip_pollinfo))
684 #define TRIMBLETSIP_DATA	    ((void *)(&trimbletsip_pollinfo))
685 
686 #define TRIMBLETAIP_ID		    GPS_ID
687 #define TRIMBLETSIP_ID		    GPS_ID
688 
689 #define TRIMBLETAIP_FORMAT	    "Trimble TAIP"
690 #define TRIMBLETSIP_FORMAT	    "Trimble TSIP"
691 
692 #define TRIMBLETAIP_ROOTDELAY        0x0
693 #define TRIMBLETSIP_ROOTDELAY        0x0
694 
695 #define TRIMBLETAIP_BASEDELAY        0.0
696 #define TRIMBLETSIP_BASEDELAY        0.020	/* GPS time message latency */
697 
698 #define TRIMBLETAIP_DESCRIPTION      "Trimble GPS (TAIP) receiver"
699 #define TRIMBLETSIP_DESCRIPTION      "Trimble GPS (TSIP) receiver"
700 
701 #define TRIMBLETAIP_MAXUNSYNC        0
702 #define TRIMBLETSIP_MAXUNSYNC        0
703 
704 #define TRIMBLETAIP_EOL		    '<'
705 
706 /*
707  * RadioCode Clocks RCC 800 receiver
708  */
709 #define RCC_POLLRATE   0       /* only true direct polling */
710 #define RCC_POLLCMD    "\r"
711 #define RCC_CMDSIZE    1
712 
713 static poll_info_t rcc8000_pollinfo = { RCC_POLLRATE, RCC_POLLCMD, RCC_CMDSIZE };
714 #define RCC8000_FLAGS		0
715 #define RCC8000_POLL            poll_dpoll
716 #define RCC8000_INIT            poll_init
717 #define RCC8000_END             0
718 #define RCC8000_DATA            ((void *)(&rcc8000_pollinfo))
719 #define RCC8000_ROOTDELAY       0.0
720 #define RCC8000_BASEDELAY       0.0
721 #define RCC8000_ID              "MSF"
722 #define RCC8000_DESCRIPTION     "RCC 8000 MSF Receiver"
723 #define RCC8000_FORMAT          "Radiocode RCC8000"
724 #define RCC8000_MAXUNSYNC       (60*60) /* should be ok for an hour */
725 #define RCC8000_SPEED		(B2400)
726 #define RCC8000_CFLAG           (CS8|CREAD|CLOCAL)
727 #define RCC8000_IFLAG           (IGNBRK|IGNPAR)
728 #define RCC8000_OFLAG           0
729 #define RCC8000_LFLAG           0
730 #define RCC8000_SAMPLES         5
731 #define RCC8000_KEEP	        3
732 
733 /*
734  * Hopf Radio clock 6021 Format
735  *
736  */
737 #define HOPF6021_ROOTDELAY	0.0
738 #define HOPF6021_BASEDELAY	0.0
739 #define HOPF6021_DESCRIPTION	"HOPF 6021"
740 #define HOPF6021_FORMAT         "hopf Funkuhr 6021"
741 #define HOPF6021_MAXUNSYNC	(60*60)  /* should be ok for an hour */
742 #define HOPF6021_SPEED         (B9600)
743 #define HOPF6021_CFLAG          (CS8|CREAD|CLOCAL)
744 #define HOPF6021_IFLAG		(IGNBRK|ISTRIP)
745 #define HOPF6021_OFLAG		0
746 #define HOPF6021_LFLAG		0
747 #define HOPF6021_FLAGS          0
748 #define HOPF6021_SAMPLES        5
749 #define HOPF6021_KEEP	        3
750 
751 /*
752  * Diem's Computime Radio Clock Receiver
753  */
754 #define COMPUTIME_FLAGS       0
755 #define COMPUTIME_ROOTDELAY   0.0
756 #define COMPUTIME_BASEDELAY   0.0
757 #define COMPUTIME_ID          DCF_ID
758 #define COMPUTIME_DESCRIPTION "Diem's Computime receiver"
759 #define COMPUTIME_FORMAT      "Diem's Computime Radio Clock"
760 #define COMPUTIME_TYPE        DCF_TYPE
761 #define COMPUTIME_MAXUNSYNC   (60*60)       /* only trust clock for 1 hour */
762 #define COMPUTIME_SPEED       (B9600)
763 #define COMPUTIME_CFLAG       (CSTOPB|CS7|CREAD|CLOCAL)
764 #define COMPUTIME_IFLAG       (IGNBRK|IGNPAR|ISTRIP)
765 #define COMPUTIME_OFLAG       0
766 #define COMPUTIME_LFLAG       0
767 #define COMPUTIME_SAMPLES     5
768 #define COMPUTIME_KEEP        3
769 
770 /*
771  * Varitext Radio Clock Receiver
772  */
773 #define VARITEXT_FLAGS       0
774 #define VARITEXT_ROOTDELAY   0.0
775 #define VARITEXT_BASEDELAY   0.0
776 #define VARITEXT_ID          "MSF"
777 #define VARITEXT_DESCRIPTION "Varitext receiver"
778 #define VARITEXT_FORMAT      "Varitext Radio Clock"
779 #define VARITEXT_TYPE        DCF_TYPE
780 #define VARITEXT_MAXUNSYNC   (60*60)       /* only trust clock for 1 hour */
781 #define VARITEXT_SPEED       (B9600)
782 #define VARITEXT_CFLAG       (CS7|CREAD|CLOCAL|PARENB|PARODD)
783 #define VARITEXT_IFLAG       (IGNPAR|IGNBRK|INPCK) /*|ISTRIP)*/
784 #define VARITEXT_OFLAG       0
785 #define VARITEXT_LFLAG       0
786 #define VARITEXT_SAMPLES     32
787 #define VARITEXT_KEEP        20
788 
789 static struct parse_clockinfo
790 {
791 	u_long  cl_flags;		/* operation flags (io modes) */
792   void  (*cl_poll)    P((struct parseunit *));			/* active poll routine */
793   int   (*cl_init)    P((struct parseunit *));			/* active poll init routine */
794   void  (*cl_event)   P((struct parseunit *, int));		/* special event handling (e.g. reset clock) */
795   void  (*cl_end)     P((struct parseunit *));			/* active poll end routine */
796   void  (*cl_message) P((struct parseunit *, parsetime_t *));	/* process a lower layer message */
797 	void   *cl_data;		/* local data area for "poll" mechanism */
798 	double    cl_rootdelay;		/* rootdelay */
799 	double    cl_basedelay;		/* current offset by which the RS232
800 				time code is delayed from the actual time */
801 	const char *cl_id;		/* ID code */
802 	const char *cl_description;		/* device name */
803 	const char *cl_format;		/* fixed format */
804 	u_char  cl_type;		/* clock type (ntp control) */
805 	u_long  cl_maxunsync;		/* time to trust oscillator after losing synch */
806 	u_long  cl_speed;		/* terminal input & output baudrate */
807 	u_long  cl_cflag;             /* terminal control flags */
808 	u_long  cl_iflag;             /* terminal input flags */
809 	u_long  cl_oflag;             /* terminal output flags */
810 	u_long  cl_lflag;             /* terminal local flags */
811 	u_long  cl_samples;	      /* samples for median filter */
812 	u_long  cl_keep;              /* samples for median filter to keep */
813 } parse_clockinfo[] =
814 {
815 	{				/* mode 0 */
816 		MBG_FLAGS,
817 		NO_POLL,
818 		NO_INIT,
819 		NO_EVENT,
820 		NO_END,
821 		NO_MESSAGE,
822 		NO_DATA,
823 		DCFPZF535_ROOTDELAY,
824 		DCFPZF535_BASEDELAY,
825 		DCF_P_ID,
826 		DCFPZF535_DESCRIPTION,
827 		DCFPZF535_FORMAT,
828 		DCF_TYPE,
829 		DCFPZF535_MAXUNSYNC,
830 		DCFPZF535_SPEED,
831 		DCFPZF535_CFLAG,
832 		DCFPZF535_IFLAG,
833 		DCFPZF535_OFLAG,
834 		DCFPZF535_LFLAG,
835 		DCFPZF535_SAMPLES,
836 		DCFPZF535_KEEP
837 	},
838 	{				/* mode 1 */
839 		MBG_FLAGS,
840 		NO_POLL,
841 		NO_INIT,
842 		NO_EVENT,
843 		NO_END,
844 		NO_MESSAGE,
845 		NO_DATA,
846 		DCFPZF535OCXO_ROOTDELAY,
847 		DCFPZF535OCXO_BASEDELAY,
848 		DCF_P_ID,
849 		DCFPZF535OCXO_DESCRIPTION,
850 		DCFPZF535OCXO_FORMAT,
851 		DCF_TYPE,
852 		DCFPZF535OCXO_MAXUNSYNC,
853 		DCFPZF535OCXO_SPEED,
854 		DCFPZF535OCXO_CFLAG,
855 		DCFPZF535OCXO_IFLAG,
856 		DCFPZF535OCXO_OFLAG,
857 		DCFPZF535OCXO_LFLAG,
858 		DCFPZF535OCXO_SAMPLES,
859 		DCFPZF535OCXO_KEEP
860 	},
861 	{				/* mode 2 */
862 		MBG_FLAGS,
863 		NO_POLL,
864 		NO_INIT,
865 		NO_EVENT,
866 		NO_END,
867 		NO_MESSAGE,
868 		NO_DATA,
869 		DCFUA31_ROOTDELAY,
870 		DCFUA31_BASEDELAY,
871 		DCF_A_ID,
872 		DCFUA31_DESCRIPTION,
873 		DCFUA31_FORMAT,
874 		DCF_TYPE,
875 		DCFUA31_MAXUNSYNC,
876 		DCFUA31_SPEED,
877 		DCFUA31_CFLAG,
878 		DCFUA31_IFLAG,
879 		DCFUA31_OFLAG,
880 		DCFUA31_LFLAG,
881 		DCFUA31_SAMPLES,
882 		DCFUA31_KEEP
883 	},
884 	{				/* mode 3 */
885 		MBG_FLAGS,
886 		NO_POLL,
887 		NO_INIT,
888 		NO_EVENT,
889 		NO_END,
890 		NO_MESSAGE,
891 		NO_DATA,
892 		DCF7000_ROOTDELAY,
893 		DCF7000_BASEDELAY,
894 		DCF_A_ID,
895 		DCF7000_DESCRIPTION,
896 		DCF7000_FORMAT,
897 		DCF_TYPE,
898 		DCF7000_MAXUNSYNC,
899 		DCF7000_SPEED,
900 		DCF7000_CFLAG,
901 		DCF7000_IFLAG,
902 		DCF7000_OFLAG,
903 		DCF7000_LFLAG,
904 		DCF7000_SAMPLES,
905 		DCF7000_KEEP
906 	},
907 	{				/* mode 4 */
908 		NO_CL_FLAGS,
909 		WSDCF_POLL,
910 		WSDCF_INIT,
911 		NO_EVENT,
912 		WSDCF_END,
913 		NO_MESSAGE,
914 		WSDCF_DATA,
915 		WSDCF_ROOTDELAY,
916 		WSDCF_BASEDELAY,
917 		DCF_A_ID,
918 		WSDCF_DESCRIPTION,
919 		WSDCF_FORMAT,
920 		DCF_TYPE,
921 		WSDCF_MAXUNSYNC,
922 		WSDCF_SPEED,
923 		WSDCF_CFLAG,
924 		WSDCF_IFLAG,
925 		WSDCF_OFLAG,
926 		WSDCF_LFLAG,
927 		WSDCF_SAMPLES,
928 		WSDCF_KEEP
929 	},
930 	{				/* mode 5 */
931 		RAWDCF_FLAGS,
932 		NO_POLL,
933 		RAWDCF_INIT,
934 		NO_EVENT,
935 		NO_END,
936 		NO_MESSAGE,
937 		NO_DATA,
938 		RAWDCF_ROOTDELAY,
939 		CONRAD_BASEDELAY,
940 		DCF_A_ID,
941 		CONRAD_DESCRIPTION,
942 		RAWDCF_FORMAT,
943 		DCF_TYPE,
944 		RAWDCF_MAXUNSYNC,
945 		RAWDCF_SPEED,
946 		RAWDCF_CFLAG,
947 		RAWDCF_IFLAG,
948 		RAWDCF_OFLAG,
949 		RAWDCF_LFLAG,
950 		RAWDCF_SAMPLES,
951 		RAWDCF_KEEP
952 	},
953 	{				/* mode 6 */
954 		RAWDCF_FLAGS,
955 		NO_POLL,
956 		RAWDCF_INIT,
957 		NO_EVENT,
958 		NO_END,
959 		NO_MESSAGE,
960 		NO_DATA,
961 		RAWDCF_ROOTDELAY,
962 		TIMEBRICK_BASEDELAY,
963 		DCF_A_ID,
964 		TIMEBRICK_DESCRIPTION,
965 		RAWDCF_FORMAT,
966 		DCF_TYPE,
967 		RAWDCF_MAXUNSYNC,
968 		RAWDCF_SPEED,
969 		RAWDCF_CFLAG,
970 		RAWDCF_IFLAG,
971 		RAWDCF_OFLAG,
972 		RAWDCF_LFLAG,
973 		RAWDCF_SAMPLES,
974 		RAWDCF_KEEP
975 	},
976 	{				/* mode 7 */
977 		MBG_FLAGS,
978 		GPS16X_POLL,
979 		GPS16X_INIT,
980 		NO_EVENT,
981 		GPS16X_END,
982 		GPS16X_MESSAGE,
983 		GPS16X_DATA,
984 		GPS16X_ROOTDELAY,
985 		GPS16X_BASEDELAY,
986 		GPS16X_ID,
987 		GPS16X_DESCRIPTION,
988 		GPS16X_FORMAT,
989 		GPS_TYPE,
990 		GPS16X_MAXUNSYNC,
991 		GPS16X_SPEED,
992 		GPS16X_CFLAG,
993 		GPS16X_IFLAG,
994 		GPS16X_OFLAG,
995 		GPS16X_LFLAG,
996 		GPS16X_SAMPLES,
997 		GPS16X_KEEP
998 	},
999 	{				/* mode 8 */
1000 		RAWDCF_FLAGS,
1001 		NO_POLL,
1002 		NO_INIT,
1003 		NO_EVENT,
1004 		NO_END,
1005 		NO_MESSAGE,
1006 		NO_DATA,
1007 		RAWDCF_ROOTDELAY,
1008 		IGELCLOCK_BASEDELAY,
1009 		DCF_A_ID,
1010 		IGELCLOCK_DESCRIPTION,
1011 		RAWDCF_FORMAT,
1012 		DCF_TYPE,
1013 		RAWDCF_MAXUNSYNC,
1014 		IGELCLOCK_SPEED,
1015 		IGELCLOCK_CFLAG,
1016 		RAWDCF_IFLAG,
1017 		RAWDCF_OFLAG,
1018 		RAWDCF_LFLAG,
1019 		RAWDCF_SAMPLES,
1020 		RAWDCF_KEEP
1021 	},
1022 	{				/* mode 9 */
1023 		TRIMBLETAIP_FLAGS,
1024 #if TRIM_POLLRATE		/* DHD940515: Allow user config */
1025 		NO_POLL,
1026 #else
1027 		TRIMBLETAIP_POLL,
1028 #endif
1029 		TRIMBLETAIP_INIT,
1030 		TRIMBLETAIP_EVENT,
1031 		TRIMBLETAIP_END,
1032 		NO_MESSAGE,
1033 		TRIMBLETAIP_DATA,
1034 		TRIMBLETAIP_ROOTDELAY,
1035 		TRIMBLETAIP_BASEDELAY,
1036 		TRIMBLETAIP_ID,
1037 		TRIMBLETAIP_DESCRIPTION,
1038 		TRIMBLETAIP_FORMAT,
1039 		GPS_TYPE,
1040 		TRIMBLETAIP_MAXUNSYNC,
1041 		TRIMBLETAIP_SPEED,
1042 		TRIMBLETAIP_CFLAG,
1043 		TRIMBLETAIP_IFLAG,
1044 		TRIMBLETAIP_OFLAG,
1045 		TRIMBLETAIP_LFLAG,
1046 		TRIMBLETAIP_SAMPLES,
1047 		TRIMBLETAIP_KEEP
1048 	},
1049 	{				/* mode 10 */
1050 		TRIMBLETSIP_FLAGS,
1051 #if TRIM_POLLRATE		/* DHD940515: Allow user config */
1052 		NO_POLL,
1053 #else
1054 		TRIMBLETSIP_POLL,
1055 #endif
1056 		TRIMBLETSIP_INIT,
1057 		TRIMBLETSIP_EVENT,
1058 		TRIMBLETSIP_END,
1059 		TRIMBLETSIP_MESSAGE,
1060 		TRIMBLETSIP_DATA,
1061 		TRIMBLETSIP_ROOTDELAY,
1062 		TRIMBLETSIP_BASEDELAY,
1063 		TRIMBLETSIP_ID,
1064 		TRIMBLETSIP_DESCRIPTION,
1065 		TRIMBLETSIP_FORMAT,
1066 		GPS_TYPE,
1067 		TRIMBLETSIP_MAXUNSYNC,
1068 		TRIMBLETSIP_SPEED,
1069 		TRIMBLETSIP_CFLAG,
1070 		TRIMBLETSIP_IFLAG,
1071 		TRIMBLETSIP_OFLAG,
1072 		TRIMBLETSIP_LFLAG,
1073 		TRIMBLETSIP_SAMPLES,
1074 		TRIMBLETSIP_KEEP
1075 	},
1076 	{                             /* mode 11 */
1077 		NO_CL_FLAGS,
1078 		RCC8000_POLL,
1079 		RCC8000_INIT,
1080 		NO_EVENT,
1081 		RCC8000_END,
1082 		NO_MESSAGE,
1083 		RCC8000_DATA,
1084 		RCC8000_ROOTDELAY,
1085 		RCC8000_BASEDELAY,
1086 		RCC8000_ID,
1087 		RCC8000_DESCRIPTION,
1088 		RCC8000_FORMAT,
1089 		DCF_TYPE,
1090 		RCC8000_MAXUNSYNC,
1091 		RCC8000_SPEED,
1092 		RCC8000_CFLAG,
1093 		RCC8000_IFLAG,
1094 		RCC8000_OFLAG,
1095 		RCC8000_LFLAG,
1096 		RCC8000_SAMPLES,
1097 		RCC8000_KEEP
1098 	},
1099 	{                             /* mode 12 */
1100 		HOPF6021_FLAGS,
1101 		NO_POLL,
1102 		NO_INIT,
1103 		NO_EVENT,
1104 		NO_END,
1105 		NO_MESSAGE,
1106 		NO_DATA,
1107 		HOPF6021_ROOTDELAY,
1108 		HOPF6021_BASEDELAY,
1109 		DCF_ID,
1110 		HOPF6021_DESCRIPTION,
1111 		HOPF6021_FORMAT,
1112 		DCF_TYPE,
1113 		HOPF6021_MAXUNSYNC,
1114 		HOPF6021_SPEED,
1115 		HOPF6021_CFLAG,
1116 		HOPF6021_IFLAG,
1117 		HOPF6021_OFLAG,
1118 		HOPF6021_LFLAG,
1119 		HOPF6021_SAMPLES,
1120 		HOPF6021_KEEP
1121 	},
1122 	{                            /* mode 13 */
1123 		COMPUTIME_FLAGS,
1124 		NO_POLL,
1125 		NO_INIT,
1126 		NO_EVENT,
1127 		NO_END,
1128 		NO_MESSAGE,
1129 		NO_DATA,
1130 		COMPUTIME_ROOTDELAY,
1131 		COMPUTIME_BASEDELAY,
1132 		COMPUTIME_ID,
1133 		COMPUTIME_DESCRIPTION,
1134 		COMPUTIME_FORMAT,
1135 		COMPUTIME_TYPE,
1136 		COMPUTIME_MAXUNSYNC,
1137 		COMPUTIME_SPEED,
1138 		COMPUTIME_CFLAG,
1139 		COMPUTIME_IFLAG,
1140 		COMPUTIME_OFLAG,
1141 		COMPUTIME_LFLAG,
1142 		COMPUTIME_SAMPLES,
1143 		COMPUTIME_KEEP
1144 	},
1145 	{				/* mode 14 */
1146 		RAWDCF_FLAGS,
1147 		NO_POLL,
1148 		RAWDCFDTRSET_INIT,
1149 		NO_EVENT,
1150 		NO_END,
1151 		NO_MESSAGE,
1152 		NO_DATA,
1153 		RAWDCF_ROOTDELAY,
1154 		RAWDCF_BASEDELAY,
1155 		DCF_A_ID,
1156 		RAWDCFDTRSET_DESCRIPTION,
1157 		RAWDCF_FORMAT,
1158 		DCF_TYPE,
1159 		RAWDCF_MAXUNSYNC,
1160 		RAWDCF_SPEED,
1161 		RAWDCF_CFLAG,
1162 		RAWDCF_IFLAG,
1163 		RAWDCF_OFLAG,
1164 		RAWDCF_LFLAG,
1165 		RAWDCF_SAMPLES,
1166 		RAWDCF_KEEP
1167 	},
1168 	{				/* mode 15 */
1169 		0,				/* operation flags (io modes) */
1170   		NO_POLL,			/* active poll routine */
1171 		NO_INIT,			/* active poll init routine */
1172   		NO_EVENT,		        /* special event handling (e.g. reset clock) */
1173   		NO_END,				/* active poll end routine */
1174   		NO_MESSAGE,			/* process a lower layer message */
1175 		NO_DATA,			/* local data area for "poll" mechanism */
1176 		0,				/* rootdelay */
1177 		11.0 /* bits */ / 9600,		/* current offset by which the RS232
1178 				           	time code is delayed from the actual time */
1179 		DCF_ID,				/* ID code */
1180 		"WHARTON 400A Series clock",	/* device name */
1181 		"WHARTON 400A Series clock Output Format 1",	/* fixed format */
1182 			/* Must match a format-name in a libparse/clk_xxx.c file */
1183 		DCF_TYPE,			/* clock type (ntp control) */
1184 		(1*60*60),		        /* time to trust oscillator after losing synch */
1185 		B9600,				/* terminal input & output baudrate */
1186 		(CS8|CREAD|PARENB|CLOCAL|HUPCL),/* terminal control flags */
1187 		0,				/* terminal input flags */
1188 		0,				/* terminal output flags */
1189 		0,				/* terminal local flags */
1190 		5,				/* samples for median filter */
1191 		3,				/* samples for median filter to keep */
1192 	},
1193 	{				/* mode 16 - RAWDCF RTS set, DTR clr */
1194 		RAWDCF_FLAGS,
1195 		NO_POLL,
1196 		RAWDCFDTRCLRRTSSET_INIT,
1197 		NO_EVENT,
1198 		NO_END,
1199 		NO_MESSAGE,
1200 		NO_DATA,
1201 		RAWDCF_ROOTDELAY,
1202 		RAWDCF_BASEDELAY,
1203 		DCF_A_ID,
1204 		RAWDCFDTRCLRRTSSET_DESCRIPTION,
1205 		RAWDCF_FORMAT,
1206 		DCF_TYPE,
1207 		RAWDCF_MAXUNSYNC,
1208 		RAWDCF_SPEED,
1209 		RAWDCF_CFLAG,
1210 		RAWDCF_IFLAG,
1211 		RAWDCF_OFLAG,
1212 		RAWDCF_LFLAG,
1213 		RAWDCF_SAMPLES,
1214 		RAWDCF_KEEP
1215 	},
1216         {                            /* mode 17 */
1217                 VARITEXT_FLAGS,
1218                 NO_POLL,
1219                 NO_INIT,
1220                 NO_EVENT,
1221                 NO_END,
1222                 NO_MESSAGE,
1223                 NO_DATA,
1224                 VARITEXT_ROOTDELAY,
1225                 VARITEXT_BASEDELAY,
1226                 VARITEXT_ID,
1227                 VARITEXT_DESCRIPTION,
1228                 VARITEXT_FORMAT,
1229                 VARITEXT_TYPE,
1230                 VARITEXT_MAXUNSYNC,
1231                 VARITEXT_SPEED,
1232                 VARITEXT_CFLAG,
1233                 VARITEXT_IFLAG,
1234                 VARITEXT_OFLAG,
1235                 VARITEXT_LFLAG,
1236                 VARITEXT_SAMPLES,
1237                 VARITEXT_KEEP
1238         }
1239 };
1240 
1241 static int ncltypes = sizeof(parse_clockinfo) / sizeof(struct parse_clockinfo);
1242 
1243 #define CLK_REALTYPE(x) ((int)(((x)->ttl) & 0x7F))
1244 #define CLK_TYPE(x)	((CLK_REALTYPE(x) >= ncltypes) ? ~0 : CLK_REALTYPE(x))
1245 #define CLK_UNIT(x)	((int)REFCLOCKUNIT(&(x)->srcadr))
1246 #define CLK_PPS(x)	(((x)->ttl) & 0x80)
1247 
1248 /*
1249  * Other constant stuff
1250  */
1251 #define	PARSEHSREFID	0x7f7f08ff	/* 127.127.8.255 refid for hi strata */
1252 
1253 #define PARSESTATISTICS   (60*60)	        /* output state statistics every hour */
1254 
1255 static struct parseunit *parseunits[MAXUNITS];
1256 
1257 static int notice = 0;
1258 
1259 #define PARSE_STATETIME(parse, i) ((parse->generic->currentstatus == i) ? parse->statetime[i] + current_time - parse->lastchange : parse->statetime[i])
1260 
1261 static void parse_event   P((struct parseunit *, int));
1262 static void parse_process P((struct parseunit *, parsetime_t *));
1263 static void clear_err     P((struct parseunit *, u_long));
1264 static int  list_err      P((struct parseunit *, u_long));
1265 static char * l_mktime    P((u_long));
1266 
1267 /**===========================================================================
1268  ** implementation error message regression module
1269  **/
1270 static void
1271 clear_err(
1272 	struct parseunit *parse,
1273 	u_long            lstate
1274 	)
1275 {
1276 	if (lstate == ERR_ALL)
1277 	{
1278 		int i;
1279 
1280 		for (i = 0; i < ERR_CNT; i++)
1281 		{
1282 			parse->errors[i].err_stage   = err_tbl[i];
1283 			parse->errors[i].err_cnt     = 0;
1284 			parse->errors[i].err_last    = 0;
1285 			parse->errors[i].err_started = 0;
1286 			parse->errors[i].err_suppressed = 0;
1287 		}
1288 	}
1289 	else
1290 	{
1291 		parse->errors[lstate].err_stage   = err_tbl[lstate];
1292 		parse->errors[lstate].err_cnt     = 0;
1293 		parse->errors[lstate].err_last    = 0;
1294 		parse->errors[lstate].err_started = 0;
1295 		parse->errors[lstate].err_suppressed = 0;
1296 	}
1297 }
1298 
1299 static int
1300 list_err(
1301 	struct parseunit *parse,
1302 	u_long            lstate
1303 	)
1304 {
1305 	int do_it;
1306 	struct errorinfo *err = &parse->errors[lstate];
1307 
1308 	if (err->err_started == 0)
1309 	{
1310 		err->err_started = current_time;
1311 	}
1312 
1313 	do_it = (current_time - err->err_last) >= err->err_stage->err_delay;
1314 
1315 	if (do_it)
1316 	    err->err_cnt++;
1317 
1318 	if (err->err_stage->err_count &&
1319 	    (err->err_cnt >= err->err_stage->err_count))
1320 	{
1321 		err->err_stage++;
1322 		err->err_cnt = 0;
1323 	}
1324 
1325 	if (!err->err_cnt && do_it)
1326 	    msyslog(LOG_INFO, "PARSE receiver #%d: interval for following error message class is at least %s",
1327 		    CLK_UNIT(parse->peer), l_mktime(err->err_stage->err_delay));
1328 
1329 	if (!do_it)
1330 	    err->err_suppressed++;
1331 	else
1332 	    err->err_last = current_time;
1333 
1334 	if (do_it && err->err_suppressed)
1335 	{
1336 		msyslog(LOG_INFO, "PARSE receiver #%d: %ld message%s suppressed, error condition class persists for %s",
1337 			CLK_UNIT(parse->peer), err->err_suppressed, (err->err_suppressed == 1) ? " was" : "s where",
1338 			l_mktime(current_time - err->err_started));
1339 		err->err_suppressed = 0;
1340 	}
1341 
1342 	return do_it;
1343 }
1344 
1345 /*--------------------------------------------------
1346  * mkreadable - make a printable ascii string (without
1347  * embedded quotes so that the ntpq protocol isn't
1348  * fooled
1349  */
1350 #ifndef isprint
1351 #define isprint(_X_) (((_X_) > 0x1F) && ((_X_) < 0x7F))
1352 #endif
1353 
1354 static char *
1355 mkreadable(
1356 	char  *buffer,
1357 	long  blen,
1358 	const char  *src,
1359 	u_long  srclen,
1360 	int hex
1361 	)
1362 {
1363 	char *b    = buffer;
1364 	char *endb = (char *)0;
1365 
1366 	if (blen < 4)
1367 		return (char *)0;		/* don't bother with mini buffers */
1368 
1369 	endb = buffer + blen - 4;
1370 
1371 	blen--;			/* account for '\0' */
1372 
1373 	while (blen && srclen--)
1374 	{
1375 		if (!hex &&             /* no binary only */
1376 		    (*src != '\\') &&   /* no plain \ */
1377 		    (*src != '"') &&    /* no " */
1378 		    isprint((int)*src))	/* only printables */
1379 		{			/* they are easy... */
1380 			*buffer++ = *src++;
1381 			blen--;
1382 		}
1383 		else
1384 		{
1385 			if (blen < 4)
1386 			{
1387 				while (blen--)
1388 				{
1389 					*buffer++ = '.';
1390 				}
1391 				*buffer = '\0';
1392 				return b;
1393 			}
1394 			else
1395 			{
1396 				if (*src == '\\')
1397 				{
1398 					strcpy(buffer,"\\\\");
1399 					buffer += 2;
1400 					blen   -= 2;
1401 					src++;
1402 				}
1403 				else
1404 				{
1405 					sprintf(buffer, "\\x%02x", *src++);
1406 					blen   -= 4;
1407 					buffer += 4;
1408 				}
1409 			}
1410 		}
1411 		if (srclen && !blen && endb) /* overflow - set last chars to ... */
1412 			strcpy(endb, "...");
1413 	}
1414 
1415 	*buffer = '\0';
1416 	return b;
1417 }
1418 
1419 
1420 /*--------------------------------------------------
1421  * mkascii - make a printable ascii string
1422  * assumes (unless defined better) 7-bit ASCII
1423  */
1424 static char *
1425 mkascii(
1426 	char  *buffer,
1427 	long  blen,
1428 	const char  *src,
1429 	u_long  srclen
1430 	)
1431 {
1432 	return mkreadable(buffer, blen, src, srclen, 0);
1433 }
1434 
1435 /**===========================================================================
1436  ** implementation of i/o handling methods
1437  ** (all STREAM, partial STREAM, user level)
1438  **/
1439 
1440 /*
1441  * define possible io handling methods
1442  */
1443 #ifdef STREAM
1444 static int  ppsclock_init   P((struct parseunit *));
1445 static int  stream_init     P((struct parseunit *));
1446 static void stream_end      P((struct parseunit *));
1447 static int  stream_enable   P((struct parseunit *));
1448 static int  stream_disable  P((struct parseunit *));
1449 static int  stream_setcs    P((struct parseunit *, parsectl_t *));
1450 static int  stream_getfmt   P((struct parseunit *, parsectl_t *));
1451 static int  stream_setfmt   P((struct parseunit *, parsectl_t *));
1452 static int  stream_timecode P((struct parseunit *, parsectl_t *));
1453 static void stream_receive  P((struct recvbuf *));
1454 #endif
1455 
1456 static int  local_init     P((struct parseunit *));
1457 static void local_end      P((struct parseunit *));
1458 static int  local_nop      P((struct parseunit *));
1459 static int  local_setcs    P((struct parseunit *, parsectl_t *));
1460 static int  local_getfmt   P((struct parseunit *, parsectl_t *));
1461 static int  local_setfmt   P((struct parseunit *, parsectl_t *));
1462 static int  local_timecode P((struct parseunit *, parsectl_t *));
1463 static void local_receive  P((struct recvbuf *));
1464 static int  local_input    P((struct recvbuf *));
1465 
1466 static bind_t io_bindings[] =
1467 {
1468 #ifdef STREAM
1469 	{
1470 		"parse STREAM",
1471 		stream_init,
1472 		stream_end,
1473 		stream_setcs,
1474 		stream_disable,
1475 		stream_enable,
1476 		stream_getfmt,
1477 		stream_setfmt,
1478 		stream_timecode,
1479 		stream_receive,
1480 		0,
1481 	},
1482 	{
1483 		"ppsclock STREAM",
1484 		ppsclock_init,
1485 		local_end,
1486 		local_setcs,
1487 		local_nop,
1488 		local_nop,
1489 		local_getfmt,
1490 		local_setfmt,
1491 		local_timecode,
1492 		local_receive,
1493 		local_input,
1494 	},
1495 #endif
1496 	{
1497 		"normal",
1498 		local_init,
1499 		local_end,
1500 		local_setcs,
1501 		local_nop,
1502 		local_nop,
1503 		local_getfmt,
1504 		local_setfmt,
1505 		local_timecode,
1506 		local_receive,
1507 		local_input,
1508 	},
1509 	{
1510 		(char *)0,
1511 	}
1512 };
1513 
1514 #ifdef STREAM
1515 
1516 #define fix_ts(_X_) \
1517                         if ((&(_X_))->tv.tv_usec >= 1000000)                \
1518                           {                                                 \
1519 			    (&(_X_))->tv.tv_usec -= 1000000;                \
1520 			    (&(_X_))->tv.tv_sec  += 1;                      \
1521 			  }
1522 
1523 #define cvt_ts(_X_, _Y_) \
1524                         {                                                   \
1525 			  l_fp ts;				            \
1526 			  fix_ts((_X_));                                    \
1527 			  if (!buftvtots((const char *)&(&(_X_))->tv, &ts)) \
1528 			    {                                               \
1529                               ERR(ERR_BADDATA)	 		            \
1530                                 msyslog(LOG_ERR,"parse: stream_receive: timestamp conversion error (buftvtots) (%s) (%ld.%06ld) ", (_Y_), (long)(&(_X_))->tv.tv_sec, (long)(&(_X_))->tv.tv_usec);\
1531 			      return;                                       \
1532 			    }                                               \
1533 			  else                                              \
1534 			    {                                               \
1535 			      (&(_X_))->fp = ts;                            \
1536 			    }                                               \
1537 		        }
1538 
1539 /*--------------------------------------------------
1540  * ppsclock STREAM init
1541  */
1542 static int
1543 ppsclock_init(
1544 	struct parseunit *parse
1545 	)
1546 {
1547         static char m1[] = "ppsclocd";
1548 	static char m2[] = "ppsclock";
1549 
1550 	/*
1551 	 * now push the parse streams module
1552 	 * it will ensure exclusive access to the device
1553 	 */
1554 	if (ioctl(parse->generic->io.fd, I_PUSH, (caddr_t)m1) == -1 &&
1555 	    ioctl(parse->generic->io.fd, I_PUSH, (caddr_t)m2) == -1)
1556 	{
1557 		if (errno != EINVAL)
1558 		{
1559 			msyslog(LOG_ERR, "PARSE receiver #%d: ppsclock_init: ioctl(fd, I_PUSH, \"ppsclock\"): %m",
1560 				CLK_UNIT(parse->peer));
1561 		}
1562 		return 0;
1563 	}
1564 	if (!local_init(parse))
1565 	{
1566 		(void)ioctl(parse->generic->io.fd, I_POP, (caddr_t)0);
1567 		return 0;
1568 	}
1569 
1570 	parse->flags |= PARSE_PPSCLOCK;
1571 	return 1;
1572 }
1573 
1574 /*--------------------------------------------------
1575  * parse STREAM init
1576  */
1577 static int
1578 stream_init(
1579 	struct parseunit *parse
1580 	)
1581 {
1582 	static char m1[] = "parse";
1583 	/*
1584 	 * now push the parse streams module
1585 	 * to test whether it is there (neat interface 8-( )
1586 	 */
1587 	if (ioctl(parse->generic->io.fd, I_PUSH, (caddr_t)m1) == -1)
1588 	{
1589 		if (errno != EINVAL) /* accept non-existence */
1590 		{
1591 			msyslog(LOG_ERR, "PARSE receiver #%d: stream_init: ioctl(fd, I_PUSH, \"parse\"): %m", CLK_UNIT(parse->peer));
1592 		}
1593 		return 0;
1594 	}
1595 	else
1596 	{
1597 		while(ioctl(parse->generic->io.fd, I_POP, (caddr_t)0) == 0)
1598 		    /* empty loop */;
1599 
1600 		/*
1601 		 * now push it a second time after we have removed all
1602 		 * module garbage
1603 		 */
1604 		if (ioctl(parse->generic->io.fd, I_PUSH, (caddr_t)m1) == -1)
1605 		{
1606 			msyslog(LOG_ERR, "PARSE receiver #%d: stream_init: ioctl(fd, I_PUSH, \"parse\"): %m", CLK_UNIT(parse->peer));
1607 			return 0;
1608 		}
1609 		else
1610 		{
1611 			return 1;
1612 		}
1613 	}
1614 }
1615 
1616 /*--------------------------------------------------
1617  * parse STREAM end
1618  */
1619 static void
1620 stream_end(
1621 	struct parseunit *parse
1622 	)
1623 {
1624 	while(ioctl(parse->generic->io.fd, I_POP, (caddr_t)0) == 0)
1625 	    /* empty loop */;
1626 }
1627 
1628 /*--------------------------------------------------
1629  * STREAM setcs
1630  */
1631 static int
1632 stream_setcs(
1633 	struct parseunit *parse,
1634 	parsectl_t  *tcl
1635 	)
1636 {
1637 	struct strioctl strioc;
1638 
1639 	strioc.ic_cmd     = PARSEIOC_SETCS;
1640 	strioc.ic_timout  = 0;
1641 	strioc.ic_dp      = (char *)tcl;
1642 	strioc.ic_len     = sizeof (*tcl);
1643 
1644 	if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1)
1645 	{
1646 		msyslog(LOG_ERR, "PARSE receiver #%d: stream_setcs: ioctl(fd, I_STR, PARSEIOC_SETCS): %m", CLK_UNIT(parse->peer));
1647 		return 0;
1648 	}
1649 	return 1;
1650 }
1651 
1652 /*--------------------------------------------------
1653  * STREAM enable
1654  */
1655 static int
1656 stream_enable(
1657 	struct parseunit *parse
1658 	)
1659 {
1660 	struct strioctl strioc;
1661 
1662 	strioc.ic_cmd     = PARSEIOC_ENABLE;
1663 	strioc.ic_timout  = 0;
1664 	strioc.ic_dp      = (char *)0;
1665 	strioc.ic_len     = 0;
1666 
1667 	if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1)
1668 	{
1669 		msyslog(LOG_ERR, "PARSE receiver #%d: stream_enable: ioctl(fd, I_STR, PARSEIOC_ENABLE): %m", CLK_UNIT(parse->peer));
1670 		return 0;
1671 	}
1672 	parse->generic->io.clock_recv = stream_receive; /* ok - parse input in kernel */
1673 	return 1;
1674 }
1675 
1676 /*--------------------------------------------------
1677  * STREAM disable
1678  */
1679 static int
1680 stream_disable(
1681 	struct parseunit *parse
1682 	)
1683 {
1684 	struct strioctl strioc;
1685 
1686 	strioc.ic_cmd     = PARSEIOC_DISABLE;
1687 	strioc.ic_timout  = 0;
1688 	strioc.ic_dp      = (char *)0;
1689 	strioc.ic_len     = 0;
1690 
1691 	if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1)
1692 	{
1693 		msyslog(LOG_ERR, "PARSE receiver #%d: stream_disable: ioctl(fd, I_STR, PARSEIOC_DISABLE): %m", CLK_UNIT(parse->peer));
1694 		return 0;
1695 	}
1696 	parse->generic->io.clock_recv = local_receive; /* ok - parse input in daemon */
1697 	return 1;
1698 }
1699 
1700 /*--------------------------------------------------
1701  * STREAM getfmt
1702  */
1703 static int
1704 stream_getfmt(
1705 	struct parseunit *parse,
1706 	parsectl_t  *tcl
1707 	)
1708 {
1709 	struct strioctl strioc;
1710 
1711 	strioc.ic_cmd     = PARSEIOC_GETFMT;
1712 	strioc.ic_timout  = 0;
1713 	strioc.ic_dp      = (char *)tcl;
1714 	strioc.ic_len     = sizeof (*tcl);
1715 	if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1)
1716 	{
1717 		msyslog(LOG_ERR, "PARSE receiver #%d: ioctl(fd, I_STR, PARSEIOC_GETFMT): %m", CLK_UNIT(parse->peer));
1718 		return 0;
1719 	}
1720 	return 1;
1721 }
1722 
1723 /*--------------------------------------------------
1724  * STREAM setfmt
1725  */
1726 static int
1727 stream_setfmt(
1728 	struct parseunit *parse,
1729 	parsectl_t  *tcl
1730 	)
1731 {
1732 	struct strioctl strioc;
1733 
1734 	strioc.ic_cmd     = PARSEIOC_SETFMT;
1735 	strioc.ic_timout  = 0;
1736 	strioc.ic_dp      = (char *)tcl;
1737 	strioc.ic_len     = sizeof (*tcl);
1738 
1739 	if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1)
1740 	{
1741 		msyslog(LOG_ERR, "PARSE receiver #%d: stream_setfmt: ioctl(fd, I_STR, PARSEIOC_SETFMT): %m", CLK_UNIT(parse->peer));
1742 		return 0;
1743 	}
1744 	return 1;
1745 }
1746 
1747 
1748 /*--------------------------------------------------
1749  * STREAM timecode
1750  */
1751 static int
1752 stream_timecode(
1753 	struct parseunit *parse,
1754 	parsectl_t  *tcl
1755 	)
1756 {
1757 	struct strioctl strioc;
1758 
1759 	strioc.ic_cmd     = PARSEIOC_TIMECODE;
1760 	strioc.ic_timout  = 0;
1761 	strioc.ic_dp      = (char *)tcl;
1762 	strioc.ic_len     = sizeof (*tcl);
1763 
1764 	if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1)
1765 	{
1766 		ERR(ERR_INTERNAL)
1767 			msyslog(LOG_ERR, "PARSE receiver #%d: stream_timecode: ioctl(fd, I_STR, PARSEIOC_TIMECODE): %m", CLK_UNIT(parse->peer));
1768 		return 0;
1769 	}
1770 	clear_err(parse, ERR_INTERNAL);
1771 	return 1;
1772 }
1773 
1774 /*--------------------------------------------------
1775  * STREAM receive
1776  */
1777 static void
1778 stream_receive(
1779 	struct recvbuf *rbufp
1780 	)
1781 {
1782 	struct parseunit *parse = (struct parseunit *)((void *)rbufp->recv_srcclock);
1783 	parsetime_t parsetime;
1784 
1785 	if (!parse->peer)
1786 	    return;
1787 
1788 	if (rbufp->recv_length != sizeof(parsetime_t))
1789 	{
1790 		ERR(ERR_BADIO)
1791 			msyslog(LOG_ERR,"PARSE receiver #%d: stream_receive: bad size (got %d expected %d)",
1792 				CLK_UNIT(parse->peer), rbufp->recv_length, (int)sizeof(parsetime_t));
1793 		parse->generic->baddata++;
1794 		parse_event(parse, CEVNT_BADREPLY);
1795 		return;
1796 	}
1797 	clear_err(parse, ERR_BADIO);
1798 
1799 	memmove((caddr_t)&parsetime,
1800 		(caddr_t)rbufp->recv_buffer,
1801 		sizeof(parsetime_t));
1802 
1803 #ifdef DEBUG
1804 	if (debug > 3)
1805 	  {
1806 	    printf("PARSE receiver #%d: status %06x, state %08x, time %lx.%08lx, stime %lx.%08lx, ptime %lx.%08lx\n",
1807 		   CLK_UNIT(parse->peer),
1808 		   (unsigned int)parsetime.parse_status,
1809 		   (unsigned int)parsetime.parse_state,
1810 		   (long)parsetime.parse_time.tv.tv_sec,
1811 		   (long)parsetime.parse_time.tv.tv_usec,
1812 		   (long)parsetime.parse_stime.tv.tv_sec,
1813 		   (long)parsetime.parse_stime.tv.tv_usec,
1814 		   (long)parsetime.parse_ptime.tv.tv_sec,
1815 		   (long)parsetime.parse_ptime.tv.tv_usec);
1816 	  }
1817 #endif
1818 
1819 	/*
1820 	 * switch time stamp world - be sure to normalize small usec field
1821 	 * errors.
1822 	 */
1823 
1824 	cvt_ts(parsetime.parse_stime, "parse_stime");
1825 
1826 	if (PARSE_TIMECODE(parsetime.parse_state))
1827 	{
1828 	    cvt_ts(parsetime.parse_time, "parse_time");
1829 	}
1830 
1831 	if (PARSE_PPS(parsetime.parse_state))
1832 	    cvt_ts(parsetime.parse_ptime, "parse_ptime");
1833 
1834 	parse_process(parse, &parsetime);
1835 }
1836 #endif
1837 
1838 /*--------------------------------------------------
1839  * local init
1840  */
1841 static int
1842 local_init(
1843 	struct parseunit *parse
1844 	)
1845 {
1846 	return parse_ioinit(&parse->parseio);
1847 }
1848 
1849 /*--------------------------------------------------
1850  * local end
1851  */
1852 static void
1853 local_end(
1854 	struct parseunit *parse
1855 	)
1856 {
1857 	parse_ioend(&parse->parseio);
1858 }
1859 
1860 
1861 /*--------------------------------------------------
1862  * local nop
1863  */
1864 static int
1865 local_nop(
1866 	struct parseunit *parse
1867 	)
1868 {
1869 	return 1;
1870 }
1871 
1872 /*--------------------------------------------------
1873  * local setcs
1874  */
1875 static int
1876 local_setcs(
1877 	struct parseunit *parse,
1878 	parsectl_t  *tcl
1879 	)
1880 {
1881 	return parse_setcs(tcl, &parse->parseio);
1882 }
1883 
1884 /*--------------------------------------------------
1885  * local getfmt
1886  */
1887 static int
1888 local_getfmt(
1889 	struct parseunit *parse,
1890 	parsectl_t  *tcl
1891 	)
1892 {
1893 	return parse_getfmt(tcl, &parse->parseio);
1894 }
1895 
1896 /*--------------------------------------------------
1897  * local setfmt
1898  */
1899 static int
1900 local_setfmt(
1901 	struct parseunit *parse,
1902 	parsectl_t  *tcl
1903 	)
1904 {
1905 	return parse_setfmt(tcl, &parse->parseio);
1906 }
1907 
1908 /*--------------------------------------------------
1909  * local timecode
1910  */
1911 static int
1912 local_timecode(
1913 	struct parseunit *parse,
1914 	parsectl_t  *tcl
1915 	)
1916 {
1917 	return parse_timecode(tcl, &parse->parseio);
1918 }
1919 
1920 
1921 /*--------------------------------------------------
1922  * local input
1923  */
1924 static int
1925 local_input(
1926 	struct recvbuf *rbufp
1927 	)
1928 {
1929 	struct parseunit *parse = (struct parseunit *)((void *)rbufp->recv_srcclock);
1930 	int count;
1931 	unsigned char *s;
1932 	timestamp_t ts;
1933 
1934 	if (!parse->peer)
1935 		return 0;
1936 
1937 	/*
1938 	 * eat all characters, parsing then and feeding complete samples
1939 	 */
1940 	count = rbufp->recv_length;
1941 	s = (unsigned char *)rbufp->recv_buffer;
1942 	ts.fp = rbufp->recv_time;
1943 
1944 	while (count--)
1945 	{
1946 		if (parse_ioread(&parse->parseio, (unsigned int)(*s++), &ts))
1947 		{
1948 			struct recvbuf buf;
1949 
1950 			/*
1951 			 * got something good to eat
1952 			 */
1953 			if (!PARSE_PPS(parse->parseio.parse_dtime.parse_state))
1954 			{
1955 #ifdef TIOCDCDTIMESTAMP
1956 				struct timeval dcd_time;
1957 
1958 				if (ioctl(rbufp->fd, TIOCDCDTIMESTAMP, &dcd_time) != -1)
1959 				{
1960 					l_fp tstmp;
1961 
1962 					TVTOTS(&dcd_time, &tstmp);
1963 					tstmp.l_ui += JAN_1970;
1964 					L_SUB(&ts.fp, &tstmp);
1965 					if (ts.fp.l_ui == 0)
1966 					{
1967 #ifdef DEBUG
1968 						if (debug)
1969 						{
1970 							printf(
1971 							       "parse: local_receive: fd %d DCDTIMESTAMP %s\n",
1972 							       rbufp->fd,
1973 							       lfptoa(&tstmp, 6));
1974 							printf(" sigio %s\n",
1975 							       lfptoa(&ts.fp, 6));
1976 						}
1977 #endif
1978 						parse->parseio.parse_dtime.parse_ptime.fp = tstmp;
1979 						parse->parseio.parse_dtime.parse_state |= PARSEB_PPS|PARSEB_S_PPS;
1980 					}
1981 				}
1982 #else /* TIOCDCDTIMESTAMP */
1983 #if defined(HAVE_STRUCT_PPSCLOCKEV) && (defined(HAVE_CIOGETEV) || defined(HAVE_TIOCGPPSEV))
1984 				if (parse->flags & PARSE_PPSCLOCK)
1985 				{
1986 					l_fp tts;
1987 					struct ppsclockev ev;
1988 
1989 #ifdef HAVE_CIOGETEV
1990 					if (ioctl(parse->generic->io.fd, CIOGETEV, (caddr_t)&ev) == 0)
1991 #endif
1992 #ifdef HAVE_TIOCGPPSEV
1993 					if (ioctl(parse->generic->io.fd, TIOCGPPSEV, (caddr_t)&ev) == 0)
1994 #endif
1995 					{
1996 						if (ev.serial != parse->ppsserial)
1997 						{
1998 							/*
1999 							 * add PPS time stamp if available via ppsclock module
2000 							 * and not supplied already.
2001 							 */
2002 							if (!buftvtots((const char *)&ev.tv, &tts))
2003 							{
2004 								ERR(ERR_BADDATA)
2005 									msyslog(LOG_ERR,"parse: local_receive: timestamp conversion error (buftvtots) (ppsclockev.tv)");
2006 							}
2007 							else
2008 							{
2009 								parse->parseio.parse_dtime.parse_ptime.fp = tts;
2010 								parse->parseio.parse_dtime.parse_state |= PARSEB_PPS|PARSEB_S_PPS;
2011 							}
2012 						}
2013 						parse->ppsserial = ev.serial;
2014 					}
2015 				}
2016 #endif
2017 #endif /* TIOCDCDTIMESTAMP */
2018 			}
2019 			if (count)
2020 			{	/* simulate receive */
2021 				memmove((caddr_t)buf.recv_buffer,
2022 					(caddr_t)&parse->parseio.parse_dtime,
2023 					sizeof(parsetime_t));
2024 				parse_iodone(&parse->parseio);
2025 				buf.recv_length = sizeof(parsetime_t);
2026 				buf.recv_time = rbufp->recv_time;
2027 				buf.srcadr = rbufp->srcadr;
2028 				buf.dstadr = rbufp->dstadr;
2029 				buf.fd     = rbufp->fd;
2030 				buf.next = 0;
2031 				buf.X_from_where = rbufp->X_from_where;
2032 				rbufp->receiver(&buf);
2033 			}
2034 			else
2035 			{
2036 				memmove((caddr_t)rbufp->recv_buffer,
2037 					(caddr_t)&parse->parseio.parse_dtime,
2038 					sizeof(parsetime_t));
2039 				parse_iodone(&parse->parseio);
2040 				rbufp->recv_length = sizeof(parsetime_t);
2041 				return 1; /* got something & in place return */
2042 			}
2043 		}
2044 	}
2045 	return 0;		/* nothing to pass up */
2046 }
2047 
2048 /*--------------------------------------------------
2049  * local receive
2050  */
2051 static void
2052 local_receive(
2053 	struct recvbuf *rbufp
2054 	)
2055 {
2056 	struct parseunit *parse = (struct parseunit *)((void *)rbufp->recv_srcclock);
2057 	parsetime_t parsetime;
2058 
2059 	if (!parse->peer)
2060 	    return;
2061 
2062 	if (rbufp->recv_length != sizeof(parsetime_t))
2063 	{
2064 		ERR(ERR_BADIO)
2065 			msyslog(LOG_ERR,"PARSE receiver #%d: local_receive: bad size (got %d expected %d)",
2066 				CLK_UNIT(parse->peer), rbufp->recv_length, (int)sizeof(parsetime_t));
2067 		parse->generic->baddata++;
2068 		parse_event(parse, CEVNT_BADREPLY);
2069 		return;
2070 	}
2071 	clear_err(parse, ERR_BADIO);
2072 
2073 	memmove((caddr_t)&parsetime,
2074 		(caddr_t)rbufp->recv_buffer,
2075 		sizeof(parsetime_t));
2076 
2077 #ifdef DEBUG
2078 	if (debug > 3)
2079 	  {
2080 	    printf("PARSE receiver #%d: status %06x, state %08x, time %lx.%08lx, stime %lx.%08lx, ptime %lx.%08lx\n",
2081 		   CLK_UNIT(parse->peer),
2082 		   (unsigned int)parsetime.parse_status,
2083 		   (unsigned int)parsetime.parse_state,
2084 		   (long)parsetime.parse_time.tv.tv_sec,
2085 		   (long)parsetime.parse_time.tv.tv_usec,
2086 		   (long)parsetime.parse_stime.tv.tv_sec,
2087 		   (long)parsetime.parse_stime.tv.tv_usec,
2088 		   (long)parsetime.parse_ptime.tv.tv_sec,
2089 		   (long)parsetime.parse_ptime.tv.tv_usec);
2090 	  }
2091 #endif
2092 
2093 	parse_process(parse, &parsetime);
2094 }
2095 
2096 /*--------------------------------------------------
2097  * init_iobinding - find and initialize lower layers
2098  */
2099 static bind_t *
2100 init_iobinding(
2101 	struct parseunit *parse
2102 	)
2103 {
2104   bind_t *b = io_bindings;
2105 
2106 	while (b->bd_description != (char *)0)
2107 	{
2108 		if ((*b->bd_init)(parse))
2109 		{
2110 			return b;
2111 		}
2112 		b++;
2113 	}
2114 	return (bind_t *)0;
2115 }
2116 
2117 /**===========================================================================
2118  ** support routines
2119  **/
2120 
2121 /*--------------------------------------------------
2122  * convert a flag field to a string
2123  */
2124 static char *
2125 parsestate(
2126 	u_long lstate,
2127 	char *buffer
2128 	)
2129 {
2130 	static struct bits
2131 	{
2132 		u_long      bit;
2133 		const char *name;
2134 	} flagstrings[] =
2135 	  {
2136 		  { PARSEB_ANNOUNCE,   "DST SWITCH WARNING" },
2137 		  { PARSEB_POWERUP,    "NOT SYNCHRONIZED" },
2138 		  { PARSEB_NOSYNC,     "TIME CODE NOT CONFIRMED" },
2139 		  { PARSEB_DST,        "DST" },
2140 		  { PARSEB_UTC,        "UTC DISPLAY" },
2141 		  { PARSEB_LEAPADD,    "LEAP ADD WARNING" },
2142 		  { PARSEB_LEAPDEL,    "LEAP DELETE WARNING" },
2143 		  { PARSEB_LEAPSECOND, "LEAP SECOND" },
2144 		  { PARSEB_ALTERNATE,  "ALTERNATE ANTENNA" },
2145 		  { PARSEB_TIMECODE,   "TIME CODE" },
2146 		  { PARSEB_PPS,        "PPS" },
2147 		  { PARSEB_POSITION,   "POSITION" },
2148 		  { 0 }
2149 	  };
2150 
2151 	static struct sbits
2152 	{
2153 		u_long      bit;
2154 		const char *name;
2155 	} sflagstrings[] =
2156 	  {
2157 		  { PARSEB_S_LEAP,     "LEAP INDICATION" },
2158 		  { PARSEB_S_PPS,      "PPS SIGNAL" },
2159 		  { PARSEB_S_ANTENNA,  "ANTENNA" },
2160 		  { PARSEB_S_POSITION, "POSITION" },
2161 		  { 0 }
2162 	  };
2163 	int i;
2164 
2165 	*buffer = '\0';
2166 
2167 	i = 0;
2168 	while (flagstrings[i].bit)
2169 	{
2170 		if (flagstrings[i].bit & lstate)
2171 		{
2172 			if (buffer[0])
2173 			    strcat(buffer, "; ");
2174 			strcat(buffer, flagstrings[i].name);
2175 		}
2176 		i++;
2177 	}
2178 
2179 	if (lstate & (PARSEB_S_LEAP|PARSEB_S_ANTENNA|PARSEB_S_PPS|PARSEB_S_POSITION))
2180 	{
2181       char *s, *t;
2182 
2183 		if (buffer[0])
2184 		    strcat(buffer, "; ");
2185 
2186 		strcat(buffer, "(");
2187 
2188 		t = s = buffer + strlen(buffer);
2189 
2190 		i = 0;
2191 		while (sflagstrings[i].bit)
2192 		{
2193 			if (sflagstrings[i].bit & lstate)
2194 			{
2195 				if (t != s)
2196 				{
2197 					strcpy(t, "; ");
2198 					t += 2;
2199 				}
2200 
2201 				strcpy(t, sflagstrings[i].name);
2202 				t += strlen(t);
2203 			}
2204 			i++;
2205 		}
2206 		strcpy(t, ")");
2207 	}
2208 	return buffer;
2209 }
2210 
2211 /*--------------------------------------------------
2212  * convert a status flag field to a string
2213  */
2214 static char *
2215 parsestatus(
2216 	u_long lstate,
2217 	char *buffer
2218 	)
2219 {
2220 	static struct bits
2221 	{
2222 		u_long      bit;
2223 		const char *name;
2224 	} flagstrings[] =
2225 	  {
2226 		  { CVT_OK,      "CONVERSION SUCCESSFUL" },
2227 		  { CVT_NONE,    "NO CONVERSION" },
2228 		  { CVT_FAIL,    "CONVERSION FAILED" },
2229 		  { CVT_BADFMT,  "ILLEGAL FORMAT" },
2230 		  { CVT_BADDATE, "DATE ILLEGAL" },
2231 		  { CVT_BADTIME, "TIME ILLEGAL" },
2232 		  { CVT_ADDITIONAL, "ADDITIONAL DATA" },
2233 		  { 0 }
2234 	  };
2235 	int i;
2236 
2237 	*buffer = '\0';
2238 
2239 	i = 0;
2240 	while (flagstrings[i].bit)
2241 	{
2242 		if (flagstrings[i].bit & lstate)
2243 		{
2244 			if (buffer[0])
2245 			    strcat(buffer, "; ");
2246 			strcat(buffer, flagstrings[i].name);
2247 		}
2248 		i++;
2249 	}
2250 
2251 	return buffer;
2252 }
2253 
2254 /*--------------------------------------------------
2255  * convert a clock status flag field to a string
2256  */
2257 static const char *
2258 clockstatus(
2259 	u_long lstate
2260 	)
2261 {
2262 	static char buffer[20];
2263 	static struct status
2264 	{
2265 		u_long      value;
2266 		const char *name;
2267 	} flagstrings[] =
2268 	  {
2269 		  { CEVNT_NOMINAL, "NOMINAL" },
2270 		  { CEVNT_TIMEOUT, "NO RESPONSE" },
2271 		  { CEVNT_BADREPLY,"BAD FORMAT" },
2272 		  { CEVNT_FAULT,   "FAULT" },
2273 		  { CEVNT_PROP,    "PROPAGATION DELAY" },
2274 		  { CEVNT_BADDATE, "ILLEGAL DATE" },
2275 		  { CEVNT_BADTIME, "ILLEGAL TIME" },
2276 		  { (unsigned)~0L }
2277 	  };
2278 	int i;
2279 
2280 	i = 0;
2281 	while (flagstrings[i].value != ~0)
2282 	{
2283 		if (flagstrings[i].value == lstate)
2284 		{
2285 			return flagstrings[i].name;
2286 		}
2287 		i++;
2288 	}
2289 
2290 	sprintf(buffer, "unknown #%ld", (u_long)lstate);
2291 
2292 	return buffer;
2293 }
2294 
2295 
2296 /*--------------------------------------------------
2297  * l_mktime - make representation of a relative time
2298  */
2299 static char *
2300 l_mktime(
2301 	u_long delta
2302 	)
2303 {
2304 	u_long tmp, m, s;
2305 	static char buffer[40];
2306 
2307 	buffer[0] = '\0';
2308 
2309 	if ((tmp = delta / (60*60*24)) != 0)
2310 	{
2311 		sprintf(buffer, "%ldd+", (u_long)tmp);
2312 		delta -= tmp * 60*60*24;
2313 	}
2314 
2315 	s = delta % 60;
2316 	delta /= 60;
2317 	m = delta % 60;
2318 	delta /= 60;
2319 
2320 	sprintf(buffer+strlen(buffer), "%02d:%02d:%02d",
2321 		(int)delta, (int)m, (int)s);
2322 
2323 	return buffer;
2324 }
2325 
2326 
2327 /*--------------------------------------------------
2328  * parse_statistics - list summary of clock states
2329  */
2330 static void
2331 parse_statistics(
2332 	struct parseunit *parse
2333 	)
2334 {
2335 	int i;
2336 
2337 	NLOG(NLOG_CLOCKSTATIST) /* conditional if clause for conditional syslog */
2338 		{
2339 			msyslog(LOG_INFO, "PARSE receiver #%d: running time: %s",
2340 				CLK_UNIT(parse->peer),
2341 				l_mktime(current_time - parse->generic->timestarted));
2342 
2343 			msyslog(LOG_INFO, "PARSE receiver #%d: current status: %s",
2344 				CLK_UNIT(parse->peer),
2345 				clockstatus(parse->generic->currentstatus));
2346 
2347 			for (i = 0; i <= CEVNT_MAX; i++)
2348 			{
2349 				u_long s_time;
2350 				u_long percent, d = current_time - parse->generic->timestarted;
2351 
2352 				percent = s_time = PARSE_STATETIME(parse, i);
2353 
2354 				while (((u_long)(~0) / 10000) < percent)
2355 				{
2356 					percent /= 10;
2357 					d       /= 10;
2358 				}
2359 
2360 				if (d)
2361 				    percent = (percent * 10000) / d;
2362 				else
2363 				    percent = 10000;
2364 
2365 				if (s_time)
2366 				    msyslog(LOG_INFO, "PARSE receiver #%d: state %18s: %13s (%3ld.%02ld%%)",
2367 					    CLK_UNIT(parse->peer),
2368 					    clockstatus((unsigned int)i),
2369 					    l_mktime(s_time),
2370 					    percent / 100, percent % 100);
2371 			}
2372 		}
2373 }
2374 
2375 /*--------------------------------------------------
2376  * cparse_statistics - wrapper for statistics call
2377  */
2378 static void
2379 cparse_statistics(
2380 	register struct parseunit *parse
2381 	)
2382 {
2383 	if (parse->laststatistic + PARSESTATISTICS < current_time)
2384 		parse_statistics(parse);
2385 	parse->laststatistic = current_time;
2386 }
2387 
2388 /**===========================================================================
2389  ** ntp interface routines
2390  **/
2391 
2392 /*--------------------------------------------------
2393  * parse_init - initialize internal parse driver data
2394  */
2395 static void
2396 parse_init(void)
2397 {
2398 	memset((caddr_t)parseunits, 0, sizeof parseunits);
2399 }
2400 
2401 
2402 /*--------------------------------------------------
2403  * parse_shutdown - shut down a PARSE clock
2404  */
2405 static void
2406 parse_shutdown(
2407 	int unit,
2408 	struct peer *peer
2409 	)
2410 {
2411 	struct parseunit *parse = (struct parseunit *)peer->procptr->unitptr;
2412 
2413 	if (parse && !parse->peer)
2414 	{
2415 		msyslog(LOG_ERR,
2416 			"PARSE receiver #%d: parse_shutdown: INTERNAL ERROR, unit not in use", unit);
2417 		return;
2418 	}
2419 
2420 	/*
2421 	 * print statistics a last time and
2422 	 * stop statistics machine
2423 	 */
2424 	parse_statistics(parse);
2425 
2426 	if (parse->parse_type->cl_end)
2427 	{
2428 		parse->parse_type->cl_end(parse);
2429 	}
2430 
2431 	if (parse->binding)
2432 	    PARSE_END(parse);
2433 
2434 	/*
2435 	 * Tell the I/O module to turn us off.  We're history.
2436 	 */
2437 	io_closeclock(&parse->generic->io);
2438 
2439 	free_varlist(parse->kv);
2440 
2441 	NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */
2442 		msyslog(LOG_INFO, "PARSE receiver #%d: reference clock \"%s\" removed",
2443 			CLK_UNIT(parse->peer), parse->parse_type->cl_description);
2444 
2445 	parse->peer = (struct peer *)0; /* unused now */
2446 	free(parse);
2447 }
2448 
2449 /*--------------------------------------------------
2450  * parse_start - open the PARSE devices and initialize data for processing
2451  */
2452 static int
2453 parse_start(
2454 	int sysunit,
2455 	struct peer *peer
2456 	)
2457 {
2458 	u_int unit;
2459 	int fd232;
2460 #ifdef HAVE_TERMIOS
2461 	struct termios tio;		/* NEEDED FOR A LONG TIME ! */
2462 #endif
2463 #ifdef HAVE_SYSV_TTYS
2464 	struct termio tio;		/* NEEDED FOR A LONG TIME ! */
2465 #endif
2466 	struct parseunit * parse;
2467 	char parsedev[sizeof(PARSEDEVICE)+20];
2468 	parsectl_t tmp_ctl;
2469 	u_int type;
2470 
2471 	type = CLK_TYPE(peer);
2472 	unit = CLK_UNIT(peer);
2473 
2474 	if ((type == ~0) || (parse_clockinfo[type].cl_description == (char *)0))
2475 	{
2476 		msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: unsupported clock type %d (max %d)",
2477 			unit, CLK_REALTYPE(peer), ncltypes-1);
2478 		return 0;
2479 	}
2480 
2481 	/*
2482 	 * Unit okay, attempt to open the device.
2483 	 */
2484 	(void) sprintf(parsedev, PARSEDEVICE, unit);
2485 
2486 #ifndef O_NOCTTY
2487 #define O_NOCTTY 0
2488 #endif
2489 
2490 	fd232 = open(parsedev, O_RDWR | O_NOCTTY
2491 #ifdef O_NONBLOCK
2492 		     | O_NONBLOCK
2493 #endif
2494 		     , 0777);
2495 
2496 	if (fd232 == -1)
2497 	{
2498 		msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: open of %s failed: %m", unit, parsedev);
2499 		return 0;
2500 	}
2501 
2502 	parse = (struct parseunit *)emalloc(sizeof(struct parseunit));
2503 
2504 	memset((char *)parse, 0, sizeof(struct parseunit));
2505 
2506 	parse->generic = peer->procptr;	 /* link up */
2507 	parse->generic->unitptr = (caddr_t)parse; /* link down */
2508 
2509 	/*
2510 	 * Set up the structures
2511 	 */
2512 	parse->generic->timestarted    = current_time;
2513 	parse->lastchange     = current_time;
2514 
2515 	parse->generic->currentstatus	        = CEVNT_TIMEOUT; /* expect the worst */
2516 
2517 	parse->flags          = 0;
2518 	parse->pollneeddata   = 0;
2519 	parse->laststatistic  = current_time;
2520 	parse->lastformat     = (unsigned short)~0;	/* assume no format known */
2521 	parse->time.parse_status = (unsigned short)~0;	/* be sure to mark initial status change */
2522 	parse->lastmissed     = 0;	/* assume got everything */
2523 	parse->ppsserial      = 0;
2524 	parse->localdata      = (void *)0;
2525 	parse->localstate     = 0;
2526 	parse->kv             = (struct ctl_var *)0;
2527 
2528 	clear_err(parse, ERR_ALL);
2529 
2530 	parse->parse_type     = &parse_clockinfo[type];
2531 
2532 	parse->generic->fudgetime1 = parse->parse_type->cl_basedelay;
2533 
2534 	parse->generic->fudgetime2 = 0.0;
2535 
2536 	parse->generic->clockdesc = parse->parse_type->cl_description;
2537 
2538 	peer->rootdelay       = parse->parse_type->cl_rootdelay;
2539 	peer->sstclktype      = parse->parse_type->cl_type;
2540 	peer->precision       = sys_precision;
2541 
2542 	peer->stratum         = STRATUM_REFCLOCK;
2543 	if (peer->stratum <= 1)
2544 	    memmove((char *)&parse->generic->refid, parse->parse_type->cl_id, 4);
2545 	else
2546 	    parse->generic->refid = htonl(PARSEHSREFID);
2547 
2548 	parse->generic->io.fd = fd232;
2549 
2550 	parse->peer = peer;		/* marks it also as busy */
2551 
2552 	/*
2553 	 * configure terminal line
2554 	 */
2555 	if (TTY_GETATTR(fd232, &tio) == -1)
2556 	{
2557 		msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: tcgetattr(%d, &tio): %m", unit, fd232);
2558 		parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
2559 		return 0;
2560 	}
2561 	else
2562 	{
2563 #ifndef _PC_VDISABLE
2564 		memset((char *)tio.c_cc, 0, sizeof(tio.c_cc));
2565 #else
2566 		int disablec;
2567 		errno = 0;		/* pathconf can deliver -1 without changing errno ! */
2568 
2569 		disablec = fpathconf(parse->generic->io.fd, _PC_VDISABLE);
2570 		if (disablec == -1 && errno)
2571 		{
2572 			msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: fpathconf(fd, _PC_VDISABLE): %m", CLK_UNIT(parse->peer));
2573 			memset((char *)tio.c_cc, 0, sizeof(tio.c_cc)); /* best guess */
2574 		}
2575 		else
2576 		    if (disablec != -1)
2577 			memset((char *)tio.c_cc, disablec, sizeof(tio.c_cc));
2578 #endif
2579 
2580 #if defined (VMIN) || defined(VTIME)
2581 		if ((parse_clockinfo[type].cl_lflag & ICANON) == 0)
2582 		{
2583 #ifdef VMIN
2584 			tio.c_cc[VMIN]   = 1;
2585 #endif
2586 #ifdef VTIME
2587 			tio.c_cc[VTIME]  = 0;
2588 #endif
2589 		}
2590 #endif
2591 
2592 		tio.c_cflag = parse_clockinfo[type].cl_cflag;
2593 		tio.c_iflag = parse_clockinfo[type].cl_iflag;
2594 		tio.c_oflag = parse_clockinfo[type].cl_oflag;
2595 		tio.c_lflag = parse_clockinfo[type].cl_lflag;
2596 
2597 
2598 #ifdef HAVE_TERMIOS
2599 		if ((cfsetospeed(&tio, parse_clockinfo[type].cl_speed) == -1) ||
2600 		    (cfsetispeed(&tio, parse_clockinfo[type].cl_speed) == -1))
2601 		{
2602 			msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: tcset{i,o}speed(&tio, speed): %m", unit);
2603 			parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
2604 			return 0;
2605 		}
2606 #else
2607 		tio.c_cflag     |= parse_clockinfo[type].cl_speed;
2608 #endif
2609 
2610 #if defined(HAVE_TIO_SERIAL_STUFF)		/* Linux hack: define PPS interface */
2611 		{
2612 		  struct serial_struct	ss;
2613 		  if (ioctl(fd232, TIOCGSERIAL, &ss) < 0 ||
2614 		      (
2615 #ifdef ASYNC_LOW_LATENCY
2616 		       ss.flags |= ASYNC_LOW_LATENCY,
2617 #endif
2618 #ifdef ASYNC_PPS_CD_NEG
2619 		       ss.flags |= ASYNC_PPS_CD_NEG,
2620 #endif
2621 		       ioctl(fd232, TIOCSSERIAL, &ss)) < 0) {
2622 		    msyslog(LOG_NOTICE, "refclock_parse: TIOCSSERIAL fd %d, %m", fd232);
2623 		    msyslog(LOG_NOTICE,
2624 			    "refclock_parse: optional PPS processing not available");
2625 		  } else {
2626 		    parse->flags    |= PARSE_PPSCLOCK;
2627 		    msyslog(LOG_INFO,
2628 			    "refclock_parse: PPS detection on");
2629 		  }
2630 		}
2631 #endif
2632 #ifdef HAVE_TIOCSPPS			/* SUN PPS support */
2633 		if (CLK_PPS(parse->peer))
2634 		  {
2635 		    int i = 1;
2636 
2637 		    if (ioctl(fd232, TIOCSPPS, (caddr_t)&i) == 0)
2638 		      {
2639 			parse->flags |= PARSE_PPSCLOCK;
2640 		      }
2641 		  }
2642 #endif
2643 
2644 		if (TTY_SETATTR(fd232, &tio) == -1)
2645 		{
2646 			msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: tcsetattr(%d, &tio): %m", unit, fd232);
2647 			parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
2648 			return 0;
2649 		}
2650 	}
2651 
2652 	/*
2653 	 * Insert in async io device list.
2654 	 */
2655 	parse->generic->io.srcclock = (caddr_t)parse;
2656 	parse->generic->io.datalen = 0;
2657 
2658 	if (!io_addclock(&parse->generic->io))
2659         {
2660 		msyslog(LOG_ERR,
2661 			"PARSE receiver #%d: parse_start: addclock %s fails (ABORT - clock type requires async io)", CLK_UNIT(parse->peer), parsedev);
2662 		parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
2663 		return 0;
2664 	}
2665 
2666 	parse->binding = init_iobinding(parse);
2667 	parse->generic->io.clock_recv = parse->binding->bd_receive; /* pick correct receive routine */
2668 	parse->generic->io.io_input   = parse->binding->bd_io_input; /* pick correct input routine */
2669 
2670 	if (parse->binding == (bind_t *)0)
2671 		{
2672 			msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: io sub system initialisation failed.", CLK_UNIT(parse->peer));
2673 			parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
2674 			return 0;			/* well, ok - special initialisation broke */
2675 		}
2676 
2677 	/*
2678 	 * as we always(?) get 8 bit chars we want to be
2679 	 * sure, that the upper bits are zero for less
2680 	 * than 8 bit I/O - so we pass that information on.
2681 	 * note that there can be only one bit count format
2682 	 * per file descriptor
2683 	 */
2684 
2685 	switch (tio.c_cflag & CSIZE)
2686 	{
2687 	    case CS5:
2688 		tmp_ctl.parsesetcs.parse_cs = PARSE_IO_CS5;
2689 		break;
2690 
2691 	    case CS6:
2692 		tmp_ctl.parsesetcs.parse_cs = PARSE_IO_CS6;
2693 		break;
2694 
2695 	    case CS7:
2696 		tmp_ctl.parsesetcs.parse_cs = PARSE_IO_CS7;
2697 		break;
2698 
2699 	    case CS8:
2700 		tmp_ctl.parsesetcs.parse_cs = PARSE_IO_CS8;
2701 		break;
2702 	}
2703 
2704 	if (!PARSE_SETCS(parse, &tmp_ctl))
2705 	{
2706 		msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: parse_setcs() FAILED.", unit);
2707 		parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
2708 		return 0;			/* well, ok - special initialisation broke */
2709 	}
2710 
2711 	strcpy(tmp_ctl.parseformat.parse_buffer, parse->parse_type->cl_format);
2712 	tmp_ctl.parseformat.parse_count = strlen(tmp_ctl.parseformat.parse_buffer);
2713 
2714 	if (!PARSE_SETFMT(parse, &tmp_ctl))
2715 	{
2716 		msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: parse_setfmt() FAILED.", unit);
2717 		parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
2718 		return 0;			/* well, ok - special initialisation broke */
2719 	}
2720 
2721 	/*
2722 	 * get rid of all IO accumulated so far
2723 	 */
2724 #ifdef HAVE_TERMIOS
2725 	(void) tcflush(parse->generic->io.fd, TCIOFLUSH);
2726 #else
2727 #ifdef TCFLSH
2728 	{
2729 #ifndef TCIOFLUSH
2730 #define TCIOFLUSH 2
2731 #endif
2732 		int flshcmd = TCIOFLUSH;
2733 
2734 		(void) ioctl(parse->generic->io.fd, TCFLSH, (caddr_t)&flshcmd);
2735 	}
2736 #endif
2737 #endif
2738 
2739 	/*
2740 	 * try to do any special initializations
2741 	 */
2742 	if (parse->parse_type->cl_init)
2743 		{
2744 			if (parse->parse_type->cl_init(parse))
2745 				{
2746 					parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
2747 					return 0;		/* well, ok - special initialisation broke */
2748 				}
2749 		}
2750 
2751 	/*
2752 	 * get out Copyright information once
2753 	 */
2754 	if (!notice)
2755         {
2756 		NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */
2757 			msyslog(LOG_INFO, "NTP PARSE support: Copyright (c) 1989-1999, Frank Kardel");
2758 		notice = 1;
2759 	}
2760 
2761 	/*
2762 	 * print out configuration
2763 	 */
2764 	NLOG(NLOG_CLOCKINFO)
2765 		{
2766 			/* conditional if clause for conditional syslog */
2767 			msyslog(LOG_INFO, "PARSE receiver #%d: reference clock \"%s\" (device %s) added",
2768 				CLK_UNIT(parse->peer),
2769 				parse->parse_type->cl_description, parsedev);
2770 
2771 			msyslog(LOG_INFO, "PARSE receiver #%d:  Stratum %d, %sPPS support, trust time %s, precision %d",
2772 				CLK_UNIT(parse->peer),
2773 				parse->peer->stratum, CLK_PPS(parse->peer) ? "" : "no ",
2774 				l_mktime(parse->parse_type->cl_maxunsync), parse->peer->precision);
2775 
2776 			msyslog(LOG_INFO, "PARSE receiver #%d:  rootdelay %.6f s, phaseadjust %.6f s, %s IO handling",
2777 				CLK_UNIT(parse->peer),
2778 				parse->parse_type->cl_rootdelay,
2779 				parse->generic->fudgetime1,
2780 				parse->binding->bd_description);
2781 
2782 			msyslog(LOG_INFO, "PARSE receiver #%d:  Format recognition: %s", CLK_UNIT(parse->peer),
2783 				parse->parse_type->cl_format);
2784 #ifdef PPS
2785                         msyslog(LOG_INFO, "PARSE receiver #%d:  %sPPS ioctl support", CLK_UNIT(parse->peer),
2786 				(parse->flags & PARSE_PPSCLOCK) ? "" : "NO ");
2787 #endif
2788 		}
2789 
2790 	return 1;
2791 }
2792 
2793 /*--------------------------------------------------
2794  * parse_poll - called by the transmit procedure
2795  */
2796 static void
2797 parse_poll(
2798 	int unit,
2799 	struct peer *peer
2800 	)
2801 {
2802 	struct parseunit *parse = (struct parseunit *)peer->procptr->unitptr;
2803 
2804 	if (peer != parse->peer)
2805 	{
2806 		msyslog(LOG_ERR,
2807 			"PARSE receiver #%d: poll: INTERNAL: peer incorrect",
2808 			unit);
2809 		return;
2810 	}
2811 
2812 	/*
2813 	 * Update clock stat counters
2814 	 */
2815 	parse->generic->polls++;
2816 
2817 	if (parse->pollneeddata &&
2818 	    ((current_time - parse->pollneeddata) > (1<<(max(min(parse->peer->hpoll, parse->peer->ppoll), parse->peer->minpoll)))))
2819 	{
2820 		/*
2821 		 * start worrying when exceeding a poll inteval
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 = current_time;
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), 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), 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 					u_char buffer[512];
3732 					u_char *p;
3733 
3734 					get_mbg_antinfo(&bufp, &antinfo);
3735 					sprintf(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(&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(&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(&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 					u_char buffer[512];
3790 					u_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(&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(&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(&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	sendcmd		P((struct txbuf *buf, int c));
4353 void	sendbyte	P((struct txbuf *buf, int b));
4354 void	sendetx		P((struct txbuf *buf, struct parseunit *parse));
4355 void	sendint		P((struct txbuf *buf, int a));
4356 void	sendflt		P((struct txbuf *buf, double a));
4357 
4358 void
4359 sendcmd(
4360 	struct txbuf *buf,
4361 	int c
4362 	)
4363 {
4364 	buf->txt[0] = DLE;
4365 	buf->txt[1] = (u_char)c;
4366 	buf->idx = 2;
4367 }
4368 
4369 void
4370 sendbyte(
4371 	struct txbuf *buf,
4372 	int b
4373 	)
4374 {
4375 	if (b == DLE)
4376 	    buf->txt[buf->idx++] = DLE;
4377 	buf->txt[buf->idx++] = (u_char)b;
4378 }
4379 
4380 void
4381 sendetx(
4382 	struct txbuf *buf,
4383 	struct parseunit *parse
4384 	)
4385 {
4386 	buf->txt[buf->idx++] = DLE;
4387 	buf->txt[buf->idx++] = ETX;
4388 
4389 	if (write(parse->generic->io.fd, buf->txt, (unsigned long)buf->idx) != buf->idx)
4390 	{
4391 		ERR(ERR_BADIO)
4392 			msyslog(LOG_ERR, "PARSE receiver #%d: sendetx: failed to send cmd to clock: %m", CLK_UNIT(parse->peer));
4393 	}
4394 	else
4395 	{
4396 #ifdef DEBUG
4397 	  if (debug > 2)
4398 	  {
4399 		  char buffer[256];
4400 
4401 		  mkreadable(buffer, sizeof(buffer), (char *)buf->txt, (unsigned)buf->idx, 1);
4402 		  printf("PARSE receiver #%d: transmitted message (%d bytes) >%s<\n",
4403 			 CLK_UNIT(parse->peer),
4404 			 buf->idx, buffer);
4405 	  }
4406 #endif
4407 		clear_err(parse, ERR_BADIO);
4408 	}
4409 }
4410 
4411 void
4412 sendint(
4413 	struct txbuf *buf,
4414 	int a
4415 	)
4416 {
4417 	/* send 16bit int, msbyte first */
4418 	sendbyte(buf, (u_char)((a>>8) & 0xff));
4419 	sendbyte(buf, (u_char)(a & 0xff));
4420 }
4421 
4422 void
4423 sendflt(
4424 	struct txbuf *buf,
4425 	double a
4426 	)
4427 {
4428 	int i;
4429 	union uval uval;
4430 
4431 	uval.fv = a;
4432 #ifdef WORDS_BIGENDIAN
4433 	for (i=0; i<=3; i++)
4434 #else
4435 	    for (i=3; i>=0; i--)
4436 #endif
4437 		sendbyte(buf, uval.bd[i]);
4438 }
4439 
4440 #define TRIM_POS_OPT	0x13	/* output position with high precision */
4441 #define TRIM_TIME_OPT	0x03	/* use UTC time stamps, on second */
4442 
4443 /*--------------------------------------------------
4444  * trimble TSIP setup routine
4445  */
4446 static int
4447 trimbletsip_setup(
4448 		  struct parseunit *parse,
4449 		  const char *reason
4450 		  )
4451 {
4452 	u_char buffer[256];
4453 	struct txbuf buf;
4454 
4455 	buf.txt = buffer;
4456 
4457 	sendcmd(&buf, CMD_CVERSION);	/* request software versions */
4458 	sendetx(&buf, parse);
4459 
4460 	sendcmd(&buf, CMD_COPERPARAM);	/* set operating parameters */
4461 	sendbyte(&buf, 4);	/* static */
4462 	sendflt(&buf, 5.0*D2R);	/* elevation angle mask = 10 deg XXX */
4463 	sendflt(&buf, 4.0);	/* s/n ratio mask = 6 XXX */
4464 	sendflt(&buf, 12.0);	/* PDOP mask = 12 */
4465 	sendflt(&buf, 8.0);	/* PDOP switch level = 8 */
4466 	sendetx(&buf, parse);
4467 
4468 	sendcmd(&buf, CMD_CMODESEL);	/* fix mode select */
4469 	sendbyte(&buf, 0);	/* automatic */
4470 	sendetx(&buf, parse);
4471 
4472 	sendcmd(&buf, CMD_CMESSAGE);	/* request system message */
4473 	sendetx(&buf, parse);
4474 
4475 	sendcmd(&buf, CMD_CSUPER);	/* superpacket fix */
4476 	sendbyte(&buf, 0x2);	/* binary mode */
4477 	sendetx(&buf, parse);
4478 
4479 	sendcmd(&buf, CMD_CIOOPTIONS);	/* set I/O options */
4480 	sendbyte(&buf, TRIM_POS_OPT);	/* position output */
4481 	sendbyte(&buf, 0x00);	/* no velocity output */
4482 	sendbyte(&buf, TRIM_TIME_OPT);	/* UTC, compute on seconds */
4483 	sendbyte(&buf, 0x00);	/* no raw measurements */
4484 	sendetx(&buf, parse);
4485 
4486 	sendcmd(&buf, CMD_CUTCPARAM);	/* request UTC correction data */
4487 	sendetx(&buf, parse);
4488 
4489 	NLOG(NLOG_CLOCKINFO)
4490 		ERR(ERR_BADIO)
4491 		msyslog(LOG_ERR, "PARSE receiver #%d: trimbletsip_setup: RECEIVER RE-INITIALIZED (%s)", CLK_UNIT(parse->peer), reason);
4492 
4493 	return 0;
4494 }
4495 
4496 /*--------------------------------------------------
4497  * TRIMBLE TSIP check routine
4498  */
4499 static void
4500 trimble_check(
4501 	      struct peer *peer
4502 	      )
4503 {
4504 	struct parseunit *parse = (struct parseunit *)peer->procptr->unitptr;
4505 	trimble_t *t = parse->localdata;
4506 	u_char buffer[256];
4507 	struct txbuf buf;
4508 	buf.txt = buffer;
4509 
4510 	if (t)
4511 	{
4512 		if (current_time > t->last_msg + TRIMBLETSIP_IDLE_TIME)
4513 			(void)trimbletsip_setup(parse, "message timeout");
4514 	}
4515 	poll_poll(parse->peer);	/* emit query string and re-arm timer */
4516 
4517 	if (t->qtracking)
4518 	{
4519 		u_long oldsats = t->ltrack & ~t->ctrack;
4520 
4521 		t->qtracking = 0;
4522 		t->ltrack = t->ctrack;
4523 
4524 		if (oldsats)
4525 		{
4526 			int i;
4527 
4528 			for (i = 0; oldsats; i++)
4529 				if (oldsats & (1 << i))
4530 					{
4531 						sendcmd(&buf, CMD_CSTATTRACK);
4532 						sendbyte(&buf, i+1);	/* old sat */
4533 						sendetx(&buf, parse);
4534 					}
4535 			oldsats &= ~(1 << i);
4536 		}
4537 
4538 		sendcmd(&buf, CMD_CSTATTRACK);
4539 		sendbyte(&buf, 0x00);	/* current tracking set */
4540 		sendetx(&buf, parse);
4541 	}
4542 }
4543 
4544 /*--------------------------------------------------
4545  * TRIMBLE TSIP end routine
4546  */
4547 static void
4548 trimbletsip_end(
4549 	      struct parseunit *parse
4550 	      )
4551 {	trimble_t *t = parse->localdata;
4552 
4553 	if (t)
4554 	{
4555 		free(t);
4556 		parse->localdata = (void *)0;
4557 	}
4558 	parse->peer->nextaction = 0;
4559 	parse->peer->action = (void (*) P((struct peer *)))0;
4560 }
4561 
4562 /*--------------------------------------------------
4563  * TRIMBLE TSIP init routine
4564  */
4565 static int
4566 trimbletsip_init(
4567 	struct parseunit *parse
4568 	)
4569 {
4570 #if defined(VEOL) || defined(VEOL2)
4571 #ifdef HAVE_TERMIOS
4572 	struct termios tio;		/* NEEDED FOR A LONG TIME ! */
4573 #endif
4574 #ifdef HAVE_SYSV_TTYS
4575 	struct termio tio;		/* NEEDED FOR A LONG TIME ! */
4576 #endif
4577 	/*
4578 	 * allocate local data area
4579 	 */
4580 	if (!parse->localdata)
4581 	{
4582 		trimble_t *t;
4583 
4584 		t = (trimble_t *)(parse->localdata = emalloc(sizeof(trimble_t)));
4585 
4586 		if (t)
4587 		{
4588 			memset((char *)t, 0, sizeof(trimble_t));
4589 			t->last_msg = current_time;
4590 		}
4591 	}
4592 
4593 	parse->peer->action     = trimble_check;
4594 	parse->peer->nextaction = current_time;
4595 
4596 	/*
4597 	 * configure terminal line for ICANON mode with VEOL characters
4598 	 */
4599 	if (TTY_GETATTR(parse->generic->io.fd, &tio) == -1)
4600 	{
4601 		msyslog(LOG_ERR, "PARSE receiver #%d: trimbletsip_init: tcgetattr(%d, &tio): %m", CLK_UNIT(parse->peer), parse->generic->io.fd);
4602 		return 0;
4603 	}
4604 	else
4605 	{
4606 		if ((parse_clockinfo[CLK_TYPE(parse->peer)].cl_lflag & ICANON))
4607 		{
4608 #ifdef VEOL
4609 			tio.c_cc[VEOL]  = ETX;
4610 #endif
4611 #ifdef VEOL2
4612 			tio.c_cc[VEOL2]  = DLE;
4613 #endif
4614 		}
4615 
4616 		if (TTY_SETATTR(parse->generic->io.fd, &tio) == -1)
4617 		{
4618 			msyslog(LOG_ERR, "PARSE receiver #%d: trimbletsip_init: tcsetattr(%d, &tio): %m", CLK_UNIT(parse->peer), parse->generic->io.fd);
4619 			return 0;
4620 		}
4621 	}
4622 #endif
4623 	return trimbletsip_setup(parse, "initial startup");
4624 }
4625 
4626 /*------------------------------------------------------------
4627  * trimbletsip_event - handle Trimble events
4628  * simple evente handler - attempt to re-initialize receiver
4629  */
4630 static void
4631 trimbletsip_event(
4632 	struct parseunit *parse,
4633 	int event
4634 	)
4635 {
4636 	switch (event)
4637 	{
4638 	    case CEVNT_BADREPLY:	/* reset on garbled input */
4639 	    case CEVNT_TIMEOUT:		/* reset on no input */
4640 		    (void)trimbletsip_setup(parse, "event BAD_REPLY/TIMEOUT");
4641 		    break;
4642 
4643 	    default:			/* ignore */
4644 		break;
4645 	}
4646 }
4647 
4648 /*
4649  * getflt, getint convert fields in the incoming data into the
4650  * appropriate type of item
4651  *
4652  * CAVEAT: these routines are currently definitely byte order dependent
4653  * and assume Representation(float) == IEEE754
4654  * These functions MUST be converted to portable versions (especially
4655  * converting the float representation into ntp_fp formats in order
4656  * to avoid floating point operations at all!
4657  */
4658 
4659 static float
4660 getflt(
4661 	u_char *bp
4662 	)
4663 {
4664 	union uval uval;
4665 
4666 #ifdef WORDS_BIGENDIAN
4667 	uval.bd[0] = *bp++;
4668 	uval.bd[1] = *bp++;
4669 	uval.bd[2] = *bp++;
4670 	uval.bd[3] = *bp;
4671 #else  /* ! WORDS_BIGENDIAN */
4672 	uval.bd[3] = *bp++;
4673 	uval.bd[2] = *bp++;
4674 	uval.bd[1] = *bp++;
4675 	uval.bd[0] = *bp;
4676 #endif /* ! WORDS_BIGENDIAN */
4677 	return uval.fv;
4678 }
4679 
4680 static double
4681 getdbl(
4682 	u_char *bp
4683 	)
4684 {
4685 	union uval uval;
4686 
4687 #ifdef WORDS_BIGENDIAN
4688 	uval.bd[0] = *bp++;
4689 	uval.bd[1] = *bp++;
4690 	uval.bd[2] = *bp++;
4691 	uval.bd[3] = *bp++;
4692 	uval.bd[4] = *bp++;
4693 	uval.bd[5] = *bp++;
4694 	uval.bd[6] = *bp++;
4695 	uval.bd[7] = *bp;
4696 #else  /* ! WORDS_BIGENDIAN */
4697 	uval.bd[7] = *bp++;
4698 	uval.bd[6] = *bp++;
4699 	uval.bd[5] = *bp++;
4700 	uval.bd[4] = *bp++;
4701 	uval.bd[3] = *bp++;
4702 	uval.bd[2] = *bp++;
4703 	uval.bd[1] = *bp++;
4704 	uval.bd[0] = *bp;
4705 #endif /* ! WORDS_BIGENDIAN */
4706 	return uval.dv;
4707 }
4708 
4709 static int
4710 getshort(
4711 	 unsigned char *p
4712 	 )
4713 {
4714 	return get_msb_short(&p);
4715 }
4716 
4717 /*--------------------------------------------------
4718  * trimbletsip_message - process trimble messages
4719  */
4720 #define RTOD (180.0 / 3.1415926535898)
4721 #define mb(_X_) (buffer[2+(_X_)]) /* shortcut for buffer access */
4722 
4723 static void
4724 trimbletsip_message(
4725 		    struct parseunit *parse,
4726 		    parsetime_t      *parsetime
4727 		    )
4728 {
4729 	unsigned char *buffer = parsetime->parse_msg;
4730 	unsigned int   size   = parsetime->parse_msglen;
4731 
4732 	if ((size < 4) ||
4733 	    (buffer[0]      != DLE) ||
4734 	    (buffer[size-1] != ETX) ||
4735 	    (buffer[size-2] != DLE))
4736 	{
4737 #ifdef DEBUG
4738 		if (debug > 2) {
4739 			int i;
4740 
4741 			printf("TRIMBLE BAD packet, size %d:\n	", size);
4742 			for (i = 0; i < size; i++) {
4743 				printf ("%2.2x, ", buffer[i]&0xff);
4744 				if (i%16 == 15) printf("\n\t");
4745 			}
4746 			printf("\n");
4747 		}
4748 #endif
4749 		return;
4750 	}
4751 	else
4752 	{
4753 		int var_flag;
4754 		trimble_t *tr = parse->localdata;
4755 		unsigned int cmd = buffer[1];
4756 		char pbuffer[200];
4757 		char *t = pbuffer;
4758 		cmd_info_t *s;
4759 
4760 #ifdef DEBUG
4761 		if (debug > 3) {
4762 			int i;
4763 
4764 			printf("TRIMBLE packet 0x%02x, size %d:\n	", cmd, size);
4765 			for (i = 0; i < size; i++) {
4766 				printf ("%2.2x, ", buffer[i]&0xff);
4767 				if (i%16 == 15) printf("\n\t");
4768 			}
4769 			printf("\n");
4770 		}
4771 #endif
4772 
4773 		if (tr)
4774 			tr->last_msg = current_time;
4775 
4776 		s = trimble_convert(cmd, trimble_rcmds);
4777 
4778 		if (s)
4779 		{
4780 			sprintf(t, "%s=\"", s->varname);
4781 		}
4782 		else
4783 		{
4784 			printf("TRIMBLE unknown command 0x%02x\n", cmd);
4785 			return;
4786 		}
4787 
4788 		var_flag = s->varmode;
4789 
4790 		t += strlen(t);
4791 
4792 		switch(cmd)
4793 		{
4794 		case CMD_RCURTIME:
4795 			sprintf(t, "%f, %d, %f",
4796 				getflt((unsigned char *)&mb(0)), getshort((unsigned char *)&mb(4)),
4797 				getflt((unsigned char *)&mb(6)));
4798 			break;
4799 
4800 		case CMD_RBEST4:
4801 			strcpy(t, "mode: ");
4802 			t += strlen(t);
4803 			switch (mb(0) & 0xF)
4804 			{
4805 			default:
4806 				sprintf(t, "0x%x", mb(0) & 0x7);
4807 				break;
4808 
4809 			case 1:
4810 				strcat(t, "0D");
4811 				break;
4812 
4813 			case 3:
4814 				strcat(t, "2D");
4815 				break;
4816 
4817 			case 4:
4818 				strcat(t, "3D");
4819 				break;
4820 			}
4821 			t += strlen(t);
4822 			if (mb(0) & 0x10)
4823 				strcpy(t, "-MANUAL, ");
4824 			else
4825 				strcpy(t, "-AUTO, ");
4826 			t += strlen(t);
4827 
4828 			sprintf(t, "satellites %02d %02d %02d %02d, PDOP %.2f, HDOP %.2f, VDOP %.2f, TDOP %.2f",
4829 				mb(1), mb(2), mb(3), mb(4),
4830 				getflt((unsigned char *)&mb(5)),
4831 				getflt((unsigned char *)&mb(9)),
4832 				getflt((unsigned char *)&mb(13)),
4833 				getflt((unsigned char *)&mb(17)));
4834 
4835 			break;
4836 
4837 		case CMD_RVERSION:
4838 			sprintf(t, "%d.%d (%d/%d/%d)",
4839 				mb(0)&0xff, mb(1)&0xff, 1900+(mb(4)&0xff), mb(2)&0xff, mb(3)&0xff);
4840 			break;
4841 
4842 		case CMD_RRECVHEALTH:
4843 		{
4844 			static const char *msgs[] =
4845 			{
4846 				"Battery backup failed",
4847 				"Signal processor error",
4848 				"Alignment error, channel or chip 1",
4849 				"Alignment error, channel or chip 2",
4850 				"Antenna feed line fault",
4851 				"Excessive ref freq. error",
4852 				"<BIT 6>",
4853 				"<BIT 7>"
4854 			};
4855 
4856 			int i, bits;
4857 
4858 			switch (mb(0) & 0xFF)
4859 			{
4860 			default:
4861 				sprintf(t, "illegal value 0x%02x", mb(0) & 0xFF);
4862 				break;
4863 			case 0x00:
4864 				strcpy(t, "doing position fixes");
4865 				break;
4866 			case 0x01:
4867 				strcpy(t, "no GPS time yet");
4868 				break;
4869 			case 0x03:
4870 				strcpy(t, "PDOP too high");
4871 				break;
4872 			case 0x08:
4873 				strcpy(t, "no usable satellites");
4874 				break;
4875 			case 0x09:
4876 				strcpy(t, "only ONE usable satellite");
4877 				break;
4878 			case 0x0A:
4879 				strcpy(t, "only TWO usable satellites");
4880 				break;
4881 			case 0x0B:
4882 				strcpy(t, "only THREE usable satellites");
4883 				break;
4884 			case 0x0C:
4885 				strcpy(t, "the chosen satellite is unusable");
4886 				break;
4887 			}
4888 
4889 			t += strlen(t);
4890 
4891 			bits = mb(1) & 0xFF;
4892 
4893 			for (i = 0; i < 8; i++)
4894 				if (bits & (0x1<<i))
4895 				{
4896 					sprintf(t, ", %s", msgs[i]);
4897 					t += strlen(t);
4898 				}
4899 		}
4900 		break;
4901 
4902 		case CMD_RMESSAGE:
4903 			mkreadable(t, (int)(sizeof(pbuffer) - (t - pbuffer)), (char *)&mb(0), (unsigned)(size - 2 - (&mb(0) - buffer)), 0);
4904 			break;
4905 
4906 		case CMD_RMACHSTAT:
4907 		{
4908 			static const char *msgs[] =
4909 			{
4910 				"Synthesizer Fault",
4911 				"Battery Powered Time Clock Fault",
4912 				"A-to-D Converter Fault",
4913 				"The almanac stored in the receiver is not complete and current",
4914 				"<BIT 4>",
4915 				"<BIT 5",
4916 				"<BIT 6>",
4917 				"<BIT 7>"
4918 			};
4919 
4920 			int i, bits;
4921 
4922 			sprintf(t, "machine id 0x%02x", mb(0) & 0xFF);
4923 			t += strlen(t);
4924 
4925 			bits = mb(1) & 0xFF;
4926 
4927 			for (i = 0; i < 8; i++)
4928 				if (bits & (0x1<<i))
4929 				{
4930 					sprintf(t, ", %s", msgs[i]);
4931 					t += strlen(t);
4932 				}
4933 
4934 			sprintf(t, ", Superpackets %ssupported", (mb(2) & 0xFF) ? "" :"un" );
4935 		}
4936 		break;
4937 
4938 		case CMD_ROPERPARAM:
4939 			sprintf(t, "%2x %.1f %.1f %.1f %.1f",
4940 				mb(0), getflt((unsigned char *)&mb(1)), getflt((unsigned char *)&mb(5)),
4941 				getflt((unsigned char *)&mb(9)), getflt((unsigned char *)&mb(13)));
4942 			break;
4943 
4944 		case CMD_RUTCPARAM:
4945 		{
4946 			float t0t = getflt((unsigned char *)&mb(14));
4947 			short wnt = getshort((unsigned char *)&mb(18));
4948 			short dtls = getshort((unsigned char *)&mb(12));
4949 			short wnlsf = getshort((unsigned char *)&mb(20));
4950 			short dn = getshort((unsigned char *)&mb(22));
4951 			short dtlsf = getshort((unsigned char *)&mb(24));
4952 
4953 			if ((int)t0t != 0)
4954 			  {
4955 			    mk_utcinfo(t, wnt, wnlsf, dn, dtls, dtlsf);
4956 			  }
4957 			else
4958 			  {
4959 			    strcpy(t, "<NO UTC DATA>");
4960 			  }
4961 		}
4962 		break;
4963 
4964 		case CMD_RSAT1BIAS:
4965 			sprintf(t, "%.1fm %.2fm/s at %.1fs",
4966 				getflt(&mb(0)), getflt(&mb(4)), getflt(&mb(8)));
4967 			break;
4968 
4969 		case CMD_RIOOPTIONS:
4970 		{
4971 			sprintf(t, "%02x %02x %02x %02x",
4972 				mb(0), mb(1), mb(2), mb(3));
4973 			if (mb(0) != TRIM_POS_OPT ||
4974 			    mb(2) != TRIM_TIME_OPT)
4975 			{
4976 				(void)trimbletsip_setup(parse, "bad io options");
4977 			}
4978 		}
4979 		break;
4980 
4981 		case CMD_RSPOSXYZ:
4982 		{
4983 			double x = getflt((unsigned char *)&mb(0));
4984 			double y = getflt((unsigned char *)&mb(4));
4985 			double z = getflt((unsigned char *)&mb(8));
4986 			double f = getflt((unsigned char *)&mb(12));
4987 
4988 			if (f > 0.0)
4989 			  sprintf(t, "x= %.1fm, y= %.1fm, z= %.1fm, time_of_fix= %f sec",
4990 				  x, y, z,
4991 				  f);
4992 			else
4993 			  return;
4994 		}
4995 		break;
4996 
4997 		case CMD_RSLLAPOS:
4998 		{
4999 			double lat = getflt((unsigned char *)&mb(0));
5000 			double lng = getflt((unsigned char *)&mb(4));
5001 			double f   = getflt((unsigned char *)&mb(12));
5002 
5003 			if (f > 0.0)
5004 			  sprintf(t, "lat %f %c, long %f %c, alt %.2fm",
5005 				  ((lat < 0.0) ? (-lat) : (lat))*RTOD, (lat < 0.0 ? 'S' : 'N'),
5006 				  ((lng < 0.0) ? (-lng) : (lng))*RTOD, (lng < 0.0 ? 'W' : 'E'),
5007 				  getflt((unsigned char *)&mb(8)));
5008 			else
5009 			  return;
5010 		}
5011 		break;
5012 
5013 		case CMD_RDOUBLEXYZ:
5014 		{
5015 			double x = getdbl((unsigned char *)&mb(0));
5016 			double y = getdbl((unsigned char *)&mb(8));
5017 			double z = getdbl((unsigned char *)&mb(16));
5018 			sprintf(t, "x= %.1fm, y= %.1fm, z= %.1fm",
5019 				x, y, z);
5020 		}
5021 		break;
5022 
5023 		case CMD_RDOUBLELLA:
5024 		{
5025 			double lat = getdbl((unsigned char *)&mb(0));
5026 			double lng = getdbl((unsigned char *)&mb(8));
5027 			sprintf(t, "lat %f %c, lon %f %c, alt %.2fm",
5028 				((lat < 0.0) ? (-lat) : (lat))*RTOD, (lat < 0.0 ? 'S' : 'N'),
5029 				((lng < 0.0) ? (-lng) : (lng))*RTOD, (lng < 0.0 ? 'W' : 'E'),
5030 				getdbl((unsigned char *)&mb(16)));
5031 		}
5032 		break;
5033 
5034 		case CMD_RALLINVIEW:
5035 		{
5036 			int i, sats;
5037 
5038 			strcpy(t, "mode: ");
5039 			t += strlen(t);
5040 			switch (mb(0) & 0x7)
5041 			{
5042 			default:
5043 				sprintf(t, "0x%x", mb(0) & 0x7);
5044 				break;
5045 
5046 			case 3:
5047 				strcat(t, "2D");
5048 				break;
5049 
5050 			case 4:
5051 				strcat(t, "3D");
5052 				break;
5053 			}
5054 			t += strlen(t);
5055 			if (mb(0) & 0x8)
5056 				strcpy(t, "-MANUAL, ");
5057 			else
5058 				strcpy(t, "-AUTO, ");
5059 			t += strlen(t);
5060 
5061 			sats = (mb(0)>>4) & 0xF;
5062 
5063 			sprintf(t, "PDOP %.2f, HDOP %.2f, VDOP %.2f, TDOP %.2f, %d satellite%s in view: ",
5064 				getflt((unsigned char *)&mb(1)),
5065 				getflt((unsigned char *)&mb(5)),
5066 				getflt((unsigned char *)&mb(9)),
5067 				getflt((unsigned char *)&mb(13)),
5068 				sats, (sats == 1) ? "" : "s");
5069 			t += strlen(t);
5070 
5071 			for (i=0; i < sats; i++)
5072 			{
5073 				sprintf(t, "%s%02d", i ? ", " : "", mb(17+i));
5074 				t += strlen(t);
5075 				if (tr)
5076 					tr->ctrack |= (1 << (mb(17+i)-1));
5077 			}
5078 
5079 			if (tr)
5080                         { /* mark for tracking status query */
5081 				tr->qtracking = 1;
5082 			}
5083 		}
5084 		break;
5085 
5086 		case CMD_RSTATTRACK:
5087 		{
5088 			sprintf(t-2, "[%02d]=\"", mb(0)); /* add index to var name */
5089 			t += strlen(t);
5090 
5091 			if (getflt((unsigned char *)&mb(4)) < 0.0)
5092 			{
5093 				strcpy(t, "<NO MEASUREMENTS>");
5094 				var_flag &= ~DEF;
5095 			}
5096 			else
5097 			{
5098 				sprintf(t, "ch=%d, acq=%s, eph=%d, signal_level= %5.2f, elevation= %5.2f, azimuth= %6.2f",
5099 					(mb(1) & 0xFF)>>3,
5100 					mb(2) ? ((mb(2) == 1) ? "ACQ" : "SRCH") : "NEVER",
5101 					mb(3),
5102 					getflt((unsigned char *)&mb(4)),
5103 					getflt((unsigned char *)&mb(12)) * RTOD,
5104 					getflt((unsigned char *)&mb(16)) * RTOD);
5105 				t += strlen(t);
5106 				if (mb(20))
5107 				{
5108 					var_flag &= ~DEF;
5109 					strcpy(t, ", OLD");
5110 				}
5111 				t += strlen(t);
5112 				if (mb(22))
5113 				{
5114 					if (mb(22) == 1)
5115 						strcpy(t, ", BAD PARITY");
5116 					else
5117 						if (mb(22) == 2)
5118 							strcpy(t, ", BAD EPH HEALTH");
5119 				}
5120 				t += strlen(t);
5121 				if (mb(23))
5122 					strcpy(t, ", collecting data");
5123 			}
5124 		}
5125 		break;
5126 
5127 		default:
5128 			strcpy(t, "<UNDECODED>");
5129 			break;
5130 		}
5131 		strcat(t,"\"");
5132 		set_var(&parse->kv, pbuffer, sizeof(pbuffer), var_flag);
5133 	}
5134 }
5135 
5136 
5137 /**============================================================
5138  ** RAWDCF support
5139  **/
5140 
5141 /*--------------------------------------------------
5142  * rawdcf_init_1 - set up modem lines for RAWDCF receivers
5143  * SET DTR line
5144  */
5145 #if defined(TIOCMSET) && (defined(TIOCM_DTR) || defined(CIOCM_DTR))
5146 static int
5147 rawdcf_init_1(
5148 	struct parseunit *parse
5149 	)
5150 {
5151 	/* fixed 2000 for using with Linux by Wolfram Pienkoss <wp@bszh.de> */
5152 	/*
5153 	 * You can use the RS232 to supply the power for a DCF77 receiver.
5154 	 * Here a voltage between the DTR and the RTS line is used. Unfortunately
5155 	 * the name has changed from CIOCM_DTR to TIOCM_DTR recently.
5156 	 */
5157 	int sl232;
5158 
5159 	if (ioctl(parse->generic->io.fd, TIOCMGET, (caddr_t)&sl232) == -1)
5160 	{
5161 		msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_1: WARNING: ioctl(fd, TIOCMGET, [C|T]IOCM_DTR): %m", CLK_UNIT(parse->peer));
5162 		return 0;
5163 	}
5164 
5165 #ifdef TIOCM_DTR
5166 	sl232 = (sl232 & ~TIOCM_RTS) | TIOCM_DTR;	/* turn on DTR, clear RTS for power supply */
5167 #else
5168 	sl232 = (sl232 & ~CIOCM_RTS) | CIOCM_DTR;	/* turn on DTR, clear RTS for power supply */
5169 #endif
5170 
5171 	if (ioctl(parse->generic->io.fd, TIOCMSET, (caddr_t)&sl232) == -1)
5172 	{
5173 		msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_1: WARNING: ioctl(fd, TIOCMSET, [C|T]IOCM_DTR): %m", CLK_UNIT(parse->peer));
5174 	}
5175 	return 0;
5176 }
5177 #else
5178 static int
5179 rawdcfdtr_init_1(
5180 	struct parseunit *parse
5181 	)
5182 {
5183 	msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_1: WARNING: OS interface incapable of setting DTR to power DCF modules", CLK_UNIT(parse->peer));
5184 	return 0;
5185 }
5186 #endif  /* DTR initialisation type */
5187 
5188 /*--------------------------------------------------
5189  * rawdcf_init_2 - set up modem lines for RAWDCF receivers
5190  * CLR DTR line, SET RTS line
5191  */
5192 #if defined(TIOCMSET) &&  (defined(TIOCM_RTS) || defined(CIOCM_RTS))
5193 static int
5194 rawdcf_init_2(
5195 	struct parseunit *parse
5196 	)
5197 {
5198 	/* fixed 2000 for using with Linux by Wolfram Pienkoss <wp@bszh.de> */
5199 	/*
5200 	 * You can use the RS232 to supply the power for a DCF77 receiver.
5201 	 * Here a voltage between the DTR and the RTS line is used. Unfortunately
5202 	 * the name has changed from CIOCM_DTR to TIOCM_DTR recently.
5203 	 */
5204 	int sl232;
5205 
5206 	if (ioctl(parse->generic->io.fd, TIOCMGET, (caddr_t)&sl232) == -1)
5207 	{
5208 		msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_2: WARNING: ioctl(fd, TIOCMGET, [C|T]IOCM_RTS): %m", CLK_UNIT(parse->peer));
5209 		return 0;
5210 	}
5211 
5212 #ifdef TIOCM_RTS
5213 	sl232 = (sl232 & ~TIOCM_DTR) | TIOCM_RTS;	/* turn on RTS, clear DTR for power supply */
5214 #else
5215 	sl232 = (sl232 & ~CIOCM_DTR) | CIOCM_RTS;	/* turn on RTS, clear DTR for power supply */
5216 #endif
5217 
5218 	if (ioctl(parse->generic->io.fd, TIOCMSET, (caddr_t)&sl232) == -1)
5219 	{
5220 		msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_2: WARNING: ioctl(fd, TIOCMSET, [C|T]IOCM_RTS): %m", CLK_UNIT(parse->peer));
5221 	}
5222 	return 0;
5223 }
5224 #else
5225 static int
5226 rawdcf_init_2(
5227 	struct parseunit *parse
5228 	)
5229 {
5230 	msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_2: WARNING: OS interface incapable of setting RTS to power DCF modules", CLK_UNIT(parse->peer));
5231 	return 0;
5232 }
5233 #endif  /* DTR initialisation type */
5234 
5235 #else	/* defined(REFCLOCK) && defined(PARSE) */
5236 int refclock_parse_bs;
5237 #endif	/* defined(REFCLOCK) && defined(PARSE) */
5238 
5239 /*
5240  * History:
5241  *
5242  * refclock_parse.c,v
5243  * Revision 4.36  1999/11/28 17:18:20  kardel
5244  * disabled burst mode
5245  *
5246  * Revision 4.35  1999/11/28 09:14:14  kardel
5247  * RECON_4_0_98F
5248  *
5249  * Revision 4.34  1999/05/14 06:08:05  kardel
5250  * store current_time in a suitable container (u_long)
5251  *
5252  * Revision 4.33  1999/05/13 21:48:38  kardel
5253  * double the no response timeout interval
5254  *
5255  * Revision 4.32  1999/05/13 20:09:13  kardel
5256  * complain only about missing polls after a full poll interval
5257  *
5258  * Revision 4.31  1999/05/13 19:59:32  kardel
5259  * add clock type 16 for RTS set DTR clr in RAWDCF
5260  *
5261  * Revision 4.30  1999/02/28 20:36:43  kardel
5262  * fixed printf fmt
5263  *
5264  * Revision 4.29  1999/02/28 19:58:23  kardel
5265  * updated copyright information
5266  *
5267  * Revision 4.28  1999/02/28 19:01:50  kardel
5268  * improved debug out on sent Meinberg messages
5269  *
5270  * Revision 4.27  1999/02/28 18:05:55  kardel
5271  * no linux/ppsclock.h stuff
5272  *
5273  * Revision 4.26  1999/02/28 15:27:27  kardel
5274  * wharton clock integration
5275  *
5276  * Revision 4.25  1999/02/28 14:04:46  kardel
5277  * added missing double quotes to UTC information string
5278  *
5279  * Revision 4.24  1999/02/28 12:06:50  kardel
5280  * (parse_control): using gmprettydate instead of prettydate()
5281  * (mk_utcinfo): new function for formatting GPS derived UTC information
5282  * (gps16x_message): changed to use mk_utcinfo()
5283  * (trimbletsip_message): changed to use mk_utcinfo()
5284  * ignoring position information in unsynchronized mode
5285  * (parse_start): augument linux support for optional ASYNC_LOW_LATENCY
5286  *
5287  * Revision 4.23  1999/02/23 19:47:53  kardel
5288  * fixed #endifs
5289  * (stream_receive): fixed formats
5290  *
5291  * Revision 4.22  1999/02/22 06:21:02  kardel
5292  * use new autoconfig symbols
5293  *
5294  * Revision 4.21  1999/02/21 12:18:13  kardel
5295  * 4.91f reconcilation
5296  *
5297  * Revision 4.20  1999/02/21 10:53:36  kardel
5298  * initial Linux PPSkit version
5299  *
5300  * Revision 4.19  1999/02/07 09:10:45  kardel
5301  * clarify STREAMS mitigation rules in comment
5302  *
5303  * Revision 4.18  1998/12/20 23:45:34  kardel
5304  * fix types and warnings
5305  *
5306  * Revision 4.17  1998/11/15 21:24:51  kardel
5307  * cannot access mbg_ routines when CLOCK_MEINBERG
5308  * is not defined
5309  *
5310  * Revision 4.16  1998/11/15 20:28:17  kardel
5311  * Release 4.0.73e13 reconcilation
5312  *
5313  * Revision 4.15  1998/08/22 21:56:08  kardel
5314  * fixed IO handling for non-STREAM IO
5315  *
5316  * Revision 4.14  1998/08/16 19:00:48  kardel
5317  * (gps16x_message): reduced UTC parameter information (dropped A0,A1)
5318  * made uval a local variable (killed one of the last globals)
5319  * (sendetx): added logging of messages when in debug mode
5320  * (trimble_check): added periodic checks to facilitate re-initialization
5321  * (trimbletsip_init): made use of EOL character if in non-kernel operation
5322  * (trimbletsip_message): extended message interpretation
5323  * (getdbl): fixed data conversion
5324  *
5325  * Revision 4.13  1998/08/09 22:29:13  kardel
5326  * Trimble TSIP support
5327  *
5328  * Revision 4.12  1998/07/11 10:05:34  kardel
5329  * Release 4.0.73d reconcilation
5330  *
5331  * Revision 4.11  1998/06/14 21:09:42  kardel
5332  * Sun acc cleanup
5333  *
5334  * Revision 4.10  1998/06/13 12:36:45  kardel
5335  * signed/unsigned, name clashes
5336  *
5337  * Revision 4.9  1998/06/12 15:30:00  kardel
5338  * prototype fixes
5339  *
5340  * Revision 4.8  1998/06/12 11:19:42  kardel
5341  * added direct input processing routine for refclocks in
5342  * order to avaiod that single character io gobbles up all
5343  * receive buffers and drops input data. (Problem started
5344  * with fast machines so a character a buffer was possible
5345  * one of the few cases where faster machines break existing
5346  * allocation algorithms)
5347  *
5348  * Revision 4.7  1998/06/06 18:35:20  kardel
5349  * (parse_start): added BURST mode initialisation
5350  *
5351  * Revision 4.6  1998/05/27 06:12:46  kardel
5352  * RAWDCF_BASEDELAY default added
5353  * old comment removed
5354  * casts for ioctl()
5355  *
5356  * Revision 4.5  1998/05/25 22:05:09  kardel
5357  * RAWDCF_SETDTR option removed
5358  * clock type 14 attempts to set DTR for
5359  * power supply of RAWDCF receivers
5360  *
5361  * Revision 4.4  1998/05/24 16:20:47  kardel
5362  * updated comments referencing Meinberg clocks
5363  * added RAWDCF clock with DTR set option as type 14
5364  *
5365  * Revision 4.3  1998/05/24 10:48:33  kardel
5366  * calibrated CONRAD RAWDCF default fudge factor
5367  *
5368  * Revision 4.2  1998/05/24 09:59:35  kardel
5369  * corrected version information (ntpq support)
5370  *
5371  * Revision 4.1  1998/05/24 09:52:31  kardel
5372  * use fixed format only (new IO model)
5373  * output debug to stdout instead of msyslog()
5374  * don't include >"< in ASCII output in order not to confuse
5375  * ntpq parsing
5376  *
5377  * Revision 4.0  1998/04/10 19:52:11  kardel
5378  * Start 4.0 release version numbering
5379  *
5380  * Revision 1.2  1998/04/10 19:28:04  kardel
5381  * initial NTP VERSION 4 integration of PARSE with GPS166 binary support
5382  * derived from 3.105.1.2 from V3 tree
5383  *
5384  * Revision information 3.1 - 3.105 from log deleted 1998/04/10 kardel
5385  *
5386  */
5387