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