refclock_parse.c revision 54359
1/* 2 * /src/NTP/ntp-4/ntpd/refclock_parse.c,v 4.29 1999/02/28 19:58:23 kardel RELEASE_19990228_A 3 * 4 * refclock_parse.c,v 4.29 1999/02/28 19:58:23 kardel RELEASE_19990228_A 5 * 6 * generic reference clock driver for receivers 7 * 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 11 * 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. 15 * 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 18 * 19 * This software may not be sold for profit without a written consent 20 * from the author. 21 * 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. 25 * 26 */ 27 28#ifdef HAVE_CONFIG_H 29# include <config.h> 30#endif 31 32#if defined(REFCLOCK) && defined(CLOCK_PARSE) 33 34/* 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) 40 * - IGEL CLOCK (DCF) 41 * - ELV DCF7000 (DCF) 42 * - Schmid clock (DCF) 43 * - Conrad DCF77 receiver module (DCF) 44 * - FAU DCF77 NTP receiver (TimeBrick) (DCF) 45 * 46 * - Meinberg GPS166/GPS167 (GPS) 47 * - Trimble (TSIP and TAIP protocol) (GPS) 48 * 49 * - RCC8000 MSF Receiver (MSF) 50 * - WHARTON 400A Series clock (DCF) 51 * - VARITEXT clock (MSF) 52 */ 53 54/* 55 * Meinberg receivers are usually connected via a 56 * 9600 baud serial line 57 * 58 * The Meinberg GPS receivers also have a special NTP time stamp 59 * format. The firmware release is Uni-Erlangen. 60 * 61 * Meinberg generic receiver setup: 62 * output time code every second 63 * Baud rate 9600 7E2S 64 * 65 * Meinberg GPS16x setup: 66 * output time code every second 67 * Baudrate 19200 8N1 68 * 69 * This software supports the standard data formats used 70 * in Meinberg receivers. 71 * 72 * Special software versions are only sensible for the 73 * GPS 16x family of receivers. 74 * 75 * Meinberg can be reached via: http://www.meinberg.de/ 76 */ 77 78#include "ntpd.h" 79#include "ntp_refclock.h" 80#include "ntp_unixtime.h" /* includes <sys/time.h> */ 81#include "ntp_control.h" 82 83#include <stdio.h> 84#include <ctype.h> 85#ifndef TM_IN_SYS_TIME 86# include <time.h> 87#endif 88 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}" 91#endif 92 93#ifdef STREAM 94# include <sys/stream.h> 95# include <sys/stropts.h> 96#endif 97 98#ifdef HAVE_TERMIOS 99# define TTY_GETATTR(_FD_, _ARG_) tcgetattr((_FD_), (_ARG_)) 100# define TTY_SETATTR(_FD_, _ARG_) tcsetattr((_FD_), TCSANOW, (_ARG_)) 101# undef HAVE_SYSV_TTYS 102#endif 103 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_)) 107#endif 108 109#ifdef HAVE_BSD_TTYS 110/* #error CURRENTLY NO BSD TTY SUPPORT */ 111# include "Bletch: BSD TTY not currently supported" 112#endif 113 114#ifdef HAVE_SYS_IOCTL_H 115# include <sys/ioctl.h> 116#endif 117 118#ifdef PPS 119#ifdef HAVE_SYS_PPSCLOCK_H 120#include <sys/ppsclock.h> 121#endif 122#ifdef HAVE_TIO_SERIAL_STUFF 123#include <linux/serial.h> 124#endif 125#endif 126 127#include "ntp_io.h" 128#include "ntp_stdlib.h" 129 130#include "parse.h" 131#include "mbg_gps166.h" 132#include "trimble.h" 133#include "binio.h" 134#include "ascii.h" 135#include "ieee754io.h" 136 137static char rcsid[]="refclock_parse.c,v 4.29 1999/02/28 19:58:23 kardel RELEASE_19990228_A"; 138 139/**=========================================================================== 140 ** external interface to ntp mechanism 141 **/ 142 143static void parse_init P((void)); 144static int parse_start P((int, struct peer *)); 145static void parse_shutdown P((int, struct peer *)); 146static void parse_poll P((int, struct peer *)); 147static void parse_control P((int, struct refclockstat *, struct refclockstat *, struct peer *)); 148 149#define parse_buginfo noentry 150 151struct refclock refclock_parse = { 152 parse_start, 153 parse_shutdown, 154 parse_poll, 155 parse_control, 156 parse_init, 157 parse_buginfo, 158 NOFLAGS 159}; 160 161/* 162 * Definitions 163 */ 164#define MAXUNITS 4 /* maximum number of "PARSE" units permitted */ 165#define PARSEDEVICE "/dev/refclock-%d" /* device to open %d is unit number */ 166 167#undef ABS 168#define ABS(_X_) (((_X_) < 0) ? -(_X_) : (_X_)) 169 170/**=========================================================================== 171 ** function vector for dynamically binding io handling mechanism 172 **/ 173 174struct parseunit; /* to keep inquiring minds happy */ 175 176typedef struct bind 177{ 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 */ 189} bind_t; 190 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_) 198 199/* 200 * io modes 201 */ 202#define PARSE_F_PPSPPS 0x0001 /* use loopfilter PPS code (CIOGETEV) */ 203#define PARSE_F_PPSONSECOND 0x0002 /* PPS pulses are on second */ 204 205 206/**=========================================================================== 207 ** error message regression handling 208 ** 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. 221 **/ 222 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) 231 232#define ERR(_X_) if (list_err(parse, (_X_))) 233 234struct errorregression 235{ 236 u_long err_count; /* number of repititions per class */ 237 u_long err_delay; /* minimum delay between messages */ 238}; 239 240static struct errorregression 241err_baddata[] = /* error messages for bad input data */ 242{ 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 */ 247}; 248 249static struct errorregression 250err_nodata[] = /* error messages for missing input data */ 251{ 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 */ 256}; 257 258static struct errorregression 259err_badstatus[] = /* unsynchronized state messages */ 260{ 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 */ 265}; 266 267static struct errorregression 268err_badio[] = /* io failures (bad reads, selects, ...) */ 269{ 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 */ 274}; 275 276static struct errorregression 277err_badevent[] = /* non nominal events */ 278{ 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 */ 283}; 284 285static struct errorregression 286err_internal[] = /* really bad things - basically coding/OS errors */ 287{ 288 { 0, 0 }, /* output all messages immediately */ 289}; 290 291static struct errorregression * 292err_tbl[] = 293{ 294 err_baddata, 295 err_nodata, 296 err_badio, 297 err_badstatus, 298 err_badevent, 299 err_internal 300}; 301 302struct errorinfo 303{ 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 */ 309}; 310 311/**=========================================================================== 312 ** refclock instance data 313 **/ 314 315struct parseunit 316{ 317 /* 318 * NTP management 319 */ 320 struct peer *peer; /* backlink to peer structure - refclock inactive if 0 */ 321 struct refclockproc *generic; /* backlink to refclockproc structure */ 322 323 /* 324 * PARSE io 325 */ 326 bind_t *binding; /* io handling binding */ 327 328 /* 329 * parse state 330 */ 331 parse_t parseio; /* io handling structure (user level parsing) */ 332 333 /* 334 * type specific parameters 335 */ 336 struct parse_clockinfo *parse_type; /* link to clock description */ 337 338 /* 339 * clock state handling/reporting 340 */ 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_char pollneeddata; /* 1 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 */ 355}; 356 357 358/**=========================================================================== 359 ** Clockinfo section all parameter for specific clock types 360 ** includes NTP parameters, TTY parameters and IO handling parameters 361 **/ 362 363static void poll_dpoll P((struct parseunit *)); 364static void poll_poll P((struct peer *)); 365static int poll_init P((struct parseunit *)); 366 367typedef struct poll_info 368{ 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 */ 372} poll_info_t; 373 374#define NO_CL_FLAGS 0 375#define NO_POLL 0 376#define NO_INIT 0 377#define NO_END 0 378#define NO_EVENT 0 379#define NO_DATA 0 380#define NO_MESSAGE 0 381#define NO_PPSDELAY 0 382 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 */ 387 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 405 406#define DCF_TYPE CTL_SST_TS_LF 407#define GPS_TYPE CTL_SST_TS_UHF 408 409/* 410 * receiver specific constants 411 */ 412#define MBG_SPEED (B9600) 413#define MBG_CFLAG (CS7|PARENB|CREAD|CLOCAL|HUPCL) 414#define MBG_IFLAG (IGNBRK|IGNPAR|ISTRIP) 415#define MBG_OFLAG 0 416#define MBG_LFLAG 0 417#define MBG_FLAGS PARSE_F_PPSONSECOND 418 419/* 420 * Meinberg DCF77 receivers 421 */ 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" 434 435/* 436 * Meinberg DCF PZF535/TCXO (FM/PZF) receiver 437 */ 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" 453 454/* 455 * Meinberg DCF PZF535/OCXO receiver 456 */ 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" 472 473/* 474 * Meinberg GPS16X receiver 475 */ 476static void gps16x_message P((struct parseunit *, parsetime_t *)); 477static int gps16x_poll_init P((struct parseunit *)); 478 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 494 495static poll_info_t gps16x_pollinfo = { GPS16X_POLLRATE, GPS16X_POLLCMD, GPS16X_CMDSIZE }; 496 497#define GPS16X_INIT gps16x_poll_init 498#define GPS16X_POLL 0 499#define GPS16X_END 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 506 507/* 508 * ELV DCF7000 Wallclock-Receiver/Switching Clock (Kit) 509 * 510 * This is really not the hottest clock - but before you have nothing ... 511 */ 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" 524 525/* 526 * Schmid DCF Receiver Kit 527 * 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 532 */ 533#define WS_POLLRATE 1 /* every second - watch interdependency with poll routine */ 534#define WS_POLLCMD "\163" 535#define WS_CMDSIZE 1 536 537static poll_info_t wsdcf_pollinfo = { WS_POLLRATE, WS_POLLCMD, WS_CMDSIZE }; 538 539#define WSDCF_INIT poll_init 540#define WSDCF_POLL poll_dpoll 541#define WSDCF_END 0 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 554#define WSDCF_KEEP 3 555 556/* 557 * RAW DCF77 - input of DCF marks via RS232 - many variants 558 */ 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) 568#else 569# define RAWDCF_CFLAG (CS8|CREAD|CLOCAL|PARENB) 570#endif 571#ifdef RAWDCF_NO_IGNPAR /* Was: defined(SYS_LINUX) && defined(CLOCK_RAWDCF) */ 572# define RAWDCF_IFLAG 0 573#else 574# define RAWDCF_IFLAG (IGNPAR) 575#endif 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 581 582/* 583 * RAW DCF variants 584 */ 585/* 586 * Conrad receiver 587 * 588 * simplest (cheapest) DCF clock - e. g. DCF77 receiver by Conrad 589 * (~40DM - roughly $30 ) followed by a level converter for RS232 590 */ 591#define CONRAD_BASEDELAY 0.292 /* Conrad receiver @ 50 Baud on a Sun */ 592#define CONRAD_DESCRIPTION "RAW DCF77 CODE (Conrad DCF77 receiver module)" 593 594/* 595 * TimeBrick receiver 596 */ 597#define TIMEBRICK_BASEDELAY 0.210 /* TimeBrick @ 50 Baud on a Sun */ 598#define TIMEBRICK_DESCRIPTION "RAW DCF77 CODE (TimeBrick)" 599 600/* 601 * IGEL:clock receiver 602 */ 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) 607 608/* 609 * RAWDCF receivers that need to be powered from DTR 610 * (like Expert mouse clock) 611 */ 612static int rawdcfdtr_init P((struct parseunit *)); 613#define RAWDCFDTR_DESCRIPTION "RAW DCF77 CODE (DTR OPTION)" 614#define RAWDCFDTR_INIT rawdcfdtr_init 615 616/* 617 * RAWDCF receivers that need to be powered from RTS 618 */ 619static int rawdcfrts_init P((struct parseunit *)); 620#define RAWDCFRTS_DESCRIPTION "RAW DCF77 CODE (RTS OPTION)" 621#define RAWDCFRTS_INIT rawdcfrts_init 622 623/* 624 * Trimble GPS receivers (TAIP and TSIP protocols) 625 */ 626#ifndef TRIM_POLLRATE 627#define TRIM_POLLRATE 0 /* only true direct polling */ 628#endif 629 630#define TRIM_TAIPPOLLCMD ">SRM;FR_FLAG=F;EC_FLAG=F<>QTM<" 631#define TRIM_TAIPCMDSIZE (sizeof(TRIM_TAIPPOLLCMD)-1) 632 633static poll_info_t trimbletaip_pollinfo = { TRIM_POLLRATE, TRIM_TAIPPOLLCMD, TRIM_TAIPCMDSIZE }; 634static int trimbletaip_init P((struct parseunit *)); 635static void trimbletaip_event P((struct parseunit *, int)); 636 637/* query time & UTC correction data */ 638static char tsipquery[] = { DLE, 0x21, DLE, ETX, DLE, 0x2F, DLE, ETX }; 639 640static poll_info_t trimbletsip_pollinfo = { TRIM_POLLRATE, tsipquery, sizeof(tsipquery) }; 641static int trimbletsip_init P((struct parseunit *)); 642static void trimbletsip_end P((struct parseunit *)); 643static void trimbletsip_message P((struct parseunit *, parsetime_t *)); 644static void trimbletsip_event P((struct parseunit *, int)); 645 646#define TRIMBLETSIP_IDLE_TIME (300) /* 5 minutes silence at most */ 647 648#define TRIMBLETAIP_SPEED (B4800) 649#define TRIMBLETAIP_CFLAG (CS8|CREAD|CLOCAL) 650#define TRIMBLETAIP_IFLAG (BRKINT|IGNPAR|ISTRIP|ICRNL|IXON) 651#define TRIMBLETAIP_OFLAG (OPOST|ONLCR) 652#define TRIMBLETAIP_LFLAG (0) 653 654#define TRIMBLETSIP_SPEED (B9600) 655#define TRIMBLETSIP_CFLAG (CS8|CLOCAL|CREAD|PARENB|PARODD) 656#define TRIMBLETSIP_IFLAG (IGNBRK) 657#define TRIMBLETSIP_OFLAG (0) 658#define TRIMBLETSIP_LFLAG (ICANON) 659 660#define TRIMBLETSIP_SAMPLES 5 661#define TRIMBLETSIP_KEEP 3 662#define TRIMBLETAIP_SAMPLES 5 663#define TRIMBLETAIP_KEEP 3 664 665#define TRIMBLETAIP_FLAGS (PARSE_F_PPSONSECOND) 666#define TRIMBLETSIP_FLAGS (TRIMBLETAIP_FLAGS) 667 668#define TRIMBLETAIP_POLL poll_dpoll 669#define TRIMBLETSIP_POLL poll_dpoll 670 671#define TRIMBLETAIP_INIT trimbletaip_init 672#define TRIMBLETSIP_INIT trimbletsip_init 673 674#define TRIMBLETAIP_EVENT trimbletaip_event 675 676#define TRIMBLETSIP_EVENT trimbletsip_event 677#define TRIMBLETSIP_MESSAGE trimbletsip_message 678 679#define TRIMBLETAIP_END 0 680#define TRIMBLETSIP_END trimbletsip_end 681 682#define TRIMBLETAIP_DATA ((void *)(&trimbletaip_pollinfo)) 683#define TRIMBLETSIP_DATA ((void *)(&trimbletsip_pollinfo)) 684 685#define TRIMBLETAIP_ID GPS_ID 686#define TRIMBLETSIP_ID GPS_ID 687 688#define TRIMBLETAIP_FORMAT "Trimble TAIP" 689#define TRIMBLETSIP_FORMAT "Trimble TSIP" 690 691#define TRIMBLETAIP_ROOTDELAY 0x0 692#define TRIMBLETSIP_ROOTDELAY 0x0 693 694#define TRIMBLETAIP_BASEDELAY 0.0 695#define TRIMBLETSIP_BASEDELAY 0.020 /* GPS time message latency */ 696 697#define TRIMBLETAIP_DESCRIPTION "Trimble GPS (TAIP) receiver" 698#define TRIMBLETSIP_DESCRIPTION "Trimble GPS (TSIP) receiver" 699 700#define TRIMBLETAIP_MAXUNSYNC 0 701#define TRIMBLETSIP_MAXUNSYNC 0 702 703#define TRIMBLETAIP_EOL '<' 704 705/* 706 * RadioCode Clocks RCC 800 receiver 707 */ 708#define RCC_POLLRATE 0 /* only true direct polling */ 709#define RCC_POLLCMD "\r" 710#define RCC_CMDSIZE 1 711 712static poll_info_t rcc8000_pollinfo = { RCC_POLLRATE, RCC_POLLCMD, RCC_CMDSIZE }; 713#define RCC8000_FLAGS 0 714#define RCC8000_POLL poll_dpoll 715#define RCC8000_INIT poll_init 716#define RCC8000_END 0 717#define RCC8000_DATA ((void *)(&rcc8000_pollinfo)) 718#define RCC8000_ROOTDELAY 0.0 719#define RCC8000_BASEDELAY 0.0 720#define RCC8000_ID "MSF" 721#define RCC8000_DESCRIPTION "RCC 8000 MSF Receiver" 722#define RCC8000_FORMAT "Radiocode RCC8000" 723#define RCC8000_MAXUNSYNC (60*60) /* should be ok for an hour */ 724#define RCC8000_SPEED (B2400) 725#define RCC8000_CFLAG (CS8|CREAD|CLOCAL) 726#define RCC8000_IFLAG (IGNBRK|IGNPAR) 727#define RCC8000_OFLAG 0 728#define RCC8000_LFLAG 0 729#define RCC8000_SAMPLES 5 730#define RCC8000_KEEP 3 731 732/* 733 * Hopf Radio clock 6021 Format 734 * 735 */ 736#define HOPF6021_ROOTDELAY 0.0 737#define HOPF6021_BASEDELAY 0.0 738#define HOPF6021_DESCRIPTION "HOPF 6021" 739#define HOPF6021_FORMAT "hopf Funkuhr 6021" 740#define HOPF6021_MAXUNSYNC (60*60) /* should be ok for an hour */ 741#define HOPF6021_SPEED (B9600) 742#define HOPF6021_CFLAG (CS8|CREAD|CLOCAL) 743#define HOPF6021_IFLAG (IGNBRK|ISTRIP) 744#define HOPF6021_OFLAG 0 745#define HOPF6021_LFLAG 0 746#define HOPF6021_FLAGS 0 747#define HOPF6021_SAMPLES 5 748#define HOPF6021_KEEP 3 749 750/* 751 * Diem's Computime Radio Clock Receiver 752 */ 753#define COMPUTIME_FLAGS 0 754#define COMPUTIME_ROOTDELAY 0.0 755#define COMPUTIME_BASEDELAY 0.0 756#define COMPUTIME_ID DCF_ID 757#define COMPUTIME_DESCRIPTION "Diem's Computime receiver" 758#define COMPUTIME_FORMAT "Diem's Computime Radio Clock" 759#define COMPUTIME_TYPE DCF_TYPE 760#define COMPUTIME_MAXUNSYNC (60*60) /* only trust clock for 1 hour */ 761#define COMPUTIME_SPEED (B9600) 762#define COMPUTIME_CFLAG (CSTOPB|CS7|CREAD|CLOCAL) 763#define COMPUTIME_IFLAG (IGNBRK|IGNPAR|ISTRIP) 764#define COMPUTIME_OFLAG 0 765#define COMPUTIME_LFLAG 0 766#define COMPUTIME_SAMPLES 5 767#define COMPUTIME_KEEP 3 768 769/* 770 * Varitext Radio Clock Receiver 771 */ 772#define VARITEXT_FLAGS 0 773#define VARITEXT_ROOTDELAY 0.0 774#define VARITEXT_BASEDELAY 0.0 775#define VARITEXT_ID "MSF" 776#define VARITEXT_DESCRIPTION "Varitext receiver" 777#define VARITEXT_FORMAT "Varitext Radio Clock" 778#define VARITEXT_TYPE DCF_TYPE 779#define VARITEXT_MAXUNSYNC (60*60) /* only trust clock for 1 hour */ 780#define VARITEXT_SPEED (B9600) 781#define VARITEXT_CFLAG (CS7|CREAD|CLOCAL|PARENB|PARODD) 782#define VARITEXT_IFLAG (IGNPAR|IGNBRK|INPCK) /*|ISTRIP)*/ 783#define VARITEXT_OFLAG 0 784#define VARITEXT_LFLAG 0 785#define VARITEXT_SAMPLES 32 786#define VARITEXT_KEEP 20 787 788static struct parse_clockinfo 789{ 790 u_long cl_flags; /* operation flags (io modes) */ 791 void (*cl_poll) P((struct parseunit *)); /* active poll routine */ 792 int (*cl_init) P((struct parseunit *)); /* active poll init routine */ 793 void (*cl_event) P((struct parseunit *, int)); /* special event handling (e.g. reset clock) */ 794 void (*cl_end) P((struct parseunit *)); /* active poll end routine */ 795 void (*cl_message) P((struct parseunit *, parsetime_t *)); /* process a lower layer message */ 796 void *cl_data; /* local data area for "poll" mechanism */ 797 double cl_rootdelay; /* rootdelay */ 798 double cl_basedelay; /* current offset by which the RS232 799 time code is delayed from the actual time */ 800 const char *cl_id; /* ID code */ 801 const char *cl_description; /* device name */ 802 const char *cl_format; /* fixed format */ 803 u_char cl_type; /* clock type (ntp control) */ 804 u_long cl_maxunsync; /* time to trust oscillator after loosing synch */ 805 u_long cl_speed; /* terminal input & output baudrate */ 806 u_long cl_cflag; /* terminal control flags */ 807 u_long cl_iflag; /* terminal input flags */ 808 u_long cl_oflag; /* terminal output flags */ 809 u_long cl_lflag; /* terminal local flags */ 810 u_long cl_samples; /* samples for median filter */ 811 u_long cl_keep; /* samples for median filter to keep */ 812} parse_clockinfo[] = 813{ 814 { /* mode 0 */ 815 MBG_FLAGS, 816 NO_POLL, 817 NO_INIT, 818 NO_EVENT, 819 NO_END, 820 NO_MESSAGE, 821 NO_DATA, 822 DCFPZF535_ROOTDELAY, 823 DCFPZF535_BASEDELAY, 824 DCF_P_ID, 825 DCFPZF535_DESCRIPTION, 826 DCFPZF535_FORMAT, 827 DCF_TYPE, 828 DCFPZF535_MAXUNSYNC, 829 DCFPZF535_SPEED, 830 DCFPZF535_CFLAG, 831 DCFPZF535_IFLAG, 832 DCFPZF535_OFLAG, 833 DCFPZF535_LFLAG, 834 DCFPZF535_SAMPLES, 835 DCFPZF535_KEEP 836 }, 837 { /* mode 1 */ 838 MBG_FLAGS, 839 NO_POLL, 840 NO_INIT, 841 NO_EVENT, 842 NO_END, 843 NO_MESSAGE, 844 NO_DATA, 845 DCFPZF535OCXO_ROOTDELAY, 846 DCFPZF535OCXO_BASEDELAY, 847 DCF_P_ID, 848 DCFPZF535OCXO_DESCRIPTION, 849 DCFPZF535OCXO_FORMAT, 850 DCF_TYPE, 851 DCFPZF535OCXO_MAXUNSYNC, 852 DCFPZF535OCXO_SPEED, 853 DCFPZF535OCXO_CFLAG, 854 DCFPZF535OCXO_IFLAG, 855 DCFPZF535OCXO_OFLAG, 856 DCFPZF535OCXO_LFLAG, 857 DCFPZF535OCXO_SAMPLES, 858 DCFPZF535OCXO_KEEP 859 }, 860 { /* mode 2 */ 861 MBG_FLAGS, 862 NO_POLL, 863 NO_INIT, 864 NO_EVENT, 865 NO_END, 866 NO_MESSAGE, 867 NO_DATA, 868 DCFUA31_ROOTDELAY, 869 DCFUA31_BASEDELAY, 870 DCF_A_ID, 871 DCFUA31_DESCRIPTION, 872 DCFUA31_FORMAT, 873 DCF_TYPE, 874 DCFUA31_MAXUNSYNC, 875 DCFUA31_SPEED, 876 DCFUA31_CFLAG, 877 DCFUA31_IFLAG, 878 DCFUA31_OFLAG, 879 DCFUA31_LFLAG, 880 DCFUA31_SAMPLES, 881 DCFUA31_KEEP 882 }, 883 { /* mode 3 */ 884 MBG_FLAGS, 885 NO_POLL, 886 NO_INIT, 887 NO_EVENT, 888 NO_END, 889 NO_MESSAGE, 890 NO_DATA, 891 DCF7000_ROOTDELAY, 892 DCF7000_BASEDELAY, 893 DCF_A_ID, 894 DCF7000_DESCRIPTION, 895 DCF7000_FORMAT, 896 DCF_TYPE, 897 DCF7000_MAXUNSYNC, 898 DCF7000_SPEED, 899 DCF7000_CFLAG, 900 DCF7000_IFLAG, 901 DCF7000_OFLAG, 902 DCF7000_LFLAG, 903 DCF7000_SAMPLES, 904 DCF7000_KEEP 905 }, 906 { /* mode 4 */ 907 NO_CL_FLAGS, 908 WSDCF_POLL, 909 WSDCF_INIT, 910 NO_EVENT, 911 WSDCF_END, 912 NO_MESSAGE, 913 WSDCF_DATA, 914 WSDCF_ROOTDELAY, 915 WSDCF_BASEDELAY, 916 DCF_A_ID, 917 WSDCF_DESCRIPTION, 918 WSDCF_FORMAT, 919 DCF_TYPE, 920 WSDCF_MAXUNSYNC, 921 WSDCF_SPEED, 922 WSDCF_CFLAG, 923 WSDCF_IFLAG, 924 WSDCF_OFLAG, 925 WSDCF_LFLAG, 926 WSDCF_SAMPLES, 927 WSDCF_KEEP 928 }, 929 { /* mode 5 */ 930 RAWDCF_FLAGS, 931 NO_POLL, 932 RAWDCF_INIT, 933 NO_EVENT, 934 NO_END, 935 NO_MESSAGE, 936 NO_DATA, 937 RAWDCF_ROOTDELAY, 938 CONRAD_BASEDELAY, 939 DCF_A_ID, 940 CONRAD_DESCRIPTION, 941 RAWDCF_FORMAT, 942 DCF_TYPE, 943 RAWDCF_MAXUNSYNC, 944 RAWDCF_SPEED, 945 RAWDCF_CFLAG, 946 RAWDCF_IFLAG, 947 RAWDCF_OFLAG, 948 RAWDCF_LFLAG, 949 RAWDCF_SAMPLES, 950 RAWDCF_KEEP 951 }, 952 { /* mode 6 */ 953 RAWDCF_FLAGS, 954 NO_POLL, 955 RAWDCF_INIT, 956 NO_EVENT, 957 NO_END, 958 NO_MESSAGE, 959 NO_DATA, 960 RAWDCF_ROOTDELAY, 961 TIMEBRICK_BASEDELAY, 962 DCF_A_ID, 963 TIMEBRICK_DESCRIPTION, 964 RAWDCF_FORMAT, 965 DCF_TYPE, 966 RAWDCF_MAXUNSYNC, 967 RAWDCF_SPEED, 968 RAWDCF_CFLAG, 969 RAWDCF_IFLAG, 970 RAWDCF_OFLAG, 971 RAWDCF_LFLAG, 972 RAWDCF_SAMPLES, 973 RAWDCF_KEEP 974 }, 975 { /* mode 7 */ 976 MBG_FLAGS, 977 GPS16X_POLL, 978 GPS16X_INIT, 979 NO_EVENT, 980 GPS16X_END, 981 GPS16X_MESSAGE, 982 GPS16X_DATA, 983 GPS16X_ROOTDELAY, 984 GPS16X_BASEDELAY, 985 GPS16X_ID, 986 GPS16X_DESCRIPTION, 987 GPS16X_FORMAT, 988 GPS_TYPE, 989 GPS16X_MAXUNSYNC, 990 GPS16X_SPEED, 991 GPS16X_CFLAG, 992 GPS16X_IFLAG, 993 GPS16X_OFLAG, 994 GPS16X_LFLAG, 995 GPS16X_SAMPLES, 996 GPS16X_KEEP 997 }, 998 { /* mode 8 */ 999 RAWDCF_FLAGS, 1000 NO_POLL, 1001 NO_INIT, 1002 NO_EVENT, 1003 NO_END, 1004 NO_MESSAGE, 1005 NO_DATA, 1006 RAWDCF_ROOTDELAY, 1007 IGELCLOCK_BASEDELAY, 1008 DCF_A_ID, 1009 IGELCLOCK_DESCRIPTION, 1010 RAWDCF_FORMAT, 1011 DCF_TYPE, 1012 RAWDCF_MAXUNSYNC, 1013 IGELCLOCK_SPEED, 1014 IGELCLOCK_CFLAG, 1015 RAWDCF_IFLAG, 1016 RAWDCF_OFLAG, 1017 RAWDCF_LFLAG, 1018 RAWDCF_SAMPLES, 1019 RAWDCF_KEEP 1020 }, 1021 { /* mode 9 */ 1022 TRIMBLETAIP_FLAGS, 1023#if TRIM_POLLRATE /* DHD940515: Allow user config */ 1024 NO_POLL, 1025#else 1026 TRIMBLETAIP_POLL, 1027#endif 1028 TRIMBLETAIP_INIT, 1029 TRIMBLETAIP_EVENT, 1030 TRIMBLETAIP_END, 1031 NO_MESSAGE, 1032 TRIMBLETAIP_DATA, 1033 TRIMBLETAIP_ROOTDELAY, 1034 TRIMBLETAIP_BASEDELAY, 1035 TRIMBLETAIP_ID, 1036 TRIMBLETAIP_DESCRIPTION, 1037 TRIMBLETAIP_FORMAT, 1038 GPS_TYPE, 1039 TRIMBLETAIP_MAXUNSYNC, 1040 TRIMBLETAIP_SPEED, 1041 TRIMBLETAIP_CFLAG, 1042 TRIMBLETAIP_IFLAG, 1043 TRIMBLETAIP_OFLAG, 1044 TRIMBLETAIP_LFLAG, 1045 TRIMBLETAIP_SAMPLES, 1046 TRIMBLETAIP_KEEP 1047 }, 1048 { /* mode 10 */ 1049 TRIMBLETSIP_FLAGS, 1050#if TRIM_POLLRATE /* DHD940515: Allow user config */ 1051 NO_POLL, 1052#else 1053 TRIMBLETSIP_POLL, 1054#endif 1055 TRIMBLETSIP_INIT, 1056 TRIMBLETSIP_EVENT, 1057 TRIMBLETSIP_END, 1058 TRIMBLETSIP_MESSAGE, 1059 TRIMBLETSIP_DATA, 1060 TRIMBLETSIP_ROOTDELAY, 1061 TRIMBLETSIP_BASEDELAY, 1062 TRIMBLETSIP_ID, 1063 TRIMBLETSIP_DESCRIPTION, 1064 TRIMBLETSIP_FORMAT, 1065 GPS_TYPE, 1066 TRIMBLETSIP_MAXUNSYNC, 1067 TRIMBLETSIP_SPEED, 1068 TRIMBLETSIP_CFLAG, 1069 TRIMBLETSIP_IFLAG, 1070 TRIMBLETSIP_OFLAG, 1071 TRIMBLETSIP_LFLAG, 1072 TRIMBLETSIP_SAMPLES, 1073 TRIMBLETSIP_KEEP 1074 }, 1075 { /* mode 11 */ 1076 NO_CL_FLAGS, 1077 RCC8000_POLL, 1078 RCC8000_INIT, 1079 NO_EVENT, 1080 RCC8000_END, 1081 NO_MESSAGE, 1082 RCC8000_DATA, 1083 RCC8000_ROOTDELAY, 1084 RCC8000_BASEDELAY, 1085 RCC8000_ID, 1086 RCC8000_DESCRIPTION, 1087 RCC8000_FORMAT, 1088 DCF_TYPE, 1089 RCC8000_MAXUNSYNC, 1090 RCC8000_SPEED, 1091 RCC8000_CFLAG, 1092 RCC8000_IFLAG, 1093 RCC8000_OFLAG, 1094 RCC8000_LFLAG, 1095 RCC8000_SAMPLES, 1096 RCC8000_KEEP 1097 }, 1098 { /* mode 12 */ 1099 HOPF6021_FLAGS, 1100 NO_POLL, 1101 NO_INIT, 1102 NO_EVENT, 1103 NO_END, 1104 NO_MESSAGE, 1105 NO_DATA, 1106 HOPF6021_ROOTDELAY, 1107 HOPF6021_BASEDELAY, 1108 DCF_ID, 1109 HOPF6021_DESCRIPTION, 1110 HOPF6021_FORMAT, 1111 DCF_TYPE, 1112 HOPF6021_MAXUNSYNC, 1113 HOPF6021_SPEED, 1114 HOPF6021_CFLAG, 1115 HOPF6021_IFLAG, 1116 HOPF6021_OFLAG, 1117 HOPF6021_LFLAG, 1118 HOPF6021_SAMPLES, 1119 HOPF6021_KEEP 1120 }, 1121 { /* mode 13 */ 1122 COMPUTIME_FLAGS, 1123 NO_POLL, 1124 NO_INIT, 1125 NO_EVENT, 1126 NO_END, 1127 NO_MESSAGE, 1128 NO_DATA, 1129 COMPUTIME_ROOTDELAY, 1130 COMPUTIME_BASEDELAY, 1131 COMPUTIME_ID, 1132 COMPUTIME_DESCRIPTION, 1133 COMPUTIME_FORMAT, 1134 COMPUTIME_TYPE, 1135 COMPUTIME_MAXUNSYNC, 1136 COMPUTIME_SPEED, 1137 COMPUTIME_CFLAG, 1138 COMPUTIME_IFLAG, 1139 COMPUTIME_OFLAG, 1140 COMPUTIME_LFLAG, 1141 COMPUTIME_SAMPLES, 1142 COMPUTIME_KEEP 1143 }, 1144 { /* mode 14 */ 1145 RAWDCF_FLAGS, 1146 NO_POLL, 1147 RAWDCFDTR_INIT, 1148 NO_EVENT, 1149 NO_END, 1150 NO_MESSAGE, 1151 NO_DATA, 1152 RAWDCF_ROOTDELAY, 1153 RAWDCF_BASEDELAY, 1154 DCF_A_ID, 1155 RAWDCFDTR_DESCRIPTION, 1156 RAWDCF_FORMAT, 1157 DCF_TYPE, 1158 RAWDCF_MAXUNSYNC, 1159 RAWDCF_SPEED, 1160 RAWDCF_CFLAG, 1161 RAWDCF_IFLAG, 1162 RAWDCF_OFLAG, 1163 RAWDCF_LFLAG, 1164 RAWDCF_SAMPLES, 1165 RAWDCF_KEEP 1166 }, 1167 { /* mode 15 */ 1168 0, /* operation flags (io modes) */ 1169 NO_POLL, /* active poll routine */ 1170 NO_INIT, /* active poll init routine */ 1171 NO_EVENT, /* special event handling (e.g. reset clock) */ 1172 NO_END, /* active poll end routine */ 1173 NO_MESSAGE, /* process a lower layer message */ 1174 NO_DATA, /* local data area for "poll" mechanism */ 1175 0, /* rootdelay */ 1176 11.0 /* bits */ / 9600, /* current offset by which the RS232 1177 time code is delayed from the actual time */ 1178 DCF_ID, /* ID code */ 1179 "WHARTON 400A Series clock", /* device name */ 1180 "WHARTON 400A Series clock Output Format 1", /* fixed format */ 1181 /* Must match a format-name in a libparse/clk_xxx.c file */ 1182 DCF_TYPE, /* clock type (ntp control) */ 1183 (1*60*60)/*?*/, /* time to trust oscillator after loosing synch */ 1184 B9600, /* terminal input & output baudrate */ 1185 (CS8|CREAD|PARENB|CLOCAL|HUPCL), /* terminal control flags */ 1186 0, /* terminal input flags */ 1187 0, /* terminal output flags */ 1188 0, /* terminal local flags */ 1189 5/*?*/, /* samples for median filter */ 1190 3/*?*/, /* samples for median filter to keep */ 1191 }, 1192 { /* mode 16 */ 1193 VARITEXT_FLAGS, 1194 NO_POLL, 1195 NO_INIT, 1196 NO_EVENT, 1197 NO_END, 1198 NO_MESSAGE, 1199 NO_DATA, 1200 VARITEXT_ROOTDELAY, 1201 VARITEXT_BASEDELAY, 1202 VARITEXT_ID, 1203 VARITEXT_DESCRIPTION, 1204 VARITEXT_FORMAT, 1205 VARITEXT_TYPE, 1206 VARITEXT_MAXUNSYNC, 1207 VARITEXT_SPEED, 1208 VARITEXT_CFLAG, 1209 VARITEXT_IFLAG, 1210 VARITEXT_OFLAG, 1211 VARITEXT_LFLAG, 1212 VARITEXT_SAMPLES, 1213 VARITEXT_KEEP 1214 }, 1215 { /* mode 17 */ 1216 RAWDCF_FLAGS, 1217 NO_POLL, 1218 RAWDCFRTS_INIT, 1219 NO_EVENT, 1220 NO_END, 1221 NO_MESSAGE, 1222 NO_DATA, 1223 RAWDCF_ROOTDELAY, 1224 RAWDCF_BASEDELAY, 1225 DCF_A_ID, 1226 RAWDCFRTS_DESCRIPTION, 1227 RAWDCF_FORMAT, 1228 DCF_TYPE, 1229 RAWDCF_MAXUNSYNC, 1230 RAWDCF_SPEED, 1231 RAWDCF_CFLAG, 1232 RAWDCF_IFLAG, 1233 RAWDCF_OFLAG, 1234 RAWDCF_LFLAG, 1235 RAWDCF_SAMPLES, 1236 RAWDCF_KEEP 1237 }, 1238}; 1239 1240static int ncltypes = sizeof(parse_clockinfo) / sizeof(struct parse_clockinfo); 1241 1242#define CLK_REALTYPE(x) ((int)(((x)->ttl) & 0x7F)) 1243#define CLK_TYPE(x) ((CLK_REALTYPE(x) >= ncltypes) ? ~0 : CLK_REALTYPE(x)) 1244#define CLK_UNIT(x) ((int)REFCLOCKUNIT(&(x)->srcadr)) 1245#define CLK_PPS(x) (((x)->ttl) & 0x80) 1246 1247/* 1248 * Other constant stuff 1249 */ 1250#define PARSEHSREFID 0x7f7f08ff /* 127.127.8.255 refid for hi strata */ 1251 1252#define PARSESTATISTICS (60*60) /* output state statistics every hour */ 1253 1254static struct parseunit *parseunits[MAXUNITS]; 1255 1256static int notice = 0; 1257 1258#define PARSE_STATETIME(parse, i) ((parse->generic->currentstatus == i) ? parse->statetime[i] + current_time - parse->lastchange : parse->statetime[i]) 1259 1260static void parse_event P((struct parseunit *, int)); 1261static void parse_process P((struct parseunit *, parsetime_t *)); 1262static void clear_err P((struct parseunit *, u_long)); 1263static int list_err P((struct parseunit *, u_long)); 1264static char * l_mktime P((u_long)); 1265 1266/**=========================================================================== 1267 ** implementation error message regression module 1268 **/ 1269static void 1270clear_err( 1271 struct parseunit *parse, 1272 u_long lstate 1273 ) 1274{ 1275 if (lstate == ERR_ALL) 1276 { 1277 int i; 1278 1279 for (i = 0; i < ERR_CNT; i++) 1280 { 1281 parse->errors[i].err_stage = err_tbl[i]; 1282 parse->errors[i].err_cnt = 0; 1283 parse->errors[i].err_last = 0; 1284 parse->errors[i].err_started = 0; 1285 parse->errors[i].err_suppressed = 0; 1286 } 1287 } 1288 else 1289 { 1290 parse->errors[lstate].err_stage = err_tbl[lstate]; 1291 parse->errors[lstate].err_cnt = 0; 1292 parse->errors[lstate].err_last = 0; 1293 parse->errors[lstate].err_started = 0; 1294 parse->errors[lstate].err_suppressed = 0; 1295 } 1296} 1297 1298static int 1299list_err( 1300 struct parseunit *parse, 1301 u_long lstate 1302 ) 1303{ 1304 int do_it; 1305 struct errorinfo *err = &parse->errors[lstate]; 1306 1307 if (err->err_started == 0) 1308 { 1309 err->err_started = current_time; 1310 } 1311 1312 do_it = (current_time - err->err_last) >= err->err_stage->err_delay; 1313 1314 if (do_it) 1315 err->err_cnt++; 1316 1317 if (err->err_stage->err_count && 1318 (err->err_cnt >= err->err_stage->err_count)) 1319 { 1320 err->err_stage++; 1321 err->err_cnt = 0; 1322 } 1323 1324 if (!err->err_cnt && do_it) 1325 msyslog(LOG_INFO, "PARSE receiver #%d: interval for following error message class is at least %s", 1326 CLK_UNIT(parse->peer), l_mktime(err->err_stage->err_delay)); 1327 1328 if (!do_it) 1329 err->err_suppressed++; 1330 else 1331 err->err_last = current_time; 1332 1333 if (do_it && err->err_suppressed) 1334 { 1335 msyslog(LOG_INFO, "PARSE receiver #%d: %ld message%s suppressed, error condition class persists for %s", 1336 CLK_UNIT(parse->peer), err->err_suppressed, (err->err_suppressed == 1) ? " was" : "s where", 1337 l_mktime(current_time - err->err_started)); 1338 err->err_suppressed = 0; 1339 } 1340 1341 return do_it; 1342} 1343 1344/*-------------------------------------------------- 1345 * mkreadable - make a printable ascii string (without 1346 * embedded quotes so that the ntpq protocol isn't 1347 * fooled 1348 */ 1349#ifndef isprint 1350#define isprint(_X_) (((_X_) > 0x1F) && ((_X_) < 0x7F)) 1351#endif 1352 1353static char * 1354mkreadable( 1355 char *buffer, 1356 long blen, 1357 const char *src, 1358 u_long srclen, 1359 int hex 1360 ) 1361{ 1362 char *b = buffer; 1363 char *endb = (char *)0; 1364 1365 if (blen < 4) 1366 return (char *)0; /* don't bother with mini buffers */ 1367 1368 endb = buffer + blen - 4; 1369 1370 blen--; /* account for '\0' */ 1371 1372 while (blen && srclen--) 1373 { 1374 if (!hex && /* no binary only */ 1375 (*src != '\\') && /* no plain \ */ 1376 (*src != '"') && /* no " */ 1377 isprint((int)*src)) /* only printables */ 1378 { /* they are easy... */ 1379 *buffer++ = *src++; 1380 blen--; 1381 } 1382 else 1383 { 1384 if (blen < 4) 1385 { 1386 while (blen--) 1387 { 1388 *buffer++ = '.'; 1389 } 1390 *buffer = '\0'; 1391 return b; 1392 } 1393 else 1394 { 1395 if (*src == '\\') 1396 { 1397 strcpy(buffer,"\\\\"); 1398 buffer += 2; 1399 blen -= 2; 1400 src++; 1401 } 1402 else 1403 { 1404 sprintf(buffer, "\\x%02x", *src++); 1405 blen -= 4; 1406 buffer += 4; 1407 } 1408 } 1409 } 1410 if (srclen && !blen && endb) /* overflow - set last chars to ... */ 1411 strcpy(endb, "..."); 1412 } 1413 1414 *buffer = '\0'; 1415 return b; 1416} 1417 1418 1419/*-------------------------------------------------- 1420 * mkascii - make a printable ascii string 1421 * assumes (unless defined better) 7-bit ASCII 1422 */ 1423static char * 1424mkascii( 1425 char *buffer, 1426 long blen, 1427 const char *src, 1428 u_long srclen 1429 ) 1430{ 1431 return mkreadable(buffer, blen, src, srclen, 0); 1432} 1433 1434/**=========================================================================== 1435 ** implementation of i/o handling methods 1436 ** (all STREAM, partial STREAM, user level) 1437 **/ 1438 1439/* 1440 * define possible io handling methods 1441 */ 1442#ifdef STREAM 1443static int ppsclock_init P((struct parseunit *)); 1444static int stream_init P((struct parseunit *)); 1445static void stream_end P((struct parseunit *)); 1446static int stream_enable P((struct parseunit *)); 1447static int stream_disable P((struct parseunit *)); 1448static int stream_setcs P((struct parseunit *, parsectl_t *)); 1449static int stream_getfmt P((struct parseunit *, parsectl_t *)); 1450static int stream_setfmt P((struct parseunit *, parsectl_t *)); 1451static int stream_timecode P((struct parseunit *, parsectl_t *)); 1452static void stream_receive P((struct recvbuf *)); 1453#endif 1454 1455static int local_init P((struct parseunit *)); 1456static void local_end P((struct parseunit *)); 1457static int local_nop P((struct parseunit *)); 1458static int local_setcs P((struct parseunit *, parsectl_t *)); 1459static int local_getfmt P((struct parseunit *, parsectl_t *)); 1460static int local_setfmt P((struct parseunit *, parsectl_t *)); 1461static int local_timecode P((struct parseunit *, parsectl_t *)); 1462static void local_receive P((struct recvbuf *)); 1463static int local_input P((struct recvbuf *)); 1464 1465static bind_t io_bindings[] = 1466{ 1467#ifdef STREAM 1468 { 1469 "parse STREAM", 1470 stream_init, 1471 stream_end, 1472 stream_setcs, 1473 stream_disable, 1474 stream_enable, 1475 stream_getfmt, 1476 stream_setfmt, 1477 stream_timecode, 1478 stream_receive, 1479 0, 1480 }, 1481 { 1482 "ppsclock STREAM", 1483 ppsclock_init, 1484 local_end, 1485 local_setcs, 1486 local_nop, 1487 local_nop, 1488 local_getfmt, 1489 local_setfmt, 1490 local_timecode, 1491 local_receive, 1492 local_input, 1493 }, 1494#endif 1495 { 1496 "normal", 1497 local_init, 1498 local_end, 1499 local_setcs, 1500 local_nop, 1501 local_nop, 1502 local_getfmt, 1503 local_setfmt, 1504 local_timecode, 1505 local_receive, 1506 local_input, 1507 }, 1508 { 1509 (char *)0, 1510 } 1511}; 1512 1513#ifdef STREAM 1514 1515#define fix_ts(_X_) \ 1516 if ((&(_X_))->tv.tv_usec >= 1000000) \ 1517 { \ 1518 (&(_X_))->tv.tv_usec -= 1000000; \ 1519 (&(_X_))->tv.tv_sec += 1; \ 1520 } 1521 1522#define cvt_ts(_X_, _Y_) \ 1523 { \ 1524 l_fp ts; \ 1525 fix_ts((_X_)); \ 1526 if (!buftvtots((const char *)&(&(_X_))->tv, &ts)) \ 1527 { \ 1528 ERR(ERR_BADDATA) \ 1529 msyslog(LOG_ERR,"parse: stream_receive: timestamp conversion error (buftvtots) (%s) (%ld.%06ld) ", (_Y_), (long)(&(_X_))->tv.tv_sec, (long)(&(_X_))->tv.tv_usec);\ 1530 return; \ 1531 } \ 1532 else \ 1533 { \ 1534 (&(_X_))->fp = ts; \ 1535 } \ 1536 } 1537 1538/*-------------------------------------------------- 1539 * ppsclock STREAM init 1540 */ 1541static int 1542ppsclock_init( 1543 struct parseunit *parse 1544 ) 1545{ 1546 static char m1[] = "ppsclocd"; 1547 static char m2[] = "ppsclock"; 1548 1549 /* 1550 * now push the parse streams module 1551 * it will ensure exclusive access to the device 1552 */ 1553 if (ioctl(parse->generic->io.fd, I_PUSH, (caddr_t)m1) == -1 && 1554 ioctl(parse->generic->io.fd, I_PUSH, (caddr_t)m2) == -1) 1555 { 1556 if (errno != EINVAL) 1557 { 1558 msyslog(LOG_ERR, "PARSE receiver #%d: ppsclock_init: ioctl(fd, I_PUSH, \"ppsclock\"): %m", 1559 CLK_UNIT(parse->peer)); 1560 } 1561 return 0; 1562 } 1563 if (!local_init(parse)) 1564 { 1565 (void)ioctl(parse->generic->io.fd, I_POP, (caddr_t)0); 1566 return 0; 1567 } 1568 1569 parse->flags |= PARSE_PPSCLOCK; 1570 return 1; 1571} 1572 1573/*-------------------------------------------------- 1574 * parse STREAM init 1575 */ 1576static int 1577stream_init( 1578 struct parseunit *parse 1579 ) 1580{ 1581 static char m1[] = "parse"; 1582 /* 1583 * now push the parse streams module 1584 * to test whether it is there (neat interface 8-( ) 1585 */ 1586 if (ioctl(parse->generic->io.fd, I_PUSH, (caddr_t)m1) == -1) 1587 { 1588 if (errno != EINVAL) /* accept non-existence */ 1589 { 1590 msyslog(LOG_ERR, "PARSE receiver #%d: stream_init: ioctl(fd, I_PUSH, \"parse\"): %m", CLK_UNIT(parse->peer)); 1591 } 1592 return 0; 1593 } 1594 else 1595 { 1596 while(ioctl(parse->generic->io.fd, I_POP, (caddr_t)0) == 0) 1597 /* empty loop */; 1598 1599 /* 1600 * now push it a second time after we have removed all 1601 * module garbage 1602 */ 1603 if (ioctl(parse->generic->io.fd, I_PUSH, (caddr_t)m1) == -1) 1604 { 1605 msyslog(LOG_ERR, "PARSE receiver #%d: stream_init: ioctl(fd, I_PUSH, \"parse\"): %m", CLK_UNIT(parse->peer)); 1606 return 0; 1607 } 1608 else 1609 { 1610 return 1; 1611 } 1612 } 1613} 1614 1615/*-------------------------------------------------- 1616 * parse STREAM end 1617 */ 1618static void 1619stream_end( 1620 struct parseunit *parse 1621 ) 1622{ 1623 while(ioctl(parse->generic->io.fd, I_POP, (caddr_t)0) == 0) 1624 /* empty loop */; 1625} 1626 1627/*-------------------------------------------------- 1628 * STREAM setcs 1629 */ 1630static int 1631stream_setcs( 1632 struct parseunit *parse, 1633 parsectl_t *tcl 1634 ) 1635{ 1636 struct strioctl strioc; 1637 1638 strioc.ic_cmd = PARSEIOC_SETCS; 1639 strioc.ic_timout = 0; 1640 strioc.ic_dp = (char *)tcl; 1641 strioc.ic_len = sizeof (*tcl); 1642 1643 if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1) 1644 { 1645 msyslog(LOG_ERR, "PARSE receiver #%d: stream_setcs: ioctl(fd, I_STR, PARSEIOC_SETCS): %m", CLK_UNIT(parse->peer)); 1646 return 0; 1647 } 1648 return 1; 1649} 1650 1651/*-------------------------------------------------- 1652 * STREAM enable 1653 */ 1654static int 1655stream_enable( 1656 struct parseunit *parse 1657 ) 1658{ 1659 struct strioctl strioc; 1660 1661 strioc.ic_cmd = PARSEIOC_ENABLE; 1662 strioc.ic_timout = 0; 1663 strioc.ic_dp = (char *)0; 1664 strioc.ic_len = 0; 1665 1666 if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1) 1667 { 1668 msyslog(LOG_ERR, "PARSE receiver #%d: stream_enable: ioctl(fd, I_STR, PARSEIOC_ENABLE): %m", CLK_UNIT(parse->peer)); 1669 return 0; 1670 } 1671 parse->generic->io.clock_recv = stream_receive; /* ok - parse input in kernel */ 1672 return 1; 1673} 1674 1675/*-------------------------------------------------- 1676 * STREAM disable 1677 */ 1678static int 1679stream_disable( 1680 struct parseunit *parse 1681 ) 1682{ 1683 struct strioctl strioc; 1684 1685 strioc.ic_cmd = PARSEIOC_DISABLE; 1686 strioc.ic_timout = 0; 1687 strioc.ic_dp = (char *)0; 1688 strioc.ic_len = 0; 1689 1690 if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1) 1691 { 1692 msyslog(LOG_ERR, "PARSE receiver #%d: stream_disable: ioctl(fd, I_STR, PARSEIOC_DISABLE): %m", CLK_UNIT(parse->peer)); 1693 return 0; 1694 } 1695 parse->generic->io.clock_recv = local_receive; /* ok - parse input in daemon */ 1696 return 1; 1697} 1698 1699/*-------------------------------------------------- 1700 * STREAM getfmt 1701 */ 1702static int 1703stream_getfmt( 1704 struct parseunit *parse, 1705 parsectl_t *tcl 1706 ) 1707{ 1708 struct strioctl strioc; 1709 1710 strioc.ic_cmd = PARSEIOC_GETFMT; 1711 strioc.ic_timout = 0; 1712 strioc.ic_dp = (char *)tcl; 1713 strioc.ic_len = sizeof (*tcl); 1714 if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1) 1715 { 1716 msyslog(LOG_ERR, "PARSE receiver #%d: ioctl(fd, I_STR, PARSEIOC_GETFMT): %m", CLK_UNIT(parse->peer)); 1717 return 0; 1718 } 1719 return 1; 1720} 1721 1722/*-------------------------------------------------- 1723 * STREAM setfmt 1724 */ 1725static int 1726stream_setfmt( 1727 struct parseunit *parse, 1728 parsectl_t *tcl 1729 ) 1730{ 1731 struct strioctl strioc; 1732 1733 strioc.ic_cmd = PARSEIOC_SETFMT; 1734 strioc.ic_timout = 0; 1735 strioc.ic_dp = (char *)tcl; 1736 strioc.ic_len = sizeof (*tcl); 1737 1738 if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1) 1739 { 1740 msyslog(LOG_ERR, "PARSE receiver #%d: stream_setfmt: ioctl(fd, I_STR, PARSEIOC_SETFMT): %m", CLK_UNIT(parse->peer)); 1741 return 0; 1742 } 1743 return 1; 1744} 1745 1746 1747/*-------------------------------------------------- 1748 * STREAM timecode 1749 */ 1750static int 1751stream_timecode( 1752 struct parseunit *parse, 1753 parsectl_t *tcl 1754 ) 1755{ 1756 struct strioctl strioc; 1757 1758 strioc.ic_cmd = PARSEIOC_TIMECODE; 1759 strioc.ic_timout = 0; 1760 strioc.ic_dp = (char *)tcl; 1761 strioc.ic_len = sizeof (*tcl); 1762 1763 if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1) 1764 { 1765 ERR(ERR_INTERNAL) 1766 msyslog(LOG_ERR, "PARSE receiver #%d: stream_timecode: ioctl(fd, I_STR, PARSEIOC_TIMECODE): %m", CLK_UNIT(parse->peer)); 1767 return 0; 1768 } 1769 clear_err(parse, ERR_INTERNAL); 1770 return 1; 1771} 1772 1773/*-------------------------------------------------- 1774 * STREAM receive 1775 */ 1776static void 1777stream_receive( 1778 struct recvbuf *rbufp 1779 ) 1780{ 1781 struct parseunit *parse = (struct parseunit *)((void *)rbufp->recv_srcclock); 1782 parsetime_t parsetime; 1783 1784 if (!parse->peer) 1785 return; 1786 1787 if (rbufp->recv_length != sizeof(parsetime_t)) 1788 { 1789 ERR(ERR_BADIO) 1790 msyslog(LOG_ERR,"PARSE receiver #%d: stream_receive: bad size (got %d expected %d)", 1791 CLK_UNIT(parse->peer), rbufp->recv_length, (int)sizeof(parsetime_t)); 1792 parse->generic->baddata++; 1793 parse_event(parse, CEVNT_BADREPLY); 1794 return; 1795 } 1796 clear_err(parse, ERR_BADIO); 1797 1798 memmove((caddr_t)&parsetime, 1799 (caddr_t)rbufp->recv_buffer, 1800 sizeof(parsetime_t)); 1801 1802#ifdef DEBUG 1803 if (debug > 3) 1804 { 1805 printf("PARSE receiver #%d: status %06x, state %08x, time %lx.%08lx, stime %lx.%08lx, ptime %lx.%08lx\n", 1806 CLK_UNIT(parse->peer), 1807 (unsigned int)parsetime.parse_status, 1808 (unsigned int)parsetime.parse_state, 1809 (long)parsetime.parse_time.tv.tv_sec, 1810 (long)parsetime.parse_time.tv.tv_usec, 1811 (long)parsetime.parse_stime.tv.tv_sec, 1812 (long)parsetime.parse_stime.tv.tv_usec, 1813 (long)parsetime.parse_ptime.tv.tv_sec, 1814 (long)parsetime.parse_ptime.tv.tv_usec); 1815 } 1816#endif 1817 1818 /* 1819 * switch time stamp world - be sure to normalize small usec field 1820 * errors. 1821 */ 1822 1823 cvt_ts(parsetime.parse_stime, "parse_stime"); 1824 1825 if (PARSE_TIMECODE(parsetime.parse_state)) 1826 { 1827 cvt_ts(parsetime.parse_time, "parse_time"); 1828 } 1829 1830 if (PARSE_PPS(parsetime.parse_state)) 1831 cvt_ts(parsetime.parse_ptime, "parse_ptime"); 1832 1833 parse_process(parse, &parsetime); 1834} 1835#endif 1836 1837/*-------------------------------------------------- 1838 * local init 1839 */ 1840static int 1841local_init( 1842 struct parseunit *parse 1843 ) 1844{ 1845 return parse_ioinit(&parse->parseio); 1846} 1847 1848/*-------------------------------------------------- 1849 * local end 1850 */ 1851static void 1852local_end( 1853 struct parseunit *parse 1854 ) 1855{ 1856 parse_ioend(&parse->parseio); 1857} 1858 1859 1860/*-------------------------------------------------- 1861 * local nop 1862 */ 1863static int 1864local_nop( 1865 struct parseunit *parse 1866 ) 1867{ 1868 return 1; 1869} 1870 1871/*-------------------------------------------------- 1872 * local setcs 1873 */ 1874static int 1875local_setcs( 1876 struct parseunit *parse, 1877 parsectl_t *tcl 1878 ) 1879{ 1880 return parse_setcs(tcl, &parse->parseio); 1881} 1882 1883/*-------------------------------------------------- 1884 * local getfmt 1885 */ 1886static int 1887local_getfmt( 1888 struct parseunit *parse, 1889 parsectl_t *tcl 1890 ) 1891{ 1892 return parse_getfmt(tcl, &parse->parseio); 1893} 1894 1895/*-------------------------------------------------- 1896 * local setfmt 1897 */ 1898static int 1899local_setfmt( 1900 struct parseunit *parse, 1901 parsectl_t *tcl 1902 ) 1903{ 1904 return parse_setfmt(tcl, &parse->parseio); 1905} 1906 1907/*-------------------------------------------------- 1908 * local timecode 1909 */ 1910static int 1911local_timecode( 1912 struct parseunit *parse, 1913 parsectl_t *tcl 1914 ) 1915{ 1916 return parse_timecode(tcl, &parse->parseio); 1917} 1918 1919 1920/*-------------------------------------------------- 1921 * local input 1922 */ 1923static int 1924local_input( 1925 struct recvbuf *rbufp 1926 ) 1927{ 1928 struct parseunit *parse = (struct parseunit *)((void *)rbufp->recv_srcclock); 1929 int count; 1930 unsigned char *s; 1931 timestamp_t ts; 1932 1933 if (!parse->peer) 1934 return 0; 1935 1936 /* 1937 * eat all characters, parsing then and feeding complete samples 1938 */ 1939 count = rbufp->recv_length; 1940 s = (unsigned char *)rbufp->recv_buffer; 1941 ts.fp = rbufp->recv_time; 1942 1943 while (count--) 1944 { 1945 if (parse_ioread(&parse->parseio, (unsigned int)(*s++), &ts)) 1946 { 1947 struct recvbuf buf; 1948 1949 /* 1950 * got something good to eat 1951 */ 1952 if (!PARSE_PPS(parse->parseio.parse_dtime.parse_state)) 1953 { 1954#ifdef TIOCDCDTIMESTAMP 1955 struct timeval dcd_time; 1956 1957 if (ioctl(rbufp->fd, TIOCDCDTIMESTAMP, &dcd_time) != -1) 1958 { 1959 l_fp tstmp; 1960 1961 TVTOTS(&dcd_time, &tstmp); 1962 tstmp.l_ui += JAN_1970; 1963 L_SUB(&ts.fp, &tstmp); 1964 if (ts.fp.l_ui == 0) 1965 { 1966#ifdef DEBUG 1967 if (debug) 1968 { 1969 printf( 1970 "parse: local_receive: fd %d DCDTIMESTAMP %s\n", 1971 rbufp->fd, 1972 lfptoa(&tstmp, 6)); 1973 printf(" sigio %s\n", 1974 lfptoa(&ts.fp, 6)); 1975 } 1976#endif 1977 parse->parseio.parse_dtime.parse_ptime.fp = tstmp; 1978 parse->parseio.parse_dtime.parse_state |= PARSEB_PPS|PARSEB_S_PPS; 1979 } 1980 } 1981#else /* TIOCDCDTIMESTAMP */ 1982#if defined(HAVE_STRUCT_PPSCLOCKEV) && (defined(HAVE_CIOGETEV) || defined(HAVE_TIOCGPPSEV)) 1983 if (parse->flags & PARSE_PPSCLOCK) 1984 { 1985 l_fp tts; 1986 struct ppsclockev ev; 1987 1988#ifdef HAVE_CIOGETEV 1989 if (ioctl(parse->generic->io.fd, CIOGETEV, (caddr_t)&ev) == 0) 1990#endif 1991#ifdef HAVE_TIOCGPPSEV 1992 if (ioctl(parse->generic->io.fd, TIOCGPPSEV, (caddr_t)&ev) == 0) 1993#endif 1994 { 1995 if (ev.serial != parse->ppsserial) 1996 { 1997 /* 1998 * add PPS time stamp if available via ppsclock module 1999 * and not supplied already. 2000 */ 2001 if (!buftvtots((const char *)&ev.tv, &tts)) 2002 { 2003 ERR(ERR_BADDATA) 2004 msyslog(LOG_ERR,"parse: local_receive: timestamp conversion error (buftvtots) (ppsclockev.tv)"); 2005 } 2006 else 2007 { 2008 parse->parseio.parse_dtime.parse_ptime.fp = tts; 2009 parse->parseio.parse_dtime.parse_state |= PARSEB_PPS|PARSEB_S_PPS; 2010 } 2011 } 2012 parse->ppsserial = ev.serial; 2013 } 2014 } 2015#endif 2016#endif /* TIOCDCDTIMESTAMP */ 2017 } 2018 if (count) 2019 { /* simulate receive */ 2020 memmove((caddr_t)buf.recv_buffer, 2021 (caddr_t)&parse->parseio.parse_dtime, 2022 sizeof(parsetime_t)); 2023 parse_iodone(&parse->parseio); 2024 buf.recv_length = sizeof(parsetime_t); 2025 buf.recv_time = rbufp->recv_time; 2026 buf.srcadr = rbufp->srcadr; 2027 buf.dstadr = rbufp->dstadr; 2028 buf.fd = rbufp->fd; 2029 buf.next = 0; 2030 buf.X_from_where = rbufp->X_from_where; 2031 rbufp->receiver(&buf); 2032 } 2033 else 2034 { 2035 memmove((caddr_t)rbufp->recv_buffer, 2036 (caddr_t)&parse->parseio.parse_dtime, 2037 sizeof(parsetime_t)); 2038 parse_iodone(&parse->parseio); 2039 rbufp->recv_length = sizeof(parsetime_t); 2040 return 1; /* got something & in place return */ 2041 } 2042 } 2043 } 2044 return 0; /* nothing to pass up */ 2045} 2046 2047/*-------------------------------------------------- 2048 * local receive 2049 */ 2050static void 2051local_receive( 2052 struct recvbuf *rbufp 2053 ) 2054{ 2055 struct parseunit *parse = (struct parseunit *)((void *)rbufp->recv_srcclock); 2056 parsetime_t parsetime; 2057 2058 if (!parse->peer) 2059 return; 2060 2061 if (rbufp->recv_length != sizeof(parsetime_t)) 2062 { 2063 ERR(ERR_BADIO) 2064 msyslog(LOG_ERR,"PARSE receiver #%d: local_receive: bad size (got %d expected %d)", 2065 CLK_UNIT(parse->peer), rbufp->recv_length, (int)sizeof(parsetime_t)); 2066 parse->generic->baddata++; 2067 parse_event(parse, CEVNT_BADREPLY); 2068 return; 2069 } 2070 clear_err(parse, ERR_BADIO); 2071 2072 memmove((caddr_t)&parsetime, 2073 (caddr_t)rbufp->recv_buffer, 2074 sizeof(parsetime_t)); 2075 2076#ifdef DEBUG 2077 if (debug > 3) 2078 { 2079 printf("PARSE receiver #%d: status %06x, state %08x, time %lx.%08lx, stime %lx.%08lx, ptime %lx.%08lx\n", 2080 CLK_UNIT(parse->peer), 2081 (unsigned int)parsetime.parse_status, 2082 (unsigned int)parsetime.parse_state, 2083 (long)parsetime.parse_time.tv.tv_sec, 2084 (long)parsetime.parse_time.tv.tv_usec, 2085 (long)parsetime.parse_stime.tv.tv_sec, 2086 (long)parsetime.parse_stime.tv.tv_usec, 2087 (long)parsetime.parse_ptime.tv.tv_sec, 2088 (long)parsetime.parse_ptime.tv.tv_usec); 2089 } 2090#endif 2091 2092 parse_process(parse, &parsetime); 2093} 2094 2095/*-------------------------------------------------- 2096 * init_iobinding - find and initialize lower layers 2097 */ 2098static bind_t * 2099init_iobinding( 2100 struct parseunit *parse 2101 ) 2102{ 2103 bind_t *b = io_bindings; 2104 2105 while (b->bd_description != (char *)0) 2106 { 2107 if ((*b->bd_init)(parse)) 2108 { 2109 return b; 2110 } 2111 b++; 2112 } 2113 return (bind_t *)0; 2114} 2115 2116/**=========================================================================== 2117 ** support routines 2118 **/ 2119 2120/*-------------------------------------------------- 2121 * convert a flag field to a string 2122 */ 2123static char * 2124parsestate( 2125 u_long lstate, 2126 char *buffer 2127 ) 2128{ 2129 static struct bits 2130 { 2131 u_long bit; 2132 const char *name; 2133 } flagstrings[] = 2134 { 2135 { PARSEB_ANNOUNCE, "DST SWITCH WARNING" }, 2136 { PARSEB_POWERUP, "NOT SYNCHRONIZED" }, 2137 { PARSEB_NOSYNC, "TIME CODE NOT CONFIRMED" }, 2138 { PARSEB_DST, "DST" }, 2139 { PARSEB_UTC, "UTC DISPLAY" }, 2140 { PARSEB_LEAPADD, "LEAP ADD WARNING" }, 2141 { PARSEB_LEAPDEL, "LEAP DELETE WARNING" }, 2142 { PARSEB_LEAPSECOND, "LEAP SECOND" }, 2143 { PARSEB_ALTERNATE,"ALTERNATE ANTENNA" }, 2144 { PARSEB_TIMECODE, "TIME CODE" }, 2145 { PARSEB_PPS, "PPS" }, 2146 { PARSEB_POSITION, "POSITION" }, 2147 { 0 } 2148 }; 2149 2150 static struct sbits 2151 { 2152 u_long bit; 2153 const char *name; 2154 } sflagstrings[] = 2155 { 2156 { PARSEB_S_LEAP, "LEAP INDICATION" }, 2157 { PARSEB_S_PPS, "PPS SIGNAL" }, 2158 { PARSEB_S_ANTENNA, "ANTENNA" }, 2159 { PARSEB_S_POSITION, "POSITION" }, 2160 { 0 } 2161 }; 2162 int i; 2163 2164 *buffer = '\0'; 2165 2166 i = 0; 2167 while (flagstrings[i].bit) 2168 { 2169 if (flagstrings[i].bit & lstate) 2170 { 2171 if (buffer[0]) 2172 strcat(buffer, "; "); 2173 strcat(buffer, flagstrings[i].name); 2174 } 2175 i++; 2176 } 2177 2178 if (lstate & (PARSEB_S_LEAP|PARSEB_S_ANTENNA|PARSEB_S_PPS|PARSEB_S_POSITION)) 2179 { 2180 char *s, *t; 2181 2182 if (buffer[0]) 2183 strcat(buffer, "; "); 2184 2185 strcat(buffer, "("); 2186 2187 t = s = buffer + strlen(buffer); 2188 2189 i = 0; 2190 while (sflagstrings[i].bit) 2191 { 2192 if (sflagstrings[i].bit & lstate) 2193 { 2194 if (t != s) 2195 { 2196 strcpy(t, "; "); 2197 t += 2; 2198 } 2199 2200 strcpy(t, sflagstrings[i].name); 2201 t += strlen(t); 2202 } 2203 i++; 2204 } 2205 strcpy(t, ")"); 2206 } 2207 return buffer; 2208} 2209 2210/*-------------------------------------------------- 2211 * convert a status flag field to a string 2212 */ 2213static char * 2214parsestatus( 2215 u_long lstate, 2216 char *buffer 2217 ) 2218{ 2219 static struct bits 2220 { 2221 u_long bit; 2222 const char *name; 2223 } flagstrings[] = 2224 { 2225 { CVT_OK, "CONVERSION SUCCESSFUL" }, 2226 { CVT_NONE, "NO CONVERSION" }, 2227 { CVT_FAIL, "CONVERSION FAILED" }, 2228 { CVT_BADFMT, "ILLEGAL FORMAT" }, 2229 { CVT_BADDATE, "DATE ILLEGAL" }, 2230 { CVT_BADTIME, "TIME ILLEGAL" }, 2231 { CVT_ADDITIONAL, "ADDITIONAL DATA" }, 2232 { 0 } 2233 }; 2234 int i; 2235 2236 *buffer = '\0'; 2237 2238 i = 0; 2239 while (flagstrings[i].bit) 2240 { 2241 if (flagstrings[i].bit & lstate) 2242 { 2243 if (buffer[0]) 2244 strcat(buffer, "; "); 2245 strcat(buffer, flagstrings[i].name); 2246 } 2247 i++; 2248 } 2249 2250 return buffer; 2251} 2252 2253/*-------------------------------------------------- 2254 * convert a clock status flag field to a string 2255 */ 2256static const char * 2257clockstatus( 2258 u_long lstate 2259 ) 2260{ 2261 static char buffer[20]; 2262 static struct status 2263 { 2264 u_long value; 2265 const char *name; 2266 } flagstrings[] = 2267 { 2268 { CEVNT_NOMINAL, "NOMINAL" }, 2269 { CEVNT_TIMEOUT, "NO RESPONSE" }, 2270 { CEVNT_BADREPLY,"BAD FORMAT" }, 2271 { CEVNT_FAULT, "FAULT" }, 2272 { CEVNT_PROP, "PROPAGATION DELAY" }, 2273 { CEVNT_BADDATE, "ILLEGAL DATE" }, 2274 { CEVNT_BADTIME, "ILLEGAL TIME" }, 2275 { (unsigned)~0L } 2276 }; 2277 int i; 2278 2279 i = 0; 2280 while (flagstrings[i].value != ~0) 2281 { 2282 if (flagstrings[i].value == lstate) 2283 { 2284 return flagstrings[i].name; 2285 } 2286 i++; 2287 } 2288 2289 sprintf(buffer, "unknown #%ld", (u_long)lstate); 2290 2291 return buffer; 2292} 2293 2294 2295/*-------------------------------------------------- 2296 * l_mktime - make representation of a relative time 2297 */ 2298static char * 2299l_mktime( 2300 u_long delta 2301 ) 2302{ 2303 u_long tmp, m, s; 2304 static char buffer[40]; 2305 2306 buffer[0] = '\0'; 2307 2308 if ((tmp = delta / (60*60*24)) != 0) 2309 { 2310 sprintf(buffer, "%ldd+", (u_long)tmp); 2311 delta -= tmp * 60*60*24; 2312 } 2313 2314 s = delta % 60; 2315 delta /= 60; 2316 m = delta % 60; 2317 delta /= 60; 2318 2319 sprintf(buffer+strlen(buffer), "%02d:%02d:%02d", 2320 (int)delta, (int)m, (int)s); 2321 2322 return buffer; 2323} 2324 2325 2326/*-------------------------------------------------- 2327 * parse_statistics - list summary of clock states 2328 */ 2329static void 2330parse_statistics( 2331 struct parseunit *parse 2332 ) 2333{ 2334 int i; 2335 2336 NLOG(NLOG_CLOCKSTATIST) /* conditional if clause for conditional syslog */ 2337 { 2338 msyslog(LOG_INFO, "PARSE receiver #%d: running time: %s", 2339 CLK_UNIT(parse->peer), 2340 l_mktime(current_time - parse->generic->timestarted)); 2341 2342 msyslog(LOG_INFO, "PARSE receiver #%d: current status: %s", 2343 CLK_UNIT(parse->peer), 2344 clockstatus(parse->generic->currentstatus)); 2345 2346 for (i = 0; i <= CEVNT_MAX; i++) 2347 { 2348 u_long s_time; 2349 u_long percent, d = current_time - parse->generic->timestarted; 2350 2351 percent = s_time = PARSE_STATETIME(parse, i); 2352 2353 while (((u_long)(~0) / 10000) < percent) 2354 { 2355 percent /= 10; 2356 d /= 10; 2357 } 2358 2359 if (d) 2360 percent = (percent * 10000) / d; 2361 else 2362 percent = 10000; 2363 2364 if (s_time) 2365 msyslog(LOG_INFO, "PARSE receiver #%d: state %18s: %13s (%3ld.%02ld%%)", 2366 CLK_UNIT(parse->peer), 2367 clockstatus((unsigned int)i), 2368 l_mktime(s_time), 2369 percent / 100, percent % 100); 2370 } 2371 } 2372} 2373 2374/*-------------------------------------------------- 2375 * cparse_statistics - wrapper for statistics call 2376 */ 2377static void 2378cparse_statistics( 2379 register struct parseunit *parse 2380 ) 2381{ 2382 if (parse->laststatistic + PARSESTATISTICS < current_time) 2383 parse_statistics(parse); 2384 parse->laststatistic = current_time; 2385} 2386 2387/**=========================================================================== 2388 ** ntp interface routines 2389 **/ 2390 2391/*-------------------------------------------------- 2392 * parse_init - initialize internal parse driver data 2393 */ 2394static void 2395parse_init(void) 2396{ 2397 memset((caddr_t)parseunits, 0, sizeof parseunits); 2398} 2399 2400 2401/*-------------------------------------------------- 2402 * parse_shutdown - shut down a PARSE clock 2403 */ 2404static void 2405parse_shutdown( 2406 int unit, 2407 struct peer *peer 2408 ) 2409{ 2410 struct parseunit *parse = (struct parseunit *)peer->procptr->unitptr; 2411 2412 if (parse && !parse->peer) 2413 { 2414 msyslog(LOG_ERR, 2415 "PARSE receiver #%d: parse_shutdown: INTERNAL ERROR, unit not in use", unit); 2416 return; 2417 } 2418 2419 /* 2420 * print statistics a last time and 2421 * stop statistics machine 2422 */ 2423 parse_statistics(parse); 2424 2425 if (parse->parse_type->cl_end) 2426 { 2427 parse->parse_type->cl_end(parse); 2428 } 2429 2430 if (parse->binding) 2431 PARSE_END(parse); 2432 2433 /* 2434 * Tell the I/O module to turn us off. We're history. 2435 */ 2436 io_closeclock(&parse->generic->io); 2437 2438 free_varlist(parse->kv); 2439 2440 NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */ 2441 msyslog(LOG_INFO, "PARSE receiver #%d: reference clock \"%s\" removed", 2442 CLK_UNIT(parse->peer), parse->parse_type->cl_description); 2443 2444 parse->peer = (struct peer *)0; /* unused now */ 2445 free(parse); 2446} 2447 2448/*-------------------------------------------------- 2449 * parse_start - open the PARSE devices and initialize data for processing 2450 */ 2451static int 2452parse_start( 2453 int sysunit, 2454 struct peer *peer 2455 ) 2456{ 2457 u_int unit; 2458 int fd232; 2459#ifdef HAVE_TERMIOS 2460 struct termios tio; /* NEEDED FOR A LONG TIME ! */ 2461#endif 2462#ifdef HAVE_SYSV_TTYS 2463 struct termio tio; /* NEEDED FOR A LONG TIME ! */ 2464#endif 2465 struct parseunit * parse; 2466 char parsedev[sizeof(PARSEDEVICE)+20]; 2467 parsectl_t tmp_ctl; 2468 u_int type; 2469 2470 type = CLK_TYPE(peer); 2471 unit = CLK_UNIT(peer); 2472 2473 if ((type == ~0) || (parse_clockinfo[type].cl_description == (char *)0)) 2474 { 2475 msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: unsupported clock type %d (max %d)", 2476 unit, CLK_REALTYPE(peer), ncltypes-1); 2477 return 0; 2478 } 2479 2480 /* 2481 * Unit okay, attempt to open the device. 2482 */ 2483 (void) sprintf(parsedev, PARSEDEVICE, unit); 2484 2485#ifndef O_NOCTTY 2486#define O_NOCTTY 0 2487#endif 2488 2489 fd232 = open(parsedev, O_RDWR | O_NOCTTY 2490#ifdef O_NONBLOCK 2491 | O_NONBLOCK 2492#endif 2493 , 0777); 2494 2495 if (fd232 == -1) 2496 { 2497 msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: open of %s failed: %m", unit, parsedev); 2498 return 0; 2499 } 2500 2501 parse = (struct parseunit *)emalloc(sizeof(struct parseunit)); 2502 2503 memset((char *)parse, 0, sizeof(struct parseunit)); 2504 2505 parse->generic = peer->procptr; /* link up */ 2506 parse->generic->unitptr = (caddr_t)parse; /* link down */ 2507 2508 /* 2509 * Set up the structures 2510 */ 2511 parse->generic->timestarted = current_time; 2512 parse->lastchange = current_time; 2513 2514 parse->generic->currentstatus = CEVNT_TIMEOUT; /* expect the worst */ 2515 2516 parse->flags = 0; 2517 parse->pollneeddata = 0; 2518 parse->laststatistic = current_time; 2519 parse->lastformat = (unsigned short)~0; /* assume no format known */ 2520 parse->time.parse_status = (unsigned short)~0; /* be sure to mark initial status change */ 2521 parse->lastmissed = 0; /* assume got everything */ 2522 parse->ppsserial = 0; 2523 parse->localdata = (void *)0; 2524 parse->localstate = 0; 2525 parse->kv = (struct ctl_var *)0; 2526 2527 clear_err(parse, ERR_ALL); 2528 2529 parse->parse_type = &parse_clockinfo[type]; 2530 2531 parse->generic->fudgetime1 = parse->parse_type->cl_basedelay; 2532 2533 parse->generic->fudgetime2 = 0.0; 2534 2535 parse->generic->clockdesc = parse->parse_type->cl_description; 2536 2537 peer->rootdelay = parse->parse_type->cl_rootdelay; 2538 peer->sstclktype = parse->parse_type->cl_type; 2539 peer->precision = sys_precision; 2540 2541 peer->burst = NTP_SHIFT; 2542 peer->flags |= FLAG_BURST; 2543 2544 peer->stratum = STRATUM_REFCLOCK; 2545 if (peer->stratum <= 1) 2546 memmove((char *)&parse->generic->refid, parse->parse_type->cl_id, 4); 2547 else 2548 parse->generic->refid = htonl(PARSEHSREFID); 2549 2550 parse->generic->io.fd = fd232; 2551 2552 parse->peer = peer; /* marks it also as busy */ 2553 2554 /* 2555 * configure terminal line 2556 */ 2557 if (TTY_GETATTR(fd232, &tio) == -1) 2558 { 2559 msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: tcgetattr(%d, &tio): %m", unit, fd232); 2560 parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */ 2561 return 0; 2562 } 2563 else 2564 { 2565#ifndef _PC_VDISABLE 2566 memset((char *)tio.c_cc, 0, sizeof(tio.c_cc)); 2567#else 2568 int disablec; 2569 errno = 0; /* pathconf can deliver -1 without changing errno ! */ 2570 2571 disablec = fpathconf(parse->generic->io.fd, _PC_VDISABLE); 2572 if (disablec == -1 && errno) 2573 { 2574 msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: fpathconf(fd, _PC_VDISABLE): %m", CLK_UNIT(parse->peer)); 2575 memset((char *)tio.c_cc, 0, sizeof(tio.c_cc)); /* best guess */ 2576 } 2577 else 2578 if (disablec != -1) 2579 memset((char *)tio.c_cc, disablec, sizeof(tio.c_cc)); 2580#endif 2581 2582#if defined (VMIN) || defined(VTIME) 2583 if ((parse_clockinfo[type].cl_lflag & ICANON) == 0) 2584 { 2585#ifdef VMIN 2586 tio.c_cc[VMIN] = 1; 2587#endif 2588#ifdef VTIME 2589 tio.c_cc[VTIME] = 0; 2590#endif 2591 } 2592#endif 2593 2594 tio.c_cflag = parse_clockinfo[type].cl_cflag; 2595 tio.c_iflag = parse_clockinfo[type].cl_iflag; 2596 tio.c_oflag = parse_clockinfo[type].cl_oflag; 2597 tio.c_lflag = parse_clockinfo[type].cl_lflag; 2598 2599 2600#ifdef HAVE_TERMIOS 2601 if ((cfsetospeed(&tio, parse_clockinfo[type].cl_speed) == -1) || 2602 (cfsetispeed(&tio, parse_clockinfo[type].cl_speed) == -1)) 2603 { 2604 msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: tcset{i,o}speed(&tio, speed): %m", unit); 2605 parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */ 2606 return 0; 2607 } 2608#else 2609 tio.c_cflag |= parse_clockinfo[type].cl_speed; 2610#endif 2611 2612#if defined(HAVE_TIO_SERIAL_STUFF) /* Linux hack: define PPS interface */ 2613 { 2614 struct serial_struct ss; 2615 if (ioctl(fd232, TIOCGSERIAL, &ss) < 0 || 2616 ( 2617#ifdef ASYNC_LOW_LATENCY 2618 ss.flags |= ASYNC_LOW_LATENCY, 2619#endif 2620#ifdef ASYNC_PPS_CD_NEG 2621 ss.flags |= ASYNC_PPS_CD_NEG, 2622#endif 2623 ioctl(fd232, TIOCSSERIAL, &ss)) < 0) { 2624 msyslog(LOG_NOTICE, "refclock_parse: TIOCSSERIAL fd %d, %m", fd232); 2625 msyslog(LOG_NOTICE, 2626 "refclock_parse: optional PPS processing not available"); 2627 } else { 2628 parse->flags |= PARSE_PPSCLOCK; 2629 msyslog(LOG_INFO, 2630 "refclock_parse: PPS detection on"); 2631 } 2632 } 2633#endif 2634#ifdef HAVE_TIOCSPPS /* SUN PPS support */ 2635 if (CLK_PPS(parse->peer)) 2636 { 2637 int i = 1; 2638 2639 if (ioctl(fd232, TIOCSPPS, (caddr_t)&i) == 0) 2640 { 2641 parse->flags |= PARSE_PPSCLOCK; 2642 } 2643 } 2644#endif 2645 2646 if (TTY_SETATTR(fd232, &tio) == -1) 2647 { 2648 msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: tcsetattr(%d, &tio): %m", unit, fd232); 2649 parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */ 2650 return 0; 2651 } 2652 } 2653 2654 /* 2655 * Insert in async io device list. 2656 */ 2657 parse->generic->io.srcclock = (caddr_t)parse; 2658 parse->generic->io.datalen = 0; 2659 2660 if (!io_addclock(&parse->generic->io)) 2661 { 2662 msyslog(LOG_ERR, 2663 "PARSE receiver #%d: parse_start: addclock %s fails (ABORT - clock type requires async io)", CLK_UNIT(parse->peer), parsedev); 2664 parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */ 2665 return 0; 2666 } 2667 2668 parse->binding = init_iobinding(parse); 2669 parse->generic->io.clock_recv = parse->binding->bd_receive; /* pick correct receive routine */ 2670 parse->generic->io.io_input = parse->binding->bd_io_input; /* pick correct input routine */ 2671 2672 if (parse->binding == (bind_t *)0) 2673 { 2674 msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: io sub system initialisation failed.", CLK_UNIT(parse->peer)); 2675 parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */ 2676 return 0; /* well, ok - special initialisation broke */ 2677 } 2678 2679 /* 2680 * as we always(?) get 8 bit chars we want to be 2681 * sure, that the upper bits are zero for less 2682 * than 8 bit I/O - so we pass that information on. 2683 * note that there can be only one bit count format 2684 * per file descriptor 2685 */ 2686 2687 switch (tio.c_cflag & CSIZE) 2688 { 2689 case CS5: 2690 tmp_ctl.parsesetcs.parse_cs = PARSE_IO_CS5; 2691 break; 2692 2693 case CS6: 2694 tmp_ctl.parsesetcs.parse_cs = PARSE_IO_CS6; 2695 break; 2696 2697 case CS7: 2698 tmp_ctl.parsesetcs.parse_cs = PARSE_IO_CS7; 2699 break; 2700 2701 case CS8: 2702 tmp_ctl.parsesetcs.parse_cs = PARSE_IO_CS8; 2703 break; 2704 } 2705 2706 if (!PARSE_SETCS(parse, &tmp_ctl)) 2707 { 2708 msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: parse_setcs() FAILED.", unit); 2709 parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */ 2710 return 0; /* well, ok - special initialisation broke */ 2711 } 2712 2713 strcpy(tmp_ctl.parseformat.parse_buffer, parse->parse_type->cl_format); 2714 tmp_ctl.parseformat.parse_count = strlen(tmp_ctl.parseformat.parse_buffer); 2715 2716 if (!PARSE_SETFMT(parse, &tmp_ctl)) 2717 { 2718 msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: parse_setfmt() FAILED.", unit); 2719 parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */ 2720 return 0; /* well, ok - special initialisation broke */ 2721 } 2722 2723 /* 2724 * get rid of all IO accumulated so far 2725 */ 2726#ifdef HAVE_TERMIOS 2727 (void) tcflush(parse->generic->io.fd, TCIOFLUSH); 2728#else 2729#ifdef TCFLSH 2730 { 2731#ifndef TCIOFLUSH 2732#define TCIOFLUSH 2 2733#endif 2734 int flshcmd = TCIOFLUSH; 2735 2736 (void) ioctl(parse->generic->io.fd, TCFLSH, (caddr_t)&flshcmd); 2737 } 2738#endif 2739#endif 2740 2741 /* 2742 * try to do any special initializations 2743 */ 2744 if (parse->parse_type->cl_init) 2745 { 2746 if (parse->parse_type->cl_init(parse)) 2747 { 2748 parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */ 2749 return 0; /* well, ok - special initialisation broke */ 2750 } 2751 } 2752 2753 /* 2754 * get out Copyright information once 2755 */ 2756 if (!notice) 2757 { 2758 NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */ 2759 msyslog(LOG_INFO, "NTP PARSE support: Copyright (c) 1989-1999, Frank Kardel"); 2760 notice = 1; 2761 } 2762 2763 /* 2764 * print out configuration 2765 */ 2766 NLOG(NLOG_CLOCKINFO) 2767 { 2768 /* conditional if clause for conditional syslog */ 2769 msyslog(LOG_INFO, "PARSE receiver #%d: reference clock \"%s\" (device %s) added", 2770 CLK_UNIT(parse->peer), 2771 parse->parse_type->cl_description, parsedev); 2772 2773 msyslog(LOG_INFO, "PARSE receiver #%d: Stratum %d, %sPPS support, trust time %s, precision %d", 2774 CLK_UNIT(parse->peer), 2775 parse->peer->stratum, CLK_PPS(parse->peer) ? "" : "no ", 2776 l_mktime(parse->parse_type->cl_maxunsync), parse->peer->precision); 2777 2778 msyslog(LOG_INFO, "PARSE receiver #%d: rootdelay %.6f s, phaseadjust %.6f s, %s IO handling", 2779 CLK_UNIT(parse->peer), 2780 parse->parse_type->cl_rootdelay, 2781 parse->generic->fudgetime1, 2782 parse->binding->bd_description); 2783 2784 msyslog(LOG_INFO, "PARSE receiver #%d: Format recognition: %s", CLK_UNIT(parse->peer), 2785 parse->parse_type->cl_format); 2786#ifdef PPS 2787 msyslog(LOG_INFO, "PARSE receiver #%d: %sPPS ioctl support", CLK_UNIT(parse->peer), 2788 (parse->flags & PARSE_PPSCLOCK) ? "" : "NO "); 2789#endif 2790 } 2791 2792 return 1; 2793} 2794 2795/*-------------------------------------------------- 2796 * parse_poll - called by the transmit procedure 2797 */ 2798static void 2799parse_poll( 2800 int unit, 2801 struct peer *peer 2802 ) 2803{ 2804 struct parseunit *parse = (struct parseunit *)peer->procptr->unitptr; 2805 2806 if (peer != parse->peer) 2807 { 2808 msyslog(LOG_ERR, 2809 "PARSE receiver #%d: poll: INTERNAL: peer incorrect", 2810 unit); 2811 return; 2812 } 2813 2814 /* 2815 * Update clock stat counters 2816 */ 2817 parse->generic->polls++; 2818 2819 if (parse->pollneeddata) 2820 { 2821 /* 2822 * bad news - didn't get a response last time 2823 */ 2824 parse->generic->noreply++; 2825 parse->lastmissed = current_time; 2826 parse_event(parse, CEVNT_TIMEOUT); 2827 2828 ERR(ERR_NODATA) 2829 msyslog(LOG_WARNING, "PARSE receiver #%d: no data from device within poll interval (check receiver / cableling)", CLK_UNIT(parse->peer)); 2830 } 2831 2832 /* 2833 * we just mark that we want the next sample for the clock filter 2834 */ 2835 parse->pollneeddata = 1; 2836 2837 if (parse->parse_type->cl_poll) 2838 { 2839 parse->parse_type->cl_poll(parse); 2840 } 2841 2842 cparse_statistics(parse); 2843 2844 return; 2845} 2846 2847#define LEN_STATES 300 /* length of state string */ 2848 2849/*-------------------------------------------------- 2850 * parse_control - set fudge factors, return statistics 2851 */ 2852static void 2853parse_control( 2854 int unit, 2855 struct refclockstat *in, 2856 struct refclockstat *out, 2857 struct peer *peer 2858 ) 2859{ 2860 register struct parseunit *parse = (struct parseunit *)peer->procptr->unitptr; 2861 parsectl_t tmpctl; 2862 2863 static char outstatus[400]; /* status output buffer */ 2864 2865 if (out) 2866 { 2867 out->lencode = 0; 2868 out->p_lastcode = 0; 2869 out->kv_list = (struct ctl_var *)0; 2870 } 2871 2872 if (!parse || !parse->peer) 2873 { 2874 msyslog(LOG_ERR, "PARSE receiver #%d: parse_control: unit invalid (UNIT INACTIVE)", 2875 unit); 2876 return; 2877 } 2878 2879 unit = CLK_UNIT(parse->peer); 2880 2881 if (in) 2882 { 2883 if (in->haveflags & (CLK_HAVEFLAG1|CLK_HAVEFLAG2|CLK_HAVEFLAG3|CLK_HAVEFLAG4)) 2884 { 2885 parse->flags = in->flags & (CLK_FLAG1|CLK_FLAG2|CLK_FLAG3|CLK_FLAG4); 2886 } 2887 } 2888 2889 if (out) 2890 { 2891 u_long sum = 0; 2892 char *t, *tt, *start; 2893 int i; 2894 2895 outstatus[0] = '\0'; 2896 2897 out->type = REFCLK_PARSE; 2898 out->haveflags |= CLK_HAVETIME2; 2899 2900 /* 2901 * figure out skew between PPS and RS232 - just for informational 2902 * purposes - returned in time2 value 2903 */ 2904 if (PARSE_SYNC(parse->time.parse_state)) 2905 { 2906 if (PARSE_PPS(parse->time.parse_state) && PARSE_TIMECODE(parse->time.parse_state)) 2907 { 2908 l_fp off; 2909 2910 /* 2911 * we have a PPS and RS232 signal - calculate the skew 2912 * WARNING: assumes on TIMECODE == PULSE (timecode after pulse) 2913 */ 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)); 2918 } 2919 } 2920 2921 if (PARSE_PPS(parse->time.parse_state)) 2922 { 2923 tt = add_var(&out->kv_list, 80, RO|DEF); 2924 sprintf(tt, "refclock_ppstime=\"%s\"", gmprettydate(&parse->time.parse_ptime.fp)); 2925 } 2926 2927 tt = add_var(&out->kv_list, 128, RO|DEF); 2928 sprintf(tt, "refclock_time=\""); 2929 tt += strlen(tt); 2930 2931 if (parse->time.parse_time.fp.l_ui == 0) 2932 { 2933 strcpy(tt, "<UNDEFINED>\""); 2934 } 2935 else 2936 { 2937 sprintf(tt, "%s\"", gmprettydate(&parse->time.parse_time.fp)); 2938 t = tt + strlen(tt); 2939 } 2940 2941 if (!PARSE_GETTIMECODE(parse, &tmpctl)) 2942 { 2943 ERR(ERR_INTERNAL) 2944 msyslog(LOG_ERR, "PARSE receiver #%d: parse_control: parse_timecode() FAILED", unit); 2945 } 2946 else 2947 { 2948 tt = add_var(&out->kv_list, 512, RO|DEF); 2949 sprintf(tt, "refclock_status=\""); 2950 tt += strlen(tt); 2951 2952 /* 2953 * copy PPS flags from last read transaction (informational only) 2954 */ 2955 tmpctl.parsegettc.parse_state |= parse->time.parse_state & 2956 (PARSEB_PPS|PARSEB_S_PPS); 2957 2958 (void) parsestate(tmpctl.parsegettc.parse_state, tt); 2959 2960 strcat(tt, "\""); 2961 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)); 2965 2966 parse->generic->badformat += tmpctl.parsegettc.parse_badformat; 2967 } 2968 2969 tmpctl.parseformat.parse_format = tmpctl.parsegettc.parse_format; 2970 2971 if (!PARSE_GETFMT(parse, &tmpctl)) 2972 { 2973 ERR(ERR_INTERNAL) 2974 msyslog(LOG_ERR, "PARSE receiver #%d: parse_control: parse_getfmt() FAILED", unit); 2975 } 2976 else 2977 { 2978 tt = add_var(&out->kv_list, 80, RO|DEF); 2979 sprintf(tt, "refclock_format=\""); 2980 2981 strncat(tt, tmpctl.parseformat.parse_buffer, tmpctl.parseformat.parse_count); 2982 strcat(tt,"\""); 2983 } 2984 2985 /* 2986 * gather state statistics 2987 */ 2988 2989 start = tt = add_var(&out->kv_list, LEN_STATES, RO|DEF); 2990 strcpy(tt, "refclock_states=\""); 2991 tt += strlen(tt); 2992 2993 for (i = 0; i <= CEVNT_MAX; i++) 2994 { 2995 u_long s_time; 2996 u_long d = current_time - parse->generic->timestarted; 2997 u_long percent; 2998 2999 percent = s_time = PARSE_STATETIME(parse, i); 3000 3001 while (((u_long)(~0) / 10000) < percent) 3002 { 3003 percent /= 10; 3004 d /= 10; 3005 } 3006 3007 if (d) 3008 percent = (percent * 10000) / d; 3009 else 3010 percent = 10000; 3011 3012 if (s_time) 3013 { 3014 char item[80]; 3015 int count; 3016 3017 sprintf(item, "%s%s%s: %s (%d.%02d%%)", 3018 sum ? "; " : "", 3019 (parse->generic->currentstatus == i) ? "*" : "", 3020 clockstatus((unsigned int)i), 3021 l_mktime(s_time), 3022 (int)(percent / 100), (int)(percent % 100)); 3023 if ((count = strlen(item)) < (LEN_STATES - 40 - (tt - start))) 3024 { 3025 strcpy(tt, item); 3026 tt += count; 3027 } 3028 sum += s_time; 3029 } 3030 } 3031 3032 sprintf(tt, "; running time: %s\"", l_mktime(sum)); 3033 3034 tt = add_var(&out->kv_list, 32, RO); 3035 sprintf(tt, "refclock_id=\"%s\"", parse->parse_type->cl_id); 3036 3037 tt = add_var(&out->kv_list, 80, RO); 3038 sprintf(tt, "refclock_iomode=\"%s\"", parse->binding->bd_description); 3039 3040 tt = add_var(&out->kv_list, 128, RO); 3041 sprintf(tt, "refclock_driver_version=\"%s\"", rcsid); 3042 3043 { 3044 struct ctl_var *k; 3045 3046 k = parse->kv; 3047 while (k && !(k->flags & EOV)) 3048 { 3049 set_var(&out->kv_list, k->text, strlen(k->text)+1, k->flags); 3050 k++; 3051 } 3052 } 3053 3054 out->lencode = strlen(outstatus); 3055 out->p_lastcode = outstatus; 3056 } 3057} 3058 3059/**=========================================================================== 3060 ** processing routines 3061 **/ 3062 3063/*-------------------------------------------------- 3064 * event handling - note that nominal events will also be posted 3065 */ 3066static void 3067parse_event( 3068 struct parseunit *parse, 3069 int event 3070 ) 3071{ 3072 if (parse->generic->currentstatus != (u_char) event) 3073 { 3074 parse->statetime[parse->generic->currentstatus] += current_time - parse->lastchange; 3075 parse->lastchange = current_time; 3076 3077 parse->generic->currentstatus = (u_char)event; 3078 3079 if (parse->parse_type->cl_event) 3080 parse->parse_type->cl_event(parse, event); 3081 3082 if (event != CEVNT_NOMINAL) 3083 { 3084 parse->generic->lastevent = parse->generic->currentstatus; 3085 } 3086 else 3087 { 3088 NLOG(NLOG_CLOCKSTATUS) 3089 msyslog(LOG_INFO, "PARSE receiver #%d: SYNCHRONIZED", 3090 CLK_UNIT(parse->peer)); 3091 } 3092 3093 if (event == CEVNT_FAULT) 3094 { 3095 NLOG(NLOG_CLOCKEVENT) /* conditional if clause for conditional syslog */ 3096 ERR(ERR_BADEVENT) 3097 msyslog(LOG_ERR, 3098 "clock %s fault '%s' (0x%02x)", refnumtoa(parse->peer->srcadr.sin_addr.s_addr), ceventstr(event), 3099 (u_int)event); 3100 } 3101 else 3102 { 3103 NLOG(NLOG_CLOCKEVENT) /* conditional if clause for conditional syslog */ 3104 if (event == CEVNT_NOMINAL || list_err(parse, ERR_BADEVENT)) 3105 msyslog(LOG_INFO, 3106 "clock %s event '%s' (0x%02x)", refnumtoa(parse->peer->srcadr.sin_addr.s_addr), ceventstr(event), 3107 (u_int)event); 3108 } 3109 3110 report_event(EVNT_PEERCLOCK, parse->peer); 3111 report_event(EVNT_CLOCKEXCPT, parse->peer); 3112 } 3113} 3114 3115/*-------------------------------------------------- 3116 * process a PARSE time sample 3117 */ 3118static void 3119parse_process( 3120 struct parseunit *parse, 3121 parsetime_t *parsetime 3122 ) 3123{ 3124 l_fp off, rectime, reftime; 3125 double fudge; 3126 3127 /* 3128 * check for changes in conversion status 3129 * (only one for each new status !) 3130 */ 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)) 3134 { 3135 char buffer[400]; 3136 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)); 3140 3141 if ((parsetime->parse_status & CVT_MASK) == CVT_FAIL) 3142 { 3143 /* 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 3147 */ 3148 parsectl_t tmpctl; 3149 3150 if (!PARSE_GETTIMECODE(parse, &tmpctl)) 3151 { 3152 ERR(ERR_INTERNAL) 3153 msyslog(LOG_ERR, "PARSE receiver #%d: parse_process: parse_timecode() FAILED", CLK_UNIT(parse->peer)); 3154 } 3155 else 3156 { 3157 ERR(ERR_BADDATA) 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; 3161 } 3162 } 3163 } 3164 3165 /* 3166 * examine status and post appropriate events 3167 */ 3168 if ((parsetime->parse_status & CVT_MASK) != CVT_OK) 3169 { 3170 /* 3171 * got bad data - tell the rest of the system 3172 */ 3173 switch (parsetime->parse_status & CVT_MASK) 3174 { 3175 case CVT_NONE: 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 */ 3180 3181 case CVT_FAIL: 3182 parse->generic->badformat++; 3183 if (parsetime->parse_status & CVT_BADFMT) 3184 { 3185 parse_event(parse, CEVNT_BADREPLY); 3186 } 3187 else 3188 if (parsetime->parse_status & CVT_BADDATE) 3189 { 3190 parse_event(parse, CEVNT_BADDATE); 3191 } 3192 else 3193 if (parsetime->parse_status & CVT_BADTIME) 3194 { 3195 parse_event(parse, CEVNT_BADTIME); 3196 } 3197 else 3198 { 3199 parse_event(parse, CEVNT_BADREPLY); /* for the lack of something better */ 3200 } 3201 } 3202 return; /* skip the rest - useless */ 3203 } 3204 3205 /* 3206 * check for format changes 3207 * (in case somebody has swapped clocks 8-) 3208 */ 3209 if (parse->lastformat != parsetime->parse_format) 3210 { 3211 parsectl_t tmpctl; 3212 3213 tmpctl.parseformat.parse_format = parsetime->parse_format; 3214 3215 if (!PARSE_GETFMT(parse, &tmpctl)) 3216 { 3217 ERR(ERR_INTERNAL) 3218 msyslog(LOG_ERR, "PARSE receiver #%d: parse_getfmt() FAILED", CLK_UNIT(parse->peer)); 3219 } 3220 else 3221 { 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); 3225 } 3226 parse->lastformat = parsetime->parse_format; 3227 } 3228 3229 /* 3230 * now, any changes ? 3231 */ 3232 if (parse->time.parse_state != parsetime->parse_state) 3233 { 3234 char tmp1[200]; 3235 char tmp2[200]; 3236 /* 3237 * something happend 3238 */ 3239 3240 (void) parsestate(parsetime->parse_state, tmp1); 3241 (void) parsestate(parse->time.parse_state, tmp2); 3242 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); 3246 } 3247 3248 /* 3249 * remember for future 3250 */ 3251 parse->time = *parsetime; 3252 3253 /* 3254 * check to see, whether the clock did a complete powerup or lost PZF signal 3255 * and post correct events for current condition 3256 */ 3257 if (PARSE_POWERUP(parsetime->parse_state)) 3258 { 3259 /* 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 3283 */ 3284 parse_event(parse, CEVNT_FAULT); 3285 NLOG(NLOG_CLOCKSTATUS) 3286 ERR(ERR_BADSTATUS) 3287 msyslog(LOG_ERR,"PARSE receiver #%d: NOT SYNCHRONIZED", 3288 CLK_UNIT(parse->peer)); 3289 } 3290 else 3291 { 3292 /* 3293 * we have two states left 3294 * 3295 * SYNC: 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 3300 * 3301 * NOSYNC: 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 3309 */ 3310 3311 if (PARSE_SYNC(parsetime->parse_state)) 3312 { 3313 /* 3314 * currently completely synchronized - best possible state 3315 */ 3316 parse->lastsync = current_time; 3317 clear_err(parse, ERR_BADSTATUS); 3318 } 3319 else 3320 { 3321 /* 3322 * we have had some problems receiving the time code 3323 */ 3324 parse_event(parse, CEVNT_PROP); 3325 NLOG(NLOG_CLOCKSTATUS) 3326 ERR(ERR_BADSTATUS) 3327 msyslog(LOG_ERR,"PARSE receiver #%d: TIMECODE NOT CONFIRMED", 3328 CLK_UNIT(parse->peer)); 3329 } 3330 } 3331 3332 fudge = parse->generic->fudgetime1; /* standard RS232 Fudgefactor */ 3333 3334 if (PARSE_TIMECODE(parsetime->parse_state)) 3335 { 3336 rectime = parsetime->parse_stime.fp; 3337 off = reftime = parsetime->parse_time.fp; 3338 3339 L_SUB(&off, &rectime); /* prepare for PPS adjustments logic */ 3340 3341#ifdef DEBUG 3342 if (debug > 3) 3343 printf("PARSE receiver #%d: Reftime %s, Recvtime %s - initial offset %s\n", 3344 CLK_UNIT(parse->peer), 3345 prettydate(&reftime), 3346 prettydate(&rectime), 3347 lfptoa(&off,6)); 3348#endif 3349 } 3350 3351 if (PARSE_PPS(parsetime->parse_state) && CLK_PPS(parse->peer)) 3352 { 3353 l_fp offset; 3354 3355 /* 3356 * we have a PPS signal - much better than the RS232 stuff (we hope) 3357 */ 3358 offset = parsetime->parse_ptime.fp; 3359 3360#ifdef DEBUG 3361 if (debug > 3) 3362 printf("PARSE receiver #%d: PPStime %s\n", 3363 CLK_UNIT(parse->peer), 3364 prettydate(&offset)); 3365#endif 3366 if (PARSE_TIMECODE(parsetime->parse_state)) 3367 { 3368 if (M_ISGEQ(off.l_i, off.l_f, -1, 0x80000000) && 3369 M_ISGEQ(0, 0x7fffffff, off.l_i, off.l_f)) 3370 { 3371 fudge = parse->generic->fudgetime2; /* pick PPS fudge factor */ 3372 3373 /* 3374 * RS232 offsets within [-0.5..0.5[ - take PPS offsets 3375 */ 3376 3377 if (parse->parse_type->cl_flags & PARSE_F_PPSONSECOND) 3378 { 3379 reftime = off = offset; 3380 if (reftime.l_uf & (unsigned)0x80000000) 3381 reftime.l_ui++; 3382 reftime.l_uf = 0; 3383 3384 3385 /* 3386 * implied on second offset 3387 */ 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 */ 3390 } 3391 else 3392 { 3393 /* 3394 * time code describes pulse 3395 */ 3396 reftime = off = parsetime->parse_time.fp; 3397 3398 L_SUB(&off, &offset); /* true offset */ 3399 } 3400 } 3401 /* 3402 * take RS232 offset when PPS when out of bounds 3403 */ 3404 } 3405 else 3406 { 3407 fudge = parse->generic->fudgetime2; /* pick PPS fudge factor */ 3408 /* 3409 * Well, no time code to guide us - assume on second pulse 3410 * and pray, that we are within [-0.5..0.5[ 3411 */ 3412 off = offset; 3413 reftime = offset; 3414 if (reftime.l_uf & (unsigned)0x80000000) 3415 reftime.l_ui++; 3416 reftime.l_uf = 0; 3417 /* 3418 * implied on second offset 3419 */ 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 */ 3422 } 3423 } 3424 else 3425 { 3426 if (!PARSE_TIMECODE(parsetime->parse_state)) 3427 { 3428 /* 3429 * Well, no PPS, no TIMECODE, no more work ... 3430 */ 3431 if ((parsetime->parse_status & CVT_ADDITIONAL) && 3432 parse->parse_type->cl_message) 3433 parse->parse_type->cl_message(parse, parsetime); 3434 return; 3435 } 3436 } 3437 3438#ifdef DEBUG 3439 if (debug > 3) 3440 printf("PARSE receiver #%d: Reftime %s, Recvtime %s - final offset %s\n", 3441 CLK_UNIT(parse->peer), 3442 prettydate(&reftime), 3443 prettydate(&rectime), 3444 lfptoa(&off,6)); 3445#endif 3446 3447 3448 rectime = reftime; 3449 L_SUB(&rectime, &off); /* just to keep the ntp interface happy */ 3450 3451#ifdef DEBUG 3452 if (debug > 3) 3453 printf("PARSE receiver #%d: calculated Reftime %s, Recvtime %s\n", 3454 CLK_UNIT(parse->peer), 3455 prettydate(&reftime), 3456 prettydate(&rectime)); 3457#endif 3458 3459 if ((parsetime->parse_status & CVT_ADDITIONAL) && 3460 parse->parse_type->cl_message) 3461 parse->parse_type->cl_message(parse, parsetime); 3462 3463 if (PARSE_SYNC(parsetime->parse_state)) 3464 { 3465 /* 3466 * log OK status 3467 */ 3468 parse_event(parse, CEVNT_NOMINAL); 3469 } 3470 3471 clear_err(parse, ERR_BADIO); 3472 clear_err(parse, ERR_BADDATA); 3473 clear_err(parse, ERR_NODATA); 3474 clear_err(parse, ERR_INTERNAL); 3475 3476#ifdef DEBUG 3477 if (debug > 2) 3478 { 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), 3483 fudge); 3484 } 3485#endif 3486 3487 refclock_process_offset(parse->generic, reftime, rectime, fudge); 3488 if (PARSE_PPS(parsetime->parse_state) && CLK_PPS(parse->peer)) 3489 { 3490 (void) pps_sample(&parse->time.parse_ptime.fp); 3491 } 3492 3493 3494 /* 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 3500 */ 3501 if (((current_time - parse->lastsync) > parse->parse_type->cl_maxunsync) || 3502 (parse->lastsync <= parse->lastmissed)) 3503 { 3504 parse->generic->leap = LEAP_NOTINSYNC; 3505 } 3506 else 3507 { 3508 if (PARSE_LEAPADD(parsetime->parse_state)) 3509 { 3510 /* 3511 * we pick this state also for time code that pass leap warnings 3512 * without direction information (as earth is currently slowing 3513 * down). 3514 */ 3515 parse->generic->leap = (parse->flags & PARSE_LEAP_DELETE) ? LEAP_DELSECOND : LEAP_ADDSECOND; 3516 } 3517 else 3518 if (PARSE_LEAPDEL(parsetime->parse_state)) 3519 { 3520 parse->generic->leap = LEAP_DELSECOND; 3521 } 3522 else 3523 { 3524 parse->generic->leap = LEAP_NOWARNING; 3525 } 3526 } 3527 3528 /* 3529 * ready, unless the machine wants a sample 3530 */ 3531 if (!parse->pollneeddata) 3532 return; 3533 3534 parse->pollneeddata = 0; 3535 3536 refclock_receive(parse->peer); 3537} 3538 3539/**=========================================================================== 3540 ** special code for special clocks 3541 **/ 3542 3543static void 3544mk_utcinfo( 3545 char *t, 3546 int wnt, 3547 int wnlsf, 3548 int dn, 3549 int dtls, 3550 int dtlsf 3551 ) 3552{ 3553 l_fp leapdate; 3554 3555 sprintf(t, "current correction %d sec", dtls); 3556 t += strlen(t); 3557 3558 if (wnlsf < 990) 3559 wnlsf += 1024; 3560 3561 if (wnt < 990) 3562 wnt += 1024; 3563 3564 gpstolfp((unsigned short)wnlsf, (unsigned short)dn, 0, &leapdate); 3565 3566 if ((dtlsf != dtls) && 3567 ((wnlsf - wnt) < 52)) 3568 { 3569 sprintf(t, ", next correction %d sec on %s, new GPS-UTC offset %d", 3570 dtlsf - dtls, gmprettydate(&leapdate), dtlsf); 3571 } 3572 else 3573 { 3574 sprintf(t, ", last correction on %s", 3575 gmprettydate(&leapdate)); 3576 } 3577} 3578 3579#ifdef CLOCK_MEINBERG 3580/**=========================================================================== 3581 ** Meinberg GPS166/GPS167 support 3582 **/ 3583 3584/*------------------------------------------------------------ 3585 * gps16x_message - process GPS16x messages 3586 */ 3587static void 3588gps16x_message( 3589 struct parseunit *parse, 3590 parsetime_t *parsetime 3591 ) 3592{ 3593 if (parse->time.parse_msglen && parsetime->parse_msg[0] == SOH) 3594 { 3595 GPS_MSG_HDR header; 3596 unsigned char *bufp = (unsigned char *)parsetime->parse_msg + 1; 3597 3598#ifdef DEBUG 3599 if (debug > 2) 3600 { 3601 char msgbuffer[600]; 3602 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, 3607 msgbuffer); 3608 } 3609#endif 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)))) 3615 { 3616 /* 3617 * clean message 3618 */ 3619 switch (header.gps_cmd) 3620 { 3621 case GPS_SW_REV: 3622 { 3623 char buffer[64]; 3624 SW_REV gps_sw_rev; 3625 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] ? " " : "", 3631 gps_sw_rev.name); 3632 set_var(&parse->kv, buffer, 64, RO|DEF); 3633 } 3634 break; 3635 3636 case GPS_STAT: 3637 { 3638 static struct state 3639 { 3640 unsigned short flag; /* status flag */ 3641 unsigned const char *string; /* bit name */ 3642 } states[] = 3643 { 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 *)"" } 3649 }; 3650 unsigned short status; 3651 struct state *s = states; 3652 char buffer[512]; 3653 char *p, *b; 3654 3655 status = get_lsb_short(&bufp); 3656 sprintf(buffer, "meinberg_gps_status=\"[0x%04x] ", status); 3657 3658 if (status) 3659 { 3660 p = b = buffer + strlen(buffer); 3661 while (s->flag) 3662 { 3663 if (status & s->flag) 3664 { 3665 if (p != b) 3666 { 3667 *p++ = ','; 3668 *p++ = ' '; 3669 } 3670 3671 strcat(p, (const char *)s->string); 3672 } 3673 s++; 3674 } 3675 3676 *p++ = '"'; 3677 *p = '\0'; 3678 } 3679 else 3680 { 3681 strcat(buffer, "<OK>\""); 3682 } 3683 3684 set_var(&parse->kv, buffer, 64, RO|DEF); 3685 } 3686 break; 3687 3688 case GPS_POS_XYZ: 3689 { 3690 XYZ xyz; 3691 char buffer[256]; 3692 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)); 3698 3699 set_var(&parse->kv, buffer, sizeof(buffer), RO|DEF); 3700 } 3701 break; 3702 3703 case GPS_POS_LLA: 3704 { 3705 LLA lla; 3706 char buffer[256]; 3707 3708 get_mbg_lla(&bufp, lla); 3709 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)); 3714 3715 set_var(&parse->kv, buffer, sizeof(buffer), RO|DEF); 3716 } 3717 break; 3718 3719 case GPS_TZDL: 3720 break; 3721 3722 case GPS_PORT_PARM: 3723 break; 3724 3725 case GPS_SYNTH: 3726 break; 3727 3728 case GPS_ANT_INFO: 3729 { 3730 ANT_INFO antinfo; 3731 char buffer[512]; 3732 char *p; 3733 3734 get_mbg_antinfo(&bufp, &antinfo); 3735 sprintf((char *)buffer, "meinberg_antenna_status=\""); 3736 p = buffer + strlen(buffer); 3737 3738 switch (antinfo.status) 3739 { 3740 case ANT_INVALID: 3741 strcat(p, "<OK>"); 3742 p += strlen(p); 3743 break; 3744 3745 case ANT_DISCONN: 3746 strcat(p, "DISCONNECTED since "); 3747 NLOG(NLOG_CLOCKSTATUS) 3748 ERR(ERR_BADSTATUS) 3749 msyslog(LOG_ERR,"PARSE receiver #%d: ANTENNA FAILURE: %s", 3750 CLK_UNIT(parse->peer), p); 3751 3752 p += strlen(p); 3753 mbg_tm_str((unsigned char **)&p, &antinfo.tm_disconn); 3754 *p = '\0'; 3755 break; 3756 3757 case ANT_RECONN: 3758 strcat(p, "RECONNECTED on "); 3759 p += strlen(p); 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); 3765 p += strlen(p); 3766 mbg_tm_str((unsigned char **)&p, &antinfo.tm_disconn); 3767 *p = '\0'; 3768 break; 3769 3770 default: 3771 sprintf(p, "bad status 0x%04x", antinfo.status); 3772 p += strlen(p); 3773 break; 3774 } 3775 3776 *p++ = '"'; 3777 *p = '\0'; 3778 3779 set_var(&parse->kv, buffer, sizeof(buffer), RO|DEF); 3780 } 3781 break; 3782 3783 case GPS_UCAP: 3784 break; 3785 3786 case GPS_CFGH: 3787 { 3788 CFGH cfgh; 3789 char buffer[512]; 3790 char *p; 3791 3792 get_mbg_cfgh(&bufp, &cfgh); 3793 if (cfgh.valid) 3794 { 3795 int i; 3796 3797 p = buffer; 3798 strcpy(buffer, "gps_tot_51=\""); 3799 p += strlen(p); 3800 mbg_tgps_str((unsigned char **)&p, &cfgh.tot_51); 3801 *p++ = '"'; 3802 *p = '\0'; 3803 set_var(&parse->kv, buffer, sizeof(buffer), RO); 3804 3805 p = buffer; 3806 strcpy(buffer, "gps_tot_63=\""); 3807 p += strlen(p); 3808 mbg_tgps_str((unsigned char **)&p, &cfgh.tot_63); 3809 *p++ = '"'; 3810 *p = '\0'; 3811 set_var(&parse->kv, buffer, sizeof(buffer), RO); 3812 3813 p = buffer; 3814 strcpy(buffer, "gps_t0a=\""); 3815 p += strlen(p); 3816 mbg_tgps_str((unsigned char **)&p, &cfgh.t0a); 3817 *p++ = '"'; 3818 *p = '\0'; 3819 set_var(&parse->kv, buffer, sizeof(buffer), RO); 3820 3821 for (i = MIN_SVNO; i <= MAX_SVNO; i++) 3822 { 3823 p = buffer; 3824 sprintf(p, "gps_cfg[%d]=\"[0x%x] ", i, cfgh.cfg[i]); 3825 p += strlen(p); 3826 switch (cfgh.cfg[i] & 0x7) 3827 { 3828 case 0: 3829 strcpy(p, "BLOCK I"); 3830 break; 3831 case 1: 3832 strcpy(p, "BLOCK II"); 3833 break; 3834 default: 3835 sprintf(p, "bad CFG"); 3836 break; 3837 } 3838 strcat(p, "\""); 3839 set_var(&parse->kv, buffer, sizeof(buffer), RO); 3840 3841 p = buffer; 3842 sprintf(p, "gps_health[%d]=\"[0x%x] ", i, cfgh.health[i]); 3843 p += strlen(p); 3844 switch ((cfgh.health[i] >> 5) & 0x7 ) 3845 { 3846 case 0: 3847 strcpy(p, "OK;"); 3848 break; 3849 case 1: 3850 strcpy(p, "PARITY;"); 3851 break; 3852 case 2: 3853 strcpy(p, "TLM/HOW;"); 3854 break; 3855 case 3: 3856 strcpy(p, "Z-COUNT;"); 3857 break; 3858 case 4: 3859 strcpy(p, "SUBFRAME 1,2,3;"); 3860 break; 3861 case 5: 3862 strcpy(p, "SUBFRAME 4,5;"); 3863 break; 3864 case 6: 3865 strcpy(p, "UPLOAD BAD;"); 3866 break; 3867 case 7: 3868 strcpy(p, "DATA BAD;"); 3869 break; 3870 } 3871 3872 p += strlen(p); 3873 3874 switch (cfgh.health[i] & 0x1F) 3875 { 3876 case 0: 3877 strcpy(p, "SIGNAL OK"); 3878 break; 3879 case 0x1C: 3880 strcpy(p, "SV TEMP OUT"); 3881 break; 3882 case 0x1D: 3883 strcpy(p, "SV WILL BE TEMP OUT"); 3884 break; 3885 case 0x1E: 3886 break; 3887 case 0x1F: 3888 strcpy(p, "MULTIPLE ERRS"); 3889 break; 3890 default: 3891 strcpy(p, "TRANSMISSION PROBLEMS"); 3892 break; 3893 } 3894 3895 strcat(p, "\""); 3896 set_var(&parse->kv, buffer, sizeof(buffer), RO); 3897 } 3898 } 3899 } 3900 break; 3901 3902 case GPS_ALM: 3903 break; 3904 3905 case GPS_EPH: 3906 break; 3907 3908 case GPS_UTC: 3909 { 3910 UTC utc; 3911 char buffer[512]; 3912 char *p; 3913 3914 p = buffer; 3915 3916 get_mbg_utc(&bufp, &utc); 3917 3918 if (utc.valid) 3919 { 3920 strcpy(p, "gps_utc_correction=\""); 3921 p += strlen(p); 3922 mk_utcinfo(p, utc.t0t.wn, utc.WNlsf, utc.DNt, utc.delta_tls, utc.delta_tlsf); 3923 strcat(p, "\""); 3924 } 3925 else 3926 { 3927 strcpy(p, "gps_utc_correction=\"<NO UTC DATA>\""); 3928 } 3929 set_var(&parse->kv, buffer, sizeof(buffer), RO|DEF); 3930 } 3931 break; 3932 3933 case GPS_IONO: 3934 break; 3935 3936 case GPS_ASCII_MSG: 3937 { 3938 ASCII_MSG gps_ascii_msg; 3939 char buffer[128]; 3940 3941 get_mbg_ascii_msg(&bufp, &gps_ascii_msg); 3942 3943 if (gps_ascii_msg.valid) 3944 { 3945 char buffer1[128]; 3946 mkreadable(buffer1, sizeof(buffer1), gps_ascii_msg.s, strlen(gps_ascii_msg.s), (int)0); 3947 3948 sprintf(buffer, "gps_message=\"%s\"", buffer1); 3949 } 3950 else 3951 strcpy(buffer, "gps_message=<NONE>"); 3952 3953 set_var(&parse->kv, buffer, 128, RO|DEF); 3954 } 3955 3956 break; 3957 3958 default: 3959 break; 3960 } 3961 } 3962 else 3963 { 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), 3967 header.gps_len, 3968 header.gps_data_csum, mbg_csum(bufp, (unsigned)((header.gps_len < sizeof(parsetime->parse_msg)) ? header.gps_len : 0))); 3969 } 3970 } 3971 3972 return; 3973} 3974 3975/*------------------------------------------------------------ 3976 * gps16x_poll - query the reciver peridically 3977 */ 3978static void 3979gps16x_poll( 3980 struct peer *peer 3981 ) 3982{ 3983 struct parseunit *parse = (struct parseunit *)peer->procptr->unitptr; 3984 3985 static GPS_MSG_HDR sequence[] = 3986 { 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 } 3996 }; 3997 3998 int rtc; 3999 unsigned char cmd_buffer[64]; 4000 unsigned char *outp = cmd_buffer; 4001 GPS_MSG_HDR *header; 4002 4003 if (((poll_info_t *)parse->parse_type->cl_data)->rate) 4004 { 4005 parse->peer->nextaction = current_time + ((poll_info_t *)parse->parse_type->cl_data)->rate; 4006 } 4007 4008 if (sequence[parse->localstate].gps_cmd == (unsigned short)~0) 4009 parse->localstate = 0; 4010 4011 header = sequence + parse->localstate++; 4012 4013 *outp++ = SOH; /* start command */ 4014 4015 put_mbg_header(&outp, header); 4016 outp = cmd_buffer + 1; 4017 4018 header->gps_hdr_csum = (short)mbg_csum(outp, 6); 4019 put_mbg_header(&outp, header); 4020 4021#ifdef DEBUG 4022 if (debug > 2) 4023 { 4024 char buffer[128]; 4025 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), 4031 buffer); 4032 } 4033#endif 4034 4035 rtc = write(parse->generic->io.fd, cmd_buffer, (unsigned long)(outp - cmd_buffer)); 4036 4037 if (rtc < 0) 4038 { 4039 ERR(ERR_BADIO) 4040 msyslog(LOG_ERR, "PARSE receiver #%d: gps16x_poll: failed to send cmd to clock: %m", CLK_UNIT(parse->peer)); 4041 } 4042 else 4043 if (rtc != outp - cmd_buffer) 4044 { 4045 ERR(ERR_BADIO) 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)); 4047 } 4048 4049 clear_err(parse, ERR_BADIO); 4050 return; 4051} 4052 4053/*-------------------------------------------------- 4054 * init routine - setup timer 4055 */ 4056static int 4057gps16x_poll_init( 4058 struct parseunit *parse 4059 ) 4060{ 4061 if (((poll_info_t *)parse->parse_type->cl_data)->rate) 4062 { 4063 parse->peer->action = gps16x_poll; 4064 gps16x_poll(parse->peer); 4065 } 4066 4067 return 0; 4068} 4069 4070#else 4071static void 4072gps16x_message( 4073 struct parseunit *parse, 4074 parsetime_t *parsetime 4075 ) 4076{} 4077static int 4078gps16x_poll_init( 4079 struct parseunit *parse 4080 ) 4081{ 4082 return 1; 4083} 4084#endif /* CLOCK_MEINBERG */ 4085 4086/**=========================================================================== 4087 ** clock polling support 4088 **/ 4089 4090/*-------------------------------------------------- 4091 * direct poll routine 4092 */ 4093static void 4094poll_dpoll( 4095 struct parseunit *parse 4096 ) 4097{ 4098 int rtc; 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; 4101 4102 rtc = write(parse->generic->io.fd, ps, (unsigned long)ct); 4103 if (rtc < 0) 4104 { 4105 ERR(ERR_BADIO) 4106 msyslog(LOG_ERR, "PARSE receiver #%d: poll_dpoll: failed to send cmd to clock: %m", CLK_UNIT(parse->peer)); 4107 } 4108 else 4109 if (rtc != ct) 4110 { 4111 ERR(ERR_BADIO) 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); 4113 } 4114 clear_err(parse, ERR_BADIO); 4115} 4116 4117/*-------------------------------------------------- 4118 * periodic poll routine 4119 */ 4120static void 4121poll_poll( 4122 struct peer *peer 4123 ) 4124{ 4125 struct parseunit *parse = (struct parseunit *)peer->procptr->unitptr; 4126 4127 if (parse->parse_type->cl_poll) 4128 parse->parse_type->cl_poll(parse); 4129 4130 if (((poll_info_t *)parse->parse_type->cl_data)->rate) 4131 { 4132 parse->peer->nextaction = current_time + ((poll_info_t *)parse->parse_type->cl_data)->rate; 4133 } 4134} 4135 4136/*-------------------------------------------------- 4137 * init routine - setup timer 4138 */ 4139static int 4140poll_init( 4141 struct parseunit *parse 4142 ) 4143{ 4144 if (((poll_info_t *)parse->parse_type->cl_data)->rate) 4145 { 4146 parse->peer->action = poll_poll; 4147 poll_poll(parse->peer); 4148 } 4149 4150 return 0; 4151} 4152 4153/**=========================================================================== 4154 ** Trimble support 4155 **/ 4156 4157/*------------------------------------------------------------- 4158 * trimble TAIP init routine - setup EOL and then do poll_init. 4159 */ 4160static int 4161trimbletaip_init( 4162 struct parseunit *parse 4163 ) 4164{ 4165#ifdef HAVE_TERMIOS 4166 struct termios tio; 4167#endif 4168#ifdef HAVE_SYSV_TTYS 4169 struct termio tio; 4170#endif 4171 /* 4172 * configure terminal line for trimble receiver 4173 */ 4174 if (TTY_GETATTR(parse->generic->io.fd, &tio) == -1) 4175 { 4176 msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_init: tcgetattr(fd, &tio): %m", CLK_UNIT(parse->peer)); 4177 return 0; 4178 } 4179 else 4180 { 4181 tio.c_cc[VEOL] = TRIMBLETAIP_EOL; 4182 4183 if (TTY_SETATTR(parse->generic->io.fd, &tio) == -1) 4184 { 4185 msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_init: tcsetattr(fd, &tio): %m", CLK_UNIT(parse->peer)); 4186 return 0; 4187 } 4188 } 4189 return poll_init(parse); 4190} 4191 4192/*-------------------------------------------------- 4193 * trimble TAIP event routine - reset receiver upon data format trouble 4194 */ 4195static const char *taipinit[] = { 4196 ">FPV00000000<", 4197 ">SRM;ID_FLAG=F;CS_FLAG=T;EC_FLAG=F;FR_FLAG=T;CR_FLAG=F<", 4198 ">FTM00020001<", 4199 (char *)0 4200}; 4201 4202static void 4203trimbletaip_event( 4204 struct parseunit *parse, 4205 int event 4206 ) 4207{ 4208 switch (event) 4209 { 4210 case CEVNT_BADREPLY: /* reset on garbled input */ 4211 case CEVNT_TIMEOUT: /* reset on no input */ 4212 { 4213 const char **iv; 4214 4215 iv = taipinit; 4216 while (*iv) 4217 { 4218 int rtc = write(parse->generic->io.fd, *iv, strlen(*iv)); 4219 if (rtc < 0) 4220 { 4221 msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_event: failed to send cmd to clock: %m", CLK_UNIT(parse->peer)); 4222 return; 4223 } 4224 else 4225 { 4226 if (rtc != strlen(*iv)) 4227 { 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)); 4230 return; 4231 } 4232 } 4233 iv++; 4234 } 4235 4236 NLOG(NLOG_CLOCKINFO) 4237 ERR(ERR_BADIO) 4238 msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_event: RECEIVER INITIALIZED", 4239 CLK_UNIT(parse->peer)); 4240 } 4241 break; 4242 4243 default: /* ignore */ 4244 break; 4245 } 4246} 4247 4248/* 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). 4252 * 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. 4264 * 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 4273 * 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: 4277 * 4278 * <DLE><id> ... <data> ... <DLE><ETX> 4279 * 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: 4291 * 4292 * ID Description 4293 * 4294 * 21 Request current time 4295 * 22 Mode Select 4296 * 2C Set/Request operating parameters 4297 * 2F Request UTC info 4298 * 35 Set/Request I/O options 4299 4300 * From receiver to driver the following are recognised: 4301 * 4302 * ID Description 4303 * 4304 * 41 GPS Time 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) 4311 * 4312 * All others are accepted but ignored. 4313 * 4314 */ 4315 4316#define PI 3.1415926535898 /* lots of sig figs */ 4317#define D2R PI/180.0 4318 4319/*------------------------------------------------------------------- 4320 * sendcmd, sendbyte, sendetx, sendflt, sendint implement the command 4321 * interface to the receiver. 4322 * 4323 * CAVEAT: the sendflt, sendint routines are byte order dependend and 4324 * float implementation dependend - these must be converted to portable 4325 * versions ! 4326 * 4327 * CURRENT LIMITATION: float implementation. This runs only on systems 4328 * with IEEE754 floats as native floats 4329 */ 4330 4331typedef struct trimble 4332{ 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 */ 4337} trimble_t; 4338 4339union uval { 4340 u_char bd[8]; 4341 int iv; 4342 float fv; 4343 double dv; 4344}; 4345 4346struct txbuf 4347{ 4348 short idx; /* index to first unused byte */ 4349 u_char *txt; /* pointer to actual data buffer */ 4350}; 4351 4352void 4353sendcmd( 4354 struct txbuf *buf, 4355 int c 4356 ) 4357{ 4358 buf->txt[0] = DLE; 4359 buf->txt[1] = (u_char)c; 4360 buf->idx = 2; 4361} 4362 4363void 4364sendbyte( 4365 struct txbuf *buf, 4366 int b 4367 ) 4368{ 4369 if (b == DLE) 4370 buf->txt[buf->idx++] = DLE; 4371 buf->txt[buf->idx++] = (u_char)b; 4372} 4373 4374void 4375sendetx( 4376 struct txbuf *buf, 4377 struct parseunit *parse 4378 ) 4379{ 4380 buf->txt[buf->idx++] = DLE; 4381 buf->txt[buf->idx++] = ETX; 4382 4383 if (write(parse->generic->io.fd, buf->txt, (unsigned long)buf->idx) != buf->idx) 4384 { 4385 ERR(ERR_BADIO) 4386 msyslog(LOG_ERR, "PARSE receiver #%d: sendetx: failed to send cmd to clock: %m", CLK_UNIT(parse->peer)); 4387 } 4388 else 4389 { 4390#ifdef DEBUG 4391 if (debug > 2) 4392 { 4393 char buffer[256]; 4394 4395 mkreadable(buffer, sizeof(buffer), (char *)buf->txt, (unsigned)buf->idx, 1); 4396 printf("PARSE receiver #%d: transmitted message (%d bytes) >%s<\n", 4397 CLK_UNIT(parse->peer), 4398 buf->idx, buffer); 4399 } 4400#endif 4401 clear_err(parse, ERR_BADIO); 4402 } 4403} 4404 4405void 4406sendint( 4407 struct txbuf *buf, 4408 int a 4409 ) 4410{ 4411 /* send 16bit int, msbyte first */ 4412 sendbyte(buf, (u_char)((a>>8) & 0xff)); 4413 sendbyte(buf, (u_char)(a & 0xff)); 4414} 4415 4416void 4417sendflt( 4418 struct txbuf *buf, 4419 double a 4420 ) 4421{ 4422 int i; 4423 union uval uval; 4424 4425 uval.fv = a; 4426#ifdef WORDS_BIGENDIAN 4427 for (i=0; i<=3; i++) 4428#else 4429 for (i=3; i>=0; i--) 4430#endif 4431 sendbyte(buf, uval.bd[i]); 4432} 4433 4434#define TRIM_POS_OPT 0x13 /* output position with high precision */ 4435#define TRIM_TIME_OPT 0x03 /* use UTC time stamps, on second */ 4436 4437/*-------------------------------------------------- 4438 * trimble TSIP setup routine 4439 */ 4440static int 4441trimbletsip_setup( 4442 struct parseunit *parse, 4443 const char *reason 4444 ) 4445{ 4446 u_char buffer[256]; 4447 struct txbuf buf; 4448 4449 buf.txt = buffer; 4450 4451 sendcmd(&buf, CMD_CVERSION); /* request software versions */ 4452 sendetx(&buf, parse); 4453 4454 sendcmd(&buf, CMD_COPERPARAM); /* set operating parameters */ 4455 sendbyte(&buf, 4); /* static */ 4456 sendflt(&buf, 5.0*D2R); /* elevation angle mask = 10 deg XXX */ 4457 sendflt(&buf, 4.0); /* s/n ratio mask = 6 XXX */ 4458 sendflt(&buf, 12.0); /* PDOP mask = 12 */ 4459 sendflt(&buf, 8.0); /* PDOP switch level = 8 */ 4460 sendetx(&buf, parse); 4461 4462 sendcmd(&buf, CMD_CMODESEL); /* fix mode select */ 4463 sendbyte(&buf, 0); /* automatic */ 4464 sendetx(&buf, parse); 4465 4466 sendcmd(&buf, CMD_CMESSAGE); /* request system message */ 4467 sendetx(&buf, parse); 4468 4469 sendcmd(&buf, CMD_CSUPER); /* superpacket fix */ 4470 sendbyte(&buf, 0x2); /* binary mode */ 4471 sendetx(&buf, parse); 4472 4473 sendcmd(&buf, CMD_CIOOPTIONS); /* set I/O options */ 4474 sendbyte(&buf, TRIM_POS_OPT); /* position output */ 4475 sendbyte(&buf, 0x00); /* no velocity output */ 4476 sendbyte(&buf, TRIM_TIME_OPT); /* UTC, compute on seconds */ 4477 sendbyte(&buf, 0x00); /* no raw measurements */ 4478 sendetx(&buf, parse); 4479 4480 sendcmd(&buf, CMD_CUTCPARAM); /* request UTC correction data */ 4481 sendetx(&buf, parse); 4482 4483 NLOG(NLOG_CLOCKINFO) 4484 ERR(ERR_BADIO) 4485 msyslog(LOG_ERR, "PARSE receiver #%d: trimbletsip_setup: RECEIVER RE-INITIALIZED (%s)", CLK_UNIT(parse->peer), reason); 4486 4487 return 0; 4488} 4489 4490/*-------------------------------------------------- 4491 * TRIMBLE TSIP check routine 4492 */ 4493static void 4494trimble_check( 4495 struct peer *peer 4496 ) 4497{ 4498 struct parseunit *parse = (struct parseunit *)peer->procptr->unitptr; 4499 trimble_t *t = parse->localdata; 4500 u_char buffer[256]; 4501 struct txbuf buf; 4502 buf.txt = buffer; 4503 4504 if (t) 4505 { 4506 if (current_time > t->last_msg + TRIMBLETSIP_IDLE_TIME) 4507 (void)trimbletsip_setup(parse, "message timeout"); 4508 } 4509 poll_poll(parse->peer); /* emit query string and re-arm timer */ 4510 4511 if (t->qtracking) 4512 { 4513 u_long oldsats = t->ltrack & ~t->ctrack; 4514 4515 t->qtracking = 0; 4516 t->ltrack = t->ctrack; 4517 4518 if (oldsats) 4519 { 4520 int i; 4521 4522 for (i = 0; oldsats; i++) 4523 if (oldsats & (1 << i)) 4524 { 4525 sendcmd(&buf, CMD_CSTATTRACK); 4526 sendbyte(&buf, i+1); /* old sat */ 4527 sendetx(&buf, parse); 4528 } 4529 oldsats &= ~(1 << i); 4530 } 4531 4532 sendcmd(&buf, CMD_CSTATTRACK); 4533 sendbyte(&buf, 0x00); /* current tracking set */ 4534 sendetx(&buf, parse); 4535 } 4536} 4537 4538/*-------------------------------------------------- 4539 * TRIMBLE TSIP end routine 4540 */ 4541static void 4542trimbletsip_end( 4543 struct parseunit *parse 4544 ) 4545{ trimble_t *t = parse->localdata; 4546 4547 if (t) 4548 { 4549 free(t); 4550 parse->localdata = (void *)0; 4551 } 4552 parse->peer->nextaction = 0; 4553 parse->peer->action = (void (*) P((struct peer *)))0; 4554} 4555 4556/*-------------------------------------------------- 4557 * TRIMBLE TSIP init routine 4558 */ 4559static int 4560trimbletsip_init( 4561 struct parseunit *parse 4562 ) 4563{ 4564#if defined(VEOL) || defined(VEOL2) 4565#ifdef HAVE_TERMIOS 4566 struct termios tio; /* NEEDED FOR A LONG TIME ! */ 4567#endif 4568#ifdef HAVE_SYSV_TTYS 4569 struct termio tio; /* NEEDED FOR A LONG TIME ! */ 4570#endif 4571 /* 4572 * allocate local data area 4573 */ 4574 if (!parse->localdata) 4575 { 4576 trimble_t *t; 4577 4578 t = (trimble_t *)(parse->localdata = emalloc(sizeof(trimble_t))); 4579 4580 if (t) 4581 { 4582 memset((char *)t, 0, sizeof(trimble_t)); 4583 t->last_msg = current_time; 4584 } 4585 } 4586 4587 parse->peer->action = trimble_check; 4588 parse->peer->nextaction = current_time; 4589 4590 /* 4591 * configure terminal line for ICANON mode with VEOL characters 4592 */ 4593 if (TTY_GETATTR(parse->generic->io.fd, &tio) == -1) 4594 { 4595 msyslog(LOG_ERR, "PARSE receiver #%d: trimbletsip_init: tcgetattr(%d, &tio): %m", CLK_UNIT(parse->peer), parse->generic->io.fd); 4596 return 0; 4597 } 4598 else 4599 { 4600 if ((parse_clockinfo[CLK_TYPE(parse->peer)].cl_lflag & ICANON)) 4601 { 4602#ifdef VEOL 4603 tio.c_cc[VEOL] = ETX; 4604#endif 4605#ifdef VEOL2 4606 tio.c_cc[VEOL2] = DLE; 4607#endif 4608} 4609 4610 if (TTY_SETATTR(parse->generic->io.fd, &tio) == -1) 4611 { 4612 msyslog(LOG_ERR, "PARSE receiver #%d: trimbletsip_init: tcsetattr(%d, &tio): %m", CLK_UNIT(parse->peer), parse->generic->io.fd); 4613 return 0; 4614 } 4615 } 4616#endif 4617 return trimbletsip_setup(parse, "initial startup"); 4618} 4619 4620/*------------------------------------------------------------ 4621 * trimbletsip_event - handle Trimble events 4622 * simple evente handler - attempt to re-initialize receiver 4623 */ 4624static void 4625trimbletsip_event( 4626 struct parseunit *parse, 4627 int event 4628 ) 4629{ 4630 switch (event) 4631 { 4632 case CEVNT_BADREPLY: /* reset on garbled input */ 4633 case CEVNT_TIMEOUT: /* reset on no input */ 4634 (void)trimbletsip_setup(parse, "event BAD_REPLY/TIMEOUT"); 4635 break; 4636 4637 default: /* ignore */ 4638 break; 4639 } 4640} 4641 4642/* 4643 * getflt, getint convert fields in the incoming data into the 4644 * appropriate type of item 4645 * 4646 * CAVEAT: these routines are currently definitely byte order dependent 4647 * and assume Representation(float) == IEEE754 4648 * These functions MUST be converted to portable versions (especially 4649 * converting the float representation into ntp_fp formats in order 4650 * to avoid floating point operations at all! 4651 */ 4652 4653static float 4654getflt( 4655 u_char *bp 4656 ) 4657{ 4658 union uval uval; 4659 4660#ifdef WORDS_BIGENDIAN 4661 uval.bd[0] = *bp++; 4662 uval.bd[1] = *bp++; 4663 uval.bd[2] = *bp++; 4664 uval.bd[3] = *bp; 4665#else /* ! WORDS_BIGENDIAN */ 4666 uval.bd[3] = *bp++; 4667 uval.bd[2] = *bp++; 4668 uval.bd[1] = *bp++; 4669 uval.bd[0] = *bp; 4670#endif /* ! WORDS_BIGENDIAN */ 4671 return uval.fv; 4672} 4673 4674static double 4675getdbl( 4676 u_char *bp 4677 ) 4678{ 4679 union uval uval; 4680 4681#ifdef WORDS_BIGENDIAN 4682 uval.bd[0] = *bp++; 4683 uval.bd[1] = *bp++; 4684 uval.bd[2] = *bp++; 4685 uval.bd[3] = *bp++; 4686 uval.bd[4] = *bp++; 4687 uval.bd[5] = *bp++; 4688 uval.bd[6] = *bp++; 4689 uval.bd[7] = *bp; 4690#else /* ! WORDS_BIGENDIAN */ 4691 uval.bd[7] = *bp++; 4692 uval.bd[6] = *bp++; 4693 uval.bd[5] = *bp++; 4694 uval.bd[4] = *bp++; 4695 uval.bd[3] = *bp++; 4696 uval.bd[2] = *bp++; 4697 uval.bd[1] = *bp++; 4698 uval.bd[0] = *bp; 4699#endif /* ! WORDS_BIGENDIAN */ 4700 return uval.dv; 4701} 4702 4703static int 4704getshort( 4705 unsigned char *p 4706 ) 4707{ 4708 return get_msb_short(&p); 4709} 4710 4711/*-------------------------------------------------- 4712 * trimbletsip_message - process trimble messages 4713 */ 4714#define RTOD (180.0 / 3.1415926535898) 4715#define mb(_X_) (buffer[2+(_X_)]) /* shortcut for buffer access */ 4716 4717static void 4718trimbletsip_message( 4719 struct parseunit *parse, 4720 parsetime_t *parsetime 4721 ) 4722{ 4723 unsigned char *buffer = parsetime->parse_msg; 4724 unsigned int size = parsetime->parse_msglen; 4725 4726 if ((size < 4) || 4727 (buffer[0] != DLE) || 4728 (buffer[size-1] != ETX) || 4729 (buffer[size-2] != DLE)) 4730 { 4731#ifdef DEBUG 4732 if (debug > 2) { 4733 int i; 4734 4735 printf("TRIMBLE BAD packet, size %d:\n ", size); 4736 for (i = 0; i < size; i++) { 4737 printf ("%2.2x, ", buffer[i]&0xff); 4738 if (i%16 == 15) printf("\n\t"); 4739 } 4740 printf("\n"); 4741 } 4742#endif 4743 return; 4744 } 4745 else 4746 { 4747 int var_flag; 4748 trimble_t *tr = parse->localdata; 4749 unsigned int cmd = buffer[1]; 4750 char pbuffer[200]; 4751 char *t = pbuffer; 4752 cmd_info_t *s; 4753 4754#ifdef DEBUG 4755 if (debug > 3) { 4756 int i; 4757 4758 printf("TRIMBLE packet 0x%02x, size %d:\n ", cmd, size); 4759 for (i = 0; i < size; i++) { 4760 printf ("%2.2x, ", buffer[i]&0xff); 4761 if (i%16 == 15) printf("\n\t"); 4762 } 4763 printf("\n"); 4764 } 4765#endif 4766 4767 if (tr) 4768 tr->last_msg = current_time; 4769 4770 s = trimble_convert(cmd, trimble_rcmds); 4771 4772 if (s) 4773 { 4774 sprintf(t, "%s=\"", s->varname); 4775 } 4776 else 4777 { 4778 printf("TRIMBLE unknown command 0x%02x\n", cmd); 4779 return; 4780 } 4781 4782 var_flag = s->varmode; 4783 4784 t += strlen(t); 4785 4786 switch(cmd) 4787 { 4788 case CMD_RCURTIME: 4789 sprintf(t, "%f, %d, %f", 4790 getflt((unsigned char *)&mb(0)), getshort((unsigned char *)&mb(4)), 4791 getflt((unsigned char *)&mb(6))); 4792 break; 4793 4794 case CMD_RBEST4: 4795 strcpy(t, "mode: "); 4796 t += strlen(t); 4797 switch (mb(0) & 0xF) 4798 { 4799 default: 4800 sprintf(t, "0x%x", mb(0) & 0x7); 4801 break; 4802 4803 case 1: 4804 strcat(t, "0D"); 4805 break; 4806 4807 case 3: 4808 strcat(t, "2D"); 4809 break; 4810 4811 case 4: 4812 strcat(t, "3D"); 4813 break; 4814 } 4815 t += strlen(t); 4816 if (mb(0) & 0x10) 4817 strcpy(t, "-MANUAL, "); 4818 else 4819 strcpy(t, "-AUTO, "); 4820 t += strlen(t); 4821 4822 sprintf(t, "satellites %02d %02d %02d %02d, PDOP %.2f, HDOP %.2f, VDOP %.2f, TDOP %.2f", 4823 mb(1), mb(2), mb(3), mb(4), 4824 getflt((unsigned char *)&mb(5)), 4825 getflt((unsigned char *)&mb(9)), 4826 getflt((unsigned char *)&mb(13)), 4827 getflt((unsigned char *)&mb(17))); 4828 4829 break; 4830 4831 case CMD_RVERSION: 4832 sprintf(t, "%d.%d (%d/%d/%d)", 4833 mb(0)&0xff, mb(1)&0xff, 1900+(mb(4)&0xff), mb(2)&0xff, mb(3)&0xff); 4834 break; 4835 4836 case CMD_RRECVHEALTH: 4837 { 4838 static const char *msgs[] = 4839 { 4840 "Battery backup failed", 4841 "Signal processor error", 4842 "Alignment error, channel or chip 1", 4843 "Alignment error, channel or chip 2", 4844 "Antenna feed line fault", 4845 "Excessive ref freq. error", 4846 "<BIT 6>", 4847 "<BIT 7>" 4848 }; 4849 4850 int i, bits; 4851 4852 switch (mb(0) & 0xFF) 4853 { 4854 default: 4855 sprintf(t, "illegal value 0x%02x", mb(0) & 0xFF); 4856 break; 4857 case 0x00: 4858 strcpy(t, "doing position fixes"); 4859 break; 4860 case 0x01: 4861 strcpy(t, "no GPS time yet"); 4862 break; 4863 case 0x03: 4864 strcpy(t, "PDOP too high"); 4865 break; 4866 case 0x08: 4867 strcpy(t, "no usable satellites"); 4868 break; 4869 case 0x09: 4870 strcpy(t, "only ONE usable satellite"); 4871 break; 4872 case 0x0A: 4873 strcpy(t, "only TWO usable satellites"); 4874 break; 4875 case 0x0B: 4876 strcpy(t, "only THREE usable satellites"); 4877 break; 4878 case 0x0C: 4879 strcpy(t, "the chosen satellite is unusable"); 4880 break; 4881 } 4882 4883 t += strlen(t); 4884 4885 bits = mb(1) & 0xFF; 4886 4887 for (i = 0; i < 8; i++) 4888 if (bits & (0x1<<i)) 4889 { 4890 sprintf(t, ", %s", msgs[i]); 4891 t += strlen(t); 4892 } 4893 } 4894 break; 4895 4896 case CMD_RMESSAGE: 4897 mkreadable(t, (int)(sizeof(pbuffer) - (t - pbuffer)), (char *)&mb(0), (unsigned)(size - 2 - (&mb(0) - buffer)), 0); 4898 break; 4899 4900 case CMD_RMACHSTAT: 4901 { 4902 static const char *msgs[] = 4903 { 4904 "Synthesizer Fault", 4905 "Battery Powered Time Clock Fault", 4906 "A-to-D Converter Fault", 4907 "The almanac stored in the receiver is not complete and current", 4908 "<BIT 4>", 4909 "<BIT 5", 4910 "<BIT 6>", 4911 "<BIT 7>" 4912 }; 4913 4914 int i, bits; 4915 4916 sprintf(t, "machine id 0x%02x", mb(0) & 0xFF); 4917 t += strlen(t); 4918 4919 bits = mb(1) & 0xFF; 4920 4921 for (i = 0; i < 8; i++) 4922 if (bits & (0x1<<i)) 4923 { 4924 sprintf(t, ", %s", msgs[i]); 4925 t += strlen(t); 4926 } 4927 4928 sprintf(t, ", Superpackets %ssupported", (mb(2) & 0xFF) ? "" :"un" ); 4929 } 4930 break; 4931 4932 case CMD_ROPERPARAM: 4933 sprintf(t, "%2x %.1f %.1f %.1f %.1f", 4934 mb(0), getflt((unsigned char *)&mb(1)), getflt((unsigned char *)&mb(5)), 4935 getflt((unsigned char *)&mb(9)), getflt((unsigned char *)&mb(13))); 4936 break; 4937 4938 case CMD_RUTCPARAM: 4939 { 4940 float t0t = getflt((unsigned char *)&mb(14)); 4941 short wnt = getshort((unsigned char *)&mb(18)); 4942 short dtls = getshort((unsigned char *)&mb(12)); 4943 short wnlsf = getshort((unsigned char *)&mb(20)); 4944 short dn = getshort((unsigned char *)&mb(22)); 4945 short dtlsf = getshort((unsigned char *)&mb(24)); 4946 4947 if ((int)t0t != 0) 4948 { 4949 mk_utcinfo(t, wnt, wnlsf, dn, dtls, dtlsf); 4950 } 4951 else 4952 { 4953 strcpy(t, "<NO UTC DATA>"); 4954 } 4955 } 4956 break; 4957 4958 case CMD_RSAT1BIAS: 4959 sprintf(t, "%.1fm %.2fm/s at %.1fs", 4960 getflt(&mb(0)), getflt(&mb(4)), getflt(&mb(8))); 4961 break; 4962 4963 case CMD_RIOOPTIONS: 4964 { 4965 sprintf(t, "%02x %02x %02x %02x", 4966 mb(0), mb(1), mb(2), mb(3)); 4967 if (mb(0) != TRIM_POS_OPT || 4968 mb(2) != TRIM_TIME_OPT) 4969 { 4970 (void)trimbletsip_setup(parse, "bad io options"); 4971 } 4972 } 4973 break; 4974 4975 case CMD_RSPOSXYZ: 4976 { 4977 double x = getflt((unsigned char *)&mb(0)); 4978 double y = getflt((unsigned char *)&mb(4)); 4979 double z = getflt((unsigned char *)&mb(8)); 4980 double f = getflt((unsigned char *)&mb(12)); 4981 4982 if (f > 0.0) 4983 sprintf(t, "x= %.1fm, y= %.1fm, z= %.1fm, time_of_fix= %f sec", 4984 x, y, z, 4985 f); 4986 else 4987 return; 4988 } 4989 break; 4990 4991 case CMD_RSLLAPOS: 4992 { 4993 double lat = getflt((unsigned char *)&mb(0)); 4994 double lng = getflt((unsigned char *)&mb(4)); 4995 double f = getflt((unsigned char *)&mb(12)); 4996 4997 if (f > 0.0) 4998 sprintf(t, "lat %f %c, long %f %c, alt %.2fm", 4999 ((lat < 0.0) ? (-lat) : (lat))*RTOD, (lat < 0.0 ? 'S' : 'N'), 5000 ((lng < 0.0) ? (-lng) : (lng))*RTOD, (lng < 0.0 ? 'W' : 'E'), 5001 getflt((unsigned char *)&mb(8))); 5002 else 5003 return; 5004 } 5005 break; 5006 5007 case CMD_RDOUBLEXYZ: 5008 { 5009 double x = getdbl((unsigned char *)&mb(0)); 5010 double y = getdbl((unsigned char *)&mb(8)); 5011 double z = getdbl((unsigned char *)&mb(16)); 5012 sprintf(t, "x= %.1fm, y= %.1fm, z= %.1fm", 5013 x, y, z); 5014 } 5015 break; 5016 5017 case CMD_RDOUBLELLA: 5018 { 5019 double lat = getdbl((unsigned char *)&mb(0)); 5020 double lng = getdbl((unsigned char *)&mb(8)); 5021 sprintf(t, "lat %f %c, lon %f %c, alt %.2fm", 5022 ((lat < 0.0) ? (-lat) : (lat))*RTOD, (lat < 0.0 ? 'S' : 'N'), 5023 ((lng < 0.0) ? (-lng) : (lng))*RTOD, (lng < 0.0 ? 'W' : 'E'), 5024 getdbl((unsigned char *)&mb(16))); 5025 } 5026 break; 5027 5028 case CMD_RALLINVIEW: 5029 { 5030 int i, sats; 5031 5032 strcpy(t, "mode: "); 5033 t += strlen(t); 5034 switch (mb(0) & 0x7) 5035 { 5036 default: 5037 sprintf(t, "0x%x", mb(0) & 0x7); 5038 break; 5039 5040 case 3: 5041 strcat(t, "2D"); 5042 break; 5043 5044 case 4: 5045 strcat(t, "3D"); 5046 break; 5047 } 5048 t += strlen(t); 5049 if (mb(0) & 0x8) 5050 strcpy(t, "-MANUAL, "); 5051 else 5052 strcpy(t, "-AUTO, "); 5053 t += strlen(t); 5054 5055 sats = (mb(0)>>4) & 0xF; 5056 5057 sprintf(t, "PDOP %.2f, HDOP %.2f, VDOP %.2f, TDOP %.2f, %d satellite%s in view: ", 5058 getflt((unsigned char *)&mb(1)), 5059 getflt((unsigned char *)&mb(5)), 5060 getflt((unsigned char *)&mb(9)), 5061 getflt((unsigned char *)&mb(13)), 5062 sats, (sats == 1) ? "" : "s"); 5063 t += strlen(t); 5064 5065 for (i=0; i < sats; i++) 5066 { 5067 sprintf(t, "%s%02d", i ? ", " : "", mb(17+i)); 5068 t += strlen(t); 5069 if (tr) 5070 tr->ctrack |= (1 << (mb(17+i)-1)); 5071 } 5072 5073 if (tr) 5074 { /* mark for tracking status query */ 5075 tr->qtracking = 1; 5076 } 5077 } 5078 break; 5079 5080 case CMD_RSTATTRACK: 5081 { 5082 sprintf(t-2, "[%02d]=\"", mb(0)); /* add index to var name */ 5083 t += strlen(t); 5084 5085 if (getflt((unsigned char *)&mb(4)) < 0.0) 5086 { 5087 strcpy(t, "<NO MEASUREMENTS>"); 5088 var_flag &= ~DEF; 5089 } 5090 else 5091 { 5092 sprintf(t, "ch=%d, acq=%s, eph=%d, signal_level= %5.2f, elevation= %5.2f, azimuth= %6.2f", 5093 (mb(1) & 0xFF)>>3, 5094 mb(2) ? ((mb(2) == 1) ? "ACQ" : "SRCH") : "NEVER", 5095 mb(3), 5096 getflt((unsigned char *)&mb(4)), 5097 getflt((unsigned char *)&mb(12)) * RTOD, 5098 getflt((unsigned char *)&mb(16)) * RTOD); 5099 t += strlen(t); 5100 if (mb(20)) 5101 { 5102 var_flag &= ~DEF; 5103 strcpy(t, ", OLD"); 5104 } 5105 t += strlen(t); 5106 if (mb(22)) 5107 { 5108 if (mb(22) == 1) 5109 strcpy(t, ", BAD PARITY"); 5110 else 5111 if (mb(22) == 2) 5112 strcpy(t, ", BAD EPH HEALTH"); 5113 } 5114 t += strlen(t); 5115 if (mb(23)) 5116 strcpy(t, ", collecting data"); 5117 } 5118 } 5119 break; 5120 5121 default: 5122 strcpy(t, "<UNDECODED>"); 5123 break; 5124 } 5125 strcat(t,"\""); 5126 set_var(&parse->kv, pbuffer, sizeof(pbuffer), var_flag); 5127 } 5128} 5129 5130 5131/**============================================================ 5132 ** RAWDCF support 5133 **/ 5134 5135/*-------------------------------------------------- 5136 * rawdcfdtr_init - set up modem lines for RAWDCF receivers 5137 */ 5138#if defined(TIOCMSET) && (defined(TIOCM_DTR) || defined(CIOCM_DTR)) 5139static int 5140rawdcfdtr_init( 5141 struct parseunit *parse 5142 ) 5143{ 5144 /* 5145 * You can use the RS232 to supply the power for a DCF77 receiver. 5146 * Here a voltage between the DTR and the RTS line is used. Unfortunately 5147 * the name has changed from CIOCM_DTR to TIOCM_DTR recently. 5148 */ 5149 5150#ifdef TIOCM_DTR 5151 int sl232 = TIOCM_DTR; /* turn on DTR for power supply */ 5152#else 5153 int sl232 = CIOCM_DTR; /* turn on DTR for power supply */ 5154#endif 5155 5156 if (ioctl(parse->generic->io.fd, TIOCMSET, (caddr_t)&sl232) == -1) 5157 { 5158 msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init: WARNING: ioctl(fd, TIOCMSET, [C|T]IOCM_DTR): %m", CLK_UNIT(parse->peer)); 5159 } 5160 return 0; 5161} 5162#else 5163static int 5164rawdcfdtr_init( 5165 struct parseunit *parse 5166 ) 5167{ 5168 msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init: WARNING: OS interface incapable of setting DTR to power DCF modules", CLK_UNIT(parse->peer)); 5169 return 0; 5170} 5171#endif /* DTR initialisation type */ 5172 5173/*-------------------------------------------------- 5174 * rawdcfrts_init - set up modem lines for RAWDCF receivers 5175 */ 5176#if defined(TIOCMSET) && (defined(TIOCM_RTS) || defined(CIOCM_RTS)) 5177static int 5178rawdcfrts_init( 5179 struct parseunit *parse 5180 ) 5181{ 5182 /* 5183 * You can use the RS232 to supply the power for a DCF77 receiver. 5184 * Here a voltage between the RTS and the DTR line is used. 5185 */ 5186 5187#ifdef TIOCM_RTS 5188 int sl232 = TIOCM_RTS; /* turn on RTS for power supply */ 5189#else 5190 int sl232 = CIOCM_RTS; /* turn on RTS for power supply */ 5191#endif 5192 5193 if (ioctl(parse->generic->io.fd, TIOCMSET, (caddr_t)&sl232) == -1) 5194 { 5195 msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init: WARNING: ioctl(fd, TIOCMSET, [C|T]IOCM_RTS): %m", CLK_UNIT(parse->peer)); 5196 } 5197 return 0; 5198} 5199#else 5200static int 5201rawdcfrts_init( 5202 struct parseunit *parse 5203 ) 5204{ 5205 msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init: WARNING: OS interface incapable of setting RTS to power DCF modules", CLK_UNIT(parse->peer)); 5206 return 0; 5207} 5208#endif /* RTS initialisation type */ 5209 5210#else /* defined(REFCLOCK) && defined(PARSE) */ 5211int refclock_parse_bs; 5212#endif /* defined(REFCLOCK) && defined(PARSE) */ 5213 5214/* 5215 * History: 5216 * 5217 * refclock_parse.c,v 5218 * Revision 4.29 1999/02/28 19:58:23 kardel 5219 * updated copyright information 5220 * 5221 * Revision 4.28 1999/02/28 19:01:50 kardel 5222 * improved debug out on sent Meinberg messages 5223 * 5224 * Revision 4.27 1999/02/28 18:05:55 kardel 5225 * no linux/ppsclock.h stuff 5226 * 5227 * Revision 4.26 1999/02/28 15:27:27 kardel 5228 * wharton clock integration 5229 * 5230 * Revision 4.25 1999/02/28 14:04:46 kardel 5231 * added missing double quotes to UTC information string 5232 * 5233 * Revision 4.24 1999/02/28 12:06:50 kardel 5234 * (parse_control): using gmprettydate instead of prettydate() 5235 * (mk_utcinfo): new function for formatting GPS derived UTC information 5236 * (gps16x_message): changed to use mk_utcinfo() 5237 * (trimbletsip_message): changed to use mk_utcinfo() 5238 * ignoring position information in unsynchronized mode 5239 * (parse_start): augument linux support for optional ASYNC_LOW_LATENCY 5240 * 5241 * Revision 4.23 1999/02/23 19:47:53 kardel 5242 * fixed #endifs 5243 * (stream_receive): fixed formats 5244 * 5245 * Revision 4.22 1999/02/22 06:21:02 kardel 5246 * use new autoconfig symbols 5247 * 5248 * Revision 4.21 1999/02/21 12:18:13 kardel 5249 * 4.91f reconcilation 5250 * 5251 * Revision 4.20 1999/02/21 10:53:36 kardel 5252 * initial Linux PPSkit version 5253 * 5254 * Revision 4.19 1999/02/07 09:10:45 kardel 5255 * clarify STREAMS mitigation rules in comment 5256 * 5257 * Revision 4.18 1998/12/20 23:45:34 kardel 5258 * fix types and warnings 5259 * 5260 * Revision 4.17 1998/11/15 21:24:51 kardel 5261 * cannot access mbg_ routines when CLOCK_MEINBERG 5262 * is not defined 5263 * 5264 * Revision 4.16 1998/11/15 20:28:17 kardel 5265 * Release 4.0.73e13 reconcilation 5266 * 5267 * Revision 4.15 1998/08/22 21:56:08 kardel 5268 * fixed IO handling for non-STREAM IO 5269 * 5270 * Revision 4.14 1998/08/16 19:00:48 kardel 5271 * (gps16x_message): reduced UTC parameter information (dropped A0,A1) 5272 * made uval a local variable (killed one of the last globals) 5273 * (sendetx): added logging of messages when in debug mode 5274 * (trimble_check): added periodic checks to facilitate re-initialization 5275 * (trimbletsip_init): made use of EOL character if in non-kernel operation 5276 * (trimbletsip_message): extended message interpretation 5277 * (getdbl): fixed data conversion 5278 * 5279 * Revision 4.13 1998/08/09 22:29:13 kardel 5280 * Trimble TSIP support 5281 * 5282 * Revision 4.12 1998/07/11 10:05:34 kardel 5283 * Release 4.0.73d reconcilation 5284 * 5285 * Revision 4.11 1998/06/14 21:09:42 kardel 5286 * Sun acc cleanup 5287 * 5288 * Revision 4.10 1998/06/13 12:36:45 kardel 5289 * signed/unsigned, name clashes 5290 * 5291 * Revision 4.9 1998/06/12 15:30:00 kardel 5292 * prototype fixes 5293 * 5294 * Revision 4.8 1998/06/12 11:19:42 kardel 5295 * added direct input processing routine for refclocks in 5296 * order to avaiod that single character io gobbles up all 5297 * receive buffers and drops input data. (Problem started 5298 * with fast machines so a character a buffer was possible 5299 * one of the few cases where faster machines break existing 5300 * allocation algorithms) 5301 * 5302 * Revision 4.7 1998/06/06 18:35:20 kardel 5303 * (parse_start): added BURST mode initialisation 5304 * 5305 * Revision 4.6 1998/05/27 06:12:46 kardel 5306 * RAWDCF_BASEDELAY default added 5307 * old comment removed 5308 * casts for ioctl() 5309 * 5310 * Revision 4.5 1998/05/25 22:05:09 kardel 5311 * RAWDCF_SETDTR option removed 5312 * clock type 14 attempts to set DTR for 5313 * power supply of RAWDCF receivers 5314 * 5315 * Revision 4.4 1998/05/24 16:20:47 kardel 5316 * updated comments referencing Meinberg clocks 5317 * added RAWDCF clock with DTR set option as type 14 5318 * 5319 * Revision 4.3 1998/05/24 10:48:33 kardel 5320 * calibrated CONRAD RAWDCF default fudge factor 5321 * 5322 * Revision 4.2 1998/05/24 09:59:35 kardel 5323 * corrected version information (ntpq support) 5324 * 5325 * Revision 4.1 1998/05/24 09:52:31 kardel 5326 * use fixed format only (new IO model) 5327 * output debug to stdout instead of msyslog() 5328 * don't include >"< in ASCII output in order not to confuse 5329 * ntpq parsing 5330 * 5331 * Revision 4.0 1998/04/10 19:52:11 kardel 5332 * Start 4.0 release version numbering 5333 * 5334 * Revision 1.2 1998/04/10 19:28:04 kardel 5335 * initial NTP VERSION 4 integration of PARSE with GPS166 binary support 5336 * derived from 3.105.1.2 from V3 tree 5337 * 5338 * Revision information 3.1 - 3.105 from log deleted 1998/04/10 kardel 5339 * 5340 */ 5341