2 * /src/NTP/REPOSITORY/ntp4-dev/ntpd/refclock_parse.c,v 4.81 2009/05/01 10:15:29 kardel RELEASE_20090105_A
4 * refclock_parse.c,v 4.81 2009/05/01 10:15:29 kardel RELEASE_20090105_A
6 * generic reference clock driver for several DCF/GPS/MSF/... receivers
9 * On systems that support PPSAPI (RFC2783) PPSAPI is the
10 * preferred interface.
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.
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
21 * Redistribution and use in source and binary forms, with or without
22 * modification, are permitted provided that the following conditions
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.
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
51 #include "ntp_types.h"
53 #if defined(REFCLOCK) && defined(CLOCK_PARSE)
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)
63 * - Schmid clock (DCF)
64 * - Conrad DCF77 receiver module (DCF)
65 * - FAU DCF77 NTP receiver (TimeBrick) (DCF)
66 * - WHARTON 400A Series clock (DCF)
68 * - Meinberg GPS receivers (GPS)
69 * - Trimble (TSIP and TAIP protocol) (GPS)
71 * - RCC8000 MSF Receiver (MSF)
72 * - VARITEXT clock (MSF)
76 * Meinberg receivers are usually connected via a
77 * 9600/7E1 or 19200/8N1 serial line.
79 * The Meinberg GPS receivers also have a special NTP time stamp
80 * format. The firmware release is Uni-Erlangen.
82 * Meinberg generic receiver setup:
83 * output time code every second
86 * Meinberg GPS receiver setup:
87 * output time code every second
90 * This software supports the standard data formats used
91 * in Meinberg receivers.
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.
98 * Meinberg can be reached via: http://www.meinberg.de/
102 #include "ntp_refclock.h"
103 #include "timevalops.h" /* includes <sys/time.h> */
104 #include "ntp_control.h"
105 #include "ntp_string.h"
109 #ifndef TM_IN_SYS_TIME
117 #if !defined(STREAM) && !defined(HAVE_SYSV_TTYS) && !defined(HAVE_BSD_TTYS) && !defined(HAVE_TERMIOS)
118 # include "Bletch: Define one of {STREAM,HAVE_SYSV_TTYS,HAVE_TERMIOS}"
122 # include <sys/stream.h>
123 # include <sys/stropts.h>
127 # include <termios.h>
128 # define TTY_GETATTR(_FD_, _ARG_) tcgetattr((_FD_), (_ARG_))
129 # define TTY_SETATTR(_FD_, _ARG_) tcsetattr((_FD_), TCSANOW, (_ARG_))
130 # undef HAVE_SYSV_TTYS
133 #ifdef HAVE_SYSV_TTYS
134 # define TTY_GETATTR(_FD_, _ARG_) ioctl((_FD_), TCGETA, (_ARG_))
135 # define TTY_SETATTR(_FD_, _ARG_) ioctl((_FD_), TCSETAW, (_ARG_))
139 /* #error CURRENTLY NO BSD TTY SUPPORT */
140 # include "Bletch: BSD TTY not currently supported"
143 #ifdef HAVE_SYS_IOCTL_H
144 # include <sys/ioctl.h>
148 # include "ppsapi_timepps.h"
149 # include "refclock_atom.h"
153 # ifdef HAVE_SYS_PPSCLOCK_H
154 # include <sys/ppsclock.h>
156 # ifdef HAVE_TIO_SERIAL_STUFF
157 # include <linux/serial.h>
161 # define BUFFER_SIZE(_BUF, _PTR) ((int)((_BUF) + sizeof(_BUF) - (_PTR)))
162 # define BUFFER_SIZES(_BUF, _PTR, _SZ) ((int)((_BUF) + (_SZ) - (_PTR)))
165 * document type of PPS interfacing - copy of ifdef mechanism in local_input()
170 #define PPS_METHOD "PPS API"
172 #ifdef TIOCDCDTIMESTAMP
173 #define PPS_METHOD "TIOCDCDTIMESTAMP"
174 #else /* TIOCDCDTIMESTAMP */
175 #if defined(HAVE_STRUCT_PPSCLOCKEV) && (defined(HAVE_CIOGETEV) || defined(HAVE_TIOCGPPSEV))
177 #define PPS_METHOD "CIOGETEV"
179 #ifdef HAVE_TIOCGPPSEV
180 #define PPS_METHOD "TIOCGPPSEV"
183 #endif /* TIOCDCDTIMESTAMP */
184 #endif /* HAVE_PPSAPI */
187 * COND_DEF can be conditionally defined as DEF or 0. If defined as DEF
188 * then some more parse-specific variables are flagged to be printed with
189 * "ntpq -c cv <assid>". This can be lengthy, so by default COND_DEF
190 * should be defined as 0.
193 # define COND_DEF DEF // enable this for testing
195 # define COND_DEF 0 // enable this by default
199 #include "ntp_stdlib.h"
202 #include "mbg_gps166.h"
206 #include "ieee754io.h"
207 #include "recvbuff.h"
209 static char rcsid[] = "refclock_parse.c,v 4.81 2009/05/01 10:15:29 kardel RELEASE_20090105_A+POWERUPTRUST";
211 /**===========================================================================
212 ** external interface to ntp mechanism
215 static int parse_start (int, struct peer *);
216 static void parse_shutdown (int, struct peer *);
217 static void parse_poll (int, struct peer *);
218 static void parse_control (int, const struct refclockstat *, struct refclockstat *, struct peer *);
220 struct refclock refclock_parse = {
233 #define MAXUNITS 4 /* maximum number of "PARSE" units permitted */
234 #define PARSEDEVICE "/dev/refclock-%d" /* device to open %d is unit number */
235 #define PARSEPPSDEVICE "/dev/refclockpps-%d" /* optional pps device to open %d is unit number */
238 #define ABS(_X_) (((_X_) < 0) ? -(_X_) : (_X_))
240 #define PARSE_HARDPPS_DISABLE 0
241 #define PARSE_HARDPPS_ENABLE 1
243 /**===========================================================================
244 ** function vector for dynamically binding io handling mechanism
247 struct parseunit; /* to keep inquiring minds happy */
251 const char *bd_description; /* name of type of binding */
252 int (*bd_init) (struct parseunit *); /* initialize */
253 void (*bd_end) (struct parseunit *); /* end */
254 int (*bd_setcs) (struct parseunit *, parsectl_t *); /* set character size */
255 int (*bd_disable) (struct parseunit *); /* disable */
256 int (*bd_enable) (struct parseunit *); /* enable */
257 int (*bd_getfmt) (struct parseunit *, parsectl_t *); /* get format */
258 int (*bd_setfmt) (struct parseunit *, parsectl_t *); /* setfmt */
259 int (*bd_timecode) (struct parseunit *, parsectl_t *); /* get time code */
260 void (*bd_receive) (struct recvbuf *); /* receive operation */
261 int (*bd_io_input) (struct recvbuf *); /* input operation */
264 #define PARSE_END(_X_) (*(_X_)->binding->bd_end)(_X_)
265 #define PARSE_SETCS(_X_, _CS_) (*(_X_)->binding->bd_setcs)(_X_, _CS_)
266 #define PARSE_ENABLE(_X_) (*(_X_)->binding->bd_enable)(_X_)
267 #define PARSE_DISABLE(_X_) (*(_X_)->binding->bd_disable)(_X_)
268 #define PARSE_GETFMT(_X_, _DCT_) (*(_X_)->binding->bd_getfmt)(_X_, _DCT_)
269 #define PARSE_SETFMT(_X_, _DCT_) (*(_X_)->binding->bd_setfmt)(_X_, _DCT_)
270 #define PARSE_GETTIMECODE(_X_, _DCT_) (*(_X_)->binding->bd_timecode)(_X_, _DCT_)
273 * special handling flags
275 #define PARSE_F_PPSONSECOND 0x00000001 /* PPS pulses are on second */
276 #define PARSE_F_POWERUPTRUST 0x00000100 /* POWERUP state ist trusted for */
277 /* trusttime after SYNC was seen */
278 /**===========================================================================
279 ** error message regression handling
281 ** there are quite a few errors that can occur in rapid succession such as
282 ** noisy input data or no data at all. in order to reduce the amount of
283 ** syslog messages in such case, we are using a backoff algorithm. We limit
284 ** the number of error messages of a certain class to 1 per time unit. if a
285 ** configurable number of messages is displayed that way, we move on to the
286 ** next time unit / count for that class. a count of messages that have been
287 ** suppressed is held and displayed whenever a corresponding message is
288 ** displayed. the time units for a message class will also be displayed.
289 ** whenever an error condition clears we reset the error message state,
290 ** thus we would still generate much output on pathological conditions
291 ** where the system oscillates between OK and NOT OK states. coping
292 ** with that condition is currently considered too complicated.
295 #define ERR_ALL (unsigned)~0 /* "all" errors */
296 #define ERR_BADDATA (unsigned)0 /* unusable input data/conversion errors */
297 #define ERR_NODATA (unsigned)1 /* no input data */
298 #define ERR_BADIO (unsigned)2 /* read/write/select errors */
299 #define ERR_BADSTATUS (unsigned)3 /* unsync states */
300 #define ERR_BADEVENT (unsigned)4 /* non nominal events */
301 #define ERR_INTERNAL (unsigned)5 /* internal error */
302 #define ERR_CNT (unsigned)(ERR_INTERNAL+1)
304 #define ERR(_X_) if (list_err(parse, (_X_)))
306 struct errorregression
308 u_long err_count; /* number of repititions per class */
309 u_long err_delay; /* minimum delay between messages */
312 static struct errorregression
313 err_baddata[] = /* error messages for bad input data */
315 { 1, 0 }, /* output first message immediately */
316 { 5, 60 }, /* output next five messages in 60 second intervals */
317 { 3, 3600 }, /* output next 3 messages in hour intervals */
318 { 0, 12*3600 } /* repeat messages only every 12 hours */
321 static struct errorregression
322 err_nodata[] = /* error messages for missing input data */
324 { 1, 0 }, /* output first message immediately */
325 { 5, 60 }, /* output next five messages in 60 second intervals */
326 { 3, 3600 }, /* output next 3 messages in hour intervals */
327 { 0, 12*3600 } /* repeat messages only every 12 hours */
330 static struct errorregression
331 err_badstatus[] = /* unsynchronized state messages */
333 { 1, 0 }, /* output first message immediately */
334 { 5, 60 }, /* output next five messages in 60 second intervals */
335 { 3, 3600 }, /* output next 3 messages in hour intervals */
336 { 0, 12*3600 } /* repeat messages only every 12 hours */
339 static struct errorregression
340 err_badio[] = /* io failures (bad reads, selects, ...) */
342 { 1, 0 }, /* output first message immediately */
343 { 5, 60 }, /* output next five messages in 60 second intervals */
344 { 5, 3600 }, /* output next 3 messages in hour intervals */
345 { 0, 12*3600 } /* repeat messages only every 12 hours */
348 static struct errorregression
349 err_badevent[] = /* non nominal events */
351 { 20, 0 }, /* output first message immediately */
352 { 6, 60 }, /* output next five messages in 60 second intervals */
353 { 5, 3600 }, /* output next 3 messages in hour intervals */
354 { 0, 12*3600 } /* repeat messages only every 12 hours */
357 static struct errorregression
358 err_internal[] = /* really bad things - basically coding/OS errors */
360 { 0, 0 }, /* output all messages immediately */
363 static struct errorregression *
376 u_long err_started; /* begin time (ntp) of error condition */
377 u_long err_last; /* last time (ntp) error occurred */
378 u_long err_cnt; /* number of error repititions */
379 u_long err_suppressed; /* number of suppressed messages */
380 struct errorregression *err_stage; /* current error stage */
383 /**===========================================================================
384 ** refclock instance data
392 struct peer *peer; /* backlink to peer structure - refclock inactive if 0 */
393 struct refclockproc *generic; /* backlink to refclockproc structure */
398 bind_t *binding; /* io handling binding */
403 parse_t parseio; /* io handling structure (user level parsing) */
406 * type specific parameters
408 struct parse_clockinfo *parse_type; /* link to clock description */
411 * clock state handling/reporting
413 u_char flags; /* flags (leap_control) */
414 u_long lastchange; /* time (ntp) when last state change accured */
415 u_long statetime[CEVNT_MAX+1]; /* accumulated time of clock states */
416 u_long pollneeddata; /* current_time(!=0) for receive sample expected in PPS mode */
417 u_short lastformat; /* last format used */
418 u_long lastsync; /* time (ntp) when clock was last seen fully synchronized */
419 u_long maxunsync; /* max time in seconds a receiver is trusted after loosing synchronisation */
420 double ppsphaseadjust; /* phase adjustment of PPS time stamp */
421 u_long lastmissed; /* time (ntp) when poll didn't get data (powerup heuristic) */
422 u_long ppsserial; /* magic cookie for ppsclock serials (avoids stale ppsclock data) */
423 int ppsfd; /* fd to ise for PPS io */
425 int hardppsstate; /* current hard pps state */
426 struct refclock_atom atom; /* PPSAPI structure */
428 parsetime_t timedata; /* last (parse module) data */
429 void *localdata; /* optional local, receiver-specific data */
430 unsigned long localstate; /* private local state */
431 struct errorinfo errors[ERR_CNT]; /* error state table for suppressing excessive error messages */
432 struct ctl_var *kv; /* additional pseudo variables */
433 u_long laststatistic; /* time when staticstics where output */
437 /**===========================================================================
438 ** Clockinfo section all parameter for specific clock types
439 ** includes NTP parameters, TTY parameters and IO handling parameters
442 static void poll_dpoll (struct parseunit *);
443 static void poll_poll (struct peer *);
444 static int poll_init (struct parseunit *);
446 typedef struct poll_info
448 u_long rate; /* poll rate - once every "rate" seconds - 0 off */
449 const char *string; /* string to send for polling */
450 u_long count; /* number of characters in string */
453 #define NO_CL_FLAGS 0
460 #define NO_PPSDELAY 0
462 #define DCF_ID "DCF" /* generic DCF */
463 #define DCF_A_ID "DCFa" /* AM demodulation */
464 #define DCF_P_ID "DCFp" /* psuedo random phase shift */
465 #define GPS_ID "GPS" /* GPS receiver */
467 #define NOCLOCK_ROOTDELAY 0.0
468 #define NOCLOCK_BASEDELAY 0.0
469 #define NOCLOCK_DESCRIPTION 0
470 #define NOCLOCK_MAXUNSYNC 0
471 #define NOCLOCK_CFLAG 0
472 #define NOCLOCK_IFLAG 0
473 #define NOCLOCK_OFLAG 0
474 #define NOCLOCK_LFLAG 0
475 #define NOCLOCK_ID "TILT"
476 #define NOCLOCK_POLL NO_POLL
477 #define NOCLOCK_INIT NO_INIT
478 #define NOCLOCK_END NO_END
479 #define NOCLOCK_DATA NO_LCLDATA
480 #define NOCLOCK_FORMAT ""
481 #define NOCLOCK_TYPE CTL_SST_TS_UNSPEC
482 #define NOCLOCK_SAMPLES 0
483 #define NOCLOCK_KEEP 0
485 #define DCF_TYPE CTL_SST_TS_LF
486 #define GPS_TYPE CTL_SST_TS_UHF
489 * receiver specific constants
491 #define MBG_SPEED (B9600)
492 #define MBG_CFLAG (CS7|PARENB|CREAD|CLOCAL|HUPCL|CSTOPB)
493 #define MBG_IFLAG (IGNBRK|IGNPAR|ISTRIP)
496 #define MBG_FLAGS PARSE_F_PPSONSECOND
499 * Meinberg DCF77 receivers
501 #define DCFUA31_ROOTDELAY 0.0 /* 0 */
502 #define DCFUA31_BASEDELAY 0.010 /* 10.7421875ms: 10 ms (+/- 3 ms) */
503 #define DCFUA31_DESCRIPTION "Meinberg DCF77 C51 or compatible"
504 #define DCFUA31_MAXUNSYNC 60*30 /* only trust clock for 1/2 hour */
505 #define DCFUA31_SPEED MBG_SPEED
506 #define DCFUA31_CFLAG MBG_CFLAG
507 #define DCFUA31_IFLAG MBG_IFLAG
508 #define DCFUA31_OFLAG MBG_OFLAG
509 #define DCFUA31_LFLAG MBG_LFLAG
510 #define DCFUA31_SAMPLES 5
511 #define DCFUA31_KEEP 3
512 #define DCFUA31_FORMAT "Meinberg Standard"
515 * Meinberg DCF PZF535/TCXO (FM/PZF) receiver
517 #define DCFPZF535_ROOTDELAY 0.0
518 #define DCFPZF535_BASEDELAY 0.001968 /* 1.968ms +- 104us (oscilloscope) - relative to start (end of STX) */
519 #define DCFPZF535_DESCRIPTION "Meinberg DCF PZF 535/509 / TCXO"
520 #define DCFPZF535_MAXUNSYNC 60*60*12 /* only trust clock for 12 hours
521 * @ 5e-8df/f we have accumulated
522 * at most 2.16 ms (thus we move to
523 * NTP synchronisation */
524 #define DCFPZF535_SPEED MBG_SPEED
525 #define DCFPZF535_CFLAG MBG_CFLAG
526 #define DCFPZF535_IFLAG MBG_IFLAG
527 #define DCFPZF535_OFLAG MBG_OFLAG
528 #define DCFPZF535_LFLAG MBG_LFLAG
529 #define DCFPZF535_SAMPLES 5
530 #define DCFPZF535_KEEP 3
531 #define DCFPZF535_FORMAT "Meinberg Standard"
534 * Meinberg DCF PZF535/OCXO receiver
536 #define DCFPZF535OCXO_ROOTDELAY 0.0
537 #define DCFPZF535OCXO_BASEDELAY 0.001968 /* 1.968ms +- 104us (oscilloscope) - relative to start (end of STX) */
538 #define DCFPZF535OCXO_DESCRIPTION "Meinberg DCF PZF 535/509 / OCXO"
539 #define DCFPZF535OCXO_MAXUNSYNC 60*60*96 /* only trust clock for 4 days
540 * @ 5e-9df/f we have accumulated
541 * at most an error of 1.73 ms
542 * (thus we move to NTP synchronisation) */
543 #define DCFPZF535OCXO_SPEED MBG_SPEED
544 #define DCFPZF535OCXO_CFLAG MBG_CFLAG
545 #define DCFPZF535OCXO_IFLAG MBG_IFLAG
546 #define DCFPZF535OCXO_OFLAG MBG_OFLAG
547 #define DCFPZF535OCXO_LFLAG MBG_LFLAG
548 #define DCFPZF535OCXO_SAMPLES 5
549 #define DCFPZF535OCXO_KEEP 3
550 #define DCFPZF535OCXO_FORMAT "Meinberg Standard"
553 * Meinberg GPS receivers
555 static void gps16x_message (struct parseunit *, parsetime_t *);
556 static int gps16x_poll_init (struct parseunit *);
558 #define GPS16X_ROOTDELAY 0.0 /* nothing here */
559 #define GPS16X_BASEDELAY 0.001968 /* XXX to be fixed ! 1.968ms +- 104us (oscilloscope) - relative to start (end of STX) */
560 #define GPS16X_DESCRIPTION "Meinberg GPS receiver"
561 #define GPS16X_MAXUNSYNC 60*60*96 /* only trust clock for 4 days
562 * @ 5e-9df/f we have accumulated
563 * at most an error of 1.73 ms
564 * (thus we move to NTP synchronisation) */
565 #define GPS16X_SPEED B19200
566 #define GPS16X_CFLAG (CS8|CREAD|CLOCAL|HUPCL)
567 #define GPS16X_IFLAG (IGNBRK|IGNPAR)
568 #define GPS16X_OFLAG MBG_OFLAG
569 #define GPS16X_LFLAG MBG_LFLAG
570 #define GPS16X_POLLRATE 6
571 #define GPS16X_POLLCMD ""
572 #define GPS16X_CMDSIZE 0
574 static poll_info_t gps16x_pollinfo = { GPS16X_POLLRATE, GPS16X_POLLCMD, GPS16X_CMDSIZE };
576 #define GPS16X_INIT gps16x_poll_init
577 #define GPS16X_POLL 0
579 #define GPS16X_DATA ((void *)(&gps16x_pollinfo))
580 #define GPS16X_MESSAGE gps16x_message
581 #define GPS16X_ID GPS_ID
582 #define GPS16X_FORMAT "Meinberg GPS Extended"
583 #define GPS16X_SAMPLES 5
584 #define GPS16X_KEEP 3
587 * ELV DCF7000 Wallclock-Receiver/Switching Clock (Kit)
589 * This is really not the hottest clock - but before you have nothing ...
591 #define DCF7000_ROOTDELAY 0.0 /* 0 */
592 #define DCF7000_BASEDELAY 0.405 /* slow blow */
593 #define DCF7000_DESCRIPTION "ELV DCF7000"
594 #define DCF7000_MAXUNSYNC (60*5) /* sorry - but it just was not build as a clock */
595 #define DCF7000_SPEED (B9600)
596 #define DCF7000_CFLAG (CS8|CREAD|PARENB|PARODD|CLOCAL|HUPCL)
597 #define DCF7000_IFLAG (IGNBRK)
598 #define DCF7000_OFLAG 0
599 #define DCF7000_LFLAG 0
600 #define DCF7000_SAMPLES 5
601 #define DCF7000_KEEP 3
602 #define DCF7000_FORMAT "ELV DCF7000"
605 * Schmid DCF Receiver Kit
607 * When the WSDCF clock is operating optimally we want the primary clock
608 * distance to come out at 300 ms. Thus, peer.distance in the WSDCF peer
609 * structure is set to 290 ms and we compute delays which are at least
610 * 10 ms long. The following are 290 ms and 10 ms expressed in u_fp format
612 #define WS_POLLRATE 1 /* every second - watch interdependency with poll routine */
613 #define WS_POLLCMD "\163"
616 static poll_info_t wsdcf_pollinfo = { WS_POLLRATE, WS_POLLCMD, WS_CMDSIZE };
618 #define WSDCF_INIT poll_init
619 #define WSDCF_POLL poll_dpoll
621 #define WSDCF_DATA ((void *)(&wsdcf_pollinfo))
622 #define WSDCF_ROOTDELAY 0.0 /* 0 */
623 #define WSDCF_BASEDELAY 0.010 /* ~ 10ms */
624 #define WSDCF_DESCRIPTION "WS/DCF Receiver"
625 #define WSDCF_FORMAT "Schmid"
626 #define WSDCF_MAXUNSYNC (60*60) /* assume this beast hold at 1 h better than 2 ms XXX-must verify */
627 #define WSDCF_SPEED (B1200)
628 #define WSDCF_CFLAG (CS8|CREAD|CLOCAL)
629 #define WSDCF_IFLAG 0
630 #define WSDCF_OFLAG 0
631 #define WSDCF_LFLAG 0
632 #define WSDCF_SAMPLES 5
636 * RAW DCF77 - input of DCF marks via RS232 - many variants
638 #define RAWDCF_FLAGS 0
639 #define RAWDCF_ROOTDELAY 0.0 /* 0 */
640 #define RAWDCF_BASEDELAY 0.258
641 #define RAWDCF_FORMAT "RAW DCF77 Timecode"
642 #define RAWDCF_MAXUNSYNC (0) /* sorry - its a true receiver - no signal - no time */
643 #define RAWDCF_SPEED (B50)
644 #ifdef NO_PARENB_IGNPAR /* Was: defined(SYS_IRIX4) || defined(SYS_IRIX5) */
645 /* somehow doesn't grok PARENB & IGNPAR (mj) */
646 # define RAWDCF_CFLAG (CS8|CREAD|CLOCAL)
648 # define RAWDCF_CFLAG (CS8|CREAD|CLOCAL|PARENB)
650 #ifdef RAWDCF_NO_IGNPAR /* Was: defined(SYS_LINUX) && defined(CLOCK_RAWDCF) */
651 # define RAWDCF_IFLAG 0
653 # define RAWDCF_IFLAG (IGNPAR)
655 #define RAWDCF_OFLAG 0
656 #define RAWDCF_LFLAG 0
657 #define RAWDCF_SAMPLES 20
658 #define RAWDCF_KEEP 12
659 #define RAWDCF_INIT 0
667 * simplest (cheapest) DCF clock - e. g. DCF77 receiver by Conrad
668 * (~40DM - roughly $30 ) followed by a level converter for RS232
670 #define CONRAD_BASEDELAY 0.292 /* Conrad receiver @ 50 Baud on a Sun */
671 #define CONRAD_DESCRIPTION "RAW DCF77 CODE (Conrad DCF77 receiver module)"
673 /* Gude Analog- und Digitalsystem GmbH 'Expert mouseCLOCK USB v2.0' */
674 #define GUDE_EMC_USB_V20_SPEED (B4800)
675 #define GUDE_EMC_USB_V20_BASEDELAY 0.425 /* USB serial<->USB converter FTDI232R */
676 #define GUDE_EMC_USB_V20_DESCRIPTION "RAW DCF77 CODE (Expert mouseCLOCK USB v2.0)"
681 #define TIMEBRICK_BASEDELAY 0.210 /* TimeBrick @ 50 Baud on a Sun */
682 #define TIMEBRICK_DESCRIPTION "RAW DCF77 CODE (TimeBrick)"
685 * IGEL:clock receiver
687 #define IGELCLOCK_BASEDELAY 0.258 /* IGEL:clock receiver */
688 #define IGELCLOCK_DESCRIPTION "RAW DCF77 CODE (IGEL:clock)"
689 #define IGELCLOCK_SPEED (B1200)
690 #define IGELCLOCK_CFLAG (CS8|CREAD|HUPCL|CLOCAL)
693 * RAWDCF receivers that need to be powered from DTR
694 * (like Expert mouse clock)
696 static int rawdcf_init_1 (struct parseunit *);
697 #define RAWDCFDTRSET_DESCRIPTION "RAW DCF77 CODE (DTR SET/RTS CLR)"
698 #define RAWDCFDTRSET75_DESCRIPTION "RAW DCF77 CODE (DTR SET/RTS CLR @ 75 baud)"
699 #define RAWDCFDTRSET_INIT rawdcf_init_1
702 * RAWDCF receivers that need to be powered from
703 * DTR CLR and RTS SET
705 static int rawdcf_init_2 (struct parseunit *);
706 #define RAWDCFDTRCLRRTSSET_DESCRIPTION "RAW DCF77 CODE (DTR CLR/RTS SET)"
707 #define RAWDCFDTRCLRRTSSET75_DESCRIPTION "RAW DCF77 CODE (DTR CLR/RTS SET @ 75 baud)"
708 #define RAWDCFDTRCLRRTSSET_INIT rawdcf_init_2
711 * Trimble GPS receivers (TAIP and TSIP protocols)
713 #ifndef TRIM_POLLRATE
714 #define TRIM_POLLRATE 0 /* only true direct polling */
717 #define TRIM_TAIPPOLLCMD ">SRM;FR_FLAG=F;EC_FLAG=F<>QTM<"
718 #define TRIM_TAIPCMDSIZE (sizeof(TRIM_TAIPPOLLCMD)-1)
720 static poll_info_t trimbletaip_pollinfo = { TRIM_POLLRATE, TRIM_TAIPPOLLCMD, TRIM_TAIPCMDSIZE };
721 static int trimbletaip_init (struct parseunit *);
722 static void trimbletaip_event (struct parseunit *, int);
724 /* query time & UTC correction data */
725 static char tsipquery[] = { DLE, 0x21, DLE, ETX, DLE, 0x2F, DLE, ETX };
727 static poll_info_t trimbletsip_pollinfo = { TRIM_POLLRATE, tsipquery, sizeof(tsipquery) };
728 static int trimbletsip_init (struct parseunit *);
729 static void trimbletsip_end (struct parseunit *);
730 static void trimbletsip_message (struct parseunit *, parsetime_t *);
731 static void trimbletsip_event (struct parseunit *, int);
733 #define TRIMBLETSIP_IDLE_TIME (300) /* 5 minutes silence at most */
734 #define TRIMBLE_RESET_HOLDOFF TRIMBLETSIP_IDLE_TIME
736 #define TRIMBLETAIP_SPEED (B4800)
737 #define TRIMBLETAIP_CFLAG (CS8|CREAD|CLOCAL)
738 #define TRIMBLETAIP_IFLAG (BRKINT|IGNPAR|ISTRIP|ICRNL|IXON)
739 #define TRIMBLETAIP_OFLAG (OPOST|ONLCR)
740 #define TRIMBLETAIP_LFLAG (0)
742 #define TRIMBLETSIP_SPEED (B9600)
743 #define TRIMBLETSIP_CFLAG (CS8|CLOCAL|CREAD|PARENB|PARODD)
744 #define TRIMBLETSIP_IFLAG (IGNBRK)
745 #define TRIMBLETSIP_OFLAG (0)
746 #define TRIMBLETSIP_LFLAG (ICANON)
748 #define TRIMBLETSIP_SAMPLES 5
749 #define TRIMBLETSIP_KEEP 3
750 #define TRIMBLETAIP_SAMPLES 5
751 #define TRIMBLETAIP_KEEP 3
753 #define TRIMBLETAIP_FLAGS (PARSE_F_PPSONSECOND)
754 #define TRIMBLETSIP_FLAGS (TRIMBLETAIP_FLAGS)
756 #define TRIMBLETAIP_POLL poll_dpoll
757 #define TRIMBLETSIP_POLL poll_dpoll
759 #define TRIMBLETAIP_INIT trimbletaip_init
760 #define TRIMBLETSIP_INIT trimbletsip_init
762 #define TRIMBLETAIP_EVENT trimbletaip_event
764 #define TRIMBLETSIP_EVENT trimbletsip_event
765 #define TRIMBLETSIP_MESSAGE trimbletsip_message
767 #define TRIMBLETAIP_END 0
768 #define TRIMBLETSIP_END trimbletsip_end
770 #define TRIMBLETAIP_DATA ((void *)(&trimbletaip_pollinfo))
771 #define TRIMBLETSIP_DATA ((void *)(&trimbletsip_pollinfo))
773 #define TRIMBLETAIP_ID GPS_ID
774 #define TRIMBLETSIP_ID GPS_ID
776 #define TRIMBLETAIP_FORMAT "Trimble TAIP"
777 #define TRIMBLETSIP_FORMAT "Trimble TSIP"
779 #define TRIMBLETAIP_ROOTDELAY 0x0
780 #define TRIMBLETSIP_ROOTDELAY 0x0
782 #define TRIMBLETAIP_BASEDELAY 0.0
783 #define TRIMBLETSIP_BASEDELAY 0.020 /* GPS time message latency */
785 #define TRIMBLETAIP_DESCRIPTION "Trimble GPS (TAIP) receiver"
786 #define TRIMBLETSIP_DESCRIPTION "Trimble GPS (TSIP) receiver"
788 #define TRIMBLETAIP_MAXUNSYNC 0
789 #define TRIMBLETSIP_MAXUNSYNC 0
791 #define TRIMBLETAIP_EOL '<'
794 * RadioCode Clocks RCC 800 receiver
796 #define RCC_POLLRATE 0 /* only true direct polling */
797 #define RCC_POLLCMD "\r"
798 #define RCC_CMDSIZE 1
800 static poll_info_t rcc8000_pollinfo = { RCC_POLLRATE, RCC_POLLCMD, RCC_CMDSIZE };
801 #define RCC8000_FLAGS 0
802 #define RCC8000_POLL poll_dpoll
803 #define RCC8000_INIT poll_init
804 #define RCC8000_END 0
805 #define RCC8000_DATA ((void *)(&rcc8000_pollinfo))
806 #define RCC8000_ROOTDELAY 0.0
807 #define RCC8000_BASEDELAY 0.0
808 #define RCC8000_ID "MSF"
809 #define RCC8000_DESCRIPTION "RCC 8000 MSF Receiver"
810 #define RCC8000_FORMAT "Radiocode RCC8000"
811 #define RCC8000_MAXUNSYNC (60*60) /* should be ok for an hour */
812 #define RCC8000_SPEED (B2400)
813 #define RCC8000_CFLAG (CS8|CREAD|CLOCAL)
814 #define RCC8000_IFLAG (IGNBRK|IGNPAR)
815 #define RCC8000_OFLAG 0
816 #define RCC8000_LFLAG 0
817 #define RCC8000_SAMPLES 5
818 #define RCC8000_KEEP 3
821 * Hopf Radio clock 6021 Format
824 #define HOPF6021_ROOTDELAY 0.0
825 #define HOPF6021_BASEDELAY 0.0
826 #define HOPF6021_DESCRIPTION "HOPF 6021"
827 #define HOPF6021_FORMAT "hopf Funkuhr 6021"
828 #define HOPF6021_MAXUNSYNC (60*60) /* should be ok for an hour */
829 #define HOPF6021_SPEED (B9600)
830 #define HOPF6021_CFLAG (CS8|CREAD|CLOCAL)
831 #define HOPF6021_IFLAG (IGNBRK|ISTRIP)
832 #define HOPF6021_OFLAG 0
833 #define HOPF6021_LFLAG 0
834 #define HOPF6021_FLAGS 0
835 #define HOPF6021_SAMPLES 5
836 #define HOPF6021_KEEP 3
839 * Diem's Computime Radio Clock Receiver
841 #define COMPUTIME_FLAGS 0
842 #define COMPUTIME_ROOTDELAY 0.0
843 #define COMPUTIME_BASEDELAY 0.0
844 #define COMPUTIME_ID DCF_ID
845 #define COMPUTIME_DESCRIPTION "Diem's Computime receiver"
846 #define COMPUTIME_FORMAT "Diem's Computime Radio Clock"
847 #define COMPUTIME_TYPE DCF_TYPE
848 #define COMPUTIME_MAXUNSYNC (60*60) /* only trust clock for 1 hour */
849 #define COMPUTIME_SPEED (B9600)
850 #define COMPUTIME_CFLAG (CSTOPB|CS7|CREAD|CLOCAL)
851 #define COMPUTIME_IFLAG (IGNBRK|IGNPAR|ISTRIP)
852 #define COMPUTIME_OFLAG 0
853 #define COMPUTIME_LFLAG 0
854 #define COMPUTIME_SAMPLES 5
855 #define COMPUTIME_KEEP 3
858 * Varitext Radio Clock Receiver
860 #define VARITEXT_FLAGS 0
861 #define VARITEXT_ROOTDELAY 0.0
862 #define VARITEXT_BASEDELAY 0.0
863 #define VARITEXT_ID "MSF"
864 #define VARITEXT_DESCRIPTION "Varitext receiver"
865 #define VARITEXT_FORMAT "Varitext Radio Clock"
866 #define VARITEXT_TYPE DCF_TYPE
867 #define VARITEXT_MAXUNSYNC (60*60) /* only trust clock for 1 hour */
868 #define VARITEXT_SPEED (B9600)
869 #define VARITEXT_CFLAG (CS7|CREAD|CLOCAL|PARENB|PARODD)
870 #define VARITEXT_IFLAG (IGNPAR|IGNBRK|INPCK) /*|ISTRIP)*/
871 #define VARITEXT_OFLAG 0
872 #define VARITEXT_LFLAG 0
873 #define VARITEXT_SAMPLES 32
874 #define VARITEXT_KEEP 20
877 * SEL240x Satellite Sychronized Clock
879 #define SEL240X_POLLRATE 0 /* only true direct polling */
880 #define SEL240X_POLLCMD "BUB8"
881 #define SEL240X_CMDSIZE 4
883 static poll_info_t sel240x_pollinfo = { SEL240X_POLLRATE,
886 #define SEL240X_FLAGS (PARSE_F_PPSONSECOND)
887 #define SEL240X_POLL poll_dpoll
888 #define SEL240X_INIT poll_init
889 #define SEL240X_END 0
890 #define SEL240X_DATA ((void *)(&sel240x_pollinfo))
891 #define SEL240X_ROOTDELAY 0.0
892 #define SEL240X_BASEDELAY 0.0
893 #define SEL240X_ID GPS_ID
894 #define SEL240X_DESCRIPTION "SEL240x Satellite Synchronized Clock"
895 #define SEL240X_FORMAT "SEL B8"
896 #define SEL240X_MAXUNSYNC 60*60*12 /* only trust clock for 12 hours */
897 #define SEL240X_SPEED (B9600)
898 #define SEL240X_CFLAG (CS8|CREAD|CLOCAL)
899 #define SEL240X_IFLAG (IGNBRK|IGNPAR)
900 #define SEL240X_OFLAG (0)
901 #define SEL240X_LFLAG (0)
902 #define SEL240X_SAMPLES 5
903 #define SEL240X_KEEP 3
905 static struct parse_clockinfo
907 u_long cl_flags; /* operation flags (PPS interpretation, trust handling) */
908 void (*cl_poll) (struct parseunit *); /* active poll routine */
909 int (*cl_init) (struct parseunit *); /* active poll init routine */
910 void (*cl_event) (struct parseunit *, int); /* special event handling (e.g. reset clock) */
911 void (*cl_end) (struct parseunit *); /* active poll end routine */
912 void (*cl_message) (struct parseunit *, parsetime_t *); /* process a lower layer message */
913 void *cl_data; /* local data area for "poll" mechanism */
914 double cl_rootdelay; /* rootdelay */
915 double cl_basedelay; /* current offset by which the RS232
916 time code is delayed from the actual time */
917 const char *cl_id; /* ID code */
918 const char *cl_description; /* device name */
919 const char *cl_format; /* fixed format */
920 u_char cl_type; /* clock type (ntp control) */
921 u_long cl_maxunsync; /* time to trust oscillator after losing synch */
922 u_long cl_speed; /* terminal input & output baudrate */
923 u_long cl_cflag; /* terminal control flags */
924 u_long cl_iflag; /* terminal input flags */
925 u_long cl_oflag; /* terminal output flags */
926 u_long cl_lflag; /* terminal local flags */
927 u_long cl_samples; /* samples for median filter */
928 u_long cl_keep; /* samples for median filter to keep */
929 } parse_clockinfo[] =
942 DCFPZF535_DESCRIPTION,
962 DCFPZF535OCXO_ROOTDELAY,
963 DCFPZF535OCXO_BASEDELAY,
965 DCFPZF535OCXO_DESCRIPTION,
966 DCFPZF535OCXO_FORMAT,
968 DCFPZF535OCXO_MAXUNSYNC,
974 DCFPZF535OCXO_SAMPLES,
1011 DCF7000_DESCRIPTION,
1078 TIMEBRICK_BASEDELAY,
1080 TIMEBRICK_DESCRIPTION,
1124 IGELCLOCK_BASEDELAY,
1126 IGELCLOCK_DESCRIPTION,
1140 #if TRIM_POLLRATE /* DHD940515: Allow user config */
1150 TRIMBLETAIP_ROOTDELAY,
1151 TRIMBLETAIP_BASEDELAY,
1153 TRIMBLETAIP_DESCRIPTION,
1156 TRIMBLETAIP_MAXUNSYNC,
1162 TRIMBLETAIP_SAMPLES,
1167 #if TRIM_POLLRATE /* DHD940515: Allow user config */
1175 TRIMBLETSIP_MESSAGE,
1177 TRIMBLETSIP_ROOTDELAY,
1178 TRIMBLETSIP_BASEDELAY,
1180 TRIMBLETSIP_DESCRIPTION,
1183 TRIMBLETSIP_MAXUNSYNC,
1189 TRIMBLETSIP_SAMPLES,
1203 RCC8000_DESCRIPTION,
1226 HOPF6021_DESCRIPTION,
1246 COMPUTIME_ROOTDELAY,
1247 COMPUTIME_BASEDELAY,
1249 COMPUTIME_DESCRIPTION,
1252 COMPUTIME_MAXUNSYNC,
1272 RAWDCFDTRSET_DESCRIPTION,
1285 0, /* operation flags (io modes) */
1286 NO_POLL, /* active poll routine */
1287 NO_INIT, /* active poll init routine */
1288 NO_EVENT, /* special event handling (e.g. reset clock) */
1289 NO_END, /* active poll end routine */
1290 NO_MESSAGE, /* process a lower layer message */
1291 NO_LCLDATA, /* local data area for "poll" mechanism */
1293 11.0 /* bits */ / 9600, /* current offset by which the RS232
1294 time code is delayed from the actual time */
1295 DCF_ID, /* ID code */
1296 "WHARTON 400A Series clock", /* device name */
1297 "WHARTON 400A Series clock Output Format 1", /* fixed format */
1298 /* Must match a format-name in a libparse/clk_xxx.c file */
1299 DCF_TYPE, /* clock type (ntp control) */
1300 (1*60*60), /* time to trust oscillator after losing synch */
1301 B9600, /* terminal input & output baudrate */
1302 (CS8|CREAD|PARENB|CLOCAL|HUPCL),/* terminal control flags */
1303 0, /* terminal input flags */
1304 0, /* terminal output flags */
1305 0, /* terminal local flags */
1306 5, /* samples for median filter */
1307 3, /* samples for median filter to keep */
1309 { /* mode 16 - RAWDCF RTS set, DTR clr */
1312 RAWDCFDTRCLRRTSSET_INIT,
1320 RAWDCFDTRCLRRTSSET_DESCRIPTION,
1343 VARITEXT_DESCRIPTION,
1387 GUDE_EMC_USB_V20_BASEDELAY,
1389 GUDE_EMC_USB_V20_DESCRIPTION,
1393 GUDE_EMC_USB_V20_SPEED,
1401 { /* mode 20, like mode 14 but driven by 75 baud */
1412 RAWDCFDTRSET75_DESCRIPTION,
1424 { /* mode 21, like mode 16 but driven by 75 baud
1425 - RAWDCF RTS set, DTR clr */
1428 RAWDCFDTRCLRRTSSET_INIT,
1436 RAWDCFDTRCLRRTSSET75_DESCRIPTION,
1448 { /* mode 22 - like 2 with POWERUP trust */
1449 MBG_FLAGS | PARSE_F_POWERUPTRUST,
1459 DCFUA31_DESCRIPTION,
1471 { /* mode 23 - like 7 with POWERUP trust */
1472 MBG_FLAGS | PARSE_F_POWERUPTRUST,
1505 SEL240X_DESCRIPTION,
1519 static int ncltypes = sizeof(parse_clockinfo) / sizeof(struct parse_clockinfo);
1521 #define CLK_REALTYPE(x) ((int)(((x)->ttl) & 0x7F))
1522 #define CLK_TYPE(x) ((CLK_REALTYPE(x) >= ncltypes) ? ~0 : CLK_REALTYPE(x))
1523 #define CLK_UNIT(x) ((int)REFCLOCKUNIT(&(x)->srcadr))
1524 #define CLK_PPS(x) (((x)->ttl) & 0x80)
1527 * Other constant stuff
1529 #define PARSEHSREFID 0x7f7f08ff /* 127.127.8.255 refid for hi strata */
1531 #define PARSESTATISTICS (60*60) /* output state statistics every hour */
1533 static int notice = 0;
1535 #define PARSE_STATETIME(parse, i) ((parse->generic->currentstatus == i) ? parse->statetime[i] + current_time - parse->lastchange : parse->statetime[i])
1537 static void parse_event (struct parseunit *, int);
1538 static void parse_process (struct parseunit *, parsetime_t *);
1539 static void clear_err (struct parseunit *, u_long);
1540 static int list_err (struct parseunit *, u_long);
1541 static char * l_mktime (u_long);
1543 /**===========================================================================
1544 ** implementation error message regression module
1548 struct parseunit *parse,
1552 if (lstate == ERR_ALL)
1556 for (i = 0; i < ERR_CNT; i++)
1558 parse->errors[i].err_stage = err_tbl[i];
1559 parse->errors[i].err_cnt = 0;
1560 parse->errors[i].err_last = 0;
1561 parse->errors[i].err_started = 0;
1562 parse->errors[i].err_suppressed = 0;
1567 parse->errors[lstate].err_stage = err_tbl[lstate];
1568 parse->errors[lstate].err_cnt = 0;
1569 parse->errors[lstate].err_last = 0;
1570 parse->errors[lstate].err_started = 0;
1571 parse->errors[lstate].err_suppressed = 0;
1577 struct parseunit *parse,
1582 struct errorinfo *err = &parse->errors[lstate];
1584 if (err->err_started == 0)
1586 err->err_started = current_time;
1589 do_it = (current_time - err->err_last) >= err->err_stage->err_delay;
1594 if (err->err_stage->err_count &&
1595 (err->err_cnt >= err->err_stage->err_count))
1601 if (!err->err_cnt && do_it)
1602 msyslog(LOG_INFO, "PARSE receiver #%d: interval for following error message class is at least %s",
1603 CLK_UNIT(parse->peer), l_mktime(err->err_stage->err_delay));
1606 err->err_suppressed++;
1608 err->err_last = current_time;
1610 if (do_it && err->err_suppressed)
1612 msyslog(LOG_INFO, "PARSE receiver #%d: %ld message%s suppressed, error condition class persists for %s",
1613 CLK_UNIT(parse->peer), err->err_suppressed, (err->err_suppressed == 1) ? " was" : "s where",
1614 l_mktime(current_time - err->err_started));
1615 err->err_suppressed = 0;
1621 /*--------------------------------------------------
1622 * mkreadable - make a printable ascii string (without
1623 * embedded quotes so that the ntpq protocol isn't
1627 #define isprint(_X_) (((_X_) > 0x1F) && ((_X_) < 0x7F))
1639 static const char ellipsis[] = "...";
1644 return NULL; /* don't bother with mini buffers */
1646 endb = buffer + blen - sizeof(ellipsis);
1648 blen--; /* account for '\0' */
1650 while (blen && srclen--)
1652 if (!hex && /* no binary only */
1653 (*src != '\\') && /* no plain \ */
1654 (*src != '"') && /* no " */
1655 isprint((unsigned char)*src)) /* only printables */
1656 { /* they are easy... */
1675 memcpy(buffer, "\\\\", 2);
1682 snprintf(buffer, blen, "\\x%02x", *src++);
1688 if (srclen && !blen && endb) /* overflow - set last chars to ... */
1689 memcpy(endb, ellipsis, sizeof(ellipsis));
1697 /*--------------------------------------------------
1698 * mkascii - make a printable ascii string
1699 * assumes (unless defined better) 7-bit ASCII
1709 return mkreadable(buffer, blen, src, srclen, 0);
1712 /**===========================================================================
1713 ** implementation of i/o handling methods
1714 ** (all STREAM, partial STREAM, user level)
1718 * define possible io handling methods
1721 static int ppsclock_init (struct parseunit *);
1722 static int stream_init (struct parseunit *);
1723 static void stream_end (struct parseunit *);
1724 static int stream_enable (struct parseunit *);
1725 static int stream_disable (struct parseunit *);
1726 static int stream_setcs (struct parseunit *, parsectl_t *);
1727 static int stream_getfmt (struct parseunit *, parsectl_t *);
1728 static int stream_setfmt (struct parseunit *, parsectl_t *);
1729 static int stream_timecode (struct parseunit *, parsectl_t *);
1730 static void stream_receive (struct recvbuf *);
1733 static int local_init (struct parseunit *);
1734 static void local_end (struct parseunit *);
1735 static int local_nop (struct parseunit *);
1736 static int local_setcs (struct parseunit *, parsectl_t *);
1737 static int local_getfmt (struct parseunit *, parsectl_t *);
1738 static int local_setfmt (struct parseunit *, parsectl_t *);
1739 static int local_timecode (struct parseunit *, parsectl_t *);
1740 static void local_receive (struct recvbuf *);
1741 static int local_input (struct recvbuf *);
1743 static bind_t io_bindings[] =
1803 /*--------------------------------------------------
1804 * ppsclock STREAM init
1808 struct parseunit *parse
1811 static char m1[] = "ppsclocd";
1812 static char m2[] = "ppsclock";
1815 * now push the parse streams module
1816 * it will ensure exclusive access to the device
1818 if (ioctl(parse->ppsfd, I_PUSH, (caddr_t)m1) == -1 &&
1819 ioctl(parse->ppsfd, I_PUSH, (caddr_t)m2) == -1)
1821 if (errno != EINVAL)
1823 msyslog(LOG_ERR, "PARSE receiver #%d: ppsclock_init: ioctl(fd, I_PUSH, \"ppsclock\"): %m",
1824 CLK_UNIT(parse->peer));
1828 if (!local_init(parse))
1830 (void)ioctl(parse->ppsfd, I_POP, (caddr_t)0);
1834 parse->flags |= PARSE_PPSCLOCK;
1838 /*--------------------------------------------------
1843 struct parseunit *parse
1846 static char m1[] = "parse";
1848 * now push the parse streams module
1849 * to test whether it is there (neat interface 8-( )
1851 if (ioctl(parse->generic->io.fd, I_PUSH, (caddr_t)m1) == -1)
1853 if (errno != EINVAL) /* accept non-existence */
1855 msyslog(LOG_ERR, "PARSE receiver #%d: stream_init: ioctl(fd, I_PUSH, \"parse\"): %m", CLK_UNIT(parse->peer));
1861 while(ioctl(parse->generic->io.fd, I_POP, (caddr_t)0) == 0)
1865 * now push it a second time after we have removed all
1868 if (ioctl(parse->generic->io.fd, I_PUSH, (caddr_t)m1) == -1)
1870 msyslog(LOG_ERR, "PARSE receiver #%d: stream_init: ioctl(fd, I_PUSH, \"parse\"): %m", CLK_UNIT(parse->peer));
1880 /*--------------------------------------------------
1885 struct parseunit *parse
1888 while(ioctl(parse->generic->io.fd, I_POP, (caddr_t)0) == 0)
1892 /*--------------------------------------------------
1897 struct parseunit *parse,
1901 struct strioctl strioc;
1903 strioc.ic_cmd = PARSEIOC_SETCS;
1904 strioc.ic_timout = 0;
1905 strioc.ic_dp = (char *)tcl;
1906 strioc.ic_len = sizeof (*tcl);
1908 if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1)
1910 msyslog(LOG_ERR, "PARSE receiver #%d: stream_setcs: ioctl(fd, I_STR, PARSEIOC_SETCS): %m", CLK_UNIT(parse->peer));
1916 /*--------------------------------------------------
1921 struct parseunit *parse
1924 struct strioctl strioc;
1926 strioc.ic_cmd = PARSEIOC_ENABLE;
1927 strioc.ic_timout = 0;
1928 strioc.ic_dp = (char *)0;
1931 if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1)
1933 msyslog(LOG_ERR, "PARSE receiver #%d: stream_enable: ioctl(fd, I_STR, PARSEIOC_ENABLE): %m", CLK_UNIT(parse->peer));
1936 parse->generic->io.clock_recv = stream_receive; /* ok - parse input in kernel */
1940 /*--------------------------------------------------
1945 struct parseunit *parse
1948 struct strioctl strioc;
1950 strioc.ic_cmd = PARSEIOC_DISABLE;
1951 strioc.ic_timout = 0;
1952 strioc.ic_dp = (char *)0;
1955 if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1)
1957 msyslog(LOG_ERR, "PARSE receiver #%d: stream_disable: ioctl(fd, I_STR, PARSEIOC_DISABLE): %m", CLK_UNIT(parse->peer));
1960 parse->generic->io.clock_recv = local_receive; /* ok - parse input in daemon */
1964 /*--------------------------------------------------
1969 struct parseunit *parse,
1973 struct strioctl strioc;
1975 strioc.ic_cmd = PARSEIOC_GETFMT;
1976 strioc.ic_timout = 0;
1977 strioc.ic_dp = (char *)tcl;
1978 strioc.ic_len = sizeof (*tcl);
1979 if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1)
1981 msyslog(LOG_ERR, "PARSE receiver #%d: ioctl(fd, I_STR, PARSEIOC_GETFMT): %m", CLK_UNIT(parse->peer));
1987 /*--------------------------------------------------
1992 struct parseunit *parse,
1996 struct strioctl strioc;
1998 strioc.ic_cmd = PARSEIOC_SETFMT;
1999 strioc.ic_timout = 0;
2000 strioc.ic_dp = (char *)tcl;
2001 strioc.ic_len = sizeof (*tcl);
2003 if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1)
2005 msyslog(LOG_ERR, "PARSE receiver #%d: stream_setfmt: ioctl(fd, I_STR, PARSEIOC_SETFMT): %m", CLK_UNIT(parse->peer));
2012 /*--------------------------------------------------
2017 struct parseunit *parse,
2021 struct strioctl strioc;
2023 strioc.ic_cmd = PARSEIOC_TIMECODE;
2024 strioc.ic_timout = 0;
2025 strioc.ic_dp = (char *)tcl;
2026 strioc.ic_len = sizeof (*tcl);
2028 if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1)
2031 msyslog(LOG_ERR, "PARSE receiver #%d: stream_timecode: ioctl(fd, I_STR, PARSEIOC_TIMECODE): %m", CLK_UNIT(parse->peer));
2034 clear_err(parse, ERR_INTERNAL);
2038 /*--------------------------------------------------
2043 struct recvbuf *rbufp
2046 struct parseunit * parse;
2047 parsetime_t parsetime;
2049 parse = (struct parseunit *)rbufp->recv_peer->procptr->unitptr;
2053 if (rbufp->recv_length != sizeof(parsetime_t))
2056 msyslog(LOG_ERR,"PARSE receiver #%d: stream_receive: bad size (got %d expected %d)",
2057 CLK_UNIT(parse->peer), rbufp->recv_length, (int)sizeof(parsetime_t));
2058 parse_event(parse, CEVNT_BADREPLY);
2061 clear_err(parse, ERR_BADIO);
2063 memmove((caddr_t)&parsetime,
2064 (caddr_t)rbufp->recv_buffer,
2065 sizeof(parsetime_t));
2070 printf("PARSE receiver #%d: status %06x, state %08x, time %lx.%08lx, stime %lx.%08lx, ptime %lx.%08lx\n",
2071 CLK_UNIT(parse->peer),
2072 (unsigned int)parsetime.parse_status,
2073 (unsigned int)parsetime.parse_state,
2074 (unsigned long)parsetime.parse_time.tv.tv_sec,
2075 (unsigned long)parsetime.parse_time.tv.tv_usec,
2076 (unsigned long)parsetime.parse_stime.tv.tv_sec,
2077 (unsigned long)parsetime.parse_stime.tv.tv_usec,
2078 (unsigned long)parsetime.parse_ptime.tv.tv_sec,
2079 (unsigned long)parsetime.parse_ptime.tv.tv_usec);
2084 * switch time stamp world - be sure to normalize small usec field
2088 parsetime.parse_stime.fp = tval_stamp_to_lfp(parsetime.parse_stime.tv);
2090 if (PARSE_TIMECODE(parsetime.parse_state))
2092 parsetime.parse_time.fp = tval_stamp_to_lfp(parsetime.parse_time.tv);
2095 if (PARSE_PPS(parsetime.parse_state))
2097 parsetime.parse_ptime.fp = tval_stamp_to_lfp(parsetime.parse_ptime.tv);
2100 parse_process(parse, &parsetime);
2104 /*--------------------------------------------------
2109 struct parseunit *parse
2112 return parse_ioinit(&parse->parseio);
2115 /*--------------------------------------------------
2120 struct parseunit *parse
2123 parse_ioend(&parse->parseio);
2127 /*--------------------------------------------------
2132 struct parseunit *parse
2138 /*--------------------------------------------------
2143 struct parseunit *parse,
2147 return parse_setcs(tcl, &parse->parseio);
2150 /*--------------------------------------------------
2155 struct parseunit *parse,
2159 return parse_getfmt(tcl, &parse->parseio);
2162 /*--------------------------------------------------
2167 struct parseunit *parse,
2171 return parse_setfmt(tcl, &parse->parseio);
2174 /*--------------------------------------------------
2179 struct parseunit *parse,
2183 return parse_timecode(tcl, &parse->parseio);
2187 /*--------------------------------------------------
2192 struct recvbuf *rbufp
2195 struct parseunit * parse;
2201 parse = (struct parseunit *)rbufp->recv_peer->procptr->unitptr;
2206 * eat all characters, parsing then and feeding complete samples
2208 count = rbufp->recv_length;
2209 s = (unsigned char *)rbufp->recv_buffer;
2210 ts.fp = rbufp->recv_time;
2214 if (parse_ioread(&parse->parseio, (unsigned int)(*s++), &ts))
2216 struct recvbuf *buf;
2219 * got something good to eat
2221 if (!PARSE_PPS(parse->parseio.parse_dtime.parse_state))
2224 if (parse->flags & PARSE_PPSCLOCK)
2226 struct timespec pps_timeout;
2227 pps_info_t pps_info;
2229 pps_timeout.tv_sec = 0;
2230 pps_timeout.tv_nsec = 0;
2232 if (time_pps_fetch(parse->atom.handle, PPS_TSFMT_TSPEC, &pps_info,
2235 if (pps_info.assert_sequence + pps_info.clear_sequence != parse->ppsserial)
2239 struct timespec pts;
2241 * add PPS time stamp if available via ppsclock module
2242 * and not supplied already.
2244 if (parse->flags & PARSE_CLEAR)
2245 pts = pps_info.clear_timestamp;
2247 pts = pps_info.assert_timestamp;
2249 parse->parseio.parse_dtime.parse_ptime.fp.l_ui = (uint32_t) (pts.tv_sec + JAN_1970);
2251 dtemp = (double) pts.tv_nsec / 1e9;
2254 parse->parseio.parse_dtime.parse_ptime.fp.l_ui--;
2258 parse->parseio.parse_dtime.parse_ptime.fp.l_ui++;
2260 parse->parseio.parse_dtime.parse_ptime.fp.l_uf = (uint32_t)(dtemp * FRAC);
2262 parse->parseio.parse_dtime.parse_state |= PARSEB_PPS|PARSEB_S_PPS;
2267 "parse: local_receive: fd %ld PPSAPI seq %ld - PPS %s\n",
2269 (long)pps_info.assert_sequence + (long)pps_info.clear_sequence,
2270 lfptoa(&parse->parseio.parse_dtime.parse_ptime.fp, 6));
2280 "parse: local_receive: fd %ld PPSAPI seq assert %ld, seq clear %ld - NO PPS event\n",
2282 (long)pps_info.assert_sequence, (long)pps_info.clear_sequence);
2286 parse->ppsserial = pps_info.assert_sequence + pps_info.clear_sequence;
2294 "parse: local_receive: fd %ld PPSAPI time_pps_fetch errno = %d\n",
2302 #ifdef TIOCDCDTIMESTAMP
2303 struct timeval dcd_time;
2305 if (ioctl(parse->ppsfd, TIOCDCDTIMESTAMP, &dcd_time) != -1)
2309 TVTOTS(&dcd_time, &tstmp);
2310 tstmp.l_ui += JAN_1970;
2311 L_SUB(&ts.fp, &tstmp);
2312 if (ts.fp.l_ui == 0)
2318 "parse: local_receive: fd %d DCDTIMESTAMP %s\n",
2321 printf(" sigio %s\n",
2325 parse->parseio.parse_dtime.parse_ptime.fp = tstmp;
2326 parse->parseio.parse_dtime.parse_state |= PARSEB_PPS|PARSEB_S_PPS;
2329 #else /* TIOCDCDTIMESTAMP */
2330 #if defined(HAVE_STRUCT_PPSCLOCKEV) && (defined(HAVE_CIOGETEV) || defined(HAVE_TIOCGPPSEV))
2331 if (parse->flags & PARSE_PPSCLOCK)
2334 struct ppsclockev ev;
2336 #ifdef HAVE_CIOGETEV
2337 if (ioctl(parse->ppsfd, CIOGETEV, (caddr_t)&ev) == 0)
2339 #ifdef HAVE_TIOCGPPSEV
2340 if (ioctl(parse->ppsfd, TIOCGPPSEV, (caddr_t)&ev) == 0)
2343 if (ev.serial != parse->ppsserial)
2346 * add PPS time stamp if available via ppsclock module
2347 * and not supplied already.
2349 if (!buftvtots((const char *)&ev.tv, &tts))
2352 msyslog(LOG_ERR,"parse: local_receive: timestamp conversion error (buftvtots) (ppsclockev.tv)");
2356 parse->parseio.parse_dtime.parse_ptime.fp = tts;
2357 parse->parseio.parse_dtime.parse_state |= PARSEB_PPS|PARSEB_S_PPS;
2360 parse->ppsserial = ev.serial;
2364 #endif /* TIOCDCDTIMESTAMP */
2365 #endif /* !HAVE_PPSAPI */
2368 { /* simulate receive */
2369 buf = get_free_recv_buffer();
2371 memmove((caddr_t)buf->recv_buffer,
2372 (caddr_t)&parse->parseio.parse_dtime,
2373 sizeof(parsetime_t));
2374 buf->recv_length = sizeof(parsetime_t);
2375 buf->recv_time = rbufp->recv_time;
2376 #ifndef HAVE_IO_COMPLETION_PORT
2377 buf->srcadr = rbufp->srcadr;
2379 buf->dstadr = rbufp->dstadr;
2380 buf->receiver = rbufp->receiver;
2381 buf->fd = rbufp->fd;
2382 buf->X_from_where = rbufp->X_from_where;
2383 parse->generic->io.recvcount++;
2385 add_full_recv_buffer(buf);
2386 #ifdef HAVE_IO_COMPLETION_PORT
2387 SetEvent(WaitableIoEventHandle);
2390 parse_iodone(&parse->parseio);
2394 memmove((caddr_t)rbufp->recv_buffer,
2395 (caddr_t)&parse->parseio.parse_dtime,
2396 sizeof(parsetime_t));
2397 parse_iodone(&parse->parseio);
2398 rbufp->recv_length = sizeof(parsetime_t);
2399 return 1; /* got something & in place return */
2403 return 0; /* nothing to pass up */
2406 /*--------------------------------------------------
2411 struct recvbuf *rbufp
2414 struct parseunit * parse;
2415 parsetime_t parsetime;
2417 parse = (struct parseunit *)rbufp->recv_peer->procptr->unitptr;
2421 if (rbufp->recv_length != sizeof(parsetime_t))
2424 msyslog(LOG_ERR,"PARSE receiver #%d: local_receive: bad size (got %d expected %d)",
2425 CLK_UNIT(parse->peer), rbufp->recv_length, (int)sizeof(parsetime_t));
2426 parse_event(parse, CEVNT_BADREPLY);
2429 clear_err(parse, ERR_BADIO);
2431 memmove((caddr_t)&parsetime,
2432 (caddr_t)rbufp->recv_buffer,
2433 sizeof(parsetime_t));
2438 printf("PARSE receiver #%d: status %06x, state %08x, time(fp) %lx.%08lx, stime(fp) %lx.%08lx, ptime(fp) %lx.%08lx\n",
2439 CLK_UNIT(parse->peer),
2440 (unsigned int)parsetime.parse_status,
2441 (unsigned int)parsetime.parse_state,
2442 (unsigned long)parsetime.parse_time.fp.l_ui,
2443 (unsigned long)parsetime.parse_time.fp.l_uf,
2444 (unsigned long)parsetime.parse_stime.fp.l_ui,
2445 (unsigned long)parsetime.parse_stime.fp.l_uf,
2446 (unsigned long)parsetime.parse_ptime.fp.l_ui,
2447 (unsigned long)parsetime.parse_ptime.fp.l_uf);
2451 parse_process(parse, &parsetime);
2454 /*--------------------------------------------------
2455 * init_iobinding - find and initialize lower layers
2459 struct parseunit *parse
2462 bind_t *b = io_bindings;
2464 while (b->bd_description != (char *)0)
2466 if ((*b->bd_init)(parse))
2475 /**===========================================================================
2479 static NTP_PRINTF(4, 5) char *
2480 ap(char *buffer, size_t len, char *pos, const char *fmt, ...)
2484 size_t rem = len - (pos - buffer);
2490 l = vsnprintf(pos, rem, fmt, va);
2495 if (rem >= (size_t)l)
2504 /*--------------------------------------------------
2505 * convert a flag field to a string
2520 { PARSEB_ANNOUNCE, "DST SWITCH WARNING" },
2521 { PARSEB_POWERUP, "NOT SYNCHRONIZED" },
2522 { PARSEB_NOSYNC, "TIME CODE NOT CONFIRMED" },
2523 { PARSEB_DST, "DST" },
2524 { PARSEB_UTC, "UTC DISPLAY" },
2525 { PARSEB_LEAPADD, "LEAP ADD WARNING" },
2526 { PARSEB_LEAPDEL, "LEAP DELETE WARNING" },
2527 { PARSEB_LEAPSECOND, "LEAP SECOND" },
2528 { PARSEB_CALLBIT, "CALL BIT" },
2529 { PARSEB_TIMECODE, "TIME CODE" },
2530 { PARSEB_PPS, "PPS" },
2531 { PARSEB_POSITION, "POSITION" },
2541 { PARSEB_S_LEAP, "LEAP INDICATION" },
2542 { PARSEB_S_PPS, "PPS SIGNAL" },
2543 { PARSEB_S_CALLBIT, "CALLBIT" },
2544 { PARSEB_S_POSITION, "POSITION" },
2554 while (flagstrings[i].bit)
2556 if (flagstrings[i].bit & lstate)
2559 t = ap(buffer, size, t, "; ");
2560 t = ap(buffer, size, t, "%s", flagstrings[i].name);
2565 if (lstate & (PARSEB_S_LEAP|PARSEB_S_CALLBIT|PARSEB_S_PPS|PARSEB_S_POSITION))
2568 t = ap(buffer, size, t, "; ");
2570 t = ap(buffer, size, t, "(");
2575 while (sflagstrings[i].bit)
2577 if (sflagstrings[i].bit & lstate)
2581 t = ap(buffer, size, t, "; ");
2584 t = ap(buffer, size, t, "%s",
2585 sflagstrings[i].name);
2589 t = ap(buffer, size, t, ")");
2590 /* t is unused here, but if we don't track it and
2591 * need it later, that's a bug waiting to happen.
2597 /*--------------------------------------------------
2598 * convert a status flag field to a string
2613 { CVT_OK, "CONVERSION SUCCESSFUL" },
2614 { CVT_NONE, "NO CONVERSION" },
2615 { CVT_FAIL, "CONVERSION FAILED" },
2616 { CVT_BADFMT, "ILLEGAL FORMAT" },
2617 { CVT_BADDATE, "DATE ILLEGAL" },
2618 { CVT_BADTIME, "TIME ILLEGAL" },
2619 { CVT_ADDITIONAL, "ADDITIONAL DATA" },
2629 while (flagstrings[i].bit)
2631 if (flagstrings[i].bit & lstate)
2634 t = ap(buffer, size, t, "; ");
2635 t = ap(buffer, size, t, "%s", flagstrings[i].name);
2643 /*--------------------------------------------------
2644 * convert a clock status flag field to a string
2651 static char buffer[20];
2652 static struct status
2658 { CEVNT_NOMINAL, "NOMINAL" },
2659 { CEVNT_TIMEOUT, "NO RESPONSE" },
2660 { CEVNT_BADREPLY,"BAD FORMAT" },
2661 { CEVNT_FAULT, "FAULT" },
2662 { CEVNT_PROP, "PROPAGATION DELAY" },
2663 { CEVNT_BADDATE, "ILLEGAL DATE" },
2664 { CEVNT_BADTIME, "ILLEGAL TIME" },
2665 { (unsigned)~0L, NULL }
2670 while (flagstrings[i].value != (u_int)~0)
2672 if (flagstrings[i].value == lstate)
2674 return flagstrings[i].name;
2679 snprintf(buffer, sizeof(buffer), "unknown #%ld", (u_long)lstate);
2685 /*--------------------------------------------------
2686 * l_mktime - make representation of a relative time
2694 static char buffer[40];
2700 if ((tmp = delta / (60*60*24)) != 0)
2702 t = ap(buffer, sizeof(buffer), t, "%ldd+", (u_long)tmp);
2703 delta -= tmp * 60*60*24;
2711 t = ap(buffer, sizeof(buffer), t, "%02d:%02d:%02d",
2712 (int)delta, (int)m, (int)s);
2718 /*--------------------------------------------------
2719 * parse_statistics - list summary of clock states
2723 struct parseunit *parse
2728 NLOG(NLOG_CLOCKSTATIST) /* conditional if clause for conditional syslog */
2730 msyslog(LOG_INFO, "PARSE receiver #%d: running time: %s",
2731 CLK_UNIT(parse->peer),
2732 l_mktime(current_time - parse->generic->timestarted));
2734 msyslog(LOG_INFO, "PARSE receiver #%d: current status: %s",
2735 CLK_UNIT(parse->peer),
2736 clockstatus(parse->generic->currentstatus));
2738 for (i = 0; i <= CEVNT_MAX; i++)
2741 u_long percent, d = current_time - parse->generic->timestarted;
2743 percent = s_time = PARSE_STATETIME(parse, i);
2745 while (((u_long)(~0) / 10000) < percent)
2752 percent = (percent * 10000) / d;
2757 msyslog(LOG_INFO, "PARSE receiver #%d: state %18s: %13s (%3ld.%02ld%%)",
2758 CLK_UNIT(parse->peer),
2759 clockstatus((unsigned int)i),
2761 percent / 100, percent % 100);
2766 /*--------------------------------------------------
2767 * cparse_statistics - wrapper for statistics call
2771 struct parseunit *parse
2774 if (parse->laststatistic + PARSESTATISTICS < current_time)
2775 parse_statistics(parse);
2776 parse->laststatistic = current_time;
2779 /**===========================================================================
2780 ** ntp interface routines
2783 /*--------------------------------------------------
2784 * parse_shutdown - shut down a PARSE clock
2792 struct parseunit *parse = NULL;
2794 if (peer && peer->procptr)
2795 parse = peer->procptr->unitptr;
2799 /* nothing to clean up */
2805 msyslog(LOG_INFO, "PARSE receiver #%d: INTERNAL ERROR - unit already inactive - shutdown ignored", unit);
2810 if (parse->flags & PARSE_PPSCLOCK)
2812 (void)time_pps_destroy(parse->atom.handle);
2815 if (parse->generic->io.fd != parse->ppsfd && parse->ppsfd != -1)
2816 (void)closeserial(parse->ppsfd); /* close separate PPS source */
2819 * print statistics a last time and
2820 * stop statistics machine
2822 parse_statistics(parse);
2824 if (parse->parse_type->cl_end)
2826 parse->parse_type->cl_end(parse);
2830 * cleanup before leaving this world
2836 * Tell the I/O module to turn us off. We're history.
2838 io_closeclock(&parse->generic->io);
2840 free_varlist(parse->kv);
2842 NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */
2843 msyslog(LOG_INFO, "PARSE receiver #%d: reference clock \"%s\" removed",
2844 CLK_UNIT(parse->peer), parse->parse_type->cl_description);
2846 parse->peer = (struct peer *)0; /* unused now */
2847 peer->procptr->unitptr = (caddr_t)0;
2852 /*----------------------------------------
2853 * set up HARDPPS via PPSAPI
2857 struct parseunit *parse,
2861 if (parse->hardppsstate == mode)
2864 if (CLK_PPS(parse->peer) && (parse->flags & PARSE_PPSKERNEL)) {
2867 if (mode == PARSE_HARDPPS_ENABLE)
2869 if (parse->flags & PARSE_CLEAR)
2870 i = PPS_CAPTURECLEAR;
2872 i = PPS_CAPTUREASSERT;
2875 if (time_pps_kcbind(parse->atom.handle, PPS_KC_HARDPPS, i,
2876 PPS_TSFMT_TSPEC) < 0) {
2877 msyslog(LOG_ERR, "PARSE receiver #%d: time_pps_kcbind failed: %m",
2878 CLK_UNIT(parse->peer));
2880 NLOG(NLOG_CLOCKINFO)
2881 msyslog(LOG_INFO, "PARSE receiver #%d: kernel PPS synchronisation %sabled",
2882 CLK_UNIT(parse->peer), (mode == PARSE_HARDPPS_ENABLE) ? "en" : "dis");
2884 * tell the rest, that we have a kernel PPS source, iff we ever enable HARDPPS
2886 if (mode == PARSE_HARDPPS_ENABLE)
2891 parse->hardppsstate = mode;
2894 /*----------------------------------------
2895 * set up PPS via PPSAPI
2899 struct parseunit *parse
2902 int cap, mode_ppsoffset;
2905 parse->flags &= (u_char) (~PARSE_PPSCLOCK);
2908 * collect PPSAPI offset capability - should move into generic handling
2910 if (time_pps_getcap(parse->atom.handle, &cap) < 0) {
2911 msyslog(LOG_ERR, "PARSE receiver #%d: parse_ppsapi: time_pps_getcap failed: %m",
2912 CLK_UNIT(parse->peer));
2918 * initialize generic PPSAPI interface
2920 * we leave out CLK_FLAG3 as time_pps_kcbind()
2921 * is handled here for now. Ideally this should also
2922 * be part of the generic PPSAPI interface
2924 if (!refclock_params(parse->flags & (CLK_FLAG1|CLK_FLAG2|CLK_FLAG4), &parse->atom))
2927 /* nb. only turn things on, if someone else has turned something
2928 * on before we get here, leave it alone!
2931 if (parse->flags & PARSE_CLEAR) {
2933 mode_ppsoffset = PPS_OFFSETCLEAR;
2936 mode_ppsoffset = PPS_OFFSETASSERT;
2939 msyslog(LOG_INFO, "PARSE receiver #%d: initializing PPS to %s",
2940 CLK_UNIT(parse->peer), cp);
2942 if (!(mode_ppsoffset & cap)) {
2943 msyslog(LOG_WARNING, "PARSE receiver #%d: Cannot set PPS_%sCLEAR, this will increase jitter (PPS API capabilities=0x%x)",
2944 CLK_UNIT(parse->peer), cp, cap);
2947 if (mode_ppsoffset == PPS_OFFSETCLEAR)
2949 parse->atom.pps_params.clear_offset.tv_sec = (time_t)(-parse->ppsphaseadjust);
2950 parse->atom.pps_params.clear_offset.tv_nsec = (long)(-1e9*(parse->ppsphaseadjust - (double)(long)parse->ppsphaseadjust));
2953 if (mode_ppsoffset == PPS_OFFSETASSERT)
2955 parse->atom.pps_params.assert_offset.tv_sec = (time_t)(-parse->ppsphaseadjust);
2956 parse->atom.pps_params.assert_offset.tv_nsec = (long)(-1e9*(parse->ppsphaseadjust - (double)(long)parse->ppsphaseadjust));
2960 parse->atom.pps_params.mode |= mode_ppsoffset;
2962 if (time_pps_setparams(parse->atom.handle, &parse->atom.pps_params) < 0) {
2963 msyslog(LOG_ERR, "PARSE receiver #%d: FAILED set PPS parameters: %m",
2964 CLK_UNIT(parse->peer));
2968 parse->flags |= PARSE_PPSCLOCK;
2972 #define parse_hardpps(_PARSE_, _MODE_) /* empty */
2975 /*--------------------------------------------------
2976 * parse_start - open the PARSE devices and initialize data for processing
2987 struct termios tio; /* NEEDED FOR A LONG TIME ! */
2989 #ifdef HAVE_SYSV_TTYS
2990 struct termio tio; /* NEEDED FOR A LONG TIME ! */
2992 struct parseunit * parse;
2993 char parsedev[sizeof(PARSEDEVICE)+20];
2994 char parseppsdev[sizeof(PARSEPPSDEVICE)+20];
2999 * get out Copyright information once
3003 NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */
3004 msyslog(LOG_INFO, "NTP PARSE support: Copyright (c) 1989-2015, Frank Kardel");
3008 type = CLK_TYPE(peer);
3009 unit = CLK_UNIT(peer);
3011 if ((type == (u_int)~0) || (parse_clockinfo[type].cl_description == (char *)0))
3013 msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: unsupported clock type %d (max %d)",
3014 unit, CLK_REALTYPE(peer), ncltypes-1);
3019 * Unit okay, attempt to open the device.
3021 (void) snprintf(parsedev, sizeof(parsedev), PARSEDEVICE, unit);
3022 (void) snprintf(parseppsdev, sizeof(parsedev), PARSEPPSDEVICE, unit);
3028 #define O_NONBLOCK 0
3031 fd232 = tty_open(parsedev, O_RDWR | O_NOCTTY | O_NONBLOCK, 0777);
3035 msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: open of %s failed: %m", unit, parsedev);
3039 parse = emalloc_zero(sizeof(*parse));
3041 parse->generic = peer->procptr; /* link up */
3042 parse->generic->unitptr = (caddr_t)parse; /* link down */
3045 * Set up the structures
3047 parse->generic->timestarted = current_time;
3048 parse->lastchange = current_time;
3051 parse->pollneeddata = 0;
3052 parse->laststatistic = current_time;
3053 parse->lastformat = (unsigned short)~0; /* assume no format known */
3054 parse->timedata.parse_status = (unsigned short)~0; /* be sure to mark initial status change */
3055 parse->lastmissed = 0; /* assume got everything */
3056 parse->ppsserial = 0;
3058 parse->localdata = (void *)0;
3059 parse->localstate = 0;
3060 parse->kv = (struct ctl_var *)0;
3062 clear_err(parse, ERR_ALL);
3064 parse->parse_type = &parse_clockinfo[type];
3066 parse->maxunsync = parse->parse_type->cl_maxunsync;
3068 parse->generic->fudgetime1 = parse->parse_type->cl_basedelay;
3070 parse->generic->fudgetime2 = 0.0;
3071 parse->ppsphaseadjust = parse->generic->fudgetime2;
3072 parse->generic->fudgeminjitter = 0.0;
3074 parse->generic->clockdesc = parse->parse_type->cl_description;
3076 peer->rootdelay = parse->parse_type->cl_rootdelay;
3077 peer->sstclktype = parse->parse_type->cl_type;
3078 peer->precision = sys_precision;
3080 peer->stratum = STRATUM_REFCLOCK;
3082 if (peer->stratum <= 1)
3083 memmove((char *)&parse->generic->refid, parse->parse_type->cl_id, 4);
3085 parse->generic->refid = htonl(PARSEHSREFID);
3087 parse->generic->io.fd = fd232;
3089 parse->peer = peer; /* marks it also as busy */
3092 * configure terminal line
3094 if (TTY_GETATTR(fd232, &tio) == -1)
3096 msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: tcgetattr(%d, &tio): %m", unit, fd232);
3097 parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
3102 #ifndef _PC_VDISABLE
3103 memset((char *)tio.c_cc, 0, sizeof(tio.c_cc));
3106 errno = 0; /* pathconf can deliver -1 without changing errno ! */
3108 disablec = fpathconf(parse->generic->io.fd, _PC_VDISABLE);
3109 if (disablec == -1 && errno)
3111 msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: fpathconf(fd, _PC_VDISABLE): %m", CLK_UNIT(parse->peer));
3112 memset((char *)tio.c_cc, 0, sizeof(tio.c_cc)); /* best guess */
3116 memset((char *)tio.c_cc, disablec, sizeof(tio.c_cc));
3119 #if defined (VMIN) || defined(VTIME)
3120 if ((parse_clockinfo[type].cl_lflag & ICANON) == 0)
3126 tio.c_cc[VTIME] = 0;
3131 tio.c_cflag = (tcflag_t) parse_clockinfo[type].cl_cflag;
3132 tio.c_iflag = (tcflag_t) parse_clockinfo[type].cl_iflag;
3133 tio.c_oflag = (tcflag_t) parse_clockinfo[type].cl_oflag;
3134 tio.c_lflag = (tcflag_t) parse_clockinfo[type].cl_lflag;
3138 if ((cfsetospeed(&tio, (speed_t) parse_clockinfo[type].cl_speed) == -1) ||
3139 (cfsetispeed(&tio, (speed_t) parse_clockinfo[type].cl_speed) == -1))
3141 msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: tcset{i,o}speed(&tio, speed): %m", unit);
3142 parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
3146 tio.c_cflag |= parse_clockinfo[type].cl_speed;
3151 * if the PARSEPPSDEVICE can be opened that will be used
3152 * for PPS else PARSEDEVICE will be used
3154 parse->ppsfd = tty_open(parseppsdev, O_RDWR | O_NOCTTY | O_NONBLOCK, 0777);
3156 if (parse->ppsfd == -1)
3158 parse->ppsfd = fd232;
3162 * Linux PPS - the old way
3164 #if defined(HAVE_TIO_SERIAL_STUFF) /* Linux hack: define PPS interface */
3166 struct serial_struct ss;
3167 if (ioctl(parse->ppsfd, TIOCGSERIAL, &ss) < 0 ||
3169 #ifdef ASYNC_LOW_LATENCY
3170 ss.flags |= ASYNC_LOW_LATENCY,
3173 #ifdef ASYNC_PPS_CD_NEG
3174 ss.flags |= ASYNC_PPS_CD_NEG,
3177 ioctl(parse->ppsfd, TIOCSSERIAL, &ss)) < 0) {
3178 msyslog(LOG_NOTICE, "refclock_parse: TIOCSSERIAL fd %d, %m", parse->ppsfd);
3180 "refclock_parse: optional PPS processing not available");
3182 parse->flags |= PARSE_PPSCLOCK;
3183 #ifdef ASYNC_PPS_CD_NEG
3184 NLOG(NLOG_CLOCKINFO)
3186 "refclock_parse: PPS detection on");
3193 * SUN the Solaris way
3195 #ifdef HAVE_TIOCSPPS /* SUN PPS support */
3196 if (CLK_PPS(parse->peer))
3200 if (ioctl(parse->ppsfd, TIOCSPPS, (caddr_t)&i) == 0)
3202 parse->flags |= PARSE_PPSCLOCK;
3210 #if defined(HAVE_PPSAPI)
3211 parse->hardppsstate = PARSE_HARDPPS_DISABLE;
3212 if (CLK_PPS(parse->peer))
3214 if (!refclock_ppsapi(parse->ppsfd, &parse->atom))
3216 msyslog(LOG_NOTICE, "PARSE receiver #%d: parse_start: could not set up PPS: %m", CLK_UNIT(parse->peer));
3220 parse_ppsapi(parse);
3225 if (TTY_SETATTR(fd232, &tio) == -1)
3227 msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: tcsetattr(%d, &tio): %m", unit, fd232);
3228 parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
3234 * pick correct input machine
3236 parse->generic->io.srcclock = peer;
3237 parse->generic->io.datalen = 0;
3239 parse->binding = init_iobinding(parse);
3241 if (parse->binding == (bind_t *)0)
3243 msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: io sub system initialisation failed.", CLK_UNIT(parse->peer));
3244 parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
3245 return 0; /* well, ok - special initialisation broke */
3248 parse->generic->io.clock_recv = parse->binding->bd_receive; /* pick correct receive routine */
3249 parse->generic->io.io_input = parse->binding->bd_io_input; /* pick correct input routine */
3252 * as we always(?) get 8 bit chars we want to be
3253 * sure, that the upper bits are zero for less
3254 * than 8 bit I/O - so we pass that information on.
3255 * note that there can be only one bit count format
3256 * per file descriptor
3259 switch (tio.c_cflag & CSIZE)
3262 tmp_ctl.parsesetcs.parse_cs = PARSE_IO_CS5;
3266 tmp_ctl.parsesetcs.parse_cs = PARSE_IO_CS6;
3270 tmp_ctl.parsesetcs.parse_cs = PARSE_IO_CS7;
3274 tmp_ctl.parsesetcs.parse_cs = PARSE_IO_CS8;
3278 if (!PARSE_SETCS(parse, &tmp_ctl))
3280 msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: parse_setcs() FAILED.", unit);
3281 parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
3282 return 0; /* well, ok - special initialisation broke */
3285 strlcpy(tmp_ctl.parseformat.parse_buffer, parse->parse_type->cl_format, sizeof(tmp_ctl.parseformat.parse_buffer));
3286 tmp_ctl.parseformat.parse_count = (u_short) strlen(tmp_ctl.parseformat.parse_buffer);
3288 if (!PARSE_SETFMT(parse, &tmp_ctl))
3290 msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: parse_setfmt() FAILED.", unit);
3291 parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
3292 return 0; /* well, ok - special initialisation broke */
3296 * get rid of all IO accumulated so far
3299 (void) tcflush(parse->generic->io.fd, TCIOFLUSH);
3301 #if defined(TCFLSH) && defined(TCIOFLUSH)
3303 int flshcmd = TCIOFLUSH;
3305 (void) ioctl(parse->generic->io.fd, TCFLSH, (caddr_t)&flshcmd);
3311 * try to do any special initializations
3313 if (parse->parse_type->cl_init)
3315 if (parse->parse_type->cl_init(parse))
3317 parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
3318 return 0; /* well, ok - special initialisation broke */
3323 * Insert in async io device list.
3325 if (!io_addclock(&parse->generic->io))
3328 "PARSE receiver #%d: parse_start: addclock %s fails (ABORT - clock type requires async io)", CLK_UNIT(parse->peer), parsedev);
3329 parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
3334 * print out configuration
3336 NLOG(NLOG_CLOCKINFO)
3338 /* conditional if clause for conditional syslog */
3339 msyslog(LOG_INFO, "PARSE receiver #%d: reference clock \"%s\" (I/O device %s, PPS device %s) added",
3340 CLK_UNIT(parse->peer),
3341 parse->parse_type->cl_description, parsedev,
3342 (parse->ppsfd != parse->generic->io.fd) ? parseppsdev : parsedev);
3344 msyslog(LOG_INFO, "PARSE receiver #%d: Stratum %d, trust time %s, precision %d",
3345 CLK_UNIT(parse->peer),
3346 parse->peer->stratum,
3347 l_mktime(parse->maxunsync), parse->peer->precision);
3349 msyslog(LOG_INFO, "PARSE receiver #%d: rootdelay %.6f s, phase adjustment %.6f s, PPS phase adjustment %.6f s, %s IO handling",
3350 CLK_UNIT(parse->peer),
3351 parse->parse_type->cl_rootdelay,
3352 parse->generic->fudgetime1,
3353 parse->ppsphaseadjust,
3354 parse->binding->bd_description);
3356 msyslog(LOG_INFO, "PARSE receiver #%d: Format recognition: %s", CLK_UNIT(parse->peer),
3357 parse->parse_type->cl_format);
3358 msyslog(LOG_INFO, "PARSE receiver #%d: %sPPS support%s", CLK_UNIT(parse->peer),
3359 CLK_PPS(parse->peer) ? "" : "NO ",
3360 CLK_PPS(parse->peer) ?
3362 " (implementation " PPS_METHOD ")"
3373 /*--------------------------------------------------
3374 * parse_ctl - process changes on flags/time values
3378 struct parseunit *parse,
3379 const struct refclockstat *in
3384 if (in->haveflags & (CLK_HAVEFLAG1|CLK_HAVEFLAG2|CLK_HAVEFLAG3|CLK_HAVEFLAG4))
3386 u_char mask = CLK_FLAG1|CLK_FLAG2|CLK_FLAG3|CLK_FLAG4;
3387 parse->flags = (parse->flags & (u_char)(~mask)) | (in->flags & mask);
3388 #if defined(HAVE_PPSAPI)
3389 if (CLK_PPS(parse->peer))
3391 parse_ppsapi(parse);
3396 if (in->haveflags & CLK_HAVETIME1)
3398 parse->generic->fudgetime1 = in->fudgetime1;
3399 msyslog(LOG_INFO, "PARSE receiver #%d: new phase adjustment %.6f s",
3400 CLK_UNIT(parse->peer),
3401 parse->generic->fudgetime1);
3404 if (in->haveflags & CLK_HAVETIME2)
3406 parse->generic->fudgetime2 = in->fudgetime2;
3407 if (parse->flags & PARSE_TRUSTTIME)
3409 parse->maxunsync = (u_long)ABS(in->fudgetime2);
3410 msyslog(LOG_INFO, "PARSE receiver #%d: new trust time %s",
3411 CLK_UNIT(parse->peer),
3412 l_mktime(parse->maxunsync));
3416 parse->ppsphaseadjust = in->fudgetime2;
3417 msyslog(LOG_INFO, "PARSE receiver #%d: new PPS phase adjustment %.6f s",
3418 CLK_UNIT(parse->peer),
3419 parse->ppsphaseadjust);
3420 #if defined(HAVE_PPSAPI)
3421 if (CLK_PPS(parse->peer))
3423 parse_ppsapi(parse);
3429 parse->generic->fudgeminjitter = in->fudgeminjitter;
3433 /*--------------------------------------------------
3434 * parse_poll - called by the transmit procedure
3442 struct parseunit *parse = peer->procptr->unitptr;
3444 if (peer != parse->peer)
3447 "PARSE receiver #%d: poll: INTERNAL: peer incorrect",
3453 * Update clock stat counters
3455 parse->generic->polls++;
3457 if (parse->pollneeddata &&
3458 ((int)(current_time - parse->pollneeddata) > (1<<(max(min(parse->peer->hpoll, parse->peer->ppoll), parse->peer->minpoll)))))
3461 * start worrying when exceeding a poll inteval
3462 * bad news - didn't get a response last time
3464 parse->lastmissed = current_time;
3465 parse_event(parse, CEVNT_TIMEOUT);
3468 msyslog(LOG_WARNING, "PARSE receiver #%d: no data from device within poll interval (check receiver / wiring)", CLK_UNIT(parse->peer));
3472 * we just mark that we want the next sample for the clock filter
3474 parse->pollneeddata = current_time;
3476 if (parse->parse_type->cl_poll)
3478 parse->parse_type->cl_poll(parse);
3481 cparse_statistics(parse);
3486 #define LEN_STATES 300 /* length of state string */
3488 /*--------------------------------------------------
3489 * parse_control - set fudge factors, return statistics
3494 const struct refclockstat *in,
3495 struct refclockstat *out,
3499 struct parseunit *parse = peer->procptr->unitptr;
3502 static char outstatus[400]; /* status output buffer */
3507 out->p_lastcode = 0;
3508 out->kv_list = (struct ctl_var *)0;
3511 if (!parse || !parse->peer)
3513 msyslog(LOG_ERR, "PARSE receiver #%d: parse_control: unit invalid (UNIT INACTIVE)",
3518 unit = CLK_UNIT(parse->peer);
3523 parse_ctl(parse, in);
3534 outstatus[0] = '\0';
3536 out->type = REFCLK_PARSE;
3539 * keep fudgetime2 in sync with TRUSTTIME/MAXUNSYNC flag1
3541 parse->generic->fudgetime2 = (parse->flags & PARSE_TRUSTTIME) ? (double)parse->maxunsync : parse->ppsphaseadjust;
3544 * figure out skew between PPS and RS232 - just for informational
3547 if (PARSE_SYNC(parse->timedata.parse_state))
3549 if (PARSE_PPS(parse->timedata.parse_state) && PARSE_TIMECODE(parse->timedata.parse_state))
3554 * we have a PPS and RS232 signal - calculate the skew
3555 * WARNING: assumes on TIMECODE == PULSE (timecode after pulse)
3557 off = parse->timedata.parse_stime.fp;
3558 L_SUB(&off, &parse->timedata.parse_ptime.fp); /* true offset */
3559 tt = add_var(&out->kv_list, 80, RO);
3560 snprintf(tt, 80, "refclock_ppsskew=%s", lfptoms(&off, 6));
3564 if (PARSE_PPS(parse->timedata.parse_state))
3566 tt = add_var(&out->kv_list, 80, RO|DEF);
3567 snprintf(tt, 80, "refclock_ppstime=\"%s\"", gmprettydate(&parse->timedata.parse_ptime.fp));
3570 start = tt = add_var(&out->kv_list, 128, RO|DEF);
3571 tt = ap(start, 128, tt, "refclock_time=\"");
3573 if (parse->timedata.parse_time.fp.l_ui == 0)
3575 tt = ap(start, 128, tt, "<UNDEFINED>\"");
3579 tt = ap(start, 128, tt, "%s\"",
3580 gmprettydate(&parse->timedata.parse_time.fp));
3583 if (!PARSE_GETTIMECODE(parse, &tmpctl))
3586 msyslog(LOG_ERR, "PARSE receiver #%d: parse_control: parse_timecode() FAILED", unit);
3590 start = tt = add_var(&out->kv_list, 512, RO|DEF);
3591 tt = ap(start, 512, tt, "refclock_status=\"");
3594 * copy PPS flags from last read transaction (informational only)
3596 tmpctl.parsegettc.parse_state |= parse->timedata.parse_state &
3597 (PARSEB_PPS|PARSEB_S_PPS);
3599 (void)parsestate(tmpctl.parsegettc.parse_state, tt, BUFFER_SIZES(start, tt, 512));
3603 tt = ap(start, 512, tt, "\"");
3605 if (tmpctl.parsegettc.parse_count)
3606 mkascii(outstatus+strlen(outstatus), (int)(sizeof(outstatus)- strlen(outstatus) - 1),
3607 tmpctl.parsegettc.parse_buffer, (unsigned)(tmpctl.parsegettc.parse_count));
3611 tmpctl.parseformat.parse_format = tmpctl.parsegettc.parse_format;
3613 if (!PARSE_GETFMT(parse, &tmpctl))
3616 msyslog(LOG_ERR, "PARSE receiver #%d: parse_control: parse_getfmt() FAILED", unit);
3620 int count = tmpctl.parseformat.parse_count;
3624 start = tt = add_var(&out->kv_list, 80, RO|DEF);
3625 tt = ap(start, 80, tt, "refclock_format=\"");
3628 tt = ap(start, 80, tt, "%*.*s",
3631 tmpctl.parseformat.parse_buffer);
3634 tt = ap(start, 80, tt, "\"");
3638 * gather state statistics
3641 start = tt = add_var(&out->kv_list, LEN_STATES, RO|DEF);
3642 tt = ap(start, LEN_STATES, tt, "refclock_states=\"");
3644 for (i = 0; i <= CEVNT_MAX; i++)
3647 u_long d = current_time - parse->generic->timestarted;
3650 percent = s_time = PARSE_STATETIME(parse, i);
3652 while (((u_long)(~0) / 10000) < percent)
3659 percent = (percent * 10000) / d;
3668 snprintf(item, 80, "%s%s%s: %s (%d.%02d%%)",
3670 (parse->generic->currentstatus == i) ? "*" : "",
3671 clockstatus((unsigned int)i),
3673 (int)(percent / 100), (int)(percent % 100));
3674 if ((count = (int) strlen(item)) < (LEN_STATES - 40 - (tt - start)))
3676 tt = ap(start, LEN_STATES, tt,
3683 ap(start, LEN_STATES, tt, "; running time: %s\"", l_mktime(sum));
3685 tt = add_var(&out->kv_list, 32, RO);
3686 snprintf(tt, 32, "refclock_id=\"%s\"", parse->parse_type->cl_id);
3688 tt = add_var(&out->kv_list, 80, RO);
3689 snprintf(tt, 80, "refclock_iomode=\"%s\"", parse->binding->bd_description);
3691 tt = add_var(&out->kv_list, 128, RO);
3692 snprintf(tt, 128, "refclock_driver_version=\"%s\"", rcsid);
3698 while (k && !(k->flags & EOV))
3700 set_var(&out->kv_list, k->text, strlen(k->text)+1, k->flags);
3705 out->lencode = (u_short) strlen(outstatus);
3706 out->p_lastcode = outstatus;
3710 /**===========================================================================
3711 ** processing routines
3714 /*--------------------------------------------------
3715 * event handling - note that nominal events will also be posted
3716 * keep track of state dwelling times
3720 struct parseunit *parse,
3724 if (parse->generic->currentstatus != (u_char) event)
3726 parse->statetime[parse->generic->currentstatus] += current_time - parse->lastchange;
3727 parse->lastchange = current_time;
3729 if (parse->parse_type->cl_event)
3730 parse->parse_type->cl_event(parse, event);
3732 if (event == CEVNT_NOMINAL)
3734 NLOG(NLOG_CLOCKSTATUS)
3735 msyslog(LOG_INFO, "PARSE receiver #%d: SYNCHRONIZED",
3736 CLK_UNIT(parse->peer));
3739 refclock_report(parse->peer, event);
3743 /*--------------------------------------------------
3744 * process a PARSE time sample
3748 struct parseunit *parse,
3749 parsetime_t *parsetime
3752 l_fp off, rectime, reftime;
3755 /* silence warning: 'off.Ul_i.Xl_i' may be used uninitialized in this function */
3759 * check for changes in conversion status
3760 * (only one for each new status !)
3762 if (((parsetime->parse_status & CVT_MASK) != CVT_OK) &&
3763 ((parsetime->parse_status & CVT_MASK) != CVT_NONE) &&
3764 (parse->timedata.parse_status != parsetime->parse_status))
3768 NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */
3769 msyslog(LOG_WARNING, "PARSE receiver #%d: conversion status \"%s\"",
3770 CLK_UNIT(parse->peer), parsestatus(parsetime->parse_status, buffer, sizeof(buffer)));
3772 if ((parsetime->parse_status & CVT_MASK) == CVT_FAIL)
3775 * tell more about the story - list time code
3776 * there is a slight change for a race condition and
3777 * the time code might be overwritten by the next packet
3781 if (!PARSE_GETTIMECODE(parse, &tmpctl))
3784 msyslog(LOG_ERR, "PARSE receiver #%d: parse_process: parse_timecode() FAILED", CLK_UNIT(parse->peer));
3788 unsigned int count = tmpctl.parsegettc.parse_count;
3792 msyslog(LOG_WARNING, "PARSE receiver #%d: FAILED TIMECODE: \"%s\" (check receiver configuration / wiring)",
3793 CLK_UNIT(parse->peer),
3794 mkascii(buffer, sizeof(buffer),
3795 tmpctl.parsegettc.parse_buffer, count));
3797 /* copy status to show only changes in case of failures */
3798 parse->timedata.parse_status = parsetime->parse_status;
3803 * examine status and post appropriate events
3805 if ((parsetime->parse_status & CVT_MASK) != CVT_OK)
3808 * got bad data - tell the rest of the system
3810 switch (parsetime->parse_status & CVT_MASK)
3813 if ((parsetime->parse_status & CVT_ADDITIONAL) &&
3814 parse->parse_type->cl_message)
3815 parse->parse_type->cl_message(parse, parsetime);
3817 * save PPS information that comes piggyback
3819 if (PARSE_PPS(parsetime->parse_state))
3821 parse->timedata.parse_state |= PARSEB_PPS|PARSEB_S_PPS;
3822 parse->timedata.parse_ptime = parsetime->parse_ptime;
3824 break; /* well, still waiting - timeout is handled at higher levels */
3827 if (parsetime->parse_status & CVT_BADFMT)
3829 parse_event(parse, CEVNT_BADREPLY);
3832 if (parsetime->parse_status & CVT_BADDATE)
3834 parse_event(parse, CEVNT_BADDATE);
3837 if (parsetime->parse_status & CVT_BADTIME)
3839 parse_event(parse, CEVNT_BADTIME);
3843 parse_event(parse, CEVNT_BADREPLY); /* for the lack of something better */
3846 return; /* skip the rest - useless */
3850 * check for format changes
3851 * (in case somebody has swapped clocks 8-)
3853 if (parse->lastformat != parsetime->parse_format)
3857 tmpctl.parseformat.parse_format = parsetime->parse_format;
3859 if (!PARSE_GETFMT(parse, &tmpctl))
3862 msyslog(LOG_ERR, "PARSE receiver #%d: parse_getfmt() FAILED", CLK_UNIT(parse->peer));
3866 NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */
3867 msyslog(LOG_INFO, "PARSE receiver #%d: packet format \"%s\"",
3868 CLK_UNIT(parse->peer), tmpctl.parseformat.parse_buffer);
3870 parse->lastformat = parsetime->parse_format;
3874 * now, any changes ?
3876 if ((parse->timedata.parse_state ^ parsetime->parse_state) &
3877 ~(unsigned)(PARSEB_PPS|PARSEB_S_PPS))
3882 * something happend - except for PPS events
3885 (void) parsestate(parsetime->parse_state, tmp1, sizeof(tmp1));
3886 (void) parsestate(parse->timedata.parse_state, tmp2, sizeof(tmp2));
3888 NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */
3889 msyslog(LOG_INFO,"PARSE receiver #%d: STATE CHANGE: %s -> %s",
3890 CLK_UNIT(parse->peer), tmp2, tmp1);
3894 * carry on PPS information if still usable
3896 if (PARSE_PPS(parse->timedata.parse_state) && !PARSE_PPS(parsetime->parse_state))
3898 parsetime->parse_state |= PARSEB_PPS|PARSEB_S_PPS;
3899 parsetime->parse_ptime = parse->timedata.parse_ptime;
3903 * remember for future
3905 parse->timedata = *parsetime;
3908 * check to see, whether the clock did a complete powerup or lost PZF signal
3909 * and post correct events for current condition
3911 if (PARSE_POWERUP(parsetime->parse_state))
3914 * this is bad, as we have completely lost synchronisation
3915 * well this is a problem with the receiver here
3916 * for PARSE Meinberg DCF77 receivers the lost synchronisation
3917 * is true as it is the powerup state and the time is taken
3918 * from a crude real time clock chip
3919 * for the PZF/GPS series this is only partly true, as
3920 * PARSE_POWERUP only means that the pseudo random
3921 * phase shift sequence cannot be found. this is only
3922 * bad, if we have never seen the clock in the SYNC
3923 * state, where the PHASE and EPOCH are correct.
3924 * for reporting events the above business does not
3925 * really matter, but we can use the time code
3926 * even in the POWERUP state after having seen
3927 * the clock in the synchronized state (PZF class
3928 * receivers) unless we have had a telegram disruption
3929 * after having seen the clock in the SYNC state. we
3930 * thus require having seen the clock in SYNC state
3931 * *after* having missed telegrams (noresponse) from
3932 * the clock. one problem remains: we might use erroneously
3933 * POWERUP data if the disruption is shorter than 1 polling
3934 * interval. fortunately powerdowns last usually longer than 64
3935 * seconds and the receiver is at least 2 minutes in the
3936 * POWERUP or NOSYNC state before switching to SYNC
3937 * for GPS receivers this can mean antenna problems and other causes.
3938 * the additional grace period can be enables by a clock
3939 * mode having the PARSE_F_POWERUPTRUST flag in cl_flag set.
3941 parse_event(parse, CEVNT_FAULT);
3942 NLOG(NLOG_CLOCKSTATUS)
3944 msyslog(LOG_ERR,"PARSE receiver #%d: NOT SYNCHRONIZED/RECEIVER PROBLEMS",
3945 CLK_UNIT(parse->peer));
3950 * we have two states left
3953 * this state means that the EPOCH (timecode) and PHASE
3954 * information has be read correctly (at least two
3955 * successive PARSE timecodes were received correctly)
3956 * this is the best possible state - full trust
3959 * The clock should be on phase with respect to the second
3960 * signal, but the timecode has not been received correctly within
3961 * at least the last two minutes. this is a sort of half baked state
3962 * for PARSE Meinberg DCF77 clocks this is bad news (clock running
3963 * without timecode confirmation)
3964 * PZF 535 has also no time confirmation, but the phase should be
3965 * very precise as the PZF signal can be decoded
3968 if (PARSE_SYNC(parsetime->parse_state))
3971 * currently completely synchronized - best possible state
3973 parse->lastsync = current_time;
3974 clear_err(parse, ERR_BADSTATUS);
3979 * we have had some problems receiving the time code
3981 parse_event(parse, CEVNT_PROP);
3982 NLOG(NLOG_CLOCKSTATUS)
3984 msyslog(LOG_ERR,"PARSE receiver #%d: TIMECODE NOT CONFIRMED",
3985 CLK_UNIT(parse->peer));
3989 fudge = parse->generic->fudgetime1; /* standard RS232 Fudgefactor */
3991 if (PARSE_TIMECODE(parsetime->parse_state))
3993 rectime = parsetime->parse_stime.fp;
3994 off = reftime = parsetime->parse_time.fp;
3996 L_SUB(&off, &rectime); /* prepare for PPS adjustments logic */
4000 printf("PARSE receiver #%d: Reftime %s, Recvtime %s - initial offset %s\n",
4001 CLK_UNIT(parse->peer),
4002 prettydate(&reftime),
4003 prettydate(&rectime),
4008 if (PARSE_PPS(parsetime->parse_state) && CLK_PPS(parse->peer))
4011 double ppsphaseadjust = parse->ppsphaseadjust;
4015 * set fudge = 0.0 if already included in PPS time stamps
4017 if (parse->atom.pps_params.mode & (PPS_OFFSETCLEAR|PPS_OFFSETASSERT))
4019 ppsphaseadjust = 0.0;
4024 * we have a PPS signal - much better than the RS232 stuff (we hope)
4026 offset = parsetime->parse_ptime.fp;
4030 printf("PARSE receiver #%d: PPStime %s\n",
4031 CLK_UNIT(parse->peer),
4032 prettydate(&offset));
4034 if (PARSE_TIMECODE(parsetime->parse_state))
4036 if (M_ISGEQ(off.l_i, off.l_uf, -1, 0x80000000) &&
4037 M_ISGEQ(0, 0x7fffffff, off.l_i, off.l_uf))
4039 fudge = ppsphaseadjust; /* pick PPS fudge factor */
4042 * RS232 offsets within [-0.5..0.5[ - take PPS offsets
4045 if (parse->parse_type->cl_flags & PARSE_F_PPSONSECOND)
4047 reftime = off = offset;
4048 if (reftime.l_uf & 0x80000000)
4054 * implied on second offset
4056 off.l_uf = ~off.l_uf; /* map [0.5..1[ -> [-0.5..0[ */
4057 off.l_i = (off.l_uf & 0x80000000) ? -1 : 0; /* sign extend */
4062 * time code describes pulse
4064 reftime = off = parsetime->parse_time.fp;
4066 L_SUB(&off, &offset); /* true offset */
4070 * take RS232 offset when PPS when out of bounds
4075 fudge = ppsphaseadjust; /* pick PPS fudge factor */
4077 * Well, no time code to guide us - assume on second pulse
4078 * and pray, that we are within [-0.5..0.5[
4082 if (reftime.l_uf & 0x80000000)
4086 * implied on second offset
4088 off.l_uf = ~off.l_uf; /* map [0.5..1[ -> [-0.5..0[ */
4089 off.l_i = (off.l_uf & 0x80000000) ? -1 : 0; /* sign extend */
4094 if (!PARSE_TIMECODE(parsetime->parse_state))
4097 * Well, no PPS, no TIMECODE, no more work ...
4099 if ((parsetime->parse_status & CVT_ADDITIONAL) &&
4100 parse->parse_type->cl_message)
4101 parse->parse_type->cl_message(parse, parsetime);
4108 printf("PARSE receiver #%d: Reftime %s, Recvtime %s - final offset %s\n",
4109 CLK_UNIT(parse->peer),
4110 prettydate(&reftime),
4111 prettydate(&rectime),
4117 L_SUB(&rectime, &off); /* just to keep the ntp interface happy */
4121 printf("PARSE receiver #%d: calculated Reftime %s, Recvtime %s\n",
4122 CLK_UNIT(parse->peer),
4123 prettydate(&reftime),
4124 prettydate(&rectime));
4127 if ((parsetime->parse_status & CVT_ADDITIONAL) &&
4128 parse->parse_type->cl_message)
4129 parse->parse_type->cl_message(parse, parsetime);
4131 if (PARSE_SYNC(parsetime->parse_state))
4136 parse_event(parse, CEVNT_NOMINAL);
4139 clear_err(parse, ERR_BADIO);
4140 clear_err(parse, ERR_BADDATA);
4141 clear_err(parse, ERR_NODATA);
4142 clear_err(parse, ERR_INTERNAL);
4145 * and now stick it into the clock machine
4146 * samples are only valid iff lastsync is not too old and
4147 * we have seen the clock in sync at least once
4148 * after the last time we didn't see an expected data telegram
4149 * at startup being not in sync is also bad just like
4150 * POWERUP state unless PARSE_F_POWERUPTRUST is set
4151 * see the clock states section above for more reasoning
4153 if (((current_time - parse->lastsync) > parse->maxunsync) ||
4154 (parse->lastsync < parse->lastmissed) ||
4155 ((parse->lastsync == 0) && !PARSE_SYNC(parsetime->parse_state)) ||
4156 (((parse->parse_type->cl_flags & PARSE_F_POWERUPTRUST) == 0) &&
4157 PARSE_POWERUP(parsetime->parse_state)))
4159 parse->generic->leap = LEAP_NOTINSYNC;
4160 parse->lastsync = 0; /* wait for full sync again */
4164 if (PARSE_LEAPADD(parsetime->parse_state))
4167 * we pick this state also for time code that pass leap warnings
4168 * without direction information (as earth is currently slowing
4171 parse->generic->leap = (parse->flags & PARSE_LEAP_DELETE) ? LEAP_DELSECOND : LEAP_ADDSECOND;
4174 if (PARSE_LEAPDEL(parsetime->parse_state))
4176 parse->generic->leap = LEAP_DELSECOND;
4180 parse->generic->leap = LEAP_NOWARNING;
4184 if (parse->generic->leap != LEAP_NOTINSYNC)
4187 * only good/trusted samples are interesting
4192 printf("PARSE receiver #%d: refclock_process_offset(reftime=%s, rectime=%s, Fudge=%f)\n",
4193 CLK_UNIT(parse->peer),
4194 prettydate(&reftime),
4195 prettydate(&rectime),
4199 parse->generic->lastref = reftime;
4201 refclock_process_offset(parse->generic, reftime, rectime, fudge);
4205 * pass PPS information on to PPS clock
4207 if (PARSE_PPS(parsetime->parse_state) && CLK_PPS(parse->peer))
4209 parse->peer->flags |= (FLAG_PPS | FLAG_TSTAMP_PPS);
4210 parse_hardpps(parse, PARSE_HARDPPS_ENABLE);
4214 parse_hardpps(parse, PARSE_HARDPPS_DISABLE);
4215 parse->peer->flags &= ~(FLAG_PPS | FLAG_TSTAMP_PPS);
4219 * ready, unless the machine wants a sample or
4220 * we are in fast startup mode (peer->dist > MAXDISTANCE)
4222 if (!parse->pollneeddata && parse->peer->disp <= MAXDISTANCE)
4225 parse->pollneeddata = 0;
4227 parse->timedata.parse_state &= ~(unsigned)(PARSEB_PPS|PARSEB_S_PPS);
4229 refclock_receive(parse->peer);
4232 /**===========================================================================
4233 ** special code for special clocks
4238 char *t, /* pointer to the output string buffer */
4244 int size /* size of the output string buffer */
4248 * The week number transmitted by the GPS satellites for the leap date
4249 * is truncated to 8 bits only. If the nearest leap second date is off
4250 * the current date by more than +/- 128 weeks then conversion to a
4251 * calendar date is ambiguous. On the other hand, if a leap second is
4252 * currently being announced (i.e. dtlsf != dtls) then the week number
4253 * wnlsf is close enough, and we can unambiguously determine the date
4254 * for which the leap second is scheduled.
4256 if ( dtlsf != dtls )
4262 wnlsf = basedate_expand_gpsweek(wnlsf);
4263 /* 'wnt' not used here: would need the same treatment as 'wnlsf */
4265 t_ls = (time_t) wnlsf * SECSPERWEEK
4266 + (time_t) dn * SECSPERDAY
4269 tm = gmtime( &t_ls );
4270 if (tm == NULL) /* gmtime() failed */
4272 snprintf( t, size, "** (gmtime() failed in mk_utcinfo())" );
4276 nc = snprintf( t, size, "UTC offset transition from %is to %is due to leap second %s",
4277 dtls, dtlsf, ( dtls < dtlsf ) ? "insertion" : "deletion" );
4283 snprintf( t + nc, size - nc, " at UTC midnight at the end of %s, %04i-%02i-%02i",
4284 daynames[tm->tm_wday], tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday );
4288 snprintf( t, size, "UTC offset parameter: %is, no leap second announced.\n", dtls );
4293 #ifdef CLOCK_MEINBERG
4294 /**===========================================================================
4295 ** Meinberg GPS receiver support
4298 /*------------------------------------------------------------
4299 * gps16x_message - process messages from Meinberg GPS receiver
4303 struct parseunit *parse,
4304 parsetime_t *parsetime
4307 if (parse->timedata.parse_msglen && parsetime->parse_msg[0] == SOH)
4310 unsigned char *bufp = (unsigned char *)parsetime->parse_msg + 1;
4315 char msgbuffer[600];
4317 mkreadable(msgbuffer, sizeof(msgbuffer), (char *)parsetime->parse_msg, parsetime->parse_msglen, 1);
4318 printf("PARSE receiver #%d: received message (%d bytes) >%s<\n",
4319 CLK_UNIT(parse->peer),
4320 parsetime->parse_msglen,
4324 get_mbg_header(&bufp, &header);
4325 if (header.hdr_csum == mbg_csum(parsetime->parse_msg + 1, 6) &&
4327 (header.len < sizeof(parsetime->parse_msg) &&
4328 header.data_csum == mbg_csum(bufp, header.len))))
4340 get_mbg_sw_rev(&bufp, &gps_sw_rev);
4341 snprintf(buffer, sizeof(buffer), "meinberg_gps_version=\"%x.%02x%s%s\"",
4342 (gps_sw_rev.code >> 8) & 0xFF,
4343 gps_sw_rev.code & 0xFF,
4344 gps_sw_rev.name[0] ? " " : "",
4346 set_var(&parse->kv, buffer, strlen(buffer)+1, RO|DEF);
4354 BVAR_STAT flag; /* status flag */
4355 const char *string; /* bit name */
4358 { BVAR_CFGH_INVALID, "Configuration/Health" },
4359 { BVAR_ALM_NOT_COMPLETE, "Almanachs" },
4360 { BVAR_UTC_INVALID, "UTC Correction" },
4361 { BVAR_IONO_INVALID, "Ionospheric Correction" },
4362 { BVAR_RCVR_POS_INVALID, "Receiver Position" },
4366 struct state *s = states;
4370 status = (BVAR_STAT) get_lsb_short(&bufp);
4372 p = ap(buffer, sizeof(buffer), p,
4373 "meinberg_gps_status=\"[0x%04x] ",
4378 p = ap(buffer, sizeof(buffer), p, "incomplete buffered data: ");
4382 if (status & s->flag)
4386 p = ap(buffer, sizeof(buffer), p, ", ");
4389 p = ap(buffer, sizeof(buffer), p, "%s", (const char *)s->string);
4393 p = ap(buffer, sizeof(buffer), p, "\"");
4397 p = ap(buffer, sizeof(buffer), p, "<all buffered data complete>\"");
4400 set_var(&parse->kv, buffer, strlen(buffer)+1, RO|DEF);
4409 get_mbg_xyz(&bufp, xyz);
4410 snprintf(buffer, sizeof(buffer), "gps_position(XYZ)=\"%s m, %s m, %s m\"",
4411 mfptoa(xyz[XP].l_ui, xyz[XP].l_uf, 1),
4412 mfptoa(xyz[YP].l_ui, xyz[YP].l_uf, 1),
4413 mfptoa(xyz[ZP].l_ui, xyz[ZP].l_uf, 1));
4415 set_var(&parse->kv, buffer, sizeof(buffer), RO|DEF);
4424 get_mbg_lla(&bufp, lla);
4426 snprintf(buffer, sizeof(buffer), "gps_position(LLA)=\"%s deg, %s deg, %s m\"",
4427 mfptoa(lla[LAT].l_ui, lla[LAT].l_uf, 4),
4428 mfptoa(lla[LON].l_ui, lla[LON].l_uf, 4),
4429 mfptoa(lla[ALT].l_ui, lla[ALT].l_uf, 1));
4431 set_var(&parse->kv, buffer, sizeof(buffer), RO|DEF);
4450 get_mbg_antinfo(&bufp, &antinfo);
4452 p = ap(buffer, sizeof(buffer), p, "meinberg_antenna_status=\"");
4453 switch (antinfo.status)
4455 case ANT_INVALID: // No other fields valid since antenna has not yet been disconnected
4456 p = ap(buffer, sizeof(buffer),
4460 case ANT_DISCONN: // Antenna is disconnected, tm_reconn and delta_t not yet set
4461 q = ap(buffer, sizeof(buffer),
4462 p, "DISCONNECTED since ");
4463 NLOG(NLOG_CLOCKSTATUS)
4465 msyslog(LOG_ERR,"PARSE receiver #%d: ANTENNA FAILURE: %s",
4466 CLK_UNIT(parse->peer), p);
4469 mbg_tm_str(&p, &antinfo.tm_disconn, BUFFER_SIZE(buffer, p), 0);
4473 case ANT_RECONN: // Antenna had been disconnect, but receiver sync. after reconnect, so all fields valid
4474 p = ap(buffer, sizeof(buffer),
4475 p, "SYNC AFTER RECONNECT on ");
4476 mbg_tm_str(&p, &antinfo.tm_reconn, BUFFER_SIZE(buffer, p), 0);
4477 p = ap(buffer, sizeof(buffer),
4478 p, ", clock offset at reconnect %c%ld.%07ld s, disconnect time ",
4479 (antinfo.delta_t < 0) ? '-' : '+',
4480 (long) ABS(antinfo.delta_t) / 10000,
4481 (long) ABS(antinfo.delta_t) % 10000);
4482 mbg_tm_str(&p, &antinfo.tm_disconn, BUFFER_SIZE(buffer, p), 0);
4487 p = ap(buffer, sizeof(buffer),
4488 p, "bad status 0x%04x",
4493 p = ap(buffer, sizeof(buffer), p, "\"");
4495 set_var(&parse->kv, buffer, sizeof(buffer), RO|DEF);
4508 get_mbg_cfgh(&bufp, &cfgh);
4516 p = ap(buffer, sizeof(buffer),
4517 p, "gps_tot_51=\"");
4518 mbg_tgps_str(&p, &cfgh.tot_51, BUFFER_SIZE(buffer, p));
4519 p = ap(buffer, sizeof(buffer),
4521 set_var(&parse->kv, buffer, sizeof(buffer), RO|COND_DEF);
4524 p = ap(buffer, sizeof(buffer),
4525 p, "gps_tot_63=\"");
4526 mbg_tgps_str(&p, &cfgh.tot_63, BUFFER_SIZE(buffer, p));
4527 p = ap(buffer, sizeof(buffer),
4529 set_var(&parse->kv, buffer, sizeof(buffer), RO|COND_DEF);
4532 p = ap(buffer, sizeof(buffer),
4534 mbg_tgps_str(&p, &cfgh.t0a, BUFFER_SIZE(buffer, p));
4535 p = ap(buffer, sizeof(buffer),
4537 set_var(&parse->kv, buffer, sizeof(buffer), RO|COND_DEF);
4539 for (i = 0; i < N_SVNO_GPS; i++)
4542 p = ap(buffer, sizeof(buffer), p, "sv_info[%d]=\"PRN%d", i, i + N_SVNO_GPS);
4544 tmp_val = cfgh.health[i]; /* a 6 bit SV health code */
4545 p = ap(buffer, sizeof(buffer), p, "; health=0x%02x (", tmp_val);
4546 /* "All Ones" has a special meaning" */
4547 if (tmp_val == 0x3F) /* satellite is unusable or doesn't even exist */
4548 cp = "SV UNAVAILABLE";
4550 /* The MSB contains a summary of the 3 MSBs of the 8 bit health code,
4551 * indicating if the data sent by the satellite is OK or not. */
4552 p = ap(buffer, sizeof(buffer), p, "DATA %s, ", (tmp_val & 0x20) ? "BAD" : "OK" );
4554 /* The 5 LSBs contain the status of the different signals sent by the satellite. */
4555 switch (tmp_val & 0x1F)
4557 case 0x00: cp = "SIGNAL OK"; break;
4558 /* codes 0x01 through 0x1B indicate that one or more
4559 * specific signal components are weak or dead.
4560 * We don't decode this here in detail. */
4561 case 0x1C: cp = "SV IS TEMP OUT"; break;
4562 case 0x1D: cp = "SV WILL BE TEMP OUT"; break;
4563 default: cp = "TRANSMISSION PROBLEMS"; break;
4566 p = ap(buffer, sizeof(buffer), p, "%s)", cp );
4568 tmp_val = cfgh.cfg[i]; /* a 4 bit SV configuration/type code */
4569 p = ap(buffer, sizeof(buffer), p, "; cfg=0x%02x (", tmp_val);
4570 switch (tmp_val & 0x7)
4572 case 0x00: cp = "(reserved)"; break;
4573 case 0x01: cp = "BLOCK II/IIA/IIR"; break;
4574 case 0x02: cp = "BLOCK IIR-M"; break;
4575 case 0x03: cp = "BLOCK IIF"; break;
4576 case 0x04: cp = "BLOCK III"; break;
4577 default: cp = "unknown SV type"; break;
4579 p = ap(buffer, sizeof(buffer), p, "%s", cp );
4580 if (tmp_val & 0x08) /* A-S is on, P-code is encrypted */
4581 p = ap( buffer, sizeof(buffer), p, ", A-S on" );
4583 p = ap(buffer, sizeof(buffer), p, ")\"");
4584 set_var(&parse->kv, buffer, sizeof(buffer), RO|COND_DEF);
4604 get_mbg_utc(&bufp, &utc);
4608 p = ap(buffer, sizeof(buffer), p, "gps_utc_correction=\"");
4609 mk_utcinfo(p, utc.t0t.wn, utc.WNlsf, utc.DNt, utc.delta_tls, utc.delta_tlsf, BUFFER_SIZE(buffer, p));
4611 p = ap(buffer, sizeof(buffer), p, "\"");
4615 p = ap(buffer, sizeof(buffer), p, "gps_utc_correction=\"<NO UTC DATA>\"");
4617 set_var(&parse->kv, buffer, sizeof(buffer), RO|DEF);
4626 ASCII_MSG gps_ascii_msg;
4629 get_mbg_ascii_msg(&bufp, &gps_ascii_msg);
4631 if (gps_ascii_msg.valid)
4634 mkreadable(buffer1, sizeof(buffer1), gps_ascii_msg.s, strlen(gps_ascii_msg.s), (int)0);
4636 snprintf(buffer, sizeof(buffer), "gps_message=\"%s\"", buffer1);
4639 snprintf(buffer, sizeof(buffer), "gps_message=<NONE>");
4641 set_var(&parse->kv, buffer, sizeof(buffer), RO|DEF);
4652 msyslog(LOG_DEBUG, "PARSE receiver #%d: gps16x_message: message checksum error: hdr_csum = 0x%x (expected 0x%x), "
4653 "data_len = %d, data_csum = 0x%x (expected 0x%x)",
4654 CLK_UNIT(parse->peer),
4655 header.hdr_csum, mbg_csum(parsetime->parse_msg + 1, 6),
4657 header.data_csum, mbg_csum(bufp, (unsigned)((header.len < sizeof(parsetime->parse_msg)) ? header.len : 0)));
4664 /*------------------------------------------------------------
4665 * gps16x_poll - query the reciver peridically
4672 struct parseunit *parse = peer->procptr->unitptr;
4674 static GPS_MSG_HDR sequence[] =
4676 { GPS_SW_REV, 0, 0, 0 },
4677 { GPS_BVAR_STAT, 0, 0, 0 },
4678 { GPS_UTC, 0, 0, 0 },
4679 { GPS_ASCII_MSG, 0, 0, 0 },
4680 { GPS_ANT_INFO, 0, 0, 0 },
4681 { GPS_CFGH, 0, 0, 0 },
4682 { GPS_POS_XYZ, 0, 0, 0 },
4683 { GPS_POS_LLA, 0, 0, 0 },
4684 { (unsigned short)~0, 0, 0, 0 }
4688 unsigned char cmd_buffer[64];
4689 unsigned char *outp = cmd_buffer;
4690 GPS_MSG_HDR *header;
4692 if (((poll_info_t *)parse->parse_type->cl_data)->rate)
4694 parse->peer->procptr->nextaction = current_time + ((poll_info_t *)parse->parse_type->cl_data)->rate;
4697 if (sequence[parse->localstate].cmd == (unsigned short)~0)
4698 parse->localstate = 0;
4700 header = sequence + parse->localstate++;
4702 *outp++ = SOH; /* start command */
4704 put_mbg_header(&outp, header);
4705 outp = cmd_buffer + 1;
4707 header->hdr_csum = (short)mbg_csum(outp, 6);
4708 put_mbg_header(&outp, header);
4715 mkreadable(buffer, sizeof(buffer), (char *)cmd_buffer, (unsigned)(outp - cmd_buffer), 1);
4716 printf("PARSE receiver #%d: transmitted message #%ld (%d bytes) >%s<\n",
4717 CLK_UNIT(parse->peer),
4718 parse->localstate - 1,
4719 (int)(outp - cmd_buffer),
4724 rtc = (int) write(parse->generic->io.fd, cmd_buffer, (unsigned long)(outp - cmd_buffer));
4729 msyslog(LOG_ERR, "PARSE receiver #%d: gps16x_poll: failed to send cmd to clock: %m", CLK_UNIT(parse->peer));
4732 if (rtc != outp - cmd_buffer)
4735 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));
4738 clear_err(parse, ERR_BADIO);
4742 /*--------------------------------------------------
4743 * init routine - setup timer
4747 struct parseunit *parse
4750 if (((poll_info_t *)parse->parse_type->cl_data)->rate)
4752 parse->peer->procptr->action = gps16x_poll;
4753 gps16x_poll(parse->peer);
4762 struct parseunit *parse,
4763 parsetime_t *parsetime
4768 struct parseunit *parse
4773 #endif /* CLOCK_MEINBERG */
4775 /**===========================================================================
4776 ** clock polling support
4779 /*--------------------------------------------------
4780 * direct poll routine
4784 struct parseunit *parse
4788 const char *ps = ((poll_info_t *)parse->parse_type->cl_data)->string;
4789 long ct = ((poll_info_t *)parse->parse_type->cl_data)->count;
4791 rtc = write(parse->generic->io.fd, ps, ct);
4795 msyslog(LOG_ERR, "PARSE receiver #%d: poll_dpoll: failed to send cmd to clock: %m", CLK_UNIT(parse->peer));
4801 msyslog(LOG_ERR, "PARSE receiver #%d: poll_dpoll: failed to send cmd incomplete (%ld of %ld bytes sent)", CLK_UNIT(parse->peer), rtc, ct);
4803 clear_err(parse, ERR_BADIO);
4806 /*--------------------------------------------------
4807 * periodic poll routine
4814 struct parseunit *parse = peer->procptr->unitptr;
4816 if (parse->parse_type->cl_poll)
4817 parse->parse_type->cl_poll(parse);
4819 if (((poll_info_t *)parse->parse_type->cl_data)->rate)
4821 parse->peer->procptr->nextaction = current_time + ((poll_info_t *)parse->parse_type->cl_data)->rate;
4825 /*--------------------------------------------------
4826 * init routine - setup timer
4830 struct parseunit *parse
4833 if (((poll_info_t *)parse->parse_type->cl_data)->rate)
4835 parse->peer->procptr->action = poll_poll;
4836 poll_poll(parse->peer);
4842 /**===========================================================================
4846 /*-------------------------------------------------------------
4847 * trimble TAIP init routine - setup EOL and then do poll_init.
4851 struct parseunit *parse
4857 #ifdef HAVE_SYSV_TTYS
4861 * configure terminal line for trimble receiver
4863 if (TTY_GETATTR(parse->generic->io.fd, &tio) == -1)
4865 msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_init: tcgetattr(fd, &tio): %m", CLK_UNIT(parse->peer));
4870 tio.c_cc[VEOL] = TRIMBLETAIP_EOL;
4872 if (TTY_SETATTR(parse->generic->io.fd, &tio) == -1)
4874 msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_init: tcsetattr(fd, &tio): %m", CLK_UNIT(parse->peer));
4878 return poll_init(parse);
4881 /*--------------------------------------------------
4882 * trimble TAIP event routine - reset receiver upon data format trouble
4884 static const char *taipinit[] = {
4886 ">SRM;ID_FLAG=F;CS_FLAG=T;EC_FLAG=F;FR_FLAG=T;CR_FLAG=F<",
4893 struct parseunit *parse,
4899 case CEVNT_BADREPLY: /* reset on garbled input */
4900 case CEVNT_TIMEOUT: /* reset on no input */
4907 int rtc = (int) write(parse->generic->io.fd, *iv, strlen(*iv));
4910 msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_event: failed to send cmd to clock: %m", CLK_UNIT(parse->peer));
4915 if (rtc != (int)strlen(*iv))
4917 msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_event: failed to send cmd incomplete (%d of %d bytes sent)",
4918 CLK_UNIT(parse->peer), rtc, (int)strlen(*iv));
4925 NLOG(NLOG_CLOCKINFO)
4927 msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_event: RECEIVER INITIALIZED",
4928 CLK_UNIT(parse->peer));
4932 default: /* ignore */
4938 * This driver supports the Trimble SVee Six Plus GPS receiver module.
4939 * It should support other Trimble receivers which use the Trimble Standard
4940 * Interface Protocol (see below).
4942 * The module has a serial I/O port for command/data and a 1 pulse-per-second
4943 * output, about 1 microsecond wide. The leading edge of the pulse is
4944 * coincident with the change of the GPS second. This is the same as
4945 * the change of the UTC second +/- ~1 microsecond. Some other clocks
4946 * specifically use a feature in the data message as a timing reference, but
4947 * the SVee Six Plus does not do this. In fact there is considerable jitter
4948 * on the timing of the messages, so this driver only supports the use
4949 * of the PPS pulse for accurate timing. Where it is determined that
4950 * the offset is way off, when first starting up ntpd for example,
4951 * the timing of the data stream is used until the offset becomes low enough
4952 * (|offset| < CLOCK_MAX), at which point the pps offset is used.
4954 * It can use either option for receiving PPS information - the 'ppsclock'
4955 * stream pushed onto the serial data interface to timestamp the Carrier
4956 * Detect interrupts, where the 1PPS connects to the CD line. This only
4957 * works on SunOS 4.1.x currently. To select this, define PPSPPS in
4958 * Config.local. The other option is to use a pulse-stretcher/level-converter
4959 * to convert the PPS pulse into a RS232 start pulse & feed this into another
4960 * tty port. To use this option, define PPSCLK in Config.local. The pps input,
4961 * by whichever method, is handled in ntp_loopfilter.c
4963 * The receiver uses a serial message protocol called Trimble Standard
4964 * Interface Protocol (it can support others but this driver only supports
4965 * TSIP). Messages in this protocol have the following form:
4967 * <DLE><id> ... <data> ... <DLE><ETX>
4969 * Any bytes within the <data> portion of value 10 hex (<DLE>) are doubled
4970 * on transmission and compressed back to one on reception. Otherwise
4971 * the values of data bytes can be anything. The serial interface is RS-422
4972 * asynchronous using 9600 baud, 8 data bits with odd party (**note** 9 bits
4973 * in total!), and 1 stop bit. The protocol supports byte, integer, single,
4974 * and double datatypes. Integers are two bytes, sent most significant first.
4975 * Singles are IEEE754 single precision floating point numbers (4 byte) sent
4976 * sign & exponent first. Doubles are IEEE754 double precision floating point
4977 * numbers (8 byte) sent sign & exponent first.
4978 * The receiver supports a large set of messages, only a small subset of
4979 * which are used here. From driver to receiver the following are used:
4983 * 21 Request current time
4985 * 2C Set/Request operating parameters
4986 * 2F Request UTC info
4987 * 35 Set/Request I/O options
4989 * From receiver to driver the following are recognised:
4994 * 44 Satellite selection, PDOP, mode
4995 * 46 Receiver health
4996 * 4B Machine code/status
4997 * 4C Report operating parameters (debug only)
4998 * 4F UTC correction data (used to get leap second warnings)
4999 * 55 I/O options (debug only)
5001 * All others are accepted but ignored.
5005 #define PI 3.1415926535898 /* lots of sig figs */
5006 #define D2R PI/180.0
5008 /*-------------------------------------------------------------------
5009 * sendcmd, sendbyte, sendetx, sendflt, sendint implement the command
5010 * interface to the receiver.
5012 * CAVEAT: the sendflt, sendint routines are byte order dependend and
5013 * float implementation dependend - these must be converted to portable
5016 * CURRENT LIMITATION: float implementation. This runs only on systems
5017 * with IEEE754 floats as native floats
5020 typedef struct trimble
5022 u_long last_msg; /* last message received */
5023 u_long last_reset; /* last time a reset was issued */
5024 u_char qtracking; /* query tracking status */
5025 u_long ctrack; /* current tracking set */
5026 u_long ltrack; /* last tracking set */
5038 short idx; /* index to first unused byte */
5039 u_char *txt; /* pointer to actual data buffer */
5042 void sendcmd (struct txbuf *buf, int c);
5043 void sendbyte (struct txbuf *buf, int b);
5044 void sendetx (struct txbuf *buf, struct parseunit *parse);
5045 void sendint (struct txbuf *buf, int a);
5046 void sendflt (struct txbuf *buf, double a);
5055 buf->txt[1] = (u_char)c;
5059 void sendcmd (struct txbuf *buf, int c);
5060 void sendbyte (struct txbuf *buf, int b);
5061 void sendetx (struct txbuf *buf, struct parseunit *parse);
5062 void sendint (struct txbuf *buf, int a);
5063 void sendflt (struct txbuf *buf, double a);
5072 buf->txt[buf->idx++] = DLE;
5073 buf->txt[buf->idx++] = (u_char)b;
5079 struct parseunit *parse
5082 buf->txt[buf->idx++] = DLE;
5083 buf->txt[buf->idx++] = ETX;
5085 if (write(parse->generic->io.fd, buf->txt, (unsigned long)buf->idx) != buf->idx)
5088 msyslog(LOG_ERR, "PARSE receiver #%d: sendetx: failed to send cmd to clock: %m", CLK_UNIT(parse->peer));
5097 mkreadable(buffer, sizeof(buffer), (char *)buf->txt, (unsigned)buf->idx, 1);
5098 printf("PARSE receiver #%d: transmitted message (%d bytes) >%s<\n",
5099 CLK_UNIT(parse->peer),
5103 clear_err(parse, ERR_BADIO);
5113 /* send 16bit int, msbyte first */
5114 sendbyte(buf, (u_char)((a>>8) & 0xff));
5115 sendbyte(buf, (u_char)(a & 0xff));
5127 uval.fv = (float) a;
5128 #ifdef WORDS_BIGENDIAN
5129 for (i=0; i<=3; i++)
5131 for (i=3; i>=0; i--)
5133 sendbyte(buf, uval.bd[i]);
5136 #define TRIM_POS_OPT 0x13 /* output position with high precision */
5137 #define TRIM_TIME_OPT 0x03 /* use UTC time stamps, on second */
5139 /*--------------------------------------------------
5140 * trimble TSIP setup routine
5144 struct parseunit *parse,
5150 trimble_t *t = parse->localdata;
5152 if (t && t->last_reset &&
5153 ((t->last_reset + TRIMBLE_RESET_HOLDOFF) > current_time)) {
5154 return 1; /* not yet */
5158 t->last_reset = current_time;
5162 sendcmd(&buf, CMD_CVERSION); /* request software versions */
5163 sendetx(&buf, parse);
5165 sendcmd(&buf, CMD_COPERPARAM); /* set operating parameters */
5166 sendbyte(&buf, 4); /* static */
5167 sendflt(&buf, 5.0*D2R); /* elevation angle mask = 10 deg XXX */
5168 sendflt(&buf, 4.0); /* s/n ratio mask = 6 XXX */
5169 sendflt(&buf, 12.0); /* PDOP mask = 12 */
5170 sendflt(&buf, 8.0); /* PDOP switch level = 8 */
5171 sendetx(&buf, parse);
5173 sendcmd(&buf, CMD_CMODESEL); /* fix mode select */
5174 sendbyte(&buf, 1); /* time transfer mode */
5175 sendetx(&buf, parse);
5177 sendcmd(&buf, CMD_CMESSAGE); /* request system message */
5178 sendetx(&buf, parse);
5180 sendcmd(&buf, CMD_CSUPER); /* superpacket fix */
5181 sendbyte(&buf, 0x2); /* binary mode */
5182 sendetx(&buf, parse);
5184 sendcmd(&buf, CMD_CIOOPTIONS); /* set I/O options */
5185 sendbyte(&buf, TRIM_POS_OPT); /* position output */
5186 sendbyte(&buf, 0x00); /* no velocity output */
5187 sendbyte(&buf, TRIM_TIME_OPT); /* UTC, compute on seconds */
5188 sendbyte(&buf, 0x00); /* no raw measurements */
5189 sendetx(&buf, parse);
5191 sendcmd(&buf, CMD_CUTCPARAM); /* request UTC correction data */
5192 sendetx(&buf, parse);
5194 NLOG(NLOG_CLOCKINFO)
5196 msyslog(LOG_ERR, "PARSE receiver #%d: trimbletsip_setup: RECEIVER RE-INITIALIZED (%s)", CLK_UNIT(parse->peer), reason);
5201 /*--------------------------------------------------
5202 * TRIMBLE TSIP check routine
5209 struct parseunit *parse = peer->procptr->unitptr;
5210 trimble_t *t = parse->localdata;
5217 if (current_time > t->last_msg + TRIMBLETSIP_IDLE_TIME)
5218 (void)trimbletsip_setup(parse, "message timeout");
5221 poll_poll(parse->peer); /* emit query string and re-arm timer */
5223 if (t && t->qtracking)
5225 u_long oldsats = t->ltrack & ~t->ctrack;
5228 t->ltrack = t->ctrack;
5234 for (i = 0; oldsats; i++) {
5235 if (oldsats & (1 << i))
5237 sendcmd(&buf, CMD_CSTATTRACK);
5238 sendbyte(&buf, i+1); /* old sat */
5239 sendetx(&buf, parse);
5241 oldsats &= ~(1 << i);
5245 sendcmd(&buf, CMD_CSTATTRACK);
5246 sendbyte(&buf, 0x00); /* current tracking set */
5247 sendetx(&buf, parse);
5251 /*--------------------------------------------------
5252 * TRIMBLE TSIP end routine
5256 struct parseunit *parse
5258 { trimble_t *t = parse->localdata;
5263 parse->localdata = NULL;
5265 parse->peer->procptr->nextaction = 0;
5266 parse->peer->procptr->action = NULL;
5269 /*--------------------------------------------------
5270 * TRIMBLE TSIP init routine
5274 struct parseunit *parse
5277 #if defined(VEOL) || defined(VEOL2)
5279 struct termios tio; /* NEEDED FOR A LONG TIME ! */
5281 #ifdef HAVE_SYSV_TTYS
5282 struct termio tio; /* NEEDED FOR A LONG TIME ! */
5285 * allocate local data area
5287 if (!parse->localdata)
5291 t = (trimble_t *)(parse->localdata = emalloc(sizeof(trimble_t)));
5295 memset((char *)t, 0, sizeof(trimble_t));
5296 t->last_msg = current_time;
5300 parse->peer->procptr->action = trimble_check;
5301 parse->peer->procptr->nextaction = current_time;
5304 * configure terminal line for ICANON mode with VEOL characters
5306 if (TTY_GETATTR(parse->generic->io.fd, &tio) == -1)
5308 msyslog(LOG_ERR, "PARSE receiver #%d: trimbletsip_init: tcgetattr(%d, &tio): %m", CLK_UNIT(parse->peer), parse->generic->io.fd);
5313 if ((parse_clockinfo[CLK_TYPE(parse->peer)].cl_lflag & ICANON))
5316 tio.c_cc[VEOL] = ETX;
5319 tio.c_cc[VEOL2] = DLE;
5323 if (TTY_SETATTR(parse->generic->io.fd, &tio) == -1)
5325 msyslog(LOG_ERR, "PARSE receiver #%d: trimbletsip_init: tcsetattr(%d, &tio): %m", CLK_UNIT(parse->peer), parse->generic->io.fd);
5330 return trimbletsip_setup(parse, "initial startup");
5333 /*------------------------------------------------------------
5334 * trimbletsip_event - handle Trimble events
5335 * simple evente handler - attempt to re-initialize receiver
5339 struct parseunit *parse,
5345 case CEVNT_BADREPLY: /* reset on garbled input */
5346 case CEVNT_TIMEOUT: /* reset on no input */
5347 (void)trimbletsip_setup(parse, "event BAD_REPLY/TIMEOUT");
5350 default: /* ignore */
5356 * getflt, getint convert fields in the incoming data into the
5357 * appropriate type of item
5359 * CAVEAT: these routines are currently definitely byte order dependent
5360 * and assume Representation(float) == IEEE754
5361 * These functions MUST be converted to portable versions (especially
5362 * converting the float representation into ntp_fp formats in order
5363 * to avoid floating point operations at all!
5373 #ifdef WORDS_BIGENDIAN
5378 #else /* ! WORDS_BIGENDIAN */
5383 #endif /* ! WORDS_BIGENDIAN */
5394 #ifdef WORDS_BIGENDIAN
5403 #else /* ! WORDS_BIGENDIAN */
5412 #endif /* ! WORDS_BIGENDIAN */
5421 return (int) get_msb_short(&p);
5424 /*--------------------------------------------------
5425 * trimbletsip_message - process trimble messages
5427 #define RTOD (180.0 / 3.1415926535898)
5428 #define mb(_X_) (buffer[2+(_X_)]) /* shortcut for buffer access */
5431 trimbletsip_message(
5432 struct parseunit *parse,
5433 parsetime_t *parsetime
5436 unsigned char *buffer = parsetime->parse_msg;
5437 unsigned int size = parsetime->parse_msglen;
5440 (buffer[0] != DLE) ||
5441 (buffer[size-1] != ETX) ||
5442 (buffer[size-2] != DLE))
5448 printf("TRIMBLE BAD packet, size %d:\n ", size);
5449 for (i = 0; i < size; i++) {
5450 printf ("%2.2x, ", buffer[i]&0xff);
5451 if (i%16 == 15) printf("\n\t");
5461 trimble_t *tr = parse->localdata;
5462 unsigned int cmd = buffer[1];
5471 printf("TRIMBLE packet 0x%02x, size %d:\n ", cmd, size);
5472 for (i = 0; i < size; i++) {
5473 printf ("%2.2x, ", buffer[i]&0xff);
5474 if (i%16 == 15) printf("\n\t");
5481 tr->last_msg = current_time;
5483 s = trimble_convert(cmd, trimble_rcmds);
5487 t = ap(pbuffer, sizeof(pbuffer), t, "%s=\"", s->varname);
5491 DPRINTF(1, ("TRIMBLE UNKNOWN COMMAND 0x%02x\n", cmd));
5495 var_flag = (u_short) s->varmode;
5500 t = ap(pbuffer, sizeof(pbuffer), t, "%f, %d, %f",
5501 getflt((unsigned char *)&mb(0)), getshort((unsigned char *)&mb(4)),
5502 getflt((unsigned char *)&mb(6)));
5506 t = ap(pbuffer, sizeof(pbuffer), t, "mode: ");
5507 switch (mb(0) & 0xF)
5510 t = ap(pbuffer, sizeof(pbuffer), t,
5511 "0x%x", mb(0) & 0x7);
5515 t = ap(pbuffer, sizeof(pbuffer), t, "0D");
5519 t = ap(pbuffer, sizeof(pbuffer), t, "2D");
5523 t = ap(pbuffer, sizeof(pbuffer), t, "3D");
5527 t = ap(pbuffer, sizeof(pbuffer), t, "-MANUAL, ");
5529 t = ap(pbuffer, sizeof(pbuffer), t, "-AUTO, ");
5531 t = ap(pbuffer, sizeof(pbuffer), t, "satellites %02d %02d %02d %02d, PDOP %.2f, HDOP %.2f, VDOP %.2f, TDOP %.2f",
5532 mb(1), mb(2), mb(3), mb(4),
5533 getflt((unsigned char *)&mb(5)),
5534 getflt((unsigned char *)&mb(9)),
5535 getflt((unsigned char *)&mb(13)),
5536 getflt((unsigned char *)&mb(17)));
5541 t = ap(pbuffer, sizeof(pbuffer), t, "%d.%d (%d/%d/%d)",
5542 mb(0)&0xff, mb(1)&0xff, 1900+(mb(4)&0xff), mb(2)&0xff, mb(3)&0xff);
5545 case CMD_RRECVHEALTH:
5547 static const char *msgs[] =
5549 "Battery backup failed",
5550 "Signal processor error",
5551 "Alignment error, channel or chip 1",
5552 "Alignment error, channel or chip 2",
5553 "Antenna feed line fault",
5554 "Excessive ref freq. error",
5561 switch (mb(0) & 0xFF)
5564 t = ap(pbuffer, sizeof(pbuffer), t, "illegal value 0x%02x", mb(0) & 0xFF);
5567 t = ap(pbuffer, sizeof(pbuffer), t, "doing position fixes");
5570 t = ap(pbuffer, sizeof(pbuffer), t, "no GPS time yet");
5573 t = ap(pbuffer, sizeof(pbuffer), t, "PDOP too high");
5576 t = ap(pbuffer, sizeof(pbuffer), t, "no usable satellites");
5579 t = ap(pbuffer, sizeof(pbuffer), t, "only ONE usable satellite");
5582 t = ap(pbuffer, sizeof(pbuffer), t, "only TWO usable satellites");
5585 t = ap(pbuffer, sizeof(pbuffer), t, "only THREE usable satellites");
5588 t = ap(pbuffer, sizeof(pbuffer), t, "the chosen satellite is unusable");
5592 bits = mb(1) & 0xFF;
5594 for (i = 0; i < 8; i++)
5595 if (bits & (0x1<<i))
5597 t = ap(pbuffer, sizeof(pbuffer), t, ", %s", msgs[i]);
5603 mkreadable(t, (int)BUFFER_SIZE(pbuffer, t), (char *)&mb(0), (unsigned)(size - 2 - (&mb(0) - buffer)), 0);
5608 static const char *msgs[] =
5610 "Synthesizer Fault",
5611 "Battery Powered Time Clock Fault",
5612 "A-to-D Converter Fault",
5613 "The almanac stored in the receiver is not complete and current",
5622 t = ap(pbuffer, sizeof(pbuffer), t, "machine id 0x%02x", mb(0) & 0xFF);
5623 bits = mb(1) & 0xFF;
5625 for (i = 0; i < 8; i++)
5626 if (bits & (0x1<<i))
5628 t = ap(pbuffer, sizeof(pbuffer), t, ", %s", msgs[i]);
5631 t = ap(pbuffer, sizeof(pbuffer), t, ", Superpackets %ssupported", (mb(2) & 0xFF) ? "" :"un" );
5635 case CMD_ROPERPARAM:
5636 t = ap(pbuffer, sizeof(pbuffer), t, "%2x %.1f %.1f %.1f %.1f",
5637 mb(0), getflt((unsigned char *)&mb(1)), getflt((unsigned char *)&mb(5)),
5638 getflt((unsigned char *)&mb(9)), getflt((unsigned char *)&mb(13)));
5643 float t0t = getflt((unsigned char *)&mb(14));
5644 short wnt = (short) getshort((unsigned char *)&mb(18));
5645 short dtls = (short) getshort((unsigned char *)&mb(12));
5646 short wnlsf = (short) getshort((unsigned char *)&mb(20));
5647 short dn = (short) getshort((unsigned char *)&mb(22));
5648 short dtlsf = (short) getshort((unsigned char *)&mb(24));
5652 mk_utcinfo(t, wnt, wnlsf, dn, dtls, dtlsf, BUFFER_SIZE(pbuffer, t));
5656 t = ap(pbuffer, sizeof(pbuffer), t, "<NO UTC DATA>");
5662 t = ap(pbuffer, sizeof(pbuffer), t, "%.1fm %.2fm/s at %.1fs",
5663 getflt(&mb(0)), getflt(&mb(4)), getflt(&mb(8)));
5666 case CMD_RIOOPTIONS:
5668 t = ap(pbuffer, sizeof(pbuffer), t, "%02x %02x %02x %02x",
5669 mb(0), mb(1), mb(2), mb(3));
5670 if (mb(0) != TRIM_POS_OPT ||
5671 mb(2) != TRIM_TIME_OPT)
5673 (void)trimbletsip_setup(parse, "bad io options");
5680 double x = getflt((unsigned char *)&mb(0));
5681 double y = getflt((unsigned char *)&mb(4));
5682 double z = getflt((unsigned char *)&mb(8));
5683 double f = getflt((unsigned char *)&mb(12));
5686 t = ap(pbuffer, sizeof(pbuffer), t, "x= %.1fm, y= %.1fm, z= %.1fm, time_of_fix= %f sec",
5696 double lat = getflt((unsigned char *)&mb(0));
5697 double lng = getflt((unsigned char *)&mb(4));
5698 double f = getflt((unsigned char *)&mb(12));
5701 t = ap(pbuffer, sizeof(pbuffer), t, "lat %f %c, long %f %c, alt %.2fm",
5702 ((lat < 0.0) ? (-lat) : (lat))*RTOD, (lat < 0.0 ? 'S' : 'N'),
5703 ((lng < 0.0) ? (-lng) : (lng))*RTOD, (lng < 0.0 ? 'W' : 'E'),
5704 getflt((unsigned char *)&mb(8)));
5710 case CMD_RDOUBLEXYZ:
5712 double x = getdbl((unsigned char *)&mb(0));
5713 double y = getdbl((unsigned char *)&mb(8));
5714 double z = getdbl((unsigned char *)&mb(16));
5715 t = ap(pbuffer, sizeof(pbuffer), t, "x= %.1fm, y= %.1fm, z= %.1fm",
5720 case CMD_RDOUBLELLA:
5722 double lat = getdbl((unsigned char *)&mb(0));
5723 double lng = getdbl((unsigned char *)&mb(8));
5724 t = ap(pbuffer, sizeof(pbuffer), t, "lat %f %c, lon %f %c, alt %.2fm",
5725 ((lat < 0.0) ? (-lat) : (lat))*RTOD, (lat < 0.0 ? 'S' : 'N'),
5726 ((lng < 0.0) ? (-lng) : (lng))*RTOD, (lng < 0.0 ? 'W' : 'E'),
5727 getdbl((unsigned char *)&mb(16)));
5731 case CMD_RALLINVIEW:
5735 t = ap(pbuffer, sizeof(pbuffer), t, "mode: ");
5736 switch (mb(0) & 0x7)
5739 t = ap(pbuffer, sizeof(pbuffer), t, "0x%x", mb(0) & 0x7);
5743 t = ap(pbuffer, sizeof(pbuffer), t, "2D");
5747 t = ap(pbuffer, sizeof(pbuffer), t, "3D");
5751 t = ap(pbuffer, sizeof(pbuffer), t, "-MANUAL, ");
5753 t = ap(pbuffer, sizeof(pbuffer), t, "-AUTO, ");
5755 sats = (mb(0)>>4) & 0xF;
5757 t = ap(pbuffer, sizeof(pbuffer), t, "PDOP %.2f, HDOP %.2f, VDOP %.2f, TDOP %.2f, %d satellite%s in view: ",
5758 getflt((unsigned char *)&mb(1)),
5759 getflt((unsigned char *)&mb(5)),
5760 getflt((unsigned char *)&mb(9)),
5761 getflt((unsigned char *)&mb(13)),
5762 sats, (sats == 1) ? "" : "s");
5764 for (i=0; i < sats; i++)
5766 t = ap(pbuffer, sizeof(pbuffer), t, "%s%02d", i ? ", " : "", mb(17+i));
5768 tr->ctrack |= (1 << (mb(17+i)-1));
5772 { /* mark for tracking status query */
5778 case CMD_RSTATTRACK:
5780 t = ap(pbuffer, sizeof(pbuffer), t-2, "[%02d]=\"", mb(0)); /* add index to var name */
5781 if (getflt((unsigned char *)&mb(4)) < 0.0)
5783 t = ap(pbuffer, sizeof(pbuffer), t, "<NO MEASUREMENTS>");
5784 var_flag &= (u_short)(~DEF);
5788 t = ap(pbuffer, sizeof(pbuffer), t, "ch=%d, acq=%s, eph=%d, signal_level= %5.2f, elevation= %5.2f, azimuth= %6.2f",
5790 mb(2) ? ((mb(2) == 1) ? "ACQ" : "SRCH") : "NEVER",
5792 getflt((unsigned char *)&mb(4)),
5793 getflt((unsigned char *)&mb(12)) * RTOD,
5794 getflt((unsigned char *)&mb(16)) * RTOD);
5797 var_flag &= (u_short)(~DEF);
5798 t = ap(pbuffer, sizeof(pbuffer), t, ", OLD");
5803 t = ap(pbuffer, sizeof(pbuffer), t, ", BAD PARITY");
5806 t = ap(pbuffer, sizeof(pbuffer), t, ", BAD EPH HEALTH");
5809 t = ap(pbuffer, sizeof(pbuffer), t, ", collecting data");
5815 t = ap(pbuffer, sizeof(pbuffer), t, "<UNDECODED>");
5819 t = ap(pbuffer, sizeof(pbuffer), t, "\"");
5820 set_var(&parse->kv, pbuffer, sizeof(pbuffer), var_flag);
5825 /**============================================================
5829 /*--------------------------------------------------
5830 * rawdcf_init_1 - set up modem lines for RAWDCF receivers
5833 #if defined(TIOCMSET) && (defined(TIOCM_DTR) || defined(CIOCM_DTR))
5836 struct parseunit *parse
5839 /* fixed 2000 for using with Linux by Wolfram Pienkoss <wp@bszh.de> */
5841 * You can use the RS232 to supply the power for a DCF77 receiver.
5842 * Here a voltage between the DTR and the RTS line is used. Unfortunately
5843 * the name has changed from CIOCM_DTR to TIOCM_DTR recently.
5847 if (ioctl(parse->generic->io.fd, TIOCMGET, (caddr_t)&sl232) == -1)
5849 msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_1: WARNING: ioctl(fd, TIOCMGET, [C|T]IOCM_DTR): %m", CLK_UNIT(parse->peer));
5854 sl232 = (sl232 & ~TIOCM_RTS) | TIOCM_DTR; /* turn on DTR, clear RTS for power supply */
5856 sl232 = (sl232 & ~CIOCM_RTS) | CIOCM_DTR; /* turn on DTR, clear RTS for power supply */
5859 if (ioctl(parse->generic->io.fd, TIOCMSET, (caddr_t)&sl232) == -1)
5861 msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_1: WARNING: ioctl(fd, TIOCMSET, [C|T]IOCM_DTR): %m", CLK_UNIT(parse->peer));
5868 struct parseunit *parse
5871 msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_1: WARNING: OS interface incapable of setting DTR to power DCF modules", CLK_UNIT(parse->peer));
5874 #endif /* DTR initialisation type */
5876 /*--------------------------------------------------
5877 * rawdcf_init_2 - set up modem lines for RAWDCF receivers
5878 * CLR DTR line, SET RTS line
5880 #if defined(TIOCMSET) && (defined(TIOCM_RTS) || defined(CIOCM_RTS))
5883 struct parseunit *parse
5886 /* fixed 2000 for using with Linux by Wolfram Pienkoss <wp@bszh.de> */
5888 * You can use the RS232 to supply the power for a DCF77 receiver.
5889 * Here a voltage between the DTR and the RTS line is used. Unfortunately
5890 * the name has changed from CIOCM_DTR to TIOCM_DTR recently.
5894 if (ioctl(parse->generic->io.fd, TIOCMGET, (caddr_t)&sl232) == -1)
5896 msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_2: WARNING: ioctl(fd, TIOCMGET, [C|T]IOCM_RTS): %m", CLK_UNIT(parse->peer));
5901 sl232 = (sl232 & ~TIOCM_DTR) | TIOCM_RTS; /* turn on RTS, clear DTR for power supply */
5903 sl232 = (sl232 & ~CIOCM_DTR) | CIOCM_RTS; /* turn on RTS, clear DTR for power supply */
5906 if (ioctl(parse->generic->io.fd, TIOCMSET, (caddr_t)&sl232) == -1)
5908 msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_2: WARNING: ioctl(fd, TIOCMSET, [C|T]IOCM_RTS): %m", CLK_UNIT(parse->peer));
5915 struct parseunit *parse
5918 msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_2: WARNING: OS interface incapable of setting RTS to power DCF modules", CLK_UNIT(parse->peer));
5921 #endif /* DTR initialisation type */
5923 #else /* defined(REFCLOCK) && defined(PARSE) */
5924 NONEMPTY_TRANSLATION_UNIT
5925 #endif /* defined(REFCLOCK) && defined(PARSE) */
5930 * refclock_parse.c,v
5931 * Revision 4.81 2009/05/01 10:15:29 kardel
5932 * use new refclock_ppsapi interface
5934 * Revision 4.80 2007/08/11 12:06:29 kardel
5935 * update comments wrt/ to PPS
5937 * Revision 4.79 2007/08/11 11:52:23 kardel
5938 * - terminate io bindings before io_closeclock() will close our file descriptor
5940 * Revision 4.78 2006/12/22 20:08:27 kardel
5941 * Bug 746 (RFE): add configuration for Expert mouseCLOCK USB v2.0 as mode 19
5943 * Revision 4.77 2006/08/05 07:44:49 kardel
5944 * support optionally separate PPS devices via /dev/refclockpps-{0..3}
5946 * Revision 4.76 2006/06/22 18:40:47 kardel
5947 * clean up signedness (gcc 4)
5949 * Revision 4.75 2006/06/22 16:58:10 kardel
5950 * Bug #632: call parse_ppsapi() in parse_ctl() when updating
5951 * the PPS offset. Fix sign of offset passed to kernel.
5953 * Revision 4.74 2006/06/18 21:18:37 kardel
5954 * NetBSD Coverity CID 3796: possible NULL deref
5956 * Revision 4.73 2006/05/26 14:23:46 kardel
5957 * cleanup of copyright info
5959 * Revision 4.72 2006/05/26 14:19:43 kardel
5960 * cleanup of ioctl cruft
5962 * Revision 4.71 2006/05/26 14:15:57 kardel
5963 * delay adding refclock to async refclock io after all initializations
5965 * Revision 4.70 2006/05/25 18:20:50 kardel
5967 * terminate parse io engine after de-registering
5968 * from refclock io engine
5970 * Revision 4.69 2006/05/25 17:28:02 kardel
5971 * complete refclock io structure initialization *before* inserting it into the
5972 * refclock input machine (avoids null pointer deref) (bug #619)
5974 * Revision 4.68 2006/05/01 17:02:51 kardel
5975 * copy receiver method also for newlwy created receive buffers
5977 * Revision 4.67 2006/05/01 14:37:29 kardel
5978 * If an input buffer parses into more than one message do insert the
5979 * parsed message in a new input buffer instead of processing it
5980 * directly. This avoids deed complicated processing in signal
5983 * Revision 4.66 2006/03/18 00:45:30 kardel
5984 * coverity fixes found in NetBSD coverity scan
5986 * Revision 4.65 2006/01/26 06:08:33 kardel
5987 * output errno on PPS setup failure
5989 * Revision 4.64 2005/11/09 20:44:47 kardel
5990 * utilize full PPS timestamp resolution from PPS API
5992 * Revision 4.63 2005/10/07 22:10:25 kardel
5993 * bounded buffer implementation
5995 * Revision 4.62.2.2 2005/09/25 10:20:16 kardel
5996 * avoid unexpected buffer overflows due to sprintf("%f") on strange floats:
5997 * replace almost all str* and *printf functions be their buffer bounded
6000 * Revision 4.62.2.1 2005/08/27 16:19:27 kardel
6001 * limit re-set rate of trimble clocks
6003 * Revision 4.62 2005/08/06 17:40:00 kardel
6004 * cleanup size handling wrt/ to buffer boundaries
6006 * Revision 4.61 2005/07/27 21:16:19 kardel
6007 * fix a long (> 11 years) misconfiguration wrt/ Meinberg cflag factory
6008 * default setup. CSTOPB was missing for the 7E2 default data format of
6011 * Revision 4.60 2005/07/17 21:14:44 kardel
6012 * change contents of version string to include the RCS/CVS Id
6014 * Revision 4.59 2005/07/06 06:56:38 kardel
6017 * Revision 4.58 2005/07/04 13:10:40 kardel
6018 * fix bug 455: tripping over NULL pointer on cleanup
6019 * fix shadow storage logic for ppsphaseadjust and trustime wrt/ time2
6020 * fix compiler warnings for some platforms wrt/ printf formatstrings and
6021 * varying structure element sizes
6022 * reorder assignment in binding to avoid tripping over NULL pointers
6024 * Revision 4.57 2005/06/25 09:25:19 kardel
6025 * sort out log output sequence
6027 * Revision 4.56 2005/06/14 21:47:27 kardel
6028 * collect samples only if samples are ok (sync or trusted flywheel)
6029 * propagate pps phase adjustment value to kernel via PPSAPI to help HARDPPS
6030 * en- and dis-able HARDPPS in correlation to receiver sync state
6032 * Revision 4.55 2005/06/02 21:28:31 kardel
6033 * clarify trust logic
6035 * Revision 4.54 2005/06/02 17:06:49 kardel
6036 * change status reporting to use fixed refclock_report()
6038 * Revision 4.53 2005/06/02 16:33:31 kardel
6039 * fix acceptance of clocks unsync clocks right at start
6041 * Revision 4.52 2005/05/26 21:55:06 kardel
6042 * cleanup status reporting
6044 * Revision 4.51 2005/05/26 19:19:14 kardel
6045 * implement fast refclock startup
6047 * Revision 4.50 2005/04/16 20:51:35 kardel
6048 * set hardpps_enable = 1 when binding a kernel PPS source
6050 * Revision 4.49 2005/04/16 17:29:26 kardel
6051 * add non polling clock type 18 for just listenning to Meinberg clocks
6053 * Revision 4.48 2005/04/16 16:22:27 kardel
6054 * bk sync 20050415 ntp-dev
6056 * Revision 4.47 2004/11/29 10:42:48 kardel
6057 * bk sync ntp-dev 20041129
6059 * Revision 4.46 2004/11/29 10:26:29 kardel
6060 * keep fudgetime2 in sync with trusttime/ppsphaseadjust depending in flag1
6062 * Revision 4.45 2004/11/14 20:53:20 kardel
6063 * clear PPS flags after using them
6065 * Revision 4.44 2004/11/14 15:29:41 kardel
6066 * support PPSAPI, upgrade Copyright to Berkeley style
6068 * Revision 4.43 2001/05/26 22:53:16 kardel
6069 * 20010526 reconcilation
6071 * Revision 4.42 2000/05/14 15:31:51 kardel
6072 * PPSAPI && RAWDCF modemline support
6074 * Revision 4.41 2000/04/09 19:50:45 kardel
6075 * fixed rawdcfdtr_init() -> rawdcf_init_1
6077 * Revision 4.40 2000/04/09 15:27:55 kardel
6078 * modem line fiddle in rawdcf_init_2
6080 * Revision 4.39 2000/03/18 09:16:55 kardel
6081 * PPSAPI integration
6083 * Revision 4.38 2000/03/05 20:25:06 kardel
6086 * Revision 4.37 2000/03/05 20:11:14 kardel
6087 * 4.0.99g reconcilation
6089 * Revision 4.36 1999/11/28 17:18:20 kardel
6090 * disabled burst mode
6092 * Revision 4.35 1999/11/28 09:14:14 kardel
6095 * Revision 4.34 1999/05/14 06:08:05 kardel
6096 * store current_time in a suitable container (u_long)
6098 * Revision 4.33 1999/05/13 21:48:38 kardel
6099 * double the no response timeout interval
6101 * Revision 4.32 1999/05/13 20:09:13 kardel
6102 * complain only about missing polls after a full poll interval
6104 * Revision 4.31 1999/05/13 19:59:32 kardel
6105 * add clock type 16 for RTS set DTR clr in RAWDCF
6107 * Revision 4.30 1999/02/28 20:36:43 kardel
6110 * Revision 4.29 1999/02/28 19:58:23 kardel
6111 * updated copyright information
6113 * Revision 4.28 1999/02/28 19:01:50 kardel
6114 * improved debug out on sent Meinberg messages
6116 * Revision 4.27 1999/02/28 18:05:55 kardel
6117 * no linux/ppsclock.h stuff
6119 * Revision 4.26 1999/02/28 15:27:27 kardel
6120 * wharton clock integration
6122 * Revision 4.25 1999/02/28 14:04:46 kardel
6123 * added missing double quotes to UTC information string
6125 * Revision 4.24 1999/02/28 12:06:50 kardel
6126 * (parse_control): using gmprettydate instead of prettydate()
6127 * (mk_utcinfo): new function for formatting GPS derived UTC information
6128 * (gps16x_message): changed to use mk_utcinfo()
6129 * (trimbletsip_message): changed to use mk_utcinfo()
6130 * ignoring position information in unsynchronized mode
6131 * (parse_start): augument linux support for optional ASYNC_LOW_LATENCY
6133 * Revision 4.23 1999/02/23 19:47:53 kardel
6135 * (stream_receive): fixed formats
6137 * Revision 4.22 1999/02/22 06:21:02 kardel
6138 * use new autoconfig symbols
6140 * Revision 4.21 1999/02/21 12:18:13 kardel
6141 * 4.91f reconcilation
6143 * Revision 4.20 1999/02/21 10:53:36 kardel
6144 * initial Linux PPSkit version
6146 * Revision 4.19 1999/02/07 09:10:45 kardel
6147 * clarify STREAMS mitigation rules in comment
6149 * Revision 4.18 1998/12/20 23:45:34 kardel
6150 * fix types and warnings
6152 * Revision 4.17 1998/11/15 21:24:51 kardel
6153 * cannot access mbg_ routines when CLOCK_MEINBERG
6156 * Revision 4.16 1998/11/15 20:28:17 kardel
6157 * Release 4.0.73e13 reconcilation
6159 * Revision 4.15 1998/08/22 21:56:08 kardel
6160 * fixed IO handling for non-STREAM IO
6162 * Revision 4.14 1998/08/16 19:00:48 kardel
6163 * (gps16x_message): reduced UTC parameter information (dropped A0,A1)
6164 * made uval a local variable (killed one of the last globals)
6165 * (sendetx): added logging of messages when in debug mode
6166 * (trimble_check): added periodic checks to facilitate re-initialization
6167 * (trimbletsip_init): made use of EOL character if in non-kernel operation
6168 * (trimbletsip_message): extended message interpretation
6169 * (getdbl): fixed data conversion
6171 * Revision 4.13 1998/08/09 22:29:13 kardel
6172 * Trimble TSIP support
6174 * Revision 4.12 1998/07/11 10:05:34 kardel
6175 * Release 4.0.73d reconcilation
6177 * Revision 4.11 1998/06/14 21:09:42 kardel
6180 * Revision 4.10 1998/06/13 12:36:45 kardel
6181 * signed/unsigned, name clashes
6183 * Revision 4.9 1998/06/12 15:30:00 kardel
6186 * Revision 4.8 1998/06/12 11:19:42 kardel
6187 * added direct input processing routine for refclocks in
6188 * order to avaiod that single character io gobbles up all
6189 * receive buffers and drops input data. (Problem started
6190 * with fast machines so a character a buffer was possible
6191 * one of the few cases where faster machines break existing
6192 * allocation algorithms)
6194 * Revision 4.7 1998/06/06 18:35:20 kardel
6195 * (parse_start): added BURST mode initialisation
6197 * Revision 4.6 1998/05/27 06:12:46 kardel
6198 * RAWDCF_BASEDELAY default added
6199 * old comment removed
6202 * Revision 4.5 1998/05/25 22:05:09 kardel
6203 * RAWDCF_SETDTR option removed
6204 * clock type 14 attempts to set DTR for
6205 * power supply of RAWDCF receivers
6207 * Revision 4.4 1998/05/24 16:20:47 kardel
6208 * updated comments referencing Meinberg clocks
6209 * added RAWDCF clock with DTR set option as type 14
6211 * Revision 4.3 1998/05/24 10:48:33 kardel
6212 * calibrated CONRAD RAWDCF default fudge factor
6214 * Revision 4.2 1998/05/24 09:59:35 kardel
6215 * corrected version information (ntpq support)
6217 * Revision 4.1 1998/05/24 09:52:31 kardel
6218 * use fixed format only (new IO model)
6219 * output debug to stdout instead of msyslog()
6220 * don't include >"< in ASCII output in order not to confuse
6223 * Revision 4.0 1998/04/10 19:52:11 kardel
6224 * Start 4.0 release version numbering
6226 * Revision 1.2 1998/04/10 19:28:04 kardel
6227 * initial NTP VERSION 4 integration of PARSE with GPS166 binary support
6228 * derived from 3.105.1.2 from V3 tree
6230 * Revision information 3.1 - 3.105 from log deleted 1998/04/10 kardel