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