2 * /src/NTP/ntp-4/ntpd/refclock_parse.c,v 4.36 1999/11/28 17:18:20 kardel RELEASE_19991128_A
4 * refclock_parse.c,v 4.36 1999/11/28 17:18:20 kardel RELEASE_19991128_A
6 * generic reference clock driver for receivers
8 * optionally make use of a STREAMS module for input processing where
9 * available and configured. Currently the STREAMS module
10 * is only available for Suns running SunOS 4.x and SunOS5.x
12 * the STREAMS module is not required for operation and may be omitted
13 * at the cost of reduced accuracy. As new kernel interfaces emerger this
14 * restriction may be lifted in future.
16 * Copyright (c) 1995-1999 by Frank Kardel <kardel@acm.org>
17 * Copyright (c) 1989-1994 by Frank Kardel, Friedrich-Alexander Universität Erlangen-Nürnberg, Germany
19 * This software may not be sold for profit without a written consent
22 * This program is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
32 #if defined(REFCLOCK) && defined(CLOCK_PARSE)
35 * This driver currently provides the support for
36 * - Meinberg receiver DCF77 PZF 535 (TCXO version) (DCF)
37 * - Meinberg receiver DCF77 PZF 535 (OCXO version) (DCF)
38 * - Meinberg receiver DCF77 PZF 509 (DCF)
39 * - Meinberg receiver DCF77 AM receivers (e.g. C51) (DCF)
42 * - Schmid clock (DCF)
43 * - Conrad DCF77 receiver module (DCF)
44 * - FAU DCF77 NTP receiver (TimeBrick) (DCF)
46 * - Meinberg GPS166/GPS167 (GPS)
47 * - Trimble (TSIP and TAIP protocol) (GPS)
49 * - RCC8000 MSF Receiver (MSF)
50 * - WHARTON 400A Series clock (DCF)
51 * - VARITEXT clock (MSF)
55 * Meinberg receivers are usually connected via a
56 * 9600 baud serial line
58 * The Meinberg GPS receivers also have a special NTP time stamp
59 * format. The firmware release is Uni-Erlangen.
61 * Meinberg generic receiver setup:
62 * output time code every second
65 * Meinberg GPS16x setup:
66 * output time code every second
69 * This software supports the standard data formats used
70 * in Meinberg receivers.
72 * Special software versions are only sensible for the
73 * GPS 16x family of receivers.
75 * Meinberg can be reached via: http://www.meinberg.de/
79 #include "ntp_refclock.h"
80 #include "ntp_unixtime.h" /* includes <sys/time.h> */
81 #include "ntp_control.h"
85 #ifndef TM_IN_SYS_TIME
89 #if !defined(STREAM) && !defined(HAVE_SYSV_TTYS) && !defined(HAVE_BSD_TTYS) && !defined(HAVE_TERMIOS)
90 # include "Bletch: Define one of {STREAM,HAVE_SYSV_TTYS,HAVE_TERMIOS}"
94 # include <sys/stream.h>
95 # include <sys/stropts.h>
99 # define TTY_GETATTR(_FD_, _ARG_) tcgetattr((_FD_), (_ARG_))
100 # define TTY_SETATTR(_FD_, _ARG_) tcsetattr((_FD_), TCSANOW, (_ARG_))
101 # undef HAVE_SYSV_TTYS
104 #ifdef HAVE_SYSV_TTYS
105 # define TTY_GETATTR(_FD_, _ARG_) ioctl((_FD_), TCGETA, (_ARG_))
106 # define TTY_SETATTR(_FD_, _ARG_) ioctl((_FD_), TCSETAW, (_ARG_))
110 /* #error CURRENTLY NO BSD TTY SUPPORT */
111 # include "Bletch: BSD TTY not currently supported"
114 #ifdef HAVE_SYS_IOCTL_H
115 # include <sys/ioctl.h>
119 #ifdef HAVE_SYS_PPSCLOCK_H
120 #include <sys/ppsclock.h>
122 #ifdef HAVE_TIO_SERIAL_STUFF
123 #include <linux/serial.h>
128 #include "ntp_stdlib.h"
131 #include "mbg_gps166.h"
135 #include "ieee754io.h"
137 static char rcsid[]="refclock_parse.c,v 4.36 1999/11/28 17:18:20 kardel RELEASE_19991128_A";
139 /**===========================================================================
140 ** external interface to ntp mechanism
143 static void parse_init P((void));
144 static int parse_start P((int, struct peer *));
145 static void parse_shutdown P((int, struct peer *));
146 static void parse_poll P((int, struct peer *));
147 static void parse_control P((int, struct refclockstat *, struct refclockstat *, struct peer *));
149 #define parse_buginfo noentry
151 struct refclock refclock_parse = {
164 #define MAXUNITS 4 /* maximum number of "PARSE" units permitted */
165 #define PARSEDEVICE "/dev/refclock-%d" /* device to open %d is unit number */
168 #define ABS(_X_) (((_X_) < 0) ? -(_X_) : (_X_))
170 /**===========================================================================
171 ** function vector for dynamically binding io handling mechanism
174 struct parseunit; /* to keep inquiring minds happy */
178 const char *bd_description; /* name of type of binding */
179 int (*bd_init) P((struct parseunit *)); /* initialize */
180 void (*bd_end) P((struct parseunit *)); /* end */
181 int (*bd_setcs) P((struct parseunit *, parsectl_t *)); /* set character size */
182 int (*bd_disable) P((struct parseunit *)); /* disable */
183 int (*bd_enable) P((struct parseunit *)); /* enable */
184 int (*bd_getfmt) P((struct parseunit *, parsectl_t *)); /* get format */
185 int (*bd_setfmt) P((struct parseunit *, parsectl_t *)); /* setfmt */
186 int (*bd_timecode) P((struct parseunit *, parsectl_t *)); /* get time code */
187 void (*bd_receive) P((struct recvbuf *)); /* receive operation */
188 int (*bd_io_input) P((struct recvbuf *)); /* input operation */
191 #define PARSE_END(_X_) (*(_X_)->binding->bd_end)(_X_)
192 #define PARSE_SETCS(_X_, _CS_) (*(_X_)->binding->bd_setcs)(_X_, _CS_)
193 #define PARSE_ENABLE(_X_) (*(_X_)->binding->bd_enable)(_X_)
194 #define PARSE_DISABLE(_X_) (*(_X_)->binding->bd_disable)(_X_)
195 #define PARSE_GETFMT(_X_, _DCT_) (*(_X_)->binding->bd_getfmt)(_X_, _DCT_)
196 #define PARSE_SETFMT(_X_, _DCT_) (*(_X_)->binding->bd_setfmt)(_X_, _DCT_)
197 #define PARSE_GETTIMECODE(_X_, _DCT_) (*(_X_)->binding->bd_timecode)(_X_, _DCT_)
202 #define PARSE_F_PPSPPS 0x0001 /* use loopfilter PPS code (CIOGETEV) */
203 #define PARSE_F_PPSONSECOND 0x0002 /* PPS pulses are on second */
206 /**===========================================================================
207 ** error message regression handling
209 ** there are quite a few errors that can occur in rapid succession such as
210 ** noisy input data or no data at all. in order to reduce the amount of
211 ** syslog messages in such case, we are using a backoff algorithm. We limit
212 ** the number of error messages of a certain class to 1 per time unit. if a
213 ** configurable number of messages is displayed that way, we move on to the
214 ** next time unit / count for that class. a count of messages that have been
215 ** suppressed is held and displayed whenever a corresponding message is
216 ** displayed. the time units for a message class will also be displayed.
217 ** whenever an error condition clears we reset the error message state,
218 ** thus we would still generate much output on pathological conditions
219 ** where the system oscillates between OK and NOT OK states. coping
220 ** with that condition is currently considered too complicated.
223 #define ERR_ALL (unsigned)~0 /* "all" errors */
224 #define ERR_BADDATA (unsigned)0 /* unusable input data/conversion errors */
225 #define ERR_NODATA (unsigned)1 /* no input data */
226 #define ERR_BADIO (unsigned)2 /* read/write/select errors */
227 #define ERR_BADSTATUS (unsigned)3 /* unsync states */
228 #define ERR_BADEVENT (unsigned)4 /* non nominal events */
229 #define ERR_INTERNAL (unsigned)5 /* internal error */
230 #define ERR_CNT (unsigned)(ERR_INTERNAL+1)
232 #define ERR(_X_) if (list_err(parse, (_X_)))
234 struct errorregression
236 u_long err_count; /* number of repititions per class */
237 u_long err_delay; /* minimum delay between messages */
240 static struct errorregression
241 err_baddata[] = /* error messages for bad input data */
243 { 1, 0 }, /* output first message immediately */
244 { 5, 60 }, /* output next five messages in 60 second intervals */
245 { 3, 3600 }, /* output next 3 messages in hour intervals */
246 { 0, 12*3600 } /* repeat messages only every 12 hours */
249 static struct errorregression
250 err_nodata[] = /* error messages for missing input data */
252 { 1, 0 }, /* output first message immediately */
253 { 5, 60 }, /* output next five messages in 60 second intervals */
254 { 3, 3600 }, /* output next 3 messages in hour intervals */
255 { 0, 12*3600 } /* repeat messages only every 12 hours */
258 static struct errorregression
259 err_badstatus[] = /* unsynchronized state messages */
261 { 1, 0 }, /* output first message immediately */
262 { 5, 60 }, /* output next five messages in 60 second intervals */
263 { 3, 3600 }, /* output next 3 messages in hour intervals */
264 { 0, 12*3600 } /* repeat messages only every 12 hours */
267 static struct errorregression
268 err_badio[] = /* io failures (bad reads, selects, ...) */
270 { 1, 0 }, /* output first message immediately */
271 { 5, 60 }, /* output next five messages in 60 second intervals */
272 { 5, 3600 }, /* output next 3 messages in hour intervals */
273 { 0, 12*3600 } /* repeat messages only every 12 hours */
276 static struct errorregression
277 err_badevent[] = /* non nominal events */
279 { 20, 0 }, /* output first message immediately */
280 { 6, 60 }, /* output next five messages in 60 second intervals */
281 { 5, 3600 }, /* output next 3 messages in hour intervals */
282 { 0, 12*3600 } /* repeat messages only every 12 hours */
285 static struct errorregression
286 err_internal[] = /* really bad things - basically coding/OS errors */
288 { 0, 0 }, /* output all messages immediately */
291 static struct errorregression *
304 u_long err_started; /* begin time (ntp) of error condition */
305 u_long err_last; /* last time (ntp) error occurred */
306 u_long err_cnt; /* number of error repititions */
307 u_long err_suppressed; /* number of suppressed messages */
308 struct errorregression *err_stage; /* current error stage */
311 /**===========================================================================
312 ** refclock instance data
320 struct peer *peer; /* backlink to peer structure - refclock inactive if 0 */
321 struct refclockproc *generic; /* backlink to refclockproc structure */
326 bind_t *binding; /* io handling binding */
331 parse_t parseio; /* io handling structure (user level parsing) */
334 * type specific parameters
336 struct parse_clockinfo *parse_type; /* link to clock description */
339 * clock state handling/reporting
341 u_char flags; /* flags (leap_control) */
342 u_long lastchange; /* time (ntp) when last state change accured */
343 u_long statetime[CEVNT_MAX+1]; /* accumulated time of clock states */
344 u_long pollneeddata; /* current_time(!=0) for receive sample expected in PPS mode */
345 u_short lastformat; /* last format used */
346 u_long lastsync; /* time (ntp) when clock was last seen fully synchronized */
347 u_long lastmissed; /* time (ntp) when poll didn't get data (powerup heuristic) */
348 u_long ppsserial; /* magic cookie for ppsclock serials (avoids stale ppsclock data) */
349 parsetime_t time; /* last (parse module) data */
350 void *localdata; /* optional local, receiver-specific data */
351 unsigned long localstate; /* private local state */
352 struct errorinfo errors[ERR_CNT]; /* error state table for suppressing excessive error messages */
353 struct ctl_var *kv; /* additional pseudo variables */
354 u_long laststatistic; /* time when staticstics where output */
358 /**===========================================================================
359 ** Clockinfo section all parameter for specific clock types
360 ** includes NTP parameters, TTY parameters and IO handling parameters
363 static void poll_dpoll P((struct parseunit *));
364 static void poll_poll P((struct peer *));
365 static int poll_init P((struct parseunit *));
367 typedef struct poll_info
369 u_long rate; /* poll rate - once every "rate" seconds - 0 off */
370 const char *string; /* string to send for polling */
371 u_long count; /* number of characters in string */
374 #define NO_CL_FLAGS 0
381 #define NO_PPSDELAY 0
383 #define DCF_ID "DCF" /* generic DCF */
384 #define DCF_A_ID "DCFa" /* AM demodulation */
385 #define DCF_P_ID "DCFp" /* psuedo random phase shift */
386 #define GPS_ID "GPS" /* GPS receiver */
388 #define NOCLOCK_ROOTDELAY 0.0
389 #define NOCLOCK_BASEDELAY 0.0
390 #define NOCLOCK_DESCRIPTION 0
391 #define NOCLOCK_MAXUNSYNC 0
392 #define NOCLOCK_CFLAG 0
393 #define NOCLOCK_IFLAG 0
394 #define NOCLOCK_OFLAG 0
395 #define NOCLOCK_LFLAG 0
396 #define NOCLOCK_ID "TILT"
397 #define NOCLOCK_POLL NO_POLL
398 #define NOCLOCK_INIT NO_INIT
399 #define NOCLOCK_END NO_END
400 #define NOCLOCK_DATA NO_DATA
401 #define NOCLOCK_FORMAT ""
402 #define NOCLOCK_TYPE CTL_SST_TS_UNSPEC
403 #define NOCLOCK_SAMPLES 0
404 #define NOCLOCK_KEEP 0
406 #define DCF_TYPE CTL_SST_TS_LF
407 #define GPS_TYPE CTL_SST_TS_UHF
410 * receiver specific constants
412 #define MBG_SPEED (B9600)
413 #define MBG_CFLAG (CS7|PARENB|CREAD|CLOCAL|HUPCL)
414 #define MBG_IFLAG (IGNBRK|IGNPAR|ISTRIP)
417 #define MBG_FLAGS PARSE_F_PPSONSECOND
420 * Meinberg DCF77 receivers
422 #define DCFUA31_ROOTDELAY 0.0 /* 0 */
423 #define DCFUA31_BASEDELAY 0.010 /* 10.7421875ms: 10 ms (+/- 3 ms) */
424 #define DCFUA31_DESCRIPTION "Meinberg DCF77 C51 or compatible"
425 #define DCFUA31_MAXUNSYNC 60*30 /* only trust clock for 1/2 hour */
426 #define DCFUA31_SPEED MBG_SPEED
427 #define DCFUA31_CFLAG MBG_CFLAG
428 #define DCFUA31_IFLAG MBG_IFLAG
429 #define DCFUA31_OFLAG MBG_OFLAG
430 #define DCFUA31_LFLAG MBG_LFLAG
431 #define DCFUA31_SAMPLES 5
432 #define DCFUA31_KEEP 3
433 #define DCFUA31_FORMAT "Meinberg Standard"
436 * Meinberg DCF PZF535/TCXO (FM/PZF) receiver
438 #define DCFPZF535_ROOTDELAY 0.0
439 #define DCFPZF535_BASEDELAY 0.001968 /* 1.968ms +- 104us (oscilloscope) - relative to start (end of STX) */
440 #define DCFPZF535_DESCRIPTION "Meinberg DCF PZF 535/509 / TCXO"
441 #define DCFPZF535_MAXUNSYNC 60*60*12 /* only trust clock for 12 hours
442 * @ 5e-8df/f we have accumulated
443 * at most 2.16 ms (thus we move to
444 * NTP synchronisation */
445 #define DCFPZF535_SPEED MBG_SPEED
446 #define DCFPZF535_CFLAG MBG_CFLAG
447 #define DCFPZF535_IFLAG MBG_IFLAG
448 #define DCFPZF535_OFLAG MBG_OFLAG
449 #define DCFPZF535_LFLAG MBG_LFLAG
450 #define DCFPZF535_SAMPLES 5
451 #define DCFPZF535_KEEP 3
452 #define DCFPZF535_FORMAT "Meinberg Standard"
455 * Meinberg DCF PZF535/OCXO receiver
457 #define DCFPZF535OCXO_ROOTDELAY 0.0
458 #define DCFPZF535OCXO_BASEDELAY 0.001968 /* 1.968ms +- 104us (oscilloscope) - relative to start (end of STX) */
459 #define DCFPZF535OCXO_DESCRIPTION "Meinberg DCF PZF 535/509 / OCXO"
460 #define DCFPZF535OCXO_MAXUNSYNC 60*60*96 /* only trust clock for 4 days
461 * @ 5e-9df/f we have accumulated
462 * at most an error of 1.73 ms
463 * (thus we move to NTP synchronisation) */
464 #define DCFPZF535OCXO_SPEED MBG_SPEED
465 #define DCFPZF535OCXO_CFLAG MBG_CFLAG
466 #define DCFPZF535OCXO_IFLAG MBG_IFLAG
467 #define DCFPZF535OCXO_OFLAG MBG_OFLAG
468 #define DCFPZF535OCXO_LFLAG MBG_LFLAG
469 #define DCFPZF535OCXO_SAMPLES 5
470 #define DCFPZF535OCXO_KEEP 3
471 #define DCFPZF535OCXO_FORMAT "Meinberg Standard"
474 * Meinberg GPS16X receiver
476 static void gps16x_message P((struct parseunit *, parsetime_t *));
477 static int gps16x_poll_init P((struct parseunit *));
479 #define GPS16X_ROOTDELAY 0.0 /* nothing here */
480 #define GPS16X_BASEDELAY 0.001968 /* XXX to be fixed ! 1.968ms +- 104us (oscilloscope) - relative to start (end of STX) */
481 #define GPS16X_DESCRIPTION "Meinberg GPS16x receiver"
482 #define GPS16X_MAXUNSYNC 60*60*96 /* only trust clock for 4 days
483 * @ 5e-9df/f we have accumulated
484 * at most an error of 1.73 ms
485 * (thus we move to NTP synchronisation) */
486 #define GPS16X_SPEED B19200
487 #define GPS16X_CFLAG (CS8|CREAD|CLOCAL|HUPCL)
488 #define GPS16X_IFLAG (IGNBRK|IGNPAR)
489 #define GPS16X_OFLAG MBG_OFLAG
490 #define GPS16X_LFLAG MBG_LFLAG
491 #define GPS16X_POLLRATE 6
492 #define GPS16X_POLLCMD ""
493 #define GPS16X_CMDSIZE 0
495 static poll_info_t gps16x_pollinfo = { GPS16X_POLLRATE, GPS16X_POLLCMD, GPS16X_CMDSIZE };
497 #define GPS16X_INIT gps16x_poll_init
498 #define GPS16X_POLL 0
500 #define GPS16X_DATA ((void *)(&gps16x_pollinfo))
501 #define GPS16X_MESSAGE gps16x_message
502 #define GPS16X_ID GPS_ID
503 #define GPS16X_FORMAT "Meinberg GPS Extended"
504 #define GPS16X_SAMPLES 5
505 #define GPS16X_KEEP 3
508 * ELV DCF7000 Wallclock-Receiver/Switching Clock (Kit)
510 * This is really not the hottest clock - but before you have nothing ...
512 #define DCF7000_ROOTDELAY 0.0 /* 0 */
513 #define DCF7000_BASEDELAY 0.405 /* slow blow */
514 #define DCF7000_DESCRIPTION "ELV DCF7000"
515 #define DCF7000_MAXUNSYNC (60*5) /* sorry - but it just was not build as a clock */
516 #define DCF7000_SPEED (B9600)
517 #define DCF7000_CFLAG (CS8|CREAD|PARENB|PARODD|CLOCAL|HUPCL)
518 #define DCF7000_IFLAG (IGNBRK)
519 #define DCF7000_OFLAG 0
520 #define DCF7000_LFLAG 0
521 #define DCF7000_SAMPLES 5
522 #define DCF7000_KEEP 3
523 #define DCF7000_FORMAT "ELV DCF7000"
526 * Schmid DCF Receiver Kit
528 * When the WSDCF clock is operating optimally we want the primary clock
529 * distance to come out at 300 ms. Thus, peer.distance in the WSDCF peer
530 * structure is set to 290 ms and we compute delays which are at least
531 * 10 ms long. The following are 290 ms and 10 ms expressed in u_fp format
533 #define WS_POLLRATE 1 /* every second - watch interdependency with poll routine */
534 #define WS_POLLCMD "\163"
537 static poll_info_t wsdcf_pollinfo = { WS_POLLRATE, WS_POLLCMD, WS_CMDSIZE };
539 #define WSDCF_INIT poll_init
540 #define WSDCF_POLL poll_dpoll
542 #define WSDCF_DATA ((void *)(&wsdcf_pollinfo))
543 #define WSDCF_ROOTDELAY 0.0 /* 0 */
544 #define WSDCF_BASEDELAY 0.010 /* ~ 10ms */
545 #define WSDCF_DESCRIPTION "WS/DCF Receiver"
546 #define WSDCF_FORMAT "Schmid"
547 #define WSDCF_MAXUNSYNC (60*60) /* assume this beast hold at 1 h better than 2 ms XXX-must verify */
548 #define WSDCF_SPEED (B1200)
549 #define WSDCF_CFLAG (CS8|CREAD|CLOCAL)
550 #define WSDCF_IFLAG 0
551 #define WSDCF_OFLAG 0
552 #define WSDCF_LFLAG 0
553 #define WSDCF_SAMPLES 5
557 * RAW DCF77 - input of DCF marks via RS232 - many variants
559 #define RAWDCF_FLAGS 0
560 #define RAWDCF_ROOTDELAY 0.0 /* 0 */
561 #define RAWDCF_BASEDELAY 0.258
562 #define RAWDCF_FORMAT "RAW DCF77 Timecode"
563 #define RAWDCF_MAXUNSYNC (0) /* sorry - its a true receiver - no signal - no time */
564 #define RAWDCF_SPEED (B50)
565 #ifdef NO_PARENB_IGNPAR /* Was: defined(SYS_IRIX4) || defined(SYS_IRIX5) */
566 /* somehow doesn't grok PARENB & IGNPAR (mj) */
567 # define RAWDCF_CFLAG (CS8|CREAD|CLOCAL)
569 # define RAWDCF_CFLAG (CS8|CREAD|CLOCAL|PARENB)
571 #ifdef RAWDCF_NO_IGNPAR /* Was: defined(SYS_LINUX) && defined(CLOCK_RAWDCF) */
572 # define RAWDCF_IFLAG 0
574 # define RAWDCF_IFLAG (IGNPAR)
576 #define RAWDCF_OFLAG 0
577 #define RAWDCF_LFLAG 0
578 #define RAWDCF_SAMPLES 20
579 #define RAWDCF_KEEP 12
580 #define RAWDCF_INIT 0
588 * simplest (cheapest) DCF clock - e. g. DCF77 receiver by Conrad
589 * (~40DM - roughly $30 ) followed by a level converter for RS232
591 #define CONRAD_BASEDELAY 0.292 /* Conrad receiver @ 50 Baud on a Sun */
592 #define CONRAD_DESCRIPTION "RAW DCF77 CODE (Conrad DCF77 receiver module)"
597 #define TIMEBRICK_BASEDELAY 0.210 /* TimeBrick @ 50 Baud on a Sun */
598 #define TIMEBRICK_DESCRIPTION "RAW DCF77 CODE (TimeBrick)"
601 * IGEL:clock receiver
603 #define IGELCLOCK_BASEDELAY 0.258 /* IGEL:clock receiver */
604 #define IGELCLOCK_DESCRIPTION "RAW DCF77 CODE (IGEL:clock)"
605 #define IGELCLOCK_SPEED (B1200)
606 #define IGELCLOCK_CFLAG (CS8|CREAD|HUPCL|CLOCAL)
609 * RAWDCF receivers that need to be powered from DTR
610 * (like Expert mouse clock)
612 static int rawdcf_init_1 P((struct parseunit *));
613 #define RAWDCFDTRSET_DESCRIPTION "RAW DCF77 CODE (DTR SET/RTS CLR)"
614 #define RAWDCFDTRSET_INIT rawdcf_init_1
617 * RAWDCF receivers that need to be powered from
618 * DTR CLR and RTS SET
620 static int rawdcf_init_2 P((struct parseunit *));
621 #define RAWDCFDTRCLRRTSSET_DESCRIPTION "RAW DCF77 CODE (DTR CLR/RTS SET)"
622 #define RAWDCFDTRCLRRTSSET_INIT rawdcf_init_2
625 * Trimble GPS receivers (TAIP and TSIP protocols)
627 #ifndef TRIM_POLLRATE
628 #define TRIM_POLLRATE 0 /* only true direct polling */
631 #define TRIM_TAIPPOLLCMD ">SRM;FR_FLAG=F;EC_FLAG=F<>QTM<"
632 #define TRIM_TAIPCMDSIZE (sizeof(TRIM_TAIPPOLLCMD)-1)
634 static poll_info_t trimbletaip_pollinfo = { TRIM_POLLRATE, TRIM_TAIPPOLLCMD, TRIM_TAIPCMDSIZE };
635 static int trimbletaip_init P((struct parseunit *));
636 static void trimbletaip_event P((struct parseunit *, int));
638 /* query time & UTC correction data */
639 static char tsipquery[] = { DLE, 0x21, DLE, ETX, DLE, 0x2F, DLE, ETX };
641 static poll_info_t trimbletsip_pollinfo = { TRIM_POLLRATE, tsipquery, sizeof(tsipquery) };
642 static int trimbletsip_init P((struct parseunit *));
643 static void trimbletsip_end P((struct parseunit *));
644 static void trimbletsip_message P((struct parseunit *, parsetime_t *));
645 static void trimbletsip_event P((struct parseunit *, int));
647 #define TRIMBLETSIP_IDLE_TIME (300) /* 5 minutes silence at most */
649 #define TRIMBLETAIP_SPEED (B4800)
650 #define TRIMBLETAIP_CFLAG (CS8|CREAD|CLOCAL)
651 #define TRIMBLETAIP_IFLAG (BRKINT|IGNPAR|ISTRIP|ICRNL|IXON)
652 #define TRIMBLETAIP_OFLAG (OPOST|ONLCR)
653 #define TRIMBLETAIP_LFLAG (0)
655 #define TRIMBLETSIP_SPEED (B9600)
656 #define TRIMBLETSIP_CFLAG (CS8|CLOCAL|CREAD|PARENB|PARODD)
657 #define TRIMBLETSIP_IFLAG (IGNBRK)
658 #define TRIMBLETSIP_OFLAG (0)
659 #define TRIMBLETSIP_LFLAG (ICANON)
661 #define TRIMBLETSIP_SAMPLES 5
662 #define TRIMBLETSIP_KEEP 3
663 #define TRIMBLETAIP_SAMPLES 5
664 #define TRIMBLETAIP_KEEP 3
666 #define TRIMBLETAIP_FLAGS (PARSE_F_PPSONSECOND)
667 #define TRIMBLETSIP_FLAGS (TRIMBLETAIP_FLAGS)
669 #define TRIMBLETAIP_POLL poll_dpoll
670 #define TRIMBLETSIP_POLL poll_dpoll
672 #define TRIMBLETAIP_INIT trimbletaip_init
673 #define TRIMBLETSIP_INIT trimbletsip_init
675 #define TRIMBLETAIP_EVENT trimbletaip_event
677 #define TRIMBLETSIP_EVENT trimbletsip_event
678 #define TRIMBLETSIP_MESSAGE trimbletsip_message
680 #define TRIMBLETAIP_END 0
681 #define TRIMBLETSIP_END trimbletsip_end
683 #define TRIMBLETAIP_DATA ((void *)(&trimbletaip_pollinfo))
684 #define TRIMBLETSIP_DATA ((void *)(&trimbletsip_pollinfo))
686 #define TRIMBLETAIP_ID GPS_ID
687 #define TRIMBLETSIP_ID GPS_ID
689 #define TRIMBLETAIP_FORMAT "Trimble TAIP"
690 #define TRIMBLETSIP_FORMAT "Trimble TSIP"
692 #define TRIMBLETAIP_ROOTDELAY 0x0
693 #define TRIMBLETSIP_ROOTDELAY 0x0
695 #define TRIMBLETAIP_BASEDELAY 0.0
696 #define TRIMBLETSIP_BASEDELAY 0.020 /* GPS time message latency */
698 #define TRIMBLETAIP_DESCRIPTION "Trimble GPS (TAIP) receiver"
699 #define TRIMBLETSIP_DESCRIPTION "Trimble GPS (TSIP) receiver"
701 #define TRIMBLETAIP_MAXUNSYNC 0
702 #define TRIMBLETSIP_MAXUNSYNC 0
704 #define TRIMBLETAIP_EOL '<'
707 * RadioCode Clocks RCC 800 receiver
709 #define RCC_POLLRATE 0 /* only true direct polling */
710 #define RCC_POLLCMD "\r"
711 #define RCC_CMDSIZE 1
713 static poll_info_t rcc8000_pollinfo = { RCC_POLLRATE, RCC_POLLCMD, RCC_CMDSIZE };
714 #define RCC8000_FLAGS 0
715 #define RCC8000_POLL poll_dpoll
716 #define RCC8000_INIT poll_init
717 #define RCC8000_END 0
718 #define RCC8000_DATA ((void *)(&rcc8000_pollinfo))
719 #define RCC8000_ROOTDELAY 0.0
720 #define RCC8000_BASEDELAY 0.0
721 #define RCC8000_ID "MSF"
722 #define RCC8000_DESCRIPTION "RCC 8000 MSF Receiver"
723 #define RCC8000_FORMAT "Radiocode RCC8000"
724 #define RCC8000_MAXUNSYNC (60*60) /* should be ok for an hour */
725 #define RCC8000_SPEED (B2400)
726 #define RCC8000_CFLAG (CS8|CREAD|CLOCAL)
727 #define RCC8000_IFLAG (IGNBRK|IGNPAR)
728 #define RCC8000_OFLAG 0
729 #define RCC8000_LFLAG 0
730 #define RCC8000_SAMPLES 5
731 #define RCC8000_KEEP 3
734 * Hopf Radio clock 6021 Format
737 #define HOPF6021_ROOTDELAY 0.0
738 #define HOPF6021_BASEDELAY 0.0
739 #define HOPF6021_DESCRIPTION "HOPF 6021"
740 #define HOPF6021_FORMAT "hopf Funkuhr 6021"
741 #define HOPF6021_MAXUNSYNC (60*60) /* should be ok for an hour */
742 #define HOPF6021_SPEED (B9600)
743 #define HOPF6021_CFLAG (CS8|CREAD|CLOCAL)
744 #define HOPF6021_IFLAG (IGNBRK|ISTRIP)
745 #define HOPF6021_OFLAG 0
746 #define HOPF6021_LFLAG 0
747 #define HOPF6021_FLAGS 0
748 #define HOPF6021_SAMPLES 5
749 #define HOPF6021_KEEP 3
752 * Diem's Computime Radio Clock Receiver
754 #define COMPUTIME_FLAGS 0
755 #define COMPUTIME_ROOTDELAY 0.0
756 #define COMPUTIME_BASEDELAY 0.0
757 #define COMPUTIME_ID DCF_ID
758 #define COMPUTIME_DESCRIPTION "Diem's Computime receiver"
759 #define COMPUTIME_FORMAT "Diem's Computime Radio Clock"
760 #define COMPUTIME_TYPE DCF_TYPE
761 #define COMPUTIME_MAXUNSYNC (60*60) /* only trust clock for 1 hour */
762 #define COMPUTIME_SPEED (B9600)
763 #define COMPUTIME_CFLAG (CSTOPB|CS7|CREAD|CLOCAL)
764 #define COMPUTIME_IFLAG (IGNBRK|IGNPAR|ISTRIP)
765 #define COMPUTIME_OFLAG 0
766 #define COMPUTIME_LFLAG 0
767 #define COMPUTIME_SAMPLES 5
768 #define COMPUTIME_KEEP 3
771 * Varitext Radio Clock Receiver
773 #define VARITEXT_FLAGS 0
774 #define VARITEXT_ROOTDELAY 0.0
775 #define VARITEXT_BASEDELAY 0.0
776 #define VARITEXT_ID "MSF"
777 #define VARITEXT_DESCRIPTION "Varitext receiver"
778 #define VARITEXT_FORMAT "Varitext Radio Clock"
779 #define VARITEXT_TYPE DCF_TYPE
780 #define VARITEXT_MAXUNSYNC (60*60) /* only trust clock for 1 hour */
781 #define VARITEXT_SPEED (B9600)
782 #define VARITEXT_CFLAG (CS7|CREAD|CLOCAL|PARENB|PARODD)
783 #define VARITEXT_IFLAG (IGNPAR|IGNBRK|INPCK) /*|ISTRIP)*/
784 #define VARITEXT_OFLAG 0
785 #define VARITEXT_LFLAG 0
786 #define VARITEXT_SAMPLES 32
787 #define VARITEXT_KEEP 20
789 static struct parse_clockinfo
791 u_long cl_flags; /* operation flags (io modes) */
792 void (*cl_poll) P((struct parseunit *)); /* active poll routine */
793 int (*cl_init) P((struct parseunit *)); /* active poll init routine */
794 void (*cl_event) P((struct parseunit *, int)); /* special event handling (e.g. reset clock) */
795 void (*cl_end) P((struct parseunit *)); /* active poll end routine */
796 void (*cl_message) P((struct parseunit *, parsetime_t *)); /* process a lower layer message */
797 void *cl_data; /* local data area for "poll" mechanism */
798 double cl_rootdelay; /* rootdelay */
799 double cl_basedelay; /* current offset by which the RS232
800 time code is delayed from the actual time */
801 const char *cl_id; /* ID code */
802 const char *cl_description; /* device name */
803 const char *cl_format; /* fixed format */
804 u_char cl_type; /* clock type (ntp control) */
805 u_long cl_maxunsync; /* time to trust oscillator after loosing synch */
806 u_long cl_speed; /* terminal input & output baudrate */
807 u_long cl_cflag; /* terminal control flags */
808 u_long cl_iflag; /* terminal input flags */
809 u_long cl_oflag; /* terminal output flags */
810 u_long cl_lflag; /* terminal local flags */
811 u_long cl_samples; /* samples for median filter */
812 u_long cl_keep; /* samples for median filter to keep */
813 } parse_clockinfo[] =
826 DCFPZF535_DESCRIPTION,
846 DCFPZF535OCXO_ROOTDELAY,
847 DCFPZF535OCXO_BASEDELAY,
849 DCFPZF535OCXO_DESCRIPTION,
850 DCFPZF535OCXO_FORMAT,
852 DCFPZF535OCXO_MAXUNSYNC,
858 DCFPZF535OCXO_SAMPLES,
964 TIMEBRICK_DESCRIPTION,
1008 IGELCLOCK_BASEDELAY,
1010 IGELCLOCK_DESCRIPTION,
1024 #if TRIM_POLLRATE /* DHD940515: Allow user config */
1034 TRIMBLETAIP_ROOTDELAY,
1035 TRIMBLETAIP_BASEDELAY,
1037 TRIMBLETAIP_DESCRIPTION,
1040 TRIMBLETAIP_MAXUNSYNC,
1046 TRIMBLETAIP_SAMPLES,
1051 #if TRIM_POLLRATE /* DHD940515: Allow user config */
1059 TRIMBLETSIP_MESSAGE,
1061 TRIMBLETSIP_ROOTDELAY,
1062 TRIMBLETSIP_BASEDELAY,
1064 TRIMBLETSIP_DESCRIPTION,
1067 TRIMBLETSIP_MAXUNSYNC,
1073 TRIMBLETSIP_SAMPLES,
1087 RCC8000_DESCRIPTION,
1110 HOPF6021_DESCRIPTION,
1130 COMPUTIME_ROOTDELAY,
1131 COMPUTIME_BASEDELAY,
1133 COMPUTIME_DESCRIPTION,
1136 COMPUTIME_MAXUNSYNC,
1156 RAWDCFDTRSET_DESCRIPTION,
1169 0, /* operation flags (io modes) */
1170 NO_POLL, /* active poll routine */
1171 NO_INIT, /* active poll init routine */
1172 NO_EVENT, /* special event handling (e.g. reset clock) */
1173 NO_END, /* active poll end routine */
1174 NO_MESSAGE, /* process a lower layer message */
1175 NO_DATA, /* local data area for "poll" mechanism */
1177 11.0 /* bits */ / 9600, /* current offset by which the RS232
1178 time code is delayed from the actual time */
1179 DCF_ID, /* ID code */
1180 "WHARTON 400A Series clock", /* device name */
1181 "WHARTON 400A Series clock Output Format 1", /* fixed format */
1182 /* Must match a format-name in a libparse/clk_xxx.c file */
1183 DCF_TYPE, /* clock type (ntp control) */
1184 (1*60*60), /* time to trust oscillator after loosing synch */
1185 B9600, /* terminal input & output baudrate */
1186 (CS8|CREAD|PARENB|CLOCAL|HUPCL),/* terminal control flags */
1187 0, /* terminal input flags */
1188 0, /* terminal output flags */
1189 0, /* terminal local flags */
1190 5, /* samples for median filter */
1191 3, /* samples for median filter to keep */
1193 { /* mode 16 - RAWDCF RTS set, DTR clr */
1196 RAWDCFDTRCLRRTSSET_INIT,
1204 RAWDCFDTRCLRRTSSET_DESCRIPTION,
1227 VARITEXT_DESCRIPTION,
1241 static int ncltypes = sizeof(parse_clockinfo) / sizeof(struct parse_clockinfo);
1243 #define CLK_REALTYPE(x) ((int)(((x)->ttlmax) & 0x7F))
1244 #define CLK_TYPE(x) ((CLK_REALTYPE(x) >= ncltypes) ? ~0 : CLK_REALTYPE(x))
1245 #define CLK_UNIT(x) ((int)REFCLOCKUNIT(&(x)->srcadr))
1246 #define CLK_PPS(x) (((x)->ttlmax) & 0x80)
1249 * Other constant stuff
1251 #define PARSEHSREFID 0x7f7f08ff /* 127.127.8.255 refid for hi strata */
1253 #define PARSESTATISTICS (60*60) /* output state statistics every hour */
1255 static struct parseunit *parseunits[MAXUNITS];
1257 static int notice = 0;
1259 #define PARSE_STATETIME(parse, i) ((parse->generic->currentstatus == i) ? parse->statetime[i] + current_time - parse->lastchange : parse->statetime[i])
1261 static void parse_event P((struct parseunit *, int));
1262 static void parse_process P((struct parseunit *, parsetime_t *));
1263 static void clear_err P((struct parseunit *, u_long));
1264 static int list_err P((struct parseunit *, u_long));
1265 static char * l_mktime P((u_long));
1267 /**===========================================================================
1268 ** implementation error message regression module
1272 struct parseunit *parse,
1276 if (lstate == ERR_ALL)
1280 for (i = 0; i < ERR_CNT; i++)
1282 parse->errors[i].err_stage = err_tbl[i];
1283 parse->errors[i].err_cnt = 0;
1284 parse->errors[i].err_last = 0;
1285 parse->errors[i].err_started = 0;
1286 parse->errors[i].err_suppressed = 0;
1291 parse->errors[lstate].err_stage = err_tbl[lstate];
1292 parse->errors[lstate].err_cnt = 0;
1293 parse->errors[lstate].err_last = 0;
1294 parse->errors[lstate].err_started = 0;
1295 parse->errors[lstate].err_suppressed = 0;
1301 struct parseunit *parse,
1306 struct errorinfo *err = &parse->errors[lstate];
1308 if (err->err_started == 0)
1310 err->err_started = current_time;
1313 do_it = (current_time - err->err_last) >= err->err_stage->err_delay;
1318 if (err->err_stage->err_count &&
1319 (err->err_cnt >= err->err_stage->err_count))
1325 if (!err->err_cnt && do_it)
1326 msyslog(LOG_INFO, "PARSE receiver #%d: interval for following error message class is at least %s",
1327 CLK_UNIT(parse->peer), l_mktime(err->err_stage->err_delay));
1330 err->err_suppressed++;
1332 err->err_last = current_time;
1334 if (do_it && err->err_suppressed)
1336 msyslog(LOG_INFO, "PARSE receiver #%d: %ld message%s suppressed, error condition class persists for %s",
1337 CLK_UNIT(parse->peer), err->err_suppressed, (err->err_suppressed == 1) ? " was" : "s where",
1338 l_mktime(current_time - err->err_started));
1339 err->err_suppressed = 0;
1345 /*--------------------------------------------------
1346 * mkreadable - make a printable ascii string (without
1347 * embedded quotes so that the ntpq protocol isn't
1351 #define isprint(_X_) (((_X_) > 0x1F) && ((_X_) < 0x7F))
1364 char *endb = (char *)0;
1367 return (char *)0; /* don't bother with mini buffers */
1369 endb = buffer + blen - 4;
1371 blen--; /* account for '\0' */
1373 while (blen && srclen--)
1375 if (!hex && /* no binary only */
1376 (*src != '\\') && /* no plain \ */
1377 (*src != '"') && /* no " */
1378 isprint((int)*src)) /* only printables */
1379 { /* they are easy... */
1398 strcpy(buffer,"\\\\");
1405 sprintf(buffer, "\\x%02x", *src++);
1411 if (srclen && !blen && endb) /* overflow - set last chars to ... */
1412 strcpy(endb, "...");
1420 /*--------------------------------------------------
1421 * mkascii - make a printable ascii string
1422 * assumes (unless defined better) 7-bit ASCII
1432 return mkreadable(buffer, blen, src, srclen, 0);
1435 /**===========================================================================
1436 ** implementation of i/o handling methods
1437 ** (all STREAM, partial STREAM, user level)
1441 * define possible io handling methods
1444 static int ppsclock_init P((struct parseunit *));
1445 static int stream_init P((struct parseunit *));
1446 static void stream_end P((struct parseunit *));
1447 static int stream_enable P((struct parseunit *));
1448 static int stream_disable P((struct parseunit *));
1449 static int stream_setcs P((struct parseunit *, parsectl_t *));
1450 static int stream_getfmt P((struct parseunit *, parsectl_t *));
1451 static int stream_setfmt P((struct parseunit *, parsectl_t *));
1452 static int stream_timecode P((struct parseunit *, parsectl_t *));
1453 static void stream_receive P((struct recvbuf *));
1456 static int local_init P((struct parseunit *));
1457 static void local_end P((struct parseunit *));
1458 static int local_nop P((struct parseunit *));
1459 static int local_setcs P((struct parseunit *, parsectl_t *));
1460 static int local_getfmt P((struct parseunit *, parsectl_t *));
1461 static int local_setfmt P((struct parseunit *, parsectl_t *));
1462 static int local_timecode P((struct parseunit *, parsectl_t *));
1463 static void local_receive P((struct recvbuf *));
1464 static int local_input P((struct recvbuf *));
1466 static bind_t io_bindings[] =
1516 #define fix_ts(_X_) \
1517 if ((&(_X_))->tv.tv_usec >= 1000000) \
1519 (&(_X_))->tv.tv_usec -= 1000000; \
1520 (&(_X_))->tv.tv_sec += 1; \
1523 #define cvt_ts(_X_, _Y_) \
1527 if (!buftvtots((const char *)&(&(_X_))->tv, &ts)) \
1530 msyslog(LOG_ERR,"parse: stream_receive: timestamp conversion error (buftvtots) (%s) (%ld.%06ld) ", (_Y_), (long)(&(_X_))->tv.tv_sec, (long)(&(_X_))->tv.tv_usec);\
1535 (&(_X_))->fp = ts; \
1539 /*--------------------------------------------------
1540 * ppsclock STREAM init
1544 struct parseunit *parse
1547 static char m1[] = "ppsclocd";
1548 static char m2[] = "ppsclock";
1551 * now push the parse streams module
1552 * it will ensure exclusive access to the device
1554 if (ioctl(parse->generic->io.fd, I_PUSH, (caddr_t)m1) == -1 &&
1555 ioctl(parse->generic->io.fd, I_PUSH, (caddr_t)m2) == -1)
1557 if (errno != EINVAL)
1559 msyslog(LOG_ERR, "PARSE receiver #%d: ppsclock_init: ioctl(fd, I_PUSH, \"ppsclock\"): %m",
1560 CLK_UNIT(parse->peer));
1564 if (!local_init(parse))
1566 (void)ioctl(parse->generic->io.fd, I_POP, (caddr_t)0);
1570 parse->flags |= PARSE_PPSCLOCK;
1574 /*--------------------------------------------------
1579 struct parseunit *parse
1582 static char m1[] = "parse";
1584 * now push the parse streams module
1585 * to test whether it is there (neat interface 8-( )
1587 if (ioctl(parse->generic->io.fd, I_PUSH, (caddr_t)m1) == -1)
1589 if (errno != EINVAL) /* accept non-existence */
1591 msyslog(LOG_ERR, "PARSE receiver #%d: stream_init: ioctl(fd, I_PUSH, \"parse\"): %m", CLK_UNIT(parse->peer));
1597 while(ioctl(parse->generic->io.fd, I_POP, (caddr_t)0) == 0)
1601 * now push it a second time after we have removed all
1604 if (ioctl(parse->generic->io.fd, I_PUSH, (caddr_t)m1) == -1)
1606 msyslog(LOG_ERR, "PARSE receiver #%d: stream_init: ioctl(fd, I_PUSH, \"parse\"): %m", CLK_UNIT(parse->peer));
1616 /*--------------------------------------------------
1621 struct parseunit *parse
1624 while(ioctl(parse->generic->io.fd, I_POP, (caddr_t)0) == 0)
1628 /*--------------------------------------------------
1633 struct parseunit *parse,
1637 struct strioctl strioc;
1639 strioc.ic_cmd = PARSEIOC_SETCS;
1640 strioc.ic_timout = 0;
1641 strioc.ic_dp = (char *)tcl;
1642 strioc.ic_len = sizeof (*tcl);
1644 if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1)
1646 msyslog(LOG_ERR, "PARSE receiver #%d: stream_setcs: ioctl(fd, I_STR, PARSEIOC_SETCS): %m", CLK_UNIT(parse->peer));
1652 /*--------------------------------------------------
1657 struct parseunit *parse
1660 struct strioctl strioc;
1662 strioc.ic_cmd = PARSEIOC_ENABLE;
1663 strioc.ic_timout = 0;
1664 strioc.ic_dp = (char *)0;
1667 if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1)
1669 msyslog(LOG_ERR, "PARSE receiver #%d: stream_enable: ioctl(fd, I_STR, PARSEIOC_ENABLE): %m", CLK_UNIT(parse->peer));
1672 parse->generic->io.clock_recv = stream_receive; /* ok - parse input in kernel */
1676 /*--------------------------------------------------
1681 struct parseunit *parse
1684 struct strioctl strioc;
1686 strioc.ic_cmd = PARSEIOC_DISABLE;
1687 strioc.ic_timout = 0;
1688 strioc.ic_dp = (char *)0;
1691 if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1)
1693 msyslog(LOG_ERR, "PARSE receiver #%d: stream_disable: ioctl(fd, I_STR, PARSEIOC_DISABLE): %m", CLK_UNIT(parse->peer));
1696 parse->generic->io.clock_recv = local_receive; /* ok - parse input in daemon */
1700 /*--------------------------------------------------
1705 struct parseunit *parse,
1709 struct strioctl strioc;
1711 strioc.ic_cmd = PARSEIOC_GETFMT;
1712 strioc.ic_timout = 0;
1713 strioc.ic_dp = (char *)tcl;
1714 strioc.ic_len = sizeof (*tcl);
1715 if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1)
1717 msyslog(LOG_ERR, "PARSE receiver #%d: ioctl(fd, I_STR, PARSEIOC_GETFMT): %m", CLK_UNIT(parse->peer));
1723 /*--------------------------------------------------
1728 struct parseunit *parse,
1732 struct strioctl strioc;
1734 strioc.ic_cmd = PARSEIOC_SETFMT;
1735 strioc.ic_timout = 0;
1736 strioc.ic_dp = (char *)tcl;
1737 strioc.ic_len = sizeof (*tcl);
1739 if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1)
1741 msyslog(LOG_ERR, "PARSE receiver #%d: stream_setfmt: ioctl(fd, I_STR, PARSEIOC_SETFMT): %m", CLK_UNIT(parse->peer));
1748 /*--------------------------------------------------
1753 struct parseunit *parse,
1757 struct strioctl strioc;
1759 strioc.ic_cmd = PARSEIOC_TIMECODE;
1760 strioc.ic_timout = 0;
1761 strioc.ic_dp = (char *)tcl;
1762 strioc.ic_len = sizeof (*tcl);
1764 if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1)
1767 msyslog(LOG_ERR, "PARSE receiver #%d: stream_timecode: ioctl(fd, I_STR, PARSEIOC_TIMECODE): %m", CLK_UNIT(parse->peer));
1770 clear_err(parse, ERR_INTERNAL);
1774 /*--------------------------------------------------
1779 struct recvbuf *rbufp
1782 struct parseunit *parse = (struct parseunit *)((void *)rbufp->recv_srcclock);
1783 parsetime_t parsetime;
1788 if (rbufp->recv_length != sizeof(parsetime_t))
1791 msyslog(LOG_ERR,"PARSE receiver #%d: stream_receive: bad size (got %d expected %d)",
1792 CLK_UNIT(parse->peer), rbufp->recv_length, (int)sizeof(parsetime_t));
1793 parse->generic->baddata++;
1794 parse_event(parse, CEVNT_BADREPLY);
1797 clear_err(parse, ERR_BADIO);
1799 memmove((caddr_t)&parsetime,
1800 (caddr_t)rbufp->recv_buffer,
1801 sizeof(parsetime_t));
1806 printf("PARSE receiver #%d: status %06x, state %08x, time %lx.%08lx, stime %lx.%08lx, ptime %lx.%08lx\n",
1807 CLK_UNIT(parse->peer),
1808 (unsigned int)parsetime.parse_status,
1809 (unsigned int)parsetime.parse_state,
1810 (long)parsetime.parse_time.tv.tv_sec,
1811 (long)parsetime.parse_time.tv.tv_usec,
1812 (long)parsetime.parse_stime.tv.tv_sec,
1813 (long)parsetime.parse_stime.tv.tv_usec,
1814 (long)parsetime.parse_ptime.tv.tv_sec,
1815 (long)parsetime.parse_ptime.tv.tv_usec);
1820 * switch time stamp world - be sure to normalize small usec field
1824 cvt_ts(parsetime.parse_stime, "parse_stime");
1826 if (PARSE_TIMECODE(parsetime.parse_state))
1828 cvt_ts(parsetime.parse_time, "parse_time");
1831 if (PARSE_PPS(parsetime.parse_state))
1832 cvt_ts(parsetime.parse_ptime, "parse_ptime");
1834 parse_process(parse, &parsetime);
1838 /*--------------------------------------------------
1843 struct parseunit *parse
1846 return parse_ioinit(&parse->parseio);
1849 /*--------------------------------------------------
1854 struct parseunit *parse
1857 parse_ioend(&parse->parseio);
1861 /*--------------------------------------------------
1866 struct parseunit *parse
1872 /*--------------------------------------------------
1877 struct parseunit *parse,
1881 return parse_setcs(tcl, &parse->parseio);
1884 /*--------------------------------------------------
1889 struct parseunit *parse,
1893 return parse_getfmt(tcl, &parse->parseio);
1896 /*--------------------------------------------------
1901 struct parseunit *parse,
1905 return parse_setfmt(tcl, &parse->parseio);
1908 /*--------------------------------------------------
1913 struct parseunit *parse,
1917 return parse_timecode(tcl, &parse->parseio);
1921 /*--------------------------------------------------
1926 struct recvbuf *rbufp
1929 struct parseunit *parse = (struct parseunit *)((void *)rbufp->recv_srcclock);
1938 * eat all characters, parsing then and feeding complete samples
1940 count = rbufp->recv_length;
1941 s = (unsigned char *)rbufp->recv_buffer;
1942 ts.fp = rbufp->recv_time;
1946 if (parse_ioread(&parse->parseio, (unsigned int)(*s++), &ts))
1951 * got something good to eat
1953 if (!PARSE_PPS(parse->parseio.parse_dtime.parse_state))
1955 #ifdef TIOCDCDTIMESTAMP
1956 struct timeval dcd_time;
1958 if (ioctl(rbufp->fd, TIOCDCDTIMESTAMP, &dcd_time) != -1)
1962 TVTOTS(&dcd_time, &tstmp);
1963 tstmp.l_ui += JAN_1970;
1964 L_SUB(&ts.fp, &tstmp);
1965 if (ts.fp.l_ui == 0)
1971 "parse: local_receive: fd %d DCDTIMESTAMP %s\n",
1974 printf(" sigio %s\n",
1978 parse->parseio.parse_dtime.parse_ptime.fp = tstmp;
1979 parse->parseio.parse_dtime.parse_state |= PARSEB_PPS|PARSEB_S_PPS;
1982 #else /* TIOCDCDTIMESTAMP */
1983 #if defined(HAVE_STRUCT_PPSCLOCKEV) && (defined(HAVE_CIOGETEV) || defined(HAVE_TIOCGPPSEV))
1984 if (parse->flags & PARSE_PPSCLOCK)
1987 struct ppsclockev ev;
1989 #ifdef HAVE_CIOGETEV
1990 if (ioctl(parse->generic->io.fd, CIOGETEV, (caddr_t)&ev) == 0)
1992 #ifdef HAVE_TIOCGPPSEV
1993 if (ioctl(parse->generic->io.fd, TIOCGPPSEV, (caddr_t)&ev) == 0)
1996 if (ev.serial != parse->ppsserial)
1999 * add PPS time stamp if available via ppsclock module
2000 * and not supplied already.
2002 if (!buftvtots((const char *)&ev.tv, &tts))
2005 msyslog(LOG_ERR,"parse: local_receive: timestamp conversion error (buftvtots) (ppsclockev.tv)");
2009 parse->parseio.parse_dtime.parse_ptime.fp = tts;
2010 parse->parseio.parse_dtime.parse_state |= PARSEB_PPS|PARSEB_S_PPS;
2013 parse->ppsserial = ev.serial;
2017 #endif /* TIOCDCDTIMESTAMP */
2020 { /* simulate receive */
2021 memmove((caddr_t)buf.recv_buffer,
2022 (caddr_t)&parse->parseio.parse_dtime,
2023 sizeof(parsetime_t));
2024 parse_iodone(&parse->parseio);
2025 buf.recv_length = sizeof(parsetime_t);
2026 buf.recv_time = rbufp->recv_time;
2027 buf.srcadr = rbufp->srcadr;
2028 buf.dstadr = rbufp->dstadr;
2031 buf.X_from_where = rbufp->X_from_where;
2032 rbufp->receiver(&buf);
2036 memmove((caddr_t)rbufp->recv_buffer,
2037 (caddr_t)&parse->parseio.parse_dtime,
2038 sizeof(parsetime_t));
2039 parse_iodone(&parse->parseio);
2040 rbufp->recv_length = sizeof(parsetime_t);
2041 return 1; /* got something & in place return */
2045 return 0; /* nothing to pass up */
2048 /*--------------------------------------------------
2053 struct recvbuf *rbufp
2056 struct parseunit *parse = (struct parseunit *)((void *)rbufp->recv_srcclock);
2057 parsetime_t parsetime;
2062 if (rbufp->recv_length != sizeof(parsetime_t))
2065 msyslog(LOG_ERR,"PARSE receiver #%d: local_receive: bad size (got %d expected %d)",
2066 CLK_UNIT(parse->peer), rbufp->recv_length, (int)sizeof(parsetime_t));
2067 parse->generic->baddata++;
2068 parse_event(parse, CEVNT_BADREPLY);
2071 clear_err(parse, ERR_BADIO);
2073 memmove((caddr_t)&parsetime,
2074 (caddr_t)rbufp->recv_buffer,
2075 sizeof(parsetime_t));
2080 printf("PARSE receiver #%d: status %06x, state %08x, time %lx.%08lx, stime %lx.%08lx, ptime %lx.%08lx\n",
2081 CLK_UNIT(parse->peer),
2082 (unsigned int)parsetime.parse_status,
2083 (unsigned int)parsetime.parse_state,
2084 (long)parsetime.parse_time.tv.tv_sec,
2085 (long)parsetime.parse_time.tv.tv_usec,
2086 (long)parsetime.parse_stime.tv.tv_sec,
2087 (long)parsetime.parse_stime.tv.tv_usec,
2088 (long)parsetime.parse_ptime.tv.tv_sec,
2089 (long)parsetime.parse_ptime.tv.tv_usec);
2093 parse_process(parse, &parsetime);
2096 /*--------------------------------------------------
2097 * init_iobinding - find and initialize lower layers
2101 struct parseunit *parse
2104 bind_t *b = io_bindings;
2106 while (b->bd_description != (char *)0)
2108 if ((*b->bd_init)(parse))
2117 /**===========================================================================
2121 /*--------------------------------------------------
2122 * convert a flag field to a string
2136 { PARSEB_ANNOUNCE, "DST SWITCH WARNING" },
2137 { PARSEB_POWERUP, "NOT SYNCHRONIZED" },
2138 { PARSEB_NOSYNC, "TIME CODE NOT CONFIRMED" },
2139 { PARSEB_DST, "DST" },
2140 { PARSEB_UTC, "UTC DISPLAY" },
2141 { PARSEB_LEAPADD, "LEAP ADD WARNING" },
2142 { PARSEB_LEAPDEL, "LEAP DELETE WARNING" },
2143 { PARSEB_LEAPSECOND, "LEAP SECOND" },
2144 { PARSEB_ALTERNATE, "ALTERNATE ANTENNA" },
2145 { PARSEB_TIMECODE, "TIME CODE" },
2146 { PARSEB_PPS, "PPS" },
2147 { PARSEB_POSITION, "POSITION" },
2157 { PARSEB_S_LEAP, "LEAP INDICATION" },
2158 { PARSEB_S_PPS, "PPS SIGNAL" },
2159 { PARSEB_S_ANTENNA, "ANTENNA" },
2160 { PARSEB_S_POSITION, "POSITION" },
2168 while (flagstrings[i].bit)
2170 if (flagstrings[i].bit & lstate)
2173 strcat(buffer, "; ");
2174 strcat(buffer, flagstrings[i].name);
2179 if (lstate & (PARSEB_S_LEAP|PARSEB_S_ANTENNA|PARSEB_S_PPS|PARSEB_S_POSITION))
2184 strcat(buffer, "; ");
2186 strcat(buffer, "(");
2188 t = s = buffer + strlen(buffer);
2191 while (sflagstrings[i].bit)
2193 if (sflagstrings[i].bit & lstate)
2201 strcpy(t, sflagstrings[i].name);
2211 /*--------------------------------------------------
2212 * convert a status flag field to a string
2226 { CVT_OK, "CONVERSION SUCCESSFUL" },
2227 { CVT_NONE, "NO CONVERSION" },
2228 { CVT_FAIL, "CONVERSION FAILED" },
2229 { CVT_BADFMT, "ILLEGAL FORMAT" },
2230 { CVT_BADDATE, "DATE ILLEGAL" },
2231 { CVT_BADTIME, "TIME ILLEGAL" },
2232 { CVT_ADDITIONAL, "ADDITIONAL DATA" },
2240 while (flagstrings[i].bit)
2242 if (flagstrings[i].bit & lstate)
2245 strcat(buffer, "; ");
2246 strcat(buffer, flagstrings[i].name);
2254 /*--------------------------------------------------
2255 * convert a clock status flag field to a string
2262 static char buffer[20];
2263 static struct status
2269 { CEVNT_NOMINAL, "NOMINAL" },
2270 { CEVNT_TIMEOUT, "NO RESPONSE" },
2271 { CEVNT_BADREPLY,"BAD FORMAT" },
2272 { CEVNT_FAULT, "FAULT" },
2273 { CEVNT_PROP, "PROPAGATION DELAY" },
2274 { CEVNT_BADDATE, "ILLEGAL DATE" },
2275 { CEVNT_BADTIME, "ILLEGAL TIME" },
2281 while (flagstrings[i].value != ~0)
2283 if (flagstrings[i].value == lstate)
2285 return flagstrings[i].name;
2290 sprintf(buffer, "unknown #%ld", (u_long)lstate);
2296 /*--------------------------------------------------
2297 * l_mktime - make representation of a relative time
2305 static char buffer[40];
2309 if ((tmp = delta / (60*60*24)) != 0)
2311 sprintf(buffer, "%ldd+", (u_long)tmp);
2312 delta -= tmp * 60*60*24;
2320 sprintf(buffer+strlen(buffer), "%02d:%02d:%02d",
2321 (int)delta, (int)m, (int)s);
2327 /*--------------------------------------------------
2328 * parse_statistics - list summary of clock states
2332 struct parseunit *parse
2337 NLOG(NLOG_CLOCKSTATIST) /* conditional if clause for conditional syslog */
2339 msyslog(LOG_INFO, "PARSE receiver #%d: running time: %s",
2340 CLK_UNIT(parse->peer),
2341 l_mktime(current_time - parse->generic->timestarted));
2343 msyslog(LOG_INFO, "PARSE receiver #%d: current status: %s",
2344 CLK_UNIT(parse->peer),
2345 clockstatus(parse->generic->currentstatus));
2347 for (i = 0; i <= CEVNT_MAX; i++)
2350 u_long percent, d = current_time - parse->generic->timestarted;
2352 percent = s_time = PARSE_STATETIME(parse, i);
2354 while (((u_long)(~0) / 10000) < percent)
2361 percent = (percent * 10000) / d;
2366 msyslog(LOG_INFO, "PARSE receiver #%d: state %18s: %13s (%3ld.%02ld%%)",
2367 CLK_UNIT(parse->peer),
2368 clockstatus((unsigned int)i),
2370 percent / 100, percent % 100);
2375 /*--------------------------------------------------
2376 * cparse_statistics - wrapper for statistics call
2380 register struct parseunit *parse
2383 if (parse->laststatistic + PARSESTATISTICS < current_time)
2384 parse_statistics(parse);
2385 parse->laststatistic = current_time;
2388 /**===========================================================================
2389 ** ntp interface routines
2392 /*--------------------------------------------------
2393 * parse_init - initialize internal parse driver data
2398 memset((caddr_t)parseunits, 0, sizeof parseunits);
2402 /*--------------------------------------------------
2403 * parse_shutdown - shut down a PARSE clock
2411 struct parseunit *parse = (struct parseunit *)peer->procptr->unitptr;
2413 if (parse && !parse->peer)
2416 "PARSE receiver #%d: parse_shutdown: INTERNAL ERROR, unit not in use", unit);
2421 * print statistics a last time and
2422 * stop statistics machine
2424 parse_statistics(parse);
2426 if (parse->parse_type->cl_end)
2428 parse->parse_type->cl_end(parse);
2435 * Tell the I/O module to turn us off. We're history.
2437 io_closeclock(&parse->generic->io);
2439 free_varlist(parse->kv);
2441 NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */
2442 msyslog(LOG_INFO, "PARSE receiver #%d: reference clock \"%s\" removed",
2443 CLK_UNIT(parse->peer), parse->parse_type->cl_description);
2445 parse->peer = (struct peer *)0; /* unused now */
2449 /*--------------------------------------------------
2450 * parse_start - open the PARSE devices and initialize data for processing
2461 struct termios tio; /* NEEDED FOR A LONG TIME ! */
2463 #ifdef HAVE_SYSV_TTYS
2464 struct termio tio; /* NEEDED FOR A LONG TIME ! */
2466 struct parseunit * parse;
2467 char parsedev[sizeof(PARSEDEVICE)+20];
2471 type = CLK_TYPE(peer);
2472 unit = CLK_UNIT(peer);
2474 if ((type == ~0) || (parse_clockinfo[type].cl_description == (char *)0))
2476 msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: unsupported clock type %d (max %d)",
2477 unit, CLK_REALTYPE(peer), ncltypes-1);
2482 * Unit okay, attempt to open the device.
2484 (void) sprintf(parsedev, PARSEDEVICE, unit);
2490 fd232 = open(parsedev, O_RDWR | O_NOCTTY
2498 msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: open of %s failed: %m", unit, parsedev);
2502 parse = (struct parseunit *)emalloc(sizeof(struct parseunit));
2504 memset((char *)parse, 0, sizeof(struct parseunit));
2506 parse->generic = peer->procptr; /* link up */
2507 parse->generic->unitptr = (caddr_t)parse; /* link down */
2510 * Set up the structures
2512 parse->generic->timestarted = current_time;
2513 parse->lastchange = current_time;
2515 parse->generic->currentstatus = CEVNT_TIMEOUT; /* expect the worst */
2518 parse->pollneeddata = 0;
2519 parse->laststatistic = current_time;
2520 parse->lastformat = (unsigned short)~0; /* assume no format known */
2521 parse->time.parse_status = (unsigned short)~0; /* be sure to mark initial status change */
2522 parse->lastmissed = 0; /* assume got everything */
2523 parse->ppsserial = 0;
2524 parse->localdata = (void *)0;
2525 parse->localstate = 0;
2526 parse->kv = (struct ctl_var *)0;
2528 clear_err(parse, ERR_ALL);
2530 parse->parse_type = &parse_clockinfo[type];
2532 parse->generic->fudgetime1 = parse->parse_type->cl_basedelay;
2534 parse->generic->fudgetime2 = 0.0;
2536 parse->generic->clockdesc = parse->parse_type->cl_description;
2538 peer->rootdelay = parse->parse_type->cl_rootdelay;
2539 peer->sstclktype = parse->parse_type->cl_type;
2540 peer->precision = sys_precision;
2542 peer->stratum = STRATUM_REFCLOCK;
2543 if (peer->stratum <= 1)
2544 memmove((char *)&parse->generic->refid, parse->parse_type->cl_id, 4);
2546 parse->generic->refid = htonl(PARSEHSREFID);
2548 parse->generic->io.fd = fd232;
2550 parse->peer = peer; /* marks it also as busy */
2553 * configure terminal line
2555 if (TTY_GETATTR(fd232, &tio) == -1)
2557 msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: tcgetattr(%d, &tio): %m", unit, fd232);
2558 parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
2563 #ifndef _PC_VDISABLE
2564 memset((char *)tio.c_cc, 0, sizeof(tio.c_cc));
2567 errno = 0; /* pathconf can deliver -1 without changing errno ! */
2569 disablec = fpathconf(parse->generic->io.fd, _PC_VDISABLE);
2570 if (disablec == -1 && errno)
2572 msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: fpathconf(fd, _PC_VDISABLE): %m", CLK_UNIT(parse->peer));
2573 memset((char *)tio.c_cc, 0, sizeof(tio.c_cc)); /* best guess */
2577 memset((char *)tio.c_cc, disablec, sizeof(tio.c_cc));
2580 #if defined (VMIN) || defined(VTIME)
2581 if ((parse_clockinfo[type].cl_lflag & ICANON) == 0)
2587 tio.c_cc[VTIME] = 0;
2592 tio.c_cflag = parse_clockinfo[type].cl_cflag;
2593 tio.c_iflag = parse_clockinfo[type].cl_iflag;
2594 tio.c_oflag = parse_clockinfo[type].cl_oflag;
2595 tio.c_lflag = parse_clockinfo[type].cl_lflag;
2599 if ((cfsetospeed(&tio, parse_clockinfo[type].cl_speed) == -1) ||
2600 (cfsetispeed(&tio, parse_clockinfo[type].cl_speed) == -1))
2602 msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: tcset{i,o}speed(&tio, speed): %m", unit);
2603 parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
2607 tio.c_cflag |= parse_clockinfo[type].cl_speed;
2610 #if defined(HAVE_TIO_SERIAL_STUFF) /* Linux hack: define PPS interface */
2612 struct serial_struct ss;
2613 if (ioctl(fd232, TIOCGSERIAL, &ss) < 0 ||
2615 #ifdef ASYNC_LOW_LATENCY
2616 ss.flags |= ASYNC_LOW_LATENCY,
2618 #ifdef ASYNC_PPS_CD_NEG
2619 ss.flags |= ASYNC_PPS_CD_NEG,
2621 ioctl(fd232, TIOCSSERIAL, &ss)) < 0) {
2622 msyslog(LOG_NOTICE, "refclock_parse: TIOCSSERIAL fd %d, %m", fd232);
2624 "refclock_parse: optional PPS processing not available");
2626 parse->flags |= PARSE_PPSCLOCK;
2628 "refclock_parse: PPS detection on");
2632 #ifdef HAVE_TIOCSPPS /* SUN PPS support */
2633 if (CLK_PPS(parse->peer))
2637 if (ioctl(fd232, TIOCSPPS, (caddr_t)&i) == 0)
2639 parse->flags |= PARSE_PPSCLOCK;
2644 if (TTY_SETATTR(fd232, &tio) == -1)
2646 msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: tcsetattr(%d, &tio): %m", unit, fd232);
2647 parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
2653 * Insert in async io device list.
2655 parse->generic->io.srcclock = (caddr_t)parse;
2656 parse->generic->io.datalen = 0;
2658 if (!io_addclock(&parse->generic->io))
2661 "PARSE receiver #%d: parse_start: addclock %s fails (ABORT - clock type requires async io)", CLK_UNIT(parse->peer), parsedev);
2662 parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
2666 parse->binding = init_iobinding(parse);
2667 parse->generic->io.clock_recv = parse->binding->bd_receive; /* pick correct receive routine */
2668 parse->generic->io.io_input = parse->binding->bd_io_input; /* pick correct input routine */
2670 if (parse->binding == (bind_t *)0)
2672 msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: io sub system initialisation failed.", CLK_UNIT(parse->peer));
2673 parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
2674 return 0; /* well, ok - special initialisation broke */
2678 * as we always(?) get 8 bit chars we want to be
2679 * sure, that the upper bits are zero for less
2680 * than 8 bit I/O - so we pass that information on.
2681 * note that there can be only one bit count format
2682 * per file descriptor
2685 switch (tio.c_cflag & CSIZE)
2688 tmp_ctl.parsesetcs.parse_cs = PARSE_IO_CS5;
2692 tmp_ctl.parsesetcs.parse_cs = PARSE_IO_CS6;
2696 tmp_ctl.parsesetcs.parse_cs = PARSE_IO_CS7;
2700 tmp_ctl.parsesetcs.parse_cs = PARSE_IO_CS8;
2704 if (!PARSE_SETCS(parse, &tmp_ctl))
2706 msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: parse_setcs() FAILED.", unit);
2707 parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
2708 return 0; /* well, ok - special initialisation broke */
2711 strcpy(tmp_ctl.parseformat.parse_buffer, parse->parse_type->cl_format);
2712 tmp_ctl.parseformat.parse_count = strlen(tmp_ctl.parseformat.parse_buffer);
2714 if (!PARSE_SETFMT(parse, &tmp_ctl))
2716 msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: parse_setfmt() FAILED.", unit);
2717 parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
2718 return 0; /* well, ok - special initialisation broke */
2722 * get rid of all IO accumulated so far
2725 (void) tcflush(parse->generic->io.fd, TCIOFLUSH);
2732 int flshcmd = TCIOFLUSH;
2734 (void) ioctl(parse->generic->io.fd, TCFLSH, (caddr_t)&flshcmd);
2740 * try to do any special initializations
2742 if (parse->parse_type->cl_init)
2744 if (parse->parse_type->cl_init(parse))
2746 parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
2747 return 0; /* well, ok - special initialisation broke */
2752 * get out Copyright information once
2756 NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */
2757 msyslog(LOG_INFO, "NTP PARSE support: Copyright (c) 1989-1999, Frank Kardel");
2762 * print out configuration
2764 NLOG(NLOG_CLOCKINFO)
2766 /* conditional if clause for conditional syslog */
2767 msyslog(LOG_INFO, "PARSE receiver #%d: reference clock \"%s\" (device %s) added",
2768 CLK_UNIT(parse->peer),
2769 parse->parse_type->cl_description, parsedev);
2771 msyslog(LOG_INFO, "PARSE receiver #%d: Stratum %d, %sPPS support, trust time %s, precision %d",
2772 CLK_UNIT(parse->peer),
2773 parse->peer->stratum, CLK_PPS(parse->peer) ? "" : "no ",
2774 l_mktime(parse->parse_type->cl_maxunsync), parse->peer->precision);
2776 msyslog(LOG_INFO, "PARSE receiver #%d: rootdelay %.6f s, phaseadjust %.6f s, %s IO handling",
2777 CLK_UNIT(parse->peer),
2778 parse->parse_type->cl_rootdelay,
2779 parse->generic->fudgetime1,
2780 parse->binding->bd_description);
2782 msyslog(LOG_INFO, "PARSE receiver #%d: Format recognition: %s", CLK_UNIT(parse->peer),
2783 parse->parse_type->cl_format);
2785 msyslog(LOG_INFO, "PARSE receiver #%d: %sPPS ioctl support", CLK_UNIT(parse->peer),
2786 (parse->flags & PARSE_PPSCLOCK) ? "" : "NO ");
2793 /*--------------------------------------------------
2794 * parse_poll - called by the transmit procedure
2802 struct parseunit *parse = (struct parseunit *)peer->procptr->unitptr;
2804 if (peer != parse->peer)
2807 "PARSE receiver #%d: poll: INTERNAL: peer incorrect",
2813 * Update clock stat counters
2815 parse->generic->polls++;
2817 if (parse->pollneeddata &&
2818 ((current_time - parse->pollneeddata) > (1<<(max(min(parse->peer->hpoll, parse->peer->ppoll), parse->peer->minpoll)))))
2821 * start worrying when exceeding a poll inteval
2822 * bad news - didn't get a response last time
2824 parse->generic->noreply++;
2825 parse->lastmissed = current_time;
2826 parse_event(parse, CEVNT_TIMEOUT);
2829 msyslog(LOG_WARNING, "PARSE receiver #%d: no data from device within poll interval (check receiver / cableling)", CLK_UNIT(parse->peer));
2833 * we just mark that we want the next sample for the clock filter
2835 parse->pollneeddata = current_time;
2837 if (parse->parse_type->cl_poll)
2839 parse->parse_type->cl_poll(parse);
2842 cparse_statistics(parse);
2847 #define LEN_STATES 300 /* length of state string */
2849 /*--------------------------------------------------
2850 * parse_control - set fudge factors, return statistics
2855 struct refclockstat *in,
2856 struct refclockstat *out,
2860 register struct parseunit *parse = (struct parseunit *)peer->procptr->unitptr;
2863 static char outstatus[400]; /* status output buffer */
2868 out->p_lastcode = 0;
2869 out->kv_list = (struct ctl_var *)0;
2872 if (!parse || !parse->peer)
2874 msyslog(LOG_ERR, "PARSE receiver #%d: parse_control: unit invalid (UNIT INACTIVE)",
2879 unit = CLK_UNIT(parse->peer);
2883 if (in->haveflags & (CLK_HAVEFLAG1|CLK_HAVEFLAG2|CLK_HAVEFLAG3|CLK_HAVEFLAG4))
2885 parse->flags = in->flags & (CLK_FLAG1|CLK_FLAG2|CLK_FLAG3|CLK_FLAG4);
2892 char *t, *tt, *start;
2895 outstatus[0] = '\0';
2897 out->type = REFCLK_PARSE;
2898 out->haveflags |= CLK_HAVETIME2;
2901 * figure out skew between PPS and RS232 - just for informational
2902 * purposes - returned in time2 value
2904 if (PARSE_SYNC(parse->time.parse_state))
2906 if (PARSE_PPS(parse->time.parse_state) && PARSE_TIMECODE(parse->time.parse_state))
2911 * we have a PPS and RS232 signal - calculate the skew
2912 * WARNING: assumes on TIMECODE == PULSE (timecode after pulse)
2914 off = parse->time.parse_stime.fp;
2915 L_SUB(&off, &parse->time.parse_ptime.fp); /* true offset */
2916 tt = add_var(&out->kv_list, 80, RO);
2917 sprintf(tt, "refclock_ppsskew=%s", lfptoms(&off, 6));
2921 if (PARSE_PPS(parse->time.parse_state))
2923 tt = add_var(&out->kv_list, 80, RO|DEF);
2924 sprintf(tt, "refclock_ppstime=\"%s\"", gmprettydate(&parse->time.parse_ptime.fp));
2927 tt = add_var(&out->kv_list, 128, RO|DEF);
2928 sprintf(tt, "refclock_time=\"");
2931 if (parse->time.parse_time.fp.l_ui == 0)
2933 strcpy(tt, "<UNDEFINED>\"");
2937 sprintf(tt, "%s\"", gmprettydate(&parse->time.parse_time.fp));
2938 t = tt + strlen(tt);
2941 if (!PARSE_GETTIMECODE(parse, &tmpctl))
2944 msyslog(LOG_ERR, "PARSE receiver #%d: parse_control: parse_timecode() FAILED", unit);
2948 tt = add_var(&out->kv_list, 512, RO|DEF);
2949 sprintf(tt, "refclock_status=\"");
2953 * copy PPS flags from last read transaction (informational only)
2955 tmpctl.parsegettc.parse_state |= parse->time.parse_state &
2956 (PARSEB_PPS|PARSEB_S_PPS);
2958 (void) parsestate(tmpctl.parsegettc.parse_state, tt);
2962 if (tmpctl.parsegettc.parse_count)
2963 mkascii(outstatus+strlen(outstatus), (int)(sizeof(outstatus)- strlen(outstatus) - 1),
2964 tmpctl.parsegettc.parse_buffer, (unsigned)(tmpctl.parsegettc.parse_count - 1));
2966 parse->generic->badformat += tmpctl.parsegettc.parse_badformat;
2969 tmpctl.parseformat.parse_format = tmpctl.parsegettc.parse_format;
2971 if (!PARSE_GETFMT(parse, &tmpctl))
2974 msyslog(LOG_ERR, "PARSE receiver #%d: parse_control: parse_getfmt() FAILED", unit);
2978 tt = add_var(&out->kv_list, 80, RO|DEF);
2979 sprintf(tt, "refclock_format=\"");
2981 strncat(tt, tmpctl.parseformat.parse_buffer, tmpctl.parseformat.parse_count);
2986 * gather state statistics
2989 start = tt = add_var(&out->kv_list, LEN_STATES, RO|DEF);
2990 strcpy(tt, "refclock_states=\"");
2993 for (i = 0; i <= CEVNT_MAX; i++)
2996 u_long d = current_time - parse->generic->timestarted;
2999 percent = s_time = PARSE_STATETIME(parse, i);
3001 while (((u_long)(~0) / 10000) < percent)
3008 percent = (percent * 10000) / d;
3017 sprintf(item, "%s%s%s: %s (%d.%02d%%)",
3019 (parse->generic->currentstatus == i) ? "*" : "",
3020 clockstatus((unsigned int)i),
3022 (int)(percent / 100), (int)(percent % 100));
3023 if ((count = strlen(item)) < (LEN_STATES - 40 - (tt - start)))
3032 sprintf(tt, "; running time: %s\"", l_mktime(sum));
3034 tt = add_var(&out->kv_list, 32, RO);
3035 sprintf(tt, "refclock_id=\"%s\"", parse->parse_type->cl_id);
3037 tt = add_var(&out->kv_list, 80, RO);
3038 sprintf(tt, "refclock_iomode=\"%s\"", parse->binding->bd_description);
3040 tt = add_var(&out->kv_list, 128, RO);
3041 sprintf(tt, "refclock_driver_version=\"%s\"", rcsid);
3047 while (k && !(k->flags & EOV))
3049 set_var(&out->kv_list, k->text, strlen(k->text)+1, k->flags);
3054 out->lencode = strlen(outstatus);
3055 out->p_lastcode = outstatus;
3059 /**===========================================================================
3060 ** processing routines
3063 /*--------------------------------------------------
3064 * event handling - note that nominal events will also be posted
3068 struct parseunit *parse,
3072 if (parse->generic->currentstatus != (u_char) event)
3074 parse->statetime[parse->generic->currentstatus] += current_time - parse->lastchange;
3075 parse->lastchange = current_time;
3077 parse->generic->currentstatus = (u_char)event;
3079 if (parse->parse_type->cl_event)
3080 parse->parse_type->cl_event(parse, event);
3082 if (event != CEVNT_NOMINAL)
3084 parse->generic->lastevent = parse->generic->currentstatus;
3088 NLOG(NLOG_CLOCKSTATUS)
3089 msyslog(LOG_INFO, "PARSE receiver #%d: SYNCHRONIZED",
3090 CLK_UNIT(parse->peer));
3093 if (event == CEVNT_FAULT)
3095 NLOG(NLOG_CLOCKEVENT) /* conditional if clause for conditional syslog */
3098 "clock %s fault '%s' (0x%02x)", refnumtoa(parse->peer->srcadr.sin_addr.s_addr), ceventstr(event),
3103 NLOG(NLOG_CLOCKEVENT) /* conditional if clause for conditional syslog */
3104 if (event == CEVNT_NOMINAL || list_err(parse, ERR_BADEVENT))
3106 "clock %s event '%s' (0x%02x)", refnumtoa(parse->peer->srcadr.sin_addr.s_addr), ceventstr(event),
3110 report_event(EVNT_PEERCLOCK, parse->peer);
3111 report_event(EVNT_CLOCKEXCPT, parse->peer);
3115 /*--------------------------------------------------
3116 * process a PARSE time sample
3120 struct parseunit *parse,
3121 parsetime_t *parsetime
3124 l_fp off, rectime, reftime;
3128 * check for changes in conversion status
3129 * (only one for each new status !)
3131 if (((parsetime->parse_status & CVT_MASK) != CVT_OK) &&
3132 ((parsetime->parse_status & CVT_MASK) != CVT_NONE) &&
3133 (parse->time.parse_status != parsetime->parse_status))
3137 NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */
3138 msyslog(LOG_WARNING, "PARSE receiver #%d: conversion status \"%s\"",
3139 CLK_UNIT(parse->peer), parsestatus(parsetime->parse_status, buffer));
3141 if ((parsetime->parse_status & CVT_MASK) == CVT_FAIL)
3144 * tell more about the story - list time code
3145 * there is a slight change for a race condition and
3146 * the time code might be overwritten by the next packet
3150 if (!PARSE_GETTIMECODE(parse, &tmpctl))
3153 msyslog(LOG_ERR, "PARSE receiver #%d: parse_process: parse_timecode() FAILED", CLK_UNIT(parse->peer));
3158 msyslog(LOG_WARNING, "PARSE receiver #%d: FAILED TIMECODE: \"%s\" (check receiver configuration / cableling)",
3159 CLK_UNIT(parse->peer), mkascii(buffer, sizeof buffer, tmpctl.parsegettc.parse_buffer, (unsigned)(tmpctl.parsegettc.parse_count - 1)));
3160 parse->generic->badformat += tmpctl.parsegettc.parse_badformat;
3166 * examine status and post appropriate events
3168 if ((parsetime->parse_status & CVT_MASK) != CVT_OK)
3171 * got bad data - tell the rest of the system
3173 switch (parsetime->parse_status & CVT_MASK)
3176 if ((parsetime->parse_status & CVT_ADDITIONAL) &&
3177 parse->parse_type->cl_message)
3178 parse->parse_type->cl_message(parse, parsetime);
3179 break; /* well, still waiting - timeout is handled at higher levels */
3182 parse->generic->badformat++;
3183 if (parsetime->parse_status & CVT_BADFMT)
3185 parse_event(parse, CEVNT_BADREPLY);
3188 if (parsetime->parse_status & CVT_BADDATE)
3190 parse_event(parse, CEVNT_BADDATE);
3193 if (parsetime->parse_status & CVT_BADTIME)
3195 parse_event(parse, CEVNT_BADTIME);
3199 parse_event(parse, CEVNT_BADREPLY); /* for the lack of something better */
3202 return; /* skip the rest - useless */
3206 * check for format changes
3207 * (in case somebody has swapped clocks 8-)
3209 if (parse->lastformat != parsetime->parse_format)
3213 tmpctl.parseformat.parse_format = parsetime->parse_format;
3215 if (!PARSE_GETFMT(parse, &tmpctl))
3218 msyslog(LOG_ERR, "PARSE receiver #%d: parse_getfmt() FAILED", CLK_UNIT(parse->peer));
3222 NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */
3223 msyslog(LOG_INFO, "PARSE receiver #%d: packet format \"%s\"",
3224 CLK_UNIT(parse->peer), tmpctl.parseformat.parse_buffer);
3226 parse->lastformat = parsetime->parse_format;
3230 * now, any changes ?
3232 if (parse->time.parse_state != parsetime->parse_state)
3240 (void) parsestate(parsetime->parse_state, tmp1);
3241 (void) parsestate(parse->time.parse_state, tmp2);
3243 NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */
3244 msyslog(LOG_INFO,"PARSE receiver #%d: STATE CHANGE: %s -> %s",
3245 CLK_UNIT(parse->peer), tmp2, tmp1);
3249 * remember for future
3251 parse->time = *parsetime;
3254 * check to see, whether the clock did a complete powerup or lost PZF signal
3255 * and post correct events for current condition
3257 if (PARSE_POWERUP(parsetime->parse_state))
3260 * this is bad, as we have completely lost synchronisation
3261 * well this is a problem with the receiver here
3262 * for PARSE Meinberg DCF77 receivers the lost synchronisation
3263 * is true as it is the powerup state and the time is taken
3264 * from a crude real time clock chip
3265 * for the PZF series this is only partly true, as
3266 * PARSE_POWERUP only means that the pseudo random
3267 * phase shift sequence cannot be found. this is only
3268 * bad, if we have never seen the clock in the SYNC
3269 * state, where the PHASE and EPOCH are correct.
3270 * for reporting events the above business does not
3271 * really matter, but we can use the time code
3272 * even in the POWERUP state after having seen
3273 * the clock in the synchronized state (PZF class
3274 * receivers) unless we have had a telegram disruption
3275 * after having seen the clock in the SYNC state. we
3276 * thus require having seen the clock in SYNC state
3277 * *after* having missed telegrams (noresponse) from
3278 * the clock. one problem remains: we might use erroneously
3279 * POWERUP data if the disruption is shorter than 1 polling
3280 * interval. fortunately powerdowns last usually longer than 64
3281 * seconds and the receiver is at least 2 minutes in the
3282 * POWERUP or NOSYNC state before switching to SYNC
3284 parse_event(parse, CEVNT_FAULT);
3285 NLOG(NLOG_CLOCKSTATUS)
3287 msyslog(LOG_ERR,"PARSE receiver #%d: NOT SYNCHRONIZED",
3288 CLK_UNIT(parse->peer));
3293 * we have two states left
3296 * this state means that the EPOCH (timecode) and PHASE
3297 * information has be read correctly (at least two
3298 * successive PARSE timecodes were received correctly)
3299 * this is the best possible state - full trust
3302 * The clock should be on phase with respect to the second
3303 * signal, but the timecode has not been received correctly within
3304 * at least the last two minutes. this is a sort of half baked state
3305 * for PARSE Meinberg DCF77 clocks this is bad news (clock running
3306 * without timecode confirmation)
3307 * PZF 535 has also no time confirmation, but the phase should be
3308 * very precise as the PZF signal can be decoded
3311 if (PARSE_SYNC(parsetime->parse_state))
3314 * currently completely synchronized - best possible state
3316 parse->lastsync = current_time;
3317 clear_err(parse, ERR_BADSTATUS);
3322 * we have had some problems receiving the time code
3324 parse_event(parse, CEVNT_PROP);
3325 NLOG(NLOG_CLOCKSTATUS)
3327 msyslog(LOG_ERR,"PARSE receiver #%d: TIMECODE NOT CONFIRMED",
3328 CLK_UNIT(parse->peer));
3332 fudge = parse->generic->fudgetime1; /* standard RS232 Fudgefactor */
3334 if (PARSE_TIMECODE(parsetime->parse_state))
3336 rectime = parsetime->parse_stime.fp;
3337 off = reftime = parsetime->parse_time.fp;
3339 L_SUB(&off, &rectime); /* prepare for PPS adjustments logic */
3343 printf("PARSE receiver #%d: Reftime %s, Recvtime %s - initial offset %s\n",
3344 CLK_UNIT(parse->peer),
3345 prettydate(&reftime),
3346 prettydate(&rectime),
3351 if (PARSE_PPS(parsetime->parse_state) && CLK_PPS(parse->peer))
3356 * we have a PPS signal - much better than the RS232 stuff (we hope)
3358 offset = parsetime->parse_ptime.fp;
3362 printf("PARSE receiver #%d: PPStime %s\n",
3363 CLK_UNIT(parse->peer),
3364 prettydate(&offset));
3366 if (PARSE_TIMECODE(parsetime->parse_state))
3368 if (M_ISGEQ(off.l_i, off.l_f, -1, 0x80000000) &&
3369 M_ISGEQ(0, 0x7fffffff, off.l_i, off.l_f))
3371 fudge = parse->generic->fudgetime2; /* pick PPS fudge factor */
3374 * RS232 offsets within [-0.5..0.5[ - take PPS offsets
3377 if (parse->parse_type->cl_flags & PARSE_F_PPSONSECOND)
3379 reftime = off = offset;
3380 if (reftime.l_uf & (unsigned)0x80000000)
3386 * implied on second offset
3388 off.l_uf = ~off.l_uf; /* map [0.5..1[ -> [-0.5..0[ */
3389 off.l_ui = (off.l_f < 0) ? ~0 : 0; /* sign extend */
3394 * time code describes pulse
3396 reftime = off = parsetime->parse_time.fp;
3398 L_SUB(&off, &offset); /* true offset */
3402 * take RS232 offset when PPS when out of bounds
3407 fudge = parse->generic->fudgetime2; /* pick PPS fudge factor */
3409 * Well, no time code to guide us - assume on second pulse
3410 * and pray, that we are within [-0.5..0.5[
3414 if (reftime.l_uf & (unsigned)0x80000000)
3418 * implied on second offset
3420 off.l_uf = ~off.l_uf; /* map [0.5..1[ -> [-0.5..0[ */
3421 off.l_ui = (off.l_f < 0) ? ~0 : 0; /* sign extend */
3426 if (!PARSE_TIMECODE(parsetime->parse_state))
3429 * Well, no PPS, no TIMECODE, no more work ...
3431 if ((parsetime->parse_status & CVT_ADDITIONAL) &&
3432 parse->parse_type->cl_message)
3433 parse->parse_type->cl_message(parse, parsetime);
3440 printf("PARSE receiver #%d: Reftime %s, Recvtime %s - final offset %s\n",
3441 CLK_UNIT(parse->peer),
3442 prettydate(&reftime),
3443 prettydate(&rectime),
3449 L_SUB(&rectime, &off); /* just to keep the ntp interface happy */
3453 printf("PARSE receiver #%d: calculated Reftime %s, Recvtime %s\n",
3454 CLK_UNIT(parse->peer),
3455 prettydate(&reftime),
3456 prettydate(&rectime));
3459 if ((parsetime->parse_status & CVT_ADDITIONAL) &&
3460 parse->parse_type->cl_message)
3461 parse->parse_type->cl_message(parse, parsetime);
3463 if (PARSE_SYNC(parsetime->parse_state))
3468 parse_event(parse, CEVNT_NOMINAL);
3471 clear_err(parse, ERR_BADIO);
3472 clear_err(parse, ERR_BADDATA);
3473 clear_err(parse, ERR_NODATA);
3474 clear_err(parse, ERR_INTERNAL);
3479 printf("PARSE receiver #%d: refclock_process_offset(reftime=%s, rectime=%s, Fudge=%f)\n",
3480 CLK_UNIT(parse->peer),
3481 prettydate(&reftime),
3482 prettydate(&rectime),
3487 refclock_process_offset(parse->generic, reftime, rectime, fudge);
3488 if (PARSE_PPS(parsetime->parse_state) && CLK_PPS(parse->peer))
3490 (void) pps_sample(&parse->time.parse_ptime.fp);
3495 * and now stick it into the clock machine
3496 * samples are only valid iff lastsync is not too old and
3497 * we have seen the clock in sync at least once
3498 * after the last time we didn't see an expected data telegram
3499 * see the clock states section above for more reasoning
3501 if (((current_time - parse->lastsync) > parse->parse_type->cl_maxunsync) ||
3502 (parse->lastsync <= parse->lastmissed))
3504 parse->generic->leap = LEAP_NOTINSYNC;
3508 if (PARSE_LEAPADD(parsetime->parse_state))
3511 * we pick this state also for time code that pass leap warnings
3512 * without direction information (as earth is currently slowing
3515 parse->generic->leap = (parse->flags & PARSE_LEAP_DELETE) ? LEAP_DELSECOND : LEAP_ADDSECOND;
3518 if (PARSE_LEAPDEL(parsetime->parse_state))
3520 parse->generic->leap = LEAP_DELSECOND;
3524 parse->generic->leap = LEAP_NOWARNING;
3529 * ready, unless the machine wants a sample
3531 if (!parse->pollneeddata)
3534 parse->pollneeddata = 0;
3536 refclock_receive(parse->peer);
3539 /**===========================================================================
3540 ** special code for special clocks
3555 sprintf(t, "current correction %d sec", dtls);
3564 gpstolfp((unsigned short)wnlsf, (unsigned short)dn, 0, &leapdate);
3566 if ((dtlsf != dtls) &&
3567 ((wnlsf - wnt) < 52))
3569 sprintf(t, ", next correction %d sec on %s, new GPS-UTC offset %d",
3570 dtlsf - dtls, gmprettydate(&leapdate), dtlsf);
3574 sprintf(t, ", last correction on %s",
3575 gmprettydate(&leapdate));
3579 #ifdef CLOCK_MEINBERG
3580 /**===========================================================================
3581 ** Meinberg GPS166/GPS167 support
3584 /*------------------------------------------------------------
3585 * gps16x_message - process GPS16x messages
3589 struct parseunit *parse,
3590 parsetime_t *parsetime
3593 if (parse->time.parse_msglen && parsetime->parse_msg[0] == SOH)
3596 unsigned char *bufp = (unsigned char *)parsetime->parse_msg + 1;
3601 char msgbuffer[600];
3603 mkreadable(msgbuffer, sizeof(msgbuffer), (char *)parsetime->parse_msg, parsetime->parse_msglen, 1);
3604 printf("PARSE receiver #%d: received message (%d bytes) >%s<\n",
3605 CLK_UNIT(parse->peer),
3606 parsetime->parse_msglen,
3610 get_mbg_header(&bufp, &header);
3611 if (header.gps_hdr_csum == mbg_csum(parsetime->parse_msg + 1, 6) &&
3612 (header.gps_len == 0 ||
3613 (header.gps_len < sizeof(parsetime->parse_msg) &&
3614 header.gps_data_csum == mbg_csum(bufp, header.gps_len))))
3619 switch (header.gps_cmd)
3626 get_mbg_sw_rev(&bufp, &gps_sw_rev);
3627 sprintf(buffer, "meinberg_gps_version=\"%x.%02x%s%s\"",
3628 (gps_sw_rev.code >> 8) & 0xFF,
3629 gps_sw_rev.code & 0xFF,
3630 gps_sw_rev.name[0] ? " " : "",
3632 set_var(&parse->kv, buffer, 64, RO|DEF);
3640 unsigned short flag; /* status flag */
3641 unsigned const char *string; /* bit name */
3644 { TM_ANT_DISCONN, (const unsigned char *)"ANTENNA FAULTY" },
3645 { TM_SYN_FLAG, (const unsigned char *)"NO SYNC SIGNAL" },
3646 { TM_NO_SYNC, (const unsigned char *)"NO SYNC POWERUP" },
3647 { TM_NO_POS, (const unsigned char *)"NO POSITION" },
3648 { 0, (const unsigned char *)"" }
3650 unsigned short status;
3651 struct state *s = states;
3655 status = get_lsb_short(&bufp);
3656 sprintf(buffer, "meinberg_gps_status=\"[0x%04x] ", status);
3660 p = b = buffer + strlen(buffer);
3663 if (status & s->flag)
3671 strcat(p, (const char *)s->string);
3681 strcat(buffer, "<OK>\"");
3684 set_var(&parse->kv, buffer, 64, RO|DEF);
3693 get_mbg_xyz(&bufp, xyz);
3694 sprintf(buffer, "gps_position(XYZ)=\"%s m, %s m, %s m\"",
3695 mfptoa(xyz[XP].l_ui, xyz[XP].l_uf, 1),
3696 mfptoa(xyz[YP].l_ui, xyz[YP].l_uf, 1),
3697 mfptoa(xyz[ZP].l_ui, xyz[ZP].l_uf, 1));
3699 set_var(&parse->kv, buffer, sizeof(buffer), RO|DEF);
3708 get_mbg_lla(&bufp, lla);
3710 sprintf(buffer, "gps_position(LLA)=\"%s deg, %s deg, %s m\"",
3711 mfptoa(lla[LAT].l_ui, lla[LAT].l_uf, 4),
3712 mfptoa(lla[LON].l_ui, lla[LON].l_uf, 4),
3713 mfptoa(lla[ALT].l_ui, lla[ALT].l_uf, 1));
3715 set_var(&parse->kv, buffer, sizeof(buffer), RO|DEF);
3734 get_mbg_antinfo(&bufp, &antinfo);
3735 sprintf((char *)buffer, "meinberg_antenna_status=\"");
3736 p = buffer + strlen(buffer);
3738 switch (antinfo.status)
3746 strcat(p, "DISCONNECTED since ");
3747 NLOG(NLOG_CLOCKSTATUS)
3749 msyslog(LOG_ERR,"PARSE receiver #%d: ANTENNA FAILURE: %s",
3750 CLK_UNIT(parse->peer), p);
3753 mbg_tm_str((unsigned char **)&p, &antinfo.tm_disconn);
3758 strcat(p, "RECONNECTED on ");
3760 mbg_tm_str((unsigned char **)&p, &antinfo.tm_reconn);
3761 sprintf(p, ", reconnect clockoffset %c%ld.%07ld s, disconnect time ",
3762 (antinfo.delta_t < 0) ? '-' : '+',
3763 ABS(antinfo.delta_t) / 10000,
3764 ABS(antinfo.delta_t) % 10000);
3766 mbg_tm_str((unsigned char **)&p, &antinfo.tm_disconn);
3771 sprintf(p, "bad status 0x%04x", antinfo.status);
3779 set_var(&parse->kv, buffer, sizeof(buffer), RO|DEF);
3792 get_mbg_cfgh(&bufp, &cfgh);
3798 strcpy(buffer, "gps_tot_51=\"");
3800 mbg_tgps_str((unsigned char **)&p, &cfgh.tot_51);
3803 set_var(&parse->kv, buffer, sizeof(buffer), RO);
3806 strcpy(buffer, "gps_tot_63=\"");
3808 mbg_tgps_str((unsigned char **)&p, &cfgh.tot_63);
3811 set_var(&parse->kv, buffer, sizeof(buffer), RO);
3814 strcpy(buffer, "gps_t0a=\"");
3816 mbg_tgps_str((unsigned char **)&p, &cfgh.t0a);
3819 set_var(&parse->kv, buffer, sizeof(buffer), RO);
3821 for (i = MIN_SVNO; i <= MAX_SVNO; i++)
3824 sprintf(p, "gps_cfg[%d]=\"[0x%x] ", i, cfgh.cfg[i]);
3826 switch (cfgh.cfg[i] & 0x7)
3829 strcpy(p, "BLOCK I");
3832 strcpy(p, "BLOCK II");
3835 sprintf(p, "bad CFG");
3839 set_var(&parse->kv, buffer, sizeof(buffer), RO);
3842 sprintf(p, "gps_health[%d]=\"[0x%x] ", i, cfgh.health[i]);
3844 switch ((cfgh.health[i] >> 5) & 0x7 )
3850 strcpy(p, "PARITY;");
3853 strcpy(p, "TLM/HOW;");
3856 strcpy(p, "Z-COUNT;");
3859 strcpy(p, "SUBFRAME 1,2,3;");
3862 strcpy(p, "SUBFRAME 4,5;");
3865 strcpy(p, "UPLOAD BAD;");
3868 strcpy(p, "DATA BAD;");
3874 switch (cfgh.health[i] & 0x1F)
3877 strcpy(p, "SIGNAL OK");
3880 strcpy(p, "SV TEMP OUT");
3883 strcpy(p, "SV WILL BE TEMP OUT");
3888 strcpy(p, "MULTIPLE ERRS");
3891 strcpy(p, "TRANSMISSION PROBLEMS");
3896 set_var(&parse->kv, buffer, sizeof(buffer), RO);
3916 get_mbg_utc(&bufp, &utc);
3920 strcpy(p, "gps_utc_correction=\"");
3922 mk_utcinfo(p, utc.t0t.wn, utc.WNlsf, utc.DNt, utc.delta_tls, utc.delta_tlsf);
3927 strcpy(p, "gps_utc_correction=\"<NO UTC DATA>\"");
3929 set_var(&parse->kv, buffer, sizeof(buffer), RO|DEF);
3938 ASCII_MSG gps_ascii_msg;
3941 get_mbg_ascii_msg(&bufp, &gps_ascii_msg);
3943 if (gps_ascii_msg.valid)
3946 mkreadable(buffer1, sizeof(buffer1), gps_ascii_msg.s, strlen(gps_ascii_msg.s), (int)0);
3948 sprintf(buffer, "gps_message=\"%s\"", buffer1);
3951 strcpy(buffer, "gps_message=<NONE>");
3953 set_var(&parse->kv, buffer, 128, RO|DEF);
3964 msyslog(LOG_DEBUG, "PARSE receiver #%d: gps16x_message: message checksum error: hdr_csum = 0x%x (expected 0x%lx), data_len = %d, data_csum = 0x%x (expected 0x%lx)",
3965 CLK_UNIT(parse->peer),
3966 header.gps_hdr_csum, mbg_csum(parsetime->parse_msg + 1, 6),
3968 header.gps_data_csum, mbg_csum(bufp, (unsigned)((header.gps_len < sizeof(parsetime->parse_msg)) ? header.gps_len : 0)));
3975 /*------------------------------------------------------------
3976 * gps16x_poll - query the reciver peridically
3983 struct parseunit *parse = (struct parseunit *)peer->procptr->unitptr;
3985 static GPS_MSG_HDR sequence[] =
3987 { GPS_SW_REV, 0, 0, 0 },
3988 { GPS_STAT, 0, 0, 0 },
3989 { GPS_UTC, 0, 0, 0 },
3990 { GPS_ASCII_MSG, 0, 0, 0 },
3991 { GPS_ANT_INFO, 0, 0, 0 },
3992 { GPS_CFGH, 0, 0, 0 },
3993 { GPS_POS_XYZ, 0, 0, 0 },
3994 { GPS_POS_LLA, 0, 0, 0 },
3995 { (unsigned short)~0, 0, 0, 0 }
3999 unsigned char cmd_buffer[64];
4000 unsigned char *outp = cmd_buffer;
4001 GPS_MSG_HDR *header;
4003 if (((poll_info_t *)parse->parse_type->cl_data)->rate)
4005 parse->peer->nextaction = current_time + ((poll_info_t *)parse->parse_type->cl_data)->rate;
4008 if (sequence[parse->localstate].gps_cmd == (unsigned short)~0)
4009 parse->localstate = 0;
4011 header = sequence + parse->localstate++;
4013 *outp++ = SOH; /* start command */
4015 put_mbg_header(&outp, header);
4016 outp = cmd_buffer + 1;
4018 header->gps_hdr_csum = (short)mbg_csum(outp, 6);
4019 put_mbg_header(&outp, header);
4026 mkreadable(buffer, sizeof(buffer), (char *)cmd_buffer, (unsigned)(outp - cmd_buffer), 1);
4027 printf("PARSE receiver #%d: transmitted message #%ld (%d bytes) >%s<\n",
4028 CLK_UNIT(parse->peer),
4029 parse->localstate - 1,
4030 (int)(outp - cmd_buffer),
4035 rtc = write(parse->generic->io.fd, cmd_buffer, (unsigned long)(outp - cmd_buffer));
4040 msyslog(LOG_ERR, "PARSE receiver #%d: gps16x_poll: failed to send cmd to clock: %m", CLK_UNIT(parse->peer));
4043 if (rtc != outp - cmd_buffer)
4046 msyslog(LOG_ERR, "PARSE receiver #%d: gps16x_poll: failed to send cmd incomplete (%d of %d bytes sent)", CLK_UNIT(parse->peer), rtc, (int)(outp - cmd_buffer));
4049 clear_err(parse, ERR_BADIO);
4053 /*--------------------------------------------------
4054 * init routine - setup timer
4058 struct parseunit *parse
4061 if (((poll_info_t *)parse->parse_type->cl_data)->rate)
4063 parse->peer->action = gps16x_poll;
4064 gps16x_poll(parse->peer);
4073 struct parseunit *parse,
4074 parsetime_t *parsetime
4079 struct parseunit *parse
4084 #endif /* CLOCK_MEINBERG */
4086 /**===========================================================================
4087 ** clock polling support
4090 /*--------------------------------------------------
4091 * direct poll routine
4095 struct parseunit *parse
4099 const char *ps = ((poll_info_t *)parse->parse_type->cl_data)->string;
4100 int ct = ((poll_info_t *)parse->parse_type->cl_data)->count;
4102 rtc = write(parse->generic->io.fd, ps, (unsigned long)ct);
4106 msyslog(LOG_ERR, "PARSE receiver #%d: poll_dpoll: failed to send cmd to clock: %m", CLK_UNIT(parse->peer));
4112 msyslog(LOG_ERR, "PARSE receiver #%d: poll_dpoll: failed to send cmd incomplete (%d of %d bytes sent)", CLK_UNIT(parse->peer), rtc, ct);
4114 clear_err(parse, ERR_BADIO);
4117 /*--------------------------------------------------
4118 * periodic poll routine
4125 struct parseunit *parse = (struct parseunit *)peer->procptr->unitptr;
4127 if (parse->parse_type->cl_poll)
4128 parse->parse_type->cl_poll(parse);
4130 if (((poll_info_t *)parse->parse_type->cl_data)->rate)
4132 parse->peer->nextaction = current_time + ((poll_info_t *)parse->parse_type->cl_data)->rate;
4136 /*--------------------------------------------------
4137 * init routine - setup timer
4141 struct parseunit *parse
4144 if (((poll_info_t *)parse->parse_type->cl_data)->rate)
4146 parse->peer->action = poll_poll;
4147 poll_poll(parse->peer);
4153 /**===========================================================================
4157 /*-------------------------------------------------------------
4158 * trimble TAIP init routine - setup EOL and then do poll_init.
4162 struct parseunit *parse
4168 #ifdef HAVE_SYSV_TTYS
4172 * configure terminal line for trimble receiver
4174 if (TTY_GETATTR(parse->generic->io.fd, &tio) == -1)
4176 msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_init: tcgetattr(fd, &tio): %m", CLK_UNIT(parse->peer));
4181 tio.c_cc[VEOL] = TRIMBLETAIP_EOL;
4183 if (TTY_SETATTR(parse->generic->io.fd, &tio) == -1)
4185 msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_init: tcsetattr(fd, &tio): %m", CLK_UNIT(parse->peer));
4189 return poll_init(parse);
4192 /*--------------------------------------------------
4193 * trimble TAIP event routine - reset receiver upon data format trouble
4195 static const char *taipinit[] = {
4197 ">SRM;ID_FLAG=F;CS_FLAG=T;EC_FLAG=F;FR_FLAG=T;CR_FLAG=F<",
4204 struct parseunit *parse,
4210 case CEVNT_BADREPLY: /* reset on garbled input */
4211 case CEVNT_TIMEOUT: /* reset on no input */
4218 int rtc = write(parse->generic->io.fd, *iv, strlen(*iv));
4221 msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_event: failed to send cmd to clock: %m", CLK_UNIT(parse->peer));
4226 if (rtc != strlen(*iv))
4228 msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_event: failed to send cmd incomplete (%d of %d bytes sent)",
4229 CLK_UNIT(parse->peer), rtc, (int)strlen(*iv));
4236 NLOG(NLOG_CLOCKINFO)
4238 msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_event: RECEIVER INITIALIZED",
4239 CLK_UNIT(parse->peer));
4243 default: /* ignore */
4249 * This driver supports the Trimble SVee Six Plus GPS receiver module.
4250 * It should support other Trimble receivers which use the Trimble Standard
4251 * Interface Protocol (see below).
4253 * The module has a serial I/O port for command/data and a 1 pulse-per-second
4254 * output, about 1 microsecond wide. The leading edge of the pulse is
4255 * coincident with the change of the GPS second. This is the same as
4256 * the change of the UTC second +/- ~1 microsecond. Some other clocks
4257 * specifically use a feature in the data message as a timing reference, but
4258 * the SVee Six Plus does not do this. In fact there is considerable jitter
4259 * on the timing of the messages, so this driver only supports the use
4260 * of the PPS pulse for accurate timing. Where it is determined that
4261 * the offset is way off, when first starting up ntpd for example,
4262 * the timing of the data stream is used until the offset becomes low enough
4263 * (|offset| < CLOCK_MAX), at which point the pps offset is used.
4265 * It can use either option for receiving PPS information - the 'ppsclock'
4266 * stream pushed onto the serial data interface to timestamp the Carrier
4267 * Detect interrupts, where the 1PPS connects to the CD line. This only
4268 * works on SunOS 4.1.x currently. To select this, define PPSPPS in
4269 * Config.local. The other option is to use a pulse-stretcher/level-converter
4270 * to convert the PPS pulse into a RS232 start pulse & feed this into another
4271 * tty port. To use this option, define PPSCLK in Config.local. The pps input,
4272 * by whichever method, is handled in ntp_loopfilter.c
4274 * The receiver uses a serial message protocol called Trimble Standard
4275 * Interface Protocol (it can support others but this driver only supports
4276 * TSIP). Messages in this protocol have the following form:
4278 * <DLE><id> ... <data> ... <DLE><ETX>
4280 * Any bytes within the <data> portion of value 10 hex (<DLE>) are doubled
4281 * on transmission and compressed back to one on reception. Otherwise
4282 * the values of data bytes can be anything. The serial interface is RS-422
4283 * asynchronous using 9600 baud, 8 data bits with odd party (**note** 9 bits
4284 * in total!), and 1 stop bit. The protocol supports byte, integer, single,
4285 * and double datatypes. Integers are two bytes, sent most significant first.
4286 * Singles are IEEE754 single precision floating point numbers (4 byte) sent
4287 * sign & exponent first. Doubles are IEEE754 double precision floating point
4288 * numbers (8 byte) sent sign & exponent first.
4289 * The receiver supports a large set of messages, only a small subset of
4290 * which are used here. From driver to receiver the following are used:
4294 * 21 Request current time
4296 * 2C Set/Request operating parameters
4297 * 2F Request UTC info
4298 * 35 Set/Request I/O options
4300 * From receiver to driver the following are recognised:
4305 * 44 Satellite selection, PDOP, mode
4306 * 46 Receiver health
4307 * 4B Machine code/status
4308 * 4C Report operating parameters (debug only)
4309 * 4F UTC correction data (used to get leap second warnings)
4310 * 55 I/O options (debug only)
4312 * All others are accepted but ignored.
4316 #define PI 3.1415926535898 /* lots of sig figs */
4317 #define D2R PI/180.0
4319 /*-------------------------------------------------------------------
4320 * sendcmd, sendbyte, sendetx, sendflt, sendint implement the command
4321 * interface to the receiver.
4323 * CAVEAT: the sendflt, sendint routines are byte order dependend and
4324 * float implementation dependend - these must be converted to portable
4327 * CURRENT LIMITATION: float implementation. This runs only on systems
4328 * with IEEE754 floats as native floats
4331 typedef struct trimble
4333 u_long last_msg; /* last message received */
4334 u_char qtracking; /* query tracking status */
4335 u_long ctrack; /* current tracking set */
4336 u_long ltrack; /* last tracking set */
4348 short idx; /* index to first unused byte */
4349 u_char *txt; /* pointer to actual data buffer */
4352 void sendcmd P((struct txbuf *buf, int c));
4353 void sendbyte P((struct txbuf *buf, int b));
4354 void sendetx P((struct txbuf *buf, struct parseunit *parse));
4355 void sendint P((struct txbuf *buf, int a));
4356 void sendflt P((struct txbuf *buf, double a));
4365 buf->txt[1] = (u_char)c;
4376 buf->txt[buf->idx++] = DLE;
4377 buf->txt[buf->idx++] = (u_char)b;
4383 struct parseunit *parse
4386 buf->txt[buf->idx++] = DLE;
4387 buf->txt[buf->idx++] = ETX;
4389 if (write(parse->generic->io.fd, buf->txt, (unsigned long)buf->idx) != buf->idx)
4392 msyslog(LOG_ERR, "PARSE receiver #%d: sendetx: failed to send cmd to clock: %m", CLK_UNIT(parse->peer));
4401 mkreadable(buffer, sizeof(buffer), (char *)buf->txt, (unsigned)buf->idx, 1);
4402 printf("PARSE receiver #%d: transmitted message (%d bytes) >%s<\n",
4403 CLK_UNIT(parse->peer),
4407 clear_err(parse, ERR_BADIO);
4417 /* send 16bit int, msbyte first */
4418 sendbyte(buf, (u_char)((a>>8) & 0xff));
4419 sendbyte(buf, (u_char)(a & 0xff));
4432 #ifdef WORDS_BIGENDIAN
4433 for (i=0; i<=3; i++)
4435 for (i=3; i>=0; i--)
4437 sendbyte(buf, uval.bd[i]);
4440 #define TRIM_POS_OPT 0x13 /* output position with high precision */
4441 #define TRIM_TIME_OPT 0x03 /* use UTC time stamps, on second */
4443 /*--------------------------------------------------
4444 * trimble TSIP setup routine
4448 struct parseunit *parse,
4457 sendcmd(&buf, CMD_CVERSION); /* request software versions */
4458 sendetx(&buf, parse);
4460 sendcmd(&buf, CMD_COPERPARAM); /* set operating parameters */
4461 sendbyte(&buf, 4); /* static */
4462 sendflt(&buf, 5.0*D2R); /* elevation angle mask = 10 deg XXX */
4463 sendflt(&buf, 4.0); /* s/n ratio mask = 6 XXX */
4464 sendflt(&buf, 12.0); /* PDOP mask = 12 */
4465 sendflt(&buf, 8.0); /* PDOP switch level = 8 */
4466 sendetx(&buf, parse);
4468 sendcmd(&buf, CMD_CMODESEL); /* fix mode select */
4469 sendbyte(&buf, 0); /* automatic */
4470 sendetx(&buf, parse);
4472 sendcmd(&buf, CMD_CMESSAGE); /* request system message */
4473 sendetx(&buf, parse);
4475 sendcmd(&buf, CMD_CSUPER); /* superpacket fix */
4476 sendbyte(&buf, 0x2); /* binary mode */
4477 sendetx(&buf, parse);
4479 sendcmd(&buf, CMD_CIOOPTIONS); /* set I/O options */
4480 sendbyte(&buf, TRIM_POS_OPT); /* position output */
4481 sendbyte(&buf, 0x00); /* no velocity output */
4482 sendbyte(&buf, TRIM_TIME_OPT); /* UTC, compute on seconds */
4483 sendbyte(&buf, 0x00); /* no raw measurements */
4484 sendetx(&buf, parse);
4486 sendcmd(&buf, CMD_CUTCPARAM); /* request UTC correction data */
4487 sendetx(&buf, parse);
4489 NLOG(NLOG_CLOCKINFO)
4491 msyslog(LOG_ERR, "PARSE receiver #%d: trimbletsip_setup: RECEIVER RE-INITIALIZED (%s)", CLK_UNIT(parse->peer), reason);
4496 /*--------------------------------------------------
4497 * TRIMBLE TSIP check routine
4504 struct parseunit *parse = (struct parseunit *)peer->procptr->unitptr;
4505 trimble_t *t = parse->localdata;
4512 if (current_time > t->last_msg + TRIMBLETSIP_IDLE_TIME)
4513 (void)trimbletsip_setup(parse, "message timeout");
4515 poll_poll(parse->peer); /* emit query string and re-arm timer */
4519 u_long oldsats = t->ltrack & ~t->ctrack;
4522 t->ltrack = t->ctrack;
4528 for (i = 0; oldsats; i++)
4529 if (oldsats & (1 << i))
4531 sendcmd(&buf, CMD_CSTATTRACK);
4532 sendbyte(&buf, i+1); /* old sat */
4533 sendetx(&buf, parse);
4535 oldsats &= ~(1 << i);
4538 sendcmd(&buf, CMD_CSTATTRACK);
4539 sendbyte(&buf, 0x00); /* current tracking set */
4540 sendetx(&buf, parse);
4544 /*--------------------------------------------------
4545 * TRIMBLE TSIP end routine
4549 struct parseunit *parse
4551 { trimble_t *t = parse->localdata;
4556 parse->localdata = (void *)0;
4558 parse->peer->nextaction = 0;
4559 parse->peer->action = (void (*) P((struct peer *)))0;
4562 /*--------------------------------------------------
4563 * TRIMBLE TSIP init routine
4567 struct parseunit *parse
4570 #if defined(VEOL) || defined(VEOL2)
4572 struct termios tio; /* NEEDED FOR A LONG TIME ! */
4574 #ifdef HAVE_SYSV_TTYS
4575 struct termio tio; /* NEEDED FOR A LONG TIME ! */
4578 * allocate local data area
4580 if (!parse->localdata)
4584 t = (trimble_t *)(parse->localdata = emalloc(sizeof(trimble_t)));
4588 memset((char *)t, 0, sizeof(trimble_t));
4589 t->last_msg = current_time;
4593 parse->peer->action = trimble_check;
4594 parse->peer->nextaction = current_time;
4597 * configure terminal line for ICANON mode with VEOL characters
4599 if (TTY_GETATTR(parse->generic->io.fd, &tio) == -1)
4601 msyslog(LOG_ERR, "PARSE receiver #%d: trimbletsip_init: tcgetattr(%d, &tio): %m", CLK_UNIT(parse->peer), parse->generic->io.fd);
4606 if ((parse_clockinfo[CLK_TYPE(parse->peer)].cl_lflag & ICANON))
4609 tio.c_cc[VEOL] = ETX;
4612 tio.c_cc[VEOL2] = DLE;
4616 if (TTY_SETATTR(parse->generic->io.fd, &tio) == -1)
4618 msyslog(LOG_ERR, "PARSE receiver #%d: trimbletsip_init: tcsetattr(%d, &tio): %m", CLK_UNIT(parse->peer), parse->generic->io.fd);
4623 return trimbletsip_setup(parse, "initial startup");
4626 /*------------------------------------------------------------
4627 * trimbletsip_event - handle Trimble events
4628 * simple evente handler - attempt to re-initialize receiver
4632 struct parseunit *parse,
4638 case CEVNT_BADREPLY: /* reset on garbled input */
4639 case CEVNT_TIMEOUT: /* reset on no input */
4640 (void)trimbletsip_setup(parse, "event BAD_REPLY/TIMEOUT");
4643 default: /* ignore */
4649 * getflt, getint convert fields in the incoming data into the
4650 * appropriate type of item
4652 * CAVEAT: these routines are currently definitely byte order dependent
4653 * and assume Representation(float) == IEEE754
4654 * These functions MUST be converted to portable versions (especially
4655 * converting the float representation into ntp_fp formats in order
4656 * to avoid floating point operations at all!
4666 #ifdef WORDS_BIGENDIAN
4671 #else /* ! WORDS_BIGENDIAN */
4676 #endif /* ! WORDS_BIGENDIAN */
4687 #ifdef WORDS_BIGENDIAN
4696 #else /* ! WORDS_BIGENDIAN */
4705 #endif /* ! WORDS_BIGENDIAN */
4714 return get_msb_short(&p);
4717 /*--------------------------------------------------
4718 * trimbletsip_message - process trimble messages
4720 #define RTOD (180.0 / 3.1415926535898)
4721 #define mb(_X_) (buffer[2+(_X_)]) /* shortcut for buffer access */
4724 trimbletsip_message(
4725 struct parseunit *parse,
4726 parsetime_t *parsetime
4729 unsigned char *buffer = parsetime->parse_msg;
4730 unsigned int size = parsetime->parse_msglen;
4733 (buffer[0] != DLE) ||
4734 (buffer[size-1] != ETX) ||
4735 (buffer[size-2] != DLE))
4741 printf("TRIMBLE BAD packet, size %d:\n ", size);
4742 for (i = 0; i < size; i++) {
4743 printf ("%2.2x, ", buffer[i]&0xff);
4744 if (i%16 == 15) printf("\n\t");
4754 trimble_t *tr = parse->localdata;
4755 unsigned int cmd = buffer[1];
4764 printf("TRIMBLE packet 0x%02x, size %d:\n ", cmd, size);
4765 for (i = 0; i < size; i++) {
4766 printf ("%2.2x, ", buffer[i]&0xff);
4767 if (i%16 == 15) printf("\n\t");
4774 tr->last_msg = current_time;
4776 s = trimble_convert(cmd, trimble_rcmds);
4780 sprintf(t, "%s=\"", s->varname);
4784 printf("TRIMBLE unknown command 0x%02x\n", cmd);
4788 var_flag = s->varmode;
4795 sprintf(t, "%f, %d, %f",
4796 getflt((unsigned char *)&mb(0)), getshort((unsigned char *)&mb(4)),
4797 getflt((unsigned char *)&mb(6)));
4801 strcpy(t, "mode: ");
4803 switch (mb(0) & 0xF)
4806 sprintf(t, "0x%x", mb(0) & 0x7);
4823 strcpy(t, "-MANUAL, ");
4825 strcpy(t, "-AUTO, ");
4828 sprintf(t, "satellites %02d %02d %02d %02d, PDOP %.2f, HDOP %.2f, VDOP %.2f, TDOP %.2f",
4829 mb(1), mb(2), mb(3), mb(4),
4830 getflt((unsigned char *)&mb(5)),
4831 getflt((unsigned char *)&mb(9)),
4832 getflt((unsigned char *)&mb(13)),
4833 getflt((unsigned char *)&mb(17)));
4838 sprintf(t, "%d.%d (%d/%d/%d)",
4839 mb(0)&0xff, mb(1)&0xff, 1900+(mb(4)&0xff), mb(2)&0xff, mb(3)&0xff);
4842 case CMD_RRECVHEALTH:
4844 static const char *msgs[] =
4846 "Battery backup failed",
4847 "Signal processor error",
4848 "Alignment error, channel or chip 1",
4849 "Alignment error, channel or chip 2",
4850 "Antenna feed line fault",
4851 "Excessive ref freq. error",
4858 switch (mb(0) & 0xFF)
4861 sprintf(t, "illegal value 0x%02x", mb(0) & 0xFF);
4864 strcpy(t, "doing position fixes");
4867 strcpy(t, "no GPS time yet");
4870 strcpy(t, "PDOP too high");
4873 strcpy(t, "no usable satellites");
4876 strcpy(t, "only ONE usable satellite");
4879 strcpy(t, "only TWO usable satellites");
4882 strcpy(t, "only THREE usable satellites");
4885 strcpy(t, "the chosen satellite is unusable");
4891 bits = mb(1) & 0xFF;
4893 for (i = 0; i < 8; i++)
4894 if (bits & (0x1<<i))
4896 sprintf(t, ", %s", msgs[i]);
4903 mkreadable(t, (int)(sizeof(pbuffer) - (t - pbuffer)), (char *)&mb(0), (unsigned)(size - 2 - (&mb(0) - buffer)), 0);
4908 static const char *msgs[] =
4910 "Synthesizer Fault",
4911 "Battery Powered Time Clock Fault",
4912 "A-to-D Converter Fault",
4913 "The almanac stored in the receiver is not complete and current",
4922 sprintf(t, "machine id 0x%02x", mb(0) & 0xFF);
4925 bits = mb(1) & 0xFF;
4927 for (i = 0; i < 8; i++)
4928 if (bits & (0x1<<i))
4930 sprintf(t, ", %s", msgs[i]);
4934 sprintf(t, ", Superpackets %ssupported", (mb(2) & 0xFF) ? "" :"un" );
4938 case CMD_ROPERPARAM:
4939 sprintf(t, "%2x %.1f %.1f %.1f %.1f",
4940 mb(0), getflt((unsigned char *)&mb(1)), getflt((unsigned char *)&mb(5)),
4941 getflt((unsigned char *)&mb(9)), getflt((unsigned char *)&mb(13)));
4946 float t0t = getflt((unsigned char *)&mb(14));
4947 short wnt = getshort((unsigned char *)&mb(18));
4948 short dtls = getshort((unsigned char *)&mb(12));
4949 short wnlsf = getshort((unsigned char *)&mb(20));
4950 short dn = getshort((unsigned char *)&mb(22));
4951 short dtlsf = getshort((unsigned char *)&mb(24));
4955 mk_utcinfo(t, wnt, wnlsf, dn, dtls, dtlsf);
4959 strcpy(t, "<NO UTC DATA>");
4965 sprintf(t, "%.1fm %.2fm/s at %.1fs",
4966 getflt(&mb(0)), getflt(&mb(4)), getflt(&mb(8)));
4969 case CMD_RIOOPTIONS:
4971 sprintf(t, "%02x %02x %02x %02x",
4972 mb(0), mb(1), mb(2), mb(3));
4973 if (mb(0) != TRIM_POS_OPT ||
4974 mb(2) != TRIM_TIME_OPT)
4976 (void)trimbletsip_setup(parse, "bad io options");
4983 double x = getflt((unsigned char *)&mb(0));
4984 double y = getflt((unsigned char *)&mb(4));
4985 double z = getflt((unsigned char *)&mb(8));
4986 double f = getflt((unsigned char *)&mb(12));
4989 sprintf(t, "x= %.1fm, y= %.1fm, z= %.1fm, time_of_fix= %f sec",
4999 double lat = getflt((unsigned char *)&mb(0));
5000 double lng = getflt((unsigned char *)&mb(4));
5001 double f = getflt((unsigned char *)&mb(12));
5004 sprintf(t, "lat %f %c, long %f %c, alt %.2fm",
5005 ((lat < 0.0) ? (-lat) : (lat))*RTOD, (lat < 0.0 ? 'S' : 'N'),
5006 ((lng < 0.0) ? (-lng) : (lng))*RTOD, (lng < 0.0 ? 'W' : 'E'),
5007 getflt((unsigned char *)&mb(8)));
5013 case CMD_RDOUBLEXYZ:
5015 double x = getdbl((unsigned char *)&mb(0));
5016 double y = getdbl((unsigned char *)&mb(8));
5017 double z = getdbl((unsigned char *)&mb(16));
5018 sprintf(t, "x= %.1fm, y= %.1fm, z= %.1fm",
5023 case CMD_RDOUBLELLA:
5025 double lat = getdbl((unsigned char *)&mb(0));
5026 double lng = getdbl((unsigned char *)&mb(8));
5027 sprintf(t, "lat %f %c, lon %f %c, alt %.2fm",
5028 ((lat < 0.0) ? (-lat) : (lat))*RTOD, (lat < 0.0 ? 'S' : 'N'),
5029 ((lng < 0.0) ? (-lng) : (lng))*RTOD, (lng < 0.0 ? 'W' : 'E'),
5030 getdbl((unsigned char *)&mb(16)));
5034 case CMD_RALLINVIEW:
5038 strcpy(t, "mode: ");
5040 switch (mb(0) & 0x7)
5043 sprintf(t, "0x%x", mb(0) & 0x7);
5056 strcpy(t, "-MANUAL, ");
5058 strcpy(t, "-AUTO, ");
5061 sats = (mb(0)>>4) & 0xF;
5063 sprintf(t, "PDOP %.2f, HDOP %.2f, VDOP %.2f, TDOP %.2f, %d satellite%s in view: ",
5064 getflt((unsigned char *)&mb(1)),
5065 getflt((unsigned char *)&mb(5)),
5066 getflt((unsigned char *)&mb(9)),
5067 getflt((unsigned char *)&mb(13)),
5068 sats, (sats == 1) ? "" : "s");
5071 for (i=0; i < sats; i++)
5073 sprintf(t, "%s%02d", i ? ", " : "", mb(17+i));
5076 tr->ctrack |= (1 << (mb(17+i)-1));
5080 { /* mark for tracking status query */
5086 case CMD_RSTATTRACK:
5088 sprintf(t-2, "[%02d]=\"", mb(0)); /* add index to var name */
5091 if (getflt((unsigned char *)&mb(4)) < 0.0)
5093 strcpy(t, "<NO MEASUREMENTS>");
5098 sprintf(t, "ch=%d, acq=%s, eph=%d, signal_level= %5.2f, elevation= %5.2f, azimuth= %6.2f",
5100 mb(2) ? ((mb(2) == 1) ? "ACQ" : "SRCH") : "NEVER",
5102 getflt((unsigned char *)&mb(4)),
5103 getflt((unsigned char *)&mb(12)) * RTOD,
5104 getflt((unsigned char *)&mb(16)) * RTOD);
5115 strcpy(t, ", BAD PARITY");
5118 strcpy(t, ", BAD EPH HEALTH");
5122 strcpy(t, ", collecting data");
5128 strcpy(t, "<UNDECODED>");
5132 set_var(&parse->kv, pbuffer, sizeof(pbuffer), var_flag);
5137 /**============================================================
5141 /*--------------------------------------------------
5142 * rawdcf_init_1 - set up modem lines for RAWDCF receivers
5145 #if defined(TIOCMSET) && (defined(TIOCM_DTR) || defined(CIOCM_DTR))
5148 struct parseunit *parse
5151 /* fixed 2000 for using with Linux by Wolfram Pienkoss <wp@bszh.de> */
5153 * You can use the RS232 to supply the power for a DCF77 receiver.
5154 * Here a voltage between the DTR and the RTS line is used. Unfortunately
5155 * the name has changed from CIOCM_DTR to TIOCM_DTR recently.
5159 if (ioctl(parse->generic->io.fd, TIOCMGET, (caddr_t)&sl232) == -1)
5161 msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_1: WARNING: ioctl(fd, TIOCMGET, [C|T]IOCM_DTR): %m", CLK_UNIT(parse->peer));
5166 sl232 = (sl232 & ~TIOCM_RTS) | TIOCM_DTR; /* turn on DTR, clear RTS for power supply */
5168 sl232 = (sl232 & ~CIOCM_RTS) | CIOCM_DTR; /* turn on DTR, clear RTS for power supply */
5171 if (ioctl(parse->generic->io.fd, TIOCMSET, (caddr_t)&sl232) == -1)
5173 msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_1: WARNING: ioctl(fd, TIOCMSET, [C|T]IOCM_DTR): %m", CLK_UNIT(parse->peer));
5180 struct parseunit *parse
5183 msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_1: WARNING: OS interface incapable of setting DTR to power DCF modules", CLK_UNIT(parse->peer));
5186 #endif /* DTR initialisation type */
5188 /*--------------------------------------------------
5189 * rawdcf_init_2 - set up modem lines for RAWDCF receivers
5190 * CLR DTR line, SET RTS line
5192 #if defined(TIOCMSET) && (defined(TIOCM_RTS) || defined(CIOCM_RTS))
5195 struct parseunit *parse
5198 /* fixed 2000 for using with Linux by Wolfram Pienkoss <wp@bszh.de> */
5200 * You can use the RS232 to supply the power for a DCF77 receiver.
5201 * Here a voltage between the DTR and the RTS line is used. Unfortunately
5202 * the name has changed from CIOCM_DTR to TIOCM_DTR recently.
5206 if (ioctl(parse->generic->io.fd, TIOCMGET, (caddr_t)&sl232) == -1)
5208 msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_2: WARNING: ioctl(fd, TIOCMGET, [C|T]IOCM_RTS): %m", CLK_UNIT(parse->peer));
5213 sl232 = (sl232 & ~TIOCM_DTR) | TIOCM_RTS; /* turn on RTS, clear DTR for power supply */
5215 sl232 = (sl232 & ~CIOCM_DTR) | CIOCM_RTS; /* turn on RTS, clear DTR for power supply */
5218 if (ioctl(parse->generic->io.fd, TIOCMSET, (caddr_t)&sl232) == -1)
5220 msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_2: WARNING: ioctl(fd, TIOCMSET, [C|T]IOCM_RTS): %m", CLK_UNIT(parse->peer));
5227 struct parseunit *parse
5230 msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_2: WARNING: OS interface incapable of setting RTS to power DCF modules", CLK_UNIT(parse->peer));
5233 #endif /* DTR initialisation type */
5235 #else /* defined(REFCLOCK) && defined(PARSE) */
5236 int refclock_parse_bs;
5237 #endif /* defined(REFCLOCK) && defined(PARSE) */
5242 * refclock_parse.c,v
5243 * Revision 4.36 1999/11/28 17:18:20 kardel
5244 * disabled burst mode
5246 * Revision 4.35 1999/11/28 09:14:14 kardel
5249 * Revision 4.34 1999/05/14 06:08:05 kardel
5250 * store current_time in a suitable container (u_long)
5252 * Revision 4.33 1999/05/13 21:48:38 kardel
5253 * double the no response timeout interval
5255 * Revision 4.32 1999/05/13 20:09:13 kardel
5256 * complain only about missing polls after a full poll interval
5258 * Revision 4.31 1999/05/13 19:59:32 kardel
5259 * add clock type 16 for RTS set DTR clr in RAWDCF
5261 * Revision 4.30 1999/02/28 20:36:43 kardel
5264 * Revision 4.29 1999/02/28 19:58:23 kardel
5265 * updated copyright information
5267 * Revision 4.28 1999/02/28 19:01:50 kardel
5268 * improved debug out on sent Meinberg messages
5270 * Revision 4.27 1999/02/28 18:05:55 kardel
5271 * no linux/ppsclock.h stuff
5273 * Revision 4.26 1999/02/28 15:27:27 kardel
5274 * wharton clock integration
5276 * Revision 4.25 1999/02/28 14:04:46 kardel
5277 * added missing double quotes to UTC information string
5279 * Revision 4.24 1999/02/28 12:06:50 kardel
5280 * (parse_control): using gmprettydate instead of prettydate()
5281 * (mk_utcinfo): new function for formatting GPS derived UTC information
5282 * (gps16x_message): changed to use mk_utcinfo()
5283 * (trimbletsip_message): changed to use mk_utcinfo()
5284 * ignoring position information in unsynchronized mode
5285 * (parse_start): augument linux support for optional ASYNC_LOW_LATENCY
5287 * Revision 4.23 1999/02/23 19:47:53 kardel
5289 * (stream_receive): fixed formats
5291 * Revision 4.22 1999/02/22 06:21:02 kardel
5292 * use new autoconfig symbols
5294 * Revision 4.21 1999/02/21 12:18:13 kardel
5295 * 4.91f reconcilation
5297 * Revision 4.20 1999/02/21 10:53:36 kardel
5298 * initial Linux PPSkit version
5300 * Revision 4.19 1999/02/07 09:10:45 kardel
5301 * clarify STREAMS mitigation rules in comment
5303 * Revision 4.18 1998/12/20 23:45:34 kardel
5304 * fix types and warnings
5306 * Revision 4.17 1998/11/15 21:24:51 kardel
5307 * cannot access mbg_ routines when CLOCK_MEINBERG
5310 * Revision 4.16 1998/11/15 20:28:17 kardel
5311 * Release 4.0.73e13 reconcilation
5313 * Revision 4.15 1998/08/22 21:56:08 kardel
5314 * fixed IO handling for non-STREAM IO
5316 * Revision 4.14 1998/08/16 19:00:48 kardel
5317 * (gps16x_message): reduced UTC parameter information (dropped A0,A1)
5318 * made uval a local variable (killed one of the last globals)
5319 * (sendetx): added logging of messages when in debug mode
5320 * (trimble_check): added periodic checks to facilitate re-initialization
5321 * (trimbletsip_init): made use of EOL character if in non-kernel operation
5322 * (trimbletsip_message): extended message interpretation
5323 * (getdbl): fixed data conversion
5325 * Revision 4.13 1998/08/09 22:29:13 kardel
5326 * Trimble TSIP support
5328 * Revision 4.12 1998/07/11 10:05:34 kardel
5329 * Release 4.0.73d reconcilation
5331 * Revision 4.11 1998/06/14 21:09:42 kardel
5334 * Revision 4.10 1998/06/13 12:36:45 kardel
5335 * signed/unsigned, name clashes
5337 * Revision 4.9 1998/06/12 15:30:00 kardel
5340 * Revision 4.8 1998/06/12 11:19:42 kardel
5341 * added direct input processing routine for refclocks in
5342 * order to avaiod that single character io gobbles up all
5343 * receive buffers and drops input data. (Problem started
5344 * with fast machines so a character a buffer was possible
5345 * one of the few cases where faster machines break existing
5346 * allocation algorithms)
5348 * Revision 4.7 1998/06/06 18:35:20 kardel
5349 * (parse_start): added BURST mode initialisation
5351 * Revision 4.6 1998/05/27 06:12:46 kardel
5352 * RAWDCF_BASEDELAY default added
5353 * old comment removed
5356 * Revision 4.5 1998/05/25 22:05:09 kardel
5357 * RAWDCF_SETDTR option removed
5358 * clock type 14 attempts to set DTR for
5359 * power supply of RAWDCF receivers
5361 * Revision 4.4 1998/05/24 16:20:47 kardel
5362 * updated comments referencing Meinberg clocks
5363 * added RAWDCF clock with DTR set option as type 14
5365 * Revision 4.3 1998/05/24 10:48:33 kardel
5366 * calibrated CONRAD RAWDCF default fudge factor
5368 * Revision 4.2 1998/05/24 09:59:35 kardel
5369 * corrected version information (ntpq support)
5371 * Revision 4.1 1998/05/24 09:52:31 kardel
5372 * use fixed format only (new IO model)
5373 * output debug to stdout instead of msyslog()
5374 * don't include >"< in ASCII output in order not to confuse
5377 * Revision 4.0 1998/04/10 19:52:11 kardel
5378 * Start 4.0 release version numbering
5380 * Revision 1.2 1998/04/10 19:28:04 kardel
5381 * initial NTP VERSION 4 integration of PARSE with GPS166 binary support
5382 * derived from 3.105.1.2 from V3 tree
5384 * Revision information 3.1 - 3.105 from log deleted 1998/04/10 kardel