1 /* $NetBSD: refclock_parse.c,v 1.1.1.1 2009/12/13 16:56:00 kardel Exp $ */
4 * /src/NTP/REPOSITORY/ntp4-dev/ntpd/refclock_parse.c,v 4.81 2009/05/01 10:15:29 kardel RELEASE_20090105_A
6 * refclock_parse.c,v 4.81 2009/05/01 10:15:29 kardel RELEASE_20090105_A
8 * generic reference clock driver for several DCF/GPS/MSF/... receivers
11 * On systems that support PPSAPI (RFC2783) PPSAPI is the
12 * preferred interface.
14 * Optionally make use of a STREAMS module for input processing where
15 * available and configured. This STREAMS module reduces the time
16 * stamp latency for serial and PPS events.
17 * Currently the STREAMS module is only available for Suns running
18 * SunOS 4.x and SunOS5.x.
20 * Copyright (c) 1995-2009 by Frank Kardel <kardel <AT> ntp.org>
21 * Copyright (c) 1989-1994 by Frank Kardel, Friedrich-Alexander Universität Erlangen-Nürnberg, Germany
23 * Redistribution and use in source and binary forms, with or without
24 * modification, are permitted provided that the following conditions
26 * 1. Redistributions of source code must retain the above copyright
27 * notice, this list of conditions and the following disclaimer.
28 * 2. Redistributions in binary form must reproduce the above copyright
29 * notice, this list of conditions and the following disclaimer in the
30 * documentation and/or other materials provided with the distribution.
31 * 3. Neither the name of the author nor the names of its contributors
32 * may be used to endorse or promote products derived from this software
33 * without specific prior written permission.
35 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
36 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
37 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
38 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
39 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
40 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
41 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
42 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
43 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
44 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
53 #if defined(REFCLOCK) && defined(CLOCK_PARSE)
56 * This driver currently provides the support for
57 * - Meinberg receiver DCF77 PZF 535 (TCXO version) (DCF)
58 * - Meinberg receiver DCF77 PZF 535 (OCXO version) (DCF)
59 * - Meinberg receiver DCF77 PZF 509 (DCF)
60 * - Meinberg receiver DCF77 AM receivers (e.g. C51) (DCF)
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 GPS166/GPS167 (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 baud 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 GPS16x 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 * GPS 16x family of receivers.
96 * Meinberg can be reached via: http://www.meinberg.de/
100 #include "ntp_refclock.h"
101 #include "ntp_unixtime.h" /* includes <sys/time.h> */
102 #include "ntp_control.h"
103 #include "ntp_string.h"
107 #ifndef TM_IN_SYS_TIME
115 #if !defined(STREAM) && !defined(HAVE_SYSV_TTYS) && !defined(HAVE_BSD_TTYS) && !defined(HAVE_TERMIOS)
116 # include "Bletch: Define one of {STREAM,HAVE_SYSV_TTYS,HAVE_TERMIOS}"
120 # include <sys/stream.h>
121 # include <sys/stropts.h>
125 # define TTY_GETATTR(_FD_, _ARG_) tcgetattr((_FD_), (_ARG_))
126 # define TTY_SETATTR(_FD_, _ARG_) tcsetattr((_FD_), TCSANOW, (_ARG_))
127 # undef HAVE_SYSV_TTYS
130 #ifdef HAVE_SYSV_TTYS
131 # define TTY_GETATTR(_FD_, _ARG_) ioctl((_FD_), TCGETA, (_ARG_))
132 # define TTY_SETATTR(_FD_, _ARG_) ioctl((_FD_), TCSETAW, (_ARG_))
136 /* #error CURRENTLY NO BSD TTY SUPPORT */
137 # include "Bletch: BSD TTY not currently supported"
140 #ifdef HAVE_SYS_IOCTL_H
141 # include <sys/ioctl.h>
145 # include "ppsapi_timepps.h"
146 # include "refclock_atom.h"
150 # ifdef HAVE_SYS_PPSCLOCK_H
151 # include <sys/ppsclock.h>
153 # ifdef HAVE_TIO_SERIAL_STUFF
154 # include <linux/serial.h>
158 #define BUFFER_SIZE(_BUF, _PTR) ((_BUF) + sizeof(_BUF) - (_PTR))
159 #define BUFFER_SIZES(_BUF, _PTR, _SZ) ((_BUF) + (_SZ) - (_PTR))
162 * document type of PPS interfacing - copy of ifdef mechanism in local_input()
167 #define PPS_METHOD "PPS API"
169 #ifdef TIOCDCDTIMESTAMP
170 #define PPS_METHOD "TIOCDCDTIMESTAMP"
171 #else /* TIOCDCDTIMESTAMP */
172 #if defined(HAVE_STRUCT_PPSCLOCKEV) && (defined(HAVE_CIOGETEV) || defined(HAVE_TIOCGPPSEV))
174 #define PPS_METHOD "CIOGETEV"
176 #ifdef HAVE_TIOCGPPSEV
177 #define PPS_METHOD "TIOCGPPSEV"
180 #endif /* TIOCDCDTIMESTAMP */
181 #endif /* HAVE_PPSAPI */
184 #include "ntp_stdlib.h"
187 #include "mbg_gps166.h"
191 #include "ieee754io.h"
192 #include "recvbuff.h"
194 static char rcsid
[] = "refclock_parse.c,v 4.81 2009/05/01 10:15:29 kardel RELEASE_20090105_A";
196 /**===========================================================================
197 ** external interface to ntp mechanism
200 static int parse_start (int, struct peer
*);
201 static void parse_shutdown (int, struct peer
*);
202 static void parse_poll (int, struct peer
*);
203 static void parse_control (int, struct refclockstat
*, struct refclockstat
*, struct peer
*);
205 struct refclock refclock_parse
= {
218 #define MAXUNITS 4 /* maximum number of "PARSE" units permitted */
219 #define PARSEDEVICE "/dev/refclock-%d" /* device to open %d is unit number */
220 #define PARSEPPSDEVICE "/dev/refclockpps-%d" /* optional pps device to open %d is unit number */
223 #define ABS(_X_) (((_X_) < 0) ? -(_X_) : (_X_))
225 #define PARSE_HARDPPS_DISABLE 0
226 #define PARSE_HARDPPS_ENABLE 1
228 /**===========================================================================
229 ** function vector for dynamically binding io handling mechanism
232 struct parseunit
; /* to keep inquiring minds happy */
236 const char *bd_description
; /* name of type of binding */
237 int (*bd_init
) (struct parseunit
*); /* initialize */
238 void (*bd_end
) (struct parseunit
*); /* end */
239 int (*bd_setcs
) (struct parseunit
*, parsectl_t
*); /* set character size */
240 int (*bd_disable
) (struct parseunit
*); /* disable */
241 int (*bd_enable
) (struct parseunit
*); /* enable */
242 int (*bd_getfmt
) (struct parseunit
*, parsectl_t
*); /* get format */
243 int (*bd_setfmt
) (struct parseunit
*, parsectl_t
*); /* setfmt */
244 int (*bd_timecode
) (struct parseunit
*, parsectl_t
*); /* get time code */
245 void (*bd_receive
) (struct recvbuf
*); /* receive operation */
246 int (*bd_io_input
) (struct recvbuf
*); /* input operation */
249 #define PARSE_END(_X_) (*(_X_)->binding->bd_end)(_X_)
250 #define PARSE_SETCS(_X_, _CS_) (*(_X_)->binding->bd_setcs)(_X_, _CS_)
251 #define PARSE_ENABLE(_X_) (*(_X_)->binding->bd_enable)(_X_)
252 #define PARSE_DISABLE(_X_) (*(_X_)->binding->bd_disable)(_X_)
253 #define PARSE_GETFMT(_X_, _DCT_) (*(_X_)->binding->bd_getfmt)(_X_, _DCT_)
254 #define PARSE_SETFMT(_X_, _DCT_) (*(_X_)->binding->bd_setfmt)(_X_, _DCT_)
255 #define PARSE_GETTIMECODE(_X_, _DCT_) (*(_X_)->binding->bd_timecode)(_X_, _DCT_)
260 #define PARSE_F_PPSPPS 0x0001 /* use loopfilter PPS code (CIOGETEV) */
261 #define PARSE_F_PPSONSECOND 0x0002 /* PPS pulses are on second */
264 /**===========================================================================
265 ** error message regression handling
267 ** there are quite a few errors that can occur in rapid succession such as
268 ** noisy input data or no data at all. in order to reduce the amount of
269 ** syslog messages in such case, we are using a backoff algorithm. We limit
270 ** the number of error messages of a certain class to 1 per time unit. if a
271 ** configurable number of messages is displayed that way, we move on to the
272 ** next time unit / count for that class. a count of messages that have been
273 ** suppressed is held and displayed whenever a corresponding message is
274 ** displayed. the time units for a message class will also be displayed.
275 ** whenever an error condition clears we reset the error message state,
276 ** thus we would still generate much output on pathological conditions
277 ** where the system oscillates between OK and NOT OK states. coping
278 ** with that condition is currently considered too complicated.
281 #define ERR_ALL (unsigned)~0 /* "all" errors */
282 #define ERR_BADDATA (unsigned)0 /* unusable input data/conversion errors */
283 #define ERR_NODATA (unsigned)1 /* no input data */
284 #define ERR_BADIO (unsigned)2 /* read/write/select errors */
285 #define ERR_BADSTATUS (unsigned)3 /* unsync states */
286 #define ERR_BADEVENT (unsigned)4 /* non nominal events */
287 #define ERR_INTERNAL (unsigned)5 /* internal error */
288 #define ERR_CNT (unsigned)(ERR_INTERNAL+1)
290 #define ERR(_X_) if (list_err(parse, (_X_)))
292 struct errorregression
294 u_long err_count
; /* number of repititions per class */
295 u_long err_delay
; /* minimum delay between messages */
298 static struct errorregression
299 err_baddata
[] = /* error messages for bad input data */
301 { 1, 0 }, /* output first message immediately */
302 { 5, 60 }, /* output next five messages in 60 second intervals */
303 { 3, 3600 }, /* output next 3 messages in hour intervals */
304 { 0, 12*3600 } /* repeat messages only every 12 hours */
307 static struct errorregression
308 err_nodata
[] = /* error messages for missing input data */
310 { 1, 0 }, /* output first message immediately */
311 { 5, 60 }, /* output next five messages in 60 second intervals */
312 { 3, 3600 }, /* output next 3 messages in hour intervals */
313 { 0, 12*3600 } /* repeat messages only every 12 hours */
316 static struct errorregression
317 err_badstatus
[] = /* unsynchronized state messages */
319 { 1, 0 }, /* output first message immediately */
320 { 5, 60 }, /* output next five messages in 60 second intervals */
321 { 3, 3600 }, /* output next 3 messages in hour intervals */
322 { 0, 12*3600 } /* repeat messages only every 12 hours */
325 static struct errorregression
326 err_badio
[] = /* io failures (bad reads, selects, ...) */
328 { 1, 0 }, /* output first message immediately */
329 { 5, 60 }, /* output next five messages in 60 second intervals */
330 { 5, 3600 }, /* output next 3 messages in hour intervals */
331 { 0, 12*3600 } /* repeat messages only every 12 hours */
334 static struct errorregression
335 err_badevent
[] = /* non nominal events */
337 { 20, 0 }, /* output first message immediately */
338 { 6, 60 }, /* output next five messages in 60 second intervals */
339 { 5, 3600 }, /* output next 3 messages in hour intervals */
340 { 0, 12*3600 } /* repeat messages only every 12 hours */
343 static struct errorregression
344 err_internal
[] = /* really bad things - basically coding/OS errors */
346 { 0, 0 }, /* output all messages immediately */
349 static struct errorregression
*
362 u_long err_started
; /* begin time (ntp) of error condition */
363 u_long err_last
; /* last time (ntp) error occurred */
364 u_long err_cnt
; /* number of error repititions */
365 u_long err_suppressed
; /* number of suppressed messages */
366 struct errorregression
*err_stage
; /* current error stage */
369 /**===========================================================================
370 ** refclock instance data
378 struct peer
*peer
; /* backlink to peer structure - refclock inactive if 0 */
379 struct refclockproc
*generic
; /* backlink to refclockproc structure */
384 bind_t
*binding
; /* io handling binding */
389 parse_t parseio
; /* io handling structure (user level parsing) */
392 * type specific parameters
394 struct parse_clockinfo
*parse_type
; /* link to clock description */
397 * clock state handling/reporting
399 u_char flags
; /* flags (leap_control) */
400 u_long lastchange
; /* time (ntp) when last state change accured */
401 u_long statetime
[CEVNT_MAX
+1]; /* accumulated time of clock states */
402 u_long pollneeddata
; /* current_time(!=0) for receive sample expected in PPS mode */
403 u_short lastformat
; /* last format used */
404 u_long lastsync
; /* time (ntp) when clock was last seen fully synchronized */
405 u_long maxunsync
; /* max time in seconds a receiver is trusted after loosing synchronisation */
406 double ppsphaseadjust
; /* phase adjustment of PPS time stamp */
407 u_long lastmissed
; /* time (ntp) when poll didn't get data (powerup heuristic) */
408 u_long ppsserial
; /* magic cookie for ppsclock serials (avoids stale ppsclock data) */
409 int ppsfd
; /* fd to ise for PPS io */
411 int hardppsstate
; /* current hard pps state */
412 struct refclock_atom atom
; /* PPSAPI structure */
414 parsetime_t timedata
; /* last (parse module) data */
415 void *localdata
; /* optional local, receiver-specific data */
416 unsigned long localstate
; /* private local state */
417 struct errorinfo errors
[ERR_CNT
]; /* error state table for suppressing excessive error messages */
418 struct ctl_var
*kv
; /* additional pseudo variables */
419 u_long laststatistic
; /* time when staticstics where output */
423 /**===========================================================================
424 ** Clockinfo section all parameter for specific clock types
425 ** includes NTP parameters, TTY parameters and IO handling parameters
428 static void poll_dpoll (struct parseunit
*);
429 static void poll_poll (struct peer
*);
430 static int poll_init (struct parseunit
*);
432 typedef struct poll_info
434 u_long rate
; /* poll rate - once every "rate" seconds - 0 off */
435 const char *string
; /* string to send for polling */
436 u_long count
; /* number of characters in string */
439 #define NO_CL_FLAGS 0
446 #define NO_PPSDELAY 0
448 #define DCF_ID "DCF" /* generic DCF */
449 #define DCF_A_ID "DCFa" /* AM demodulation */
450 #define DCF_P_ID "DCFp" /* psuedo random phase shift */
451 #define GPS_ID "GPS" /* GPS receiver */
453 #define NOCLOCK_ROOTDELAY 0.0
454 #define NOCLOCK_BASEDELAY 0.0
455 #define NOCLOCK_DESCRIPTION 0
456 #define NOCLOCK_MAXUNSYNC 0
457 #define NOCLOCK_CFLAG 0
458 #define NOCLOCK_IFLAG 0
459 #define NOCLOCK_OFLAG 0
460 #define NOCLOCK_LFLAG 0
461 #define NOCLOCK_ID "TILT"
462 #define NOCLOCK_POLL NO_POLL
463 #define NOCLOCK_INIT NO_INIT
464 #define NOCLOCK_END NO_END
465 #define NOCLOCK_DATA NO_LCLDATA
466 #define NOCLOCK_FORMAT ""
467 #define NOCLOCK_TYPE CTL_SST_TS_UNSPEC
468 #define NOCLOCK_SAMPLES 0
469 #define NOCLOCK_KEEP 0
471 #define DCF_TYPE CTL_SST_TS_LF
472 #define GPS_TYPE CTL_SST_TS_UHF
475 * receiver specific constants
477 #define MBG_SPEED (B9600)
478 #define MBG_CFLAG (CS7|PARENB|CREAD|CLOCAL|HUPCL|CSTOPB)
479 #define MBG_IFLAG (IGNBRK|IGNPAR|ISTRIP)
482 #define MBG_FLAGS PARSE_F_PPSONSECOND
485 * Meinberg DCF77 receivers
487 #define DCFUA31_ROOTDELAY 0.0 /* 0 */
488 #define DCFUA31_BASEDELAY 0.010 /* 10.7421875ms: 10 ms (+/- 3 ms) */
489 #define DCFUA31_DESCRIPTION "Meinberg DCF77 C51 or compatible"
490 #define DCFUA31_MAXUNSYNC 60*30 /* only trust clock for 1/2 hour */
491 #define DCFUA31_SPEED MBG_SPEED
492 #define DCFUA31_CFLAG MBG_CFLAG
493 #define DCFUA31_IFLAG MBG_IFLAG
494 #define DCFUA31_OFLAG MBG_OFLAG
495 #define DCFUA31_LFLAG MBG_LFLAG
496 #define DCFUA31_SAMPLES 5
497 #define DCFUA31_KEEP 3
498 #define DCFUA31_FORMAT "Meinberg Standard"
501 * Meinberg DCF PZF535/TCXO (FM/PZF) receiver
503 #define DCFPZF535_ROOTDELAY 0.0
504 #define DCFPZF535_BASEDELAY 0.001968 /* 1.968ms +- 104us (oscilloscope) - relative to start (end of STX) */
505 #define DCFPZF535_DESCRIPTION "Meinberg DCF PZF 535/509 / TCXO"
506 #define DCFPZF535_MAXUNSYNC 60*60*12 /* only trust clock for 12 hours
507 * @ 5e-8df/f we have accumulated
508 * at most 2.16 ms (thus we move to
509 * NTP synchronisation */
510 #define DCFPZF535_SPEED MBG_SPEED
511 #define DCFPZF535_CFLAG MBG_CFLAG
512 #define DCFPZF535_IFLAG MBG_IFLAG
513 #define DCFPZF535_OFLAG MBG_OFLAG
514 #define DCFPZF535_LFLAG MBG_LFLAG
515 #define DCFPZF535_SAMPLES 5
516 #define DCFPZF535_KEEP 3
517 #define DCFPZF535_FORMAT "Meinberg Standard"
520 * Meinberg DCF PZF535/OCXO receiver
522 #define DCFPZF535OCXO_ROOTDELAY 0.0
523 #define DCFPZF535OCXO_BASEDELAY 0.001968 /* 1.968ms +- 104us (oscilloscope) - relative to start (end of STX) */
524 #define DCFPZF535OCXO_DESCRIPTION "Meinberg DCF PZF 535/509 / OCXO"
525 #define DCFPZF535OCXO_MAXUNSYNC 60*60*96 /* only trust clock for 4 days
526 * @ 5e-9df/f we have accumulated
527 * at most an error of 1.73 ms
528 * (thus we move to NTP synchronisation) */
529 #define DCFPZF535OCXO_SPEED MBG_SPEED
530 #define DCFPZF535OCXO_CFLAG MBG_CFLAG
531 #define DCFPZF535OCXO_IFLAG MBG_IFLAG
532 #define DCFPZF535OCXO_OFLAG MBG_OFLAG
533 #define DCFPZF535OCXO_LFLAG MBG_LFLAG
534 #define DCFPZF535OCXO_SAMPLES 5
535 #define DCFPZF535OCXO_KEEP 3
536 #define DCFPZF535OCXO_FORMAT "Meinberg Standard"
539 * Meinberg GPS16X receiver
541 static void gps16x_message (struct parseunit
*, parsetime_t
*);
542 static int gps16x_poll_init (struct parseunit
*);
544 #define GPS16X_ROOTDELAY 0.0 /* nothing here */
545 #define GPS16X_BASEDELAY 0.001968 /* XXX to be fixed ! 1.968ms +- 104us (oscilloscope) - relative to start (end of STX) */
546 #define GPS16X_DESCRIPTION "Meinberg GPS16x receiver"
547 #define GPS16X_MAXUNSYNC 60*60*96 /* only trust clock for 4 days
548 * @ 5e-9df/f we have accumulated
549 * at most an error of 1.73 ms
550 * (thus we move to NTP synchronisation) */
551 #define GPS16X_SPEED B19200
552 #define GPS16X_CFLAG (CS8|CREAD|CLOCAL|HUPCL)
553 #define GPS16X_IFLAG (IGNBRK|IGNPAR)
554 #define GPS16X_OFLAG MBG_OFLAG
555 #define GPS16X_LFLAG MBG_LFLAG
556 #define GPS16X_POLLRATE 6
557 #define GPS16X_POLLCMD ""
558 #define GPS16X_CMDSIZE 0
560 static poll_info_t gps16x_pollinfo
= { GPS16X_POLLRATE
, GPS16X_POLLCMD
, GPS16X_CMDSIZE
};
562 #define GPS16X_INIT gps16x_poll_init
563 #define GPS16X_POLL 0
565 #define GPS16X_DATA ((void *)(&gps16x_pollinfo))
566 #define GPS16X_MESSAGE gps16x_message
567 #define GPS16X_ID GPS_ID
568 #define GPS16X_FORMAT "Meinberg GPS Extended"
569 #define GPS16X_SAMPLES 5
570 #define GPS16X_KEEP 3
573 * ELV DCF7000 Wallclock-Receiver/Switching Clock (Kit)
575 * This is really not the hottest clock - but before you have nothing ...
577 #define DCF7000_ROOTDELAY 0.0 /* 0 */
578 #define DCF7000_BASEDELAY 0.405 /* slow blow */
579 #define DCF7000_DESCRIPTION "ELV DCF7000"
580 #define DCF7000_MAXUNSYNC (60*5) /* sorry - but it just was not build as a clock */
581 #define DCF7000_SPEED (B9600)
582 #define DCF7000_CFLAG (CS8|CREAD|PARENB|PARODD|CLOCAL|HUPCL)
583 #define DCF7000_IFLAG (IGNBRK)
584 #define DCF7000_OFLAG 0
585 #define DCF7000_LFLAG 0
586 #define DCF7000_SAMPLES 5
587 #define DCF7000_KEEP 3
588 #define DCF7000_FORMAT "ELV DCF7000"
591 * Schmid DCF Receiver Kit
593 * When the WSDCF clock is operating optimally we want the primary clock
594 * distance to come out at 300 ms. Thus, peer.distance in the WSDCF peer
595 * structure is set to 290 ms and we compute delays which are at least
596 * 10 ms long. The following are 290 ms and 10 ms expressed in u_fp format
598 #define WS_POLLRATE 1 /* every second - watch interdependency with poll routine */
599 #define WS_POLLCMD "\163"
602 static poll_info_t wsdcf_pollinfo
= { WS_POLLRATE
, WS_POLLCMD
, WS_CMDSIZE
};
604 #define WSDCF_INIT poll_init
605 #define WSDCF_POLL poll_dpoll
607 #define WSDCF_DATA ((void *)(&wsdcf_pollinfo))
608 #define WSDCF_ROOTDELAY 0.0 /* 0 */
609 #define WSDCF_BASEDELAY 0.010 /* ~ 10ms */
610 #define WSDCF_DESCRIPTION "WS/DCF Receiver"
611 #define WSDCF_FORMAT "Schmid"
612 #define WSDCF_MAXUNSYNC (60*60) /* assume this beast hold at 1 h better than 2 ms XXX-must verify */
613 #define WSDCF_SPEED (B1200)
614 #define WSDCF_CFLAG (CS8|CREAD|CLOCAL)
615 #define WSDCF_IFLAG 0
616 #define WSDCF_OFLAG 0
617 #define WSDCF_LFLAG 0
618 #define WSDCF_SAMPLES 5
622 * RAW DCF77 - input of DCF marks via RS232 - many variants
624 #define RAWDCF_FLAGS 0
625 #define RAWDCF_ROOTDELAY 0.0 /* 0 */
626 #define RAWDCF_BASEDELAY 0.258
627 #define RAWDCF_FORMAT "RAW DCF77 Timecode"
628 #define RAWDCF_MAXUNSYNC (0) /* sorry - its a true receiver - no signal - no time */
629 #define RAWDCF_SPEED (B50)
630 #ifdef NO_PARENB_IGNPAR /* Was: defined(SYS_IRIX4) || defined(SYS_IRIX5) */
631 /* somehow doesn't grok PARENB & IGNPAR (mj) */
632 # define RAWDCF_CFLAG (CS8|CREAD|CLOCAL)
634 # define RAWDCF_CFLAG (CS8|CREAD|CLOCAL|PARENB)
636 #ifdef RAWDCF_NO_IGNPAR /* Was: defined(SYS_LINUX) && defined(CLOCK_RAWDCF) */
637 # define RAWDCF_IFLAG 0
639 # define RAWDCF_IFLAG (IGNPAR)
641 #define RAWDCF_OFLAG 0
642 #define RAWDCF_LFLAG 0
643 #define RAWDCF_SAMPLES 20
644 #define RAWDCF_KEEP 12
645 #define RAWDCF_INIT 0
653 * simplest (cheapest) DCF clock - e. g. DCF77 receiver by Conrad
654 * (~40DM - roughly $30 ) followed by a level converter for RS232
656 #define CONRAD_BASEDELAY 0.292 /* Conrad receiver @ 50 Baud on a Sun */
657 #define CONRAD_DESCRIPTION "RAW DCF77 CODE (Conrad DCF77 receiver module)"
659 /* Gude Analog- und Digitalsystem GmbH 'Expert mouseCLOCK USB v2.0' */
660 #define GUDE_EMC_USB_V20_SPEED (B4800)
661 #define GUDE_EMC_USB_V20_BASEDELAY 0.425 /* USB serial<->USB converter FTDI232R */
662 #define GUDE_EMC_USB_V20_DESCRIPTION "RAW DCF77 CODE (Expert mouseCLOCK USB v2.0)"
667 #define TIMEBRICK_BASEDELAY 0.210 /* TimeBrick @ 50 Baud on a Sun */
668 #define TIMEBRICK_DESCRIPTION "RAW DCF77 CODE (TimeBrick)"
671 * IGEL:clock receiver
673 #define IGELCLOCK_BASEDELAY 0.258 /* IGEL:clock receiver */
674 #define IGELCLOCK_DESCRIPTION "RAW DCF77 CODE (IGEL:clock)"
675 #define IGELCLOCK_SPEED (B1200)
676 #define IGELCLOCK_CFLAG (CS8|CREAD|HUPCL|CLOCAL)
679 * RAWDCF receivers that need to be powered from DTR
680 * (like Expert mouse clock)
682 static int rawdcf_init_1 (struct parseunit
*);
683 #define RAWDCFDTRSET_DESCRIPTION "RAW DCF77 CODE (DTR SET/RTS CLR)"
684 #define RAWDCFDTRSET_INIT rawdcf_init_1
687 * RAWDCF receivers that need to be powered from
688 * DTR CLR and RTS SET
690 static int rawdcf_init_2 (struct parseunit
*);
691 #define RAWDCFDTRCLRRTSSET_DESCRIPTION "RAW DCF77 CODE (DTR CLR/RTS SET)"
692 #define RAWDCFDTRCLRRTSSET_INIT rawdcf_init_2
695 * Trimble GPS receivers (TAIP and TSIP protocols)
697 #ifndef TRIM_POLLRATE
698 #define TRIM_POLLRATE 0 /* only true direct polling */
701 #define TRIM_TAIPPOLLCMD ">SRM;FR_FLAG=F;EC_FLAG=F<>QTM<"
702 #define TRIM_TAIPCMDSIZE (sizeof(TRIM_TAIPPOLLCMD)-1)
704 static poll_info_t trimbletaip_pollinfo
= { TRIM_POLLRATE
, TRIM_TAIPPOLLCMD
, TRIM_TAIPCMDSIZE
};
705 static int trimbletaip_init (struct parseunit
*);
706 static void trimbletaip_event (struct parseunit
*, int);
708 /* query time & UTC correction data */
709 static char tsipquery
[] = { DLE
, 0x21, DLE
, ETX
, DLE
, 0x2F, DLE
, ETX
};
711 static poll_info_t trimbletsip_pollinfo
= { TRIM_POLLRATE
, tsipquery
, sizeof(tsipquery
) };
712 static int trimbletsip_init (struct parseunit
*);
713 static void trimbletsip_end (struct parseunit
*);
714 static void trimbletsip_message (struct parseunit
*, parsetime_t
*);
715 static void trimbletsip_event (struct parseunit
*, int);
717 #define TRIMBLETSIP_IDLE_TIME (300) /* 5 minutes silence at most */
718 #define TRIMBLE_RESET_HOLDOFF TRIMBLETSIP_IDLE_TIME
720 #define TRIMBLETAIP_SPEED (B4800)
721 #define TRIMBLETAIP_CFLAG (CS8|CREAD|CLOCAL)
722 #define TRIMBLETAIP_IFLAG (BRKINT|IGNPAR|ISTRIP|ICRNL|IXON)
723 #define TRIMBLETAIP_OFLAG (OPOST|ONLCR)
724 #define TRIMBLETAIP_LFLAG (0)
726 #define TRIMBLETSIP_SPEED (B9600)
727 #define TRIMBLETSIP_CFLAG (CS8|CLOCAL|CREAD|PARENB|PARODD)
728 #define TRIMBLETSIP_IFLAG (IGNBRK)
729 #define TRIMBLETSIP_OFLAG (0)
730 #define TRIMBLETSIP_LFLAG (ICANON)
732 #define TRIMBLETSIP_SAMPLES 5
733 #define TRIMBLETSIP_KEEP 3
734 #define TRIMBLETAIP_SAMPLES 5
735 #define TRIMBLETAIP_KEEP 3
737 #define TRIMBLETAIP_FLAGS (PARSE_F_PPSONSECOND)
738 #define TRIMBLETSIP_FLAGS (TRIMBLETAIP_FLAGS)
740 #define TRIMBLETAIP_POLL poll_dpoll
741 #define TRIMBLETSIP_POLL poll_dpoll
743 #define TRIMBLETAIP_INIT trimbletaip_init
744 #define TRIMBLETSIP_INIT trimbletsip_init
746 #define TRIMBLETAIP_EVENT trimbletaip_event
748 #define TRIMBLETSIP_EVENT trimbletsip_event
749 #define TRIMBLETSIP_MESSAGE trimbletsip_message
751 #define TRIMBLETAIP_END 0
752 #define TRIMBLETSIP_END trimbletsip_end
754 #define TRIMBLETAIP_DATA ((void *)(&trimbletaip_pollinfo))
755 #define TRIMBLETSIP_DATA ((void *)(&trimbletsip_pollinfo))
757 #define TRIMBLETAIP_ID GPS_ID
758 #define TRIMBLETSIP_ID GPS_ID
760 #define TRIMBLETAIP_FORMAT "Trimble TAIP"
761 #define TRIMBLETSIP_FORMAT "Trimble TSIP"
763 #define TRIMBLETAIP_ROOTDELAY 0x0
764 #define TRIMBLETSIP_ROOTDELAY 0x0
766 #define TRIMBLETAIP_BASEDELAY 0.0
767 #define TRIMBLETSIP_BASEDELAY 0.020 /* GPS time message latency */
769 #define TRIMBLETAIP_DESCRIPTION "Trimble GPS (TAIP) receiver"
770 #define TRIMBLETSIP_DESCRIPTION "Trimble GPS (TSIP) receiver"
772 #define TRIMBLETAIP_MAXUNSYNC 0
773 #define TRIMBLETSIP_MAXUNSYNC 0
775 #define TRIMBLETAIP_EOL '<'
778 * RadioCode Clocks RCC 800 receiver
780 #define RCC_POLLRATE 0 /* only true direct polling */
781 #define RCC_POLLCMD "\r"
782 #define RCC_CMDSIZE 1
784 static poll_info_t rcc8000_pollinfo
= { RCC_POLLRATE
, RCC_POLLCMD
, RCC_CMDSIZE
};
785 #define RCC8000_FLAGS 0
786 #define RCC8000_POLL poll_dpoll
787 #define RCC8000_INIT poll_init
788 #define RCC8000_END 0
789 #define RCC8000_DATA ((void *)(&rcc8000_pollinfo))
790 #define RCC8000_ROOTDELAY 0.0
791 #define RCC8000_BASEDELAY 0.0
792 #define RCC8000_ID "MSF"
793 #define RCC8000_DESCRIPTION "RCC 8000 MSF Receiver"
794 #define RCC8000_FORMAT "Radiocode RCC8000"
795 #define RCC8000_MAXUNSYNC (60*60) /* should be ok for an hour */
796 #define RCC8000_SPEED (B2400)
797 #define RCC8000_CFLAG (CS8|CREAD|CLOCAL)
798 #define RCC8000_IFLAG (IGNBRK|IGNPAR)
799 #define RCC8000_OFLAG 0
800 #define RCC8000_LFLAG 0
801 #define RCC8000_SAMPLES 5
802 #define RCC8000_KEEP 3
805 * Hopf Radio clock 6021 Format
808 #define HOPF6021_ROOTDELAY 0.0
809 #define HOPF6021_BASEDELAY 0.0
810 #define HOPF6021_DESCRIPTION "HOPF 6021"
811 #define HOPF6021_FORMAT "hopf Funkuhr 6021"
812 #define HOPF6021_MAXUNSYNC (60*60) /* should be ok for an hour */
813 #define HOPF6021_SPEED (B9600)
814 #define HOPF6021_CFLAG (CS8|CREAD|CLOCAL)
815 #define HOPF6021_IFLAG (IGNBRK|ISTRIP)
816 #define HOPF6021_OFLAG 0
817 #define HOPF6021_LFLAG 0
818 #define HOPF6021_FLAGS 0
819 #define HOPF6021_SAMPLES 5
820 #define HOPF6021_KEEP 3
823 * Diem's Computime Radio Clock Receiver
825 #define COMPUTIME_FLAGS 0
826 #define COMPUTIME_ROOTDELAY 0.0
827 #define COMPUTIME_BASEDELAY 0.0
828 #define COMPUTIME_ID DCF_ID
829 #define COMPUTIME_DESCRIPTION "Diem's Computime receiver"
830 #define COMPUTIME_FORMAT "Diem's Computime Radio Clock"
831 #define COMPUTIME_TYPE DCF_TYPE
832 #define COMPUTIME_MAXUNSYNC (60*60) /* only trust clock for 1 hour */
833 #define COMPUTIME_SPEED (B9600)
834 #define COMPUTIME_CFLAG (CSTOPB|CS7|CREAD|CLOCAL)
835 #define COMPUTIME_IFLAG (IGNBRK|IGNPAR|ISTRIP)
836 #define COMPUTIME_OFLAG 0
837 #define COMPUTIME_LFLAG 0
838 #define COMPUTIME_SAMPLES 5
839 #define COMPUTIME_KEEP 3
842 * Varitext Radio Clock Receiver
844 #define VARITEXT_FLAGS 0
845 #define VARITEXT_ROOTDELAY 0.0
846 #define VARITEXT_BASEDELAY 0.0
847 #define VARITEXT_ID "MSF"
848 #define VARITEXT_DESCRIPTION "Varitext receiver"
849 #define VARITEXT_FORMAT "Varitext Radio Clock"
850 #define VARITEXT_TYPE DCF_TYPE
851 #define VARITEXT_MAXUNSYNC (60*60) /* only trust clock for 1 hour */
852 #define VARITEXT_SPEED (B9600)
853 #define VARITEXT_CFLAG (CS7|CREAD|CLOCAL|PARENB|PARODD)
854 #define VARITEXT_IFLAG (IGNPAR|IGNBRK|INPCK) /*|ISTRIP)*/
855 #define VARITEXT_OFLAG 0
856 #define VARITEXT_LFLAG 0
857 #define VARITEXT_SAMPLES 32
858 #define VARITEXT_KEEP 20
860 static struct parse_clockinfo
862 u_long cl_flags
; /* operation flags (io modes) */
863 void (*cl_poll
) (struct parseunit
*); /* active poll routine */
864 int (*cl_init
) (struct parseunit
*); /* active poll init routine */
865 void (*cl_event
) (struct parseunit
*, int); /* special event handling (e.g. reset clock) */
866 void (*cl_end
) (struct parseunit
*); /* active poll end routine */
867 void (*cl_message
) (struct parseunit
*, parsetime_t
*); /* process a lower layer message */
868 void *cl_data
; /* local data area for "poll" mechanism */
869 double cl_rootdelay
; /* rootdelay */
870 double cl_basedelay
; /* current offset by which the RS232
871 time code is delayed from the actual time */
872 const char *cl_id
; /* ID code */
873 const char *cl_description
; /* device name */
874 const char *cl_format
; /* fixed format */
875 u_char cl_type
; /* clock type (ntp control) */
876 u_long cl_maxunsync
; /* time to trust oscillator after losing synch */
877 u_long cl_speed
; /* terminal input & output baudrate */
878 u_long cl_cflag
; /* terminal control flags */
879 u_long cl_iflag
; /* terminal input flags */
880 u_long cl_oflag
; /* terminal output flags */
881 u_long cl_lflag
; /* terminal local flags */
882 u_long cl_samples
; /* samples for median filter */
883 u_long cl_keep
; /* samples for median filter to keep */
884 } parse_clockinfo
[] =
897 DCFPZF535_DESCRIPTION
,
917 DCFPZF535OCXO_ROOTDELAY
,
918 DCFPZF535OCXO_BASEDELAY
,
920 DCFPZF535OCXO_DESCRIPTION
,
921 DCFPZF535OCXO_FORMAT
,
923 DCFPZF535OCXO_MAXUNSYNC
,
929 DCFPZF535OCXO_SAMPLES
,
1033 TIMEBRICK_BASEDELAY
,
1035 TIMEBRICK_DESCRIPTION
,
1079 IGELCLOCK_BASEDELAY
,
1081 IGELCLOCK_DESCRIPTION
,
1095 #if TRIM_POLLRATE /* DHD940515: Allow user config */
1105 TRIMBLETAIP_ROOTDELAY
,
1106 TRIMBLETAIP_BASEDELAY
,
1108 TRIMBLETAIP_DESCRIPTION
,
1111 TRIMBLETAIP_MAXUNSYNC
,
1117 TRIMBLETAIP_SAMPLES
,
1122 #if TRIM_POLLRATE /* DHD940515: Allow user config */
1130 TRIMBLETSIP_MESSAGE
,
1132 TRIMBLETSIP_ROOTDELAY
,
1133 TRIMBLETSIP_BASEDELAY
,
1135 TRIMBLETSIP_DESCRIPTION
,
1138 TRIMBLETSIP_MAXUNSYNC
,
1144 TRIMBLETSIP_SAMPLES
,
1158 RCC8000_DESCRIPTION
,
1181 HOPF6021_DESCRIPTION
,
1201 COMPUTIME_ROOTDELAY
,
1202 COMPUTIME_BASEDELAY
,
1204 COMPUTIME_DESCRIPTION
,
1207 COMPUTIME_MAXUNSYNC
,
1227 RAWDCFDTRSET_DESCRIPTION
,
1240 0, /* operation flags (io modes) */
1241 NO_POLL
, /* active poll routine */
1242 NO_INIT
, /* active poll init routine */
1243 NO_EVENT
, /* special event handling (e.g. reset clock) */
1244 NO_END
, /* active poll end routine */
1245 NO_MESSAGE
, /* process a lower layer message */
1246 NO_LCLDATA
, /* local data area for "poll" mechanism */
1248 11.0 /* bits */ / 9600, /* current offset by which the RS232
1249 time code is delayed from the actual time */
1250 DCF_ID
, /* ID code */
1251 "WHARTON 400A Series clock", /* device name */
1252 "WHARTON 400A Series clock Output Format 1", /* fixed format */
1253 /* Must match a format-name in a libparse/clk_xxx.c file */
1254 DCF_TYPE
, /* clock type (ntp control) */
1255 (1*60*60), /* time to trust oscillator after losing synch */
1256 B9600
, /* terminal input & output baudrate */
1257 (CS8
|CREAD
|PARENB
|CLOCAL
|HUPCL
),/* terminal control flags */
1258 0, /* terminal input flags */
1259 0, /* terminal output flags */
1260 0, /* terminal local flags */
1261 5, /* samples for median filter */
1262 3, /* samples for median filter to keep */
1264 { /* mode 16 - RAWDCF RTS set, DTR clr */
1267 RAWDCFDTRCLRRTSSET_INIT
,
1275 RAWDCFDTRCLRRTSSET_DESCRIPTION
,
1298 VARITEXT_DESCRIPTION
,
1342 GUDE_EMC_USB_V20_BASEDELAY
,
1344 GUDE_EMC_USB_V20_DESCRIPTION
,
1348 GUDE_EMC_USB_V20_SPEED
,
1358 static int ncltypes
= sizeof(parse_clockinfo
) / sizeof(struct parse_clockinfo
);
1360 #define CLK_REALTYPE(x) ((int)(((x)->ttl) & 0x7F))
1361 #define CLK_TYPE(x) ((CLK_REALTYPE(x) >= ncltypes) ? ~0 : CLK_REALTYPE(x))
1362 #define CLK_UNIT(x) ((int)REFCLOCKUNIT(&(x)->srcadr))
1363 #define CLK_PPS(x) (((x)->ttl) & 0x80)
1366 * Other constant stuff
1368 #define PARSEHSREFID 0x7f7f08ff /* 127.127.8.255 refid for hi strata */
1370 #define PARSESTATISTICS (60*60) /* output state statistics every hour */
1372 static int notice
= 0;
1374 #define PARSE_STATETIME(parse, i) ((parse->generic->currentstatus == i) ? parse->statetime[i] + current_time - parse->lastchange : parse->statetime[i])
1376 static void parse_event (struct parseunit
*, int);
1377 static void parse_process (struct parseunit
*, parsetime_t
*);
1378 static void clear_err (struct parseunit
*, u_long
);
1379 static int list_err (struct parseunit
*, u_long
);
1380 static char * l_mktime (u_long
);
1382 /**===========================================================================
1383 ** implementation error message regression module
1387 struct parseunit
*parse
,
1391 if (lstate
== ERR_ALL
)
1395 for (i
= 0; i
< ERR_CNT
; i
++)
1397 parse
->errors
[i
].err_stage
= err_tbl
[i
];
1398 parse
->errors
[i
].err_cnt
= 0;
1399 parse
->errors
[i
].err_last
= 0;
1400 parse
->errors
[i
].err_started
= 0;
1401 parse
->errors
[i
].err_suppressed
= 0;
1406 parse
->errors
[lstate
].err_stage
= err_tbl
[lstate
];
1407 parse
->errors
[lstate
].err_cnt
= 0;
1408 parse
->errors
[lstate
].err_last
= 0;
1409 parse
->errors
[lstate
].err_started
= 0;
1410 parse
->errors
[lstate
].err_suppressed
= 0;
1416 struct parseunit
*parse
,
1421 struct errorinfo
*err
= &parse
->errors
[lstate
];
1423 if (err
->err_started
== 0)
1425 err
->err_started
= current_time
;
1428 do_it
= (current_time
- err
->err_last
) >= err
->err_stage
->err_delay
;
1433 if (err
->err_stage
->err_count
&&
1434 (err
->err_cnt
>= err
->err_stage
->err_count
))
1440 if (!err
->err_cnt
&& do_it
)
1441 msyslog(LOG_INFO
, "PARSE receiver #%d: interval for following error message class is at least %s",
1442 CLK_UNIT(parse
->peer
), l_mktime(err
->err_stage
->err_delay
));
1445 err
->err_suppressed
++;
1447 err
->err_last
= current_time
;
1449 if (do_it
&& err
->err_suppressed
)
1451 msyslog(LOG_INFO
, "PARSE receiver #%d: %ld message%s suppressed, error condition class persists for %s",
1452 CLK_UNIT(parse
->peer
), err
->err_suppressed
, (err
->err_suppressed
== 1) ? " was" : "s where",
1453 l_mktime(current_time
- err
->err_started
));
1454 err
->err_suppressed
= 0;
1460 /*--------------------------------------------------
1461 * mkreadable - make a printable ascii string (without
1462 * embedded quotes so that the ntpq protocol isn't
1466 #define isprint(_X_) (((_X_) > 0x1F) && ((_X_) < 0x7F))
1479 char *endb
= (char *)0;
1482 return (char *)0; /* don't bother with mini buffers */
1484 endb
= buffer
+ blen
- 4;
1486 blen
--; /* account for '\0' */
1488 while (blen
&& srclen
--)
1490 if (!hex
&& /* no binary only */
1491 (*src
!= '\\') && /* no plain \ */
1492 (*src
!= '"') && /* no " */
1493 isprint((unsigned char)*src
)) /* only printables */
1494 { /* they are easy... */
1513 strcpy(buffer
,"\\\\");
1520 sprintf(buffer
, "\\x%02x", *src
++);
1526 if (srclen
&& !blen
&& endb
) /* overflow - set last chars to ... */
1527 strcpy(endb
, "...");
1535 /*--------------------------------------------------
1536 * mkascii - make a printable ascii string
1537 * assumes (unless defined better) 7-bit ASCII
1547 return mkreadable(buffer
, blen
, src
, srclen
, 0);
1550 /**===========================================================================
1551 ** implementation of i/o handling methods
1552 ** (all STREAM, partial STREAM, user level)
1556 * define possible io handling methods
1559 static int ppsclock_init (struct parseunit
*);
1560 static int stream_init (struct parseunit
*);
1561 static void stream_end (struct parseunit
*);
1562 static int stream_enable (struct parseunit
*);
1563 static int stream_disable (struct parseunit
*);
1564 static int stream_setcs (struct parseunit
*, parsectl_t
*);
1565 static int stream_getfmt (struct parseunit
*, parsectl_t
*);
1566 static int stream_setfmt (struct parseunit
*, parsectl_t
*);
1567 static int stream_timecode (struct parseunit
*, parsectl_t
*);
1568 static void stream_receive (struct recvbuf
*);
1571 static int local_init (struct parseunit
*);
1572 static void local_end (struct parseunit
*);
1573 static int local_nop (struct parseunit
*);
1574 static int local_setcs (struct parseunit
*, parsectl_t
*);
1575 static int local_getfmt (struct parseunit
*, parsectl_t
*);
1576 static int local_setfmt (struct parseunit
*, parsectl_t
*);
1577 static int local_timecode (struct parseunit
*, parsectl_t
*);
1578 static void local_receive (struct recvbuf
*);
1579 static int local_input (struct recvbuf
*);
1581 static bind_t io_bindings
[] =
1631 #define fix_ts(_X_) \
1632 if ((&(_X_))->tv.tv_usec >= 1000000) \
1634 (&(_X_))->tv.tv_usec -= 1000000; \
1635 (&(_X_))->tv.tv_sec += 1; \
1638 #define cvt_ts(_X_, _Y_) \
1642 if (!buftvtots((const char *)&(&(_X_))->tv, &ts)) \
1645 msyslog(LOG_ERR,"parse: stream_receive: timestamp conversion error (buftvtots) (%s) (%ld.%06ld) ", (_Y_), (long)(&(_X_))->tv.tv_sec, (long)(&(_X_))->tv.tv_usec);\
1650 (&(_X_))->fp = ts; \
1654 /*--------------------------------------------------
1655 * ppsclock STREAM init
1659 struct parseunit
*parse
1662 static char m1
[] = "ppsclocd";
1663 static char m2
[] = "ppsclock";
1666 * now push the parse streams module
1667 * it will ensure exclusive access to the device
1669 if (ioctl(parse
->ppsfd
, I_PUSH
, (caddr_t
)m1
) == -1 &&
1670 ioctl(parse
->ppsfd
, I_PUSH
, (caddr_t
)m2
) == -1)
1672 if (errno
!= EINVAL
)
1674 msyslog(LOG_ERR
, "PARSE receiver #%d: ppsclock_init: ioctl(fd, I_PUSH, \"ppsclock\"): %m",
1675 CLK_UNIT(parse
->peer
));
1679 if (!local_init(parse
))
1681 (void)ioctl(parse
->ppsfd
, I_POP
, (caddr_t
)0);
1685 parse
->flags
|= PARSE_PPSCLOCK
;
1689 /*--------------------------------------------------
1694 struct parseunit
*parse
1697 static char m1
[] = "parse";
1699 * now push the parse streams module
1700 * to test whether it is there (neat interface 8-( )
1702 if (ioctl(parse
->generic
->io
.fd
, I_PUSH
, (caddr_t
)m1
) == -1)
1704 if (errno
!= EINVAL
) /* accept non-existence */
1706 msyslog(LOG_ERR
, "PARSE receiver #%d: stream_init: ioctl(fd, I_PUSH, \"parse\"): %m", CLK_UNIT(parse
->peer
));
1712 while(ioctl(parse
->generic
->io
.fd
, I_POP
, (caddr_t
)0) == 0)
1716 * now push it a second time after we have removed all
1719 if (ioctl(parse
->generic
->io
.fd
, I_PUSH
, (caddr_t
)m1
) == -1)
1721 msyslog(LOG_ERR
, "PARSE receiver #%d: stream_init: ioctl(fd, I_PUSH, \"parse\"): %m", CLK_UNIT(parse
->peer
));
1731 /*--------------------------------------------------
1736 struct parseunit
*parse
1739 while(ioctl(parse
->generic
->io
.fd
, I_POP
, (caddr_t
)0) == 0)
1743 /*--------------------------------------------------
1748 struct parseunit
*parse
,
1752 struct strioctl strioc
;
1754 strioc
.ic_cmd
= PARSEIOC_SETCS
;
1755 strioc
.ic_timout
= 0;
1756 strioc
.ic_dp
= (char *)tcl
;
1757 strioc
.ic_len
= sizeof (*tcl
);
1759 if (ioctl(parse
->generic
->io
.fd
, I_STR
, (caddr_t
)&strioc
) == -1)
1761 msyslog(LOG_ERR
, "PARSE receiver #%d: stream_setcs: ioctl(fd, I_STR, PARSEIOC_SETCS): %m", CLK_UNIT(parse
->peer
));
1767 /*--------------------------------------------------
1772 struct parseunit
*parse
1775 struct strioctl strioc
;
1777 strioc
.ic_cmd
= PARSEIOC_ENABLE
;
1778 strioc
.ic_timout
= 0;
1779 strioc
.ic_dp
= (char *)0;
1782 if (ioctl(parse
->generic
->io
.fd
, I_STR
, (caddr_t
)&strioc
) == -1)
1784 msyslog(LOG_ERR
, "PARSE receiver #%d: stream_enable: ioctl(fd, I_STR, PARSEIOC_ENABLE): %m", CLK_UNIT(parse
->peer
));
1787 parse
->generic
->io
.clock_recv
= stream_receive
; /* ok - parse input in kernel */
1791 /*--------------------------------------------------
1796 struct parseunit
*parse
1799 struct strioctl strioc
;
1801 strioc
.ic_cmd
= PARSEIOC_DISABLE
;
1802 strioc
.ic_timout
= 0;
1803 strioc
.ic_dp
= (char *)0;
1806 if (ioctl(parse
->generic
->io
.fd
, I_STR
, (caddr_t
)&strioc
) == -1)
1808 msyslog(LOG_ERR
, "PARSE receiver #%d: stream_disable: ioctl(fd, I_STR, PARSEIOC_DISABLE): %m", CLK_UNIT(parse
->peer
));
1811 parse
->generic
->io
.clock_recv
= local_receive
; /* ok - parse input in daemon */
1815 /*--------------------------------------------------
1820 struct parseunit
*parse
,
1824 struct strioctl strioc
;
1826 strioc
.ic_cmd
= PARSEIOC_GETFMT
;
1827 strioc
.ic_timout
= 0;
1828 strioc
.ic_dp
= (char *)tcl
;
1829 strioc
.ic_len
= sizeof (*tcl
);
1830 if (ioctl(parse
->generic
->io
.fd
, I_STR
, (caddr_t
)&strioc
) == -1)
1832 msyslog(LOG_ERR
, "PARSE receiver #%d: ioctl(fd, I_STR, PARSEIOC_GETFMT): %m", CLK_UNIT(parse
->peer
));
1838 /*--------------------------------------------------
1843 struct parseunit
*parse
,
1847 struct strioctl strioc
;
1849 strioc
.ic_cmd
= PARSEIOC_SETFMT
;
1850 strioc
.ic_timout
= 0;
1851 strioc
.ic_dp
= (char *)tcl
;
1852 strioc
.ic_len
= sizeof (*tcl
);
1854 if (ioctl(parse
->generic
->io
.fd
, I_STR
, (caddr_t
)&strioc
) == -1)
1856 msyslog(LOG_ERR
, "PARSE receiver #%d: stream_setfmt: ioctl(fd, I_STR, PARSEIOC_SETFMT): %m", CLK_UNIT(parse
->peer
));
1863 /*--------------------------------------------------
1868 struct parseunit
*parse
,
1872 struct strioctl strioc
;
1874 strioc
.ic_cmd
= PARSEIOC_TIMECODE
;
1875 strioc
.ic_timout
= 0;
1876 strioc
.ic_dp
= (char *)tcl
;
1877 strioc
.ic_len
= sizeof (*tcl
);
1879 if (ioctl(parse
->generic
->io
.fd
, I_STR
, (caddr_t
)&strioc
) == -1)
1882 msyslog(LOG_ERR
, "PARSE receiver #%d: stream_timecode: ioctl(fd, I_STR, PARSEIOC_TIMECODE): %m", CLK_UNIT(parse
->peer
));
1885 clear_err(parse
, ERR_INTERNAL
);
1889 /*--------------------------------------------------
1894 struct recvbuf
*rbufp
1897 struct parseunit
*parse
= (struct parseunit
*)((void *)rbufp
->recv_srcclock
);
1898 parsetime_t parsetime
;
1903 if (rbufp
->recv_length
!= sizeof(parsetime_t
))
1906 msyslog(LOG_ERR
,"PARSE receiver #%d: stream_receive: bad size (got %d expected %d)",
1907 CLK_UNIT(parse
->peer
), rbufp
->recv_length
, (int)sizeof(parsetime_t
));
1908 parse_event(parse
, CEVNT_BADREPLY
);
1911 clear_err(parse
, ERR_BADIO
);
1913 memmove((caddr_t
)&parsetime
,
1914 (caddr_t
)rbufp
->recv_buffer
,
1915 sizeof(parsetime_t
));
1920 printf("PARSE receiver #%d: status %06x, state %08x, time %lx.%08lx, stime %lx.%08lx, ptime %lx.%08lx\n",
1921 CLK_UNIT(parse
->peer
),
1922 (unsigned int)parsetime
.parse_status
,
1923 (unsigned int)parsetime
.parse_state
,
1924 (unsigned long)parsetime
.parse_time
.tv
.tv_sec
,
1925 (unsigned long)parsetime
.parse_time
.tv
.tv_usec
,
1926 (unsigned long)parsetime
.parse_stime
.tv
.tv_sec
,
1927 (unsigned long)parsetime
.parse_stime
.tv
.tv_usec
,
1928 (unsigned long)parsetime
.parse_ptime
.tv
.tv_sec
,
1929 (unsigned long)parsetime
.parse_ptime
.tv
.tv_usec
);
1934 * switch time stamp world - be sure to normalize small usec field
1938 cvt_ts(parsetime
.parse_stime
, "parse_stime");
1940 if (PARSE_TIMECODE(parsetime
.parse_state
))
1942 cvt_ts(parsetime
.parse_time
, "parse_time");
1945 if (PARSE_PPS(parsetime
.parse_state
))
1946 cvt_ts(parsetime
.parse_ptime
, "parse_ptime");
1948 parse_process(parse
, &parsetime
);
1952 /*--------------------------------------------------
1957 struct parseunit
*parse
1960 return parse_ioinit(&parse
->parseio
);
1963 /*--------------------------------------------------
1968 struct parseunit
*parse
1971 parse_ioend(&parse
->parseio
);
1975 /*--------------------------------------------------
1980 struct parseunit
*parse
1986 /*--------------------------------------------------
1991 struct parseunit
*parse
,
1995 return parse_setcs(tcl
, &parse
->parseio
);
1998 /*--------------------------------------------------
2003 struct parseunit
*parse
,
2007 return parse_getfmt(tcl
, &parse
->parseio
);
2010 /*--------------------------------------------------
2015 struct parseunit
*parse
,
2019 return parse_setfmt(tcl
, &parse
->parseio
);
2022 /*--------------------------------------------------
2027 struct parseunit
*parse
,
2031 return parse_timecode(tcl
, &parse
->parseio
);
2035 /*--------------------------------------------------
2040 struct recvbuf
*rbufp
2043 struct parseunit
*parse
= (struct parseunit
*)((void *)rbufp
->recv_srcclock
);
2052 * eat all characters, parsing then and feeding complete samples
2054 count
= rbufp
->recv_length
;
2055 s
= (unsigned char *)rbufp
->recv_buffer
;
2056 ts
.fp
= rbufp
->recv_time
;
2060 if (parse_ioread(&parse
->parseio
, (unsigned int)(*s
++), &ts
))
2062 struct recvbuf
*buf
;
2065 * got something good to eat
2067 if (!PARSE_PPS(parse
->parseio
.parse_dtime
.parse_state
))
2070 if (parse
->flags
& PARSE_PPSCLOCK
)
2072 struct timespec pps_timeout
;
2073 pps_info_t pps_info
;
2075 pps_timeout
.tv_sec
= 0;
2076 pps_timeout
.tv_nsec
= 0;
2078 if (time_pps_fetch(parse
->atom
.handle
, PPS_TSFMT_TSPEC
, &pps_info
,
2081 if (pps_info
.assert_sequence
+ pps_info
.clear_sequence
!= parse
->ppsserial
)
2085 struct timespec pts
;
2087 * add PPS time stamp if available via ppsclock module
2088 * and not supplied already.
2090 if (parse
->flags
& PARSE_CLEAR
)
2091 pts
= pps_info
.clear_timestamp
;
2093 pts
= pps_info
.assert_timestamp
;
2095 parse
->parseio
.parse_dtime
.parse_ptime
.fp
.l_ui
= pts
.tv_sec
+ JAN_1970
;
2097 dtemp
= pts
.tv_nsec
/ 1e9
;
2100 parse
->parseio
.parse_dtime
.parse_ptime
.fp
.l_ui
--;
2104 parse
->parseio
.parse_dtime
.parse_ptime
.fp
.l_ui
++;
2106 parse
->parseio
.parse_dtime
.parse_ptime
.fp
.l_uf
= dtemp
* FRAC
;
2108 parse
->parseio
.parse_dtime
.parse_state
|= PARSEB_PPS
|PARSEB_S_PPS
;
2113 "parse: local_receive: fd %d PPSAPI seq %ld - PPS %s\n",
2115 (long)pps_info
.assert_sequence
+ (long)pps_info
.clear_sequence
,
2116 lfptoa(&parse
->parseio
.parse_dtime
.parse_ptime
.fp
, 6));
2126 "parse: local_receive: fd %d PPSAPI seq assert %ld, seq clear %ld - NO PPS event\n",
2128 (long)pps_info
.assert_sequence
, (long)pps_info
.clear_sequence
);
2132 parse
->ppsserial
= pps_info
.assert_sequence
+ pps_info
.clear_sequence
;
2140 "parse: local_receive: fd %d PPSAPI time_pps_fetch errno = %d\n",
2148 #ifdef TIOCDCDTIMESTAMP
2149 struct timeval dcd_time
;
2151 if (ioctl(parse
->ppsfd
, TIOCDCDTIMESTAMP
, &dcd_time
) != -1)
2155 TVTOTS(&dcd_time
, &tstmp
);
2156 tstmp
.l_ui
+= JAN_1970
;
2157 L_SUB(&ts
.fp
, &tstmp
);
2158 if (ts
.fp
.l_ui
== 0)
2164 "parse: local_receive: fd %d DCDTIMESTAMP %s\n",
2167 printf(" sigio %s\n",
2171 parse
->parseio
.parse_dtime
.parse_ptime
.fp
= tstmp
;
2172 parse
->parseio
.parse_dtime
.parse_state
|= PARSEB_PPS
|PARSEB_S_PPS
;
2175 #else /* TIOCDCDTIMESTAMP */
2176 #if defined(HAVE_STRUCT_PPSCLOCKEV) && (defined(HAVE_CIOGETEV) || defined(HAVE_TIOCGPPSEV))
2177 if (parse
->flags
& PARSE_PPSCLOCK
)
2180 struct ppsclockev ev
;
2182 #ifdef HAVE_CIOGETEV
2183 if (ioctl(parse
->ppsfd
, CIOGETEV
, (caddr_t
)&ev
) == 0)
2185 #ifdef HAVE_TIOCGPPSEV
2186 if (ioctl(parse
->ppsfd
, TIOCGPPSEV
, (caddr_t
)&ev
) == 0)
2189 if (ev
.serial
!= parse
->ppsserial
)
2192 * add PPS time stamp if available via ppsclock module
2193 * and not supplied already.
2195 if (!buftvtots((const char *)&ev
.tv
, &tts
))
2198 msyslog(LOG_ERR
,"parse: local_receive: timestamp conversion error (buftvtots) (ppsclockev.tv)");
2202 parse
->parseio
.parse_dtime
.parse_ptime
.fp
= tts
;
2203 parse
->parseio
.parse_dtime
.parse_state
|= PARSEB_PPS
|PARSEB_S_PPS
;
2206 parse
->ppsserial
= ev
.serial
;
2210 #endif /* TIOCDCDTIMESTAMP */
2211 #endif /* !HAVE_PPSAPI */
2214 { /* simulate receive */
2215 buf
= get_free_recv_buffer();
2217 memmove((caddr_t
)buf
->recv_buffer
,
2218 (caddr_t
)&parse
->parseio
.parse_dtime
,
2219 sizeof(parsetime_t
));
2220 buf
->recv_length
= sizeof(parsetime_t
);
2221 buf
->recv_time
= rbufp
->recv_time
;
2222 buf
->srcadr
= rbufp
->srcadr
;
2223 buf
->dstadr
= rbufp
->dstadr
;
2224 buf
->receiver
= rbufp
->receiver
;
2225 buf
->fd
= rbufp
->fd
;
2226 buf
->X_from_where
= rbufp
->X_from_where
;
2227 add_full_recv_buffer(buf
);
2229 parse_iodone(&parse
->parseio
);
2233 memmove((caddr_t
)rbufp
->recv_buffer
,
2234 (caddr_t
)&parse
->parseio
.parse_dtime
,
2235 sizeof(parsetime_t
));
2236 parse_iodone(&parse
->parseio
);
2237 rbufp
->recv_length
= sizeof(parsetime_t
);
2238 return 1; /* got something & in place return */
2242 return 0; /* nothing to pass up */
2245 /*--------------------------------------------------
2250 struct recvbuf
*rbufp
2253 struct parseunit
*parse
= (struct parseunit
*)((void *)rbufp
->recv_srcclock
);
2254 parsetime_t parsetime
;
2259 if (rbufp
->recv_length
!= sizeof(parsetime_t
))
2262 msyslog(LOG_ERR
,"PARSE receiver #%d: local_receive: bad size (got %d expected %d)",
2263 CLK_UNIT(parse
->peer
), rbufp
->recv_length
, (int)sizeof(parsetime_t
));
2264 parse_event(parse
, CEVNT_BADREPLY
);
2267 clear_err(parse
, ERR_BADIO
);
2269 memmove((caddr_t
)&parsetime
,
2270 (caddr_t
)rbufp
->recv_buffer
,
2271 sizeof(parsetime_t
));
2276 printf("PARSE receiver #%d: status %06x, state %08x, time(fp) %lx.%08lx, stime(fp) %lx.%08lx, ptime(fp) %lx.%08lx\n",
2277 CLK_UNIT(parse
->peer
),
2278 (unsigned int)parsetime
.parse_status
,
2279 (unsigned int)parsetime
.parse_state
,
2280 (unsigned long)parsetime
.parse_time
.fp
.l_ui
,
2281 (unsigned long)parsetime
.parse_time
.fp
.l_uf
,
2282 (unsigned long)parsetime
.parse_stime
.fp
.l_ui
,
2283 (unsigned long)parsetime
.parse_stime
.fp
.l_uf
,
2284 (unsigned long)parsetime
.parse_ptime
.fp
.l_ui
,
2285 (unsigned long)parsetime
.parse_ptime
.fp
.l_uf
);
2289 parse_process(parse
, &parsetime
);
2292 /*--------------------------------------------------
2293 * init_iobinding - find and initialize lower layers
2297 struct parseunit
*parse
2300 bind_t
*b
= io_bindings
;
2302 while (b
->bd_description
!= (char *)0)
2304 if ((*b
->bd_init
)(parse
))
2313 /**===========================================================================
2317 /*--------------------------------------------------
2318 * convert a flag field to a string
2333 { PARSEB_ANNOUNCE
, "DST SWITCH WARNING" },
2334 { PARSEB_POWERUP
, "NOT SYNCHRONIZED" },
2335 { PARSEB_NOSYNC
, "TIME CODE NOT CONFIRMED" },
2336 { PARSEB_DST
, "DST" },
2337 { PARSEB_UTC
, "UTC DISPLAY" },
2338 { PARSEB_LEAPADD
, "LEAP ADD WARNING" },
2339 { PARSEB_LEAPDEL
, "LEAP DELETE WARNING" },
2340 { PARSEB_LEAPSECOND
, "LEAP SECOND" },
2341 { PARSEB_ALTERNATE
, "ALTERNATE ANTENNA" },
2342 { PARSEB_TIMECODE
, "TIME CODE" },
2343 { PARSEB_PPS
, "PPS" },
2344 { PARSEB_POSITION
, "POSITION" },
2354 { PARSEB_S_LEAP
, "LEAP INDICATION" },
2355 { PARSEB_S_PPS
, "PPS SIGNAL" },
2356 { PARSEB_S_ANTENNA
, "ANTENNA" },
2357 { PARSEB_S_POSITION
, "POSITION" },
2368 while (flagstrings
[i
].bit
)
2370 if (flagstrings
[i
].bit
& lstate
)
2373 strncpy(t
, "; ", BUFFER_SIZES(buffer
, t
, size
));
2374 strncat(t
, flagstrings
[i
].name
, BUFFER_SIZES(buffer
, t
, size
));
2380 if (lstate
& (PARSEB_S_LEAP
|PARSEB_S_ANTENNA
|PARSEB_S_PPS
|PARSEB_S_POSITION
))
2383 strncpy(t
, "; ", BUFFER_SIZES(buffer
, t
, size
));
2387 strncpy(t
, "(", BUFFER_SIZES(buffer
, t
, size
));
2389 s
= t
= t
+ strlen(t
);
2392 while (sflagstrings
[i
].bit
)
2394 if (sflagstrings
[i
].bit
& lstate
)
2398 strncpy(t
, "; ", BUFFER_SIZES(buffer
, t
, size
));
2402 strncpy(t
, sflagstrings
[i
].name
, BUFFER_SIZES(buffer
, t
, size
));
2407 strncpy(t
, ")", BUFFER_SIZES(buffer
, t
, size
));
2412 /*--------------------------------------------------
2413 * convert a status flag field to a string
2428 { CVT_OK
, "CONVERSION SUCCESSFUL" },
2429 { CVT_NONE
, "NO CONVERSION" },
2430 { CVT_FAIL
, "CONVERSION FAILED" },
2431 { CVT_BADFMT
, "ILLEGAL FORMAT" },
2432 { CVT_BADDATE
, "DATE ILLEGAL" },
2433 { CVT_BADTIME
, "TIME ILLEGAL" },
2434 { CVT_ADDITIONAL
, "ADDITIONAL DATA" },
2442 while (flagstrings
[i
].bit
)
2444 if (flagstrings
[i
].bit
& lstate
)
2447 strncat(buffer
, "; ", size
);
2448 strncat(buffer
, flagstrings
[i
].name
, size
);
2456 /*--------------------------------------------------
2457 * convert a clock status flag field to a string
2464 static char buffer
[20];
2465 static struct status
2471 { CEVNT_NOMINAL
, "NOMINAL" },
2472 { CEVNT_TIMEOUT
, "NO RESPONSE" },
2473 { CEVNT_BADREPLY
,"BAD FORMAT" },
2474 { CEVNT_FAULT
, "FAULT" },
2475 { CEVNT_PROP
, "PROPAGATION DELAY" },
2476 { CEVNT_BADDATE
, "ILLEGAL DATE" },
2477 { CEVNT_BADTIME
, "ILLEGAL TIME" },
2483 while (flagstrings
[i
].value
!= ~0)
2485 if (flagstrings
[i
].value
== lstate
)
2487 return flagstrings
[i
].name
;
2492 snprintf(buffer
, sizeof(buffer
), "unknown #%ld", (u_long
)lstate
);
2498 /*--------------------------------------------------
2499 * l_mktime - make representation of a relative time
2507 static char buffer
[40];
2512 if ((tmp
= delta
/ (60*60*24)) != 0)
2514 snprintf(buffer
, BUFFER_SIZE(buffer
, buffer
), "%ldd+", (u_long
)tmp
);
2515 delta
-= tmp
* 60*60*24;
2523 t
= buffer
+ strlen(buffer
);
2525 snprintf(t
, BUFFER_SIZE(buffer
, t
), "%02d:%02d:%02d",
2526 (int)delta
, (int)m
, (int)s
);
2532 /*--------------------------------------------------
2533 * parse_statistics - list summary of clock states
2537 struct parseunit
*parse
2542 NLOG(NLOG_CLOCKSTATIST
) /* conditional if clause for conditional syslog */
2544 msyslog(LOG_INFO
, "PARSE receiver #%d: running time: %s",
2545 CLK_UNIT(parse
->peer
),
2546 l_mktime(current_time
- parse
->generic
->timestarted
));
2548 msyslog(LOG_INFO
, "PARSE receiver #%d: current status: %s",
2549 CLK_UNIT(parse
->peer
),
2550 clockstatus(parse
->generic
->currentstatus
));
2552 for (i
= 0; i
<= CEVNT_MAX
; i
++)
2555 u_long percent
, d
= current_time
- parse
->generic
->timestarted
;
2557 percent
= s_time
= PARSE_STATETIME(parse
, i
);
2559 while (((u_long
)(~0) / 10000) < percent
)
2566 percent
= (percent
* 10000) / d
;
2571 msyslog(LOG_INFO
, "PARSE receiver #%d: state %18s: %13s (%3ld.%02ld%%)",
2572 CLK_UNIT(parse
->peer
),
2573 clockstatus((unsigned int)i
),
2575 percent
/ 100, percent
% 100);
2580 /*--------------------------------------------------
2581 * cparse_statistics - wrapper for statistics call
2585 struct parseunit
*parse
2588 if (parse
->laststatistic
+ PARSESTATISTICS
< current_time
)
2589 parse_statistics(parse
);
2590 parse
->laststatistic
= current_time
;
2593 /**===========================================================================
2594 ** ntp interface routines
2597 /*--------------------------------------------------
2598 * parse_shutdown - shut down a PARSE clock
2606 struct parseunit
*parse
= (struct parseunit
*)0;
2608 if (peer
&& peer
->procptr
)
2609 parse
= (struct parseunit
*)peer
->procptr
->unitptr
;
2613 /* nothing to clean up */
2619 msyslog(LOG_INFO
, "PARSE receiver #%d: INTERNAL ERROR - unit already inactive - shutdown ignored", unit
);
2624 if (parse
->flags
& PARSE_PPSCLOCK
)
2626 (void)time_pps_destroy(parse
->atom
.handle
);
2629 if (parse
->generic
->io
.fd
!= parse
->ppsfd
&& parse
->ppsfd
!= -1)
2630 (void)close(parse
->ppsfd
); /* close separate PPS source */
2633 * print statistics a last time and
2634 * stop statistics machine
2636 parse_statistics(parse
);
2638 if (parse
->parse_type
->cl_end
)
2640 parse
->parse_type
->cl_end(parse
);
2644 * cleanup before leaving this world
2650 * Tell the I/O module to turn us off. We're history.
2652 io_closeclock(&parse
->generic
->io
);
2654 free_varlist(parse
->kv
);
2656 NLOG(NLOG_CLOCKINFO
) /* conditional if clause for conditional syslog */
2657 msyslog(LOG_INFO
, "PARSE receiver #%d: reference clock \"%s\" removed",
2658 CLK_UNIT(parse
->peer
), parse
->parse_type
->cl_description
);
2660 parse
->peer
= (struct peer
*)0; /* unused now */
2661 peer
->procptr
->unitptr
= (caddr_t
)0;
2666 /*----------------------------------------
2667 * set up HARDPPS via PPSAPI
2671 struct parseunit
*parse
,
2675 if (parse
->hardppsstate
== mode
)
2678 if (CLK_PPS(parse
->peer
) && (parse
->flags
& PARSE_PPSKERNEL
)) {
2681 if (mode
== PARSE_HARDPPS_ENABLE
)
2683 if (parse
->flags
& PARSE_CLEAR
)
2684 i
= PPS_CAPTURECLEAR
;
2686 i
= PPS_CAPTUREASSERT
;
2689 if (time_pps_kcbind(parse
->atom
.handle
, PPS_KC_HARDPPS
, i
,
2690 PPS_TSFMT_TSPEC
) < 0) {
2691 msyslog(LOG_ERR
, "PARSE receiver #%d: time_pps_kcbind failed: %m",
2692 CLK_UNIT(parse
->peer
));
2694 NLOG(NLOG_CLOCKINFO
)
2695 msyslog(LOG_INFO
, "PARSE receiver #%d: kernel PPS synchronisation %sabled",
2696 CLK_UNIT(parse
->peer
), (mode
== PARSE_HARDPPS_ENABLE
) ? "en" : "dis");
2698 * tell the rest, that we have a kernel PPS source, iff we ever enable HARDPPS
2700 if (mode
== PARSE_HARDPPS_ENABLE
)
2705 parse
->hardppsstate
= mode
;
2708 /*----------------------------------------
2709 * set up PPS via PPSAPI
2713 struct parseunit
*parse
2716 int cap
, mode_ppsoffset
;
2719 parse
->flags
&= ~PARSE_PPSCLOCK
;
2722 * collect PPSAPI offset capability - should move into generic handling
2724 if (time_pps_getcap(parse
->atom
.handle
, &cap
) < 0) {
2725 msyslog(LOG_ERR
, "PARSE receiver #%d: parse_ppsapi: time_pps_getcap failed: %m",
2726 CLK_UNIT(parse
->peer
));
2732 * initialize generic PPSAPI interface
2734 * we leave out CLK_FLAG3 as time_pps_kcbind()
2735 * is handled here for now. Ideally this should also
2736 * be part of the generic PPSAPI interface
2738 if (!refclock_params(parse
->flags
& (CLK_FLAG1
|CLK_FLAG2
|CLK_FLAG4
), &parse
->atom
))
2741 /* nb. only turn things on, if someone else has turned something
2742 * on before we get here, leave it alone!
2745 if (parse
->flags
& PARSE_CLEAR
) {
2747 mode_ppsoffset
= PPS_OFFSETCLEAR
;
2750 mode_ppsoffset
= PPS_OFFSETASSERT
;
2753 msyslog(LOG_INFO
, "PARSE receiver #%d: initializing PPS to %s",
2754 CLK_UNIT(parse
->peer
), cp
);
2756 if (!(mode_ppsoffset
& cap
)) {
2757 msyslog(LOG_WARNING
, "PARSE receiver #%d: Cannot set PPS_%sCLEAR, this will increase jitter (PPS API capabilities=0x%x)",
2758 CLK_UNIT(parse
->peer
), cp
, cap
);
2761 if (mode_ppsoffset
== PPS_OFFSETCLEAR
)
2763 parse
->atom
.pps_params
.clear_offset
.tv_sec
= -parse
->ppsphaseadjust
;
2764 parse
->atom
.pps_params
.clear_offset
.tv_nsec
= -1e9
*(parse
->ppsphaseadjust
- (long)parse
->ppsphaseadjust
);
2767 if (mode_ppsoffset
== PPS_OFFSETASSERT
)
2769 parse
->atom
.pps_params
.assert_offset
.tv_sec
= -parse
->ppsphaseadjust
;
2770 parse
->atom
.pps_params
.assert_offset
.tv_nsec
= -1e9
*(parse
->ppsphaseadjust
- (long)parse
->ppsphaseadjust
);
2774 parse
->atom
.pps_params
.mode
|= mode_ppsoffset
;
2776 if (time_pps_setparams(parse
->atom
.handle
, &parse
->atom
.pps_params
) < 0) {
2777 msyslog(LOG_ERR
, "PARSE receiver #%d: FAILED set PPS parameters: %m",
2778 CLK_UNIT(parse
->peer
));
2782 parse
->flags
|= PARSE_PPSCLOCK
;
2786 #define parse_hardpps(_PARSE_, _MODE_) /* empty */
2789 /*--------------------------------------------------
2790 * parse_start - open the PARSE devices and initialize data for processing
2801 struct termios tio
; /* NEEDED FOR A LONG TIME ! */
2803 #ifdef HAVE_SYSV_TTYS
2804 struct termio tio
; /* NEEDED FOR A LONG TIME ! */
2806 struct parseunit
* parse
;
2807 char parsedev
[sizeof(PARSEDEVICE
)+20];
2808 char parseppsdev
[sizeof(PARSEPPSDEVICE
)+20];
2813 * get out Copyright information once
2817 NLOG(NLOG_CLOCKINFO
) /* conditional if clause for conditional syslog */
2818 msyslog(LOG_INFO
, "NTP PARSE support: Copyright (c) 1989-2009, Frank Kardel");
2822 type
= CLK_TYPE(peer
);
2823 unit
= CLK_UNIT(peer
);
2825 if ((type
== ~0) || (parse_clockinfo
[type
].cl_description
== (char *)0))
2827 msyslog(LOG_ERR
, "PARSE receiver #%d: parse_start: unsupported clock type %d (max %d)",
2828 unit
, CLK_REALTYPE(peer
), ncltypes
-1);
2833 * Unit okay, attempt to open the device.
2835 (void) snprintf(parsedev
, sizeof(parsedev
), PARSEDEVICE
, unit
);
2836 (void) snprintf(parseppsdev
, sizeof(parsedev
), PARSEPPSDEVICE
, unit
);
2842 fd232
= open(parsedev
, O_RDWR
| O_NOCTTY
2850 msyslog(LOG_ERR
, "PARSE receiver #%d: parse_start: open of %s failed: %m", unit
, parsedev
);
2854 parse
= (struct parseunit
*)emalloc(sizeof(struct parseunit
));
2856 memset((char *)parse
, 0, sizeof(struct parseunit
));
2858 parse
->generic
= peer
->procptr
; /* link up */
2859 parse
->generic
->unitptr
= (caddr_t
)parse
; /* link down */
2862 * Set up the structures
2864 parse
->generic
->timestarted
= current_time
;
2865 parse
->lastchange
= current_time
;
2868 parse
->pollneeddata
= 0;
2869 parse
->laststatistic
= current_time
;
2870 parse
->lastformat
= (unsigned short)~0; /* assume no format known */
2871 parse
->timedata
.parse_status
= (unsigned short)~0; /* be sure to mark initial status change */
2872 parse
->lastmissed
= 0; /* assume got everything */
2873 parse
->ppsserial
= 0;
2875 parse
->localdata
= (void *)0;
2876 parse
->localstate
= 0;
2877 parse
->kv
= (struct ctl_var
*)0;
2879 clear_err(parse
, ERR_ALL
);
2881 parse
->parse_type
= &parse_clockinfo
[type
];
2883 parse
->maxunsync
= parse
->parse_type
->cl_maxunsync
;
2885 parse
->generic
->fudgetime1
= parse
->parse_type
->cl_basedelay
;
2887 parse
->generic
->fudgetime2
= 0.0;
2888 parse
->ppsphaseadjust
= parse
->generic
->fudgetime2
;
2890 parse
->generic
->clockdesc
= parse
->parse_type
->cl_description
;
2892 peer
->rootdelay
= parse
->parse_type
->cl_rootdelay
;
2893 peer
->sstclktype
= parse
->parse_type
->cl_type
;
2894 peer
->precision
= sys_precision
;
2896 peer
->stratum
= STRATUM_REFCLOCK
;
2898 if (peer
->stratum
<= 1)
2899 memmove((char *)&parse
->generic
->refid
, parse
->parse_type
->cl_id
, 4);
2901 parse
->generic
->refid
= htonl(PARSEHSREFID
);
2903 parse
->generic
->io
.fd
= fd232
;
2905 parse
->peer
= peer
; /* marks it also as busy */
2908 * configure terminal line
2910 if (TTY_GETATTR(fd232
, &tio
) == -1)
2912 msyslog(LOG_ERR
, "PARSE receiver #%d: parse_start: tcgetattr(%d, &tio): %m", unit
, fd232
);
2913 parse_shutdown(CLK_UNIT(parse
->peer
), peer
); /* let our cleaning staff do the work */
2918 #ifndef _PC_VDISABLE
2919 memset((char *)tio
.c_cc
, 0, sizeof(tio
.c_cc
));
2922 errno
= 0; /* pathconf can deliver -1 without changing errno ! */
2924 disablec
= fpathconf(parse
->generic
->io
.fd
, _PC_VDISABLE
);
2925 if (disablec
== -1 && errno
)
2927 msyslog(LOG_ERR
, "PARSE receiver #%d: parse_start: fpathconf(fd, _PC_VDISABLE): %m", CLK_UNIT(parse
->peer
));
2928 memset((char *)tio
.c_cc
, 0, sizeof(tio
.c_cc
)); /* best guess */
2932 memset((char *)tio
.c_cc
, disablec
, sizeof(tio
.c_cc
));
2935 #if defined (VMIN) || defined(VTIME)
2936 if ((parse_clockinfo
[type
].cl_lflag
& ICANON
) == 0)
2942 tio
.c_cc
[VTIME
] = 0;
2947 tio
.c_cflag
= parse_clockinfo
[type
].cl_cflag
;
2948 tio
.c_iflag
= parse_clockinfo
[type
].cl_iflag
;
2949 tio
.c_oflag
= parse_clockinfo
[type
].cl_oflag
;
2950 tio
.c_lflag
= parse_clockinfo
[type
].cl_lflag
;
2954 if ((cfsetospeed(&tio
, parse_clockinfo
[type
].cl_speed
) == -1) ||
2955 (cfsetispeed(&tio
, parse_clockinfo
[type
].cl_speed
) == -1))
2957 msyslog(LOG_ERR
, "PARSE receiver #%d: parse_start: tcset{i,o}speed(&tio, speed): %m", unit
);
2958 parse_shutdown(CLK_UNIT(parse
->peer
), peer
); /* let our cleaning staff do the work */
2962 tio
.c_cflag
|= parse_clockinfo
[type
].cl_speed
;
2967 * if the PARSEPPSDEVICE can be opened that will be used
2968 * for PPS else PARSEDEVICE will be used
2970 parse
->ppsfd
= open(parseppsdev
, O_RDWR
| O_NOCTTY
2976 if (parse
->ppsfd
== -1)
2978 parse
->ppsfd
= fd232
;
2982 * Linux PPS - the old way
2984 #if defined(HAVE_TIO_SERIAL_STUFF) /* Linux hack: define PPS interface */
2986 struct serial_struct ss
;
2987 if (ioctl(parse
->ppsfd
, TIOCGSERIAL
, &ss
) < 0 ||
2989 #ifdef ASYNC_LOW_LATENCY
2990 ss
.flags
|= ASYNC_LOW_LATENCY
,
2993 #ifdef ASYNC_PPS_CD_NEG
2994 ss
.flags
|= ASYNC_PPS_CD_NEG
,
2997 ioctl(parse
->ppsfd
, TIOCSSERIAL
, &ss
)) < 0) {
2998 msyslog(LOG_NOTICE
, "refclock_parse: TIOCSSERIAL fd %d, %m", parse
->ppsfd
);
3000 "refclock_parse: optional PPS processing not available");
3002 parse
->flags
|= PARSE_PPSCLOCK
;
3003 #ifdef ASYNC_PPS_CD_NEG
3004 NLOG(NLOG_CLOCKINFO
)
3006 "refclock_parse: PPS detection on");
3013 * SUN the Solaris way
3015 #ifdef HAVE_TIOCSPPS /* SUN PPS support */
3016 if (CLK_PPS(parse
->peer
))
3020 if (ioctl(parse
->ppsfd
, TIOCSPPS
, (caddr_t
)&i
) == 0)
3022 parse
->flags
|= PARSE_PPSCLOCK
;
3030 #if defined(HAVE_PPSAPI)
3031 parse
->hardppsstate
= PARSE_HARDPPS_DISABLE
;
3032 if (CLK_PPS(parse
->peer
))
3034 if (!refclock_ppsapi(parse
->ppsfd
, &parse
->atom
))
3036 msyslog(LOG_NOTICE
, "PARSE receiver #%d: parse_start: could not set up PPS: %m", CLK_UNIT(parse
->peer
));
3040 parse_ppsapi(parse
);
3045 if (TTY_SETATTR(fd232
, &tio
) == -1)
3047 msyslog(LOG_ERR
, "PARSE receiver #%d: parse_start: tcsetattr(%d, &tio): %m", unit
, fd232
);
3048 parse_shutdown(CLK_UNIT(parse
->peer
), peer
); /* let our cleaning staff do the work */
3054 * pick correct input machine
3056 parse
->generic
->io
.srcclock
= (caddr_t
)parse
;
3057 parse
->generic
->io
.datalen
= 0;
3059 parse
->binding
= init_iobinding(parse
);
3061 if (parse
->binding
== (bind_t
*)0)
3063 msyslog(LOG_ERR
, "PARSE receiver #%d: parse_start: io sub system initialisation failed.", CLK_UNIT(parse
->peer
));
3064 parse_shutdown(CLK_UNIT(parse
->peer
), peer
); /* let our cleaning staff do the work */
3065 return 0; /* well, ok - special initialisation broke */
3068 parse
->generic
->io
.clock_recv
= parse
->binding
->bd_receive
; /* pick correct receive routine */
3069 parse
->generic
->io
.io_input
= parse
->binding
->bd_io_input
; /* pick correct input routine */
3072 * as we always(?) get 8 bit chars we want to be
3073 * sure, that the upper bits are zero for less
3074 * than 8 bit I/O - so we pass that information on.
3075 * note that there can be only one bit count format
3076 * per file descriptor
3079 switch (tio
.c_cflag
& CSIZE
)
3082 tmp_ctl
.parsesetcs
.parse_cs
= PARSE_IO_CS5
;
3086 tmp_ctl
.parsesetcs
.parse_cs
= PARSE_IO_CS6
;
3090 tmp_ctl
.parsesetcs
.parse_cs
= PARSE_IO_CS7
;
3094 tmp_ctl
.parsesetcs
.parse_cs
= PARSE_IO_CS8
;
3098 if (!PARSE_SETCS(parse
, &tmp_ctl
))
3100 msyslog(LOG_ERR
, "PARSE receiver #%d: parse_start: parse_setcs() FAILED.", unit
);
3101 parse_shutdown(CLK_UNIT(parse
->peer
), peer
); /* let our cleaning staff do the work */
3102 return 0; /* well, ok - special initialisation broke */
3105 strncpy(tmp_ctl
.parseformat
.parse_buffer
, parse
->parse_type
->cl_format
, sizeof(tmp_ctl
.parseformat
.parse_buffer
));
3106 tmp_ctl
.parseformat
.parse_count
= strlen(tmp_ctl
.parseformat
.parse_buffer
);
3108 if (!PARSE_SETFMT(parse
, &tmp_ctl
))
3110 msyslog(LOG_ERR
, "PARSE receiver #%d: parse_start: parse_setfmt() FAILED.", unit
);
3111 parse_shutdown(CLK_UNIT(parse
->peer
), peer
); /* let our cleaning staff do the work */
3112 return 0; /* well, ok - special initialisation broke */
3116 * get rid of all IO accumulated so far
3119 (void) tcflush(parse
->generic
->io
.fd
, TCIOFLUSH
);
3121 #if defined(TCFLSH) && defined(TCIOFLUSH)
3123 int flshcmd
= TCIOFLUSH
;
3125 (void) ioctl(parse
->generic
->io
.fd
, TCFLSH
, (caddr_t
)&flshcmd
);
3131 * try to do any special initializations
3133 if (parse
->parse_type
->cl_init
)
3135 if (parse
->parse_type
->cl_init(parse
))
3137 parse_shutdown(CLK_UNIT(parse
->peer
), peer
); /* let our cleaning staff do the work */
3138 return 0; /* well, ok - special initialisation broke */
3143 * Insert in async io device list.
3145 if (!io_addclock(&parse
->generic
->io
))
3148 "PARSE receiver #%d: parse_start: addclock %s fails (ABORT - clock type requires async io)", CLK_UNIT(parse
->peer
), parsedev
);
3149 parse_shutdown(CLK_UNIT(parse
->peer
), peer
); /* let our cleaning staff do the work */
3154 * print out configuration
3156 NLOG(NLOG_CLOCKINFO
)
3158 /* conditional if clause for conditional syslog */
3159 msyslog(LOG_INFO
, "PARSE receiver #%d: reference clock \"%s\" (I/O device %s, PPS device %s) added",
3160 CLK_UNIT(parse
->peer
),
3161 parse
->parse_type
->cl_description
, parsedev
,
3162 (parse
->ppsfd
!= parse
->generic
->io
.fd
) ? parseppsdev
: parsedev
);
3164 msyslog(LOG_INFO
, "PARSE receiver #%d: Stratum %d, trust time %s, precision %d",
3165 CLK_UNIT(parse
->peer
),
3166 parse
->peer
->stratum
,
3167 l_mktime(parse
->maxunsync
), parse
->peer
->precision
);
3169 msyslog(LOG_INFO
, "PARSE receiver #%d: rootdelay %.6f s, phase adjustment %.6f s, PPS phase adjustment %.6f s, %s IO handling",
3170 CLK_UNIT(parse
->peer
),
3171 parse
->parse_type
->cl_rootdelay
,
3172 parse
->generic
->fudgetime1
,
3173 parse
->ppsphaseadjust
,
3174 parse
->binding
->bd_description
);
3176 msyslog(LOG_INFO
, "PARSE receiver #%d: Format recognition: %s", CLK_UNIT(parse
->peer
),
3177 parse
->parse_type
->cl_format
);
3178 msyslog(LOG_INFO
, "PARSE receiver #%d: %sPPS support%s", CLK_UNIT(parse
->peer
),
3179 CLK_PPS(parse
->peer
) ? "" : "NO ",
3180 CLK_PPS(parse
->peer
) ?
3182 " (implementation " PPS_METHOD
")"
3193 /*--------------------------------------------------
3194 * parse_ctl - process changes on flags/time values
3198 struct parseunit
*parse
,
3199 struct refclockstat
*in
3204 if (in
->haveflags
& (CLK_HAVEFLAG1
|CLK_HAVEFLAG2
|CLK_HAVEFLAG3
|CLK_HAVEFLAG4
))
3206 parse
->flags
= (parse
->flags
& ~(CLK_FLAG1
|CLK_FLAG2
|CLK_FLAG3
|CLK_FLAG4
)) |
3207 (in
->flags
& (CLK_FLAG1
|CLK_FLAG2
|CLK_FLAG3
|CLK_FLAG4
));
3208 #if defined(HAVE_PPSAPI)
3209 if (CLK_PPS(parse
->peer
))
3211 parse_ppsapi(parse
);
3216 if (in
->haveflags
& CLK_HAVETIME1
)
3218 parse
->generic
->fudgetime1
= in
->fudgetime1
;
3219 msyslog(LOG_INFO
, "PARSE receiver #%d: new phase adjustment %.6f s",
3220 CLK_UNIT(parse
->peer
),
3221 parse
->generic
->fudgetime1
);
3224 if (in
->haveflags
& CLK_HAVETIME2
)
3226 parse
->generic
->fudgetime2
= in
->fudgetime2
;
3227 if (parse
->flags
& PARSE_TRUSTTIME
)
3229 parse
->maxunsync
= (u_long
)ABS(in
->fudgetime2
);
3230 msyslog(LOG_INFO
, "PARSE receiver #%d: new trust time %s",
3231 CLK_UNIT(parse
->peer
),
3232 l_mktime(parse
->maxunsync
));
3236 parse
->ppsphaseadjust
= in
->fudgetime2
;
3237 msyslog(LOG_INFO
, "PARSE receiver #%d: new PPS phase adjustment %.6f s",
3238 CLK_UNIT(parse
->peer
),
3239 parse
->ppsphaseadjust
);
3240 #if defined(HAVE_PPSAPI)
3241 if (CLK_PPS(parse
->peer
))
3243 parse_ppsapi(parse
);
3251 /*--------------------------------------------------
3252 * parse_poll - called by the transmit procedure
3260 struct parseunit
*parse
= (struct parseunit
*)peer
->procptr
->unitptr
;
3262 if (peer
!= parse
->peer
)
3265 "PARSE receiver #%d: poll: INTERNAL: peer incorrect",
3271 * Update clock stat counters
3273 parse
->generic
->polls
++;
3275 if (parse
->pollneeddata
&&
3276 ((current_time
- parse
->pollneeddata
) > (1<<(max(min(parse
->peer
->hpoll
, parse
->peer
->ppoll
), parse
->peer
->minpoll
)))))
3279 * start worrying when exceeding a poll inteval
3280 * bad news - didn't get a response last time
3282 parse
->lastmissed
= current_time
;
3283 parse_event(parse
, CEVNT_TIMEOUT
);
3286 msyslog(LOG_WARNING
, "PARSE receiver #%d: no data from device within poll interval (check receiver / wiring)", CLK_UNIT(parse
->peer
));
3290 * we just mark that we want the next sample for the clock filter
3292 parse
->pollneeddata
= current_time
;
3294 if (parse
->parse_type
->cl_poll
)
3296 parse
->parse_type
->cl_poll(parse
);
3299 cparse_statistics(parse
);
3304 #define LEN_STATES 300 /* length of state string */
3306 /*--------------------------------------------------
3307 * parse_control - set fudge factors, return statistics
3312 struct refclockstat
*in
,
3313 struct refclockstat
*out
,
3317 struct parseunit
*parse
= (struct parseunit
*)peer
->procptr
->unitptr
;
3320 static char outstatus
[400]; /* status output buffer */
3325 out
->p_lastcode
= 0;
3326 out
->kv_list
= (struct ctl_var
*)0;
3329 if (!parse
|| !parse
->peer
)
3331 msyslog(LOG_ERR
, "PARSE receiver #%d: parse_control: unit invalid (UNIT INACTIVE)",
3336 unit
= CLK_UNIT(parse
->peer
);
3341 parse_ctl(parse
, in
);
3352 outstatus
[0] = '\0';
3354 out
->type
= REFCLK_PARSE
;
3357 * keep fudgetime2 in sync with TRUSTTIME/MAXUNSYNC flag1
3359 parse
->generic
->fudgetime2
= (parse
->flags
& PARSE_TRUSTTIME
) ? (double)parse
->maxunsync
: parse
->ppsphaseadjust
;
3362 * figure out skew between PPS and RS232 - just for informational
3365 if (PARSE_SYNC(parse
->timedata
.parse_state
))
3367 if (PARSE_PPS(parse
->timedata
.parse_state
) && PARSE_TIMECODE(parse
->timedata
.parse_state
))
3372 * we have a PPS and RS232 signal - calculate the skew
3373 * WARNING: assumes on TIMECODE == PULSE (timecode after pulse)
3375 off
= parse
->timedata
.parse_stime
.fp
;
3376 L_SUB(&off
, &parse
->timedata
.parse_ptime
.fp
); /* true offset */
3377 tt
= add_var(&out
->kv_list
, 80, RO
);
3378 snprintf(tt
, 80, "refclock_ppsskew=%s", lfptoms(&off
, 6));
3382 if (PARSE_PPS(parse
->timedata
.parse_state
))
3384 tt
= add_var(&out
->kv_list
, 80, RO
|DEF
);
3385 snprintf(tt
, 80, "refclock_ppstime=\"%s\"", gmprettydate(&parse
->timedata
.parse_ptime
.fp
));
3388 start
= tt
= add_var(&out
->kv_list
, 128, RO
|DEF
);
3389 snprintf(tt
, 128, "refclock_time=\"");
3392 if (parse
->timedata
.parse_time
.fp
.l_ui
== 0)
3394 strncpy(tt
, "<UNDEFINED>\"", BUFFER_SIZES(start
, tt
, 128));
3398 snprintf(tt
, 128, "%s\"", gmprettydate(&parse
->timedata
.parse_time
.fp
));
3401 if (!PARSE_GETTIMECODE(parse
, &tmpctl
))
3404 msyslog(LOG_ERR
, "PARSE receiver #%d: parse_control: parse_timecode() FAILED", unit
);
3408 start
= tt
= add_var(&out
->kv_list
, 512, RO
|DEF
);
3409 snprintf(tt
, 512, "refclock_status=\"");
3413 * copy PPS flags from last read transaction (informational only)
3415 tmpctl
.parsegettc
.parse_state
|= parse
->timedata
.parse_state
&
3416 (PARSEB_PPS
|PARSEB_S_PPS
);
3418 (void) parsestate(tmpctl
.parsegettc
.parse_state
, tt
, BUFFER_SIZES(start
, tt
, 512));
3420 strncat(tt
, "\"", BUFFER_SIZES(start
, tt
, 512));
3422 if (tmpctl
.parsegettc
.parse_count
)
3423 mkascii(outstatus
+strlen(outstatus
), (int)(sizeof(outstatus
)- strlen(outstatus
) - 1),
3424 tmpctl
.parsegettc
.parse_buffer
, (unsigned)(tmpctl
.parsegettc
.parse_count
));
3428 tmpctl
.parseformat
.parse_format
= tmpctl
.parsegettc
.parse_format
;
3430 if (!PARSE_GETFMT(parse
, &tmpctl
))
3433 msyslog(LOG_ERR
, "PARSE receiver #%d: parse_control: parse_getfmt() FAILED", unit
);
3437 tt
= add_var(&out
->kv_list
, 80, RO
|DEF
);
3438 snprintf(tt
, 80, "refclock_format=\"");
3440 strncat(tt
, tmpctl
.parseformat
.parse_buffer
, tmpctl
.parseformat
.parse_count
);
3441 strncat(tt
,"\"", 80);
3445 * gather state statistics
3448 start
= tt
= add_var(&out
->kv_list
, LEN_STATES
, RO
|DEF
);
3449 strncpy(tt
, "refclock_states=\"", LEN_STATES
);
3452 for (i
= 0; i
<= CEVNT_MAX
; i
++)
3455 u_long d
= current_time
- parse
->generic
->timestarted
;
3458 percent
= s_time
= PARSE_STATETIME(parse
, i
);
3460 while (((u_long
)(~0) / 10000) < percent
)
3467 percent
= (percent
* 10000) / d
;
3476 snprintf(item
, 80, "%s%s%s: %s (%d.%02d%%)",
3478 (parse
->generic
->currentstatus
== i
) ? "*" : "",
3479 clockstatus((unsigned int)i
),
3481 (int)(percent
/ 100), (int)(percent
% 100));
3482 if ((count
= strlen(item
)) < (LEN_STATES
- 40 - (tt
- start
)))
3484 strncpy(tt
, item
, BUFFER_SIZES(start
, tt
, LEN_STATES
));
3491 snprintf(tt
, BUFFER_SIZES(start
, tt
, LEN_STATES
), "; running time: %s\"", l_mktime(sum
));
3493 tt
= add_var(&out
->kv_list
, 32, RO
);
3494 snprintf(tt
, 32, "refclock_id=\"%s\"", parse
->parse_type
->cl_id
);
3496 tt
= add_var(&out
->kv_list
, 80, RO
);
3497 snprintf(tt
, 80, "refclock_iomode=\"%s\"", parse
->binding
->bd_description
);
3499 tt
= add_var(&out
->kv_list
, 128, RO
);
3500 snprintf(tt
, 128, "refclock_driver_version=\"%s\"", rcsid
);
3506 while (k
&& !(k
->flags
& EOV
))
3508 set_var(&out
->kv_list
, k
->text
, strlen(k
->text
)+1, k
->flags
);
3513 out
->lencode
= strlen(outstatus
);
3514 out
->p_lastcode
= outstatus
;
3518 /**===========================================================================
3519 ** processing routines
3522 /*--------------------------------------------------
3523 * event handling - note that nominal events will also be posted
3524 * keep track of state dwelling times
3528 struct parseunit
*parse
,
3532 if (parse
->generic
->currentstatus
!= (u_char
) event
)
3534 parse
->statetime
[parse
->generic
->currentstatus
] += current_time
- parse
->lastchange
;
3535 parse
->lastchange
= current_time
;
3537 if (parse
->parse_type
->cl_event
)
3538 parse
->parse_type
->cl_event(parse
, event
);
3540 if (event
== CEVNT_NOMINAL
)
3542 NLOG(NLOG_CLOCKSTATUS
)
3543 msyslog(LOG_INFO
, "PARSE receiver #%d: SYNCHRONIZED",
3544 CLK_UNIT(parse
->peer
));
3547 refclock_report(parse
->peer
, event
);
3551 /*--------------------------------------------------
3552 * process a PARSE time sample
3556 struct parseunit
*parse
,
3557 parsetime_t
*parsetime
3560 l_fp off
, rectime
, reftime
;
3564 * check for changes in conversion status
3565 * (only one for each new status !)
3567 if (((parsetime
->parse_status
& CVT_MASK
) != CVT_OK
) &&
3568 ((parsetime
->parse_status
& CVT_MASK
) != CVT_NONE
) &&
3569 (parse
->timedata
.parse_status
!= parsetime
->parse_status
))
3573 NLOG(NLOG_CLOCKINFO
) /* conditional if clause for conditional syslog */
3574 msyslog(LOG_WARNING
, "PARSE receiver #%d: conversion status \"%s\"",
3575 CLK_UNIT(parse
->peer
), parsestatus(parsetime
->parse_status
, buffer
, sizeof(buffer
)));
3577 if ((parsetime
->parse_status
& CVT_MASK
) == CVT_FAIL
)
3580 * tell more about the story - list time code
3581 * there is a slight change for a race condition and
3582 * the time code might be overwritten by the next packet
3586 if (!PARSE_GETTIMECODE(parse
, &tmpctl
))
3589 msyslog(LOG_ERR
, "PARSE receiver #%d: parse_process: parse_timecode() FAILED", CLK_UNIT(parse
->peer
));
3594 msyslog(LOG_WARNING
, "PARSE receiver #%d: FAILED TIMECODE: \"%s\" (check receiver configuration / wiring)",
3595 CLK_UNIT(parse
->peer
), mkascii(buffer
, sizeof buffer
, tmpctl
.parsegettc
.parse_buffer
, (unsigned)(tmpctl
.parsegettc
.parse_count
- 1)));
3601 * examine status and post appropriate events
3603 if ((parsetime
->parse_status
& CVT_MASK
) != CVT_OK
)
3606 * got bad data - tell the rest of the system
3608 switch (parsetime
->parse_status
& CVT_MASK
)
3611 if ((parsetime
->parse_status
& CVT_ADDITIONAL
) &&
3612 parse
->parse_type
->cl_message
)
3613 parse
->parse_type
->cl_message(parse
, parsetime
);
3615 * save PPS information that comes piggyback
3617 if (PARSE_PPS(parsetime
->parse_state
))
3619 parse
->timedata
.parse_state
|= PARSEB_PPS
|PARSEB_S_PPS
;
3620 parse
->timedata
.parse_ptime
= parsetime
->parse_ptime
;
3622 break; /* well, still waiting - timeout is handled at higher levels */
3625 if (parsetime
->parse_status
& CVT_BADFMT
)
3627 parse_event(parse
, CEVNT_BADREPLY
);
3630 if (parsetime
->parse_status
& CVT_BADDATE
)
3632 parse_event(parse
, CEVNT_BADDATE
);
3635 if (parsetime
->parse_status
& CVT_BADTIME
)
3637 parse_event(parse
, CEVNT_BADTIME
);
3641 parse_event(parse
, CEVNT_BADREPLY
); /* for the lack of something better */
3644 return; /* skip the rest - useless */
3648 * check for format changes
3649 * (in case somebody has swapped clocks 8-)
3651 if (parse
->lastformat
!= parsetime
->parse_format
)
3655 tmpctl
.parseformat
.parse_format
= parsetime
->parse_format
;
3657 if (!PARSE_GETFMT(parse
, &tmpctl
))
3660 msyslog(LOG_ERR
, "PARSE receiver #%d: parse_getfmt() FAILED", CLK_UNIT(parse
->peer
));
3664 NLOG(NLOG_CLOCKINFO
) /* conditional if clause for conditional syslog */
3665 msyslog(LOG_INFO
, "PARSE receiver #%d: packet format \"%s\"",
3666 CLK_UNIT(parse
->peer
), tmpctl
.parseformat
.parse_buffer
);
3668 parse
->lastformat
= parsetime
->parse_format
;
3672 * now, any changes ?
3674 if ((parse
->timedata
.parse_state
^ parsetime
->parse_state
) &
3675 ~(unsigned)(PARSEB_PPS
|PARSEB_S_PPS
))
3680 * something happend - except for PPS events
3683 (void) parsestate(parsetime
->parse_state
, tmp1
, sizeof(tmp1
));
3684 (void) parsestate(parse
->timedata
.parse_state
, tmp2
, sizeof(tmp2
));
3686 NLOG(NLOG_CLOCKINFO
) /* conditional if clause for conditional syslog */
3687 msyslog(LOG_INFO
,"PARSE receiver #%d: STATE CHANGE: %s -> %s",
3688 CLK_UNIT(parse
->peer
), tmp2
, tmp1
);
3692 * carry on PPS information if still usable
3694 if (PARSE_PPS(parse
->timedata
.parse_state
) && !PARSE_PPS(parsetime
->parse_state
))
3696 parsetime
->parse_state
|= PARSEB_PPS
|PARSEB_S_PPS
;
3697 parsetime
->parse_ptime
= parse
->timedata
.parse_ptime
;
3701 * remember for future
3703 parse
->timedata
= *parsetime
;
3706 * check to see, whether the clock did a complete powerup or lost PZF signal
3707 * and post correct events for current condition
3709 if (PARSE_POWERUP(parsetime
->parse_state
))
3712 * this is bad, as we have completely lost synchronisation
3713 * well this is a problem with the receiver here
3714 * for PARSE Meinberg DCF77 receivers the lost synchronisation
3715 * is true as it is the powerup state and the time is taken
3716 * from a crude real time clock chip
3717 * for the PZF series this is only partly true, as
3718 * PARSE_POWERUP only means that the pseudo random
3719 * phase shift sequence cannot be found. this is only
3720 * bad, if we have never seen the clock in the SYNC
3721 * state, where the PHASE and EPOCH are correct.
3722 * for reporting events the above business does not
3723 * really matter, but we can use the time code
3724 * even in the POWERUP state after having seen
3725 * the clock in the synchronized state (PZF class
3726 * receivers) unless we have had a telegram disruption
3727 * after having seen the clock in the SYNC state. we
3728 * thus require having seen the clock in SYNC state
3729 * *after* having missed telegrams (noresponse) from
3730 * the clock. one problem remains: we might use erroneously
3731 * POWERUP data if the disruption is shorter than 1 polling
3732 * interval. fortunately powerdowns last usually longer than 64
3733 * seconds and the receiver is at least 2 minutes in the
3734 * POWERUP or NOSYNC state before switching to SYNC
3736 parse_event(parse
, CEVNT_FAULT
);
3737 NLOG(NLOG_CLOCKSTATUS
)
3739 msyslog(LOG_ERR
,"PARSE receiver #%d: NOT SYNCHRONIZED",
3740 CLK_UNIT(parse
->peer
));
3745 * we have two states left
3748 * this state means that the EPOCH (timecode) and PHASE
3749 * information has be read correctly (at least two
3750 * successive PARSE timecodes were received correctly)
3751 * this is the best possible state - full trust
3754 * The clock should be on phase with respect to the second
3755 * signal, but the timecode has not been received correctly within
3756 * at least the last two minutes. this is a sort of half baked state
3757 * for PARSE Meinberg DCF77 clocks this is bad news (clock running
3758 * without timecode confirmation)
3759 * PZF 535 has also no time confirmation, but the phase should be
3760 * very precise as the PZF signal can be decoded
3763 if (PARSE_SYNC(parsetime
->parse_state
))
3766 * currently completely synchronized - best possible state
3768 parse
->lastsync
= current_time
;
3769 clear_err(parse
, ERR_BADSTATUS
);
3774 * we have had some problems receiving the time code
3776 parse_event(parse
, CEVNT_PROP
);
3777 NLOG(NLOG_CLOCKSTATUS
)
3779 msyslog(LOG_ERR
,"PARSE receiver #%d: TIMECODE NOT CONFIRMED",
3780 CLK_UNIT(parse
->peer
));
3784 fudge
= parse
->generic
->fudgetime1
; /* standard RS232 Fudgefactor */
3786 if (PARSE_TIMECODE(parsetime
->parse_state
))
3788 rectime
= parsetime
->parse_stime
.fp
;
3789 off
= reftime
= parsetime
->parse_time
.fp
;
3791 L_SUB(&off
, &rectime
); /* prepare for PPS adjustments logic */
3795 printf("PARSE receiver #%d: Reftime %s, Recvtime %s - initial offset %s\n",
3796 CLK_UNIT(parse
->peer
),
3797 prettydate(&reftime
),
3798 prettydate(&rectime
),
3803 if (PARSE_PPS(parsetime
->parse_state
) && CLK_PPS(parse
->peer
))
3806 double ppsphaseadjust
= parse
->ppsphaseadjust
;
3810 * set fudge = 0.0 if already included in PPS time stamps
3812 if (parse
->atom
.pps_params
.mode
& (PPS_OFFSETCLEAR
|PPS_OFFSETASSERT
))
3814 ppsphaseadjust
= 0.0;
3819 * we have a PPS signal - much better than the RS232 stuff (we hope)
3821 offset
= parsetime
->parse_ptime
.fp
;
3825 printf("PARSE receiver #%d: PPStime %s\n",
3826 CLK_UNIT(parse
->peer
),
3827 prettydate(&offset
));
3829 if (PARSE_TIMECODE(parsetime
->parse_state
))
3831 if (M_ISGEQ(off
.l_i
, off
.l_f
, -1, 0x80000000) &&
3832 M_ISGEQ(0, 0x7fffffff, off
.l_i
, off
.l_f
))
3834 fudge
= ppsphaseadjust
; /* pick PPS fudge factor */
3837 * RS232 offsets within [-0.5..0.5[ - take PPS offsets
3840 if (parse
->parse_type
->cl_flags
& PARSE_F_PPSONSECOND
)
3842 reftime
= off
= offset
;
3843 if (reftime
.l_uf
& (unsigned)0x80000000)
3849 * implied on second offset
3851 off
.l_uf
= ~off
.l_uf
; /* map [0.5..1[ -> [-0.5..0[ */
3852 off
.l_ui
= (off
.l_f
< 0) ? ~0 : 0; /* sign extend */
3857 * time code describes pulse
3859 reftime
= off
= parsetime
->parse_time
.fp
;
3861 L_SUB(&off
, &offset
); /* true offset */
3865 * take RS232 offset when PPS when out of bounds
3870 fudge
= ppsphaseadjust
; /* pick PPS fudge factor */
3872 * Well, no time code to guide us - assume on second pulse
3873 * and pray, that we are within [-0.5..0.5[
3877 if (reftime
.l_uf
& (unsigned)0x80000000)
3881 * implied on second offset
3883 off
.l_uf
= ~off
.l_uf
; /* map [0.5..1[ -> [-0.5..0[ */
3884 off
.l_ui
= (off
.l_f
< 0) ? ~0 : 0; /* sign extend */
3889 if (!PARSE_TIMECODE(parsetime
->parse_state
))
3892 * Well, no PPS, no TIMECODE, no more work ...
3894 if ((parsetime
->parse_status
& CVT_ADDITIONAL
) &&
3895 parse
->parse_type
->cl_message
)
3896 parse
->parse_type
->cl_message(parse
, parsetime
);
3903 printf("PARSE receiver #%d: Reftime %s, Recvtime %s - final offset %s\n",
3904 CLK_UNIT(parse
->peer
),
3905 prettydate(&reftime
),
3906 prettydate(&rectime
),
3912 L_SUB(&rectime
, &off
); /* just to keep the ntp interface happy */
3916 printf("PARSE receiver #%d: calculated Reftime %s, Recvtime %s\n",
3917 CLK_UNIT(parse
->peer
),
3918 prettydate(&reftime
),
3919 prettydate(&rectime
));
3922 if ((parsetime
->parse_status
& CVT_ADDITIONAL
) &&
3923 parse
->parse_type
->cl_message
)
3924 parse
->parse_type
->cl_message(parse
, parsetime
);
3926 if (PARSE_SYNC(parsetime
->parse_state
))
3931 parse_event(parse
, CEVNT_NOMINAL
);
3934 clear_err(parse
, ERR_BADIO
);
3935 clear_err(parse
, ERR_BADDATA
);
3936 clear_err(parse
, ERR_NODATA
);
3937 clear_err(parse
, ERR_INTERNAL
);
3940 * and now stick it into the clock machine
3941 * samples are only valid iff lastsync is not too old and
3942 * we have seen the clock in sync at least once
3943 * after the last time we didn't see an expected data telegram
3944 * at startup being not in sync is also bad just like
3946 * see the clock states section above for more reasoning
3948 if (((current_time
- parse
->lastsync
) > parse
->maxunsync
) ||
3949 (parse
->lastsync
< parse
->lastmissed
) ||
3950 ((parse
->lastsync
== 0) && !PARSE_SYNC(parsetime
->parse_state
)) ||
3951 PARSE_POWERUP(parsetime
->parse_state
))
3953 parse
->generic
->leap
= LEAP_NOTINSYNC
;
3954 parse
->lastsync
= 0; /* wait for full sync again */
3958 if (PARSE_LEAPADD(parsetime
->parse_state
))
3961 * we pick this state also for time code that pass leap warnings
3962 * without direction information (as earth is currently slowing
3965 parse
->generic
->leap
= (parse
->flags
& PARSE_LEAP_DELETE
) ? LEAP_DELSECOND
: LEAP_ADDSECOND
;
3968 if (PARSE_LEAPDEL(parsetime
->parse_state
))
3970 parse
->generic
->leap
= LEAP_DELSECOND
;
3974 parse
->generic
->leap
= LEAP_NOWARNING
;
3978 if (parse
->generic
->leap
!= LEAP_NOTINSYNC
)
3981 * only good/trusted samples are interesting
3986 printf("PARSE receiver #%d: refclock_process_offset(reftime=%s, rectime=%s, Fudge=%f)\n",
3987 CLK_UNIT(parse
->peer
),
3988 prettydate(&reftime
),
3989 prettydate(&rectime
),
3993 parse
->generic
->lastref
= reftime
;
3995 refclock_process_offset(parse
->generic
, reftime
, rectime
, fudge
);
3999 * pass PPS information on to PPS clock
4001 if (PARSE_PPS(parsetime
->parse_state
) && CLK_PPS(parse
->peer
))
4003 /* refclock_pps includes fudgetime1 - we keep the RS232 offset in there :-( */
4004 double savedtime1
= parse
->generic
->fudgetime1
;
4006 parse
->generic
->fudgetime1
= fudge
;
4008 if (refclock_pps(parse
->peer
, &parse
->atom
,
4009 parse
->flags
& (CLK_FLAG1
|CLK_FLAG2
|CLK_FLAG3
|CLK_FLAG4
))) {
4010 parse
->peer
->flags
|= FLAG_PPS
;
4012 parse
->peer
->flags
&= ~FLAG_PPS
;
4015 parse
->generic
->fudgetime1
= savedtime1
;
4017 parse_hardpps(parse
, PARSE_HARDPPS_ENABLE
);
4021 parse_hardpps(parse
, PARSE_HARDPPS_DISABLE
);
4022 parse
->peer
->flags
&= ~FLAG_PPS
;
4026 * ready, unless the machine wants a sample or
4027 * we are in fast startup mode (peer->dist > MAXDISTANCE)
4029 if (!parse
->pollneeddata
&& parse
->peer
->disp
<= MAXDISTANCE
)
4032 parse
->pollneeddata
= 0;
4034 parse
->timedata
.parse_state
&= ~(unsigned)(PARSEB_PPS
|PARSEB_S_PPS
);
4036 refclock_receive(parse
->peer
);
4039 /**===========================================================================
4040 ** special code for special clocks
4057 snprintf(t
, size
, "current correction %d sec", dtls
);
4066 gpstolfp((unsigned short)wnlsf
, (unsigned short)dn
, 0, &leapdate
);
4068 if ((dtlsf
!= dtls
) &&
4069 ((wnlsf
- wnt
) < 52))
4071 snprintf(t
, BUFFER_SIZES(start
, t
, size
), ", next correction %d sec on %s, new GPS-UTC offset %d",
4072 dtlsf
- dtls
, gmprettydate(&leapdate
), dtlsf
);
4076 snprintf(t
, BUFFER_SIZES(start
, t
, size
), ", last correction on %s",
4077 gmprettydate(&leapdate
));
4081 #ifdef CLOCK_MEINBERG
4082 /**===========================================================================
4083 ** Meinberg GPS166/GPS167 support
4086 /*------------------------------------------------------------
4087 * gps16x_message - process GPS16x messages
4091 struct parseunit
*parse
,
4092 parsetime_t
*parsetime
4095 if (parse
->timedata
.parse_msglen
&& parsetime
->parse_msg
[0] == SOH
)
4098 unsigned char *bufp
= (unsigned char *)parsetime
->parse_msg
+ 1;
4103 char msgbuffer
[600];
4105 mkreadable(msgbuffer
, sizeof(msgbuffer
), (char *)parsetime
->parse_msg
, parsetime
->parse_msglen
, 1);
4106 printf("PARSE receiver #%d: received message (%d bytes) >%s<\n",
4107 CLK_UNIT(parse
->peer
),
4108 parsetime
->parse_msglen
,
4112 get_mbg_header(&bufp
, &header
);
4113 if (header
.gps_hdr_csum
== mbg_csum(parsetime
->parse_msg
+ 1, 6) &&
4114 (header
.gps_len
== 0 ||
4115 (header
.gps_len
< sizeof(parsetime
->parse_msg
) &&
4116 header
.gps_data_csum
== mbg_csum(bufp
, header
.gps_len
))))
4121 switch (header
.gps_cmd
)
4128 get_mbg_sw_rev(&bufp
, &gps_sw_rev
);
4129 snprintf(buffer
, sizeof(buffer
), "meinberg_gps_version=\"%x.%02x%s%s\"",
4130 (gps_sw_rev
.code
>> 8) & 0xFF,
4131 gps_sw_rev
.code
& 0xFF,
4132 gps_sw_rev
.name
[0] ? " " : "",
4134 set_var(&parse
->kv
, buffer
, strlen(buffer
)+1, RO
|DEF
);
4142 unsigned short flag
; /* status flag */
4143 unsigned const char *string
; /* bit name */
4146 { TM_ANT_DISCONN
, (const unsigned char *)"ANTENNA FAULTY" },
4147 { TM_SYN_FLAG
, (const unsigned char *)"NO SYNC SIGNAL" },
4148 { TM_NO_SYNC
, (const unsigned char *)"NO SYNC POWERUP" },
4149 { TM_NO_POS
, (const unsigned char *)"NO POSITION" },
4150 { 0, (const unsigned char *)"" }
4152 unsigned short status
;
4153 struct state
*s
= states
;
4157 status
= get_lsb_short(&bufp
);
4158 snprintf(buffer
, sizeof(buffer
), "meinberg_gps_status=\"[0x%04x] ", status
);
4162 p
= b
= buffer
+ strlen(buffer
);
4165 if (status
& s
->flag
)
4173 strncat(p
, (const char *)s
->string
, sizeof(buffer
));
4183 strncat(buffer
, "<OK>\"", sizeof(buffer
));
4186 set_var(&parse
->kv
, buffer
, strlen(buffer
)+1, RO
|DEF
);
4195 get_mbg_xyz(&bufp
, xyz
);
4196 snprintf(buffer
, sizeof(buffer
), "gps_position(XYZ)=\"%s m, %s m, %s m\"",
4197 mfptoa(xyz
[XP
].l_ui
, xyz
[XP
].l_uf
, 1),
4198 mfptoa(xyz
[YP
].l_ui
, xyz
[YP
].l_uf
, 1),
4199 mfptoa(xyz
[ZP
].l_ui
, xyz
[ZP
].l_uf
, 1));
4201 set_var(&parse
->kv
, buffer
, sizeof(buffer
), RO
|DEF
);
4210 get_mbg_lla(&bufp
, lla
);
4212 snprintf(buffer
, sizeof(buffer
), "gps_position(LLA)=\"%s deg, %s deg, %s m\"",
4213 mfptoa(lla
[LAT
].l_ui
, lla
[LAT
].l_uf
, 4),
4214 mfptoa(lla
[LON
].l_ui
, lla
[LON
].l_uf
, 4),
4215 mfptoa(lla
[ALT
].l_ui
, lla
[ALT
].l_uf
, 1));
4217 set_var(&parse
->kv
, buffer
, sizeof(buffer
), RO
|DEF
);
4236 get_mbg_antinfo(&bufp
, &antinfo
);
4237 snprintf(buffer
, sizeof(buffer
), "meinberg_antenna_status=\"");
4238 p
= buffer
+ strlen(buffer
);
4240 switch (antinfo
.status
)
4243 strncat(p
, "<OK>", BUFFER_SIZE(buffer
, p
));
4248 strncat(p
, "DISCONNECTED since ", BUFFER_SIZE(buffer
, p
));
4249 NLOG(NLOG_CLOCKSTATUS
)
4251 msyslog(LOG_ERR
,"PARSE receiver #%d: ANTENNA FAILURE: %s",
4252 CLK_UNIT(parse
->peer
), p
);
4255 mbg_tm_str(&p
, &antinfo
.tm_disconn
, BUFFER_SIZE(buffer
, p
));
4260 strncat(p
, "RECONNECTED on ", BUFFER_SIZE(buffer
, p
));
4262 mbg_tm_str(&p
, &antinfo
.tm_reconn
, BUFFER_SIZE(buffer
, p
));
4263 snprintf(p
, BUFFER_SIZE(buffer
, p
), ", reconnect clockoffset %c%ld.%07ld s, disconnect time ",
4264 (antinfo
.delta_t
< 0) ? '-' : '+',
4265 ABS(antinfo
.delta_t
) / 10000,
4266 ABS(antinfo
.delta_t
) % 10000);
4268 mbg_tm_str(&p
, &antinfo
.tm_disconn
, BUFFER_SIZE(buffer
, p
));
4273 snprintf(p
, BUFFER_SIZE(buffer
, p
), "bad status 0x%04x", antinfo
.status
);
4278 strncat(p
, "\"", BUFFER_SIZE(buffer
, p
));
4280 set_var(&parse
->kv
, buffer
, strlen(buffer
)+1, RO
|DEF
);
4293 get_mbg_cfgh(&bufp
, &cfgh
);
4299 strncpy(buffer
, "gps_tot_51=\"", BUFFER_SIZE(buffer
, p
));
4301 mbg_tgps_str(&p
, &cfgh
.tot_51
, BUFFER_SIZE(buffer
, p
));
4302 strncpy(p
, "\"", BUFFER_SIZE(buffer
, p
));
4303 set_var(&parse
->kv
, buffer
, strlen(buffer
)+1, RO
);
4306 strncpy(buffer
, "gps_tot_63=\"", BUFFER_SIZE(buffer
, p
));
4308 mbg_tgps_str(&p
, &cfgh
.tot_63
, BUFFER_SIZE(buffer
, p
));
4309 strncpy(p
, "\"", BUFFER_SIZE(buffer
, p
));
4310 set_var(&parse
->kv
, buffer
, strlen(buffer
)+1, RO
);
4313 strncpy(buffer
, "gps_t0a=\"", BUFFER_SIZE(buffer
, p
));
4315 mbg_tgps_str(&p
, &cfgh
.t0a
, BUFFER_SIZE(buffer
, p
));
4316 strncpy(p
, "\"", BUFFER_SIZE(buffer
, p
));
4317 set_var(&parse
->kv
, buffer
, strlen(buffer
)+1, RO
);
4319 for (i
= MIN_SVNO
; i
< MAX_SVNO
; i
++)
4322 snprintf(p
, BUFFER_SIZE(buffer
, p
), "gps_cfg[%d]=\"[0x%x] ", i
, cfgh
.cfg
[i
]);
4324 switch (cfgh
.cfg
[i
] & 0x7)
4327 strncpy(p
, "BLOCK I", BUFFER_SIZE(buffer
, p
));
4330 strncpy(p
, "BLOCK II", BUFFER_SIZE(buffer
, p
));
4333 strncpy(p
, "bad CFG", BUFFER_SIZE(buffer
, p
));
4336 strncat(p
, "\"", BUFFER_SIZE(buffer
, p
));
4337 set_var(&parse
->kv
, buffer
, strlen(buffer
)+1, RO
);
4340 snprintf(p
, BUFFER_SIZE(buffer
, p
), "gps_health[%d]=\"[0x%x] ", i
, cfgh
.health
[i
]);
4342 switch ((cfgh
.health
[i
] >> 5) & 0x7 )
4345 strncpy(p
, "OK;", BUFFER_SIZE(buffer
, p
));
4348 strncpy(p
, "PARITY;", BUFFER_SIZE(buffer
, p
));
4351 strncpy(p
, "TLM/HOW;", BUFFER_SIZE(buffer
, p
));
4354 strncpy(p
, "Z-COUNT;", BUFFER_SIZE(buffer
, p
));
4357 strncpy(p
, "SUBFRAME 1,2,3;", BUFFER_SIZE(buffer
, p
));
4360 strncpy(p
, "SUBFRAME 4,5;", BUFFER_SIZE(buffer
, p
));
4363 strncpy(p
, "UPLOAD BAD;", BUFFER_SIZE(buffer
, p
));
4366 strncpy(p
, "DATA BAD;", BUFFER_SIZE(buffer
, p
));
4372 switch (cfgh
.health
[i
] & 0x1F)
4375 strncpy(p
, "SIGNAL OK", BUFFER_SIZE(buffer
, p
));
4378 strncpy(p
, "SV TEMP OUT", BUFFER_SIZE(buffer
, p
));
4381 strncpy(p
, "SV WILL BE TEMP OUT", BUFFER_SIZE(buffer
, p
));
4386 strncpy(p
, "MULTIPLE ERRS", BUFFER_SIZE(buffer
, p
));
4389 strncpy(p
, "TRANSMISSION PROBLEMS", BUFFER_SIZE(buffer
, p
));
4393 strncat(p
, "\"", sizeof(buffer
));
4394 set_var(&parse
->kv
, buffer
, strlen(buffer
)+1, RO
);
4414 get_mbg_utc(&bufp
, &utc
);
4418 strncpy(p
, "gps_utc_correction=\"", sizeof(buffer
));
4420 mk_utcinfo(p
, utc
.t0t
.wn
, utc
.WNlsf
, utc
.DNt
, utc
.delta_tls
, utc
.delta_tlsf
, BUFFER_SIZE(buffer
, p
));
4421 strncat(p
, "\"", BUFFER_SIZE(buffer
, p
));
4425 strncpy(p
, "gps_utc_correction=\"<NO UTC DATA>\"", BUFFER_SIZE(buffer
, p
));
4427 set_var(&parse
->kv
, buffer
, strlen(buffer
)+1, RO
|DEF
);
4436 ASCII_MSG gps_ascii_msg
;
4439 get_mbg_ascii_msg(&bufp
, &gps_ascii_msg
);
4441 if (gps_ascii_msg
.valid
)
4444 mkreadable(buffer1
, sizeof(buffer1
), gps_ascii_msg
.s
, strlen(gps_ascii_msg
.s
), (int)0);
4446 snprintf(buffer
, sizeof(buffer
), "gps_message=\"%s\"", buffer1
);
4449 strncpy(buffer
, "gps_message=<NONE>", sizeof(buffer
));
4451 set_var(&parse
->kv
, buffer
, strlen(buffer
)+1, RO
|DEF
);
4462 msyslog(LOG_DEBUG
, "PARSE receiver #%d: gps16x_message: message checksum error: hdr_csum = 0x%x (expected 0x%lx), data_len = %d, data_csum = 0x%x (expected 0x%lx)",
4463 CLK_UNIT(parse
->peer
),
4464 header
.gps_hdr_csum
, mbg_csum(parsetime
->parse_msg
+ 1, 6),
4466 header
.gps_data_csum
, mbg_csum(bufp
, (unsigned)((header
.gps_len
< sizeof(parsetime
->parse_msg
)) ? header
.gps_len
: 0)));
4473 /*------------------------------------------------------------
4474 * gps16x_poll - query the reciver peridically
4481 struct parseunit
*parse
= (struct parseunit
*)peer
->procptr
->unitptr
;
4483 static GPS_MSG_HDR sequence
[] =
4485 { GPS_SW_REV
, 0, 0, 0 },
4486 { GPS_STAT
, 0, 0, 0 },
4487 { GPS_UTC
, 0, 0, 0 },
4488 { GPS_ASCII_MSG
, 0, 0, 0 },
4489 { GPS_ANT_INFO
, 0, 0, 0 },
4490 { GPS_CFGH
, 0, 0, 0 },
4491 { GPS_POS_XYZ
, 0, 0, 0 },
4492 { GPS_POS_LLA
, 0, 0, 0 },
4493 { (unsigned short)~0, 0, 0, 0 }
4497 unsigned char cmd_buffer
[64];
4498 unsigned char *outp
= cmd_buffer
;
4499 GPS_MSG_HDR
*header
;
4501 if (((poll_info_t
*)parse
->parse_type
->cl_data
)->rate
)
4503 parse
->peer
->nextaction
= current_time
+ ((poll_info_t
*)parse
->parse_type
->cl_data
)->rate
;
4506 if (sequence
[parse
->localstate
].gps_cmd
== (unsigned short)~0)
4507 parse
->localstate
= 0;
4509 header
= sequence
+ parse
->localstate
++;
4511 *outp
++ = SOH
; /* start command */
4513 put_mbg_header(&outp
, header
);
4514 outp
= cmd_buffer
+ 1;
4516 header
->gps_hdr_csum
= (short)mbg_csum(outp
, 6);
4517 put_mbg_header(&outp
, header
);
4524 mkreadable(buffer
, sizeof(buffer
), (char *)cmd_buffer
, (unsigned)(outp
- cmd_buffer
), 1);
4525 printf("PARSE receiver #%d: transmitted message #%ld (%d bytes) >%s<\n",
4526 CLK_UNIT(parse
->peer
),
4527 parse
->localstate
- 1,
4528 (int)(outp
- cmd_buffer
),
4533 rtc
= write(parse
->generic
->io
.fd
, cmd_buffer
, (unsigned long)(outp
- cmd_buffer
));
4538 msyslog(LOG_ERR
, "PARSE receiver #%d: gps16x_poll: failed to send cmd to clock: %m", CLK_UNIT(parse
->peer
));
4541 if (rtc
!= outp
- cmd_buffer
)
4544 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
));
4547 clear_err(parse
, ERR_BADIO
);
4551 /*--------------------------------------------------
4552 * init routine - setup timer
4556 struct parseunit
*parse
4559 if (((poll_info_t
*)parse
->parse_type
->cl_data
)->rate
)
4561 parse
->peer
->action
= gps16x_poll
;
4562 gps16x_poll(parse
->peer
);
4571 struct parseunit
*parse
,
4572 parsetime_t
*parsetime
4577 struct parseunit
*parse
4582 #endif /* CLOCK_MEINBERG */
4584 /**===========================================================================
4585 ** clock polling support
4588 /*--------------------------------------------------
4589 * direct poll routine
4593 struct parseunit
*parse
4597 const char *ps
= ((poll_info_t
*)parse
->parse_type
->cl_data
)->string
;
4598 int ct
= ((poll_info_t
*)parse
->parse_type
->cl_data
)->count
;
4600 rtc
= write(parse
->generic
->io
.fd
, ps
, (unsigned long)ct
);
4604 msyslog(LOG_ERR
, "PARSE receiver #%d: poll_dpoll: failed to send cmd to clock: %m", CLK_UNIT(parse
->peer
));
4610 msyslog(LOG_ERR
, "PARSE receiver #%d: poll_dpoll: failed to send cmd incomplete (%d of %d bytes sent)", CLK_UNIT(parse
->peer
), rtc
, ct
);
4612 clear_err(parse
, ERR_BADIO
);
4615 /*--------------------------------------------------
4616 * periodic poll routine
4623 struct parseunit
*parse
= (struct parseunit
*)peer
->procptr
->unitptr
;
4625 if (parse
->parse_type
->cl_poll
)
4626 parse
->parse_type
->cl_poll(parse
);
4628 if (((poll_info_t
*)parse
->parse_type
->cl_data
)->rate
)
4630 parse
->peer
->nextaction
= current_time
+ ((poll_info_t
*)parse
->parse_type
->cl_data
)->rate
;
4634 /*--------------------------------------------------
4635 * init routine - setup timer
4639 struct parseunit
*parse
4642 if (((poll_info_t
*)parse
->parse_type
->cl_data
)->rate
)
4644 parse
->peer
->action
= poll_poll
;
4645 poll_poll(parse
->peer
);
4651 /**===========================================================================
4655 /*-------------------------------------------------------------
4656 * trimble TAIP init routine - setup EOL and then do poll_init.
4660 struct parseunit
*parse
4666 #ifdef HAVE_SYSV_TTYS
4670 * configure terminal line for trimble receiver
4672 if (TTY_GETATTR(parse
->generic
->io
.fd
, &tio
) == -1)
4674 msyslog(LOG_ERR
, "PARSE receiver #%d: trimbletaip_init: tcgetattr(fd, &tio): %m", CLK_UNIT(parse
->peer
));
4679 tio
.c_cc
[VEOL
] = TRIMBLETAIP_EOL
;
4681 if (TTY_SETATTR(parse
->generic
->io
.fd
, &tio
) == -1)
4683 msyslog(LOG_ERR
, "PARSE receiver #%d: trimbletaip_init: tcsetattr(fd, &tio): %m", CLK_UNIT(parse
->peer
));
4687 return poll_init(parse
);
4690 /*--------------------------------------------------
4691 * trimble TAIP event routine - reset receiver upon data format trouble
4693 static const char *taipinit
[] = {
4695 ">SRM;ID_FLAG=F;CS_FLAG=T;EC_FLAG=F;FR_FLAG=T;CR_FLAG=F<",
4702 struct parseunit
*parse
,
4708 case CEVNT_BADREPLY
: /* reset on garbled input */
4709 case CEVNT_TIMEOUT
: /* reset on no input */
4716 int rtc
= write(parse
->generic
->io
.fd
, *iv
, strlen(*iv
));
4719 msyslog(LOG_ERR
, "PARSE receiver #%d: trimbletaip_event: failed to send cmd to clock: %m", CLK_UNIT(parse
->peer
));
4724 if (rtc
!= strlen(*iv
))
4726 msyslog(LOG_ERR
, "PARSE receiver #%d: trimbletaip_event: failed to send cmd incomplete (%d of %d bytes sent)",
4727 CLK_UNIT(parse
->peer
), rtc
, (int)strlen(*iv
));
4734 NLOG(NLOG_CLOCKINFO
)
4736 msyslog(LOG_ERR
, "PARSE receiver #%d: trimbletaip_event: RECEIVER INITIALIZED",
4737 CLK_UNIT(parse
->peer
));
4741 default: /* ignore */
4747 * This driver supports the Trimble SVee Six Plus GPS receiver module.
4748 * It should support other Trimble receivers which use the Trimble Standard
4749 * Interface Protocol (see below).
4751 * The module has a serial I/O port for command/data and a 1 pulse-per-second
4752 * output, about 1 microsecond wide. The leading edge of the pulse is
4753 * coincident with the change of the GPS second. This is the same as
4754 * the change of the UTC second +/- ~1 microsecond. Some other clocks
4755 * specifically use a feature in the data message as a timing reference, but
4756 * the SVee Six Plus does not do this. In fact there is considerable jitter
4757 * on the timing of the messages, so this driver only supports the use
4758 * of the PPS pulse for accurate timing. Where it is determined that
4759 * the offset is way off, when first starting up ntpd for example,
4760 * the timing of the data stream is used until the offset becomes low enough
4761 * (|offset| < CLOCK_MAX), at which point the pps offset is used.
4763 * It can use either option for receiving PPS information - the 'ppsclock'
4764 * stream pushed onto the serial data interface to timestamp the Carrier
4765 * Detect interrupts, where the 1PPS connects to the CD line. This only
4766 * works on SunOS 4.1.x currently. To select this, define PPSPPS in
4767 * Config.local. The other option is to use a pulse-stretcher/level-converter
4768 * to convert the PPS pulse into a RS232 start pulse & feed this into another
4769 * tty port. To use this option, define PPSCLK in Config.local. The pps input,
4770 * by whichever method, is handled in ntp_loopfilter.c
4772 * The receiver uses a serial message protocol called Trimble Standard
4773 * Interface Protocol (it can support others but this driver only supports
4774 * TSIP). Messages in this protocol have the following form:
4776 * <DLE><id> ... <data> ... <DLE><ETX>
4778 * Any bytes within the <data> portion of value 10 hex (<DLE>) are doubled
4779 * on transmission and compressed back to one on reception. Otherwise
4780 * the values of data bytes can be anything. The serial interface is RS-422
4781 * asynchronous using 9600 baud, 8 data bits with odd party (**note** 9 bits
4782 * in total!), and 1 stop bit. The protocol supports byte, integer, single,
4783 * and double datatypes. Integers are two bytes, sent most significant first.
4784 * Singles are IEEE754 single precision floating point numbers (4 byte) sent
4785 * sign & exponent first. Doubles are IEEE754 double precision floating point
4786 * numbers (8 byte) sent sign & exponent first.
4787 * The receiver supports a large set of messages, only a small subset of
4788 * which are used here. From driver to receiver the following are used:
4792 * 21 Request current time
4794 * 2C Set/Request operating parameters
4795 * 2F Request UTC info
4796 * 35 Set/Request I/O options
4798 * From receiver to driver the following are recognised:
4803 * 44 Satellite selection, PDOP, mode
4804 * 46 Receiver health
4805 * 4B Machine code/status
4806 * 4C Report operating parameters (debug only)
4807 * 4F UTC correction data (used to get leap second warnings)
4808 * 55 I/O options (debug only)
4810 * All others are accepted but ignored.
4814 #define PI 3.1415926535898 /* lots of sig figs */
4815 #define D2R PI/180.0
4817 /*-------------------------------------------------------------------
4818 * sendcmd, sendbyte, sendetx, sendflt, sendint implement the command
4819 * interface to the receiver.
4821 * CAVEAT: the sendflt, sendint routines are byte order dependend and
4822 * float implementation dependend - these must be converted to portable
4825 * CURRENT LIMITATION: float implementation. This runs only on systems
4826 * with IEEE754 floats as native floats
4829 typedef struct trimble
4831 u_long last_msg
; /* last message received */
4832 u_long last_reset
; /* last time a reset was issued */
4833 u_char qtracking
; /* query tracking status */
4834 u_long ctrack
; /* current tracking set */
4835 u_long ltrack
; /* last tracking set */
4847 short idx
; /* index to first unused byte */
4848 u_char
*txt
; /* pointer to actual data buffer */
4851 void sendcmd (struct txbuf
*buf
, int c
);
4852 void sendbyte (struct txbuf
*buf
, int b
);
4853 void sendetx (struct txbuf
*buf
, struct parseunit
*parse
);
4854 void sendint (struct txbuf
*buf
, int a
);
4855 void sendflt (struct txbuf
*buf
, double a
);
4864 buf
->txt
[1] = (u_char
)c
;
4868 void sendcmd (struct txbuf
*buf
, int c
);
4869 void sendbyte (struct txbuf
*buf
, int b
);
4870 void sendetx (struct txbuf
*buf
, struct parseunit
*parse
);
4871 void sendint (struct txbuf
*buf
, int a
);
4872 void sendflt (struct txbuf
*buf
, double a
);
4881 buf
->txt
[buf
->idx
++] = DLE
;
4882 buf
->txt
[buf
->idx
++] = (u_char
)b
;
4888 struct parseunit
*parse
4891 buf
->txt
[buf
->idx
++] = DLE
;
4892 buf
->txt
[buf
->idx
++] = ETX
;
4894 if (write(parse
->generic
->io
.fd
, buf
->txt
, (unsigned long)buf
->idx
) != buf
->idx
)
4897 msyslog(LOG_ERR
, "PARSE receiver #%d: sendetx: failed to send cmd to clock: %m", CLK_UNIT(parse
->peer
));
4906 mkreadable(buffer
, sizeof(buffer
), (char *)buf
->txt
, (unsigned)buf
->idx
, 1);
4907 printf("PARSE receiver #%d: transmitted message (%d bytes) >%s<\n",
4908 CLK_UNIT(parse
->peer
),
4912 clear_err(parse
, ERR_BADIO
);
4922 /* send 16bit int, msbyte first */
4923 sendbyte(buf
, (u_char
)((a
>>8) & 0xff));
4924 sendbyte(buf
, (u_char
)(a
& 0xff));
4937 #ifdef WORDS_BIGENDIAN
4938 for (i
=0; i
<=3; i
++)
4940 for (i
=3; i
>=0; i
--)
4942 sendbyte(buf
, uval
.bd
[i
]);
4945 #define TRIM_POS_OPT 0x13 /* output position with high precision */
4946 #define TRIM_TIME_OPT 0x03 /* use UTC time stamps, on second */
4948 /*--------------------------------------------------
4949 * trimble TSIP setup routine
4953 struct parseunit
*parse
,
4959 trimble_t
*t
= parse
->localdata
;
4961 if (t
&& t
->last_reset
&&
4962 ((t
->last_reset
+ TRIMBLE_RESET_HOLDOFF
) > current_time
)) {
4963 return 1; /* not yet */
4967 t
->last_reset
= current_time
;
4971 sendcmd(&buf
, CMD_CVERSION
); /* request software versions */
4972 sendetx(&buf
, parse
);
4974 sendcmd(&buf
, CMD_COPERPARAM
); /* set operating parameters */
4975 sendbyte(&buf
, 4); /* static */
4976 sendflt(&buf
, 5.0*D2R
); /* elevation angle mask = 10 deg XXX */
4977 sendflt(&buf
, 4.0); /* s/n ratio mask = 6 XXX */
4978 sendflt(&buf
, 12.0); /* PDOP mask = 12 */
4979 sendflt(&buf
, 8.0); /* PDOP switch level = 8 */
4980 sendetx(&buf
, parse
);
4982 sendcmd(&buf
, CMD_CMODESEL
); /* fix mode select */
4983 sendbyte(&buf
, 1); /* time transfer mode */
4984 sendetx(&buf
, parse
);
4986 sendcmd(&buf
, CMD_CMESSAGE
); /* request system message */
4987 sendetx(&buf
, parse
);
4989 sendcmd(&buf
, CMD_CSUPER
); /* superpacket fix */
4990 sendbyte(&buf
, 0x2); /* binary mode */
4991 sendetx(&buf
, parse
);
4993 sendcmd(&buf
, CMD_CIOOPTIONS
); /* set I/O options */
4994 sendbyte(&buf
, TRIM_POS_OPT
); /* position output */
4995 sendbyte(&buf
, 0x00); /* no velocity output */
4996 sendbyte(&buf
, TRIM_TIME_OPT
); /* UTC, compute on seconds */
4997 sendbyte(&buf
, 0x00); /* no raw measurements */
4998 sendetx(&buf
, parse
);
5000 sendcmd(&buf
, CMD_CUTCPARAM
); /* request UTC correction data */
5001 sendetx(&buf
, parse
);
5003 NLOG(NLOG_CLOCKINFO
)
5005 msyslog(LOG_ERR
, "PARSE receiver #%d: trimbletsip_setup: RECEIVER RE-INITIALIZED (%s)", CLK_UNIT(parse
->peer
), reason
);
5010 /*--------------------------------------------------
5011 * TRIMBLE TSIP check routine
5018 struct parseunit
*parse
= (struct parseunit
*)peer
->procptr
->unitptr
;
5019 trimble_t
*t
= parse
->localdata
;
5026 if (current_time
> t
->last_msg
+ TRIMBLETSIP_IDLE_TIME
)
5027 (void)trimbletsip_setup(parse
, "message timeout");
5030 poll_poll(parse
->peer
); /* emit query string and re-arm timer */
5032 if (t
&& t
->qtracking
)
5034 u_long oldsats
= t
->ltrack
& ~t
->ctrack
;
5037 t
->ltrack
= t
->ctrack
;
5043 for (i
= 0; oldsats
; i
++) {
5044 if (oldsats
& (1 << i
))
5046 sendcmd(&buf
, CMD_CSTATTRACK
);
5047 sendbyte(&buf
, i
+1); /* old sat */
5048 sendetx(&buf
, parse
);
5050 oldsats
&= ~(1 << i
);
5054 sendcmd(&buf
, CMD_CSTATTRACK
);
5055 sendbyte(&buf
, 0x00); /* current tracking set */
5056 sendetx(&buf
, parse
);
5060 /*--------------------------------------------------
5061 * TRIMBLE TSIP end routine
5065 struct parseunit
*parse
5067 { trimble_t
*t
= parse
->localdata
;
5072 parse
->localdata
= (void *)0;
5074 parse
->peer
->nextaction
= 0;
5075 parse
->peer
->action
= (void (*) (struct peer
*))0;
5078 /*--------------------------------------------------
5079 * TRIMBLE TSIP init routine
5083 struct parseunit
*parse
5086 #if defined(VEOL) || defined(VEOL2)
5088 struct termios tio
; /* NEEDED FOR A LONG TIME ! */
5090 #ifdef HAVE_SYSV_TTYS
5091 struct termio tio
; /* NEEDED FOR A LONG TIME ! */
5094 * allocate local data area
5096 if (!parse
->localdata
)
5100 t
= (trimble_t
*)(parse
->localdata
= emalloc(sizeof(trimble_t
)));
5104 memset((char *)t
, 0, sizeof(trimble_t
));
5105 t
->last_msg
= current_time
;
5109 parse
->peer
->action
= trimble_check
;
5110 parse
->peer
->nextaction
= current_time
;
5113 * configure terminal line for ICANON mode with VEOL characters
5115 if (TTY_GETATTR(parse
->generic
->io
.fd
, &tio
) == -1)
5117 msyslog(LOG_ERR
, "PARSE receiver #%d: trimbletsip_init: tcgetattr(%d, &tio): %m", CLK_UNIT(parse
->peer
), parse
->generic
->io
.fd
);
5122 if ((parse_clockinfo
[CLK_TYPE(parse
->peer
)].cl_lflag
& ICANON
))
5125 tio
.c_cc
[VEOL
] = ETX
;
5128 tio
.c_cc
[VEOL2
] = DLE
;
5132 if (TTY_SETATTR(parse
->generic
->io
.fd
, &tio
) == -1)
5134 msyslog(LOG_ERR
, "PARSE receiver #%d: trimbletsip_init: tcsetattr(%d, &tio): %m", CLK_UNIT(parse
->peer
), parse
->generic
->io
.fd
);
5139 return trimbletsip_setup(parse
, "initial startup");
5142 /*------------------------------------------------------------
5143 * trimbletsip_event - handle Trimble events
5144 * simple evente handler - attempt to re-initialize receiver
5148 struct parseunit
*parse
,
5154 case CEVNT_BADREPLY
: /* reset on garbled input */
5155 case CEVNT_TIMEOUT
: /* reset on no input */
5156 (void)trimbletsip_setup(parse
, "event BAD_REPLY/TIMEOUT");
5159 default: /* ignore */
5165 * getflt, getint convert fields in the incoming data into the
5166 * appropriate type of item
5168 * CAVEAT: these routines are currently definitely byte order dependent
5169 * and assume Representation(float) == IEEE754
5170 * These functions MUST be converted to portable versions (especially
5171 * converting the float representation into ntp_fp formats in order
5172 * to avoid floating point operations at all!
5182 #ifdef WORDS_BIGENDIAN
5187 #else /* ! WORDS_BIGENDIAN */
5192 #endif /* ! WORDS_BIGENDIAN */
5203 #ifdef WORDS_BIGENDIAN
5212 #else /* ! WORDS_BIGENDIAN */
5221 #endif /* ! WORDS_BIGENDIAN */
5230 return get_msb_short(&p
);
5233 /*--------------------------------------------------
5234 * trimbletsip_message - process trimble messages
5236 #define RTOD (180.0 / 3.1415926535898)
5237 #define mb(_X_) (buffer[2+(_X_)]) /* shortcut for buffer access */
5240 trimbletsip_message(
5241 struct parseunit
*parse
,
5242 parsetime_t
*parsetime
5245 unsigned char *buffer
= parsetime
->parse_msg
;
5246 unsigned int size
= parsetime
->parse_msglen
;
5249 (buffer
[0] != DLE
) ||
5250 (buffer
[size
-1] != ETX
) ||
5251 (buffer
[size
-2] != DLE
))
5257 printf("TRIMBLE BAD packet, size %d:\n ", size
);
5258 for (i
= 0; i
< size
; i
++) {
5259 printf ("%2.2x, ", buffer
[i
]&0xff);
5260 if (i
%16 == 15) printf("\n\t");
5270 trimble_t
*tr
= parse
->localdata
;
5271 unsigned int cmd
= buffer
[1];
5280 printf("TRIMBLE packet 0x%02x, size %d:\n ", cmd
, size
);
5281 for (i
= 0; i
< size
; i
++) {
5282 printf ("%2.2x, ", buffer
[i
]&0xff);
5283 if (i
%16 == 15) printf("\n\t");
5290 tr
->last_msg
= current_time
;
5292 s
= trimble_convert(cmd
, trimble_rcmds
);
5296 snprintf(t
, BUFFER_SIZE(pbuffer
, t
), "%s=\"", s
->varname
);
5300 DPRINTF(1, ("TRIMBLE UNKNOWN COMMAND 0x%02x\n", cmd
));
5304 var_flag
= s
->varmode
;
5311 snprintf(t
, BUFFER_SIZE(pbuffer
, t
), "%f, %d, %f",
5312 getflt((unsigned char *)&mb(0)), getshort((unsigned char *)&mb(4)),
5313 getflt((unsigned char *)&mb(6)));
5317 strncpy(t
, "mode: ", BUFFER_SIZE(pbuffer
, t
));
5319 switch (mb(0) & 0xF)
5322 snprintf(t
, BUFFER_SIZE(pbuffer
, t
), "0x%x", mb(0) & 0x7);
5326 strncpy(t
, "0D", BUFFER_SIZE(pbuffer
, t
));
5330 strncpy(t
, "2D", BUFFER_SIZE(pbuffer
, t
));
5334 strncpy(t
, "3D", BUFFER_SIZE(pbuffer
, t
));
5339 strncpy(t
, "-MANUAL, ", BUFFER_SIZE(pbuffer
, t
));
5341 strncpy(t
, "-AUTO, ", BUFFER_SIZE(pbuffer
, t
));
5344 snprintf(t
, BUFFER_SIZE(pbuffer
, t
), "satellites %02d %02d %02d %02d, PDOP %.2f, HDOP %.2f, VDOP %.2f, TDOP %.2f",
5345 mb(1), mb(2), mb(3), mb(4),
5346 getflt((unsigned char *)&mb(5)),
5347 getflt((unsigned char *)&mb(9)),
5348 getflt((unsigned char *)&mb(13)),
5349 getflt((unsigned char *)&mb(17)));
5354 snprintf(t
, BUFFER_SIZE(pbuffer
, t
), "%d.%d (%d/%d/%d)",
5355 mb(0)&0xff, mb(1)&0xff, 1900+(mb(4)&0xff), mb(2)&0xff, mb(3)&0xff);
5358 case CMD_RRECVHEALTH
:
5360 static const char *msgs
[] =
5362 "Battery backup failed",
5363 "Signal processor error",
5364 "Alignment error, channel or chip 1",
5365 "Alignment error, channel or chip 2",
5366 "Antenna feed line fault",
5367 "Excessive ref freq. error",
5374 switch (mb(0) & 0xFF)
5377 snprintf(t
, BUFFER_SIZE(pbuffer
, t
), "illegal value 0x%02x", mb(0) & 0xFF);
5380 strncpy(t
, "doing position fixes", BUFFER_SIZE(pbuffer
, t
));
5383 strncpy(t
, "no GPS time yet", BUFFER_SIZE(pbuffer
, t
));
5386 strncpy(t
, "PDOP too high", BUFFER_SIZE(pbuffer
, t
));
5389 strncpy(t
, "no usable satellites", BUFFER_SIZE(pbuffer
, t
));
5392 strncpy(t
, "only ONE usable satellite", BUFFER_SIZE(pbuffer
, t
));
5395 strncpy(t
, "only TWO usable satellites", BUFFER_SIZE(pbuffer
, t
));
5398 strncpy(t
, "only THREE usable satellites", BUFFER_SIZE(pbuffer
, t
));
5401 strncpy(t
, "the chosen satellite is unusable", BUFFER_SIZE(pbuffer
, t
));
5407 bits
= mb(1) & 0xFF;
5409 for (i
= 0; i
< 8; i
++)
5410 if (bits
& (0x1<<i
))
5412 snprintf(t
, BUFFER_SIZE(pbuffer
, t
), ", %s", msgs
[i
]);
5419 mkreadable(t
, (int)BUFFER_SIZE(pbuffer
, t
), (char *)&mb(0), (unsigned)(size
- 2 - (&mb(0) - buffer
)), 0);
5424 static const char *msgs
[] =
5426 "Synthesizer Fault",
5427 "Battery Powered Time Clock Fault",
5428 "A-to-D Converter Fault",
5429 "The almanac stored in the receiver is not complete and current",
5438 snprintf(t
, BUFFER_SIZE(pbuffer
, t
), "machine id 0x%02x", mb(0) & 0xFF);
5441 bits
= mb(1) & 0xFF;
5443 for (i
= 0; i
< 8; i
++)
5444 if (bits
& (0x1<<i
))
5446 snprintf(t
, BUFFER_SIZE(pbuffer
, t
), ", %s", msgs
[i
]);
5450 snprintf(t
, BUFFER_SIZE(pbuffer
, t
), ", Superpackets %ssupported", (mb(2) & 0xFF) ? "" :"un" );
5454 case CMD_ROPERPARAM
:
5455 snprintf(t
, BUFFER_SIZE(pbuffer
, t
), "%2x %.1f %.1f %.1f %.1f",
5456 mb(0), getflt((unsigned char *)&mb(1)), getflt((unsigned char *)&mb(5)),
5457 getflt((unsigned char *)&mb(9)), getflt((unsigned char *)&mb(13)));
5462 float t0t
= getflt((unsigned char *)&mb(14));
5463 short wnt
= getshort((unsigned char *)&mb(18));
5464 short dtls
= getshort((unsigned char *)&mb(12));
5465 short wnlsf
= getshort((unsigned char *)&mb(20));
5466 short dn
= getshort((unsigned char *)&mb(22));
5467 short dtlsf
= getshort((unsigned char *)&mb(24));
5471 mk_utcinfo(t
, wnt
, wnlsf
, dn
, dtls
, dtlsf
, BUFFER_SIZE(pbuffer
, t
));
5475 strncpy(t
, "<NO UTC DATA>", BUFFER_SIZE(pbuffer
, t
));
5481 snprintf(t
, BUFFER_SIZE(pbuffer
, t
), "%.1fm %.2fm/s at %.1fs",
5482 getflt(&mb(0)), getflt(&mb(4)), getflt(&mb(8)));
5485 case CMD_RIOOPTIONS
:
5487 snprintf(t
, BUFFER_SIZE(pbuffer
, t
), "%02x %02x %02x %02x",
5488 mb(0), mb(1), mb(2), mb(3));
5489 if (mb(0) != TRIM_POS_OPT
||
5490 mb(2) != TRIM_TIME_OPT
)
5492 (void)trimbletsip_setup(parse
, "bad io options");
5499 double x
= getflt((unsigned char *)&mb(0));
5500 double y
= getflt((unsigned char *)&mb(4));
5501 double z
= getflt((unsigned char *)&mb(8));
5502 double f
= getflt((unsigned char *)&mb(12));
5505 snprintf(t
, BUFFER_SIZE(pbuffer
, t
), "x= %.1fm, y= %.1fm, z= %.1fm, time_of_fix= %f sec",
5515 double lat
= getflt((unsigned char *)&mb(0));
5516 double lng
= getflt((unsigned char *)&mb(4));
5517 double f
= getflt((unsigned char *)&mb(12));
5520 snprintf(t
, BUFFER_SIZE(pbuffer
, t
), "lat %f %c, long %f %c, alt %.2fm",
5521 ((lat
< 0.0) ? (-lat
) : (lat
))*RTOD
, (lat
< 0.0 ? 'S' : 'N'),
5522 ((lng
< 0.0) ? (-lng
) : (lng
))*RTOD
, (lng
< 0.0 ? 'W' : 'E'),
5523 getflt((unsigned char *)&mb(8)));
5529 case CMD_RDOUBLEXYZ
:
5531 double x
= getdbl((unsigned char *)&mb(0));
5532 double y
= getdbl((unsigned char *)&mb(8));
5533 double z
= getdbl((unsigned char *)&mb(16));
5534 snprintf(t
, BUFFER_SIZE(pbuffer
, t
), "x= %.1fm, y= %.1fm, z= %.1fm",
5539 case CMD_RDOUBLELLA
:
5541 double lat
= getdbl((unsigned char *)&mb(0));
5542 double lng
= getdbl((unsigned char *)&mb(8));
5543 snprintf(t
, BUFFER_SIZE(pbuffer
, t
), "lat %f %c, lon %f %c, alt %.2fm",
5544 ((lat
< 0.0) ? (-lat
) : (lat
))*RTOD
, (lat
< 0.0 ? 'S' : 'N'),
5545 ((lng
< 0.0) ? (-lng
) : (lng
))*RTOD
, (lng
< 0.0 ? 'W' : 'E'),
5546 getdbl((unsigned char *)&mb(16)));
5550 case CMD_RALLINVIEW
:
5554 strncpy(t
, "mode: ", BUFFER_SIZE(pbuffer
, t
));
5556 switch (mb(0) & 0x7)
5559 snprintf(t
, BUFFER_SIZE(pbuffer
, t
), "0x%x", mb(0) & 0x7);
5563 strncpy(t
, "2D", BUFFER_SIZE(pbuffer
, t
));
5567 strncpy(t
, "3D", BUFFER_SIZE(pbuffer
, t
));
5572 strncpy(t
, "-MANUAL, ", BUFFER_SIZE(pbuffer
, t
));
5574 strncpy(t
, "-AUTO, ", BUFFER_SIZE(pbuffer
, t
));
5577 sats
= (mb(0)>>4) & 0xF;
5579 snprintf(t
, BUFFER_SIZE(pbuffer
, t
), "PDOP %.2f, HDOP %.2f, VDOP %.2f, TDOP %.2f, %d satellite%s in view: ",
5580 getflt((unsigned char *)&mb(1)),
5581 getflt((unsigned char *)&mb(5)),
5582 getflt((unsigned char *)&mb(9)),
5583 getflt((unsigned char *)&mb(13)),
5584 sats
, (sats
== 1) ? "" : "s");
5587 for (i
=0; i
< sats
; i
++)
5589 snprintf(t
, BUFFER_SIZE(pbuffer
, t
), "%s%02d", i
? ", " : "", mb(17+i
));
5592 tr
->ctrack
|= (1 << (mb(17+i
)-1));
5596 { /* mark for tracking status query */
5602 case CMD_RSTATTRACK
:
5604 snprintf(t
-2, BUFFER_SIZE(pbuffer
, t
-2), "[%02d]=\"", mb(0)); /* add index to var name */
5607 if (getflt((unsigned char *)&mb(4)) < 0.0)
5609 strncpy(t
, "<NO MEASUREMENTS>", BUFFER_SIZE(pbuffer
, t
));
5614 snprintf(t
, BUFFER_SIZE(pbuffer
, t
), "ch=%d, acq=%s, eph=%d, signal_level= %5.2f, elevation= %5.2f, azimuth= %6.2f",
5616 mb(2) ? ((mb(2) == 1) ? "ACQ" : "SRCH") : "NEVER",
5618 getflt((unsigned char *)&mb(4)),
5619 getflt((unsigned char *)&mb(12)) * RTOD
,
5620 getflt((unsigned char *)&mb(16)) * RTOD
);
5625 strncpy(t
, ", OLD", BUFFER_SIZE(pbuffer
, t
));
5631 strncpy(t
, ", BAD PARITY", BUFFER_SIZE(pbuffer
, t
));
5634 strncpy(t
, ", BAD EPH HEALTH", BUFFER_SIZE(pbuffer
, t
));
5638 strncpy(t
, ", collecting data", BUFFER_SIZE(pbuffer
, t
));
5644 strncpy(t
, "<UNDECODED>", BUFFER_SIZE(pbuffer
, t
));
5649 strncpy(t
,"\"", BUFFER_SIZE(pbuffer
, t
));
5650 set_var(&parse
->kv
, pbuffer
, sizeof(pbuffer
), var_flag
);
5655 /**============================================================
5659 /*--------------------------------------------------
5660 * rawdcf_init_1 - set up modem lines for RAWDCF receivers
5663 #if defined(TIOCMSET) && (defined(TIOCM_DTR) || defined(CIOCM_DTR))
5666 struct parseunit
*parse
5669 /* fixed 2000 for using with Linux by Wolfram Pienkoss <wp@bszh.de> */
5671 * You can use the RS232 to supply the power for a DCF77 receiver.
5672 * Here a voltage between the DTR and the RTS line is used. Unfortunately
5673 * the name has changed from CIOCM_DTR to TIOCM_DTR recently.
5677 if (ioctl(parse
->generic
->io
.fd
, TIOCMGET
, (caddr_t
)&sl232
) == -1)
5679 msyslog(LOG_NOTICE
, "PARSE receiver #%d: rawdcf_init_1: WARNING: ioctl(fd, TIOCMGET, [C|T]IOCM_DTR): %m", CLK_UNIT(parse
->peer
));
5684 sl232
= (sl232
& ~TIOCM_RTS
) | TIOCM_DTR
; /* turn on DTR, clear RTS for power supply */
5686 sl232
= (sl232
& ~CIOCM_RTS
) | CIOCM_DTR
; /* turn on DTR, clear RTS for power supply */
5689 if (ioctl(parse
->generic
->io
.fd
, TIOCMSET
, (caddr_t
)&sl232
) == -1)
5691 msyslog(LOG_NOTICE
, "PARSE receiver #%d: rawdcf_init_1: WARNING: ioctl(fd, TIOCMSET, [C|T]IOCM_DTR): %m", CLK_UNIT(parse
->peer
));
5698 struct parseunit
*parse
5701 msyslog(LOG_NOTICE
, "PARSE receiver #%d: rawdcf_init_1: WARNING: OS interface incapable of setting DTR to power DCF modules", CLK_UNIT(parse
->peer
));
5704 #endif /* DTR initialisation type */
5706 /*--------------------------------------------------
5707 * rawdcf_init_2 - set up modem lines for RAWDCF receivers
5708 * CLR DTR line, SET RTS line
5710 #if defined(TIOCMSET) && (defined(TIOCM_RTS) || defined(CIOCM_RTS))
5713 struct parseunit
*parse
5716 /* fixed 2000 for using with Linux by Wolfram Pienkoss <wp@bszh.de> */
5718 * You can use the RS232 to supply the power for a DCF77 receiver.
5719 * Here a voltage between the DTR and the RTS line is used. Unfortunately
5720 * the name has changed from CIOCM_DTR to TIOCM_DTR recently.
5724 if (ioctl(parse
->generic
->io
.fd
, TIOCMGET
, (caddr_t
)&sl232
) == -1)
5726 msyslog(LOG_NOTICE
, "PARSE receiver #%d: rawdcf_init_2: WARNING: ioctl(fd, TIOCMGET, [C|T]IOCM_RTS): %m", CLK_UNIT(parse
->peer
));
5731 sl232
= (sl232
& ~TIOCM_DTR
) | TIOCM_RTS
; /* turn on RTS, clear DTR for power supply */
5733 sl232
= (sl232
& ~CIOCM_DTR
) | CIOCM_RTS
; /* turn on RTS, clear DTR for power supply */
5736 if (ioctl(parse
->generic
->io
.fd
, TIOCMSET
, (caddr_t
)&sl232
) == -1)
5738 msyslog(LOG_NOTICE
, "PARSE receiver #%d: rawdcf_init_2: WARNING: ioctl(fd, TIOCMSET, [C|T]IOCM_RTS): %m", CLK_UNIT(parse
->peer
));
5745 struct parseunit
*parse
5748 msyslog(LOG_NOTICE
, "PARSE receiver #%d: rawdcf_init_2: WARNING: OS interface incapable of setting RTS to power DCF modules", CLK_UNIT(parse
->peer
));
5751 #endif /* DTR initialisation type */
5753 #else /* defined(REFCLOCK) && defined(PARSE) */
5754 int refclock_parse_bs
;
5755 #endif /* defined(REFCLOCK) && defined(PARSE) */
5760 * refclock_parse.c,v
5761 * Revision 4.81 2009/05/01 10:15:29 kardel
5762 * use new refclock_ppsapi interface
5764 * Revision 4.80 2007/08/11 12:06:29 kardel
5765 * update comments wrt/ to PPS
5767 * Revision 4.79 2007/08/11 11:52:23 kardel
5768 * - terminate io bindings before io_closeclock() will close our file descriptor
5770 * Revision 4.78 2006/12/22 20:08:27 kardel
5771 * Bug 746 (RFE): add configuration for Expert mouseCLOCK USB v2.0 as mode 19
5773 * Revision 4.77 2006/08/05 07:44:49 kardel
5774 * support optionally separate PPS devices via /dev/refclockpps-{0..3}
5776 * Revision 4.76 2006/06/22 18:40:47 kardel
5777 * clean up signedness (gcc 4)
5779 * Revision 4.75 2006/06/22 16:58:10 kardel
5780 * Bug #632: call parse_ppsapi() in parse_ctl() when updating
5781 * the PPS offset. Fix sign of offset passed to kernel.
5783 * Revision 4.74 2006/06/18 21:18:37 kardel
5784 * NetBSD Coverity CID 3796: possible NULL deref
5786 * Revision 4.73 2006/05/26 14:23:46 kardel
5787 * cleanup of copyright info
5789 * Revision 4.72 2006/05/26 14:19:43 kardel
5790 * cleanup of ioctl cruft
5792 * Revision 4.71 2006/05/26 14:15:57 kardel
5793 * delay adding refclock to async refclock io after all initializations
5795 * Revision 4.70 2006/05/25 18:20:50 kardel
5797 * terminate parse io engine after de-registering
5798 * from refclock io engine
5800 * Revision 4.69 2006/05/25 17:28:02 kardel
5801 * complete refclock io structure initialization *before* inserting it into the
5802 * refclock input machine (avoids null pointer deref) (bug #619)
5804 * Revision 4.68 2006/05/01 17:02:51 kardel
5805 * copy receiver method also for newlwy created receive buffers
5807 * Revision 4.67 2006/05/01 14:37:29 kardel
5808 * If an input buffer parses into more than one message do insert the
5809 * parsed message in a new input buffer instead of processing it
5810 * directly. This avoids deed complicated processing in signal
5813 * Revision 4.66 2006/03/18 00:45:30 kardel
5814 * coverity fixes found in NetBSD coverity scan
5816 * Revision 4.65 2006/01/26 06:08:33 kardel
5817 * output errno on PPS setup failure
5819 * Revision 4.64 2005/11/09 20:44:47 kardel
5820 * utilize full PPS timestamp resolution from PPS API
5822 * Revision 4.63 2005/10/07 22:10:25 kardel
5823 * bounded buffer implementation
5825 * Revision 4.62.2.2 2005/09/25 10:20:16 kardel
5826 * avoid unexpected buffer overflows due to sprintf("%f") on strange floats:
5827 * replace almost all str* and *printf functions be their buffer bounded
5830 * Revision 4.62.2.1 2005/08/27 16:19:27 kardel
5831 * limit re-set rate of trimble clocks
5833 * Revision 4.62 2005/08/06 17:40:00 kardel
5834 * cleanup size handling wrt/ to buffer boundaries
5836 * Revision 4.61 2005/07/27 21:16:19 kardel
5837 * fix a long (> 11 years) misconfiguration wrt/ Meinberg cflag factory
5838 * default setup. CSTOPB was missing for the 7E2 default data format of
5841 * Revision 4.60 2005/07/17 21:14:44 kardel
5842 * change contents of version string to include the RCS/CVS Id
5844 * Revision 4.59 2005/07/06 06:56:38 kardel
5847 * Revision 4.58 2005/07/04 13:10:40 kardel
5848 * fix bug 455: tripping over NULL pointer on cleanup
5849 * fix shadow storage logic for ppsphaseadjust and trustime wrt/ time2
5850 * fix compiler warnings for some platforms wrt/ printf formatstrings and
5851 * varying structure element sizes
5852 * reorder assignment in binding to avoid tripping over NULL pointers
5854 * Revision 4.57 2005/06/25 09:25:19 kardel
5855 * sort out log output sequence
5857 * Revision 4.56 2005/06/14 21:47:27 kardel
5858 * collect samples only if samples are ok (sync or trusted flywheel)
5859 * propagate pps phase adjustment value to kernel via PPSAPI to help HARDPPS
5860 * en- and dis-able HARDPPS in correlation to receiver sync state
5862 * Revision 4.55 2005/06/02 21:28:31 kardel
5863 * clarify trust logic
5865 * Revision 4.54 2005/06/02 17:06:49 kardel
5866 * change status reporting to use fixed refclock_report()
5868 * Revision 4.53 2005/06/02 16:33:31 kardel
5869 * fix acceptance of clocks unsync clocks right at start
5871 * Revision 4.52 2005/05/26 21:55:06 kardel
5872 * cleanup status reporting
5874 * Revision 4.51 2005/05/26 19:19:14 kardel
5875 * implement fast refclock startup
5877 * Revision 4.50 2005/04/16 20:51:35 kardel
5878 * set pps_enable = 1 when binding a kernel PPS source
5880 * Revision 4.49 2005/04/16 17:29:26 kardel
5881 * add non polling clock type 18 for just listenning to Meinberg clocks
5883 * Revision 4.48 2005/04/16 16:22:27 kardel
5884 * bk sync 20050415 ntp-dev
5886 * Revision 4.47 2004/11/29 10:42:48 kardel
5887 * bk sync ntp-dev 20041129
5889 * Revision 4.46 2004/11/29 10:26:29 kardel
5890 * keep fudgetime2 in sync with trusttime/ppsphaseadjust depending in flag1
5892 * Revision 4.45 2004/11/14 20:53:20 kardel
5893 * clear PPS flags after using them
5895 * Revision 4.44 2004/11/14 15:29:41 kardel
5896 * support PPSAPI, upgrade Copyright to Berkeley style
5898 * Revision 4.43 2001/05/26 22:53:16 kardel
5899 * 20010526 reconcilation
5901 * Revision 4.42 2000/05/14 15:31:51 kardel
5902 * PPSAPI && RAWDCF modemline support
5904 * Revision 4.41 2000/04/09 19:50:45 kardel
5905 * fixed rawdcfdtr_init() -> rawdcf_init_1
5907 * Revision 4.40 2000/04/09 15:27:55 kardel
5908 * modem line fiddle in rawdcf_init_2
5910 * Revision 4.39 2000/03/18 09:16:55 kardel
5911 * PPSAPI integration
5913 * Revision 4.38 2000/03/05 20:25:06 kardel
5916 * Revision 4.37 2000/03/05 20:11:14 kardel
5917 * 4.0.99g reconcilation
5919 * Revision 4.36 1999/11/28 17:18:20 kardel
5920 * disabled burst mode
5922 * Revision 4.35 1999/11/28 09:14:14 kardel
5925 * Revision 4.34 1999/05/14 06:08:05 kardel
5926 * store current_time in a suitable container (u_long)
5928 * Revision 4.33 1999/05/13 21:48:38 kardel
5929 * double the no response timeout interval
5931 * Revision 4.32 1999/05/13 20:09:13 kardel
5932 * complain only about missing polls after a full poll interval
5934 * Revision 4.31 1999/05/13 19:59:32 kardel
5935 * add clock type 16 for RTS set DTR clr in RAWDCF
5937 * Revision 4.30 1999/02/28 20:36:43 kardel
5940 * Revision 4.29 1999/02/28 19:58:23 kardel
5941 * updated copyright information
5943 * Revision 4.28 1999/02/28 19:01:50 kardel
5944 * improved debug out on sent Meinberg messages
5946 * Revision 4.27 1999/02/28 18:05:55 kardel
5947 * no linux/ppsclock.h stuff
5949 * Revision 4.26 1999/02/28 15:27:27 kardel
5950 * wharton clock integration
5952 * Revision 4.25 1999/02/28 14:04:46 kardel
5953 * added missing double quotes to UTC information string
5955 * Revision 4.24 1999/02/28 12:06:50 kardel
5956 * (parse_control): using gmprettydate instead of prettydate()
5957 * (mk_utcinfo): new function for formatting GPS derived UTC information
5958 * (gps16x_message): changed to use mk_utcinfo()
5959 * (trimbletsip_message): changed to use mk_utcinfo()
5960 * ignoring position information in unsynchronized mode
5961 * (parse_start): augument linux support for optional ASYNC_LOW_LATENCY
5963 * Revision 4.23 1999/02/23 19:47:53 kardel
5965 * (stream_receive): fixed formats
5967 * Revision 4.22 1999/02/22 06:21:02 kardel
5968 * use new autoconfig symbols
5970 * Revision 4.21 1999/02/21 12:18:13 kardel
5971 * 4.91f reconcilation
5973 * Revision 4.20 1999/02/21 10:53:36 kardel
5974 * initial Linux PPSkit version
5976 * Revision 4.19 1999/02/07 09:10:45 kardel
5977 * clarify STREAMS mitigation rules in comment
5979 * Revision 4.18 1998/12/20 23:45:34 kardel
5980 * fix types and warnings
5982 * Revision 4.17 1998/11/15 21:24:51 kardel
5983 * cannot access mbg_ routines when CLOCK_MEINBERG
5986 * Revision 4.16 1998/11/15 20:28:17 kardel
5987 * Release 4.0.73e13 reconcilation
5989 * Revision 4.15 1998/08/22 21:56:08 kardel
5990 * fixed IO handling for non-STREAM IO
5992 * Revision 4.14 1998/08/16 19:00:48 kardel
5993 * (gps16x_message): reduced UTC parameter information (dropped A0,A1)
5994 * made uval a local variable (killed one of the last globals)
5995 * (sendetx): added logging of messages when in debug mode
5996 * (trimble_check): added periodic checks to facilitate re-initialization
5997 * (trimbletsip_init): made use of EOL character if in non-kernel operation
5998 * (trimbletsip_message): extended message interpretation
5999 * (getdbl): fixed data conversion
6001 * Revision 4.13 1998/08/09 22:29:13 kardel
6002 * Trimble TSIP support
6004 * Revision 4.12 1998/07/11 10:05:34 kardel
6005 * Release 4.0.73d reconcilation
6007 * Revision 4.11 1998/06/14 21:09:42 kardel
6010 * Revision 4.10 1998/06/13 12:36:45 kardel
6011 * signed/unsigned, name clashes
6013 * Revision 4.9 1998/06/12 15:30:00 kardel
6016 * Revision 4.8 1998/06/12 11:19:42 kardel
6017 * added direct input processing routine for refclocks in
6018 * order to avaiod that single character io gobbles up all
6019 * receive buffers and drops input data. (Problem started
6020 * with fast machines so a character a buffer was possible
6021 * one of the few cases where faster machines break existing
6022 * allocation algorithms)
6024 * Revision 4.7 1998/06/06 18:35:20 kardel
6025 * (parse_start): added BURST mode initialisation
6027 * Revision 4.6 1998/05/27 06:12:46 kardel
6028 * RAWDCF_BASEDELAY default added
6029 * old comment removed
6032 * Revision 4.5 1998/05/25 22:05:09 kardel
6033 * RAWDCF_SETDTR option removed
6034 * clock type 14 attempts to set DTR for
6035 * power supply of RAWDCF receivers
6037 * Revision 4.4 1998/05/24 16:20:47 kardel
6038 * updated comments referencing Meinberg clocks
6039 * added RAWDCF clock with DTR set option as type 14
6041 * Revision 4.3 1998/05/24 10:48:33 kardel
6042 * calibrated CONRAD RAWDCF default fudge factor
6044 * Revision 4.2 1998/05/24 09:59:35 kardel
6045 * corrected version information (ntpq support)
6047 * Revision 4.1 1998/05/24 09:52:31 kardel
6048 * use fixed format only (new IO model)
6049 * output debug to stdout instead of msyslog()
6050 * don't include >"< in ASCII output in order not to confuse
6053 * Revision 4.0 1998/04/10 19:52:11 kardel
6054 * Start 4.0 release version numbering
6056 * Revision 1.2 1998/04/10 19:28:04 kardel
6057 * initial NTP VERSION 4 integration of PARSE with GPS166 binary support
6058 * derived from 3.105.1.2 from V3 tree
6060 * Revision information 3.1 - 3.105 from log deleted 1998/04/10 kardel