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