2 * /src/NTP/REPOSITORY/ntp4-dev/ntpd/refclock_parse.c,v 4.80 2007/08/11 12:06:29 kardel Exp
4 * refclock_parse.c,v 4.80 2007/08/11 12:06:29 kardel Exp
6 * generic reference clock driver for several DCF/GPS/MSF/... receivers
9 * On systems that support PPSAPI (RFC2783) PPSAPI is the
10 * preferred interface.
12 * Optionally make use of a STREAMS module for input processing where
13 * available and configured. This STREAMS module reduces the time
14 * stamp latency for serial and PPS events.
15 * Currently the STREAMS module is only available for Suns running
16 * SunOS 4.x and SunOS5.x.
18 * Copyright (c) 1995-2007 by Frank Kardel <kardel <AT> ntp.org>
19 * Copyright (c) 1989-1994 by Frank Kardel, Friedrich-Alexander Universität Erlangen-Nürnberg, Germany
21 * Redistribution and use in source and binary forms, with or without
22 * modification, are permitted provided that the following conditions
24 * 1. Redistributions of source code must retain the above copyright
25 * notice, this list of conditions and the following disclaimer.
26 * 2. Redistributions in binary form must reproduce the above copyright
27 * notice, this list of conditions and the following disclaimer in the
28 * documentation and/or other materials provided with the distribution.
29 * 3. Neither the name of the author nor the names of its contributors
30 * may be used to endorse or promote products derived from this software
31 * without specific prior written permission.
33 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
34 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
35 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
36 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
37 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
38 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
39 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
40 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
41 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
42 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
51 #if defined(REFCLOCK) && defined(CLOCK_PARSE)
54 * This driver currently provides the support for
55 * - Meinberg receiver DCF77 PZF 535 (TCXO version) (DCF)
56 * - Meinberg receiver DCF77 PZF 535 (OCXO version) (DCF)
57 * - Meinberg receiver DCF77 PZF 509 (DCF)
58 * - Meinberg receiver DCF77 AM receivers (e.g. C51) (DCF)
61 * - Schmid clock (DCF)
62 * - Conrad DCF77 receiver module (DCF)
63 * - FAU DCF77 NTP receiver (TimeBrick) (DCF)
64 * - WHARTON 400A Series clock (DCF)
66 * - Meinberg GPS166/GPS167 (GPS)
67 * - Trimble (TSIP and TAIP protocol) (GPS)
69 * - RCC8000 MSF Receiver (MSF)
70 * - VARITEXT clock (MSF)
74 * Meinberg receivers are usually connected via a
75 * 9600 baud serial line
77 * The Meinberg GPS receivers also have a special NTP time stamp
78 * format. The firmware release is Uni-Erlangen.
80 * Meinberg generic receiver setup:
81 * output time code every second
84 * Meinberg GPS16x setup:
85 * output time code every second
88 * This software supports the standard data formats used
89 * in Meinberg receivers.
91 * Special software versions are only sensible for the
92 * GPS 16x family of receivers.
94 * Meinberg can be reached via: http://www.meinberg.de/
98 #include "ntp_refclock.h"
99 #include "ntp_unixtime.h" /* includes <sys/time.h> */
100 #include "ntp_control.h"
101 #include "ntp_string.h"
105 #ifndef TM_IN_SYS_TIME
113 #if !defined(STREAM) && !defined(HAVE_SYSV_TTYS) && !defined(HAVE_BSD_TTYS) && !defined(HAVE_TERMIOS)
114 # include "Bletch: Define one of {STREAM,HAVE_SYSV_TTYS,HAVE_TERMIOS}"
118 # include <sys/stream.h>
119 # include <sys/stropts.h>
123 # define TTY_GETATTR(_FD_, _ARG_) tcgetattr((_FD_), (_ARG_))
124 # define TTY_SETATTR(_FD_, _ARG_) tcsetattr((_FD_), TCSANOW, (_ARG_))
125 # undef HAVE_SYSV_TTYS
128 #ifdef HAVE_SYSV_TTYS
129 # define TTY_GETATTR(_FD_, _ARG_) ioctl((_FD_), TCGETA, (_ARG_))
130 # define TTY_SETATTR(_FD_, _ARG_) ioctl((_FD_), TCSETAW, (_ARG_))
134 /* #error CURRENTLY NO BSD TTY SUPPORT */
135 # include "Bletch: BSD TTY not currently supported"
138 #ifdef HAVE_SYS_IOCTL_H
139 # include <sys/ioctl.h>
143 # include "ppsapi_timepps.h"
147 # ifdef HAVE_SYS_PPSCLOCK_H
148 # include <sys/ppsclock.h>
150 # ifdef HAVE_TIO_SERIAL_STUFF
151 # include <linux/serial.h>
155 #define BUFFER_SIZE(_BUF, _PTR) ((_BUF) + sizeof(_BUF) - (_PTR))
156 #define BUFFER_SIZES(_BUF, _PTR, _SZ) ((_BUF) + (_SZ) - (_PTR))
159 * document type of PPS interfacing - copy of ifdef mechanism in local_input()
164 #define PPS_METHOD "PPS API"
166 #ifdef TIOCDCDTIMESTAMP
167 #define PPS_METHOD "TIOCDCDTIMESTAMP"
168 #else /* TIOCDCDTIMESTAMP */
169 #if defined(HAVE_STRUCT_PPSCLOCKEV) && (defined(HAVE_CIOGETEV) || defined(HAVE_TIOCGPPSEV))
171 #define PPS_METHOD "CIOGETEV"
173 #ifdef HAVE_TIOCGPPSEV
174 #define PPS_METHOD "TIOCGPPSEV"
177 #endif /* TIOCDCDTIMESTAMP */
178 #endif /* HAVE_PPSAPI */
181 #include "ntp_stdlib.h"
184 #include "mbg_gps166.h"
188 #include "ieee754io.h"
189 #include "recvbuff.h"
191 static char rcsid[] = "refclock_parse.c,v 4.80 2007/08/11 12:06:29 kardel Exp";
193 /**===========================================================================
194 ** external interface to ntp mechanism
197 static int parse_start P((int, struct peer *));
198 static void parse_shutdown P((int, struct peer *));
199 static void parse_poll P((int, struct peer *));
200 static void parse_control P((int, struct refclockstat *, struct refclockstat *, struct peer *));
202 struct refclock refclock_parse = {
215 #define MAXUNITS 4 /* maximum number of "PARSE" units permitted */
216 #define PARSEDEVICE "/dev/refclock-%d" /* device to open %d is unit number */
217 #define PARSEPPSDEVICE "/dev/refclockpps-%d" /* optional pps device to open %d is unit number */
220 #define ABS(_X_) (((_X_) < 0) ? -(_X_) : (_X_))
222 #define PARSE_HARDPPS_DISABLE 0
223 #define PARSE_HARDPPS_ENABLE 1
225 /**===========================================================================
226 ** function vector for dynamically binding io handling mechanism
229 struct parseunit; /* to keep inquiring minds happy */
233 const char *bd_description; /* name of type of binding */
234 int (*bd_init) P((struct parseunit *)); /* initialize */
235 void (*bd_end) P((struct parseunit *)); /* end */
236 int (*bd_setcs) P((struct parseunit *, parsectl_t *)); /* set character size */
237 int (*bd_disable) P((struct parseunit *)); /* disable */
238 int (*bd_enable) P((struct parseunit *)); /* enable */
239 int (*bd_getfmt) P((struct parseunit *, parsectl_t *)); /* get format */
240 int (*bd_setfmt) P((struct parseunit *, parsectl_t *)); /* setfmt */
241 int (*bd_timecode) P((struct parseunit *, parsectl_t *)); /* get time code */
242 void (*bd_receive) P((struct recvbuf *)); /* receive operation */
243 int (*bd_io_input) P((struct recvbuf *)); /* input operation */
246 #define PARSE_END(_X_) (*(_X_)->binding->bd_end)(_X_)
247 #define PARSE_SETCS(_X_, _CS_) (*(_X_)->binding->bd_setcs)(_X_, _CS_)
248 #define PARSE_ENABLE(_X_) (*(_X_)->binding->bd_enable)(_X_)
249 #define PARSE_DISABLE(_X_) (*(_X_)->binding->bd_disable)(_X_)
250 #define PARSE_GETFMT(_X_, _DCT_) (*(_X_)->binding->bd_getfmt)(_X_, _DCT_)
251 #define PARSE_SETFMT(_X_, _DCT_) (*(_X_)->binding->bd_setfmt)(_X_, _DCT_)
252 #define PARSE_GETTIMECODE(_X_, _DCT_) (*(_X_)->binding->bd_timecode)(_X_, _DCT_)
257 #define PARSE_F_PPSPPS 0x0001 /* use loopfilter PPS code (CIOGETEV) */
258 #define PARSE_F_PPSONSECOND 0x0002 /* PPS pulses are on second */
261 /**===========================================================================
262 ** error message regression handling
264 ** there are quite a few errors that can occur in rapid succession such as
265 ** noisy input data or no data at all. in order to reduce the amount of
266 ** syslog messages in such case, we are using a backoff algorithm. We limit
267 ** the number of error messages of a certain class to 1 per time unit. if a
268 ** configurable number of messages is displayed that way, we move on to the
269 ** next time unit / count for that class. a count of messages that have been
270 ** suppressed is held and displayed whenever a corresponding message is
271 ** displayed. the time units for a message class will also be displayed.
272 ** whenever an error condition clears we reset the error message state,
273 ** thus we would still generate much output on pathological conditions
274 ** where the system oscillates between OK and NOT OK states. coping
275 ** with that condition is currently considered too complicated.
278 #define ERR_ALL (unsigned)~0 /* "all" errors */
279 #define ERR_BADDATA (unsigned)0 /* unusable input data/conversion errors */
280 #define ERR_NODATA (unsigned)1 /* no input data */
281 #define ERR_BADIO (unsigned)2 /* read/write/select errors */
282 #define ERR_BADSTATUS (unsigned)3 /* unsync states */
283 #define ERR_BADEVENT (unsigned)4 /* non nominal events */
284 #define ERR_INTERNAL (unsigned)5 /* internal error */
285 #define ERR_CNT (unsigned)(ERR_INTERNAL+1)
287 #define ERR(_X_) if (list_err(parse, (_X_)))
289 struct errorregression
291 u_long err_count; /* number of repititions per class */
292 u_long err_delay; /* minimum delay between messages */
295 static struct errorregression
296 err_baddata[] = /* error messages for bad input data */
298 { 1, 0 }, /* output first message immediately */
299 { 5, 60 }, /* output next five messages in 60 second intervals */
300 { 3, 3600 }, /* output next 3 messages in hour intervals */
301 { 0, 12*3600 } /* repeat messages only every 12 hours */
304 static struct errorregression
305 err_nodata[] = /* error messages for missing input data */
307 { 1, 0 }, /* output first message immediately */
308 { 5, 60 }, /* output next five messages in 60 second intervals */
309 { 3, 3600 }, /* output next 3 messages in hour intervals */
310 { 0, 12*3600 } /* repeat messages only every 12 hours */
313 static struct errorregression
314 err_badstatus[] = /* unsynchronized state messages */
316 { 1, 0 }, /* output first message immediately */
317 { 5, 60 }, /* output next five messages in 60 second intervals */
318 { 3, 3600 }, /* output next 3 messages in hour intervals */
319 { 0, 12*3600 } /* repeat messages only every 12 hours */
322 static struct errorregression
323 err_badio[] = /* io failures (bad reads, selects, ...) */
325 { 1, 0 }, /* output first message immediately */
326 { 5, 60 }, /* output next five messages in 60 second intervals */
327 { 5, 3600 }, /* output next 3 messages in hour intervals */
328 { 0, 12*3600 } /* repeat messages only every 12 hours */
331 static struct errorregression
332 err_badevent[] = /* non nominal events */
334 { 20, 0 }, /* output first message immediately */
335 { 6, 60 }, /* output next five messages in 60 second intervals */
336 { 5, 3600 }, /* output next 3 messages in hour intervals */
337 { 0, 12*3600 } /* repeat messages only every 12 hours */
340 static struct errorregression
341 err_internal[] = /* really bad things - basically coding/OS errors */
343 { 0, 0 }, /* output all messages immediately */
346 static struct errorregression *
359 u_long err_started; /* begin time (ntp) of error condition */
360 u_long err_last; /* last time (ntp) error occurred */
361 u_long err_cnt; /* number of error repititions */
362 u_long err_suppressed; /* number of suppressed messages */
363 struct errorregression *err_stage; /* current error stage */
366 /**===========================================================================
367 ** refclock instance data
375 struct peer *peer; /* backlink to peer structure - refclock inactive if 0 */
376 struct refclockproc *generic; /* backlink to refclockproc structure */
381 bind_t *binding; /* io handling binding */
386 parse_t parseio; /* io handling structure (user level parsing) */
389 * type specific parameters
391 struct parse_clockinfo *parse_type; /* link to clock description */
394 * clock state handling/reporting
396 u_char flags; /* flags (leap_control) */
397 u_long lastchange; /* time (ntp) when last state change accured */
398 u_long statetime[CEVNT_MAX+1]; /* accumulated time of clock states */
399 u_long pollneeddata; /* current_time(!=0) for receive sample expected in PPS mode */
400 u_short lastformat; /* last format used */
401 u_long lastsync; /* time (ntp) when clock was last seen fully synchronized */
402 u_long maxunsync; /* max time in seconds a receiver is trusted after loosing synchronisation */
403 double ppsphaseadjust; /* phase adjustment of PPS time stamp */
404 u_long lastmissed; /* time (ntp) when poll didn't get data (powerup heuristic) */
405 u_long ppsserial; /* magic cookie for ppsclock serials (avoids stale ppsclock data) */
406 int ppsfd; /* fd to ise for PPS io */
408 pps_handle_t ppshandle; /* store PPSAPI handle */
409 pps_params_t ppsparams; /* current PPS parameters */
410 int hardppsstate; /* current hard pps state */
412 parsetime_t timedata; /* last (parse module) data */
413 void *localdata; /* optional local, receiver-specific data */
414 unsigned long localstate; /* private local state */
415 struct errorinfo errors[ERR_CNT]; /* error state table for suppressing excessive error messages */
416 struct ctl_var *kv; /* additional pseudo variables */
417 u_long laststatistic; /* time when staticstics where output */
421 /**===========================================================================
422 ** Clockinfo section all parameter for specific clock types
423 ** includes NTP parameters, TTY parameters and IO handling parameters
426 static void poll_dpoll P((struct parseunit *));
427 static void poll_poll P((struct peer *));
428 static int poll_init P((struct parseunit *));
430 typedef struct poll_info
432 u_long rate; /* poll rate - once every "rate" seconds - 0 off */
433 const char *string; /* string to send for polling */
434 u_long count; /* number of characters in string */
437 #define NO_CL_FLAGS 0
444 #define NO_PPSDELAY 0
446 #define DCF_ID "DCF" /* generic DCF */
447 #define DCF_A_ID "DCFa" /* AM demodulation */
448 #define DCF_P_ID "DCFp" /* psuedo random phase shift */
449 #define GPS_ID "GPS" /* GPS receiver */
451 #define NOCLOCK_ROOTDELAY 0.0
452 #define NOCLOCK_BASEDELAY 0.0
453 #define NOCLOCK_DESCRIPTION 0
454 #define NOCLOCK_MAXUNSYNC 0
455 #define NOCLOCK_CFLAG 0
456 #define NOCLOCK_IFLAG 0
457 #define NOCLOCK_OFLAG 0
458 #define NOCLOCK_LFLAG 0
459 #define NOCLOCK_ID "TILT"
460 #define NOCLOCK_POLL NO_POLL
461 #define NOCLOCK_INIT NO_INIT
462 #define NOCLOCK_END NO_END
463 #define NOCLOCK_DATA NO_LCLDATA
464 #define NOCLOCK_FORMAT ""
465 #define NOCLOCK_TYPE CTL_SST_TS_UNSPEC
466 #define NOCLOCK_SAMPLES 0
467 #define NOCLOCK_KEEP 0
469 #define DCF_TYPE CTL_SST_TS_LF
470 #define GPS_TYPE CTL_SST_TS_UHF
473 * receiver specific constants
475 #define MBG_SPEED (B9600)
476 #define MBG_CFLAG (CS7|PARENB|CREAD|CLOCAL|HUPCL|CSTOPB)
477 #define MBG_IFLAG (IGNBRK|IGNPAR|ISTRIP)
480 #define MBG_FLAGS PARSE_F_PPSONSECOND
483 * Meinberg DCF77 receivers
485 #define DCFUA31_ROOTDELAY 0.0 /* 0 */
486 #define DCFUA31_BASEDELAY 0.010 /* 10.7421875ms: 10 ms (+/- 3 ms) */
487 #define DCFUA31_DESCRIPTION "Meinberg DCF77 C51 or compatible"
488 #define DCFUA31_MAXUNSYNC 60*30 /* only trust clock for 1/2 hour */
489 #define DCFUA31_SPEED MBG_SPEED
490 #define DCFUA31_CFLAG MBG_CFLAG
491 #define DCFUA31_IFLAG MBG_IFLAG
492 #define DCFUA31_OFLAG MBG_OFLAG
493 #define DCFUA31_LFLAG MBG_LFLAG
494 #define DCFUA31_SAMPLES 5
495 #define DCFUA31_KEEP 3
496 #define DCFUA31_FORMAT "Meinberg Standard"
499 * Meinberg DCF PZF535/TCXO (FM/PZF) receiver
501 #define DCFPZF535_ROOTDELAY 0.0
502 #define DCFPZF535_BASEDELAY 0.001968 /* 1.968ms +- 104us (oscilloscope) - relative to start (end of STX) */
503 #define DCFPZF535_DESCRIPTION "Meinberg DCF PZF 535/509 / TCXO"
504 #define DCFPZF535_MAXUNSYNC 60*60*12 /* only trust clock for 12 hours
505 * @ 5e-8df/f we have accumulated
506 * at most 2.16 ms (thus we move to
507 * NTP synchronisation */
508 #define DCFPZF535_SPEED MBG_SPEED
509 #define DCFPZF535_CFLAG MBG_CFLAG
510 #define DCFPZF535_IFLAG MBG_IFLAG
511 #define DCFPZF535_OFLAG MBG_OFLAG
512 #define DCFPZF535_LFLAG MBG_LFLAG
513 #define DCFPZF535_SAMPLES 5
514 #define DCFPZF535_KEEP 3
515 #define DCFPZF535_FORMAT "Meinberg Standard"
518 * Meinberg DCF PZF535/OCXO receiver
520 #define DCFPZF535OCXO_ROOTDELAY 0.0
521 #define DCFPZF535OCXO_BASEDELAY 0.001968 /* 1.968ms +- 104us (oscilloscope) - relative to start (end of STX) */
522 #define DCFPZF535OCXO_DESCRIPTION "Meinberg DCF PZF 535/509 / OCXO"
523 #define DCFPZF535OCXO_MAXUNSYNC 60*60*96 /* only trust clock for 4 days
524 * @ 5e-9df/f we have accumulated
525 * at most an error of 1.73 ms
526 * (thus we move to NTP synchronisation) */
527 #define DCFPZF535OCXO_SPEED MBG_SPEED
528 #define DCFPZF535OCXO_CFLAG MBG_CFLAG
529 #define DCFPZF535OCXO_IFLAG MBG_IFLAG
530 #define DCFPZF535OCXO_OFLAG MBG_OFLAG
531 #define DCFPZF535OCXO_LFLAG MBG_LFLAG
532 #define DCFPZF535OCXO_SAMPLES 5
533 #define DCFPZF535OCXO_KEEP 3
534 #define DCFPZF535OCXO_FORMAT "Meinberg Standard"
537 * Meinberg GPS16X receiver
539 static void gps16x_message P((struct parseunit *, parsetime_t *));
540 static int gps16x_poll_init P((struct parseunit *));
542 #define GPS16X_ROOTDELAY 0.0 /* nothing here */
543 #define GPS16X_BASEDELAY 0.001968 /* XXX to be fixed ! 1.968ms +- 104us (oscilloscope) - relative to start (end of STX) */
544 #define GPS16X_DESCRIPTION "Meinberg GPS16x receiver"
545 #define GPS16X_MAXUNSYNC 60*60*96 /* only trust clock for 4 days
546 * @ 5e-9df/f we have accumulated
547 * at most an error of 1.73 ms
548 * (thus we move to NTP synchronisation) */
549 #define GPS16X_SPEED B19200
550 #define GPS16X_CFLAG (CS8|CREAD|CLOCAL|HUPCL)
551 #define GPS16X_IFLAG (IGNBRK|IGNPAR)
552 #define GPS16X_OFLAG MBG_OFLAG
553 #define GPS16X_LFLAG MBG_LFLAG
554 #define GPS16X_POLLRATE 6
555 #define GPS16X_POLLCMD ""
556 #define GPS16X_CMDSIZE 0
558 static poll_info_t gps16x_pollinfo = { GPS16X_POLLRATE, GPS16X_POLLCMD, GPS16X_CMDSIZE };
560 #define GPS16X_INIT gps16x_poll_init
561 #define GPS16X_POLL 0
563 #define GPS16X_DATA ((void *)(&gps16x_pollinfo))
564 #define GPS16X_MESSAGE gps16x_message
565 #define GPS16X_ID GPS_ID
566 #define GPS16X_FORMAT "Meinberg GPS Extended"
567 #define GPS16X_SAMPLES 5
568 #define GPS16X_KEEP 3
571 * ELV DCF7000 Wallclock-Receiver/Switching Clock (Kit)
573 * This is really not the hottest clock - but before you have nothing ...
575 #define DCF7000_ROOTDELAY 0.0 /* 0 */
576 #define DCF7000_BASEDELAY 0.405 /* slow blow */
577 #define DCF7000_DESCRIPTION "ELV DCF7000"
578 #define DCF7000_MAXUNSYNC (60*5) /* sorry - but it just was not build as a clock */
579 #define DCF7000_SPEED (B9600)
580 #define DCF7000_CFLAG (CS8|CREAD|PARENB|PARODD|CLOCAL|HUPCL)
581 #define DCF7000_IFLAG (IGNBRK)
582 #define DCF7000_OFLAG 0
583 #define DCF7000_LFLAG 0
584 #define DCF7000_SAMPLES 5
585 #define DCF7000_KEEP 3
586 #define DCF7000_FORMAT "ELV DCF7000"
589 * Schmid DCF Receiver Kit
591 * When the WSDCF clock is operating optimally we want the primary clock
592 * distance to come out at 300 ms. Thus, peer.distance in the WSDCF peer
593 * structure is set to 290 ms and we compute delays which are at least
594 * 10 ms long. The following are 290 ms and 10 ms expressed in u_fp format
596 #define WS_POLLRATE 1 /* every second - watch interdependency with poll routine */
597 #define WS_POLLCMD "\163"
600 static poll_info_t wsdcf_pollinfo = { WS_POLLRATE, WS_POLLCMD, WS_CMDSIZE };
602 #define WSDCF_INIT poll_init
603 #define WSDCF_POLL poll_dpoll
605 #define WSDCF_DATA ((void *)(&wsdcf_pollinfo))
606 #define WSDCF_ROOTDELAY 0.0 /* 0 */
607 #define WSDCF_BASEDELAY 0.010 /* ~ 10ms */
608 #define WSDCF_DESCRIPTION "WS/DCF Receiver"
609 #define WSDCF_FORMAT "Schmid"
610 #define WSDCF_MAXUNSYNC (60*60) /* assume this beast hold at 1 h better than 2 ms XXX-must verify */
611 #define WSDCF_SPEED (B1200)
612 #define WSDCF_CFLAG (CS8|CREAD|CLOCAL)
613 #define WSDCF_IFLAG 0
614 #define WSDCF_OFLAG 0
615 #define WSDCF_LFLAG 0
616 #define WSDCF_SAMPLES 5
620 * RAW DCF77 - input of DCF marks via RS232 - many variants
622 #define RAWDCF_FLAGS 0
623 #define RAWDCF_ROOTDELAY 0.0 /* 0 */
624 #define RAWDCF_BASEDELAY 0.258
625 #define RAWDCF_FORMAT "RAW DCF77 Timecode"
626 #define RAWDCF_MAXUNSYNC (0) /* sorry - its a true receiver - no signal - no time */
627 #define RAWDCF_SPEED (B50)
628 #ifdef NO_PARENB_IGNPAR /* Was: defined(SYS_IRIX4) || defined(SYS_IRIX5) */
629 /* somehow doesn't grok PARENB & IGNPAR (mj) */
630 # define RAWDCF_CFLAG (CS8|CREAD|CLOCAL)
632 # define RAWDCF_CFLAG (CS8|CREAD|CLOCAL|PARENB)
634 #ifdef RAWDCF_NO_IGNPAR /* Was: defined(SYS_LINUX) && defined(CLOCK_RAWDCF) */
635 # define RAWDCF_IFLAG 0
637 # define RAWDCF_IFLAG (IGNPAR)
639 #define RAWDCF_OFLAG 0
640 #define RAWDCF_LFLAG 0
641 #define RAWDCF_SAMPLES 20
642 #define RAWDCF_KEEP 12
643 #define RAWDCF_INIT 0
651 * simplest (cheapest) DCF clock - e. g. DCF77 receiver by Conrad
652 * (~40DM - roughly $30 ) followed by a level converter for RS232
654 #define CONRAD_BASEDELAY 0.292 /* Conrad receiver @ 50 Baud on a Sun */
655 #define CONRAD_DESCRIPTION "RAW DCF77 CODE (Conrad DCF77 receiver module)"
657 /* Gude Analog- und Digitalsystem GmbH 'Expert mouseCLOCK USB v2.0' */
658 #define GUDE_EMC_USB_V20_SPEED (B4800)
659 #define GUDE_EMC_USB_V20_BASEDELAY 0.425 /* USB serial<->USB converter FTDI232R */
660 #define GUDE_EMC_USB_V20_DESCRIPTION "RAW DCF77 CODE (Expert mouseCLOCK USB v2.0)"
665 #define TIMEBRICK_BASEDELAY 0.210 /* TimeBrick @ 50 Baud on a Sun */
666 #define TIMEBRICK_DESCRIPTION "RAW DCF77 CODE (TimeBrick)"
669 * IGEL:clock receiver
671 #define IGELCLOCK_BASEDELAY 0.258 /* IGEL:clock receiver */
672 #define IGELCLOCK_DESCRIPTION "RAW DCF77 CODE (IGEL:clock)"
673 #define IGELCLOCK_SPEED (B1200)
674 #define IGELCLOCK_CFLAG (CS8|CREAD|HUPCL|CLOCAL)
677 * RAWDCF receivers that need to be powered from DTR
678 * (like Expert mouse clock)
680 static int rawdcf_init_1 P((struct parseunit *));
681 #define RAWDCFDTRSET_DESCRIPTION "RAW DCF77 CODE (DTR SET/RTS CLR)"
682 #define RAWDCFDTRSET_INIT rawdcf_init_1
685 * RAWDCF receivers that need to be powered from
686 * DTR CLR and RTS SET
688 static int rawdcf_init_2 P((struct parseunit *));
689 #define RAWDCFDTRCLRRTSSET_DESCRIPTION "RAW DCF77 CODE (DTR CLR/RTS SET)"
690 #define RAWDCFDTRCLRRTSSET_INIT rawdcf_init_2
693 * Trimble GPS receivers (TAIP and TSIP protocols)
695 #ifndef TRIM_POLLRATE
696 #define TRIM_POLLRATE 0 /* only true direct polling */
699 #define TRIM_TAIPPOLLCMD ">SRM;FR_FLAG=F;EC_FLAG=F<>QTM<"
700 #define TRIM_TAIPCMDSIZE (sizeof(TRIM_TAIPPOLLCMD)-1)
702 static poll_info_t trimbletaip_pollinfo = { TRIM_POLLRATE, TRIM_TAIPPOLLCMD, TRIM_TAIPCMDSIZE };
703 static int trimbletaip_init P((struct parseunit *));
704 static void trimbletaip_event P((struct parseunit *, int));
706 /* query time & UTC correction data */
707 static char tsipquery[] = { DLE, 0x21, DLE, ETX, DLE, 0x2F, DLE, ETX };
709 static poll_info_t trimbletsip_pollinfo = { TRIM_POLLRATE, tsipquery, sizeof(tsipquery) };
710 static int trimbletsip_init P((struct parseunit *));
711 static void trimbletsip_end P((struct parseunit *));
712 static void trimbletsip_message P((struct parseunit *, parsetime_t *));
713 static void trimbletsip_event P((struct parseunit *, int));
715 #define TRIMBLETSIP_IDLE_TIME (300) /* 5 minutes silence at most */
716 #define TRIMBLE_RESET_HOLDOFF TRIMBLETSIP_IDLE_TIME
718 #define TRIMBLETAIP_SPEED (B4800)
719 #define TRIMBLETAIP_CFLAG (CS8|CREAD|CLOCAL)
720 #define TRIMBLETAIP_IFLAG (BRKINT|IGNPAR|ISTRIP|ICRNL|IXON)
721 #define TRIMBLETAIP_OFLAG (OPOST|ONLCR)
722 #define TRIMBLETAIP_LFLAG (0)
724 #define TRIMBLETSIP_SPEED (B9600)
725 #define TRIMBLETSIP_CFLAG (CS8|CLOCAL|CREAD|PARENB|PARODD)
726 #define TRIMBLETSIP_IFLAG (IGNBRK)
727 #define TRIMBLETSIP_OFLAG (0)
728 #define TRIMBLETSIP_LFLAG (ICANON)
730 #define TRIMBLETSIP_SAMPLES 5
731 #define TRIMBLETSIP_KEEP 3
732 #define TRIMBLETAIP_SAMPLES 5
733 #define TRIMBLETAIP_KEEP 3
735 #define TRIMBLETAIP_FLAGS (PARSE_F_PPSONSECOND)
736 #define TRIMBLETSIP_FLAGS (TRIMBLETAIP_FLAGS)
738 #define TRIMBLETAIP_POLL poll_dpoll
739 #define TRIMBLETSIP_POLL poll_dpoll
741 #define TRIMBLETAIP_INIT trimbletaip_init
742 #define TRIMBLETSIP_INIT trimbletsip_init
744 #define TRIMBLETAIP_EVENT trimbletaip_event
746 #define TRIMBLETSIP_EVENT trimbletsip_event
747 #define TRIMBLETSIP_MESSAGE trimbletsip_message
749 #define TRIMBLETAIP_END 0
750 #define TRIMBLETSIP_END trimbletsip_end
752 #define TRIMBLETAIP_DATA ((void *)(&trimbletaip_pollinfo))
753 #define TRIMBLETSIP_DATA ((void *)(&trimbletsip_pollinfo))
755 #define TRIMBLETAIP_ID GPS_ID
756 #define TRIMBLETSIP_ID GPS_ID
758 #define TRIMBLETAIP_FORMAT "Trimble TAIP"
759 #define TRIMBLETSIP_FORMAT "Trimble TSIP"
761 #define TRIMBLETAIP_ROOTDELAY 0x0
762 #define TRIMBLETSIP_ROOTDELAY 0x0
764 #define TRIMBLETAIP_BASEDELAY 0.0
765 #define TRIMBLETSIP_BASEDELAY 0.020 /* GPS time message latency */
767 #define TRIMBLETAIP_DESCRIPTION "Trimble GPS (TAIP) receiver"
768 #define TRIMBLETSIP_DESCRIPTION "Trimble GPS (TSIP) receiver"
770 #define TRIMBLETAIP_MAXUNSYNC 0
771 #define TRIMBLETSIP_MAXUNSYNC 0
773 #define TRIMBLETAIP_EOL '<'
776 * RadioCode Clocks RCC 800 receiver
778 #define RCC_POLLRATE 0 /* only true direct polling */
779 #define RCC_POLLCMD "\r"
780 #define RCC_CMDSIZE 1
782 static poll_info_t rcc8000_pollinfo = { RCC_POLLRATE, RCC_POLLCMD, RCC_CMDSIZE };
783 #define RCC8000_FLAGS 0
784 #define RCC8000_POLL poll_dpoll
785 #define RCC8000_INIT poll_init
786 #define RCC8000_END 0
787 #define RCC8000_DATA ((void *)(&rcc8000_pollinfo))
788 #define RCC8000_ROOTDELAY 0.0
789 #define RCC8000_BASEDELAY 0.0
790 #define RCC8000_ID "MSF"
791 #define RCC8000_DESCRIPTION "RCC 8000 MSF Receiver"
792 #define RCC8000_FORMAT "Radiocode RCC8000"
793 #define RCC8000_MAXUNSYNC (60*60) /* should be ok for an hour */
794 #define RCC8000_SPEED (B2400)
795 #define RCC8000_CFLAG (CS8|CREAD|CLOCAL)
796 #define RCC8000_IFLAG (IGNBRK|IGNPAR)
797 #define RCC8000_OFLAG 0
798 #define RCC8000_LFLAG 0
799 #define RCC8000_SAMPLES 5
800 #define RCC8000_KEEP 3
803 * Hopf Radio clock 6021 Format
806 #define HOPF6021_ROOTDELAY 0.0
807 #define HOPF6021_BASEDELAY 0.0
808 #define HOPF6021_DESCRIPTION "HOPF 6021"
809 #define HOPF6021_FORMAT "hopf Funkuhr 6021"
810 #define HOPF6021_MAXUNSYNC (60*60) /* should be ok for an hour */
811 #define HOPF6021_SPEED (B9600)
812 #define HOPF6021_CFLAG (CS8|CREAD|CLOCAL)
813 #define HOPF6021_IFLAG (IGNBRK|ISTRIP)
814 #define HOPF6021_OFLAG 0
815 #define HOPF6021_LFLAG 0
816 #define HOPF6021_FLAGS 0
817 #define HOPF6021_SAMPLES 5
818 #define HOPF6021_KEEP 3
821 * Diem's Computime Radio Clock Receiver
823 #define COMPUTIME_FLAGS 0
824 #define COMPUTIME_ROOTDELAY 0.0
825 #define COMPUTIME_BASEDELAY 0.0
826 #define COMPUTIME_ID DCF_ID
827 #define COMPUTIME_DESCRIPTION "Diem's Computime receiver"
828 #define COMPUTIME_FORMAT "Diem's Computime Radio Clock"
829 #define COMPUTIME_TYPE DCF_TYPE
830 #define COMPUTIME_MAXUNSYNC (60*60) /* only trust clock for 1 hour */
831 #define COMPUTIME_SPEED (B9600)
832 #define COMPUTIME_CFLAG (CSTOPB|CS7|CREAD|CLOCAL)
833 #define COMPUTIME_IFLAG (IGNBRK|IGNPAR|ISTRIP)
834 #define COMPUTIME_OFLAG 0
835 #define COMPUTIME_LFLAG 0
836 #define COMPUTIME_SAMPLES 5
837 #define COMPUTIME_KEEP 3
840 * Varitext Radio Clock Receiver
842 #define VARITEXT_FLAGS 0
843 #define VARITEXT_ROOTDELAY 0.0
844 #define VARITEXT_BASEDELAY 0.0
845 #define VARITEXT_ID "MSF"
846 #define VARITEXT_DESCRIPTION "Varitext receiver"
847 #define VARITEXT_FORMAT "Varitext Radio Clock"
848 #define VARITEXT_TYPE DCF_TYPE
849 #define VARITEXT_MAXUNSYNC (60*60) /* only trust clock for 1 hour */
850 #define VARITEXT_SPEED (B9600)
851 #define VARITEXT_CFLAG (CS7|CREAD|CLOCAL|PARENB|PARODD)
852 #define VARITEXT_IFLAG (IGNPAR|IGNBRK|INPCK) /*|ISTRIP)*/
853 #define VARITEXT_OFLAG 0
854 #define VARITEXT_LFLAG 0
855 #define VARITEXT_SAMPLES 32
856 #define VARITEXT_KEEP 20
858 static struct parse_clockinfo
860 u_long cl_flags; /* operation flags (io modes) */
861 void (*cl_poll) P((struct parseunit *)); /* active poll routine */
862 int (*cl_init) P((struct parseunit *)); /* active poll init routine */
863 void (*cl_event) P((struct parseunit *, int)); /* special event handling (e.g. reset clock) */
864 void (*cl_end) P((struct parseunit *)); /* active poll end routine */
865 void (*cl_message) P((struct parseunit *, parsetime_t *)); /* process a lower layer message */
866 void *cl_data; /* local data area for "poll" mechanism */
867 double cl_rootdelay; /* rootdelay */
868 double cl_basedelay; /* current offset by which the RS232
869 time code is delayed from the actual time */
870 const char *cl_id; /* ID code */
871 const char *cl_description; /* device name */
872 const char *cl_format; /* fixed format */
873 u_char cl_type; /* clock type (ntp control) */
874 u_long cl_maxunsync; /* time to trust oscillator after losing synch */
875 u_long cl_speed; /* terminal input & output baudrate */
876 u_long cl_cflag; /* terminal control flags */
877 u_long cl_iflag; /* terminal input flags */
878 u_long cl_oflag; /* terminal output flags */
879 u_long cl_lflag; /* terminal local flags */
880 u_long cl_samples; /* samples for median filter */
881 u_long cl_keep; /* samples for median filter to keep */
882 } parse_clockinfo[] =
895 DCFPZF535_DESCRIPTION,
915 DCFPZF535OCXO_ROOTDELAY,
916 DCFPZF535OCXO_BASEDELAY,
918 DCFPZF535OCXO_DESCRIPTION,
919 DCFPZF535OCXO_FORMAT,
921 DCFPZF535OCXO_MAXUNSYNC,
927 DCFPZF535OCXO_SAMPLES,
1031 TIMEBRICK_BASEDELAY,
1033 TIMEBRICK_DESCRIPTION,
1077 IGELCLOCK_BASEDELAY,
1079 IGELCLOCK_DESCRIPTION,
1093 #if TRIM_POLLRATE /* DHD940515: Allow user config */
1103 TRIMBLETAIP_ROOTDELAY,
1104 TRIMBLETAIP_BASEDELAY,
1106 TRIMBLETAIP_DESCRIPTION,
1109 TRIMBLETAIP_MAXUNSYNC,
1115 TRIMBLETAIP_SAMPLES,
1120 #if TRIM_POLLRATE /* DHD940515: Allow user config */
1128 TRIMBLETSIP_MESSAGE,
1130 TRIMBLETSIP_ROOTDELAY,
1131 TRIMBLETSIP_BASEDELAY,
1133 TRIMBLETSIP_DESCRIPTION,
1136 TRIMBLETSIP_MAXUNSYNC,
1142 TRIMBLETSIP_SAMPLES,
1156 RCC8000_DESCRIPTION,
1179 HOPF6021_DESCRIPTION,
1199 COMPUTIME_ROOTDELAY,
1200 COMPUTIME_BASEDELAY,
1202 COMPUTIME_DESCRIPTION,
1205 COMPUTIME_MAXUNSYNC,
1225 RAWDCFDTRSET_DESCRIPTION,
1238 0, /* operation flags (io modes) */
1239 NO_POLL, /* active poll routine */
1240 NO_INIT, /* active poll init routine */
1241 NO_EVENT, /* special event handling (e.g. reset clock) */
1242 NO_END, /* active poll end routine */
1243 NO_MESSAGE, /* process a lower layer message */
1244 NO_LCLDATA, /* local data area for "poll" mechanism */
1246 11.0 /* bits */ / 9600, /* current offset by which the RS232
1247 time code is delayed from the actual time */
1248 DCF_ID, /* ID code */
1249 "WHARTON 400A Series clock", /* device name */
1250 "WHARTON 400A Series clock Output Format 1", /* fixed format */
1251 /* Must match a format-name in a libparse/clk_xxx.c file */
1252 DCF_TYPE, /* clock type (ntp control) */
1253 (1*60*60), /* time to trust oscillator after losing synch */
1254 B9600, /* terminal input & output baudrate */
1255 (CS8|CREAD|PARENB|CLOCAL|HUPCL),/* terminal control flags */
1256 0, /* terminal input flags */
1257 0, /* terminal output flags */
1258 0, /* terminal local flags */
1259 5, /* samples for median filter */
1260 3, /* samples for median filter to keep */
1262 { /* mode 16 - RAWDCF RTS set, DTR clr */
1265 RAWDCFDTRCLRRTSSET_INIT,
1273 RAWDCFDTRCLRRTSSET_DESCRIPTION,
1296 VARITEXT_DESCRIPTION,
1340 GUDE_EMC_USB_V20_BASEDELAY,
1342 GUDE_EMC_USB_V20_DESCRIPTION,
1346 GUDE_EMC_USB_V20_SPEED,
1356 static int ncltypes = sizeof(parse_clockinfo) / sizeof(struct parse_clockinfo);
1358 #define CLK_REALTYPE(x) ((int)(((x)->ttl) & 0x7F))
1359 #define CLK_TYPE(x) ((CLK_REALTYPE(x) >= ncltypes) ? ~0 : CLK_REALTYPE(x))
1360 #define CLK_UNIT(x) ((int)REFCLOCKUNIT(&(x)->srcadr))
1361 #define CLK_PPS(x) (((x)->ttl) & 0x80)
1364 * Other constant stuff
1366 #define PARSEHSREFID 0x7f7f08ff /* 127.127.8.255 refid for hi strata */
1368 #define PARSESTATISTICS (60*60) /* output state statistics every hour */
1370 static int notice = 0;
1372 #define PARSE_STATETIME(parse, i) ((parse->generic->currentstatus == i) ? parse->statetime[i] + current_time - parse->lastchange : parse->statetime[i])
1374 static void parse_event P((struct parseunit *, int));
1375 static void parse_process P((struct parseunit *, parsetime_t *));
1376 static void clear_err P((struct parseunit *, u_long));
1377 static int list_err P((struct parseunit *, u_long));
1378 static char * l_mktime P((u_long));
1380 /**===========================================================================
1381 ** implementation error message regression module
1385 struct parseunit *parse,
1389 if (lstate == ERR_ALL)
1393 for (i = 0; i < ERR_CNT; i++)
1395 parse->errors[i].err_stage = err_tbl[i];
1396 parse->errors[i].err_cnt = 0;
1397 parse->errors[i].err_last = 0;
1398 parse->errors[i].err_started = 0;
1399 parse->errors[i].err_suppressed = 0;
1404 parse->errors[lstate].err_stage = err_tbl[lstate];
1405 parse->errors[lstate].err_cnt = 0;
1406 parse->errors[lstate].err_last = 0;
1407 parse->errors[lstate].err_started = 0;
1408 parse->errors[lstate].err_suppressed = 0;
1414 struct parseunit *parse,
1419 struct errorinfo *err = &parse->errors[lstate];
1421 if (err->err_started == 0)
1423 err->err_started = current_time;
1426 do_it = (current_time - err->err_last) >= err->err_stage->err_delay;
1431 if (err->err_stage->err_count &&
1432 (err->err_cnt >= err->err_stage->err_count))
1438 if (!err->err_cnt && do_it)
1439 msyslog(LOG_INFO, "PARSE receiver #%d: interval for following error message class is at least %s",
1440 CLK_UNIT(parse->peer), l_mktime(err->err_stage->err_delay));
1443 err->err_suppressed++;
1445 err->err_last = current_time;
1447 if (do_it && err->err_suppressed)
1449 msyslog(LOG_INFO, "PARSE receiver #%d: %ld message%s suppressed, error condition class persists for %s",
1450 CLK_UNIT(parse->peer), err->err_suppressed, (err->err_suppressed == 1) ? " was" : "s where",
1451 l_mktime(current_time - err->err_started));
1452 err->err_suppressed = 0;
1458 /*--------------------------------------------------
1459 * mkreadable - make a printable ascii string (without
1460 * embedded quotes so that the ntpq protocol isn't
1464 #define isprint(_X_) (((_X_) > 0x1F) && ((_X_) < 0x7F))
1477 char *endb = (char *)0;
1480 return (char *)0; /* don't bother with mini buffers */
1482 endb = buffer + blen - 4;
1484 blen--; /* account for '\0' */
1486 while (blen && srclen--)
1488 if (!hex && /* no binary only */
1489 (*src != '\\') && /* no plain \ */
1490 (*src != '"') && /* no " */
1491 isprint((int)*src)) /* only printables */
1492 { /* they are easy... */
1511 strcpy(buffer,"\\\\");
1518 sprintf(buffer, "\\x%02x", *src++);
1524 if (srclen && !blen && endb) /* overflow - set last chars to ... */
1525 strcpy(endb, "...");
1533 /*--------------------------------------------------
1534 * mkascii - make a printable ascii string
1535 * assumes (unless defined better) 7-bit ASCII
1545 return mkreadable(buffer, blen, src, srclen, 0);
1548 /**===========================================================================
1549 ** implementation of i/o handling methods
1550 ** (all STREAM, partial STREAM, user level)
1554 * define possible io handling methods
1557 static int ppsclock_init P((struct parseunit *));
1558 static int stream_init P((struct parseunit *));
1559 static void stream_end P((struct parseunit *));
1560 static int stream_enable P((struct parseunit *));
1561 static int stream_disable P((struct parseunit *));
1562 static int stream_setcs P((struct parseunit *, parsectl_t *));
1563 static int stream_getfmt P((struct parseunit *, parsectl_t *));
1564 static int stream_setfmt P((struct parseunit *, parsectl_t *));
1565 static int stream_timecode P((struct parseunit *, parsectl_t *));
1566 static void stream_receive P((struct recvbuf *));
1569 static int local_init P((struct parseunit *));
1570 static void local_end P((struct parseunit *));
1571 static int local_nop P((struct parseunit *));
1572 static int local_setcs P((struct parseunit *, parsectl_t *));
1573 static int local_getfmt P((struct parseunit *, parsectl_t *));
1574 static int local_setfmt P((struct parseunit *, parsectl_t *));
1575 static int local_timecode P((struct parseunit *, parsectl_t *));
1576 static void local_receive P((struct recvbuf *));
1577 static int local_input P((struct recvbuf *));
1579 static bind_t io_bindings[] =
1629 #define fix_ts(_X_) \
1630 if ((&(_X_))->tv.tv_usec >= 1000000) \
1632 (&(_X_))->tv.tv_usec -= 1000000; \
1633 (&(_X_))->tv.tv_sec += 1; \
1636 #define cvt_ts(_X_, _Y_) \
1640 if (!buftvtots((const char *)&(&(_X_))->tv, &ts)) \
1643 msyslog(LOG_ERR,"parse: stream_receive: timestamp conversion error (buftvtots) (%s) (%ld.%06ld) ", (_Y_), (long)(&(_X_))->tv.tv_sec, (long)(&(_X_))->tv.tv_usec);\
1648 (&(_X_))->fp = ts; \
1652 /*--------------------------------------------------
1653 * ppsclock STREAM init
1657 struct parseunit *parse
1660 static char m1[] = "ppsclocd";
1661 static char m2[] = "ppsclock";
1664 * now push the parse streams module
1665 * it will ensure exclusive access to the device
1667 if (ioctl(parse->ppsfd, I_PUSH, (caddr_t)m1) == -1 &&
1668 ioctl(parse->ppsfd, I_PUSH, (caddr_t)m2) == -1)
1670 if (errno != EINVAL)
1672 msyslog(LOG_ERR, "PARSE receiver #%d: ppsclock_init: ioctl(fd, I_PUSH, \"ppsclock\"): %m",
1673 CLK_UNIT(parse->peer));
1677 if (!local_init(parse))
1679 (void)ioctl(parse->ppsfd, I_POP, (caddr_t)0);
1683 parse->flags |= PARSE_PPSCLOCK;
1687 /*--------------------------------------------------
1692 struct parseunit *parse
1695 static char m1[] = "parse";
1697 * now push the parse streams module
1698 * to test whether it is there (neat interface 8-( )
1700 if (ioctl(parse->generic->io.fd, I_PUSH, (caddr_t)m1) == -1)
1702 if (errno != EINVAL) /* accept non-existence */
1704 msyslog(LOG_ERR, "PARSE receiver #%d: stream_init: ioctl(fd, I_PUSH, \"parse\"): %m", CLK_UNIT(parse->peer));
1710 while(ioctl(parse->generic->io.fd, I_POP, (caddr_t)0) == 0)
1714 * now push it a second time after we have removed all
1717 if (ioctl(parse->generic->io.fd, I_PUSH, (caddr_t)m1) == -1)
1719 msyslog(LOG_ERR, "PARSE receiver #%d: stream_init: ioctl(fd, I_PUSH, \"parse\"): %m", CLK_UNIT(parse->peer));
1729 /*--------------------------------------------------
1734 struct parseunit *parse
1737 while(ioctl(parse->generic->io.fd, I_POP, (caddr_t)0) == 0)
1741 /*--------------------------------------------------
1746 struct parseunit *parse,
1750 struct strioctl strioc;
1752 strioc.ic_cmd = PARSEIOC_SETCS;
1753 strioc.ic_timout = 0;
1754 strioc.ic_dp = (char *)tcl;
1755 strioc.ic_len = sizeof (*tcl);
1757 if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1)
1759 msyslog(LOG_ERR, "PARSE receiver #%d: stream_setcs: ioctl(fd, I_STR, PARSEIOC_SETCS): %m", CLK_UNIT(parse->peer));
1765 /*--------------------------------------------------
1770 struct parseunit *parse
1773 struct strioctl strioc;
1775 strioc.ic_cmd = PARSEIOC_ENABLE;
1776 strioc.ic_timout = 0;
1777 strioc.ic_dp = (char *)0;
1780 if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1)
1782 msyslog(LOG_ERR, "PARSE receiver #%d: stream_enable: ioctl(fd, I_STR, PARSEIOC_ENABLE): %m", CLK_UNIT(parse->peer));
1785 parse->generic->io.clock_recv = stream_receive; /* ok - parse input in kernel */
1789 /*--------------------------------------------------
1794 struct parseunit *parse
1797 struct strioctl strioc;
1799 strioc.ic_cmd = PARSEIOC_DISABLE;
1800 strioc.ic_timout = 0;
1801 strioc.ic_dp = (char *)0;
1804 if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1)
1806 msyslog(LOG_ERR, "PARSE receiver #%d: stream_disable: ioctl(fd, I_STR, PARSEIOC_DISABLE): %m", CLK_UNIT(parse->peer));
1809 parse->generic->io.clock_recv = local_receive; /* ok - parse input in daemon */
1813 /*--------------------------------------------------
1818 struct parseunit *parse,
1822 struct strioctl strioc;
1824 strioc.ic_cmd = PARSEIOC_GETFMT;
1825 strioc.ic_timout = 0;
1826 strioc.ic_dp = (char *)tcl;
1827 strioc.ic_len = sizeof (*tcl);
1828 if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1)
1830 msyslog(LOG_ERR, "PARSE receiver #%d: ioctl(fd, I_STR, PARSEIOC_GETFMT): %m", CLK_UNIT(parse->peer));
1836 /*--------------------------------------------------
1841 struct parseunit *parse,
1845 struct strioctl strioc;
1847 strioc.ic_cmd = PARSEIOC_SETFMT;
1848 strioc.ic_timout = 0;
1849 strioc.ic_dp = (char *)tcl;
1850 strioc.ic_len = sizeof (*tcl);
1852 if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1)
1854 msyslog(LOG_ERR, "PARSE receiver #%d: stream_setfmt: ioctl(fd, I_STR, PARSEIOC_SETFMT): %m", CLK_UNIT(parse->peer));
1861 /*--------------------------------------------------
1866 struct parseunit *parse,
1870 struct strioctl strioc;
1872 strioc.ic_cmd = PARSEIOC_TIMECODE;
1873 strioc.ic_timout = 0;
1874 strioc.ic_dp = (char *)tcl;
1875 strioc.ic_len = sizeof (*tcl);
1877 if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1)
1880 msyslog(LOG_ERR, "PARSE receiver #%d: stream_timecode: ioctl(fd, I_STR, PARSEIOC_TIMECODE): %m", CLK_UNIT(parse->peer));
1883 clear_err(parse, ERR_INTERNAL);
1887 /*--------------------------------------------------
1892 struct recvbuf *rbufp
1895 struct parseunit *parse = (struct parseunit *)((void *)rbufp->recv_srcclock);
1896 parsetime_t parsetime;
1901 if (rbufp->recv_length != sizeof(parsetime_t))
1904 msyslog(LOG_ERR,"PARSE receiver #%d: stream_receive: bad size (got %d expected %d)",
1905 CLK_UNIT(parse->peer), rbufp->recv_length, (int)sizeof(parsetime_t));
1906 parse_event(parse, CEVNT_BADREPLY);
1909 clear_err(parse, ERR_BADIO);
1911 memmove((caddr_t)&parsetime,
1912 (caddr_t)rbufp->recv_buffer,
1913 sizeof(parsetime_t));
1918 printf("PARSE receiver #%d: status %06x, state %08x, time %lx.%08lx, stime %lx.%08lx, ptime %lx.%08lx\n",
1919 CLK_UNIT(parse->peer),
1920 (unsigned int)parsetime.parse_status,
1921 (unsigned int)parsetime.parse_state,
1922 (unsigned long)parsetime.parse_time.tv.tv_sec,
1923 (unsigned long)parsetime.parse_time.tv.tv_usec,
1924 (unsigned long)parsetime.parse_stime.tv.tv_sec,
1925 (unsigned long)parsetime.parse_stime.tv.tv_usec,
1926 (unsigned long)parsetime.parse_ptime.tv.tv_sec,
1927 (unsigned long)parsetime.parse_ptime.tv.tv_usec);
1932 * switch time stamp world - be sure to normalize small usec field
1936 cvt_ts(parsetime.parse_stime, "parse_stime");
1938 if (PARSE_TIMECODE(parsetime.parse_state))
1940 cvt_ts(parsetime.parse_time, "parse_time");
1943 if (PARSE_PPS(parsetime.parse_state))
1944 cvt_ts(parsetime.parse_ptime, "parse_ptime");
1946 parse_process(parse, &parsetime);
1950 /*--------------------------------------------------
1955 struct parseunit *parse
1958 return parse_ioinit(&parse->parseio);
1961 /*--------------------------------------------------
1966 struct parseunit *parse
1969 parse_ioend(&parse->parseio);
1973 /*--------------------------------------------------
1978 struct parseunit *parse
1984 /*--------------------------------------------------
1989 struct parseunit *parse,
1993 return parse_setcs(tcl, &parse->parseio);
1996 /*--------------------------------------------------
2001 struct parseunit *parse,
2005 return parse_getfmt(tcl, &parse->parseio);
2008 /*--------------------------------------------------
2013 struct parseunit *parse,
2017 return parse_setfmt(tcl, &parse->parseio);
2020 /*--------------------------------------------------
2025 struct parseunit *parse,
2029 return parse_timecode(tcl, &parse->parseio);
2033 /*--------------------------------------------------
2038 struct recvbuf *rbufp
2041 struct parseunit *parse = (struct parseunit *)((void *)rbufp->recv_srcclock);
2050 * eat all characters, parsing then and feeding complete samples
2052 count = rbufp->recv_length;
2053 s = (unsigned char *)rbufp->recv_buffer;
2054 ts.fp = rbufp->recv_time;
2058 if (parse_ioread(&parse->parseio, (unsigned int)(*s++), &ts))
2060 struct recvbuf *buf;
2063 * got something good to eat
2065 if (!PARSE_PPS(parse->parseio.parse_dtime.parse_state))
2068 if (parse->flags & PARSE_PPSCLOCK)
2070 struct timespec pps_timeout;
2071 pps_info_t pps_info;
2073 pps_timeout.tv_sec = 0;
2074 pps_timeout.tv_nsec = 0;
2076 if (time_pps_fetch(parse->ppshandle, PPS_TSFMT_TSPEC, &pps_info,
2079 if (pps_info.assert_sequence + pps_info.clear_sequence != parse->ppsserial)
2083 struct timespec pts;
2085 * add PPS time stamp if available via ppsclock module
2086 * and not supplied already.
2088 if (parse->flags & PARSE_CLEAR)
2089 pts = pps_info.clear_timestamp;
2091 pts = pps_info.assert_timestamp;
2093 parse->parseio.parse_dtime.parse_ptime.fp.l_ui = pts.tv_sec + JAN_1970;
2095 dtemp = pts.tv_nsec / 1e9;
2098 parse->parseio.parse_dtime.parse_ptime.fp.l_ui--;
2102 parse->parseio.parse_dtime.parse_ptime.fp.l_ui++;
2104 parse->parseio.parse_dtime.parse_ptime.fp.l_uf = dtemp * FRAC;
2106 parse->parseio.parse_dtime.parse_state |= PARSEB_PPS|PARSEB_S_PPS;
2111 "parse: local_receive: fd %d PPSAPI seq %ld - PPS %s\n",
2113 (long)pps_info.assert_sequence + (long)pps_info.clear_sequence,
2114 lfptoa(&parse->parseio.parse_dtime.parse_ptime.fp, 6));
2124 "parse: local_receive: fd %d PPSAPI seq assert %ld, seq clear %ld - NO PPS event\n",
2126 (long)pps_info.assert_sequence, (long)pps_info.clear_sequence);
2130 parse->ppsserial = pps_info.assert_sequence + pps_info.clear_sequence;
2138 "parse: local_receive: fd %d PPSAPI time_pps_fetch errno = %d\n",
2146 #ifdef TIOCDCDTIMESTAMP
2147 struct timeval dcd_time;
2149 if (ioctl(parse->ppsfd, TIOCDCDTIMESTAMP, &dcd_time) != -1)
2153 TVTOTS(&dcd_time, &tstmp);
2154 tstmp.l_ui += JAN_1970;
2155 L_SUB(&ts.fp, &tstmp);
2156 if (ts.fp.l_ui == 0)
2162 "parse: local_receive: fd %d DCDTIMESTAMP %s\n",
2165 printf(" sigio %s\n",
2169 parse->parseio.parse_dtime.parse_ptime.fp = tstmp;
2170 parse->parseio.parse_dtime.parse_state |= PARSEB_PPS|PARSEB_S_PPS;
2173 #else /* TIOCDCDTIMESTAMP */
2174 #if defined(HAVE_STRUCT_PPSCLOCKEV) && (defined(HAVE_CIOGETEV) || defined(HAVE_TIOCGPPSEV))
2175 if (parse->flags & PARSE_PPSCLOCK)
2178 struct ppsclockev ev;
2180 #ifdef HAVE_CIOGETEV
2181 if (ioctl(parse->ppsfd, CIOGETEV, (caddr_t)&ev) == 0)
2183 #ifdef HAVE_TIOCGPPSEV
2184 if (ioctl(parse->ppsfd, TIOCGPPSEV, (caddr_t)&ev) == 0)
2187 if (ev.serial != parse->ppsserial)
2190 * add PPS time stamp if available via ppsclock module
2191 * and not supplied already.
2193 if (!buftvtots((const char *)&ev.tv, &tts))
2196 msyslog(LOG_ERR,"parse: local_receive: timestamp conversion error (buftvtots) (ppsclockev.tv)");
2200 parse->parseio.parse_dtime.parse_ptime.fp = tts;
2201 parse->parseio.parse_dtime.parse_state |= PARSEB_PPS|PARSEB_S_PPS;
2204 parse->ppsserial = ev.serial;
2208 #endif /* TIOCDCDTIMESTAMP */
2209 #endif /* !HAVE_PPSAPI */
2212 { /* simulate receive */
2213 buf = get_free_recv_buffer();
2215 memmove((caddr_t)buf->recv_buffer,
2216 (caddr_t)&parse->parseio.parse_dtime,
2217 sizeof(parsetime_t));
2218 buf->recv_length = sizeof(parsetime_t);
2219 buf->recv_time = rbufp->recv_time;
2220 buf->srcadr = rbufp->srcadr;
2221 buf->dstadr = rbufp->dstadr;
2222 buf->receiver = rbufp->receiver;
2223 buf->fd = rbufp->fd;
2224 buf->X_from_where = rbufp->X_from_where;
2225 add_full_recv_buffer(buf);
2227 parse_iodone(&parse->parseio);
2231 memmove((caddr_t)rbufp->recv_buffer,
2232 (caddr_t)&parse->parseio.parse_dtime,
2233 sizeof(parsetime_t));
2234 parse_iodone(&parse->parseio);
2235 rbufp->recv_length = sizeof(parsetime_t);
2236 return 1; /* got something & in place return */
2240 return 0; /* nothing to pass up */
2243 /*--------------------------------------------------
2248 struct recvbuf *rbufp
2251 struct parseunit *parse = (struct parseunit *)((void *)rbufp->recv_srcclock);
2252 parsetime_t parsetime;
2257 if (rbufp->recv_length != sizeof(parsetime_t))
2260 msyslog(LOG_ERR,"PARSE receiver #%d: local_receive: bad size (got %d expected %d)",
2261 CLK_UNIT(parse->peer), rbufp->recv_length, (int)sizeof(parsetime_t));
2262 parse_event(parse, CEVNT_BADREPLY);
2265 clear_err(parse, ERR_BADIO);
2267 memmove((caddr_t)&parsetime,
2268 (caddr_t)rbufp->recv_buffer,
2269 sizeof(parsetime_t));
2274 printf("PARSE receiver #%d: status %06x, state %08x, time(fp) %lx.%08lx, stime(fp) %lx.%08lx, ptime(fp) %lx.%08lx\n",
2275 CLK_UNIT(parse->peer),
2276 (unsigned int)parsetime.parse_status,
2277 (unsigned int)parsetime.parse_state,
2278 (unsigned long)parsetime.parse_time.fp.l_ui,
2279 (unsigned long)parsetime.parse_time.fp.l_uf,
2280 (unsigned long)parsetime.parse_stime.fp.l_ui,
2281 (unsigned long)parsetime.parse_stime.fp.l_uf,
2282 (unsigned long)parsetime.parse_ptime.fp.l_ui,
2283 (unsigned long)parsetime.parse_ptime.fp.l_uf);
2287 parse_process(parse, &parsetime);
2290 /*--------------------------------------------------
2291 * init_iobinding - find and initialize lower layers
2295 struct parseunit *parse
2298 bind_t *b = io_bindings;
2300 while (b->bd_description != (char *)0)
2302 if ((*b->bd_init)(parse))
2311 /**===========================================================================
2315 /*--------------------------------------------------
2316 * convert a flag field to a string
2331 { PARSEB_ANNOUNCE, "DST SWITCH WARNING" },
2332 { PARSEB_POWERUP, "NOT SYNCHRONIZED" },
2333 { PARSEB_NOSYNC, "TIME CODE NOT CONFIRMED" },
2334 { PARSEB_DST, "DST" },
2335 { PARSEB_UTC, "UTC DISPLAY" },
2336 { PARSEB_LEAPADD, "LEAP ADD WARNING" },
2337 { PARSEB_LEAPDEL, "LEAP DELETE WARNING" },
2338 { PARSEB_LEAPSECOND, "LEAP SECOND" },
2339 { PARSEB_ALTERNATE, "ALTERNATE ANTENNA" },
2340 { PARSEB_TIMECODE, "TIME CODE" },
2341 { PARSEB_PPS, "PPS" },
2342 { PARSEB_POSITION, "POSITION" },
2352 { PARSEB_S_LEAP, "LEAP INDICATION" },
2353 { PARSEB_S_PPS, "PPS SIGNAL" },
2354 { PARSEB_S_ANTENNA, "ANTENNA" },
2355 { PARSEB_S_POSITION, "POSITION" },
2366 while (flagstrings[i].bit)
2368 if (flagstrings[i].bit & lstate)
2371 strncpy(t, "; ", BUFFER_SIZES(buffer, t, size));
2372 strncat(t, flagstrings[i].name, BUFFER_SIZES(buffer, t, size));
2378 if (lstate & (PARSEB_S_LEAP|PARSEB_S_ANTENNA|PARSEB_S_PPS|PARSEB_S_POSITION))
2381 strncpy(t, "; ", BUFFER_SIZES(buffer, t, size));
2385 strncpy(t, "(", BUFFER_SIZES(buffer, t, size));
2387 s = t = t + strlen(t);
2390 while (sflagstrings[i].bit)
2392 if (sflagstrings[i].bit & lstate)
2396 strncpy(t, "; ", BUFFER_SIZES(buffer, t, size));
2400 strncpy(t, sflagstrings[i].name, BUFFER_SIZES(buffer, t, size));
2405 strncpy(t, ")", BUFFER_SIZES(buffer, t, size));
2410 /*--------------------------------------------------
2411 * convert a status flag field to a string
2426 { CVT_OK, "CONVERSION SUCCESSFUL" },
2427 { CVT_NONE, "NO CONVERSION" },
2428 { CVT_FAIL, "CONVERSION FAILED" },
2429 { CVT_BADFMT, "ILLEGAL FORMAT" },
2430 { CVT_BADDATE, "DATE ILLEGAL" },
2431 { CVT_BADTIME, "TIME ILLEGAL" },
2432 { CVT_ADDITIONAL, "ADDITIONAL DATA" },
2440 while (flagstrings[i].bit)
2442 if (flagstrings[i].bit & lstate)
2445 strncat(buffer, "; ", size);
2446 strncat(buffer, flagstrings[i].name, size);
2454 /*--------------------------------------------------
2455 * convert a clock status flag field to a string
2462 static char buffer[20];
2463 static struct status
2469 { CEVNT_NOMINAL, "NOMINAL" },
2470 { CEVNT_TIMEOUT, "NO RESPONSE" },
2471 { CEVNT_BADREPLY,"BAD FORMAT" },
2472 { CEVNT_FAULT, "FAULT" },
2473 { CEVNT_PROP, "PROPAGATION DELAY" },
2474 { CEVNT_BADDATE, "ILLEGAL DATE" },
2475 { CEVNT_BADTIME, "ILLEGAL TIME" },
2481 while (flagstrings[i].value != ~0)
2483 if (flagstrings[i].value == lstate)
2485 return flagstrings[i].name;
2490 snprintf(buffer, sizeof(buffer), "unknown #%ld", (u_long)lstate);
2496 /*--------------------------------------------------
2497 * l_mktime - make representation of a relative time
2505 static char buffer[40];
2510 if ((tmp = delta / (60*60*24)) != 0)
2512 snprintf(buffer, BUFFER_SIZE(buffer, buffer), "%ldd+", (u_long)tmp);
2513 delta -= tmp * 60*60*24;
2521 t = buffer + strlen(buffer);
2523 snprintf(t, BUFFER_SIZE(buffer, t), "%02d:%02d:%02d",
2524 (int)delta, (int)m, (int)s);
2530 /*--------------------------------------------------
2531 * parse_statistics - list summary of clock states
2535 struct parseunit *parse
2540 NLOG(NLOG_CLOCKSTATIST) /* conditional if clause for conditional syslog */
2542 msyslog(LOG_INFO, "PARSE receiver #%d: running time: %s",
2543 CLK_UNIT(parse->peer),
2544 l_mktime(current_time - parse->generic->timestarted));
2546 msyslog(LOG_INFO, "PARSE receiver #%d: current status: %s",
2547 CLK_UNIT(parse->peer),
2548 clockstatus(parse->generic->currentstatus));
2550 for (i = 0; i <= CEVNT_MAX; i++)
2553 u_long percent, d = current_time - parse->generic->timestarted;
2555 percent = s_time = PARSE_STATETIME(parse, i);
2557 while (((u_long)(~0) / 10000) < percent)
2564 percent = (percent * 10000) / d;
2569 msyslog(LOG_INFO, "PARSE receiver #%d: state %18s: %13s (%3ld.%02ld%%)",
2570 CLK_UNIT(parse->peer),
2571 clockstatus((unsigned int)i),
2573 percent / 100, percent % 100);
2578 /*--------------------------------------------------
2579 * cparse_statistics - wrapper for statistics call
2583 struct parseunit *parse
2586 if (parse->laststatistic + PARSESTATISTICS < current_time)
2587 parse_statistics(parse);
2588 parse->laststatistic = current_time;
2591 /**===========================================================================
2592 ** ntp interface routines
2595 /*--------------------------------------------------
2596 * parse_shutdown - shut down a PARSE clock
2604 struct parseunit *parse = (struct parseunit *)0;
2606 if (peer && peer->procptr)
2607 parse = (struct parseunit *)peer->procptr->unitptr;
2611 /* nothing to clean up */
2617 msyslog(LOG_INFO, "PARSE receiver #%d: INTERNAL ERROR - unit already inactive - shutdown ignored", unit);
2622 if (parse->flags & PARSE_PPSCLOCK)
2624 (void)time_pps_destroy(parse->ppshandle);
2627 if (parse->generic->io.fd != parse->ppsfd && parse->ppsfd != -1)
2628 (void)close(parse->ppsfd); /* close separate PPS source */
2631 * print statistics a last time and
2632 * stop statistics machine
2634 parse_statistics(parse);
2636 if (parse->parse_type->cl_end)
2638 parse->parse_type->cl_end(parse);
2642 * cleanup before leaving this world
2648 * Tell the I/O module to turn us off. We're history.
2650 io_closeclock(&parse->generic->io);
2652 free_varlist(parse->kv);
2654 NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */
2655 msyslog(LOG_INFO, "PARSE receiver #%d: reference clock \"%s\" removed",
2656 CLK_UNIT(parse->peer), parse->parse_type->cl_description);
2658 parse->peer = (struct peer *)0; /* unused now */
2659 peer->procptr->unitptr = (caddr_t)0;
2664 /*----------------------------------------
2665 * set up HARDPPS via PPSAPI
2669 struct parseunit *parse,
2673 if (parse->hardppsstate == mode)
2676 if (CLK_PPS(parse->peer) && (parse->flags & PARSE_PPSKERNEL)) {
2679 if (mode == PARSE_HARDPPS_ENABLE)
2681 if (parse->flags & PARSE_CLEAR)
2682 i = PPS_CAPTURECLEAR;
2684 i = PPS_CAPTUREASSERT;
2687 if (time_pps_kcbind(parse->ppshandle, PPS_KC_HARDPPS, i,
2688 PPS_TSFMT_TSPEC) < 0) {
2689 msyslog(LOG_ERR, "PARSE receiver #%d: time_pps_kcbind failed: %m",
2690 CLK_UNIT(parse->peer));
2692 NLOG(NLOG_CLOCKINFO)
2693 msyslog(LOG_INFO, "PARSE receiver #%d: kernel PPS synchronisation %sabled",
2694 CLK_UNIT(parse->peer), (mode == PARSE_HARDPPS_ENABLE) ? "en" : "dis");
2696 * tell the rest, that we have a kernel PPS source, iff we ever enable HARDPPS
2698 if (mode == PARSE_HARDPPS_ENABLE)
2703 parse->hardppsstate = mode;
2706 /*----------------------------------------
2707 * set up PPS via PPSAPI
2711 struct parseunit *parse
2714 int cap, mode, mode1;
2717 parse->flags &= ~PARSE_PPSCLOCK;
2719 if (time_pps_getcap(parse->ppshandle, &cap) < 0) {
2720 msyslog(LOG_ERR, "PARSE receiver #%d: parse_ppsapi: time_pps_getcap failed: %m",
2721 CLK_UNIT(parse->peer));
2726 if (time_pps_getparams(parse->ppshandle, &parse->ppsparams) < 0) {
2727 msyslog(LOG_ERR, "PARSE receiver #%d: parse_ppsapi: time_pps_getparams failed: %m",
2728 CLK_UNIT(parse->peer));
2732 /* nb. only turn things on, if someone else has turned something
2733 * on before we get here, leave it alone!
2736 if (parse->flags & PARSE_CLEAR) {
2738 mode = PPS_CAPTURECLEAR;
2739 mode1 = PPS_OFFSETCLEAR;
2742 mode = PPS_CAPTUREASSERT;
2743 mode1 = PPS_OFFSETASSERT;
2746 msyslog(LOG_INFO, "PARSE receiver #%d: initializing PPS to %s",
2747 CLK_UNIT(parse->peer), cp);
2749 if (!(mode & cap)) {
2750 msyslog(LOG_ERR, "PARSE receiver #%d: FAILED to initialize PPS to %s (PPS API capabilities=0x%x)",
2751 CLK_UNIT(parse->peer), cp, cap);
2756 if (!(mode1 & 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 (mode1 == PPS_OFFSETCLEAR)
2763 parse->ppsparams.clear_offset.tv_sec = -parse->ppsphaseadjust;
2764 parse->ppsparams.clear_offset.tv_nsec = -1e9*(parse->ppsphaseadjust - (long)parse->ppsphaseadjust);
2767 if (mode1 == PPS_OFFSETASSERT)
2769 parse->ppsparams.assert_offset.tv_sec = -parse->ppsphaseadjust;
2770 parse->ppsparams.assert_offset.tv_nsec = -1e9*(parse->ppsphaseadjust - (long)parse->ppsphaseadjust);
2774 /* only set what is legal */
2776 parse->ppsparams.mode = (mode | mode1 | PPS_TSFMT_TSPEC) & cap;
2778 if (time_pps_setparams(parse->ppshandle, &parse->ppsparams) < 0) {
2779 msyslog(LOG_ERR, "PARSE receiver #%d: FAILED set PPS parameters: %m",
2780 CLK_UNIT(parse->peer));
2784 parse->flags |= PARSE_PPSCLOCK;
2788 #define parse_hardpps(_PARSE_, _MODE_) /* empty */
2791 /*--------------------------------------------------
2792 * parse_start - open the PARSE devices and initialize data for processing
2803 struct termios tio; /* NEEDED FOR A LONG TIME ! */
2805 #ifdef HAVE_SYSV_TTYS
2806 struct termio tio; /* NEEDED FOR A LONG TIME ! */
2808 struct parseunit * parse;
2809 char parsedev[sizeof(PARSEDEVICE)+20];
2810 char parseppsdev[sizeof(PARSEPPSDEVICE)+20];
2815 * get out Copyright information once
2819 NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */
2820 msyslog(LOG_INFO, "NTP PARSE support: Copyright (c) 1989-2006, Frank Kardel");
2824 type = CLK_TYPE(peer);
2825 unit = CLK_UNIT(peer);
2827 if ((type == ~0) || (parse_clockinfo[type].cl_description == (char *)0))
2829 msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: unsupported clock type %d (max %d)",
2830 unit, CLK_REALTYPE(peer), ncltypes-1);
2835 * Unit okay, attempt to open the device.
2837 (void) snprintf(parsedev, sizeof(parsedev), PARSEDEVICE, unit);
2838 (void) snprintf(parseppsdev, sizeof(parsedev), PARSEPPSDEVICE, unit);
2844 fd232 = open(parsedev, O_RDWR | O_NOCTTY
2852 msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: open of %s failed: %m", unit, parsedev);
2856 parse = (struct parseunit *)emalloc(sizeof(struct parseunit));
2858 memset((char *)parse, 0, sizeof(struct parseunit));
2860 parse->generic = peer->procptr; /* link up */
2861 parse->generic->unitptr = (caddr_t)parse; /* link down */
2864 * Set up the structures
2866 parse->generic->timestarted = current_time;
2867 parse->lastchange = current_time;
2870 parse->pollneeddata = 0;
2871 parse->laststatistic = current_time;
2872 parse->lastformat = (unsigned short)~0; /* assume no format known */
2873 parse->timedata.parse_status = (unsigned short)~0; /* be sure to mark initial status change */
2874 parse->lastmissed = 0; /* assume got everything */
2875 parse->ppsserial = 0;
2877 parse->localdata = (void *)0;
2878 parse->localstate = 0;
2879 parse->kv = (struct ctl_var *)0;
2881 clear_err(parse, ERR_ALL);
2883 parse->parse_type = &parse_clockinfo[type];
2885 parse->maxunsync = parse->parse_type->cl_maxunsync;
2887 parse->generic->fudgetime1 = parse->parse_type->cl_basedelay;
2889 parse->generic->fudgetime2 = 0.0;
2890 parse->ppsphaseadjust = parse->generic->fudgetime2;
2892 parse->generic->clockdesc = parse->parse_type->cl_description;
2894 peer->rootdelay = parse->parse_type->cl_rootdelay;
2895 peer->sstclktype = parse->parse_type->cl_type;
2896 peer->precision = sys_precision;
2898 peer->stratum = STRATUM_REFCLOCK;
2900 if (peer->stratum <= 1)
2901 memmove((char *)&parse->generic->refid, parse->parse_type->cl_id, 4);
2903 parse->generic->refid = htonl(PARSEHSREFID);
2905 parse->generic->io.fd = fd232;
2907 parse->peer = peer; /* marks it also as busy */
2910 * configure terminal line
2912 if (TTY_GETATTR(fd232, &tio) == -1)
2914 msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: tcgetattr(%d, &tio): %m", unit, fd232);
2915 parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
2920 #ifndef _PC_VDISABLE
2921 memset((char *)tio.c_cc, 0, sizeof(tio.c_cc));
2924 errno = 0; /* pathconf can deliver -1 without changing errno ! */
2926 disablec = fpathconf(parse->generic->io.fd, _PC_VDISABLE);
2927 if (disablec == -1 && errno)
2929 msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: fpathconf(fd, _PC_VDISABLE): %m", CLK_UNIT(parse->peer));
2930 memset((char *)tio.c_cc, 0, sizeof(tio.c_cc)); /* best guess */
2934 memset((char *)tio.c_cc, disablec, sizeof(tio.c_cc));
2937 #if defined (VMIN) || defined(VTIME)
2938 if ((parse_clockinfo[type].cl_lflag & ICANON) == 0)
2944 tio.c_cc[VTIME] = 0;
2949 tio.c_cflag = parse_clockinfo[type].cl_cflag;
2950 tio.c_iflag = parse_clockinfo[type].cl_iflag;
2951 tio.c_oflag = parse_clockinfo[type].cl_oflag;
2952 tio.c_lflag = parse_clockinfo[type].cl_lflag;
2956 if ((cfsetospeed(&tio, parse_clockinfo[type].cl_speed) == -1) ||
2957 (cfsetispeed(&tio, parse_clockinfo[type].cl_speed) == -1))
2959 msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: tcset{i,o}speed(&tio, speed): %m", unit);
2960 parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
2964 tio.c_cflag |= parse_clockinfo[type].cl_speed;
2969 * if the PARSEPPSDEVICE can be opened that will be used
2970 * for PPS else PARSEDEVICE will be used
2972 parse->ppsfd = open(parseppsdev, O_RDWR | O_NOCTTY
2978 if (parse->ppsfd == -1)
2980 parse->ppsfd = fd232;
2984 * Linux PPS - the old way
2986 #if defined(HAVE_TIO_SERIAL_STUFF) /* Linux hack: define PPS interface */
2988 struct serial_struct ss;
2989 if (ioctl(parse->ppsfd, TIOCGSERIAL, &ss) < 0 ||
2991 #ifdef ASYNC_LOW_LATENCY
2992 ss.flags |= ASYNC_LOW_LATENCY,
2995 #ifdef ASYNC_PPS_CD_NEG
2996 ss.flags |= ASYNC_PPS_CD_NEG,
2999 ioctl(parse->ppsfd, TIOCSSERIAL, &ss)) < 0) {
3000 msyslog(LOG_NOTICE, "refclock_parse: TIOCSSERIAL fd %d, %m", parse->ppsfd);
3002 "refclock_parse: optional PPS processing not available");
3004 parse->flags |= PARSE_PPSCLOCK;
3005 #ifdef ASYNC_PPS_CD_NEG
3006 NLOG(NLOG_CLOCKINFO)
3008 "refclock_parse: PPS detection on");
3015 * SUN the Solaris way
3017 #ifdef HAVE_TIOCSPPS /* SUN PPS support */
3018 if (CLK_PPS(parse->peer))
3022 if (ioctl(parse->ppsfd, TIOCSPPS, (caddr_t)&i) == 0)
3024 parse->flags |= PARSE_PPSCLOCK;
3032 #if defined(HAVE_PPSAPI)
3033 parse->hardppsstate = PARSE_HARDPPS_DISABLE;
3034 if (CLK_PPS(parse->peer))
3036 if (time_pps_create(parse->ppsfd, &parse->ppshandle) < 0)
3038 msyslog(LOG_NOTICE, "PARSE receiver #%d: parse_start: could not set up PPS: %m", CLK_UNIT(parse->peer));
3042 parse_ppsapi(parse);
3047 if (TTY_SETATTR(fd232, &tio) == -1)
3049 msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: tcsetattr(%d, &tio): %m", unit, fd232);
3050 parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
3056 * pick correct input machine
3058 parse->generic->io.srcclock = (caddr_t)parse;
3059 parse->generic->io.datalen = 0;
3061 parse->binding = init_iobinding(parse);
3063 if (parse->binding == (bind_t *)0)
3065 msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: io sub system initialisation failed.", CLK_UNIT(parse->peer));
3066 parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
3067 return 0; /* well, ok - special initialisation broke */
3070 parse->generic->io.clock_recv = parse->binding->bd_receive; /* pick correct receive routine */
3071 parse->generic->io.io_input = parse->binding->bd_io_input; /* pick correct input routine */
3074 * as we always(?) get 8 bit chars we want to be
3075 * sure, that the upper bits are zero for less
3076 * than 8 bit I/O - so we pass that information on.
3077 * note that there can be only one bit count format
3078 * per file descriptor
3081 switch (tio.c_cflag & CSIZE)
3084 tmp_ctl.parsesetcs.parse_cs = PARSE_IO_CS5;
3088 tmp_ctl.parsesetcs.parse_cs = PARSE_IO_CS6;
3092 tmp_ctl.parsesetcs.parse_cs = PARSE_IO_CS7;
3096 tmp_ctl.parsesetcs.parse_cs = PARSE_IO_CS8;
3100 if (!PARSE_SETCS(parse, &tmp_ctl))
3102 msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: parse_setcs() FAILED.", unit);
3103 parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
3104 return 0; /* well, ok - special initialisation broke */
3107 strncpy(tmp_ctl.parseformat.parse_buffer, parse->parse_type->cl_format, sizeof(tmp_ctl.parseformat.parse_buffer));
3108 tmp_ctl.parseformat.parse_count = strlen(tmp_ctl.parseformat.parse_buffer);
3110 if (!PARSE_SETFMT(parse, &tmp_ctl))
3112 msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: parse_setfmt() FAILED.", unit);
3113 parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
3114 return 0; /* well, ok - special initialisation broke */
3118 * get rid of all IO accumulated so far
3121 (void) tcflush(parse->generic->io.fd, TCIOFLUSH);
3123 #if defined(TCFLSH) && defined(TCIOFLUSH)
3125 int flshcmd = TCIOFLUSH;
3127 (void) ioctl(parse->generic->io.fd, TCFLSH, (caddr_t)&flshcmd);
3133 * try to do any special initializations
3135 if (parse->parse_type->cl_init)
3137 if (parse->parse_type->cl_init(parse))
3139 parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
3140 return 0; /* well, ok - special initialisation broke */
3145 * Insert in async io device list.
3147 if (!io_addclock(&parse->generic->io))
3150 "PARSE receiver #%d: parse_start: addclock %s fails (ABORT - clock type requires async io)", CLK_UNIT(parse->peer), parsedev);
3151 parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
3156 * print out configuration
3158 NLOG(NLOG_CLOCKINFO)
3160 /* conditional if clause for conditional syslog */
3161 msyslog(LOG_INFO, "PARSE receiver #%d: reference clock \"%s\" (I/O device %s, PPS device %s) added",
3162 CLK_UNIT(parse->peer),
3163 parse->parse_type->cl_description, parsedev,
3164 (parse->ppsfd != parse->generic->io.fd) ? parseppsdev : parsedev);
3166 msyslog(LOG_INFO, "PARSE receiver #%d: Stratum %d, trust time %s, precision %d",
3167 CLK_UNIT(parse->peer),
3168 parse->peer->stratum,
3169 l_mktime(parse->maxunsync), parse->peer->precision);
3171 msyslog(LOG_INFO, "PARSE receiver #%d: rootdelay %.6f s, phase adjustment %.6f s, PPS phase adjustment %.6f s, %s IO handling",
3172 CLK_UNIT(parse->peer),
3173 parse->parse_type->cl_rootdelay,
3174 parse->generic->fudgetime1,
3175 parse->ppsphaseadjust,
3176 parse->binding->bd_description);
3178 msyslog(LOG_INFO, "PARSE receiver #%d: Format recognition: %s", CLK_UNIT(parse->peer),
3179 parse->parse_type->cl_format);
3180 msyslog(LOG_INFO, "PARSE receiver #%d: %sPPS support%s", CLK_UNIT(parse->peer),
3181 CLK_PPS(parse->peer) ? "" : "NO ",
3182 CLK_PPS(parse->peer) ?
3184 " (implementation " PPS_METHOD ")"
3195 /*--------------------------------------------------
3196 * parse_ctl - process changes on flags/time values
3200 struct parseunit *parse,
3201 struct refclockstat *in
3206 if (in->haveflags & (CLK_HAVEFLAG1|CLK_HAVEFLAG2|CLK_HAVEFLAG3|CLK_HAVEFLAG4))
3208 parse->flags = (parse->flags & ~(CLK_FLAG1|CLK_FLAG2|CLK_FLAG3|CLK_FLAG4)) |
3209 (in->flags & (CLK_FLAG1|CLK_FLAG2|CLK_FLAG3|CLK_FLAG4));
3210 #if defined(HAVE_PPSAPI)
3211 if (CLK_PPS(parse->peer))
3213 parse_ppsapi(parse);
3218 if (in->haveflags & CLK_HAVETIME1)
3220 parse->generic->fudgetime1 = in->fudgetime1;
3221 msyslog(LOG_INFO, "PARSE receiver #%d: new phase adjustment %.6f s",
3222 CLK_UNIT(parse->peer),
3223 parse->generic->fudgetime1);
3226 if (in->haveflags & CLK_HAVETIME2)
3228 parse->generic->fudgetime2 = in->fudgetime2;
3229 if (parse->flags & PARSE_TRUSTTIME)
3231 parse->maxunsync = (u_long)ABS(in->fudgetime2);
3232 msyslog(LOG_INFO, "PARSE receiver #%d: new trust time %s",
3233 CLK_UNIT(parse->peer),
3234 l_mktime(parse->maxunsync));
3238 parse->ppsphaseadjust = in->fudgetime2;
3239 msyslog(LOG_INFO, "PARSE receiver #%d: new PPS phase adjustment %.6f s",
3240 CLK_UNIT(parse->peer),
3241 parse->ppsphaseadjust);
3242 #if defined(HAVE_PPSAPI)
3243 if (CLK_PPS(parse->peer))
3245 parse_ppsapi(parse);
3253 /*--------------------------------------------------
3254 * parse_poll - called by the transmit procedure
3262 struct parseunit *parse = (struct parseunit *)peer->procptr->unitptr;
3264 if (peer != parse->peer)
3267 "PARSE receiver #%d: poll: INTERNAL: peer incorrect",
3273 * Update clock stat counters
3275 parse->generic->polls++;
3277 if (parse->pollneeddata &&
3278 ((current_time - parse->pollneeddata) > (1<<(max(min(parse->peer->hpoll, parse->peer->ppoll), parse->peer->minpoll)))))
3281 * start worrying when exceeding a poll inteval
3282 * bad news - didn't get a response last time
3284 parse->lastmissed = current_time;
3285 parse_event(parse, CEVNT_TIMEOUT);
3288 msyslog(LOG_WARNING, "PARSE receiver #%d: no data from device within poll interval (check receiver / wiring)", CLK_UNIT(parse->peer));
3292 * we just mark that we want the next sample for the clock filter
3294 parse->pollneeddata = current_time;
3296 if (parse->parse_type->cl_poll)
3298 parse->parse_type->cl_poll(parse);
3301 cparse_statistics(parse);
3306 #define LEN_STATES 300 /* length of state string */
3308 /*--------------------------------------------------
3309 * parse_control - set fudge factors, return statistics
3314 struct refclockstat *in,
3315 struct refclockstat *out,
3319 struct parseunit *parse = (struct parseunit *)peer->procptr->unitptr;
3322 static char outstatus[400]; /* status output buffer */
3327 out->p_lastcode = 0;
3328 out->kv_list = (struct ctl_var *)0;
3331 if (!parse || !parse->peer)
3333 msyslog(LOG_ERR, "PARSE receiver #%d: parse_control: unit invalid (UNIT INACTIVE)",
3338 unit = CLK_UNIT(parse->peer);
3343 parse_ctl(parse, in);
3354 outstatus[0] = '\0';
3356 out->type = REFCLK_PARSE;
3359 * keep fudgetime2 in sync with TRUSTTIME/MAXUNSYNC flag1
3361 parse->generic->fudgetime2 = (parse->flags & PARSE_TRUSTTIME) ? (double)parse->maxunsync : parse->ppsphaseadjust;
3364 * figure out skew between PPS and RS232 - just for informational
3367 if (PARSE_SYNC(parse->timedata.parse_state))
3369 if (PARSE_PPS(parse->timedata.parse_state) && PARSE_TIMECODE(parse->timedata.parse_state))
3374 * we have a PPS and RS232 signal - calculate the skew
3375 * WARNING: assumes on TIMECODE == PULSE (timecode after pulse)
3377 off = parse->timedata.parse_stime.fp;
3378 L_SUB(&off, &parse->timedata.parse_ptime.fp); /* true offset */
3379 tt = add_var(&out->kv_list, 80, RO);
3380 snprintf(tt, 80, "refclock_ppsskew=%s", lfptoms(&off, 6));
3384 if (PARSE_PPS(parse->timedata.parse_state))
3386 tt = add_var(&out->kv_list, 80, RO|DEF);
3387 snprintf(tt, 80, "refclock_ppstime=\"%s\"", gmprettydate(&parse->timedata.parse_ptime.fp));
3390 start = tt = add_var(&out->kv_list, 128, RO|DEF);
3391 snprintf(tt, 128, "refclock_time=\"");
3394 if (parse->timedata.parse_time.fp.l_ui == 0)
3396 strncpy(tt, "<UNDEFINED>\"", BUFFER_SIZES(start, tt, 128));
3400 snprintf(tt, 128, "%s\"", gmprettydate(&parse->timedata.parse_time.fp));
3403 if (!PARSE_GETTIMECODE(parse, &tmpctl))
3406 msyslog(LOG_ERR, "PARSE receiver #%d: parse_control: parse_timecode() FAILED", unit);
3410 start = tt = add_var(&out->kv_list, 512, RO|DEF);
3411 snprintf(tt, 512, "refclock_status=\"");
3415 * copy PPS flags from last read transaction (informational only)
3417 tmpctl.parsegettc.parse_state |= parse->timedata.parse_state &
3418 (PARSEB_PPS|PARSEB_S_PPS);
3420 (void) parsestate(tmpctl.parsegettc.parse_state, tt, BUFFER_SIZES(start, tt, 512));
3422 strncat(tt, "\"", BUFFER_SIZES(start, tt, 512));
3424 if (tmpctl.parsegettc.parse_count)
3425 mkascii(outstatus+strlen(outstatus), (int)(sizeof(outstatus)- strlen(outstatus) - 1),
3426 tmpctl.parsegettc.parse_buffer, (unsigned)(tmpctl.parsegettc.parse_count));
3430 tmpctl.parseformat.parse_format = tmpctl.parsegettc.parse_format;
3432 if (!PARSE_GETFMT(parse, &tmpctl))
3435 msyslog(LOG_ERR, "PARSE receiver #%d: parse_control: parse_getfmt() FAILED", unit);
3439 tt = add_var(&out->kv_list, 80, RO|DEF);
3440 snprintf(tt, 80, "refclock_format=\"");
3442 strncat(tt, tmpctl.parseformat.parse_buffer, tmpctl.parseformat.parse_count);
3443 strncat(tt,"\"", 80);
3447 * gather state statistics
3450 start = tt = add_var(&out->kv_list, LEN_STATES, RO|DEF);
3451 strncpy(tt, "refclock_states=\"", LEN_STATES);
3454 for (i = 0; i <= CEVNT_MAX; i++)
3457 u_long d = current_time - parse->generic->timestarted;
3460 percent = s_time = PARSE_STATETIME(parse, i);
3462 while (((u_long)(~0) / 10000) < percent)
3469 percent = (percent * 10000) / d;
3478 snprintf(item, 80, "%s%s%s: %s (%d.%02d%%)",
3480 (parse->generic->currentstatus == i) ? "*" : "",
3481 clockstatus((unsigned int)i),
3483 (int)(percent / 100), (int)(percent % 100));
3484 if ((count = strlen(item)) < (LEN_STATES - 40 - (tt - start)))
3486 strncpy(tt, item, BUFFER_SIZES(start, tt, LEN_STATES));
3493 snprintf(tt, BUFFER_SIZES(start, tt, LEN_STATES), "; running time: %s\"", l_mktime(sum));
3495 tt = add_var(&out->kv_list, 32, RO);
3496 snprintf(tt, 32, "refclock_id=\"%s\"", parse->parse_type->cl_id);
3498 tt = add_var(&out->kv_list, 80, RO);
3499 snprintf(tt, 80, "refclock_iomode=\"%s\"", parse->binding->bd_description);
3501 tt = add_var(&out->kv_list, 128, RO);
3502 snprintf(tt, 128, "refclock_driver_version=\"%s\"", rcsid);
3508 while (k && !(k->flags & EOV))
3510 set_var(&out->kv_list, k->text, strlen(k->text)+1, k->flags);
3515 out->lencode = strlen(outstatus);
3516 out->p_lastcode = outstatus;
3520 /**===========================================================================
3521 ** processing routines
3524 /*--------------------------------------------------
3525 * event handling - note that nominal events will also be posted
3526 * keep track of state dwelling times
3530 struct parseunit *parse,
3534 if (parse->generic->currentstatus != (u_char) event)
3536 parse->statetime[parse->generic->currentstatus] += current_time - parse->lastchange;
3537 parse->lastchange = current_time;
3539 if (parse->parse_type->cl_event)
3540 parse->parse_type->cl_event(parse, event);
3542 if (event == CEVNT_NOMINAL)
3544 NLOG(NLOG_CLOCKSTATUS)
3545 msyslog(LOG_INFO, "PARSE receiver #%d: SYNCHRONIZED",
3546 CLK_UNIT(parse->peer));
3549 refclock_report(parse->peer, event);
3553 /*--------------------------------------------------
3554 * process a PARSE time sample
3558 struct parseunit *parse,
3559 parsetime_t *parsetime
3562 l_fp off, rectime, reftime;
3566 * check for changes in conversion status
3567 * (only one for each new status !)
3569 if (((parsetime->parse_status & CVT_MASK) != CVT_OK) &&
3570 ((parsetime->parse_status & CVT_MASK) != CVT_NONE) &&
3571 (parse->timedata.parse_status != parsetime->parse_status))
3575 NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */
3576 msyslog(LOG_WARNING, "PARSE receiver #%d: conversion status \"%s\"",
3577 CLK_UNIT(parse->peer), parsestatus(parsetime->parse_status, buffer, sizeof(buffer)));
3579 if ((parsetime->parse_status & CVT_MASK) == CVT_FAIL)
3582 * tell more about the story - list time code
3583 * there is a slight change for a race condition and
3584 * the time code might be overwritten by the next packet
3588 if (!PARSE_GETTIMECODE(parse, &tmpctl))
3591 msyslog(LOG_ERR, "PARSE receiver #%d: parse_process: parse_timecode() FAILED", CLK_UNIT(parse->peer));
3596 msyslog(LOG_WARNING, "PARSE receiver #%d: FAILED TIMECODE: \"%s\" (check receiver configuration / wiring)",
3597 CLK_UNIT(parse->peer), mkascii(buffer, sizeof buffer, tmpctl.parsegettc.parse_buffer, (unsigned)(tmpctl.parsegettc.parse_count - 1)));
3603 * examine status and post appropriate events
3605 if ((parsetime->parse_status & CVT_MASK) != CVT_OK)
3608 * got bad data - tell the rest of the system
3610 switch (parsetime->parse_status & CVT_MASK)
3613 if ((parsetime->parse_status & CVT_ADDITIONAL) &&
3614 parse->parse_type->cl_message)
3615 parse->parse_type->cl_message(parse, parsetime);
3617 * save PPS information that comes piggyback
3619 if (PARSE_PPS(parsetime->parse_state))
3621 parse->timedata.parse_state |= PARSEB_PPS|PARSEB_S_PPS;
3622 parse->timedata.parse_ptime = parsetime->parse_ptime;
3624 break; /* well, still waiting - timeout is handled at higher levels */
3627 if (parsetime->parse_status & CVT_BADFMT)
3629 parse_event(parse, CEVNT_BADREPLY);
3632 if (parsetime->parse_status & CVT_BADDATE)
3634 parse_event(parse, CEVNT_BADDATE);
3637 if (parsetime->parse_status & CVT_BADTIME)
3639 parse_event(parse, CEVNT_BADTIME);
3643 parse_event(parse, CEVNT_BADREPLY); /* for the lack of something better */
3646 return; /* skip the rest - useless */
3650 * check for format changes
3651 * (in case somebody has swapped clocks 8-)
3653 if (parse->lastformat != parsetime->parse_format)
3657 tmpctl.parseformat.parse_format = parsetime->parse_format;
3659 if (!PARSE_GETFMT(parse, &tmpctl))
3662 msyslog(LOG_ERR, "PARSE receiver #%d: parse_getfmt() FAILED", CLK_UNIT(parse->peer));
3666 NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */
3667 msyslog(LOG_INFO, "PARSE receiver #%d: packet format \"%s\"",
3668 CLK_UNIT(parse->peer), tmpctl.parseformat.parse_buffer);
3670 parse->lastformat = parsetime->parse_format;
3674 * now, any changes ?
3676 if ((parse->timedata.parse_state ^ parsetime->parse_state) &
3677 ~(unsigned)(PARSEB_PPS|PARSEB_S_PPS))
3682 * something happend - except for PPS events
3685 (void) parsestate(parsetime->parse_state, tmp1, sizeof(tmp1));
3686 (void) parsestate(parse->timedata.parse_state, tmp2, sizeof(tmp2));
3688 NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */
3689 msyslog(LOG_INFO,"PARSE receiver #%d: STATE CHANGE: %s -> %s",
3690 CLK_UNIT(parse->peer), tmp2, tmp1);
3694 * carry on PPS information if still usable
3696 if (PARSE_PPS(parse->timedata.parse_state) && !PARSE_PPS(parsetime->parse_state))
3698 parsetime->parse_state |= PARSEB_PPS|PARSEB_S_PPS;
3699 parsetime->parse_ptime = parse->timedata.parse_ptime;
3703 * remember for future
3705 parse->timedata = *parsetime;
3708 * check to see, whether the clock did a complete powerup or lost PZF signal
3709 * and post correct events for current condition
3711 if (PARSE_POWERUP(parsetime->parse_state))
3714 * this is bad, as we have completely lost synchronisation
3715 * well this is a problem with the receiver here
3716 * for PARSE Meinberg DCF77 receivers the lost synchronisation
3717 * is true as it is the powerup state and the time is taken
3718 * from a crude real time clock chip
3719 * for the PZF series this is only partly true, as
3720 * PARSE_POWERUP only means that the pseudo random
3721 * phase shift sequence cannot be found. this is only
3722 * bad, if we have never seen the clock in the SYNC
3723 * state, where the PHASE and EPOCH are correct.
3724 * for reporting events the above business does not
3725 * really matter, but we can use the time code
3726 * even in the POWERUP state after having seen
3727 * the clock in the synchronized state (PZF class
3728 * receivers) unless we have had a telegram disruption
3729 * after having seen the clock in the SYNC state. we
3730 * thus require having seen the clock in SYNC state
3731 * *after* having missed telegrams (noresponse) from
3732 * the clock. one problem remains: we might use erroneously
3733 * POWERUP data if the disruption is shorter than 1 polling
3734 * interval. fortunately powerdowns last usually longer than 64
3735 * seconds and the receiver is at least 2 minutes in the
3736 * POWERUP or NOSYNC state before switching to SYNC
3738 parse_event(parse, CEVNT_FAULT);
3739 NLOG(NLOG_CLOCKSTATUS)
3741 msyslog(LOG_ERR,"PARSE receiver #%d: NOT SYNCHRONIZED",
3742 CLK_UNIT(parse->peer));
3747 * we have two states left
3750 * this state means that the EPOCH (timecode) and PHASE
3751 * information has be read correctly (at least two
3752 * successive PARSE timecodes were received correctly)
3753 * this is the best possible state - full trust
3756 * The clock should be on phase with respect to the second
3757 * signal, but the timecode has not been received correctly within
3758 * at least the last two minutes. this is a sort of half baked state
3759 * for PARSE Meinberg DCF77 clocks this is bad news (clock running
3760 * without timecode confirmation)
3761 * PZF 535 has also no time confirmation, but the phase should be
3762 * very precise as the PZF signal can be decoded
3765 if (PARSE_SYNC(parsetime->parse_state))
3768 * currently completely synchronized - best possible state
3770 parse->lastsync = current_time;
3771 clear_err(parse, ERR_BADSTATUS);
3776 * we have had some problems receiving the time code
3778 parse_event(parse, CEVNT_PROP);
3779 NLOG(NLOG_CLOCKSTATUS)
3781 msyslog(LOG_ERR,"PARSE receiver #%d: TIMECODE NOT CONFIRMED",
3782 CLK_UNIT(parse->peer));
3786 fudge = parse->generic->fudgetime1; /* standard RS232 Fudgefactor */
3788 if (PARSE_TIMECODE(parsetime->parse_state))
3790 rectime = parsetime->parse_stime.fp;
3791 off = reftime = parsetime->parse_time.fp;
3793 L_SUB(&off, &rectime); /* prepare for PPS adjustments logic */
3797 printf("PARSE receiver #%d: Reftime %s, Recvtime %s - initial offset %s\n",
3798 CLK_UNIT(parse->peer),
3799 prettydate(&reftime),
3800 prettydate(&rectime),
3805 if (PARSE_PPS(parsetime->parse_state) && CLK_PPS(parse->peer))
3808 double ppsphaseadjust = parse->ppsphaseadjust;
3812 * set fudge = 0.0 if already included in PPS time stamps
3814 if (parse->ppsparams.mode & (PPS_OFFSETCLEAR|PPS_OFFSETASSERT))
3816 ppsphaseadjust = 0.0;
3821 * we have a PPS signal - much better than the RS232 stuff (we hope)
3823 offset = parsetime->parse_ptime.fp;
3827 printf("PARSE receiver #%d: PPStime %s\n",
3828 CLK_UNIT(parse->peer),
3829 prettydate(&offset));
3831 if (PARSE_TIMECODE(parsetime->parse_state))
3833 if (M_ISGEQ(off.l_i, off.l_f, -1, 0x80000000) &&
3834 M_ISGEQ(0, 0x7fffffff, off.l_i, off.l_f))
3836 fudge = ppsphaseadjust; /* pick PPS fudge factor */
3839 * RS232 offsets within [-0.5..0.5[ - take PPS offsets
3842 if (parse->parse_type->cl_flags & PARSE_F_PPSONSECOND)
3844 reftime = off = offset;
3845 if (reftime.l_uf & (unsigned)0x80000000)
3851 * implied on second offset
3853 off.l_uf = ~off.l_uf; /* map [0.5..1[ -> [-0.5..0[ */
3854 off.l_ui = (off.l_f < 0) ? ~0 : 0; /* sign extend */
3859 * time code describes pulse
3861 reftime = off = parsetime->parse_time.fp;
3863 L_SUB(&off, &offset); /* true offset */
3867 * take RS232 offset when PPS when out of bounds
3872 fudge = ppsphaseadjust; /* pick PPS fudge factor */
3874 * Well, no time code to guide us - assume on second pulse
3875 * and pray, that we are within [-0.5..0.5[
3879 if (reftime.l_uf & (unsigned)0x80000000)
3883 * implied on second offset
3885 off.l_uf = ~off.l_uf; /* map [0.5..1[ -> [-0.5..0[ */
3886 off.l_ui = (off.l_f < 0) ? ~0 : 0; /* sign extend */
3891 if (!PARSE_TIMECODE(parsetime->parse_state))
3894 * Well, no PPS, no TIMECODE, no more work ...
3896 if ((parsetime->parse_status & CVT_ADDITIONAL) &&
3897 parse->parse_type->cl_message)
3898 parse->parse_type->cl_message(parse, parsetime);
3905 printf("PARSE receiver #%d: Reftime %s, Recvtime %s - final offset %s\n",
3906 CLK_UNIT(parse->peer),
3907 prettydate(&reftime),
3908 prettydate(&rectime),
3914 L_SUB(&rectime, &off); /* just to keep the ntp interface happy */
3918 printf("PARSE receiver #%d: calculated Reftime %s, Recvtime %s\n",
3919 CLK_UNIT(parse->peer),
3920 prettydate(&reftime),
3921 prettydate(&rectime));
3924 if ((parsetime->parse_status & CVT_ADDITIONAL) &&
3925 parse->parse_type->cl_message)
3926 parse->parse_type->cl_message(parse, parsetime);
3928 if (PARSE_SYNC(parsetime->parse_state))
3933 parse_event(parse, CEVNT_NOMINAL);
3936 clear_err(parse, ERR_BADIO);
3937 clear_err(parse, ERR_BADDATA);
3938 clear_err(parse, ERR_NODATA);
3939 clear_err(parse, ERR_INTERNAL);
3942 * and now stick it into the clock machine
3943 * samples are only valid iff lastsync is not too old and
3944 * we have seen the clock in sync at least once
3945 * after the last time we didn't see an expected data telegram
3946 * at startup being not in sync is also bad just like
3948 * see the clock states section above for more reasoning
3950 if (((current_time - parse->lastsync) > parse->maxunsync) ||
3951 (parse->lastsync < parse->lastmissed) ||
3952 ((parse->lastsync == 0) && !PARSE_SYNC(parsetime->parse_state)) ||
3953 PARSE_POWERUP(parsetime->parse_state))
3955 parse->generic->leap = LEAP_NOTINSYNC;
3956 parse->lastsync = 0; /* wait for full sync again */
3960 if (PARSE_LEAPADD(parsetime->parse_state))
3963 * we pick this state also for time code that pass leap warnings
3964 * without direction information (as earth is currently slowing
3967 parse->generic->leap = (parse->flags & PARSE_LEAP_DELETE) ? LEAP_DELSECOND : LEAP_ADDSECOND;
3970 if (PARSE_LEAPDEL(parsetime->parse_state))
3972 parse->generic->leap = LEAP_DELSECOND;
3976 parse->generic->leap = LEAP_NOWARNING;
3980 if (parse->generic->leap != LEAP_NOTINSYNC)
3983 * only good/trusted samples are interesting
3988 printf("PARSE receiver #%d: refclock_process_offset(reftime=%s, rectime=%s, Fudge=%f)\n",
3989 CLK_UNIT(parse->peer),
3990 prettydate(&reftime),
3991 prettydate(&rectime),
3995 parse->generic->lastref = reftime;
3997 refclock_process_offset(parse->generic, reftime, rectime, fudge);
4000 * pass PPS information on to PPS clock
4002 if (PARSE_PPS(parsetime->parse_state) && CLK_PPS(parse->peer))
4004 (void) pps_sample(&parse->timedata.parse_ptime.fp);
4005 parse_hardpps(parse, PARSE_HARDPPS_ENABLE);
4008 parse_hardpps(parse, PARSE_HARDPPS_DISABLE);
4012 * ready, unless the machine wants a sample or
4013 * we are in fast startup mode (peer->dist > MAXDISTANCE)
4015 if (!parse->pollneeddata && parse->peer->disp <= MAXDISTANCE)
4018 parse->pollneeddata = 0;
4020 parse->timedata.parse_state &= ~(unsigned)(PARSEB_PPS|PARSEB_S_PPS);
4022 refclock_receive(parse->peer);
4025 /**===========================================================================
4026 ** special code for special clocks
4043 snprintf(t, size, "current correction %d sec", dtls);
4052 gpstolfp((unsigned short)wnlsf, (unsigned short)dn, 0, &leapdate);
4054 if ((dtlsf != dtls) &&
4055 ((wnlsf - wnt) < 52))
4057 snprintf(t, BUFFER_SIZES(start, t, size), ", next correction %d sec on %s, new GPS-UTC offset %d",
4058 dtlsf - dtls, gmprettydate(&leapdate), dtlsf);
4062 snprintf(t, BUFFER_SIZES(start, t, size), ", last correction on %s",
4063 gmprettydate(&leapdate));
4067 #ifdef CLOCK_MEINBERG
4068 /**===========================================================================
4069 ** Meinberg GPS166/GPS167 support
4072 /*------------------------------------------------------------
4073 * gps16x_message - process GPS16x messages
4077 struct parseunit *parse,
4078 parsetime_t *parsetime
4081 if (parse->timedata.parse_msglen && parsetime->parse_msg[0] == SOH)
4084 unsigned char *bufp = (unsigned char *)parsetime->parse_msg + 1;
4089 char msgbuffer[600];
4091 mkreadable(msgbuffer, sizeof(msgbuffer), (char *)parsetime->parse_msg, parsetime->parse_msglen, 1);
4092 printf("PARSE receiver #%d: received message (%d bytes) >%s<\n",
4093 CLK_UNIT(parse->peer),
4094 parsetime->parse_msglen,
4098 get_mbg_header(&bufp, &header);
4099 if (header.gps_hdr_csum == mbg_csum(parsetime->parse_msg + 1, 6) &&
4100 (header.gps_len == 0 ||
4101 (header.gps_len < sizeof(parsetime->parse_msg) &&
4102 header.gps_data_csum == mbg_csum(bufp, header.gps_len))))
4107 switch (header.gps_cmd)
4114 get_mbg_sw_rev(&bufp, &gps_sw_rev);
4115 snprintf(buffer, sizeof(buffer), "meinberg_gps_version=\"%x.%02x%s%s\"",
4116 (gps_sw_rev.code >> 8) & 0xFF,
4117 gps_sw_rev.code & 0xFF,
4118 gps_sw_rev.name[0] ? " " : "",
4120 set_var(&parse->kv, buffer, strlen(buffer)+1, RO|DEF);
4128 unsigned short flag; /* status flag */
4129 unsigned const char *string; /* bit name */
4132 { TM_ANT_DISCONN, (const unsigned char *)"ANTENNA FAULTY" },
4133 { TM_SYN_FLAG, (const unsigned char *)"NO SYNC SIGNAL" },
4134 { TM_NO_SYNC, (const unsigned char *)"NO SYNC POWERUP" },
4135 { TM_NO_POS, (const unsigned char *)"NO POSITION" },
4136 { 0, (const unsigned char *)"" }
4138 unsigned short status;
4139 struct state *s = states;
4143 status = get_lsb_short(&bufp);
4144 snprintf(buffer, sizeof(buffer), "meinberg_gps_status=\"[0x%04x] ", status);
4148 p = b = buffer + strlen(buffer);
4151 if (status & s->flag)
4159 strncat(p, (const char *)s->string, sizeof(buffer));
4169 strncat(buffer, "<OK>\"", sizeof(buffer));
4172 set_var(&parse->kv, buffer, strlen(buffer)+1, RO|DEF);
4181 get_mbg_xyz(&bufp, xyz);
4182 snprintf(buffer, sizeof(buffer), "gps_position(XYZ)=\"%s m, %s m, %s m\"",
4183 mfptoa(xyz[XP].l_ui, xyz[XP].l_uf, 1),
4184 mfptoa(xyz[YP].l_ui, xyz[YP].l_uf, 1),
4185 mfptoa(xyz[ZP].l_ui, xyz[ZP].l_uf, 1));
4187 set_var(&parse->kv, buffer, sizeof(buffer), RO|DEF);
4196 get_mbg_lla(&bufp, lla);
4198 snprintf(buffer, sizeof(buffer), "gps_position(LLA)=\"%s deg, %s deg, %s m\"",
4199 mfptoa(lla[LAT].l_ui, lla[LAT].l_uf, 4),
4200 mfptoa(lla[LON].l_ui, lla[LON].l_uf, 4),
4201 mfptoa(lla[ALT].l_ui, lla[ALT].l_uf, 1));
4203 set_var(&parse->kv, buffer, sizeof(buffer), RO|DEF);
4222 get_mbg_antinfo(&bufp, &antinfo);
4223 snprintf(buffer, sizeof(buffer), "meinberg_antenna_status=\"");
4224 p = buffer + strlen(buffer);
4226 switch (antinfo.status)
4229 strncat(p, "<OK>", BUFFER_SIZE(buffer, p));
4234 strncat(p, "DISCONNECTED since ", BUFFER_SIZE(buffer, p));
4235 NLOG(NLOG_CLOCKSTATUS)
4237 msyslog(LOG_ERR,"PARSE receiver #%d: ANTENNA FAILURE: %s",
4238 CLK_UNIT(parse->peer), p);
4241 mbg_tm_str(&p, &antinfo.tm_disconn, BUFFER_SIZE(buffer, p));
4246 strncat(p, "RECONNECTED on ", BUFFER_SIZE(buffer, p));
4248 mbg_tm_str(&p, &antinfo.tm_reconn, BUFFER_SIZE(buffer, p));
4249 snprintf(p, BUFFER_SIZE(buffer, p), ", reconnect clockoffset %c%ld.%07ld s, disconnect time ",
4250 (antinfo.delta_t < 0) ? '-' : '+',
4251 ABS(antinfo.delta_t) / 10000,
4252 ABS(antinfo.delta_t) % 10000);
4254 mbg_tm_str(&p, &antinfo.tm_disconn, BUFFER_SIZE(buffer, p));
4259 snprintf(p, BUFFER_SIZE(buffer, p), "bad status 0x%04x", antinfo.status);
4264 strncat(p, "\"", BUFFER_SIZE(buffer, p));
4266 set_var(&parse->kv, buffer, strlen(buffer)+1, RO|DEF);
4279 get_mbg_cfgh(&bufp, &cfgh);
4285 strncpy(buffer, "gps_tot_51=\"", BUFFER_SIZE(buffer, p));
4287 mbg_tgps_str(&p, &cfgh.tot_51, BUFFER_SIZE(buffer, p));
4288 strncpy(p, "\"", BUFFER_SIZE(buffer, p));
4289 set_var(&parse->kv, buffer, strlen(buffer)+1, RO);
4292 strncpy(buffer, "gps_tot_63=\"", BUFFER_SIZE(buffer, p));
4294 mbg_tgps_str(&p, &cfgh.tot_63, BUFFER_SIZE(buffer, p));
4295 strncpy(p, "\"", BUFFER_SIZE(buffer, p));
4296 set_var(&parse->kv, buffer, strlen(buffer)+1, RO);
4299 strncpy(buffer, "gps_t0a=\"", BUFFER_SIZE(buffer, p));
4301 mbg_tgps_str(&p, &cfgh.t0a, BUFFER_SIZE(buffer, p));
4302 strncpy(p, "\"", BUFFER_SIZE(buffer, p));
4303 set_var(&parse->kv, buffer, strlen(buffer)+1, RO);
4305 for (i = MIN_SVNO; i < MAX_SVNO; i++)
4308 snprintf(p, BUFFER_SIZE(buffer, p), "gps_cfg[%d]=\"[0x%x] ", i, cfgh.cfg[i]);
4310 switch (cfgh.cfg[i] & 0x7)
4313 strncpy(p, "BLOCK I", BUFFER_SIZE(buffer, p));
4316 strncpy(p, "BLOCK II", BUFFER_SIZE(buffer, p));
4319 strncpy(p, "bad CFG", BUFFER_SIZE(buffer, p));
4322 strncat(p, "\"", BUFFER_SIZE(buffer, p));
4323 set_var(&parse->kv, buffer, strlen(buffer)+1, RO);
4326 snprintf(p, BUFFER_SIZE(buffer, p), "gps_health[%d]=\"[0x%x] ", i, cfgh.health[i]);
4328 switch ((cfgh.health[i] >> 5) & 0x7 )
4331 strncpy(p, "OK;", BUFFER_SIZE(buffer, p));
4334 strncpy(p, "PARITY;", BUFFER_SIZE(buffer, p));
4337 strncpy(p, "TLM/HOW;", BUFFER_SIZE(buffer, p));
4340 strncpy(p, "Z-COUNT;", BUFFER_SIZE(buffer, p));
4343 strncpy(p, "SUBFRAME 1,2,3;", BUFFER_SIZE(buffer, p));
4346 strncpy(p, "SUBFRAME 4,5;", BUFFER_SIZE(buffer, p));
4349 strncpy(p, "UPLOAD BAD;", BUFFER_SIZE(buffer, p));
4352 strncpy(p, "DATA BAD;", BUFFER_SIZE(buffer, p));
4358 switch (cfgh.health[i] & 0x1F)
4361 strncpy(p, "SIGNAL OK", BUFFER_SIZE(buffer, p));
4364 strncpy(p, "SV TEMP OUT", BUFFER_SIZE(buffer, p));
4367 strncpy(p, "SV WILL BE TEMP OUT", BUFFER_SIZE(buffer, p));
4372 strncpy(p, "MULTIPLE ERRS", BUFFER_SIZE(buffer, p));
4375 strncpy(p, "TRANSMISSION PROBLEMS", BUFFER_SIZE(buffer, p));
4379 strncat(p, "\"", sizeof(buffer));
4380 set_var(&parse->kv, buffer, strlen(buffer)+1, RO);
4400 get_mbg_utc(&bufp, &utc);
4404 strncpy(p, "gps_utc_correction=\"", sizeof(buffer));
4406 mk_utcinfo(p, utc.t0t.wn, utc.WNlsf, utc.DNt, utc.delta_tls, utc.delta_tlsf, BUFFER_SIZE(buffer, p));
4407 strncat(p, "\"", BUFFER_SIZE(buffer, p));
4411 strncpy(p, "gps_utc_correction=\"<NO UTC DATA>\"", BUFFER_SIZE(buffer, p));
4413 set_var(&parse->kv, buffer, strlen(buffer)+1, RO|DEF);
4422 ASCII_MSG gps_ascii_msg;
4425 get_mbg_ascii_msg(&bufp, &gps_ascii_msg);
4427 if (gps_ascii_msg.valid)
4430 mkreadable(buffer1, sizeof(buffer1), gps_ascii_msg.s, strlen(gps_ascii_msg.s), (int)0);
4432 snprintf(buffer, sizeof(buffer), "gps_message=\"%s\"", buffer1);
4435 strncpy(buffer, "gps_message=<NONE>", sizeof(buffer));
4437 set_var(&parse->kv, buffer, strlen(buffer)+1, RO|DEF);
4448 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)",
4449 CLK_UNIT(parse->peer),
4450 header.gps_hdr_csum, mbg_csum(parsetime->parse_msg + 1, 6),
4452 header.gps_data_csum, mbg_csum(bufp, (unsigned)((header.gps_len < sizeof(parsetime->parse_msg)) ? header.gps_len : 0)));
4459 /*------------------------------------------------------------
4460 * gps16x_poll - query the reciver peridically
4467 struct parseunit *parse = (struct parseunit *)peer->procptr->unitptr;
4469 static GPS_MSG_HDR sequence[] =
4471 { GPS_SW_REV, 0, 0, 0 },
4472 { GPS_STAT, 0, 0, 0 },
4473 { GPS_UTC, 0, 0, 0 },
4474 { GPS_ASCII_MSG, 0, 0, 0 },
4475 { GPS_ANT_INFO, 0, 0, 0 },
4476 { GPS_CFGH, 0, 0, 0 },
4477 { GPS_POS_XYZ, 0, 0, 0 },
4478 { GPS_POS_LLA, 0, 0, 0 },
4479 { (unsigned short)~0, 0, 0, 0 }
4483 unsigned char cmd_buffer[64];
4484 unsigned char *outp = cmd_buffer;
4485 GPS_MSG_HDR *header;
4487 if (((poll_info_t *)parse->parse_type->cl_data)->rate)
4489 parse->peer->nextaction = current_time + ((poll_info_t *)parse->parse_type->cl_data)->rate;
4492 if (sequence[parse->localstate].gps_cmd == (unsigned short)~0)
4493 parse->localstate = 0;
4495 header = sequence + parse->localstate++;
4497 *outp++ = SOH; /* start command */
4499 put_mbg_header(&outp, header);
4500 outp = cmd_buffer + 1;
4502 header->gps_hdr_csum = (short)mbg_csum(outp, 6);
4503 put_mbg_header(&outp, header);
4510 mkreadable(buffer, sizeof(buffer), (char *)cmd_buffer, (unsigned)(outp - cmd_buffer), 1);
4511 printf("PARSE receiver #%d: transmitted message #%ld (%d bytes) >%s<\n",
4512 CLK_UNIT(parse->peer),
4513 parse->localstate - 1,
4514 (int)(outp - cmd_buffer),
4519 rtc = write(parse->generic->io.fd, cmd_buffer, (unsigned long)(outp - cmd_buffer));
4524 msyslog(LOG_ERR, "PARSE receiver #%d: gps16x_poll: failed to send cmd to clock: %m", CLK_UNIT(parse->peer));
4527 if (rtc != outp - cmd_buffer)
4530 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));
4533 clear_err(parse, ERR_BADIO);
4537 /*--------------------------------------------------
4538 * init routine - setup timer
4542 struct parseunit *parse
4545 if (((poll_info_t *)parse->parse_type->cl_data)->rate)
4547 parse->peer->action = gps16x_poll;
4548 gps16x_poll(parse->peer);
4557 struct parseunit *parse,
4558 parsetime_t *parsetime
4563 struct parseunit *parse
4568 #endif /* CLOCK_MEINBERG */
4570 /**===========================================================================
4571 ** clock polling support
4574 /*--------------------------------------------------
4575 * direct poll routine
4579 struct parseunit *parse
4583 const char *ps = ((poll_info_t *)parse->parse_type->cl_data)->string;
4584 int ct = ((poll_info_t *)parse->parse_type->cl_data)->count;
4586 rtc = write(parse->generic->io.fd, ps, (unsigned long)ct);
4590 msyslog(LOG_ERR, "PARSE receiver #%d: poll_dpoll: failed to send cmd to clock: %m", CLK_UNIT(parse->peer));
4596 msyslog(LOG_ERR, "PARSE receiver #%d: poll_dpoll: failed to send cmd incomplete (%d of %d bytes sent)", CLK_UNIT(parse->peer), rtc, ct);
4598 clear_err(parse, ERR_BADIO);
4601 /*--------------------------------------------------
4602 * periodic poll routine
4609 struct parseunit *parse = (struct parseunit *)peer->procptr->unitptr;
4611 if (parse->parse_type->cl_poll)
4612 parse->parse_type->cl_poll(parse);
4614 if (((poll_info_t *)parse->parse_type->cl_data)->rate)
4616 parse->peer->nextaction = current_time + ((poll_info_t *)parse->parse_type->cl_data)->rate;
4620 /*--------------------------------------------------
4621 * init routine - setup timer
4625 struct parseunit *parse
4628 if (((poll_info_t *)parse->parse_type->cl_data)->rate)
4630 parse->peer->action = poll_poll;
4631 poll_poll(parse->peer);
4637 /**===========================================================================
4641 /*-------------------------------------------------------------
4642 * trimble TAIP init routine - setup EOL and then do poll_init.
4646 struct parseunit *parse
4652 #ifdef HAVE_SYSV_TTYS
4656 * configure terminal line for trimble receiver
4658 if (TTY_GETATTR(parse->generic->io.fd, &tio) == -1)
4660 msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_init: tcgetattr(fd, &tio): %m", CLK_UNIT(parse->peer));
4665 tio.c_cc[VEOL] = TRIMBLETAIP_EOL;
4667 if (TTY_SETATTR(parse->generic->io.fd, &tio) == -1)
4669 msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_init: tcsetattr(fd, &tio): %m", CLK_UNIT(parse->peer));
4673 return poll_init(parse);
4676 /*--------------------------------------------------
4677 * trimble TAIP event routine - reset receiver upon data format trouble
4679 static const char *taipinit[] = {
4681 ">SRM;ID_FLAG=F;CS_FLAG=T;EC_FLAG=F;FR_FLAG=T;CR_FLAG=F<",
4688 struct parseunit *parse,
4694 case CEVNT_BADREPLY: /* reset on garbled input */
4695 case CEVNT_TIMEOUT: /* reset on no input */
4702 int rtc = write(parse->generic->io.fd, *iv, strlen(*iv));
4705 msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_event: failed to send cmd to clock: %m", CLK_UNIT(parse->peer));
4710 if (rtc != strlen(*iv))
4712 msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_event: failed to send cmd incomplete (%d of %d bytes sent)",
4713 CLK_UNIT(parse->peer), rtc, (int)strlen(*iv));
4720 NLOG(NLOG_CLOCKINFO)
4722 msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_event: RECEIVER INITIALIZED",
4723 CLK_UNIT(parse->peer));
4727 default: /* ignore */
4733 * This driver supports the Trimble SVee Six Plus GPS receiver module.
4734 * It should support other Trimble receivers which use the Trimble Standard
4735 * Interface Protocol (see below).
4737 * The module has a serial I/O port for command/data and a 1 pulse-per-second
4738 * output, about 1 microsecond wide. The leading edge of the pulse is
4739 * coincident with the change of the GPS second. This is the same as
4740 * the change of the UTC second +/- ~1 microsecond. Some other clocks
4741 * specifically use a feature in the data message as a timing reference, but
4742 * the SVee Six Plus does not do this. In fact there is considerable jitter
4743 * on the timing of the messages, so this driver only supports the use
4744 * of the PPS pulse for accurate timing. Where it is determined that
4745 * the offset is way off, when first starting up ntpd for example,
4746 * the timing of the data stream is used until the offset becomes low enough
4747 * (|offset| < CLOCK_MAX), at which point the pps offset is used.
4749 * It can use either option for receiving PPS information - the 'ppsclock'
4750 * stream pushed onto the serial data interface to timestamp the Carrier
4751 * Detect interrupts, where the 1PPS connects to the CD line. This only
4752 * works on SunOS 4.1.x currently. To select this, define PPSPPS in
4753 * Config.local. The other option is to use a pulse-stretcher/level-converter
4754 * to convert the PPS pulse into a RS232 start pulse & feed this into another
4755 * tty port. To use this option, define PPSCLK in Config.local. The pps input,
4756 * by whichever method, is handled in ntp_loopfilter.c
4758 * The receiver uses a serial message protocol called Trimble Standard
4759 * Interface Protocol (it can support others but this driver only supports
4760 * TSIP). Messages in this protocol have the following form:
4762 * <DLE><id> ... <data> ... <DLE><ETX>
4764 * Any bytes within the <data> portion of value 10 hex (<DLE>) are doubled
4765 * on transmission and compressed back to one on reception. Otherwise
4766 * the values of data bytes can be anything. The serial interface is RS-422
4767 * asynchronous using 9600 baud, 8 data bits with odd party (**note** 9 bits
4768 * in total!), and 1 stop bit. The protocol supports byte, integer, single,
4769 * and double datatypes. Integers are two bytes, sent most significant first.
4770 * Singles are IEEE754 single precision floating point numbers (4 byte) sent
4771 * sign & exponent first. Doubles are IEEE754 double precision floating point
4772 * numbers (8 byte) sent sign & exponent first.
4773 * The receiver supports a large set of messages, only a small subset of
4774 * which are used here. From driver to receiver the following are used:
4778 * 21 Request current time
4780 * 2C Set/Request operating parameters
4781 * 2F Request UTC info
4782 * 35 Set/Request I/O options
4784 * From receiver to driver the following are recognised:
4789 * 44 Satellite selection, PDOP, mode
4790 * 46 Receiver health
4791 * 4B Machine code/status
4792 * 4C Report operating parameters (debug only)
4793 * 4F UTC correction data (used to get leap second warnings)
4794 * 55 I/O options (debug only)
4796 * All others are accepted but ignored.
4800 #define PI 3.1415926535898 /* lots of sig figs */
4801 #define D2R PI/180.0
4803 /*-------------------------------------------------------------------
4804 * sendcmd, sendbyte, sendetx, sendflt, sendint implement the command
4805 * interface to the receiver.
4807 * CAVEAT: the sendflt, sendint routines are byte order dependend and
4808 * float implementation dependend - these must be converted to portable
4811 * CURRENT LIMITATION: float implementation. This runs only on systems
4812 * with IEEE754 floats as native floats
4815 typedef struct trimble
4817 u_long last_msg; /* last message received */
4818 u_long last_reset; /* last time a reset was issued */
4819 u_char qtracking; /* query tracking status */
4820 u_long ctrack; /* current tracking set */
4821 u_long ltrack; /* last tracking set */
4833 short idx; /* index to first unused byte */
4834 u_char *txt; /* pointer to actual data buffer */
4837 void sendcmd P((struct txbuf *buf, int c));
4838 void sendbyte P((struct txbuf *buf, int b));
4839 void sendetx P((struct txbuf *buf, struct parseunit *parse));
4840 void sendint P((struct txbuf *buf, int a));
4841 void sendflt P((struct txbuf *buf, double a));
4850 buf->txt[1] = (u_char)c;
4854 void sendcmd P((struct txbuf *buf, int c));
4855 void sendbyte P((struct txbuf *buf, int b));
4856 void sendetx P((struct txbuf *buf, struct parseunit *parse));
4857 void sendint P((struct txbuf *buf, int a));
4858 void sendflt P((struct txbuf *buf, double a));
4867 buf->txt[buf->idx++] = DLE;
4868 buf->txt[buf->idx++] = (u_char)b;
4874 struct parseunit *parse
4877 buf->txt[buf->idx++] = DLE;
4878 buf->txt[buf->idx++] = ETX;
4880 if (write(parse->generic->io.fd, buf->txt, (unsigned long)buf->idx) != buf->idx)
4883 msyslog(LOG_ERR, "PARSE receiver #%d: sendetx: failed to send cmd to clock: %m", CLK_UNIT(parse->peer));
4892 mkreadable(buffer, sizeof(buffer), (char *)buf->txt, (unsigned)buf->idx, 1);
4893 printf("PARSE receiver #%d: transmitted message (%d bytes) >%s<\n",
4894 CLK_UNIT(parse->peer),
4898 clear_err(parse, ERR_BADIO);
4908 /* send 16bit int, msbyte first */
4909 sendbyte(buf, (u_char)((a>>8) & 0xff));
4910 sendbyte(buf, (u_char)(a & 0xff));
4923 #ifdef WORDS_BIGENDIAN
4924 for (i=0; i<=3; i++)
4926 for (i=3; i>=0; i--)
4928 sendbyte(buf, uval.bd[i]);
4931 #define TRIM_POS_OPT 0x13 /* output position with high precision */
4932 #define TRIM_TIME_OPT 0x03 /* use UTC time stamps, on second */
4934 /*--------------------------------------------------
4935 * trimble TSIP setup routine
4939 struct parseunit *parse,
4945 trimble_t *t = parse->localdata;
4947 if (t && t->last_reset &&
4948 ((t->last_reset + TRIMBLE_RESET_HOLDOFF) > current_time)) {
4949 return 1; /* not yet */
4953 t->last_reset = current_time;
4957 sendcmd(&buf, CMD_CVERSION); /* request software versions */
4958 sendetx(&buf, parse);
4960 sendcmd(&buf, CMD_COPERPARAM); /* set operating parameters */
4961 sendbyte(&buf, 4); /* static */
4962 sendflt(&buf, 5.0*D2R); /* elevation angle mask = 10 deg XXX */
4963 sendflt(&buf, 4.0); /* s/n ratio mask = 6 XXX */
4964 sendflt(&buf, 12.0); /* PDOP mask = 12 */
4965 sendflt(&buf, 8.0); /* PDOP switch level = 8 */
4966 sendetx(&buf, parse);
4968 sendcmd(&buf, CMD_CMODESEL); /* fix mode select */
4969 sendbyte(&buf, 1); /* time transfer mode */
4970 sendetx(&buf, parse);
4972 sendcmd(&buf, CMD_CMESSAGE); /* request system message */
4973 sendetx(&buf, parse);
4975 sendcmd(&buf, CMD_CSUPER); /* superpacket fix */
4976 sendbyte(&buf, 0x2); /* binary mode */
4977 sendetx(&buf, parse);
4979 sendcmd(&buf, CMD_CIOOPTIONS); /* set I/O options */
4980 sendbyte(&buf, TRIM_POS_OPT); /* position output */
4981 sendbyte(&buf, 0x00); /* no velocity output */
4982 sendbyte(&buf, TRIM_TIME_OPT); /* UTC, compute on seconds */
4983 sendbyte(&buf, 0x00); /* no raw measurements */
4984 sendetx(&buf, parse);
4986 sendcmd(&buf, CMD_CUTCPARAM); /* request UTC correction data */
4987 sendetx(&buf, parse);
4989 NLOG(NLOG_CLOCKINFO)
4991 msyslog(LOG_ERR, "PARSE receiver #%d: trimbletsip_setup: RECEIVER RE-INITIALIZED (%s)", CLK_UNIT(parse->peer), reason);
4996 /*--------------------------------------------------
4997 * TRIMBLE TSIP check routine
5004 struct parseunit *parse = (struct parseunit *)peer->procptr->unitptr;
5005 trimble_t *t = parse->localdata;
5012 if (current_time > t->last_msg + TRIMBLETSIP_IDLE_TIME)
5013 (void)trimbletsip_setup(parse, "message timeout");
5016 poll_poll(parse->peer); /* emit query string and re-arm timer */
5018 if (t && t->qtracking)
5020 u_long oldsats = t->ltrack & ~t->ctrack;
5023 t->ltrack = t->ctrack;
5029 for (i = 0; oldsats; i++) {
5030 if (oldsats & (1 << i))
5032 sendcmd(&buf, CMD_CSTATTRACK);
5033 sendbyte(&buf, i+1); /* old sat */
5034 sendetx(&buf, parse);
5036 oldsats &= ~(1 << i);
5040 sendcmd(&buf, CMD_CSTATTRACK);
5041 sendbyte(&buf, 0x00); /* current tracking set */
5042 sendetx(&buf, parse);
5046 /*--------------------------------------------------
5047 * TRIMBLE TSIP end routine
5051 struct parseunit *parse
5053 { trimble_t *t = parse->localdata;
5058 parse->localdata = (void *)0;
5060 parse->peer->nextaction = 0;
5061 parse->peer->action = (void (*) P((struct peer *)))0;
5064 /*--------------------------------------------------
5065 * TRIMBLE TSIP init routine
5069 struct parseunit *parse
5072 #if defined(VEOL) || defined(VEOL2)
5074 struct termios tio; /* NEEDED FOR A LONG TIME ! */
5076 #ifdef HAVE_SYSV_TTYS
5077 struct termio tio; /* NEEDED FOR A LONG TIME ! */
5080 * allocate local data area
5082 if (!parse->localdata)
5086 t = (trimble_t *)(parse->localdata = emalloc(sizeof(trimble_t)));
5090 memset((char *)t, 0, sizeof(trimble_t));
5091 t->last_msg = current_time;
5095 parse->peer->action = trimble_check;
5096 parse->peer->nextaction = current_time;
5099 * configure terminal line for ICANON mode with VEOL characters
5101 if (TTY_GETATTR(parse->generic->io.fd, &tio) == -1)
5103 msyslog(LOG_ERR, "PARSE receiver #%d: trimbletsip_init: tcgetattr(%d, &tio): %m", CLK_UNIT(parse->peer), parse->generic->io.fd);
5108 if ((parse_clockinfo[CLK_TYPE(parse->peer)].cl_lflag & ICANON))
5111 tio.c_cc[VEOL] = ETX;
5114 tio.c_cc[VEOL2] = DLE;
5118 if (TTY_SETATTR(parse->generic->io.fd, &tio) == -1)
5120 msyslog(LOG_ERR, "PARSE receiver #%d: trimbletsip_init: tcsetattr(%d, &tio): %m", CLK_UNIT(parse->peer), parse->generic->io.fd);
5125 return trimbletsip_setup(parse, "initial startup");
5128 /*------------------------------------------------------------
5129 * trimbletsip_event - handle Trimble events
5130 * simple evente handler - attempt to re-initialize receiver
5134 struct parseunit *parse,
5140 case CEVNT_BADREPLY: /* reset on garbled input */
5141 case CEVNT_TIMEOUT: /* reset on no input */
5142 (void)trimbletsip_setup(parse, "event BAD_REPLY/TIMEOUT");
5145 default: /* ignore */
5151 * getflt, getint convert fields in the incoming data into the
5152 * appropriate type of item
5154 * CAVEAT: these routines are currently definitely byte order dependent
5155 * and assume Representation(float) == IEEE754
5156 * These functions MUST be converted to portable versions (especially
5157 * converting the float representation into ntp_fp formats in order
5158 * to avoid floating point operations at all!
5168 #ifdef WORDS_BIGENDIAN
5173 #else /* ! WORDS_BIGENDIAN */
5178 #endif /* ! WORDS_BIGENDIAN */
5189 #ifdef WORDS_BIGENDIAN
5198 #else /* ! WORDS_BIGENDIAN */
5207 #endif /* ! WORDS_BIGENDIAN */
5216 return get_msb_short(&p);
5219 /*--------------------------------------------------
5220 * trimbletsip_message - process trimble messages
5222 #define RTOD (180.0 / 3.1415926535898)
5223 #define mb(_X_) (buffer[2+(_X_)]) /* shortcut for buffer access */
5226 trimbletsip_message(
5227 struct parseunit *parse,
5228 parsetime_t *parsetime
5231 unsigned char *buffer = parsetime->parse_msg;
5232 unsigned int size = parsetime->parse_msglen;
5235 (buffer[0] != DLE) ||
5236 (buffer[size-1] != ETX) ||
5237 (buffer[size-2] != DLE))
5243 printf("TRIMBLE BAD packet, size %d:\n ", size);
5244 for (i = 0; i < size; i++) {
5245 printf ("%2.2x, ", buffer[i]&0xff);
5246 if (i%16 == 15) printf("\n\t");
5256 trimble_t *tr = parse->localdata;
5257 unsigned int cmd = buffer[1];
5266 printf("TRIMBLE packet 0x%02x, size %d:\n ", cmd, size);
5267 for (i = 0; i < size; i++) {
5268 printf ("%2.2x, ", buffer[i]&0xff);
5269 if (i%16 == 15) printf("\n\t");
5276 tr->last_msg = current_time;
5278 s = trimble_convert(cmd, trimble_rcmds);
5282 snprintf(t, BUFFER_SIZE(pbuffer, t), "%s=\"", s->varname);
5286 DPRINTF(1, ("TRIMBLE UNKNOWN COMMAND 0x%02x\n", cmd));
5290 var_flag = s->varmode;
5297 snprintf(t, BUFFER_SIZE(pbuffer, t), "%f, %d, %f",
5298 getflt((unsigned char *)&mb(0)), getshort((unsigned char *)&mb(4)),
5299 getflt((unsigned char *)&mb(6)));
5303 strncpy(t, "mode: ", BUFFER_SIZE(pbuffer, t));
5305 switch (mb(0) & 0xF)
5308 snprintf(t, BUFFER_SIZE(pbuffer, t), "0x%x", mb(0) & 0x7);
5312 strncpy(t, "0D", BUFFER_SIZE(pbuffer, t));
5316 strncpy(t, "2D", BUFFER_SIZE(pbuffer, t));
5320 strncpy(t, "3D", BUFFER_SIZE(pbuffer, t));
5325 strncpy(t, "-MANUAL, ", BUFFER_SIZE(pbuffer, t));
5327 strncpy(t, "-AUTO, ", BUFFER_SIZE(pbuffer, t));
5330 snprintf(t, BUFFER_SIZE(pbuffer, t), "satellites %02d %02d %02d %02d, PDOP %.2f, HDOP %.2f, VDOP %.2f, TDOP %.2f",
5331 mb(1), mb(2), mb(3), mb(4),
5332 getflt((unsigned char *)&mb(5)),
5333 getflt((unsigned char *)&mb(9)),
5334 getflt((unsigned char *)&mb(13)),
5335 getflt((unsigned char *)&mb(17)));
5340 snprintf(t, BUFFER_SIZE(pbuffer, t), "%d.%d (%d/%d/%d)",
5341 mb(0)&0xff, mb(1)&0xff, 1900+(mb(4)&0xff), mb(2)&0xff, mb(3)&0xff);
5344 case CMD_RRECVHEALTH:
5346 static const char *msgs[] =
5348 "Battery backup failed",
5349 "Signal processor error",
5350 "Alignment error, channel or chip 1",
5351 "Alignment error, channel or chip 2",
5352 "Antenna feed line fault",
5353 "Excessive ref freq. error",
5360 switch (mb(0) & 0xFF)
5363 snprintf(t, BUFFER_SIZE(pbuffer, t), "illegal value 0x%02x", mb(0) & 0xFF);
5366 strncpy(t, "doing position fixes", BUFFER_SIZE(pbuffer, t));
5369 strncpy(t, "no GPS time yet", BUFFER_SIZE(pbuffer, t));
5372 strncpy(t, "PDOP too high", BUFFER_SIZE(pbuffer, t));
5375 strncpy(t, "no usable satellites", BUFFER_SIZE(pbuffer, t));
5378 strncpy(t, "only ONE usable satellite", BUFFER_SIZE(pbuffer, t));
5381 strncpy(t, "only TWO usable satellites", BUFFER_SIZE(pbuffer, t));
5384 strncpy(t, "only THREE usable satellites", BUFFER_SIZE(pbuffer, t));
5387 strncpy(t, "the chosen satellite is unusable", BUFFER_SIZE(pbuffer, t));
5393 bits = mb(1) & 0xFF;
5395 for (i = 0; i < 8; i++)
5396 if (bits & (0x1<<i))
5398 snprintf(t, BUFFER_SIZE(pbuffer, t), ", %s", msgs[i]);
5405 mkreadable(t, (int)BUFFER_SIZE(pbuffer, t), (char *)&mb(0), (unsigned)(size - 2 - (&mb(0) - buffer)), 0);
5410 static const char *msgs[] =
5412 "Synthesizer Fault",
5413 "Battery Powered Time Clock Fault",
5414 "A-to-D Converter Fault",
5415 "The almanac stored in the receiver is not complete and current",
5424 snprintf(t, BUFFER_SIZE(pbuffer, t), "machine id 0x%02x", mb(0) & 0xFF);
5427 bits = mb(1) & 0xFF;
5429 for (i = 0; i < 8; i++)
5430 if (bits & (0x1<<i))
5432 snprintf(t, BUFFER_SIZE(pbuffer, t), ", %s", msgs[i]);
5436 snprintf(t, BUFFER_SIZE(pbuffer, t), ", Superpackets %ssupported", (mb(2) & 0xFF) ? "" :"un" );
5440 case CMD_ROPERPARAM:
5441 snprintf(t, BUFFER_SIZE(pbuffer, t), "%2x %.1f %.1f %.1f %.1f",
5442 mb(0), getflt((unsigned char *)&mb(1)), getflt((unsigned char *)&mb(5)),
5443 getflt((unsigned char *)&mb(9)), getflt((unsigned char *)&mb(13)));
5448 float t0t = getflt((unsigned char *)&mb(14));
5449 short wnt = getshort((unsigned char *)&mb(18));
5450 short dtls = getshort((unsigned char *)&mb(12));
5451 short wnlsf = getshort((unsigned char *)&mb(20));
5452 short dn = getshort((unsigned char *)&mb(22));
5453 short dtlsf = getshort((unsigned char *)&mb(24));
5457 mk_utcinfo(t, wnt, wnlsf, dn, dtls, dtlsf, BUFFER_SIZE(pbuffer, t));
5461 strncpy(t, "<NO UTC DATA>", BUFFER_SIZE(pbuffer, t));
5467 snprintf(t, BUFFER_SIZE(pbuffer, t), "%.1fm %.2fm/s at %.1fs",
5468 getflt(&mb(0)), getflt(&mb(4)), getflt(&mb(8)));
5471 case CMD_RIOOPTIONS:
5473 snprintf(t, BUFFER_SIZE(pbuffer, t), "%02x %02x %02x %02x",
5474 mb(0), mb(1), mb(2), mb(3));
5475 if (mb(0) != TRIM_POS_OPT ||
5476 mb(2) != TRIM_TIME_OPT)
5478 (void)trimbletsip_setup(parse, "bad io options");
5485 double x = getflt((unsigned char *)&mb(0));
5486 double y = getflt((unsigned char *)&mb(4));
5487 double z = getflt((unsigned char *)&mb(8));
5488 double f = getflt((unsigned char *)&mb(12));
5491 snprintf(t, BUFFER_SIZE(pbuffer, t), "x= %.1fm, y= %.1fm, z= %.1fm, time_of_fix= %f sec",
5501 double lat = getflt((unsigned char *)&mb(0));
5502 double lng = getflt((unsigned char *)&mb(4));
5503 double f = getflt((unsigned char *)&mb(12));
5506 snprintf(t, BUFFER_SIZE(pbuffer, t), "lat %f %c, long %f %c, alt %.2fm",
5507 ((lat < 0.0) ? (-lat) : (lat))*RTOD, (lat < 0.0 ? 'S' : 'N'),
5508 ((lng < 0.0) ? (-lng) : (lng))*RTOD, (lng < 0.0 ? 'W' : 'E'),
5509 getflt((unsigned char *)&mb(8)));
5515 case CMD_RDOUBLEXYZ:
5517 double x = getdbl((unsigned char *)&mb(0));
5518 double y = getdbl((unsigned char *)&mb(8));
5519 double z = getdbl((unsigned char *)&mb(16));
5520 snprintf(t, BUFFER_SIZE(pbuffer, t), "x= %.1fm, y= %.1fm, z= %.1fm",
5525 case CMD_RDOUBLELLA:
5527 double lat = getdbl((unsigned char *)&mb(0));
5528 double lng = getdbl((unsigned char *)&mb(8));
5529 snprintf(t, BUFFER_SIZE(pbuffer, t), "lat %f %c, lon %f %c, alt %.2fm",
5530 ((lat < 0.0) ? (-lat) : (lat))*RTOD, (lat < 0.0 ? 'S' : 'N'),
5531 ((lng < 0.0) ? (-lng) : (lng))*RTOD, (lng < 0.0 ? 'W' : 'E'),
5532 getdbl((unsigned char *)&mb(16)));
5536 case CMD_RALLINVIEW:
5540 strncpy(t, "mode: ", BUFFER_SIZE(pbuffer, t));
5542 switch (mb(0) & 0x7)
5545 snprintf(t, BUFFER_SIZE(pbuffer, t), "0x%x", mb(0) & 0x7);
5549 strncpy(t, "2D", BUFFER_SIZE(pbuffer, t));
5553 strncpy(t, "3D", BUFFER_SIZE(pbuffer, t));
5558 strncpy(t, "-MANUAL, ", BUFFER_SIZE(pbuffer, t));
5560 strncpy(t, "-AUTO, ", BUFFER_SIZE(pbuffer, t));
5563 sats = (mb(0)>>4) & 0xF;
5565 snprintf(t, BUFFER_SIZE(pbuffer, t), "PDOP %.2f, HDOP %.2f, VDOP %.2f, TDOP %.2f, %d satellite%s in view: ",
5566 getflt((unsigned char *)&mb(1)),
5567 getflt((unsigned char *)&mb(5)),
5568 getflt((unsigned char *)&mb(9)),
5569 getflt((unsigned char *)&mb(13)),
5570 sats, (sats == 1) ? "" : "s");
5573 for (i=0; i < sats; i++)
5575 snprintf(t, BUFFER_SIZE(pbuffer, t), "%s%02d", i ? ", " : "", mb(17+i));
5578 tr->ctrack |= (1 << (mb(17+i)-1));
5582 { /* mark for tracking status query */
5588 case CMD_RSTATTRACK:
5590 snprintf(t-2, BUFFER_SIZE(pbuffer, t-2), "[%02d]=\"", mb(0)); /* add index to var name */
5593 if (getflt((unsigned char *)&mb(4)) < 0.0)
5595 strncpy(t, "<NO MEASUREMENTS>", BUFFER_SIZE(pbuffer, t));
5600 snprintf(t, BUFFER_SIZE(pbuffer, t), "ch=%d, acq=%s, eph=%d, signal_level= %5.2f, elevation= %5.2f, azimuth= %6.2f",
5602 mb(2) ? ((mb(2) == 1) ? "ACQ" : "SRCH") : "NEVER",
5604 getflt((unsigned char *)&mb(4)),
5605 getflt((unsigned char *)&mb(12)) * RTOD,
5606 getflt((unsigned char *)&mb(16)) * RTOD);
5611 strncpy(t, ", OLD", BUFFER_SIZE(pbuffer, t));
5617 strncpy(t, ", BAD PARITY", BUFFER_SIZE(pbuffer, t));
5620 strncpy(t, ", BAD EPH HEALTH", BUFFER_SIZE(pbuffer, t));
5624 strncpy(t, ", collecting data", BUFFER_SIZE(pbuffer, t));
5630 strncpy(t, "<UNDECODED>", BUFFER_SIZE(pbuffer, t));
5635 strncpy(t,"\"", BUFFER_SIZE(pbuffer, t));
5636 set_var(&parse->kv, pbuffer, sizeof(pbuffer), var_flag);
5641 /**============================================================
5645 /*--------------------------------------------------
5646 * rawdcf_init_1 - set up modem lines for RAWDCF receivers
5649 #if defined(TIOCMSET) && (defined(TIOCM_DTR) || defined(CIOCM_DTR))
5652 struct parseunit *parse
5655 /* fixed 2000 for using with Linux by Wolfram Pienkoss <wp@bszh.de> */
5657 * You can use the RS232 to supply the power for a DCF77 receiver.
5658 * Here a voltage between the DTR and the RTS line is used. Unfortunately
5659 * the name has changed from CIOCM_DTR to TIOCM_DTR recently.
5663 if (ioctl(parse->generic->io.fd, TIOCMGET, (caddr_t)&sl232) == -1)
5665 msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_1: WARNING: ioctl(fd, TIOCMGET, [C|T]IOCM_DTR): %m", CLK_UNIT(parse->peer));
5670 sl232 = (sl232 & ~TIOCM_RTS) | TIOCM_DTR; /* turn on DTR, clear RTS for power supply */
5672 sl232 = (sl232 & ~CIOCM_RTS) | CIOCM_DTR; /* turn on DTR, clear RTS for power supply */
5675 if (ioctl(parse->generic->io.fd, TIOCMSET, (caddr_t)&sl232) == -1)
5677 msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_1: WARNING: ioctl(fd, TIOCMSET, [C|T]IOCM_DTR): %m", CLK_UNIT(parse->peer));
5684 struct parseunit *parse
5687 msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_1: WARNING: OS interface incapable of setting DTR to power DCF modules", CLK_UNIT(parse->peer));
5690 #endif /* DTR initialisation type */
5692 /*--------------------------------------------------
5693 * rawdcf_init_2 - set up modem lines for RAWDCF receivers
5694 * CLR DTR line, SET RTS line
5696 #if defined(TIOCMSET) && (defined(TIOCM_RTS) || defined(CIOCM_RTS))
5699 struct parseunit *parse
5702 /* fixed 2000 for using with Linux by Wolfram Pienkoss <wp@bszh.de> */
5704 * You can use the RS232 to supply the power for a DCF77 receiver.
5705 * Here a voltage between the DTR and the RTS line is used. Unfortunately
5706 * the name has changed from CIOCM_DTR to TIOCM_DTR recently.
5710 if (ioctl(parse->generic->io.fd, TIOCMGET, (caddr_t)&sl232) == -1)
5712 msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_2: WARNING: ioctl(fd, TIOCMGET, [C|T]IOCM_RTS): %m", CLK_UNIT(parse->peer));
5717 sl232 = (sl232 & ~TIOCM_DTR) | TIOCM_RTS; /* turn on RTS, clear DTR for power supply */
5719 sl232 = (sl232 & ~CIOCM_DTR) | CIOCM_RTS; /* turn on RTS, clear DTR for power supply */
5722 if (ioctl(parse->generic->io.fd, TIOCMSET, (caddr_t)&sl232) == -1)
5724 msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_2: WARNING: ioctl(fd, TIOCMSET, [C|T]IOCM_RTS): %m", CLK_UNIT(parse->peer));
5731 struct parseunit *parse
5734 msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_2: WARNING: OS interface incapable of setting RTS to power DCF modules", CLK_UNIT(parse->peer));
5737 #endif /* DTR initialisation type */
5739 #else /* defined(REFCLOCK) && defined(PARSE) */
5740 int refclock_parse_bs;
5741 #endif /* defined(REFCLOCK) && defined(PARSE) */
5746 * refclock_parse.c,v
5747 * Revision 4.80 2007/08/11 12:06:29 kardel
5748 * update comments wrt/ to PPS
5750 * Revision 4.79 2007/08/11 11:52:23 kardel
5751 * - terminate io bindings before io_closeclock() will close our file descriptor
5753 * Revision 4.78 2006/12/22 20:08:27 kardel
5754 * Bug 746 (RFE): add configuration for Expert mouseCLOCK USB v2.0 as mode 19
5756 * Revision 4.77 2006/08/05 07:44:49 kardel
5757 * support optionally separate PPS devices via /dev/refclockpps-{0..3}
5759 * Revision 4.76 2006/06/22 18:40:47 kardel
5760 * clean up signedness (gcc 4)
5762 * Revision 4.75 2006/06/22 16:58:10 kardel
5763 * Bug #632: call parse_ppsapi() in parse_ctl() when updating
5764 * the PPS offset. Fix sign of offset passed to kernel.
5766 * Revision 4.74 2006/06/18 21:18:37 kardel
5767 * NetBSD Coverity CID 3796: possible NULL deref
5769 * Revision 4.73 2006/05/26 14:23:46 kardel
5770 * cleanup of copyright info
5772 * Revision 4.72 2006/05/26 14:19:43 kardel
5773 * cleanup of ioctl cruft
5775 * Revision 4.71 2006/05/26 14:15:57 kardel
5776 * delay adding refclock to async refclock io after all initializations
5778 * Revision 4.70 2006/05/25 18:20:50 kardel
5780 * terminate parse io engine after de-registering
5781 * from refclock io engine
5783 * Revision 4.69 2006/05/25 17:28:02 kardel
5784 * complete refclock io structure initialization *before* inserting it into the
5785 * refclock input machine (avoids null pointer deref) (bug #619)
5787 * Revision 4.68 2006/05/01 17:02:51 kardel
5788 * copy receiver method also for newlwy created receive buffers
5790 * Revision 4.67 2006/05/01 14:37:29 kardel
5791 * If an input buffer parses into more than one message do insert the
5792 * parsed message in a new input buffer instead of processing it
5793 * directly. This avoids deed complicated processing in signal
5796 * Revision 4.66 2006/03/18 00:45:30 kardel
5797 * coverity fixes found in NetBSD coverity scan
5799 * Revision 4.65 2006/01/26 06:08:33 kardel
5800 * output errno on PPS setup failure
5802 * Revision 4.64 2005/11/09 20:44:47 kardel
5803 * utilize full PPS timestamp resolution from PPS API
5805 * Revision 4.63 2005/10/07 22:10:25 kardel
5806 * bounded buffer implementation
5808 * Revision 4.62.2.2 2005/09/25 10:20:16 kardel
5809 * avoid unexpected buffer overflows due to sprintf("%f") on strange floats:
5810 * replace almost all str* and *printf functions be their buffer bounded
5813 * Revision 4.62.2.1 2005/08/27 16:19:27 kardel
5814 * limit re-set rate of trimble clocks
5816 * Revision 4.62 2005/08/06 17:40:00 kardel
5817 * cleanup size handling wrt/ to buffer boundaries
5819 * Revision 4.61 2005/07/27 21:16:19 kardel
5820 * fix a long (> 11 years) misconfiguration wrt/ Meinberg cflag factory
5821 * default setup. CSTOPB was missing for the 7E2 default data format of
5824 * Revision 4.60 2005/07/17 21:14:44 kardel
5825 * change contents of version string to include the RCS/CVS Id
5827 * Revision 4.59 2005/07/06 06:56:38 kardel
5830 * Revision 4.58 2005/07/04 13:10:40 kardel
5831 * fix bug 455: tripping over NULL pointer on cleanup
5832 * fix shadow storage logic for ppsphaseadjust and trustime wrt/ time2
5833 * fix compiler warnings for some platforms wrt/ printf formatstrings and
5834 * varying structure element sizes
5835 * reorder assignment in binding to avoid tripping over NULL pointers
5837 * Revision 4.57 2005/06/25 09:25:19 kardel
5838 * sort out log output sequence
5840 * Revision 4.56 2005/06/14 21:47:27 kardel
5841 * collect samples only if samples are ok (sync or trusted flywheel)
5842 * propagate pps phase adjustment value to kernel via PPSAPI to help HARDPPS
5843 * en- and dis-able HARDPPS in correlation to receiver sync state
5845 * Revision 4.55 2005/06/02 21:28:31 kardel
5846 * clarify trust logic
5848 * Revision 4.54 2005/06/02 17:06:49 kardel
5849 * change status reporting to use fixed refclock_report()
5851 * Revision 4.53 2005/06/02 16:33:31 kardel
5852 * fix acceptance of clocks unsync clocks right at start
5854 * Revision 4.52 2005/05/26 21:55:06 kardel
5855 * cleanup status reporting
5857 * Revision 4.51 2005/05/26 19:19:14 kardel
5858 * implement fast refclock startup
5860 * Revision 4.50 2005/04/16 20:51:35 kardel
5861 * set pps_enable = 1 when binding a kernel PPS source
5863 * Revision 4.49 2005/04/16 17:29:26 kardel
5864 * add non polling clock type 18 for just listenning to Meinberg clocks
5866 * Revision 4.48 2005/04/16 16:22:27 kardel
5867 * bk sync 20050415 ntp-dev
5869 * Revision 4.47 2004/11/29 10:42:48 kardel
5870 * bk sync ntp-dev 20041129
5872 * Revision 4.46 2004/11/29 10:26:29 kardel
5873 * keep fudgetime2 in sync with trusttime/ppsphaseadjust depending in flag1
5875 * Revision 4.45 2004/11/14 20:53:20 kardel
5876 * clear PPS flags after using them
5878 * Revision 4.44 2004/11/14 15:29:41 kardel
5879 * support PPSAPI, upgrade Copyright to Berkeley style
5881 * Revision 4.43 2001/05/26 22:53:16 kardel
5882 * 20010526 reconcilation
5884 * Revision 4.42 2000/05/14 15:31:51 kardel
5885 * PPSAPI && RAWDCF modemline support
5887 * Revision 4.41 2000/04/09 19:50:45 kardel
5888 * fixed rawdcfdtr_init() -> rawdcf_init_1
5890 * Revision 4.40 2000/04/09 15:27:55 kardel
5891 * modem line fiddle in rawdcf_init_2
5893 * Revision 4.39 2000/03/18 09:16:55 kardel
5894 * PPSAPI integration
5896 * Revision 4.38 2000/03/05 20:25:06 kardel
5899 * Revision 4.37 2000/03/05 20:11:14 kardel
5900 * 4.0.99g reconcilation
5902 * Revision 4.36 1999/11/28 17:18:20 kardel
5903 * disabled burst mode
5905 * Revision 4.35 1999/11/28 09:14:14 kardel
5908 * Revision 4.34 1999/05/14 06:08:05 kardel
5909 * store current_time in a suitable container (u_long)
5911 * Revision 4.33 1999/05/13 21:48:38 kardel
5912 * double the no response timeout interval
5914 * Revision 4.32 1999/05/13 20:09:13 kardel
5915 * complain only about missing polls after a full poll interval
5917 * Revision 4.31 1999/05/13 19:59:32 kardel
5918 * add clock type 16 for RTS set DTR clr in RAWDCF
5920 * Revision 4.30 1999/02/28 20:36:43 kardel
5923 * Revision 4.29 1999/02/28 19:58:23 kardel
5924 * updated copyright information
5926 * Revision 4.28 1999/02/28 19:01:50 kardel
5927 * improved debug out on sent Meinberg messages
5929 * Revision 4.27 1999/02/28 18:05:55 kardel
5930 * no linux/ppsclock.h stuff
5932 * Revision 4.26 1999/02/28 15:27:27 kardel
5933 * wharton clock integration
5935 * Revision 4.25 1999/02/28 14:04:46 kardel
5936 * added missing double quotes to UTC information string
5938 * Revision 4.24 1999/02/28 12:06:50 kardel
5939 * (parse_control): using gmprettydate instead of prettydate()
5940 * (mk_utcinfo): new function for formatting GPS derived UTC information
5941 * (gps16x_message): changed to use mk_utcinfo()
5942 * (trimbletsip_message): changed to use mk_utcinfo()
5943 * ignoring position information in unsynchronized mode
5944 * (parse_start): augument linux support for optional ASYNC_LOW_LATENCY
5946 * Revision 4.23 1999/02/23 19:47:53 kardel
5948 * (stream_receive): fixed formats
5950 * Revision 4.22 1999/02/22 06:21:02 kardel
5951 * use new autoconfig symbols
5953 * Revision 4.21 1999/02/21 12:18:13 kardel
5954 * 4.91f reconcilation
5956 * Revision 4.20 1999/02/21 10:53:36 kardel
5957 * initial Linux PPSkit version
5959 * Revision 4.19 1999/02/07 09:10:45 kardel
5960 * clarify STREAMS mitigation rules in comment
5962 * Revision 4.18 1998/12/20 23:45:34 kardel
5963 * fix types and warnings
5965 * Revision 4.17 1998/11/15 21:24:51 kardel
5966 * cannot access mbg_ routines when CLOCK_MEINBERG
5969 * Revision 4.16 1998/11/15 20:28:17 kardel
5970 * Release 4.0.73e13 reconcilation
5972 * Revision 4.15 1998/08/22 21:56:08 kardel
5973 * fixed IO handling for non-STREAM IO
5975 * Revision 4.14 1998/08/16 19:00:48 kardel
5976 * (gps16x_message): reduced UTC parameter information (dropped A0,A1)
5977 * made uval a local variable (killed one of the last globals)
5978 * (sendetx): added logging of messages when in debug mode
5979 * (trimble_check): added periodic checks to facilitate re-initialization
5980 * (trimbletsip_init): made use of EOL character if in non-kernel operation
5981 * (trimbletsip_message): extended message interpretation
5982 * (getdbl): fixed data conversion
5984 * Revision 4.13 1998/08/09 22:29:13 kardel
5985 * Trimble TSIP support
5987 * Revision 4.12 1998/07/11 10:05:34 kardel
5988 * Release 4.0.73d reconcilation
5990 * Revision 4.11 1998/06/14 21:09:42 kardel
5993 * Revision 4.10 1998/06/13 12:36:45 kardel
5994 * signed/unsigned, name clashes
5996 * Revision 4.9 1998/06/12 15:30:00 kardel
5999 * Revision 4.8 1998/06/12 11:19:42 kardel
6000 * added direct input processing routine for refclocks in
6001 * order to avaiod that single character io gobbles up all
6002 * receive buffers and drops input data. (Problem started
6003 * with fast machines so a character a buffer was possible
6004 * one of the few cases where faster machines break existing
6005 * allocation algorithms)
6007 * Revision 4.7 1998/06/06 18:35:20 kardel
6008 * (parse_start): added BURST mode initialisation
6010 * Revision 4.6 1998/05/27 06:12:46 kardel
6011 * RAWDCF_BASEDELAY default added
6012 * old comment removed
6015 * Revision 4.5 1998/05/25 22:05:09 kardel
6016 * RAWDCF_SETDTR option removed
6017 * clock type 14 attempts to set DTR for
6018 * power supply of RAWDCF receivers
6020 * Revision 4.4 1998/05/24 16:20:47 kardel
6021 * updated comments referencing Meinberg clocks
6022 * added RAWDCF clock with DTR set option as type 14
6024 * Revision 4.3 1998/05/24 10:48:33 kardel
6025 * calibrated CONRAD RAWDCF default fudge factor
6027 * Revision 4.2 1998/05/24 09:59:35 kardel
6028 * corrected version information (ntpq support)
6030 * Revision 4.1 1998/05/24 09:52:31 kardel
6031 * use fixed format only (new IO model)
6032 * output debug to stdout instead of msyslog()
6033 * don't include >"< in ASCII output in order not to confuse
6036 * Revision 4.0 1998/04/10 19:52:11 kardel
6037 * Start 4.0 release version numbering
6039 * Revision 1.2 1998/04/10 19:28:04 kardel
6040 * initial NTP VERSION 4 integration of PARSE with GPS166 binary support
6041 * derived from 3.105.1.2 from V3 tree
6043 * Revision information 3.1 - 3.105 from log deleted 1998/04/10 kardel