1 /* 2 * /src/NTP/REPOSITORY/ntp4-dev/ntpd/refclock_parse.c,v 4.80 2007/08/11 12:06:29 kardel Exp 3 * 4 * refclock_parse.c,v 4.80 2007/08/11 12:06:29 kardel Exp 5 * 6 * generic reference clock driver for several DCF/GPS/MSF/... receivers 7 * 8 * PPS notes: 9 * On systems that support PPSAPI (RFC2783) PPSAPI is the 10 * preferred interface. 11 * 12 * Optionally make use of a STREAMS module for input processing where 13 * available and configured. This STREAMS module reduces the time 14 * stamp latency for serial and PPS events. 15 * Currently the STREAMS module is only available for Suns running 16 * SunOS 4.x and SunOS5.x. 17 * 18 * Copyright (c) 1995-2007 by Frank Kardel <kardel <AT> ntp.org> 19 * Copyright (c) 1989-1994 by Frank Kardel, Friedrich-Alexander Universit�t Erlangen-N�rnberg, Germany 20 * 21 * Redistribution and use in source and binary forms, with or without 22 * modification, are permitted provided that the following conditions 23 * are met: 24 * 1. Redistributions of source code must retain the above copyright 25 * notice, this list of conditions and the following disclaimer. 26 * 2. Redistributions in binary form must reproduce the above copyright 27 * notice, this list of conditions and the following disclaimer in the 28 * documentation and/or other materials provided with the distribution. 29 * 3. Neither the name of the author nor the names of its contributors 30 * may be used to endorse or promote products derived from this software 31 * without specific prior written permission. 32 * 33 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 34 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 35 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 36 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 37 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 38 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 39 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 40 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 41 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 42 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 43 * SUCH DAMAGE. 44 * 45 */ 46 47 #ifdef HAVE_CONFIG_H 48 # include "config.h" 49 #endif 50 51 #if defined(REFCLOCK) && defined(CLOCK_PARSE) 52 53 /* 54 * This driver currently provides the support for 55 * - Meinberg receiver DCF77 PZF 535 (TCXO version) (DCF) 56 * - Meinberg receiver DCF77 PZF 535 (OCXO version) (DCF) 57 * - Meinberg receiver DCF77 PZF 509 (DCF) 58 * - Meinberg receiver DCF77 AM receivers (e.g. C51) (DCF) 59 * - IGEL CLOCK (DCF) 60 * - ELV DCF7000 (DCF) 61 * - Schmid clock (DCF) 62 * - Conrad DCF77 receiver module (DCF) 63 * - FAU DCF77 NTP receiver (TimeBrick) (DCF) 64 * - WHARTON 400A Series clock (DCF) 65 * 66 * - Meinberg GPS166/GPS167 (GPS) 67 * - Trimble (TSIP and TAIP protocol) (GPS) 68 * 69 * - RCC8000 MSF Receiver (MSF) 70 * - VARITEXT clock (MSF) 71 */ 72 73 /* 74 * Meinberg receivers are usually connected via a 75 * 9600 baud serial line 76 * 77 * The Meinberg GPS receivers also have a special NTP time stamp 78 * format. The firmware release is Uni-Erlangen. 79 * 80 * Meinberg generic receiver setup: 81 * output time code every second 82 * Baud rate 9600 7E2S 83 * 84 * Meinberg GPS16x setup: 85 * output time code every second 86 * Baudrate 19200 8N1 87 * 88 * This software supports the standard data formats used 89 * in Meinberg receivers. 90 * 91 * Special software versions are only sensible for the 92 * GPS 16x family of receivers. 93 * 94 * Meinberg can be reached via: http://www.meinberg.de/ 95 */ 96 97 #include "ntpd.h" 98 #include "ntp_refclock.h" 99 #include "ntp_unixtime.h" /* includes <sys/time.h> */ 100 #include "ntp_control.h" 101 #include "ntp_string.h" 102 103 #include <stdio.h> 104 #include <ctype.h> 105 #ifndef TM_IN_SYS_TIME 106 # include <time.h> 107 #endif 108 109 #ifdef HAVE_UNISTD_H 110 # include <unistd.h> 111 #endif 112 113 #if !defined(STREAM) && !defined(HAVE_SYSV_TTYS) && !defined(HAVE_BSD_TTYS) && !defined(HAVE_TERMIOS) 114 # include "Bletch: Define one of {STREAM,HAVE_SYSV_TTYS,HAVE_TERMIOS}" 115 #endif 116 117 #ifdef STREAM 118 # include <sys/stream.h> 119 # include <sys/stropts.h> 120 #endif 121 122 #ifdef HAVE_TERMIOS 123 # define TTY_GETATTR(_FD_, _ARG_) tcgetattr((_FD_), (_ARG_)) 124 # define TTY_SETATTR(_FD_, _ARG_) tcsetattr((_FD_), TCSANOW, (_ARG_)) 125 # undef HAVE_SYSV_TTYS 126 #endif 127 128 #ifdef HAVE_SYSV_TTYS 129 # define TTY_GETATTR(_FD_, _ARG_) ioctl((_FD_), TCGETA, (_ARG_)) 130 # define TTY_SETATTR(_FD_, _ARG_) ioctl((_FD_), TCSETAW, (_ARG_)) 131 #endif 132 133 #ifdef HAVE_BSD_TTYS 134 /* #error CURRENTLY NO BSD TTY SUPPORT */ 135 # include "Bletch: BSD TTY not currently supported" 136 #endif 137 138 #ifdef HAVE_SYS_IOCTL_H 139 # include <sys/ioctl.h> 140 #endif 141 142 #ifdef HAVE_PPSAPI 143 # include "ppsapi_timepps.h" 144 #endif 145 146 #ifdef PPS 147 # ifdef HAVE_SYS_PPSCLOCK_H 148 # include <sys/ppsclock.h> 149 # endif 150 # ifdef HAVE_TIO_SERIAL_STUFF 151 # include <linux/serial.h> 152 # endif 153 #endif 154 155 #define BUFFER_SIZE(_BUF, _PTR) ((_BUF) + sizeof(_BUF) - (_PTR)) 156 #define BUFFER_SIZES(_BUF, _PTR, _SZ) ((_BUF) + (_SZ) - (_PTR)) 157 158 /* 159 * document type of PPS interfacing - copy of ifdef mechanism in local_input() 160 */ 161 #undef PPS_METHOD 162 163 #ifdef HAVE_PPSAPI 164 #define PPS_METHOD "PPS API" 165 #else 166 #ifdef TIOCDCDTIMESTAMP 167 #define PPS_METHOD "TIOCDCDTIMESTAMP" 168 #else /* TIOCDCDTIMESTAMP */ 169 #if defined(HAVE_STRUCT_PPSCLOCKEV) && (defined(HAVE_CIOGETEV) || defined(HAVE_TIOCGPPSEV)) 170 #ifdef HAVE_CIOGETEV 171 #define PPS_METHOD "CIOGETEV" 172 #endif 173 #ifdef HAVE_TIOCGPPSEV 174 #define PPS_METHOD "TIOCGPPSEV" 175 #endif 176 #endif 177 #endif /* TIOCDCDTIMESTAMP */ 178 #endif /* HAVE_PPSAPI */ 179 180 #include "ntp_io.h" 181 #include "ntp_stdlib.h" 182 183 #include "parse.h" 184 #include "mbg_gps166.h" 185 #include "trimble.h" 186 #include "binio.h" 187 #include "ascii.h" 188 #include "ieee754io.h" 189 #include "recvbuff.h" 190 191 static char rcsid[] = "refclock_parse.c,v 4.80 2007/08/11 12:06:29 kardel Exp"; 192 193 /**=========================================================================== 194 ** external interface to ntp mechanism 195 **/ 196 197 static int parse_start P((int, struct peer *)); 198 static void parse_shutdown P((int, struct peer *)); 199 static void parse_poll P((int, struct peer *)); 200 static void parse_control P((int, struct refclockstat *, struct refclockstat *, struct peer *)); 201 202 struct refclock refclock_parse = { 203 parse_start, 204 parse_shutdown, 205 parse_poll, 206 parse_control, 207 noentry, 208 noentry, 209 NOFLAGS 210 }; 211 212 /* 213 * Definitions 214 */ 215 #define MAXUNITS 4 /* maximum number of "PARSE" units permitted */ 216 #define PARSEDEVICE "/dev/refclock-%d" /* device to open %d is unit number */ 217 #define PARSEPPSDEVICE "/dev/refclockpps-%d" /* optional pps device to open %d is unit number */ 218 219 #undef ABS 220 #define ABS(_X_) (((_X_) < 0) ? -(_X_) : (_X_)) 221 222 #define PARSE_HARDPPS_DISABLE 0 223 #define PARSE_HARDPPS_ENABLE 1 224 225 /**=========================================================================== 226 ** function vector for dynamically binding io handling mechanism 227 **/ 228 229 struct parseunit; /* to keep inquiring minds happy */ 230 231 typedef struct bind 232 { 233 const char *bd_description; /* name of type of binding */ 234 int (*bd_init) P((struct parseunit *)); /* initialize */ 235 void (*bd_end) P((struct parseunit *)); /* end */ 236 int (*bd_setcs) P((struct parseunit *, parsectl_t *)); /* set character size */ 237 int (*bd_disable) P((struct parseunit *)); /* disable */ 238 int (*bd_enable) P((struct parseunit *)); /* enable */ 239 int (*bd_getfmt) P((struct parseunit *, parsectl_t *)); /* get format */ 240 int (*bd_setfmt) P((struct parseunit *, parsectl_t *)); /* setfmt */ 241 int (*bd_timecode) P((struct parseunit *, parsectl_t *)); /* get time code */ 242 void (*bd_receive) P((struct recvbuf *)); /* receive operation */ 243 int (*bd_io_input) P((struct recvbuf *)); /* input operation */ 244 } bind_t; 245 246 #define PARSE_END(_X_) (*(_X_)->binding->bd_end)(_X_) 247 #define PARSE_SETCS(_X_, _CS_) (*(_X_)->binding->bd_setcs)(_X_, _CS_) 248 #define PARSE_ENABLE(_X_) (*(_X_)->binding->bd_enable)(_X_) 249 #define PARSE_DISABLE(_X_) (*(_X_)->binding->bd_disable)(_X_) 250 #define PARSE_GETFMT(_X_, _DCT_) (*(_X_)->binding->bd_getfmt)(_X_, _DCT_) 251 #define PARSE_SETFMT(_X_, _DCT_) (*(_X_)->binding->bd_setfmt)(_X_, _DCT_) 252 #define PARSE_GETTIMECODE(_X_, _DCT_) (*(_X_)->binding->bd_timecode)(_X_, _DCT_) 253 254 /* 255 * io modes 256 */ 257 #define PARSE_F_PPSPPS 0x0001 /* use loopfilter PPS code (CIOGETEV) */ 258 #define PARSE_F_PPSONSECOND 0x0002 /* PPS pulses are on second */ 259 260 261 /**=========================================================================== 262 ** error message regression handling 263 ** 264 ** there are quite a few errors that can occur in rapid succession such as 265 ** noisy input data or no data at all. in order to reduce the amount of 266 ** syslog messages in such case, we are using a backoff algorithm. We limit 267 ** the number of error messages of a certain class to 1 per time unit. if a 268 ** configurable number of messages is displayed that way, we move on to the 269 ** next time unit / count for that class. a count of messages that have been 270 ** suppressed is held and displayed whenever a corresponding message is 271 ** displayed. the time units for a message class will also be displayed. 272 ** whenever an error condition clears we reset the error message state, 273 ** thus we would still generate much output on pathological conditions 274 ** where the system oscillates between OK and NOT OK states. coping 275 ** with that condition is currently considered too complicated. 276 **/ 277 278 #define ERR_ALL (unsigned)~0 /* "all" errors */ 279 #define ERR_BADDATA (unsigned)0 /* unusable input data/conversion errors */ 280 #define ERR_NODATA (unsigned)1 /* no input data */ 281 #define ERR_BADIO (unsigned)2 /* read/write/select errors */ 282 #define ERR_BADSTATUS (unsigned)3 /* unsync states */ 283 #define ERR_BADEVENT (unsigned)4 /* non nominal events */ 284 #define ERR_INTERNAL (unsigned)5 /* internal error */ 285 #define ERR_CNT (unsigned)(ERR_INTERNAL+1) 286 287 #define ERR(_X_) if (list_err(parse, (_X_))) 288 289 struct errorregression 290 { 291 u_long err_count; /* number of repititions per class */ 292 u_long err_delay; /* minimum delay between messages */ 293 }; 294 295 static struct errorregression 296 err_baddata[] = /* error messages for bad input data */ 297 { 298 { 1, 0 }, /* output first message immediately */ 299 { 5, 60 }, /* output next five messages in 60 second intervals */ 300 { 3, 3600 }, /* output next 3 messages in hour intervals */ 301 { 0, 12*3600 } /* repeat messages only every 12 hours */ 302 }; 303 304 static struct errorregression 305 err_nodata[] = /* error messages for missing input data */ 306 { 307 { 1, 0 }, /* output first message immediately */ 308 { 5, 60 }, /* output next five messages in 60 second intervals */ 309 { 3, 3600 }, /* output next 3 messages in hour intervals */ 310 { 0, 12*3600 } /* repeat messages only every 12 hours */ 311 }; 312 313 static struct errorregression 314 err_badstatus[] = /* unsynchronized state messages */ 315 { 316 { 1, 0 }, /* output first message immediately */ 317 { 5, 60 }, /* output next five messages in 60 second intervals */ 318 { 3, 3600 }, /* output next 3 messages in hour intervals */ 319 { 0, 12*3600 } /* repeat messages only every 12 hours */ 320 }; 321 322 static struct errorregression 323 err_badio[] = /* io failures (bad reads, selects, ...) */ 324 { 325 { 1, 0 }, /* output first message immediately */ 326 { 5, 60 }, /* output next five messages in 60 second intervals */ 327 { 5, 3600 }, /* output next 3 messages in hour intervals */ 328 { 0, 12*3600 } /* repeat messages only every 12 hours */ 329 }; 330 331 static struct errorregression 332 err_badevent[] = /* non nominal events */ 333 { 334 { 20, 0 }, /* output first message immediately */ 335 { 6, 60 }, /* output next five messages in 60 second intervals */ 336 { 5, 3600 }, /* output next 3 messages in hour intervals */ 337 { 0, 12*3600 } /* repeat messages only every 12 hours */ 338 }; 339 340 static struct errorregression 341 err_internal[] = /* really bad things - basically coding/OS errors */ 342 { 343 { 0, 0 }, /* output all messages immediately */ 344 }; 345 346 static struct errorregression * 347 err_tbl[] = 348 { 349 err_baddata, 350 err_nodata, 351 err_badio, 352 err_badstatus, 353 err_badevent, 354 err_internal 355 }; 356 357 struct errorinfo 358 { 359 u_long err_started; /* begin time (ntp) of error condition */ 360 u_long err_last; /* last time (ntp) error occurred */ 361 u_long err_cnt; /* number of error repititions */ 362 u_long err_suppressed; /* number of suppressed messages */ 363 struct errorregression *err_stage; /* current error stage */ 364 }; 365 366 /**=========================================================================== 367 ** refclock instance data 368 **/ 369 370 struct parseunit 371 { 372 /* 373 * NTP management 374 */ 375 struct peer *peer; /* backlink to peer structure - refclock inactive if 0 */ 376 struct refclockproc *generic; /* backlink to refclockproc structure */ 377 378 /* 379 * PARSE io 380 */ 381 bind_t *binding; /* io handling binding */ 382 383 /* 384 * parse state 385 */ 386 parse_t parseio; /* io handling structure (user level parsing) */ 387 388 /* 389 * type specific parameters 390 */ 391 struct parse_clockinfo *parse_type; /* link to clock description */ 392 393 /* 394 * clock state handling/reporting 395 */ 396 u_char flags; /* flags (leap_control) */ 397 u_long lastchange; /* time (ntp) when last state change accured */ 398 u_long statetime[CEVNT_MAX+1]; /* accumulated time of clock states */ 399 u_long pollneeddata; /* current_time(!=0) for receive sample expected in PPS mode */ 400 u_short lastformat; /* last format used */ 401 u_long lastsync; /* time (ntp) when clock was last seen fully synchronized */ 402 u_long maxunsync; /* max time in seconds a receiver is trusted after loosing synchronisation */ 403 double ppsphaseadjust; /* phase adjustment of PPS time stamp */ 404 u_long lastmissed; /* time (ntp) when poll didn't get data (powerup heuristic) */ 405 u_long ppsserial; /* magic cookie for ppsclock serials (avoids stale ppsclock data) */ 406 int ppsfd; /* fd to ise for PPS io */ 407 #ifdef HAVE_PPSAPI 408 pps_handle_t ppshandle; /* store PPSAPI handle */ 409 pps_params_t ppsparams; /* current PPS parameters */ 410 int hardppsstate; /* current hard pps state */ 411 #endif 412 parsetime_t timedata; /* last (parse module) data */ 413 void *localdata; /* optional local, receiver-specific data */ 414 unsigned long localstate; /* private local state */ 415 struct errorinfo errors[ERR_CNT]; /* error state table for suppressing excessive error messages */ 416 struct ctl_var *kv; /* additional pseudo variables */ 417 u_long laststatistic; /* time when staticstics where output */ 418 }; 419 420 421 /**=========================================================================== 422 ** Clockinfo section all parameter for specific clock types 423 ** includes NTP parameters, TTY parameters and IO handling parameters 424 **/ 425 426 static void poll_dpoll P((struct parseunit *)); 427 static void poll_poll P((struct peer *)); 428 static int poll_init P((struct parseunit *)); 429 430 typedef struct poll_info 431 { 432 u_long rate; /* poll rate - once every "rate" seconds - 0 off */ 433 const char *string; /* string to send for polling */ 434 u_long count; /* number of characters in string */ 435 } poll_info_t; 436 437 #define NO_CL_FLAGS 0 438 #define NO_POLL 0 439 #define NO_INIT 0 440 #define NO_END 0 441 #define NO_EVENT 0 442 #define NO_LCLDATA 0 443 #define NO_MESSAGE 0 444 #define NO_PPSDELAY 0 445 446 #define DCF_ID "DCF" /* generic DCF */ 447 #define DCF_A_ID "DCFa" /* AM demodulation */ 448 #define DCF_P_ID "DCFp" /* psuedo random phase shift */ 449 #define GPS_ID "GPS" /* GPS receiver */ 450 451 #define NOCLOCK_ROOTDELAY 0.0 452 #define NOCLOCK_BASEDELAY 0.0 453 #define NOCLOCK_DESCRIPTION 0 454 #define NOCLOCK_MAXUNSYNC 0 455 #define NOCLOCK_CFLAG 0 456 #define NOCLOCK_IFLAG 0 457 #define NOCLOCK_OFLAG 0 458 #define NOCLOCK_LFLAG 0 459 #define NOCLOCK_ID "TILT" 460 #define NOCLOCK_POLL NO_POLL 461 #define NOCLOCK_INIT NO_INIT 462 #define NOCLOCK_END NO_END 463 #define NOCLOCK_DATA NO_LCLDATA 464 #define NOCLOCK_FORMAT "" 465 #define NOCLOCK_TYPE CTL_SST_TS_UNSPEC 466 #define NOCLOCK_SAMPLES 0 467 #define NOCLOCK_KEEP 0 468 469 #define DCF_TYPE CTL_SST_TS_LF 470 #define GPS_TYPE CTL_SST_TS_UHF 471 472 /* 473 * receiver specific constants 474 */ 475 #define MBG_SPEED (B9600) 476 #define MBG_CFLAG (CS7|PARENB|CREAD|CLOCAL|HUPCL|CSTOPB) 477 #define MBG_IFLAG (IGNBRK|IGNPAR|ISTRIP) 478 #define MBG_OFLAG 0 479 #define MBG_LFLAG 0 480 #define MBG_FLAGS PARSE_F_PPSONSECOND 481 482 /* 483 * Meinberg DCF77 receivers 484 */ 485 #define DCFUA31_ROOTDELAY 0.0 /* 0 */ 486 #define DCFUA31_BASEDELAY 0.010 /* 10.7421875ms: 10 ms (+/- 3 ms) */ 487 #define DCFUA31_DESCRIPTION "Meinberg DCF77 C51 or compatible" 488 #define DCFUA31_MAXUNSYNC 60*30 /* only trust clock for 1/2 hour */ 489 #define DCFUA31_SPEED MBG_SPEED 490 #define DCFUA31_CFLAG MBG_CFLAG 491 #define DCFUA31_IFLAG MBG_IFLAG 492 #define DCFUA31_OFLAG MBG_OFLAG 493 #define DCFUA31_LFLAG MBG_LFLAG 494 #define DCFUA31_SAMPLES 5 495 #define DCFUA31_KEEP 3 496 #define DCFUA31_FORMAT "Meinberg Standard" 497 498 /* 499 * Meinberg DCF PZF535/TCXO (FM/PZF) receiver 500 */ 501 #define DCFPZF535_ROOTDELAY 0.0 502 #define DCFPZF535_BASEDELAY 0.001968 /* 1.968ms +- 104us (oscilloscope) - relative to start (end of STX) */ 503 #define DCFPZF535_DESCRIPTION "Meinberg DCF PZF 535/509 / TCXO" 504 #define DCFPZF535_MAXUNSYNC 60*60*12 /* only trust clock for 12 hours 505 * @ 5e-8df/f we have accumulated 506 * at most 2.16 ms (thus we move to 507 * NTP synchronisation */ 508 #define DCFPZF535_SPEED MBG_SPEED 509 #define DCFPZF535_CFLAG MBG_CFLAG 510 #define DCFPZF535_IFLAG MBG_IFLAG 511 #define DCFPZF535_OFLAG MBG_OFLAG 512 #define DCFPZF535_LFLAG MBG_LFLAG 513 #define DCFPZF535_SAMPLES 5 514 #define DCFPZF535_KEEP 3 515 #define DCFPZF535_FORMAT "Meinberg Standard" 516 517 /* 518 * Meinberg DCF PZF535/OCXO receiver 519 */ 520 #define DCFPZF535OCXO_ROOTDELAY 0.0 521 #define DCFPZF535OCXO_BASEDELAY 0.001968 /* 1.968ms +- 104us (oscilloscope) - relative to start (end of STX) */ 522 #define DCFPZF535OCXO_DESCRIPTION "Meinberg DCF PZF 535/509 / OCXO" 523 #define DCFPZF535OCXO_MAXUNSYNC 60*60*96 /* only trust clock for 4 days 524 * @ 5e-9df/f we have accumulated 525 * at most an error of 1.73 ms 526 * (thus we move to NTP synchronisation) */ 527 #define DCFPZF535OCXO_SPEED MBG_SPEED 528 #define DCFPZF535OCXO_CFLAG MBG_CFLAG 529 #define DCFPZF535OCXO_IFLAG MBG_IFLAG 530 #define DCFPZF535OCXO_OFLAG MBG_OFLAG 531 #define DCFPZF535OCXO_LFLAG MBG_LFLAG 532 #define DCFPZF535OCXO_SAMPLES 5 533 #define DCFPZF535OCXO_KEEP 3 534 #define DCFPZF535OCXO_FORMAT "Meinberg Standard" 535 536 /* 537 * Meinberg GPS16X receiver 538 */ 539 static void gps16x_message P((struct parseunit *, parsetime_t *)); 540 static int gps16x_poll_init P((struct parseunit *)); 541 542 #define GPS16X_ROOTDELAY 0.0 /* nothing here */ 543 #define GPS16X_BASEDELAY 0.001968 /* XXX to be fixed ! 1.968ms +- 104us (oscilloscope) - relative to start (end of STX) */ 544 #define GPS16X_DESCRIPTION "Meinberg GPS16x receiver" 545 #define GPS16X_MAXUNSYNC 60*60*96 /* only trust clock for 4 days 546 * @ 5e-9df/f we have accumulated 547 * at most an error of 1.73 ms 548 * (thus we move to NTP synchronisation) */ 549 #define GPS16X_SPEED B19200 550 #define GPS16X_CFLAG (CS8|CREAD|CLOCAL|HUPCL) 551 #define GPS16X_IFLAG (IGNBRK|IGNPAR) 552 #define GPS16X_OFLAG MBG_OFLAG 553 #define GPS16X_LFLAG MBG_LFLAG 554 #define GPS16X_POLLRATE 6 555 #define GPS16X_POLLCMD "" 556 #define GPS16X_CMDSIZE 0 557 558 static poll_info_t gps16x_pollinfo = { GPS16X_POLLRATE, GPS16X_POLLCMD, GPS16X_CMDSIZE }; 559 560 #define GPS16X_INIT gps16x_poll_init 561 #define GPS16X_POLL 0 562 #define GPS16X_END 0 563 #define GPS16X_DATA ((void *)(&gps16x_pollinfo)) 564 #define GPS16X_MESSAGE gps16x_message 565 #define GPS16X_ID GPS_ID 566 #define GPS16X_FORMAT "Meinberg GPS Extended" 567 #define GPS16X_SAMPLES 5 568 #define GPS16X_KEEP 3 569 570 /* 571 * ELV DCF7000 Wallclock-Receiver/Switching Clock (Kit) 572 * 573 * This is really not the hottest clock - but before you have nothing ... 574 */ 575 #define DCF7000_ROOTDELAY 0.0 /* 0 */ 576 #define DCF7000_BASEDELAY 0.405 /* slow blow */ 577 #define DCF7000_DESCRIPTION "ELV DCF7000" 578 #define DCF7000_MAXUNSYNC (60*5) /* sorry - but it just was not build as a clock */ 579 #define DCF7000_SPEED (B9600) 580 #define DCF7000_CFLAG (CS8|CREAD|PARENB|PARODD|CLOCAL|HUPCL) 581 #define DCF7000_IFLAG (IGNBRK) 582 #define DCF7000_OFLAG 0 583 #define DCF7000_LFLAG 0 584 #define DCF7000_SAMPLES 5 585 #define DCF7000_KEEP 3 586 #define DCF7000_FORMAT "ELV DCF7000" 587 588 /* 589 * Schmid DCF Receiver Kit 590 * 591 * When the WSDCF clock is operating optimally we want the primary clock 592 * distance to come out at 300 ms. Thus, peer.distance in the WSDCF peer 593 * structure is set to 290 ms and we compute delays which are at least 594 * 10 ms long. The following are 290 ms and 10 ms expressed in u_fp format 595 */ 596 #define WS_POLLRATE 1 /* every second - watch interdependency with poll routine */ 597 #define WS_POLLCMD "\163" 598 #define WS_CMDSIZE 1 599 600 static poll_info_t wsdcf_pollinfo = { WS_POLLRATE, WS_POLLCMD, WS_CMDSIZE }; 601 602 #define WSDCF_INIT poll_init 603 #define WSDCF_POLL poll_dpoll 604 #define WSDCF_END 0 605 #define WSDCF_DATA ((void *)(&wsdcf_pollinfo)) 606 #define WSDCF_ROOTDELAY 0.0 /* 0 */ 607 #define WSDCF_BASEDELAY 0.010 /* ~ 10ms */ 608 #define WSDCF_DESCRIPTION "WS/DCF Receiver" 609 #define WSDCF_FORMAT "Schmid" 610 #define WSDCF_MAXUNSYNC (60*60) /* assume this beast hold at 1 h better than 2 ms XXX-must verify */ 611 #define WSDCF_SPEED (B1200) 612 #define WSDCF_CFLAG (CS8|CREAD|CLOCAL) 613 #define WSDCF_IFLAG 0 614 #define WSDCF_OFLAG 0 615 #define WSDCF_LFLAG 0 616 #define WSDCF_SAMPLES 5 617 #define WSDCF_KEEP 3 618 619 /* 620 * RAW DCF77 - input of DCF marks via RS232 - many variants 621 */ 622 #define RAWDCF_FLAGS 0 623 #define RAWDCF_ROOTDELAY 0.0 /* 0 */ 624 #define RAWDCF_BASEDELAY 0.258 625 #define RAWDCF_FORMAT "RAW DCF77 Timecode" 626 #define RAWDCF_MAXUNSYNC (0) /* sorry - its a true receiver - no signal - no time */ 627 #define RAWDCF_SPEED (B50) 628 #ifdef NO_PARENB_IGNPAR /* Was: defined(SYS_IRIX4) || defined(SYS_IRIX5) */ 629 /* somehow doesn't grok PARENB & IGNPAR (mj) */ 630 # define RAWDCF_CFLAG (CS8|CREAD|CLOCAL) 631 #else 632 # define RAWDCF_CFLAG (CS8|CREAD|CLOCAL|PARENB) 633 #endif 634 #ifdef RAWDCF_NO_IGNPAR /* Was: defined(SYS_LINUX) && defined(CLOCK_RAWDCF) */ 635 # define RAWDCF_IFLAG 0 636 #else 637 # define RAWDCF_IFLAG (IGNPAR) 638 #endif 639 #define RAWDCF_OFLAG 0 640 #define RAWDCF_LFLAG 0 641 #define RAWDCF_SAMPLES 20 642 #define RAWDCF_KEEP 12 643 #define RAWDCF_INIT 0 644 645 /* 646 * RAW DCF variants 647 */ 648 /* 649 * Conrad receiver 650 * 651 * simplest (cheapest) DCF clock - e. g. DCF77 receiver by Conrad 652 * (~40DM - roughly $30 ) followed by a level converter for RS232 653 */ 654 #define CONRAD_BASEDELAY 0.292 /* Conrad receiver @ 50 Baud on a Sun */ 655 #define CONRAD_DESCRIPTION "RAW DCF77 CODE (Conrad DCF77 receiver module)" 656 657 /* Gude Analog- und Digitalsystem GmbH 'Expert mouseCLOCK USB v2.0' */ 658 #define GUDE_EMC_USB_V20_SPEED (B4800) 659 #define GUDE_EMC_USB_V20_BASEDELAY 0.425 /* USB serial<->USB converter FTDI232R */ 660 #define GUDE_EMC_USB_V20_DESCRIPTION "RAW DCF77 CODE (Expert mouseCLOCK USB v2.0)" 661 662 /* 663 * TimeBrick receiver 664 */ 665 #define TIMEBRICK_BASEDELAY 0.210 /* TimeBrick @ 50 Baud on a Sun */ 666 #define TIMEBRICK_DESCRIPTION "RAW DCF77 CODE (TimeBrick)" 667 668 /* 669 * IGEL:clock receiver 670 */ 671 #define IGELCLOCK_BASEDELAY 0.258 /* IGEL:clock receiver */ 672 #define IGELCLOCK_DESCRIPTION "RAW DCF77 CODE (IGEL:clock)" 673 #define IGELCLOCK_SPEED (B1200) 674 #define IGELCLOCK_CFLAG (CS8|CREAD|HUPCL|CLOCAL) 675 676 /* 677 * RAWDCF receivers that need to be powered from DTR 678 * (like Expert mouse clock) 679 */ 680 static int rawdcf_init_1 P((struct parseunit *)); 681 #define RAWDCFDTRSET_DESCRIPTION "RAW DCF77 CODE (DTR SET/RTS CLR)" 682 #define RAWDCFDTRSET_INIT rawdcf_init_1 683 684 /* 685 * RAWDCF receivers that need to be powered from 686 * DTR CLR and RTS SET 687 */ 688 static int rawdcf_init_2 P((struct parseunit *)); 689 #define RAWDCFDTRCLRRTSSET_DESCRIPTION "RAW DCF77 CODE (DTR CLR/RTS SET)" 690 #define RAWDCFDTRCLRRTSSET_INIT rawdcf_init_2 691 692 /* 693 * Trimble GPS receivers (TAIP and TSIP protocols) 694 */ 695 #ifndef TRIM_POLLRATE 696 #define TRIM_POLLRATE 0 /* only true direct polling */ 697 #endif 698 699 #define TRIM_TAIPPOLLCMD ">SRM;FR_FLAG=F;EC_FLAG=F<>QTM<" 700 #define TRIM_TAIPCMDSIZE (sizeof(TRIM_TAIPPOLLCMD)-1) 701 702 static poll_info_t trimbletaip_pollinfo = { TRIM_POLLRATE, TRIM_TAIPPOLLCMD, TRIM_TAIPCMDSIZE }; 703 static int trimbletaip_init P((struct parseunit *)); 704 static void trimbletaip_event P((struct parseunit *, int)); 705 706 /* query time & UTC correction data */ 707 static char tsipquery[] = { DLE, 0x21, DLE, ETX, DLE, 0x2F, DLE, ETX }; 708 709 static poll_info_t trimbletsip_pollinfo = { TRIM_POLLRATE, tsipquery, sizeof(tsipquery) }; 710 static int trimbletsip_init P((struct parseunit *)); 711 static void trimbletsip_end P((struct parseunit *)); 712 static void trimbletsip_message P((struct parseunit *, parsetime_t *)); 713 static void trimbletsip_event P((struct parseunit *, int)); 714 715 #define TRIMBLETSIP_IDLE_TIME (300) /* 5 minutes silence at most */ 716 #define TRIMBLE_RESET_HOLDOFF TRIMBLETSIP_IDLE_TIME 717 718 #define TRIMBLETAIP_SPEED (B4800) 719 #define TRIMBLETAIP_CFLAG (CS8|CREAD|CLOCAL) 720 #define TRIMBLETAIP_IFLAG (BRKINT|IGNPAR|ISTRIP|ICRNL|IXON) 721 #define TRIMBLETAIP_OFLAG (OPOST|ONLCR) 722 #define TRIMBLETAIP_LFLAG (0) 723 724 #define TRIMBLETSIP_SPEED (B9600) 725 #define TRIMBLETSIP_CFLAG (CS8|CLOCAL|CREAD|PARENB|PARODD) 726 #define TRIMBLETSIP_IFLAG (IGNBRK) 727 #define TRIMBLETSIP_OFLAG (0) 728 #define TRIMBLETSIP_LFLAG (ICANON) 729 730 #define TRIMBLETSIP_SAMPLES 5 731 #define TRIMBLETSIP_KEEP 3 732 #define TRIMBLETAIP_SAMPLES 5 733 #define TRIMBLETAIP_KEEP 3 734 735 #define TRIMBLETAIP_FLAGS (PARSE_F_PPSONSECOND) 736 #define TRIMBLETSIP_FLAGS (TRIMBLETAIP_FLAGS) 737 738 #define TRIMBLETAIP_POLL poll_dpoll 739 #define TRIMBLETSIP_POLL poll_dpoll 740 741 #define TRIMBLETAIP_INIT trimbletaip_init 742 #define TRIMBLETSIP_INIT trimbletsip_init 743 744 #define TRIMBLETAIP_EVENT trimbletaip_event 745 746 #define TRIMBLETSIP_EVENT trimbletsip_event 747 #define TRIMBLETSIP_MESSAGE trimbletsip_message 748 749 #define TRIMBLETAIP_END 0 750 #define TRIMBLETSIP_END trimbletsip_end 751 752 #define TRIMBLETAIP_DATA ((void *)(&trimbletaip_pollinfo)) 753 #define TRIMBLETSIP_DATA ((void *)(&trimbletsip_pollinfo)) 754 755 #define TRIMBLETAIP_ID GPS_ID 756 #define TRIMBLETSIP_ID GPS_ID 757 758 #define TRIMBLETAIP_FORMAT "Trimble TAIP" 759 #define TRIMBLETSIP_FORMAT "Trimble TSIP" 760 761 #define TRIMBLETAIP_ROOTDELAY 0x0 762 #define TRIMBLETSIP_ROOTDELAY 0x0 763 764 #define TRIMBLETAIP_BASEDELAY 0.0 765 #define TRIMBLETSIP_BASEDELAY 0.020 /* GPS time message latency */ 766 767 #define TRIMBLETAIP_DESCRIPTION "Trimble GPS (TAIP) receiver" 768 #define TRIMBLETSIP_DESCRIPTION "Trimble GPS (TSIP) receiver" 769 770 #define TRIMBLETAIP_MAXUNSYNC 0 771 #define TRIMBLETSIP_MAXUNSYNC 0 772 773 #define TRIMBLETAIP_EOL '<' 774 775 /* 776 * RadioCode Clocks RCC 800 receiver 777 */ 778 #define RCC_POLLRATE 0 /* only true direct polling */ 779 #define RCC_POLLCMD "\r" 780 #define RCC_CMDSIZE 1 781 782 static poll_info_t rcc8000_pollinfo = { RCC_POLLRATE, RCC_POLLCMD, RCC_CMDSIZE }; 783 #define RCC8000_FLAGS 0 784 #define RCC8000_POLL poll_dpoll 785 #define RCC8000_INIT poll_init 786 #define RCC8000_END 0 787 #define RCC8000_DATA ((void *)(&rcc8000_pollinfo)) 788 #define RCC8000_ROOTDELAY 0.0 789 #define RCC8000_BASEDELAY 0.0 790 #define RCC8000_ID "MSF" 791 #define RCC8000_DESCRIPTION "RCC 8000 MSF Receiver" 792 #define RCC8000_FORMAT "Radiocode RCC8000" 793 #define RCC8000_MAXUNSYNC (60*60) /* should be ok for an hour */ 794 #define RCC8000_SPEED (B2400) 795 #define RCC8000_CFLAG (CS8|CREAD|CLOCAL) 796 #define RCC8000_IFLAG (IGNBRK|IGNPAR) 797 #define RCC8000_OFLAG 0 798 #define RCC8000_LFLAG 0 799 #define RCC8000_SAMPLES 5 800 #define RCC8000_KEEP 3 801 802 /* 803 * Hopf Radio clock 6021 Format 804 * 805 */ 806 #define HOPF6021_ROOTDELAY 0.0 807 #define HOPF6021_BASEDELAY 0.0 808 #define HOPF6021_DESCRIPTION "HOPF 6021" 809 #define HOPF6021_FORMAT "hopf Funkuhr 6021" 810 #define HOPF6021_MAXUNSYNC (60*60) /* should be ok for an hour */ 811 #define HOPF6021_SPEED (B9600) 812 #define HOPF6021_CFLAG (CS8|CREAD|CLOCAL) 813 #define HOPF6021_IFLAG (IGNBRK|ISTRIP) 814 #define HOPF6021_OFLAG 0 815 #define HOPF6021_LFLAG 0 816 #define HOPF6021_FLAGS 0 817 #define HOPF6021_SAMPLES 5 818 #define HOPF6021_KEEP 3 819 820 /* 821 * Diem's Computime Radio Clock Receiver 822 */ 823 #define COMPUTIME_FLAGS 0 824 #define COMPUTIME_ROOTDELAY 0.0 825 #define COMPUTIME_BASEDELAY 0.0 826 #define COMPUTIME_ID DCF_ID 827 #define COMPUTIME_DESCRIPTION "Diem's Computime receiver" 828 #define COMPUTIME_FORMAT "Diem's Computime Radio Clock" 829 #define COMPUTIME_TYPE DCF_TYPE 830 #define COMPUTIME_MAXUNSYNC (60*60) /* only trust clock for 1 hour */ 831 #define COMPUTIME_SPEED (B9600) 832 #define COMPUTIME_CFLAG (CSTOPB|CS7|CREAD|CLOCAL) 833 #define COMPUTIME_IFLAG (IGNBRK|IGNPAR|ISTRIP) 834 #define COMPUTIME_OFLAG 0 835 #define COMPUTIME_LFLAG 0 836 #define COMPUTIME_SAMPLES 5 837 #define COMPUTIME_KEEP 3 838 839 /* 840 * Varitext Radio Clock Receiver 841 */ 842 #define VARITEXT_FLAGS 0 843 #define VARITEXT_ROOTDELAY 0.0 844 #define VARITEXT_BASEDELAY 0.0 845 #define VARITEXT_ID "MSF" 846 #define VARITEXT_DESCRIPTION "Varitext receiver" 847 #define VARITEXT_FORMAT "Varitext Radio Clock" 848 #define VARITEXT_TYPE DCF_TYPE 849 #define VARITEXT_MAXUNSYNC (60*60) /* only trust clock for 1 hour */ 850 #define VARITEXT_SPEED (B9600) 851 #define VARITEXT_CFLAG (CS7|CREAD|CLOCAL|PARENB|PARODD) 852 #define VARITEXT_IFLAG (IGNPAR|IGNBRK|INPCK) /*|ISTRIP)*/ 853 #define VARITEXT_OFLAG 0 854 #define VARITEXT_LFLAG 0 855 #define VARITEXT_SAMPLES 32 856 #define VARITEXT_KEEP 20 857 858 static struct parse_clockinfo 859 { 860 u_long cl_flags; /* operation flags (io modes) */ 861 void (*cl_poll) P((struct parseunit *)); /* active poll routine */ 862 int (*cl_init) P((struct parseunit *)); /* active poll init routine */ 863 void (*cl_event) P((struct parseunit *, int)); /* special event handling (e.g. reset clock) */ 864 void (*cl_end) P((struct parseunit *)); /* active poll end routine */ 865 void (*cl_message) P((struct parseunit *, parsetime_t *)); /* process a lower layer message */ 866 void *cl_data; /* local data area for "poll" mechanism */ 867 double cl_rootdelay; /* rootdelay */ 868 double cl_basedelay; /* current offset by which the RS232 869 time code is delayed from the actual time */ 870 const char *cl_id; /* ID code */ 871 const char *cl_description; /* device name */ 872 const char *cl_format; /* fixed format */ 873 u_char cl_type; /* clock type (ntp control) */ 874 u_long cl_maxunsync; /* time to trust oscillator after losing synch */ 875 u_long cl_speed; /* terminal input & output baudrate */ 876 u_long cl_cflag; /* terminal control flags */ 877 u_long cl_iflag; /* terminal input flags */ 878 u_long cl_oflag; /* terminal output flags */ 879 u_long cl_lflag; /* terminal local flags */ 880 u_long cl_samples; /* samples for median filter */ 881 u_long cl_keep; /* samples for median filter to keep */ 882 } parse_clockinfo[] = 883 { 884 { /* mode 0 */ 885 MBG_FLAGS, 886 NO_POLL, 887 NO_INIT, 888 NO_EVENT, 889 NO_END, 890 NO_MESSAGE, 891 NO_LCLDATA, 892 DCFPZF535_ROOTDELAY, 893 DCFPZF535_BASEDELAY, 894 DCF_P_ID, 895 DCFPZF535_DESCRIPTION, 896 DCFPZF535_FORMAT, 897 DCF_TYPE, 898 DCFPZF535_MAXUNSYNC, 899 DCFPZF535_SPEED, 900 DCFPZF535_CFLAG, 901 DCFPZF535_IFLAG, 902 DCFPZF535_OFLAG, 903 DCFPZF535_LFLAG, 904 DCFPZF535_SAMPLES, 905 DCFPZF535_KEEP 906 }, 907 { /* mode 1 */ 908 MBG_FLAGS, 909 NO_POLL, 910 NO_INIT, 911 NO_EVENT, 912 NO_END, 913 NO_MESSAGE, 914 NO_LCLDATA, 915 DCFPZF535OCXO_ROOTDELAY, 916 DCFPZF535OCXO_BASEDELAY, 917 DCF_P_ID, 918 DCFPZF535OCXO_DESCRIPTION, 919 DCFPZF535OCXO_FORMAT, 920 DCF_TYPE, 921 DCFPZF535OCXO_MAXUNSYNC, 922 DCFPZF535OCXO_SPEED, 923 DCFPZF535OCXO_CFLAG, 924 DCFPZF535OCXO_IFLAG, 925 DCFPZF535OCXO_OFLAG, 926 DCFPZF535OCXO_LFLAG, 927 DCFPZF535OCXO_SAMPLES, 928 DCFPZF535OCXO_KEEP 929 }, 930 { /* mode 2 */ 931 MBG_FLAGS, 932 NO_POLL, 933 NO_INIT, 934 NO_EVENT, 935 NO_END, 936 NO_MESSAGE, 937 NO_LCLDATA, 938 DCFUA31_ROOTDELAY, 939 DCFUA31_BASEDELAY, 940 DCF_A_ID, 941 DCFUA31_DESCRIPTION, 942 DCFUA31_FORMAT, 943 DCF_TYPE, 944 DCFUA31_MAXUNSYNC, 945 DCFUA31_SPEED, 946 DCFUA31_CFLAG, 947 DCFUA31_IFLAG, 948 DCFUA31_OFLAG, 949 DCFUA31_LFLAG, 950 DCFUA31_SAMPLES, 951 DCFUA31_KEEP 952 }, 953 { /* mode 3 */ 954 MBG_FLAGS, 955 NO_POLL, 956 NO_INIT, 957 NO_EVENT, 958 NO_END, 959 NO_MESSAGE, 960 NO_LCLDATA, 961 DCF7000_ROOTDELAY, 962 DCF7000_BASEDELAY, 963 DCF_A_ID, 964 DCF7000_DESCRIPTION, 965 DCF7000_FORMAT, 966 DCF_TYPE, 967 DCF7000_MAXUNSYNC, 968 DCF7000_SPEED, 969 DCF7000_CFLAG, 970 DCF7000_IFLAG, 971 DCF7000_OFLAG, 972 DCF7000_LFLAG, 973 DCF7000_SAMPLES, 974 DCF7000_KEEP 975 }, 976 { /* mode 4 */ 977 NO_CL_FLAGS, 978 WSDCF_POLL, 979 WSDCF_INIT, 980 NO_EVENT, 981 WSDCF_END, 982 NO_MESSAGE, 983 WSDCF_DATA, 984 WSDCF_ROOTDELAY, 985 WSDCF_BASEDELAY, 986 DCF_A_ID, 987 WSDCF_DESCRIPTION, 988 WSDCF_FORMAT, 989 DCF_TYPE, 990 WSDCF_MAXUNSYNC, 991 WSDCF_SPEED, 992 WSDCF_CFLAG, 993 WSDCF_IFLAG, 994 WSDCF_OFLAG, 995 WSDCF_LFLAG, 996 WSDCF_SAMPLES, 997 WSDCF_KEEP 998 }, 999 { /* mode 5 */ 1000 RAWDCF_FLAGS, 1001 NO_POLL, 1002 RAWDCF_INIT, 1003 NO_EVENT, 1004 NO_END, 1005 NO_MESSAGE, 1006 NO_LCLDATA, 1007 RAWDCF_ROOTDELAY, 1008 CONRAD_BASEDELAY, 1009 DCF_A_ID, 1010 CONRAD_DESCRIPTION, 1011 RAWDCF_FORMAT, 1012 DCF_TYPE, 1013 RAWDCF_MAXUNSYNC, 1014 RAWDCF_SPEED, 1015 RAWDCF_CFLAG, 1016 RAWDCF_IFLAG, 1017 RAWDCF_OFLAG, 1018 RAWDCF_LFLAG, 1019 RAWDCF_SAMPLES, 1020 RAWDCF_KEEP 1021 }, 1022 { /* mode 6 */ 1023 RAWDCF_FLAGS, 1024 NO_POLL, 1025 RAWDCF_INIT, 1026 NO_EVENT, 1027 NO_END, 1028 NO_MESSAGE, 1029 NO_LCLDATA, 1030 RAWDCF_ROOTDELAY, 1031 TIMEBRICK_BASEDELAY, 1032 DCF_A_ID, 1033 TIMEBRICK_DESCRIPTION, 1034 RAWDCF_FORMAT, 1035 DCF_TYPE, 1036 RAWDCF_MAXUNSYNC, 1037 RAWDCF_SPEED, 1038 RAWDCF_CFLAG, 1039 RAWDCF_IFLAG, 1040 RAWDCF_OFLAG, 1041 RAWDCF_LFLAG, 1042 RAWDCF_SAMPLES, 1043 RAWDCF_KEEP 1044 }, 1045 { /* mode 7 */ 1046 MBG_FLAGS, 1047 GPS16X_POLL, 1048 GPS16X_INIT, 1049 NO_EVENT, 1050 GPS16X_END, 1051 GPS16X_MESSAGE, 1052 GPS16X_DATA, 1053 GPS16X_ROOTDELAY, 1054 GPS16X_BASEDELAY, 1055 GPS16X_ID, 1056 GPS16X_DESCRIPTION, 1057 GPS16X_FORMAT, 1058 GPS_TYPE, 1059 GPS16X_MAXUNSYNC, 1060 GPS16X_SPEED, 1061 GPS16X_CFLAG, 1062 GPS16X_IFLAG, 1063 GPS16X_OFLAG, 1064 GPS16X_LFLAG, 1065 GPS16X_SAMPLES, 1066 GPS16X_KEEP 1067 }, 1068 { /* mode 8 */ 1069 RAWDCF_FLAGS, 1070 NO_POLL, 1071 NO_INIT, 1072 NO_EVENT, 1073 NO_END, 1074 NO_MESSAGE, 1075 NO_LCLDATA, 1076 RAWDCF_ROOTDELAY, 1077 IGELCLOCK_BASEDELAY, 1078 DCF_A_ID, 1079 IGELCLOCK_DESCRIPTION, 1080 RAWDCF_FORMAT, 1081 DCF_TYPE, 1082 RAWDCF_MAXUNSYNC, 1083 IGELCLOCK_SPEED, 1084 IGELCLOCK_CFLAG, 1085 RAWDCF_IFLAG, 1086 RAWDCF_OFLAG, 1087 RAWDCF_LFLAG, 1088 RAWDCF_SAMPLES, 1089 RAWDCF_KEEP 1090 }, 1091 { /* mode 9 */ 1092 TRIMBLETAIP_FLAGS, 1093 #if TRIM_POLLRATE /* DHD940515: Allow user config */ 1094 NO_POLL, 1095 #else 1096 TRIMBLETAIP_POLL, 1097 #endif 1098 TRIMBLETAIP_INIT, 1099 TRIMBLETAIP_EVENT, 1100 TRIMBLETAIP_END, 1101 NO_MESSAGE, 1102 TRIMBLETAIP_DATA, 1103 TRIMBLETAIP_ROOTDELAY, 1104 TRIMBLETAIP_BASEDELAY, 1105 TRIMBLETAIP_ID, 1106 TRIMBLETAIP_DESCRIPTION, 1107 TRIMBLETAIP_FORMAT, 1108 GPS_TYPE, 1109 TRIMBLETAIP_MAXUNSYNC, 1110 TRIMBLETAIP_SPEED, 1111 TRIMBLETAIP_CFLAG, 1112 TRIMBLETAIP_IFLAG, 1113 TRIMBLETAIP_OFLAG, 1114 TRIMBLETAIP_LFLAG, 1115 TRIMBLETAIP_SAMPLES, 1116 TRIMBLETAIP_KEEP 1117 }, 1118 { /* mode 10 */ 1119 TRIMBLETSIP_FLAGS, 1120 #if TRIM_POLLRATE /* DHD940515: Allow user config */ 1121 NO_POLL, 1122 #else 1123 TRIMBLETSIP_POLL, 1124 #endif 1125 TRIMBLETSIP_INIT, 1126 TRIMBLETSIP_EVENT, 1127 TRIMBLETSIP_END, 1128 TRIMBLETSIP_MESSAGE, 1129 TRIMBLETSIP_DATA, 1130 TRIMBLETSIP_ROOTDELAY, 1131 TRIMBLETSIP_BASEDELAY, 1132 TRIMBLETSIP_ID, 1133 TRIMBLETSIP_DESCRIPTION, 1134 TRIMBLETSIP_FORMAT, 1135 GPS_TYPE, 1136 TRIMBLETSIP_MAXUNSYNC, 1137 TRIMBLETSIP_SPEED, 1138 TRIMBLETSIP_CFLAG, 1139 TRIMBLETSIP_IFLAG, 1140 TRIMBLETSIP_OFLAG, 1141 TRIMBLETSIP_LFLAG, 1142 TRIMBLETSIP_SAMPLES, 1143 TRIMBLETSIP_KEEP 1144 }, 1145 { /* mode 11 */ 1146 NO_CL_FLAGS, 1147 RCC8000_POLL, 1148 RCC8000_INIT, 1149 NO_EVENT, 1150 RCC8000_END, 1151 NO_MESSAGE, 1152 RCC8000_DATA, 1153 RCC8000_ROOTDELAY, 1154 RCC8000_BASEDELAY, 1155 RCC8000_ID, 1156 RCC8000_DESCRIPTION, 1157 RCC8000_FORMAT, 1158 DCF_TYPE, 1159 RCC8000_MAXUNSYNC, 1160 RCC8000_SPEED, 1161 RCC8000_CFLAG, 1162 RCC8000_IFLAG, 1163 RCC8000_OFLAG, 1164 RCC8000_LFLAG, 1165 RCC8000_SAMPLES, 1166 RCC8000_KEEP 1167 }, 1168 { /* mode 12 */ 1169 HOPF6021_FLAGS, 1170 NO_POLL, 1171 NO_INIT, 1172 NO_EVENT, 1173 NO_END, 1174 NO_MESSAGE, 1175 NO_LCLDATA, 1176 HOPF6021_ROOTDELAY, 1177 HOPF6021_BASEDELAY, 1178 DCF_ID, 1179 HOPF6021_DESCRIPTION, 1180 HOPF6021_FORMAT, 1181 DCF_TYPE, 1182 HOPF6021_MAXUNSYNC, 1183 HOPF6021_SPEED, 1184 HOPF6021_CFLAG, 1185 HOPF6021_IFLAG, 1186 HOPF6021_OFLAG, 1187 HOPF6021_LFLAG, 1188 HOPF6021_SAMPLES, 1189 HOPF6021_KEEP 1190 }, 1191 { /* mode 13 */ 1192 COMPUTIME_FLAGS, 1193 NO_POLL, 1194 NO_INIT, 1195 NO_EVENT, 1196 NO_END, 1197 NO_MESSAGE, 1198 NO_LCLDATA, 1199 COMPUTIME_ROOTDELAY, 1200 COMPUTIME_BASEDELAY, 1201 COMPUTIME_ID, 1202 COMPUTIME_DESCRIPTION, 1203 COMPUTIME_FORMAT, 1204 COMPUTIME_TYPE, 1205 COMPUTIME_MAXUNSYNC, 1206 COMPUTIME_SPEED, 1207 COMPUTIME_CFLAG, 1208 COMPUTIME_IFLAG, 1209 COMPUTIME_OFLAG, 1210 COMPUTIME_LFLAG, 1211 COMPUTIME_SAMPLES, 1212 COMPUTIME_KEEP 1213 }, 1214 { /* mode 14 */ 1215 RAWDCF_FLAGS, 1216 NO_POLL, 1217 RAWDCFDTRSET_INIT, 1218 NO_EVENT, 1219 NO_END, 1220 NO_MESSAGE, 1221 NO_LCLDATA, 1222 RAWDCF_ROOTDELAY, 1223 RAWDCF_BASEDELAY, 1224 DCF_A_ID, 1225 RAWDCFDTRSET_DESCRIPTION, 1226 RAWDCF_FORMAT, 1227 DCF_TYPE, 1228 RAWDCF_MAXUNSYNC, 1229 RAWDCF_SPEED, 1230 RAWDCF_CFLAG, 1231 RAWDCF_IFLAG, 1232 RAWDCF_OFLAG, 1233 RAWDCF_LFLAG, 1234 RAWDCF_SAMPLES, 1235 RAWDCF_KEEP 1236 }, 1237 { /* mode 15 */ 1238 0, /* operation flags (io modes) */ 1239 NO_POLL, /* active poll routine */ 1240 NO_INIT, /* active poll init routine */ 1241 NO_EVENT, /* special event handling (e.g. reset clock) */ 1242 NO_END, /* active poll end routine */ 1243 NO_MESSAGE, /* process a lower layer message */ 1244 NO_LCLDATA, /* local data area for "poll" mechanism */ 1245 0, /* rootdelay */ 1246 11.0 /* bits */ / 9600, /* current offset by which the RS232 1247 time code is delayed from the actual time */ 1248 DCF_ID, /* ID code */ 1249 "WHARTON 400A Series clock", /* device name */ 1250 "WHARTON 400A Series clock Output Format 1", /* fixed format */ 1251 /* Must match a format-name in a libparse/clk_xxx.c file */ 1252 DCF_TYPE, /* clock type (ntp control) */ 1253 (1*60*60), /* time to trust oscillator after losing synch */ 1254 B9600, /* terminal input & output baudrate */ 1255 (CS8|CREAD|PARENB|CLOCAL|HUPCL),/* terminal control flags */ 1256 0, /* terminal input flags */ 1257 0, /* terminal output flags */ 1258 0, /* terminal local flags */ 1259 5, /* samples for median filter */ 1260 3, /* samples for median filter to keep */ 1261 }, 1262 { /* mode 16 - RAWDCF RTS set, DTR clr */ 1263 RAWDCF_FLAGS, 1264 NO_POLL, 1265 RAWDCFDTRCLRRTSSET_INIT, 1266 NO_EVENT, 1267 NO_END, 1268 NO_MESSAGE, 1269 NO_LCLDATA, 1270 RAWDCF_ROOTDELAY, 1271 RAWDCF_BASEDELAY, 1272 DCF_A_ID, 1273 RAWDCFDTRCLRRTSSET_DESCRIPTION, 1274 RAWDCF_FORMAT, 1275 DCF_TYPE, 1276 RAWDCF_MAXUNSYNC, 1277 RAWDCF_SPEED, 1278 RAWDCF_CFLAG, 1279 RAWDCF_IFLAG, 1280 RAWDCF_OFLAG, 1281 RAWDCF_LFLAG, 1282 RAWDCF_SAMPLES, 1283 RAWDCF_KEEP 1284 }, 1285 { /* mode 17 */ 1286 VARITEXT_FLAGS, 1287 NO_POLL, 1288 NO_INIT, 1289 NO_EVENT, 1290 NO_END, 1291 NO_MESSAGE, 1292 NO_LCLDATA, 1293 VARITEXT_ROOTDELAY, 1294 VARITEXT_BASEDELAY, 1295 VARITEXT_ID, 1296 VARITEXT_DESCRIPTION, 1297 VARITEXT_FORMAT, 1298 VARITEXT_TYPE, 1299 VARITEXT_MAXUNSYNC, 1300 VARITEXT_SPEED, 1301 VARITEXT_CFLAG, 1302 VARITEXT_IFLAG, 1303 VARITEXT_OFLAG, 1304 VARITEXT_LFLAG, 1305 VARITEXT_SAMPLES, 1306 VARITEXT_KEEP 1307 }, 1308 { /* mode 18 */ 1309 MBG_FLAGS, 1310 NO_POLL, 1311 NO_INIT, 1312 NO_EVENT, 1313 GPS16X_END, 1314 GPS16X_MESSAGE, 1315 GPS16X_DATA, 1316 GPS16X_ROOTDELAY, 1317 GPS16X_BASEDELAY, 1318 GPS16X_ID, 1319 GPS16X_DESCRIPTION, 1320 GPS16X_FORMAT, 1321 GPS_TYPE, 1322 GPS16X_MAXUNSYNC, 1323 GPS16X_SPEED, 1324 GPS16X_CFLAG, 1325 GPS16X_IFLAG, 1326 GPS16X_OFLAG, 1327 GPS16X_LFLAG, 1328 GPS16X_SAMPLES, 1329 GPS16X_KEEP 1330 }, 1331 { /* mode 19 */ 1332 RAWDCF_FLAGS, 1333 NO_POLL, 1334 RAWDCF_INIT, 1335 NO_EVENT, 1336 NO_END, 1337 NO_MESSAGE, 1338 NO_LCLDATA, 1339 RAWDCF_ROOTDELAY, 1340 GUDE_EMC_USB_V20_BASEDELAY, 1341 DCF_A_ID, 1342 GUDE_EMC_USB_V20_DESCRIPTION, 1343 RAWDCF_FORMAT, 1344 DCF_TYPE, 1345 RAWDCF_MAXUNSYNC, 1346 GUDE_EMC_USB_V20_SPEED, 1347 RAWDCF_CFLAG, 1348 RAWDCF_IFLAG, 1349 RAWDCF_OFLAG, 1350 RAWDCF_LFLAG, 1351 RAWDCF_SAMPLES, 1352 RAWDCF_KEEP 1353 }, 1354 }; 1355 1356 static int ncltypes = sizeof(parse_clockinfo) / sizeof(struct parse_clockinfo); 1357 1358 #define CLK_REALTYPE(x) ((int)(((x)->ttl) & 0x7F)) 1359 #define CLK_TYPE(x) ((CLK_REALTYPE(x) >= ncltypes) ? ~0 : CLK_REALTYPE(x)) 1360 #define CLK_UNIT(x) ((int)REFCLOCKUNIT(&(x)->srcadr)) 1361 #define CLK_PPS(x) (((x)->ttl) & 0x80) 1362 1363 /* 1364 * Other constant stuff 1365 */ 1366 #define PARSEHSREFID 0x7f7f08ff /* 127.127.8.255 refid for hi strata */ 1367 1368 #define PARSESTATISTICS (60*60) /* output state statistics every hour */ 1369 1370 static int notice = 0; 1371 1372 #define PARSE_STATETIME(parse, i) ((parse->generic->currentstatus == i) ? parse->statetime[i] + current_time - parse->lastchange : parse->statetime[i]) 1373 1374 static void parse_event P((struct parseunit *, int)); 1375 static void parse_process P((struct parseunit *, parsetime_t *)); 1376 static void clear_err P((struct parseunit *, u_long)); 1377 static int list_err P((struct parseunit *, u_long)); 1378 static char * l_mktime P((u_long)); 1379 1380 /**=========================================================================== 1381 ** implementation error message regression module 1382 **/ 1383 static void 1384 clear_err( 1385 struct parseunit *parse, 1386 u_long lstate 1387 ) 1388 { 1389 if (lstate == ERR_ALL) 1390 { 1391 int i; 1392 1393 for (i = 0; i < ERR_CNT; i++) 1394 { 1395 parse->errors[i].err_stage = err_tbl[i]; 1396 parse->errors[i].err_cnt = 0; 1397 parse->errors[i].err_last = 0; 1398 parse->errors[i].err_started = 0; 1399 parse->errors[i].err_suppressed = 0; 1400 } 1401 } 1402 else 1403 { 1404 parse->errors[lstate].err_stage = err_tbl[lstate]; 1405 parse->errors[lstate].err_cnt = 0; 1406 parse->errors[lstate].err_last = 0; 1407 parse->errors[lstate].err_started = 0; 1408 parse->errors[lstate].err_suppressed = 0; 1409 } 1410 } 1411 1412 static int 1413 list_err( 1414 struct parseunit *parse, 1415 u_long lstate 1416 ) 1417 { 1418 int do_it; 1419 struct errorinfo *err = &parse->errors[lstate]; 1420 1421 if (err->err_started == 0) 1422 { 1423 err->err_started = current_time; 1424 } 1425 1426 do_it = (current_time - err->err_last) >= err->err_stage->err_delay; 1427 1428 if (do_it) 1429 err->err_cnt++; 1430 1431 if (err->err_stage->err_count && 1432 (err->err_cnt >= err->err_stage->err_count)) 1433 { 1434 err->err_stage++; 1435 err->err_cnt = 0; 1436 } 1437 1438 if (!err->err_cnt && do_it) 1439 msyslog(LOG_INFO, "PARSE receiver #%d: interval for following error message class is at least %s", 1440 CLK_UNIT(parse->peer), l_mktime(err->err_stage->err_delay)); 1441 1442 if (!do_it) 1443 err->err_suppressed++; 1444 else 1445 err->err_last = current_time; 1446 1447 if (do_it && err->err_suppressed) 1448 { 1449 msyslog(LOG_INFO, "PARSE receiver #%d: %ld message%s suppressed, error condition class persists for %s", 1450 CLK_UNIT(parse->peer), err->err_suppressed, (err->err_suppressed == 1) ? " was" : "s where", 1451 l_mktime(current_time - err->err_started)); 1452 err->err_suppressed = 0; 1453 } 1454 1455 return do_it; 1456 } 1457 1458 /*-------------------------------------------------- 1459 * mkreadable - make a printable ascii string (without 1460 * embedded quotes so that the ntpq protocol isn't 1461 * fooled 1462 */ 1463 #ifndef isprint 1464 #define isprint(_X_) (((_X_) > 0x1F) && ((_X_) < 0x7F)) 1465 #endif 1466 1467 static char * 1468 mkreadable( 1469 char *buffer, 1470 long blen, 1471 const char *src, 1472 u_long srclen, 1473 int hex 1474 ) 1475 { 1476 char *b = buffer; 1477 char *endb = (char *)0; 1478 1479 if (blen < 4) 1480 return (char *)0; /* don't bother with mini buffers */ 1481 1482 endb = buffer + blen - 4; 1483 1484 blen--; /* account for '\0' */ 1485 1486 while (blen && srclen--) 1487 { 1488 if (!hex && /* no binary only */ 1489 (*src != '\\') && /* no plain \ */ 1490 (*src != '"') && /* no " */ 1491 isprint((int)*src)) /* only printables */ 1492 { /* they are easy... */ 1493 *buffer++ = *src++; 1494 blen--; 1495 } 1496 else 1497 { 1498 if (blen < 4) 1499 { 1500 while (blen--) 1501 { 1502 *buffer++ = '.'; 1503 } 1504 *buffer = '\0'; 1505 return b; 1506 } 1507 else 1508 { 1509 if (*src == '\\') 1510 { 1511 strcpy(buffer,"\\\\"); 1512 buffer += 2; 1513 blen -= 2; 1514 src++; 1515 } 1516 else 1517 { 1518 sprintf(buffer, "\\x%02x", *src++); 1519 blen -= 4; 1520 buffer += 4; 1521 } 1522 } 1523 } 1524 if (srclen && !blen && endb) /* overflow - set last chars to ... */ 1525 strcpy(endb, "..."); 1526 } 1527 1528 *buffer = '\0'; 1529 return b; 1530 } 1531 1532 1533 /*-------------------------------------------------- 1534 * mkascii - make a printable ascii string 1535 * assumes (unless defined better) 7-bit ASCII 1536 */ 1537 static char * 1538 mkascii( 1539 char *buffer, 1540 long blen, 1541 const char *src, 1542 u_long srclen 1543 ) 1544 { 1545 return mkreadable(buffer, blen, src, srclen, 0); 1546 } 1547 1548 /**=========================================================================== 1549 ** implementation of i/o handling methods 1550 ** (all STREAM, partial STREAM, user level) 1551 **/ 1552 1553 /* 1554 * define possible io handling methods 1555 */ 1556 #ifdef STREAM 1557 static int ppsclock_init P((struct parseunit *)); 1558 static int stream_init P((struct parseunit *)); 1559 static void stream_end P((struct parseunit *)); 1560 static int stream_enable P((struct parseunit *)); 1561 static int stream_disable P((struct parseunit *)); 1562 static int stream_setcs P((struct parseunit *, parsectl_t *)); 1563 static int stream_getfmt P((struct parseunit *, parsectl_t *)); 1564 static int stream_setfmt P((struct parseunit *, parsectl_t *)); 1565 static int stream_timecode P((struct parseunit *, parsectl_t *)); 1566 static void stream_receive P((struct recvbuf *)); 1567 #endif 1568 1569 static int local_init P((struct parseunit *)); 1570 static void local_end P((struct parseunit *)); 1571 static int local_nop P((struct parseunit *)); 1572 static int local_setcs P((struct parseunit *, parsectl_t *)); 1573 static int local_getfmt P((struct parseunit *, parsectl_t *)); 1574 static int local_setfmt P((struct parseunit *, parsectl_t *)); 1575 static int local_timecode P((struct parseunit *, parsectl_t *)); 1576 static void local_receive P((struct recvbuf *)); 1577 static int local_input P((struct recvbuf *)); 1578 1579 static bind_t io_bindings[] = 1580 { 1581 #ifdef STREAM 1582 { 1583 "parse STREAM", 1584 stream_init, 1585 stream_end, 1586 stream_setcs, 1587 stream_disable, 1588 stream_enable, 1589 stream_getfmt, 1590 stream_setfmt, 1591 stream_timecode, 1592 stream_receive, 1593 0, 1594 }, 1595 { 1596 "ppsclock STREAM", 1597 ppsclock_init, 1598 local_end, 1599 local_setcs, 1600 local_nop, 1601 local_nop, 1602 local_getfmt, 1603 local_setfmt, 1604 local_timecode, 1605 local_receive, 1606 local_input, 1607 }, 1608 #endif 1609 { 1610 "normal", 1611 local_init, 1612 local_end, 1613 local_setcs, 1614 local_nop, 1615 local_nop, 1616 local_getfmt, 1617 local_setfmt, 1618 local_timecode, 1619 local_receive, 1620 local_input, 1621 }, 1622 { 1623 (char *)0, 1624 } 1625 }; 1626 1627 #ifdef STREAM 1628 1629 #define fix_ts(_X_) \ 1630 if ((&(_X_))->tv.tv_usec >= 1000000) \ 1631 { \ 1632 (&(_X_))->tv.tv_usec -= 1000000; \ 1633 (&(_X_))->tv.tv_sec += 1; \ 1634 } 1635 1636 #define cvt_ts(_X_, _Y_) \ 1637 { \ 1638 l_fp ts; \ 1639 fix_ts((_X_)); \ 1640 if (!buftvtots((const char *)&(&(_X_))->tv, &ts)) \ 1641 { \ 1642 ERR(ERR_BADDATA) \ 1643 msyslog(LOG_ERR,"parse: stream_receive: timestamp conversion error (buftvtots) (%s) (%ld.%06ld) ", (_Y_), (long)(&(_X_))->tv.tv_sec, (long)(&(_X_))->tv.tv_usec);\ 1644 return; \ 1645 } \ 1646 else \ 1647 { \ 1648 (&(_X_))->fp = ts; \ 1649 } \ 1650 } 1651 1652 /*-------------------------------------------------- 1653 * ppsclock STREAM init 1654 */ 1655 static int 1656 ppsclock_init( 1657 struct parseunit *parse 1658 ) 1659 { 1660 static char m1[] = "ppsclocd"; 1661 static char m2[] = "ppsclock"; 1662 1663 /* 1664 * now push the parse streams module 1665 * it will ensure exclusive access to the device 1666 */ 1667 if (ioctl(parse->ppsfd, I_PUSH, (caddr_t)m1) == -1 && 1668 ioctl(parse->ppsfd, I_PUSH, (caddr_t)m2) == -1) 1669 { 1670 if (errno != EINVAL) 1671 { 1672 msyslog(LOG_ERR, "PARSE receiver #%d: ppsclock_init: ioctl(fd, I_PUSH, \"ppsclock\"): %m", 1673 CLK_UNIT(parse->peer)); 1674 } 1675 return 0; 1676 } 1677 if (!local_init(parse)) 1678 { 1679 (void)ioctl(parse->ppsfd, I_POP, (caddr_t)0); 1680 return 0; 1681 } 1682 1683 parse->flags |= PARSE_PPSCLOCK; 1684 return 1; 1685 } 1686 1687 /*-------------------------------------------------- 1688 * parse STREAM init 1689 */ 1690 static int 1691 stream_init( 1692 struct parseunit *parse 1693 ) 1694 { 1695 static char m1[] = "parse"; 1696 /* 1697 * now push the parse streams module 1698 * to test whether it is there (neat interface 8-( ) 1699 */ 1700 if (ioctl(parse->generic->io.fd, I_PUSH, (caddr_t)m1) == -1) 1701 { 1702 if (errno != EINVAL) /* accept non-existence */ 1703 { 1704 msyslog(LOG_ERR, "PARSE receiver #%d: stream_init: ioctl(fd, I_PUSH, \"parse\"): %m", CLK_UNIT(parse->peer)); 1705 } 1706 return 0; 1707 } 1708 else 1709 { 1710 while(ioctl(parse->generic->io.fd, I_POP, (caddr_t)0) == 0) 1711 /* empty loop */; 1712 1713 /* 1714 * now push it a second time after we have removed all 1715 * module garbage 1716 */ 1717 if (ioctl(parse->generic->io.fd, I_PUSH, (caddr_t)m1) == -1) 1718 { 1719 msyslog(LOG_ERR, "PARSE receiver #%d: stream_init: ioctl(fd, I_PUSH, \"parse\"): %m", CLK_UNIT(parse->peer)); 1720 return 0; 1721 } 1722 else 1723 { 1724 return 1; 1725 } 1726 } 1727 } 1728 1729 /*-------------------------------------------------- 1730 * parse STREAM end 1731 */ 1732 static void 1733 stream_end( 1734 struct parseunit *parse 1735 ) 1736 { 1737 while(ioctl(parse->generic->io.fd, I_POP, (caddr_t)0) == 0) 1738 /* empty loop */; 1739 } 1740 1741 /*-------------------------------------------------- 1742 * STREAM setcs 1743 */ 1744 static int 1745 stream_setcs( 1746 struct parseunit *parse, 1747 parsectl_t *tcl 1748 ) 1749 { 1750 struct strioctl strioc; 1751 1752 strioc.ic_cmd = PARSEIOC_SETCS; 1753 strioc.ic_timout = 0; 1754 strioc.ic_dp = (char *)tcl; 1755 strioc.ic_len = sizeof (*tcl); 1756 1757 if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1) 1758 { 1759 msyslog(LOG_ERR, "PARSE receiver #%d: stream_setcs: ioctl(fd, I_STR, PARSEIOC_SETCS): %m", CLK_UNIT(parse->peer)); 1760 return 0; 1761 } 1762 return 1; 1763 } 1764 1765 /*-------------------------------------------------- 1766 * STREAM enable 1767 */ 1768 static int 1769 stream_enable( 1770 struct parseunit *parse 1771 ) 1772 { 1773 struct strioctl strioc; 1774 1775 strioc.ic_cmd = PARSEIOC_ENABLE; 1776 strioc.ic_timout = 0; 1777 strioc.ic_dp = (char *)0; 1778 strioc.ic_len = 0; 1779 1780 if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1) 1781 { 1782 msyslog(LOG_ERR, "PARSE receiver #%d: stream_enable: ioctl(fd, I_STR, PARSEIOC_ENABLE): %m", CLK_UNIT(parse->peer)); 1783 return 0; 1784 } 1785 parse->generic->io.clock_recv = stream_receive; /* ok - parse input in kernel */ 1786 return 1; 1787 } 1788 1789 /*-------------------------------------------------- 1790 * STREAM disable 1791 */ 1792 static int 1793 stream_disable( 1794 struct parseunit *parse 1795 ) 1796 { 1797 struct strioctl strioc; 1798 1799 strioc.ic_cmd = PARSEIOC_DISABLE; 1800 strioc.ic_timout = 0; 1801 strioc.ic_dp = (char *)0; 1802 strioc.ic_len = 0; 1803 1804 if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1) 1805 { 1806 msyslog(LOG_ERR, "PARSE receiver #%d: stream_disable: ioctl(fd, I_STR, PARSEIOC_DISABLE): %m", CLK_UNIT(parse->peer)); 1807 return 0; 1808 } 1809 parse->generic->io.clock_recv = local_receive; /* ok - parse input in daemon */ 1810 return 1; 1811 } 1812 1813 /*-------------------------------------------------- 1814 * STREAM getfmt 1815 */ 1816 static int 1817 stream_getfmt( 1818 struct parseunit *parse, 1819 parsectl_t *tcl 1820 ) 1821 { 1822 struct strioctl strioc; 1823 1824 strioc.ic_cmd = PARSEIOC_GETFMT; 1825 strioc.ic_timout = 0; 1826 strioc.ic_dp = (char *)tcl; 1827 strioc.ic_len = sizeof (*tcl); 1828 if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1) 1829 { 1830 msyslog(LOG_ERR, "PARSE receiver #%d: ioctl(fd, I_STR, PARSEIOC_GETFMT): %m", CLK_UNIT(parse->peer)); 1831 return 0; 1832 } 1833 return 1; 1834 } 1835 1836 /*-------------------------------------------------- 1837 * STREAM setfmt 1838 */ 1839 static int 1840 stream_setfmt( 1841 struct parseunit *parse, 1842 parsectl_t *tcl 1843 ) 1844 { 1845 struct strioctl strioc; 1846 1847 strioc.ic_cmd = PARSEIOC_SETFMT; 1848 strioc.ic_timout = 0; 1849 strioc.ic_dp = (char *)tcl; 1850 strioc.ic_len = sizeof (*tcl); 1851 1852 if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1) 1853 { 1854 msyslog(LOG_ERR, "PARSE receiver #%d: stream_setfmt: ioctl(fd, I_STR, PARSEIOC_SETFMT): %m", CLK_UNIT(parse->peer)); 1855 return 0; 1856 } 1857 return 1; 1858 } 1859 1860 1861 /*-------------------------------------------------- 1862 * STREAM timecode 1863 */ 1864 static int 1865 stream_timecode( 1866 struct parseunit *parse, 1867 parsectl_t *tcl 1868 ) 1869 { 1870 struct strioctl strioc; 1871 1872 strioc.ic_cmd = PARSEIOC_TIMECODE; 1873 strioc.ic_timout = 0; 1874 strioc.ic_dp = (char *)tcl; 1875 strioc.ic_len = sizeof (*tcl); 1876 1877 if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1) 1878 { 1879 ERR(ERR_INTERNAL) 1880 msyslog(LOG_ERR, "PARSE receiver #%d: stream_timecode: ioctl(fd, I_STR, PARSEIOC_TIMECODE): %m", CLK_UNIT(parse->peer)); 1881 return 0; 1882 } 1883 clear_err(parse, ERR_INTERNAL); 1884 return 1; 1885 } 1886 1887 /*-------------------------------------------------- 1888 * STREAM receive 1889 */ 1890 static void 1891 stream_receive( 1892 struct recvbuf *rbufp 1893 ) 1894 { 1895 struct parseunit *parse = (struct parseunit *)((void *)rbufp->recv_srcclock); 1896 parsetime_t parsetime; 1897 1898 if (!parse->peer) 1899 return; 1900 1901 if (rbufp->recv_length != sizeof(parsetime_t)) 1902 { 1903 ERR(ERR_BADIO) 1904 msyslog(LOG_ERR,"PARSE receiver #%d: stream_receive: bad size (got %d expected %d)", 1905 CLK_UNIT(parse->peer), rbufp->recv_length, (int)sizeof(parsetime_t)); 1906 parse_event(parse, CEVNT_BADREPLY); 1907 return; 1908 } 1909 clear_err(parse, ERR_BADIO); 1910 1911 memmove((caddr_t)&parsetime, 1912 (caddr_t)rbufp->recv_buffer, 1913 sizeof(parsetime_t)); 1914 1915 #ifdef DEBUG 1916 if (debug > 3) 1917 { 1918 printf("PARSE receiver #%d: status %06x, state %08x, time %lx.%08lx, stime %lx.%08lx, ptime %lx.%08lx\n", 1919 CLK_UNIT(parse->peer), 1920 (unsigned int)parsetime.parse_status, 1921 (unsigned int)parsetime.parse_state, 1922 (unsigned long)parsetime.parse_time.tv.tv_sec, 1923 (unsigned long)parsetime.parse_time.tv.tv_usec, 1924 (unsigned long)parsetime.parse_stime.tv.tv_sec, 1925 (unsigned long)parsetime.parse_stime.tv.tv_usec, 1926 (unsigned long)parsetime.parse_ptime.tv.tv_sec, 1927 (unsigned long)parsetime.parse_ptime.tv.tv_usec); 1928 } 1929 #endif 1930 1931 /* 1932 * switch time stamp world - be sure to normalize small usec field 1933 * errors. 1934 */ 1935 1936 cvt_ts(parsetime.parse_stime, "parse_stime"); 1937 1938 if (PARSE_TIMECODE(parsetime.parse_state)) 1939 { 1940 cvt_ts(parsetime.parse_time, "parse_time"); 1941 } 1942 1943 if (PARSE_PPS(parsetime.parse_state)) 1944 cvt_ts(parsetime.parse_ptime, "parse_ptime"); 1945 1946 parse_process(parse, &parsetime); 1947 } 1948 #endif 1949 1950 /*-------------------------------------------------- 1951 * local init 1952 */ 1953 static int 1954 local_init( 1955 struct parseunit *parse 1956 ) 1957 { 1958 return parse_ioinit(&parse->parseio); 1959 } 1960 1961 /*-------------------------------------------------- 1962 * local end 1963 */ 1964 static void 1965 local_end( 1966 struct parseunit *parse 1967 ) 1968 { 1969 parse_ioend(&parse->parseio); 1970 } 1971 1972 1973 /*-------------------------------------------------- 1974 * local nop 1975 */ 1976 static int 1977 local_nop( 1978 struct parseunit *parse 1979 ) 1980 { 1981 return 1; 1982 } 1983 1984 /*-------------------------------------------------- 1985 * local setcs 1986 */ 1987 static int 1988 local_setcs( 1989 struct parseunit *parse, 1990 parsectl_t *tcl 1991 ) 1992 { 1993 return parse_setcs(tcl, &parse->parseio); 1994 } 1995 1996 /*-------------------------------------------------- 1997 * local getfmt 1998 */ 1999 static int 2000 local_getfmt( 2001 struct parseunit *parse, 2002 parsectl_t *tcl 2003 ) 2004 { 2005 return parse_getfmt(tcl, &parse->parseio); 2006 } 2007 2008 /*-------------------------------------------------- 2009 * local setfmt 2010 */ 2011 static int 2012 local_setfmt( 2013 struct parseunit *parse, 2014 parsectl_t *tcl 2015 ) 2016 { 2017 return parse_setfmt(tcl, &parse->parseio); 2018 } 2019 2020 /*-------------------------------------------------- 2021 * local timecode 2022 */ 2023 static int 2024 local_timecode( 2025 struct parseunit *parse, 2026 parsectl_t *tcl 2027 ) 2028 { 2029 return parse_timecode(tcl, &parse->parseio); 2030 } 2031 2032 2033 /*-------------------------------------------------- 2034 * local input 2035 */ 2036 static int 2037 local_input( 2038 struct recvbuf *rbufp 2039 ) 2040 { 2041 struct parseunit *parse = (struct parseunit *)((void *)rbufp->recv_srcclock); 2042 int count; 2043 unsigned char *s; 2044 timestamp_t ts; 2045 2046 if (!parse->peer) 2047 return 0; 2048 2049 /* 2050 * eat all characters, parsing then and feeding complete samples 2051 */ 2052 count = rbufp->recv_length; 2053 s = (unsigned char *)rbufp->recv_buffer; 2054 ts.fp = rbufp->recv_time; 2055 2056 while (count--) 2057 { 2058 if (parse_ioread(&parse->parseio, (unsigned int)(*s++), &ts)) 2059 { 2060 struct recvbuf *buf; 2061 2062 /* 2063 * got something good to eat 2064 */ 2065 if (!PARSE_PPS(parse->parseio.parse_dtime.parse_state)) 2066 { 2067 #ifdef HAVE_PPSAPI 2068 if (parse->flags & PARSE_PPSCLOCK) 2069 { 2070 struct timespec pps_timeout; 2071 pps_info_t pps_info; 2072 2073 pps_timeout.tv_sec = 0; 2074 pps_timeout.tv_nsec = 0; 2075 2076 if (time_pps_fetch(parse->ppshandle, PPS_TSFMT_TSPEC, &pps_info, 2077 &pps_timeout) == 0) 2078 { 2079 if (pps_info.assert_sequence + pps_info.clear_sequence != parse->ppsserial) 2080 { 2081 double dtemp; 2082 2083 struct timespec pts; 2084 /* 2085 * add PPS time stamp if available via ppsclock module 2086 * and not supplied already. 2087 */ 2088 if (parse->flags & PARSE_CLEAR) 2089 pts = pps_info.clear_timestamp; 2090 else 2091 pts = pps_info.assert_timestamp; 2092 2093 parse->parseio.parse_dtime.parse_ptime.fp.l_ui = pts.tv_sec + JAN_1970; 2094 2095 dtemp = pts.tv_nsec / 1e9; 2096 if (dtemp < 0.) { 2097 dtemp += 1; 2098 parse->parseio.parse_dtime.parse_ptime.fp.l_ui--; 2099 } 2100 if (dtemp > 1.) { 2101 dtemp -= 1; 2102 parse->parseio.parse_dtime.parse_ptime.fp.l_ui++; 2103 } 2104 parse->parseio.parse_dtime.parse_ptime.fp.l_uf = dtemp * FRAC; 2105 2106 parse->parseio.parse_dtime.parse_state |= PARSEB_PPS|PARSEB_S_PPS; 2107 #ifdef DEBUG 2108 if (debug > 3) 2109 { 2110 printf( 2111 "parse: local_receive: fd %d PPSAPI seq %ld - PPS %s\n", 2112 rbufp->fd, 2113 (long)pps_info.assert_sequence + (long)pps_info.clear_sequence, 2114 lfptoa(&parse->parseio.parse_dtime.parse_ptime.fp, 6)); 2115 } 2116 #endif 2117 } 2118 #ifdef DEBUG 2119 else 2120 { 2121 if (debug > 3) 2122 { 2123 printf( 2124 "parse: local_receive: fd %d PPSAPI seq assert %ld, seq clear %ld - NO PPS event\n", 2125 rbufp->fd, 2126 (long)pps_info.assert_sequence, (long)pps_info.clear_sequence); 2127 } 2128 } 2129 #endif 2130 parse->ppsserial = pps_info.assert_sequence + pps_info.clear_sequence; 2131 } 2132 #ifdef DEBUG 2133 else 2134 { 2135 if (debug > 3) 2136 { 2137 printf( 2138 "parse: local_receive: fd %d PPSAPI time_pps_fetch errno = %d\n", 2139 rbufp->fd, 2140 errno); 2141 } 2142 } 2143 #endif 2144 } 2145 #else 2146 #ifdef TIOCDCDTIMESTAMP 2147 struct timeval dcd_time; 2148 2149 if (ioctl(parse->ppsfd, TIOCDCDTIMESTAMP, &dcd_time) != -1) 2150 { 2151 l_fp tstmp; 2152 2153 TVTOTS(&dcd_time, &tstmp); 2154 tstmp.l_ui += JAN_1970; 2155 L_SUB(&ts.fp, &tstmp); 2156 if (ts.fp.l_ui == 0) 2157 { 2158 #ifdef DEBUG 2159 if (debug) 2160 { 2161 printf( 2162 "parse: local_receive: fd %d DCDTIMESTAMP %s\n", 2163 parse->ppsfd, 2164 lfptoa(&tstmp, 6)); 2165 printf(" sigio %s\n", 2166 lfptoa(&ts.fp, 6)); 2167 } 2168 #endif 2169 parse->parseio.parse_dtime.parse_ptime.fp = tstmp; 2170 parse->parseio.parse_dtime.parse_state |= PARSEB_PPS|PARSEB_S_PPS; 2171 } 2172 } 2173 #else /* TIOCDCDTIMESTAMP */ 2174 #if defined(HAVE_STRUCT_PPSCLOCKEV) && (defined(HAVE_CIOGETEV) || defined(HAVE_TIOCGPPSEV)) 2175 if (parse->flags & PARSE_PPSCLOCK) 2176 { 2177 l_fp tts; 2178 struct ppsclockev ev; 2179 2180 #ifdef HAVE_CIOGETEV 2181 if (ioctl(parse->ppsfd, CIOGETEV, (caddr_t)&ev) == 0) 2182 #endif 2183 #ifdef HAVE_TIOCGPPSEV 2184 if (ioctl(parse->ppsfd, TIOCGPPSEV, (caddr_t)&ev) == 0) 2185 #endif 2186 { 2187 if (ev.serial != parse->ppsserial) 2188 { 2189 /* 2190 * add PPS time stamp if available via ppsclock module 2191 * and not supplied already. 2192 */ 2193 if (!buftvtots((const char *)&ev.tv, &tts)) 2194 { 2195 ERR(ERR_BADDATA) 2196 msyslog(LOG_ERR,"parse: local_receive: timestamp conversion error (buftvtots) (ppsclockev.tv)"); 2197 } 2198 else 2199 { 2200 parse->parseio.parse_dtime.parse_ptime.fp = tts; 2201 parse->parseio.parse_dtime.parse_state |= PARSEB_PPS|PARSEB_S_PPS; 2202 } 2203 } 2204 parse->ppsserial = ev.serial; 2205 } 2206 } 2207 #endif 2208 #endif /* TIOCDCDTIMESTAMP */ 2209 #endif /* !HAVE_PPSAPI */ 2210 } 2211 if (count) 2212 { /* simulate receive */ 2213 buf = get_free_recv_buffer(); 2214 if (buf != NULL) { 2215 memmove((caddr_t)buf->recv_buffer, 2216 (caddr_t)&parse->parseio.parse_dtime, 2217 sizeof(parsetime_t)); 2218 buf->recv_length = sizeof(parsetime_t); 2219 buf->recv_time = rbufp->recv_time; 2220 buf->srcadr = rbufp->srcadr; 2221 buf->dstadr = rbufp->dstadr; 2222 buf->receiver = rbufp->receiver; 2223 buf->fd = rbufp->fd; 2224 buf->X_from_where = rbufp->X_from_where; 2225 add_full_recv_buffer(buf); 2226 } 2227 parse_iodone(&parse->parseio); 2228 } 2229 else 2230 { 2231 memmove((caddr_t)rbufp->recv_buffer, 2232 (caddr_t)&parse->parseio.parse_dtime, 2233 sizeof(parsetime_t)); 2234 parse_iodone(&parse->parseio); 2235 rbufp->recv_length = sizeof(parsetime_t); 2236 return 1; /* got something & in place return */ 2237 } 2238 } 2239 } 2240 return 0; /* nothing to pass up */ 2241 } 2242 2243 /*-------------------------------------------------- 2244 * local receive 2245 */ 2246 static void 2247 local_receive( 2248 struct recvbuf *rbufp 2249 ) 2250 { 2251 struct parseunit *parse = (struct parseunit *)((void *)rbufp->recv_srcclock); 2252 parsetime_t parsetime; 2253 2254 if (!parse->peer) 2255 return; 2256 2257 if (rbufp->recv_length != sizeof(parsetime_t)) 2258 { 2259 ERR(ERR_BADIO) 2260 msyslog(LOG_ERR,"PARSE receiver #%d: local_receive: bad size (got %d expected %d)", 2261 CLK_UNIT(parse->peer), rbufp->recv_length, (int)sizeof(parsetime_t)); 2262 parse_event(parse, CEVNT_BADREPLY); 2263 return; 2264 } 2265 clear_err(parse, ERR_BADIO); 2266 2267 memmove((caddr_t)&parsetime, 2268 (caddr_t)rbufp->recv_buffer, 2269 sizeof(parsetime_t)); 2270 2271 #ifdef DEBUG 2272 if (debug > 3) 2273 { 2274 printf("PARSE receiver #%d: status %06x, state %08x, time(fp) %lx.%08lx, stime(fp) %lx.%08lx, ptime(fp) %lx.%08lx\n", 2275 CLK_UNIT(parse->peer), 2276 (unsigned int)parsetime.parse_status, 2277 (unsigned int)parsetime.parse_state, 2278 (unsigned long)parsetime.parse_time.fp.l_ui, 2279 (unsigned long)parsetime.parse_time.fp.l_uf, 2280 (unsigned long)parsetime.parse_stime.fp.l_ui, 2281 (unsigned long)parsetime.parse_stime.fp.l_uf, 2282 (unsigned long)parsetime.parse_ptime.fp.l_ui, 2283 (unsigned long)parsetime.parse_ptime.fp.l_uf); 2284 } 2285 #endif 2286 2287 parse_process(parse, &parsetime); 2288 } 2289 2290 /*-------------------------------------------------- 2291 * init_iobinding - find and initialize lower layers 2292 */ 2293 static bind_t * 2294 init_iobinding( 2295 struct parseunit *parse 2296 ) 2297 { 2298 bind_t *b = io_bindings; 2299 2300 while (b->bd_description != (char *)0) 2301 { 2302 if ((*b->bd_init)(parse)) 2303 { 2304 return b; 2305 } 2306 b++; 2307 } 2308 return (bind_t *)0; 2309 } 2310 2311 /**=========================================================================== 2312 ** support routines 2313 **/ 2314 2315 /*-------------------------------------------------- 2316 * convert a flag field to a string 2317 */ 2318 static char * 2319 parsestate( 2320 u_long lstate, 2321 char *buffer, 2322 int size 2323 ) 2324 { 2325 static struct bits 2326 { 2327 u_long bit; 2328 const char *name; 2329 } flagstrings[] = 2330 { 2331 { PARSEB_ANNOUNCE, "DST SWITCH WARNING" }, 2332 { PARSEB_POWERUP, "NOT SYNCHRONIZED" }, 2333 { PARSEB_NOSYNC, "TIME CODE NOT CONFIRMED" }, 2334 { PARSEB_DST, "DST" }, 2335 { PARSEB_UTC, "UTC DISPLAY" }, 2336 { PARSEB_LEAPADD, "LEAP ADD WARNING" }, 2337 { PARSEB_LEAPDEL, "LEAP DELETE WARNING" }, 2338 { PARSEB_LEAPSECOND, "LEAP SECOND" }, 2339 { PARSEB_ALTERNATE, "ALTERNATE ANTENNA" }, 2340 { PARSEB_TIMECODE, "TIME CODE" }, 2341 { PARSEB_PPS, "PPS" }, 2342 { PARSEB_POSITION, "POSITION" }, 2343 { 0 } 2344 }; 2345 2346 static struct sbits 2347 { 2348 u_long bit; 2349 const char *name; 2350 } sflagstrings[] = 2351 { 2352 { PARSEB_S_LEAP, "LEAP INDICATION" }, 2353 { PARSEB_S_PPS, "PPS SIGNAL" }, 2354 { PARSEB_S_ANTENNA, "ANTENNA" }, 2355 { PARSEB_S_POSITION, "POSITION" }, 2356 { 0 } 2357 }; 2358 int i; 2359 char *s, *t; 2360 2361 2362 *buffer = '\0'; 2363 s = t = buffer; 2364 2365 i = 0; 2366 while (flagstrings[i].bit) 2367 { 2368 if (flagstrings[i].bit & lstate) 2369 { 2370 if (s != t) 2371 strncpy(t, "; ", BUFFER_SIZES(buffer, t, size)); 2372 strncat(t, flagstrings[i].name, BUFFER_SIZES(buffer, t, size)); 2373 t += strlen(t); 2374 } 2375 i++; 2376 } 2377 2378 if (lstate & (PARSEB_S_LEAP|PARSEB_S_ANTENNA|PARSEB_S_PPS|PARSEB_S_POSITION)) 2379 { 2380 if (s != t) 2381 strncpy(t, "; ", BUFFER_SIZES(buffer, t, size)); 2382 2383 t += strlen(t); 2384 2385 strncpy(t, "(", BUFFER_SIZES(buffer, t, size)); 2386 2387 s = t = t + strlen(t); 2388 2389 i = 0; 2390 while (sflagstrings[i].bit) 2391 { 2392 if (sflagstrings[i].bit & lstate) 2393 { 2394 if (t != s) 2395 { 2396 strncpy(t, "; ", BUFFER_SIZES(buffer, t, size)); 2397 t += 2; 2398 } 2399 2400 strncpy(t, sflagstrings[i].name, BUFFER_SIZES(buffer, t, size)); 2401 t += strlen(t); 2402 } 2403 i++; 2404 } 2405 strncpy(t, ")", BUFFER_SIZES(buffer, t, size)); 2406 } 2407 return buffer; 2408 } 2409 2410 /*-------------------------------------------------- 2411 * convert a status flag field to a string 2412 */ 2413 static char * 2414 parsestatus( 2415 u_long lstate, 2416 char *buffer, 2417 int size 2418 ) 2419 { 2420 static struct bits 2421 { 2422 u_long bit; 2423 const char *name; 2424 } flagstrings[] = 2425 { 2426 { CVT_OK, "CONVERSION SUCCESSFUL" }, 2427 { CVT_NONE, "NO CONVERSION" }, 2428 { CVT_FAIL, "CONVERSION FAILED" }, 2429 { CVT_BADFMT, "ILLEGAL FORMAT" }, 2430 { CVT_BADDATE, "DATE ILLEGAL" }, 2431 { CVT_BADTIME, "TIME ILLEGAL" }, 2432 { CVT_ADDITIONAL, "ADDITIONAL DATA" }, 2433 { 0 } 2434 }; 2435 int i; 2436 2437 *buffer = '\0'; 2438 2439 i = 0; 2440 while (flagstrings[i].bit) 2441 { 2442 if (flagstrings[i].bit & lstate) 2443 { 2444 if (buffer[0]) 2445 strncat(buffer, "; ", size); 2446 strncat(buffer, flagstrings[i].name, size); 2447 } 2448 i++; 2449 } 2450 2451 return buffer; 2452 } 2453 2454 /*-------------------------------------------------- 2455 * convert a clock status flag field to a string 2456 */ 2457 static const char * 2458 clockstatus( 2459 u_long lstate 2460 ) 2461 { 2462 static char buffer[20]; 2463 static struct status 2464 { 2465 u_long value; 2466 const char *name; 2467 } flagstrings[] = 2468 { 2469 { CEVNT_NOMINAL, "NOMINAL" }, 2470 { CEVNT_TIMEOUT, "NO RESPONSE" }, 2471 { CEVNT_BADREPLY,"BAD FORMAT" }, 2472 { CEVNT_FAULT, "FAULT" }, 2473 { CEVNT_PROP, "PROPAGATION DELAY" }, 2474 { CEVNT_BADDATE, "ILLEGAL DATE" }, 2475 { CEVNT_BADTIME, "ILLEGAL TIME" }, 2476 { (unsigned)~0L } 2477 }; 2478 int i; 2479 2480 i = 0; 2481 while (flagstrings[i].value != ~0) 2482 { 2483 if (flagstrings[i].value == lstate) 2484 { 2485 return flagstrings[i].name; 2486 } 2487 i++; 2488 } 2489 2490 snprintf(buffer, sizeof(buffer), "unknown #%ld", (u_long)lstate); 2491 2492 return buffer; 2493 } 2494 2495 2496 /*-------------------------------------------------- 2497 * l_mktime - make representation of a relative time 2498 */ 2499 static char * 2500 l_mktime( 2501 u_long delta 2502 ) 2503 { 2504 u_long tmp, m, s; 2505 static char buffer[40]; 2506 char *t; 2507 2508 buffer[0] = '\0'; 2509 2510 if ((tmp = delta / (60*60*24)) != 0) 2511 { 2512 snprintf(buffer, BUFFER_SIZE(buffer, buffer), "%ldd+", (u_long)tmp); 2513 delta -= tmp * 60*60*24; 2514 } 2515 2516 s = delta % 60; 2517 delta /= 60; 2518 m = delta % 60; 2519 delta /= 60; 2520 2521 t = buffer + strlen(buffer); 2522 2523 snprintf(t, BUFFER_SIZE(buffer, t), "%02d:%02d:%02d", 2524 (int)delta, (int)m, (int)s); 2525 2526 return buffer; 2527 } 2528 2529 2530 /*-------------------------------------------------- 2531 * parse_statistics - list summary of clock states 2532 */ 2533 static void 2534 parse_statistics( 2535 struct parseunit *parse 2536 ) 2537 { 2538 int i; 2539 2540 NLOG(NLOG_CLOCKSTATIST) /* conditional if clause for conditional syslog */ 2541 { 2542 msyslog(LOG_INFO, "PARSE receiver #%d: running time: %s", 2543 CLK_UNIT(parse->peer), 2544 l_mktime(current_time - parse->generic->timestarted)); 2545 2546 msyslog(LOG_INFO, "PARSE receiver #%d: current status: %s", 2547 CLK_UNIT(parse->peer), 2548 clockstatus(parse->generic->currentstatus)); 2549 2550 for (i = 0; i <= CEVNT_MAX; i++) 2551 { 2552 u_long s_time; 2553 u_long percent, d = current_time - parse->generic->timestarted; 2554 2555 percent = s_time = PARSE_STATETIME(parse, i); 2556 2557 while (((u_long)(~0) / 10000) < percent) 2558 { 2559 percent /= 10; 2560 d /= 10; 2561 } 2562 2563 if (d) 2564 percent = (percent * 10000) / d; 2565 else 2566 percent = 10000; 2567 2568 if (s_time) 2569 msyslog(LOG_INFO, "PARSE receiver #%d: state %18s: %13s (%3ld.%02ld%%)", 2570 CLK_UNIT(parse->peer), 2571 clockstatus((unsigned int)i), 2572 l_mktime(s_time), 2573 percent / 100, percent % 100); 2574 } 2575 } 2576 } 2577 2578 /*-------------------------------------------------- 2579 * cparse_statistics - wrapper for statistics call 2580 */ 2581 static void 2582 cparse_statistics( 2583 struct parseunit *parse 2584 ) 2585 { 2586 if (parse->laststatistic + PARSESTATISTICS < current_time) 2587 parse_statistics(parse); 2588 parse->laststatistic = current_time; 2589 } 2590 2591 /**=========================================================================== 2592 ** ntp interface routines 2593 **/ 2594 2595 /*-------------------------------------------------- 2596 * parse_shutdown - shut down a PARSE clock 2597 */ 2598 static void 2599 parse_shutdown( 2600 int unit, 2601 struct peer *peer 2602 ) 2603 { 2604 struct parseunit *parse = (struct parseunit *)0; 2605 2606 if (peer && peer->procptr) 2607 parse = (struct parseunit *)peer->procptr->unitptr; 2608 2609 if (!parse) 2610 { 2611 /* nothing to clean up */ 2612 return; 2613 } 2614 2615 if (!parse->peer) 2616 { 2617 msyslog(LOG_INFO, "PARSE receiver #%d: INTERNAL ERROR - unit already inactive - shutdown ignored", unit); 2618 return; 2619 } 2620 2621 #ifdef HAVE_PPSAPI 2622 if (parse->flags & PARSE_PPSCLOCK) 2623 { 2624 (void)time_pps_destroy(parse->ppshandle); 2625 } 2626 #endif 2627 if (parse->generic->io.fd != parse->ppsfd && parse->ppsfd != -1) 2628 (void)close(parse->ppsfd); /* close separate PPS source */ 2629 2630 /* 2631 * print statistics a last time and 2632 * stop statistics machine 2633 */ 2634 parse_statistics(parse); 2635 2636 if (parse->parse_type->cl_end) 2637 { 2638 parse->parse_type->cl_end(parse); 2639 } 2640 2641 /* 2642 * cleanup before leaving this world 2643 */ 2644 if (parse->binding) 2645 PARSE_END(parse); 2646 2647 /* 2648 * Tell the I/O module to turn us off. We're history. 2649 */ 2650 io_closeclock(&parse->generic->io); 2651 2652 free_varlist(parse->kv); 2653 2654 NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */ 2655 msyslog(LOG_INFO, "PARSE receiver #%d: reference clock \"%s\" removed", 2656 CLK_UNIT(parse->peer), parse->parse_type->cl_description); 2657 2658 parse->peer = (struct peer *)0; /* unused now */ 2659 peer->procptr->unitptr = (caddr_t)0; 2660 free(parse); 2661 } 2662 2663 #ifdef HAVE_PPSAPI 2664 /*---------------------------------------- 2665 * set up HARDPPS via PPSAPI 2666 */ 2667 static void 2668 parse_hardpps( 2669 struct parseunit *parse, 2670 int mode 2671 ) 2672 { 2673 if (parse->hardppsstate == mode) 2674 return; 2675 2676 if (CLK_PPS(parse->peer) && (parse->flags & PARSE_PPSKERNEL)) { 2677 int i = 0; 2678 2679 if (mode == PARSE_HARDPPS_ENABLE) 2680 { 2681 if (parse->flags & PARSE_CLEAR) 2682 i = PPS_CAPTURECLEAR; 2683 else 2684 i = PPS_CAPTUREASSERT; 2685 } 2686 2687 if (time_pps_kcbind(parse->ppshandle, PPS_KC_HARDPPS, i, 2688 PPS_TSFMT_TSPEC) < 0) { 2689 msyslog(LOG_ERR, "PARSE receiver #%d: time_pps_kcbind failed: %m", 2690 CLK_UNIT(parse->peer)); 2691 } else { 2692 NLOG(NLOG_CLOCKINFO) 2693 msyslog(LOG_INFO, "PARSE receiver #%d: kernel PPS synchronisation %sabled", 2694 CLK_UNIT(parse->peer), (mode == PARSE_HARDPPS_ENABLE) ? "en" : "dis"); 2695 /* 2696 * tell the rest, that we have a kernel PPS source, iff we ever enable HARDPPS 2697 */ 2698 if (mode == PARSE_HARDPPS_ENABLE) 2699 pps_enable = 1; 2700 } 2701 } 2702 2703 parse->hardppsstate = mode; 2704 } 2705 2706 /*---------------------------------------- 2707 * set up PPS via PPSAPI 2708 */ 2709 static int 2710 parse_ppsapi( 2711 struct parseunit *parse 2712 ) 2713 { 2714 int cap, mode, mode1; 2715 char *cp; 2716 2717 parse->flags &= ~PARSE_PPSCLOCK; 2718 2719 if (time_pps_getcap(parse->ppshandle, &cap) < 0) { 2720 msyslog(LOG_ERR, "PARSE receiver #%d: parse_ppsapi: time_pps_getcap failed: %m", 2721 CLK_UNIT(parse->peer)); 2722 2723 return 0; 2724 } 2725 2726 if (time_pps_getparams(parse->ppshandle, &parse->ppsparams) < 0) { 2727 msyslog(LOG_ERR, "PARSE receiver #%d: parse_ppsapi: time_pps_getparams failed: %m", 2728 CLK_UNIT(parse->peer)); 2729 return 0; 2730 } 2731 2732 /* nb. only turn things on, if someone else has turned something 2733 * on before we get here, leave it alone! 2734 */ 2735 2736 if (parse->flags & PARSE_CLEAR) { 2737 cp = "CLEAR"; 2738 mode = PPS_CAPTURECLEAR; 2739 mode1 = PPS_OFFSETCLEAR; 2740 } else { 2741 cp = "ASSERT"; 2742 mode = PPS_CAPTUREASSERT; 2743 mode1 = PPS_OFFSETASSERT; 2744 } 2745 2746 msyslog(LOG_INFO, "PARSE receiver #%d: initializing PPS to %s", 2747 CLK_UNIT(parse->peer), cp); 2748 2749 if (!(mode & cap)) { 2750 msyslog(LOG_ERR, "PARSE receiver #%d: FAILED to initialize PPS to %s (PPS API capabilities=0x%x)", 2751 CLK_UNIT(parse->peer), cp, cap); 2752 2753 return 0; 2754 } 2755 2756 if (!(mode1 & cap)) { 2757 msyslog(LOG_WARNING, "PARSE receiver #%d: Cannot set PPS_%sCLEAR, this will increase jitter (PPS API capabilities=0x%x)", 2758 CLK_UNIT(parse->peer), cp, cap); 2759 mode1 = 0; 2760 } else { 2761 if (mode1 == PPS_OFFSETCLEAR) 2762 { 2763 parse->ppsparams.clear_offset.tv_sec = -parse->ppsphaseadjust; 2764 parse->ppsparams.clear_offset.tv_nsec = -1e9*(parse->ppsphaseadjust - (long)parse->ppsphaseadjust); 2765 } 2766 2767 if (mode1 == PPS_OFFSETASSERT) 2768 { 2769 parse->ppsparams.assert_offset.tv_sec = -parse->ppsphaseadjust; 2770 parse->ppsparams.assert_offset.tv_nsec = -1e9*(parse->ppsphaseadjust - (long)parse->ppsphaseadjust); 2771 } 2772 } 2773 2774 /* only set what is legal */ 2775 2776 parse->ppsparams.mode = (mode | mode1 | PPS_TSFMT_TSPEC) & cap; 2777 2778 if (time_pps_setparams(parse->ppshandle, &parse->ppsparams) < 0) { 2779 msyslog(LOG_ERR, "PARSE receiver #%d: FAILED set PPS parameters: %m", 2780 CLK_UNIT(parse->peer)); 2781 return 0; 2782 } 2783 2784 parse->flags |= PARSE_PPSCLOCK; 2785 return 1; 2786 } 2787 #else 2788 #define parse_hardpps(_PARSE_, _MODE_) /* empty */ 2789 #endif 2790 2791 /*-------------------------------------------------- 2792 * parse_start - open the PARSE devices and initialize data for processing 2793 */ 2794 static int 2795 parse_start( 2796 int sysunit, 2797 struct peer *peer 2798 ) 2799 { 2800 u_int unit; 2801 int fd232; 2802 #ifdef HAVE_TERMIOS 2803 struct termios tio; /* NEEDED FOR A LONG TIME ! */ 2804 #endif 2805 #ifdef HAVE_SYSV_TTYS 2806 struct termio tio; /* NEEDED FOR A LONG TIME ! */ 2807 #endif 2808 struct parseunit * parse; 2809 char parsedev[sizeof(PARSEDEVICE)+20]; 2810 char parseppsdev[sizeof(PARSEPPSDEVICE)+20]; 2811 parsectl_t tmp_ctl; 2812 u_int type; 2813 2814 /* 2815 * get out Copyright information once 2816 */ 2817 if (!notice) 2818 { 2819 NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */ 2820 msyslog(LOG_INFO, "NTP PARSE support: Copyright (c) 1989-2006, Frank Kardel"); 2821 notice = 1; 2822 } 2823 2824 type = CLK_TYPE(peer); 2825 unit = CLK_UNIT(peer); 2826 2827 if ((type == ~0) || (parse_clockinfo[type].cl_description == (char *)0)) 2828 { 2829 msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: unsupported clock type %d (max %d)", 2830 unit, CLK_REALTYPE(peer), ncltypes-1); 2831 return 0; 2832 } 2833 2834 /* 2835 * Unit okay, attempt to open the device. 2836 */ 2837 (void) snprintf(parsedev, sizeof(parsedev), PARSEDEVICE, unit); 2838 (void) snprintf(parseppsdev, sizeof(parsedev), PARSEPPSDEVICE, unit); 2839 2840 #ifndef O_NOCTTY 2841 #define O_NOCTTY 0 2842 #endif 2843 2844 fd232 = open(parsedev, O_RDWR | O_NOCTTY 2845 #ifdef O_NONBLOCK 2846 | O_NONBLOCK 2847 #endif 2848 , 0777); 2849 2850 if (fd232 == -1) 2851 { 2852 msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: open of %s failed: %m", unit, parsedev); 2853 return 0; 2854 } 2855 2856 parse = (struct parseunit *)emalloc(sizeof(struct parseunit)); 2857 2858 memset((char *)parse, 0, sizeof(struct parseunit)); 2859 2860 parse->generic = peer->procptr; /* link up */ 2861 parse->generic->unitptr = (caddr_t)parse; /* link down */ 2862 2863 /* 2864 * Set up the structures 2865 */ 2866 parse->generic->timestarted = current_time; 2867 parse->lastchange = current_time; 2868 2869 parse->flags = 0; 2870 parse->pollneeddata = 0; 2871 parse->laststatistic = current_time; 2872 parse->lastformat = (unsigned short)~0; /* assume no format known */ 2873 parse->timedata.parse_status = (unsigned short)~0; /* be sure to mark initial status change */ 2874 parse->lastmissed = 0; /* assume got everything */ 2875 parse->ppsserial = 0; 2876 parse->ppsfd = -1; 2877 parse->localdata = (void *)0; 2878 parse->localstate = 0; 2879 parse->kv = (struct ctl_var *)0; 2880 2881 clear_err(parse, ERR_ALL); 2882 2883 parse->parse_type = &parse_clockinfo[type]; 2884 2885 parse->maxunsync = parse->parse_type->cl_maxunsync; 2886 2887 parse->generic->fudgetime1 = parse->parse_type->cl_basedelay; 2888 2889 parse->generic->fudgetime2 = 0.0; 2890 parse->ppsphaseadjust = parse->generic->fudgetime2; 2891 2892 parse->generic->clockdesc = parse->parse_type->cl_description; 2893 2894 peer->rootdelay = parse->parse_type->cl_rootdelay; 2895 peer->sstclktype = parse->parse_type->cl_type; 2896 peer->precision = sys_precision; 2897 2898 peer->stratum = STRATUM_REFCLOCK; 2899 2900 if (peer->stratum <= 1) 2901 memmove((char *)&parse->generic->refid, parse->parse_type->cl_id, 4); 2902 else 2903 parse->generic->refid = htonl(PARSEHSREFID); 2904 2905 parse->generic->io.fd = fd232; 2906 2907 parse->peer = peer; /* marks it also as busy */ 2908 2909 /* 2910 * configure terminal line 2911 */ 2912 if (TTY_GETATTR(fd232, &tio) == -1) 2913 { 2914 msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: tcgetattr(%d, &tio): %m", unit, fd232); 2915 parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */ 2916 return 0; 2917 } 2918 else 2919 { 2920 #ifndef _PC_VDISABLE 2921 memset((char *)tio.c_cc, 0, sizeof(tio.c_cc)); 2922 #else 2923 int disablec; 2924 errno = 0; /* pathconf can deliver -1 without changing errno ! */ 2925 2926 disablec = fpathconf(parse->generic->io.fd, _PC_VDISABLE); 2927 if (disablec == -1 && errno) 2928 { 2929 msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: fpathconf(fd, _PC_VDISABLE): %m", CLK_UNIT(parse->peer)); 2930 memset((char *)tio.c_cc, 0, sizeof(tio.c_cc)); /* best guess */ 2931 } 2932 else 2933 if (disablec != -1) 2934 memset((char *)tio.c_cc, disablec, sizeof(tio.c_cc)); 2935 #endif 2936 2937 #if defined (VMIN) || defined(VTIME) 2938 if ((parse_clockinfo[type].cl_lflag & ICANON) == 0) 2939 { 2940 #ifdef VMIN 2941 tio.c_cc[VMIN] = 1; 2942 #endif 2943 #ifdef VTIME 2944 tio.c_cc[VTIME] = 0; 2945 #endif 2946 } 2947 #endif 2948 2949 tio.c_cflag = parse_clockinfo[type].cl_cflag; 2950 tio.c_iflag = parse_clockinfo[type].cl_iflag; 2951 tio.c_oflag = parse_clockinfo[type].cl_oflag; 2952 tio.c_lflag = parse_clockinfo[type].cl_lflag; 2953 2954 2955 #ifdef HAVE_TERMIOS 2956 if ((cfsetospeed(&tio, parse_clockinfo[type].cl_speed) == -1) || 2957 (cfsetispeed(&tio, parse_clockinfo[type].cl_speed) == -1)) 2958 { 2959 msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: tcset{i,o}speed(&tio, speed): %m", unit); 2960 parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */ 2961 return 0; 2962 } 2963 #else 2964 tio.c_cflag |= parse_clockinfo[type].cl_speed; 2965 #endif 2966 2967 /* 2968 * set up pps device 2969 * if the PARSEPPSDEVICE can be opened that will be used 2970 * for PPS else PARSEDEVICE will be used 2971 */ 2972 parse->ppsfd = open(parseppsdev, O_RDWR | O_NOCTTY 2973 #ifdef O_NONBLOCK 2974 | O_NONBLOCK 2975 #endif 2976 , 0777); 2977 2978 if (parse->ppsfd == -1) 2979 { 2980 parse->ppsfd = fd232; 2981 } 2982 2983 /* 2984 * Linux PPS - the old way 2985 */ 2986 #if defined(HAVE_TIO_SERIAL_STUFF) /* Linux hack: define PPS interface */ 2987 { 2988 struct serial_struct ss; 2989 if (ioctl(parse->ppsfd, TIOCGSERIAL, &ss) < 0 || 2990 ( 2991 #ifdef ASYNC_LOW_LATENCY 2992 ss.flags |= ASYNC_LOW_LATENCY, 2993 #endif 2994 #ifndef HAVE_PPSAPI 2995 #ifdef ASYNC_PPS_CD_NEG 2996 ss.flags |= ASYNC_PPS_CD_NEG, 2997 #endif 2998 #endif 2999 ioctl(parse->ppsfd, TIOCSSERIAL, &ss)) < 0) { 3000 msyslog(LOG_NOTICE, "refclock_parse: TIOCSSERIAL fd %d, %m", parse->ppsfd); 3001 msyslog(LOG_NOTICE, 3002 "refclock_parse: optional PPS processing not available"); 3003 } else { 3004 parse->flags |= PARSE_PPSCLOCK; 3005 #ifdef ASYNC_PPS_CD_NEG 3006 NLOG(NLOG_CLOCKINFO) 3007 msyslog(LOG_INFO, 3008 "refclock_parse: PPS detection on"); 3009 #endif 3010 } 3011 } 3012 #endif 3013 3014 /* 3015 * SUN the Solaris way 3016 */ 3017 #ifdef HAVE_TIOCSPPS /* SUN PPS support */ 3018 if (CLK_PPS(parse->peer)) 3019 { 3020 int i = 1; 3021 3022 if (ioctl(parse->ppsfd, TIOCSPPS, (caddr_t)&i) == 0) 3023 { 3024 parse->flags |= PARSE_PPSCLOCK; 3025 } 3026 } 3027 #endif 3028 3029 /* 3030 * PPS via PPSAPI 3031 */ 3032 #if defined(HAVE_PPSAPI) 3033 parse->hardppsstate = PARSE_HARDPPS_DISABLE; 3034 if (CLK_PPS(parse->peer)) 3035 { 3036 if (time_pps_create(parse->ppsfd, &parse->ppshandle) < 0) 3037 { 3038 msyslog(LOG_NOTICE, "PARSE receiver #%d: parse_start: could not set up PPS: %m", CLK_UNIT(parse->peer)); 3039 } 3040 else 3041 { 3042 parse_ppsapi(parse); 3043 } 3044 } 3045 #endif 3046 3047 if (TTY_SETATTR(fd232, &tio) == -1) 3048 { 3049 msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: tcsetattr(%d, &tio): %m", unit, fd232); 3050 parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */ 3051 return 0; 3052 } 3053 } 3054 3055 /* 3056 * pick correct input machine 3057 */ 3058 parse->generic->io.srcclock = (caddr_t)parse; 3059 parse->generic->io.datalen = 0; 3060 3061 parse->binding = init_iobinding(parse); 3062 3063 if (parse->binding == (bind_t *)0) 3064 { 3065 msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: io sub system initialisation failed.", CLK_UNIT(parse->peer)); 3066 parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */ 3067 return 0; /* well, ok - special initialisation broke */ 3068 } 3069 3070 parse->generic->io.clock_recv = parse->binding->bd_receive; /* pick correct receive routine */ 3071 parse->generic->io.io_input = parse->binding->bd_io_input; /* pick correct input routine */ 3072 3073 /* 3074 * as we always(?) get 8 bit chars we want to be 3075 * sure, that the upper bits are zero for less 3076 * than 8 bit I/O - so we pass that information on. 3077 * note that there can be only one bit count format 3078 * per file descriptor 3079 */ 3080 3081 switch (tio.c_cflag & CSIZE) 3082 { 3083 case CS5: 3084 tmp_ctl.parsesetcs.parse_cs = PARSE_IO_CS5; 3085 break; 3086 3087 case CS6: 3088 tmp_ctl.parsesetcs.parse_cs = PARSE_IO_CS6; 3089 break; 3090 3091 case CS7: 3092 tmp_ctl.parsesetcs.parse_cs = PARSE_IO_CS7; 3093 break; 3094 3095 case CS8: 3096 tmp_ctl.parsesetcs.parse_cs = PARSE_IO_CS8; 3097 break; 3098 } 3099 3100 if (!PARSE_SETCS(parse, &tmp_ctl)) 3101 { 3102 msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: parse_setcs() FAILED.", unit); 3103 parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */ 3104 return 0; /* well, ok - special initialisation broke */ 3105 } 3106 3107 strncpy(tmp_ctl.parseformat.parse_buffer, parse->parse_type->cl_format, sizeof(tmp_ctl.parseformat.parse_buffer)); 3108 tmp_ctl.parseformat.parse_count = strlen(tmp_ctl.parseformat.parse_buffer); 3109 3110 if (!PARSE_SETFMT(parse, &tmp_ctl)) 3111 { 3112 msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: parse_setfmt() FAILED.", unit); 3113 parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */ 3114 return 0; /* well, ok - special initialisation broke */ 3115 } 3116 3117 /* 3118 * get rid of all IO accumulated so far 3119 */ 3120 #ifdef HAVE_TERMIOS 3121 (void) tcflush(parse->generic->io.fd, TCIOFLUSH); 3122 #else 3123 #if defined(TCFLSH) && defined(TCIOFLUSH) 3124 { 3125 int flshcmd = TCIOFLUSH; 3126 3127 (void) ioctl(parse->generic->io.fd, TCFLSH, (caddr_t)&flshcmd); 3128 } 3129 #endif 3130 #endif 3131 3132 /* 3133 * try to do any special initializations 3134 */ 3135 if (parse->parse_type->cl_init) 3136 { 3137 if (parse->parse_type->cl_init(parse)) 3138 { 3139 parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */ 3140 return 0; /* well, ok - special initialisation broke */ 3141 } 3142 } 3143 3144 /* 3145 * Insert in async io device list. 3146 */ 3147 if (!io_addclock(&parse->generic->io)) 3148 { 3149 msyslog(LOG_ERR, 3150 "PARSE receiver #%d: parse_start: addclock %s fails (ABORT - clock type requires async io)", CLK_UNIT(parse->peer), parsedev); 3151 parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */ 3152 return 0; 3153 } 3154 3155 /* 3156 * print out configuration 3157 */ 3158 NLOG(NLOG_CLOCKINFO) 3159 { 3160 /* conditional if clause for conditional syslog */ 3161 msyslog(LOG_INFO, "PARSE receiver #%d: reference clock \"%s\" (I/O device %s, PPS device %s) added", 3162 CLK_UNIT(parse->peer), 3163 parse->parse_type->cl_description, parsedev, 3164 (parse->ppsfd != parse->generic->io.fd) ? parseppsdev : parsedev); 3165 3166 msyslog(LOG_INFO, "PARSE receiver #%d: Stratum %d, trust time %s, precision %d", 3167 CLK_UNIT(parse->peer), 3168 parse->peer->stratum, 3169 l_mktime(parse->maxunsync), parse->peer->precision); 3170 3171 msyslog(LOG_INFO, "PARSE receiver #%d: rootdelay %.6f s, phase adjustment %.6f s, PPS phase adjustment %.6f s, %s IO handling", 3172 CLK_UNIT(parse->peer), 3173 parse->parse_type->cl_rootdelay, 3174 parse->generic->fudgetime1, 3175 parse->ppsphaseadjust, 3176 parse->binding->bd_description); 3177 3178 msyslog(LOG_INFO, "PARSE receiver #%d: Format recognition: %s", CLK_UNIT(parse->peer), 3179 parse->parse_type->cl_format); 3180 msyslog(LOG_INFO, "PARSE receiver #%d: %sPPS support%s", CLK_UNIT(parse->peer), 3181 CLK_PPS(parse->peer) ? "" : "NO ", 3182 CLK_PPS(parse->peer) ? 3183 #ifdef PPS_METHOD 3184 " (implementation " PPS_METHOD ")" 3185 #else 3186 "" 3187 #endif 3188 : "" 3189 ); 3190 } 3191 3192 return 1; 3193 } 3194 3195 /*-------------------------------------------------- 3196 * parse_ctl - process changes on flags/time values 3197 */ 3198 static void 3199 parse_ctl( 3200 struct parseunit *parse, 3201 struct refclockstat *in 3202 ) 3203 { 3204 if (in) 3205 { 3206 if (in->haveflags & (CLK_HAVEFLAG1|CLK_HAVEFLAG2|CLK_HAVEFLAG3|CLK_HAVEFLAG4)) 3207 { 3208 parse->flags = (parse->flags & ~(CLK_FLAG1|CLK_FLAG2|CLK_FLAG3|CLK_FLAG4)) | 3209 (in->flags & (CLK_FLAG1|CLK_FLAG2|CLK_FLAG3|CLK_FLAG4)); 3210 #if defined(HAVE_PPSAPI) 3211 if (CLK_PPS(parse->peer)) 3212 { 3213 parse_ppsapi(parse); 3214 } 3215 #endif 3216 } 3217 3218 if (in->haveflags & CLK_HAVETIME1) 3219 { 3220 parse->generic->fudgetime1 = in->fudgetime1; 3221 msyslog(LOG_INFO, "PARSE receiver #%d: new phase adjustment %.6f s", 3222 CLK_UNIT(parse->peer), 3223 parse->generic->fudgetime1); 3224 } 3225 3226 if (in->haveflags & CLK_HAVETIME2) 3227 { 3228 parse->generic->fudgetime2 = in->fudgetime2; 3229 if (parse->flags & PARSE_TRUSTTIME) 3230 { 3231 parse->maxunsync = (u_long)ABS(in->fudgetime2); 3232 msyslog(LOG_INFO, "PARSE receiver #%d: new trust time %s", 3233 CLK_UNIT(parse->peer), 3234 l_mktime(parse->maxunsync)); 3235 } 3236 else 3237 { 3238 parse->ppsphaseadjust = in->fudgetime2; 3239 msyslog(LOG_INFO, "PARSE receiver #%d: new PPS phase adjustment %.6f s", 3240 CLK_UNIT(parse->peer), 3241 parse->ppsphaseadjust); 3242 #if defined(HAVE_PPSAPI) 3243 if (CLK_PPS(parse->peer)) 3244 { 3245 parse_ppsapi(parse); 3246 } 3247 #endif 3248 } 3249 } 3250 } 3251 } 3252 3253 /*-------------------------------------------------- 3254 * parse_poll - called by the transmit procedure 3255 */ 3256 static void 3257 parse_poll( 3258 int unit, 3259 struct peer *peer 3260 ) 3261 { 3262 struct parseunit *parse = (struct parseunit *)peer->procptr->unitptr; 3263 3264 if (peer != parse->peer) 3265 { 3266 msyslog(LOG_ERR, 3267 "PARSE receiver #%d: poll: INTERNAL: peer incorrect", 3268 unit); 3269 return; 3270 } 3271 3272 /* 3273 * Update clock stat counters 3274 */ 3275 parse->generic->polls++; 3276 3277 if (parse->pollneeddata && 3278 ((current_time - parse->pollneeddata) > (1<<(max(min(parse->peer->hpoll, parse->peer->ppoll), parse->peer->minpoll))))) 3279 { 3280 /* 3281 * start worrying when exceeding a poll inteval 3282 * bad news - didn't get a response last time 3283 */ 3284 parse->lastmissed = current_time; 3285 parse_event(parse, CEVNT_TIMEOUT); 3286 3287 ERR(ERR_NODATA) 3288 msyslog(LOG_WARNING, "PARSE receiver #%d: no data from device within poll interval (check receiver / wiring)", CLK_UNIT(parse->peer)); 3289 } 3290 3291 /* 3292 * we just mark that we want the next sample for the clock filter 3293 */ 3294 parse->pollneeddata = current_time; 3295 3296 if (parse->parse_type->cl_poll) 3297 { 3298 parse->parse_type->cl_poll(parse); 3299 } 3300 3301 cparse_statistics(parse); 3302 3303 return; 3304 } 3305 3306 #define LEN_STATES 300 /* length of state string */ 3307 3308 /*-------------------------------------------------- 3309 * parse_control - set fudge factors, return statistics 3310 */ 3311 static void 3312 parse_control( 3313 int unit, 3314 struct refclockstat *in, 3315 struct refclockstat *out, 3316 struct peer *peer 3317 ) 3318 { 3319 struct parseunit *parse = (struct parseunit *)peer->procptr->unitptr; 3320 parsectl_t tmpctl; 3321 3322 static char outstatus[400]; /* status output buffer */ 3323 3324 if (out) 3325 { 3326 out->lencode = 0; 3327 out->p_lastcode = 0; 3328 out->kv_list = (struct ctl_var *)0; 3329 } 3330 3331 if (!parse || !parse->peer) 3332 { 3333 msyslog(LOG_ERR, "PARSE receiver #%d: parse_control: unit invalid (UNIT INACTIVE)", 3334 unit); 3335 return; 3336 } 3337 3338 unit = CLK_UNIT(parse->peer); 3339 3340 /* 3341 * handle changes 3342 */ 3343 parse_ctl(parse, in); 3344 3345 /* 3346 * supply data 3347 */ 3348 if (out) 3349 { 3350 u_long sum = 0; 3351 char *tt, *start; 3352 int i; 3353 3354 outstatus[0] = '\0'; 3355 3356 out->type = REFCLK_PARSE; 3357 3358 /* 3359 * keep fudgetime2 in sync with TRUSTTIME/MAXUNSYNC flag1 3360 */ 3361 parse->generic->fudgetime2 = (parse->flags & PARSE_TRUSTTIME) ? (double)parse->maxunsync : parse->ppsphaseadjust; 3362 3363 /* 3364 * figure out skew between PPS and RS232 - just for informational 3365 * purposes 3366 */ 3367 if (PARSE_SYNC(parse->timedata.parse_state)) 3368 { 3369 if (PARSE_PPS(parse->timedata.parse_state) && PARSE_TIMECODE(parse->timedata.parse_state)) 3370 { 3371 l_fp off; 3372 3373 /* 3374 * we have a PPS and RS232 signal - calculate the skew 3375 * WARNING: assumes on TIMECODE == PULSE (timecode after pulse) 3376 */ 3377 off = parse->timedata.parse_stime.fp; 3378 L_SUB(&off, &parse->timedata.parse_ptime.fp); /* true offset */ 3379 tt = add_var(&out->kv_list, 80, RO); 3380 snprintf(tt, 80, "refclock_ppsskew=%s", lfptoms(&off, 6)); 3381 } 3382 } 3383 3384 if (PARSE_PPS(parse->timedata.parse_state)) 3385 { 3386 tt = add_var(&out->kv_list, 80, RO|DEF); 3387 snprintf(tt, 80, "refclock_ppstime=\"%s\"", gmprettydate(&parse->timedata.parse_ptime.fp)); 3388 } 3389 3390 start = tt = add_var(&out->kv_list, 128, RO|DEF); 3391 snprintf(tt, 128, "refclock_time=\""); 3392 tt += strlen(tt); 3393 3394 if (parse->timedata.parse_time.fp.l_ui == 0) 3395 { 3396 strncpy(tt, "<UNDEFINED>\"", BUFFER_SIZES(start, tt, 128)); 3397 } 3398 else 3399 { 3400 snprintf(tt, 128, "%s\"", gmprettydate(&parse->timedata.parse_time.fp)); 3401 } 3402 3403 if (!PARSE_GETTIMECODE(parse, &tmpctl)) 3404 { 3405 ERR(ERR_INTERNAL) 3406 msyslog(LOG_ERR, "PARSE receiver #%d: parse_control: parse_timecode() FAILED", unit); 3407 } 3408 else 3409 { 3410 start = tt = add_var(&out->kv_list, 512, RO|DEF); 3411 snprintf(tt, 512, "refclock_status=\""); 3412 tt += strlen(tt); 3413 3414 /* 3415 * copy PPS flags from last read transaction (informational only) 3416 */ 3417 tmpctl.parsegettc.parse_state |= parse->timedata.parse_state & 3418 (PARSEB_PPS|PARSEB_S_PPS); 3419 3420 (void) parsestate(tmpctl.parsegettc.parse_state, tt, BUFFER_SIZES(start, tt, 512)); 3421 3422 strncat(tt, "\"", BUFFER_SIZES(start, tt, 512)); 3423 3424 if (tmpctl.parsegettc.parse_count) 3425 mkascii(outstatus+strlen(outstatus), (int)(sizeof(outstatus)- strlen(outstatus) - 1), 3426 tmpctl.parsegettc.parse_buffer, (unsigned)(tmpctl.parsegettc.parse_count)); 3427 3428 } 3429 3430 tmpctl.parseformat.parse_format = tmpctl.parsegettc.parse_format; 3431 3432 if (!PARSE_GETFMT(parse, &tmpctl)) 3433 { 3434 ERR(ERR_INTERNAL) 3435 msyslog(LOG_ERR, "PARSE receiver #%d: parse_control: parse_getfmt() FAILED", unit); 3436 } 3437 else 3438 { 3439 tt = add_var(&out->kv_list, 80, RO|DEF); 3440 snprintf(tt, 80, "refclock_format=\""); 3441 3442 strncat(tt, tmpctl.parseformat.parse_buffer, tmpctl.parseformat.parse_count); 3443 strncat(tt,"\"", 80); 3444 } 3445 3446 /* 3447 * gather state statistics 3448 */ 3449 3450 start = tt = add_var(&out->kv_list, LEN_STATES, RO|DEF); 3451 strncpy(tt, "refclock_states=\"", LEN_STATES); 3452 tt += strlen(tt); 3453 3454 for (i = 0; i <= CEVNT_MAX; i++) 3455 { 3456 u_long s_time; 3457 u_long d = current_time - parse->generic->timestarted; 3458 u_long percent; 3459 3460 percent = s_time = PARSE_STATETIME(parse, i); 3461 3462 while (((u_long)(~0) / 10000) < percent) 3463 { 3464 percent /= 10; 3465 d /= 10; 3466 } 3467 3468 if (d) 3469 percent = (percent * 10000) / d; 3470 else 3471 percent = 10000; 3472 3473 if (s_time) 3474 { 3475 char item[80]; 3476 int count; 3477 3478 snprintf(item, 80, "%s%s%s: %s (%d.%02d%%)", 3479 sum ? "; " : "", 3480 (parse->generic->currentstatus == i) ? "*" : "", 3481 clockstatus((unsigned int)i), 3482 l_mktime(s_time), 3483 (int)(percent / 100), (int)(percent % 100)); 3484 if ((count = strlen(item)) < (LEN_STATES - 40 - (tt - start))) 3485 { 3486 strncpy(tt, item, BUFFER_SIZES(start, tt, LEN_STATES)); 3487 tt += count; 3488 } 3489 sum += s_time; 3490 } 3491 } 3492 3493 snprintf(tt, BUFFER_SIZES(start, tt, LEN_STATES), "; running time: %s\"", l_mktime(sum)); 3494 3495 tt = add_var(&out->kv_list, 32, RO); 3496 snprintf(tt, 32, "refclock_id=\"%s\"", parse->parse_type->cl_id); 3497 3498 tt = add_var(&out->kv_list, 80, RO); 3499 snprintf(tt, 80, "refclock_iomode=\"%s\"", parse->binding->bd_description); 3500 3501 tt = add_var(&out->kv_list, 128, RO); 3502 snprintf(tt, 128, "refclock_driver_version=\"%s\"", rcsid); 3503 3504 { 3505 struct ctl_var *k; 3506 3507 k = parse->kv; 3508 while (k && !(k->flags & EOV)) 3509 { 3510 set_var(&out->kv_list, k->text, strlen(k->text)+1, k->flags); 3511 k++; 3512 } 3513 } 3514 3515 out->lencode = strlen(outstatus); 3516 out->p_lastcode = outstatus; 3517 } 3518 } 3519 3520 /**=========================================================================== 3521 ** processing routines 3522 **/ 3523 3524 /*-------------------------------------------------- 3525 * event handling - note that nominal events will also be posted 3526 * keep track of state dwelling times 3527 */ 3528 static void 3529 parse_event( 3530 struct parseunit *parse, 3531 int event 3532 ) 3533 { 3534 if (parse->generic->currentstatus != (u_char) event) 3535 { 3536 parse->statetime[parse->generic->currentstatus] += current_time - parse->lastchange; 3537 parse->lastchange = current_time; 3538 3539 if (parse->parse_type->cl_event) 3540 parse->parse_type->cl_event(parse, event); 3541 3542 if (event == CEVNT_NOMINAL) 3543 { 3544 NLOG(NLOG_CLOCKSTATUS) 3545 msyslog(LOG_INFO, "PARSE receiver #%d: SYNCHRONIZED", 3546 CLK_UNIT(parse->peer)); 3547 } 3548 3549 refclock_report(parse->peer, event); 3550 } 3551 } 3552 3553 /*-------------------------------------------------- 3554 * process a PARSE time sample 3555 */ 3556 static void 3557 parse_process( 3558 struct parseunit *parse, 3559 parsetime_t *parsetime 3560 ) 3561 { 3562 l_fp off, rectime, reftime; 3563 double fudge; 3564 3565 /* 3566 * check for changes in conversion status 3567 * (only one for each new status !) 3568 */ 3569 if (((parsetime->parse_status & CVT_MASK) != CVT_OK) && 3570 ((parsetime->parse_status & CVT_MASK) != CVT_NONE) && 3571 (parse->timedata.parse_status != parsetime->parse_status)) 3572 { 3573 char buffer[400]; 3574 3575 NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */ 3576 msyslog(LOG_WARNING, "PARSE receiver #%d: conversion status \"%s\"", 3577 CLK_UNIT(parse->peer), parsestatus(parsetime->parse_status, buffer, sizeof(buffer))); 3578 3579 if ((parsetime->parse_status & CVT_MASK) == CVT_FAIL) 3580 { 3581 /* 3582 * tell more about the story - list time code 3583 * there is a slight change for a race condition and 3584 * the time code might be overwritten by the next packet 3585 */ 3586 parsectl_t tmpctl; 3587 3588 if (!PARSE_GETTIMECODE(parse, &tmpctl)) 3589 { 3590 ERR(ERR_INTERNAL) 3591 msyslog(LOG_ERR, "PARSE receiver #%d: parse_process: parse_timecode() FAILED", CLK_UNIT(parse->peer)); 3592 } 3593 else 3594 { 3595 ERR(ERR_BADDATA) 3596 msyslog(LOG_WARNING, "PARSE receiver #%d: FAILED TIMECODE: \"%s\" (check receiver configuration / wiring)", 3597 CLK_UNIT(parse->peer), mkascii(buffer, sizeof buffer, tmpctl.parsegettc.parse_buffer, (unsigned)(tmpctl.parsegettc.parse_count - 1))); 3598 } 3599 } 3600 } 3601 3602 /* 3603 * examine status and post appropriate events 3604 */ 3605 if ((parsetime->parse_status & CVT_MASK) != CVT_OK) 3606 { 3607 /* 3608 * got bad data - tell the rest of the system 3609 */ 3610 switch (parsetime->parse_status & CVT_MASK) 3611 { 3612 case CVT_NONE: 3613 if ((parsetime->parse_status & CVT_ADDITIONAL) && 3614 parse->parse_type->cl_message) 3615 parse->parse_type->cl_message(parse, parsetime); 3616 /* 3617 * save PPS information that comes piggyback 3618 */ 3619 if (PARSE_PPS(parsetime->parse_state)) 3620 { 3621 parse->timedata.parse_state |= PARSEB_PPS|PARSEB_S_PPS; 3622 parse->timedata.parse_ptime = parsetime->parse_ptime; 3623 } 3624 break; /* well, still waiting - timeout is handled at higher levels */ 3625 3626 case CVT_FAIL: 3627 if (parsetime->parse_status & CVT_BADFMT) 3628 { 3629 parse_event(parse, CEVNT_BADREPLY); 3630 } 3631 else 3632 if (parsetime->parse_status & CVT_BADDATE) 3633 { 3634 parse_event(parse, CEVNT_BADDATE); 3635 } 3636 else 3637 if (parsetime->parse_status & CVT_BADTIME) 3638 { 3639 parse_event(parse, CEVNT_BADTIME); 3640 } 3641 else 3642 { 3643 parse_event(parse, CEVNT_BADREPLY); /* for the lack of something better */ 3644 } 3645 } 3646 return; /* skip the rest - useless */ 3647 } 3648 3649 /* 3650 * check for format changes 3651 * (in case somebody has swapped clocks 8-) 3652 */ 3653 if (parse->lastformat != parsetime->parse_format) 3654 { 3655 parsectl_t tmpctl; 3656 3657 tmpctl.parseformat.parse_format = parsetime->parse_format; 3658 3659 if (!PARSE_GETFMT(parse, &tmpctl)) 3660 { 3661 ERR(ERR_INTERNAL) 3662 msyslog(LOG_ERR, "PARSE receiver #%d: parse_getfmt() FAILED", CLK_UNIT(parse->peer)); 3663 } 3664 else 3665 { 3666 NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */ 3667 msyslog(LOG_INFO, "PARSE receiver #%d: packet format \"%s\"", 3668 CLK_UNIT(parse->peer), tmpctl.parseformat.parse_buffer); 3669 } 3670 parse->lastformat = parsetime->parse_format; 3671 } 3672 3673 /* 3674 * now, any changes ? 3675 */ 3676 if ((parse->timedata.parse_state ^ parsetime->parse_state) & 3677 ~(unsigned)(PARSEB_PPS|PARSEB_S_PPS)) 3678 { 3679 char tmp1[200]; 3680 char tmp2[200]; 3681 /* 3682 * something happend - except for PPS events 3683 */ 3684 3685 (void) parsestate(parsetime->parse_state, tmp1, sizeof(tmp1)); 3686 (void) parsestate(parse->timedata.parse_state, tmp2, sizeof(tmp2)); 3687 3688 NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */ 3689 msyslog(LOG_INFO,"PARSE receiver #%d: STATE CHANGE: %s -> %s", 3690 CLK_UNIT(parse->peer), tmp2, tmp1); 3691 } 3692 3693 /* 3694 * carry on PPS information if still usable 3695 */ 3696 if (PARSE_PPS(parse->timedata.parse_state) && !PARSE_PPS(parsetime->parse_state)) 3697 { 3698 parsetime->parse_state |= PARSEB_PPS|PARSEB_S_PPS; 3699 parsetime->parse_ptime = parse->timedata.parse_ptime; 3700 } 3701 3702 /* 3703 * remember for future 3704 */ 3705 parse->timedata = *parsetime; 3706 3707 /* 3708 * check to see, whether the clock did a complete powerup or lost PZF signal 3709 * and post correct events for current condition 3710 */ 3711 if (PARSE_POWERUP(parsetime->parse_state)) 3712 { 3713 /* 3714 * this is bad, as we have completely lost synchronisation 3715 * well this is a problem with the receiver here 3716 * for PARSE Meinberg DCF77 receivers the lost synchronisation 3717 * is true as it is the powerup state and the time is taken 3718 * from a crude real time clock chip 3719 * for the PZF series this is only partly true, as 3720 * PARSE_POWERUP only means that the pseudo random 3721 * phase shift sequence cannot be found. this is only 3722 * bad, if we have never seen the clock in the SYNC 3723 * state, where the PHASE and EPOCH are correct. 3724 * for reporting events the above business does not 3725 * really matter, but we can use the time code 3726 * even in the POWERUP state after having seen 3727 * the clock in the synchronized state (PZF class 3728 * receivers) unless we have had a telegram disruption 3729 * after having seen the clock in the SYNC state. we 3730 * thus require having seen the clock in SYNC state 3731 * *after* having missed telegrams (noresponse) from 3732 * the clock. one problem remains: we might use erroneously 3733 * POWERUP data if the disruption is shorter than 1 polling 3734 * interval. fortunately powerdowns last usually longer than 64 3735 * seconds and the receiver is at least 2 minutes in the 3736 * POWERUP or NOSYNC state before switching to SYNC 3737 */ 3738 parse_event(parse, CEVNT_FAULT); 3739 NLOG(NLOG_CLOCKSTATUS) 3740 ERR(ERR_BADSTATUS) 3741 msyslog(LOG_ERR,"PARSE receiver #%d: NOT SYNCHRONIZED", 3742 CLK_UNIT(parse->peer)); 3743 } 3744 else 3745 { 3746 /* 3747 * we have two states left 3748 * 3749 * SYNC: 3750 * this state means that the EPOCH (timecode) and PHASE 3751 * information has be read correctly (at least two 3752 * successive PARSE timecodes were received correctly) 3753 * this is the best possible state - full trust 3754 * 3755 * NOSYNC: 3756 * The clock should be on phase with respect to the second 3757 * signal, but the timecode has not been received correctly within 3758 * at least the last two minutes. this is a sort of half baked state 3759 * for PARSE Meinberg DCF77 clocks this is bad news (clock running 3760 * without timecode confirmation) 3761 * PZF 535 has also no time confirmation, but the phase should be 3762 * very precise as the PZF signal can be decoded 3763 */ 3764 3765 if (PARSE_SYNC(parsetime->parse_state)) 3766 { 3767 /* 3768 * currently completely synchronized - best possible state 3769 */ 3770 parse->lastsync = current_time; 3771 clear_err(parse, ERR_BADSTATUS); 3772 } 3773 else 3774 { 3775 /* 3776 * we have had some problems receiving the time code 3777 */ 3778 parse_event(parse, CEVNT_PROP); 3779 NLOG(NLOG_CLOCKSTATUS) 3780 ERR(ERR_BADSTATUS) 3781 msyslog(LOG_ERR,"PARSE receiver #%d: TIMECODE NOT CONFIRMED", 3782 CLK_UNIT(parse->peer)); 3783 } 3784 } 3785 3786 fudge = parse->generic->fudgetime1; /* standard RS232 Fudgefactor */ 3787 3788 if (PARSE_TIMECODE(parsetime->parse_state)) 3789 { 3790 rectime = parsetime->parse_stime.fp; 3791 off = reftime = parsetime->parse_time.fp; 3792 3793 L_SUB(&off, &rectime); /* prepare for PPS adjustments logic */ 3794 3795 #ifdef DEBUG 3796 if (debug > 3) 3797 printf("PARSE receiver #%d: Reftime %s, Recvtime %s - initial offset %s\n", 3798 CLK_UNIT(parse->peer), 3799 prettydate(&reftime), 3800 prettydate(&rectime), 3801 lfptoa(&off,6)); 3802 #endif 3803 } 3804 3805 if (PARSE_PPS(parsetime->parse_state) && CLK_PPS(parse->peer)) 3806 { 3807 l_fp offset; 3808 double ppsphaseadjust = parse->ppsphaseadjust; 3809 3810 #ifdef HAVE_PPSAPI 3811 /* 3812 * set fudge = 0.0 if already included in PPS time stamps 3813 */ 3814 if (parse->ppsparams.mode & (PPS_OFFSETCLEAR|PPS_OFFSETASSERT)) 3815 { 3816 ppsphaseadjust = 0.0; 3817 } 3818 #endif 3819 3820 /* 3821 * we have a PPS signal - much better than the RS232 stuff (we hope) 3822 */ 3823 offset = parsetime->parse_ptime.fp; 3824 3825 #ifdef DEBUG 3826 if (debug > 3) 3827 printf("PARSE receiver #%d: PPStime %s\n", 3828 CLK_UNIT(parse->peer), 3829 prettydate(&offset)); 3830 #endif 3831 if (PARSE_TIMECODE(parsetime->parse_state)) 3832 { 3833 if (M_ISGEQ(off.l_i, off.l_f, -1, 0x80000000) && 3834 M_ISGEQ(0, 0x7fffffff, off.l_i, off.l_f)) 3835 { 3836 fudge = ppsphaseadjust; /* pick PPS fudge factor */ 3837 3838 /* 3839 * RS232 offsets within [-0.5..0.5[ - take PPS offsets 3840 */ 3841 3842 if (parse->parse_type->cl_flags & PARSE_F_PPSONSECOND) 3843 { 3844 reftime = off = offset; 3845 if (reftime.l_uf & (unsigned)0x80000000) 3846 reftime.l_ui++; 3847 reftime.l_uf = 0; 3848 3849 3850 /* 3851 * implied on second offset 3852 */ 3853 off.l_uf = ~off.l_uf; /* map [0.5..1[ -> [-0.5..0[ */ 3854 off.l_ui = (off.l_f < 0) ? ~0 : 0; /* sign extend */ 3855 } 3856 else 3857 { 3858 /* 3859 * time code describes pulse 3860 */ 3861 reftime = off = parsetime->parse_time.fp; 3862 3863 L_SUB(&off, &offset); /* true offset */ 3864 } 3865 } 3866 /* 3867 * take RS232 offset when PPS when out of bounds 3868 */ 3869 } 3870 else 3871 { 3872 fudge = ppsphaseadjust; /* pick PPS fudge factor */ 3873 /* 3874 * Well, no time code to guide us - assume on second pulse 3875 * and pray, that we are within [-0.5..0.5[ 3876 */ 3877 off = offset; 3878 reftime = offset; 3879 if (reftime.l_uf & (unsigned)0x80000000) 3880 reftime.l_ui++; 3881 reftime.l_uf = 0; 3882 /* 3883 * implied on second offset 3884 */ 3885 off.l_uf = ~off.l_uf; /* map [0.5..1[ -> [-0.5..0[ */ 3886 off.l_ui = (off.l_f < 0) ? ~0 : 0; /* sign extend */ 3887 } 3888 } 3889 else 3890 { 3891 if (!PARSE_TIMECODE(parsetime->parse_state)) 3892 { 3893 /* 3894 * Well, no PPS, no TIMECODE, no more work ... 3895 */ 3896 if ((parsetime->parse_status & CVT_ADDITIONAL) && 3897 parse->parse_type->cl_message) 3898 parse->parse_type->cl_message(parse, parsetime); 3899 return; 3900 } 3901 } 3902 3903 #ifdef DEBUG 3904 if (debug > 3) 3905 printf("PARSE receiver #%d: Reftime %s, Recvtime %s - final offset %s\n", 3906 CLK_UNIT(parse->peer), 3907 prettydate(&reftime), 3908 prettydate(&rectime), 3909 lfptoa(&off,6)); 3910 #endif 3911 3912 3913 rectime = reftime; 3914 L_SUB(&rectime, &off); /* just to keep the ntp interface happy */ 3915 3916 #ifdef DEBUG 3917 if (debug > 3) 3918 printf("PARSE receiver #%d: calculated Reftime %s, Recvtime %s\n", 3919 CLK_UNIT(parse->peer), 3920 prettydate(&reftime), 3921 prettydate(&rectime)); 3922 #endif 3923 3924 if ((parsetime->parse_status & CVT_ADDITIONAL) && 3925 parse->parse_type->cl_message) 3926 parse->parse_type->cl_message(parse, parsetime); 3927 3928 if (PARSE_SYNC(parsetime->parse_state)) 3929 { 3930 /* 3931 * log OK status 3932 */ 3933 parse_event(parse, CEVNT_NOMINAL); 3934 } 3935 3936 clear_err(parse, ERR_BADIO); 3937 clear_err(parse, ERR_BADDATA); 3938 clear_err(parse, ERR_NODATA); 3939 clear_err(parse, ERR_INTERNAL); 3940 3941 /* 3942 * and now stick it into the clock machine 3943 * samples are only valid iff lastsync is not too old and 3944 * we have seen the clock in sync at least once 3945 * after the last time we didn't see an expected data telegram 3946 * at startup being not in sync is also bad just like 3947 * POWERUP state 3948 * see the clock states section above for more reasoning 3949 */ 3950 if (((current_time - parse->lastsync) > parse->maxunsync) || 3951 (parse->lastsync < parse->lastmissed) || 3952 ((parse->lastsync == 0) && !PARSE_SYNC(parsetime->parse_state)) || 3953 PARSE_POWERUP(parsetime->parse_state)) 3954 { 3955 parse->generic->leap = LEAP_NOTINSYNC; 3956 parse->lastsync = 0; /* wait for full sync again */ 3957 } 3958 else 3959 { 3960 if (PARSE_LEAPADD(parsetime->parse_state)) 3961 { 3962 /* 3963 * we pick this state also for time code that pass leap warnings 3964 * without direction information (as earth is currently slowing 3965 * down). 3966 */ 3967 parse->generic->leap = (parse->flags & PARSE_LEAP_DELETE) ? LEAP_DELSECOND : LEAP_ADDSECOND; 3968 } 3969 else 3970 if (PARSE_LEAPDEL(parsetime->parse_state)) 3971 { 3972 parse->generic->leap = LEAP_DELSECOND; 3973 } 3974 else 3975 { 3976 parse->generic->leap = LEAP_NOWARNING; 3977 } 3978 } 3979 3980 if (parse->generic->leap != LEAP_NOTINSYNC) 3981 { 3982 /* 3983 * only good/trusted samples are interesting 3984 */ 3985 #ifdef DEBUG 3986 if (debug > 2) 3987 { 3988 printf("PARSE receiver #%d: refclock_process_offset(reftime=%s, rectime=%s, Fudge=%f)\n", 3989 CLK_UNIT(parse->peer), 3990 prettydate(&reftime), 3991 prettydate(&rectime), 3992 fudge); 3993 } 3994 #endif 3995 parse->generic->lastref = reftime; 3996 3997 refclock_process_offset(parse->generic, reftime, rectime, fudge); 3998 3999 /* 4000 * pass PPS information on to PPS clock 4001 */ 4002 if (PARSE_PPS(parsetime->parse_state) && CLK_PPS(parse->peer)) 4003 { 4004 (void) pps_sample(&parse->timedata.parse_ptime.fp); 4005 parse_hardpps(parse, PARSE_HARDPPS_ENABLE); 4006 } 4007 } else { 4008 parse_hardpps(parse, PARSE_HARDPPS_DISABLE); 4009 } 4010 4011 /* 4012 * ready, unless the machine wants a sample or 4013 * we are in fast startup mode (peer->dist > MAXDISTANCE) 4014 */ 4015 if (!parse->pollneeddata && parse->peer->disp <= MAXDISTANCE) 4016 return; 4017 4018 parse->pollneeddata = 0; 4019 4020 parse->timedata.parse_state &= ~(unsigned)(PARSEB_PPS|PARSEB_S_PPS); 4021 4022 refclock_receive(parse->peer); 4023 } 4024 4025 /**=========================================================================== 4026 ** special code for special clocks 4027 **/ 4028 4029 static void 4030 mk_utcinfo( 4031 char *t, 4032 int wnt, 4033 int wnlsf, 4034 int dn, 4035 int dtls, 4036 int dtlsf, 4037 int size 4038 ) 4039 { 4040 l_fp leapdate; 4041 char *start = t; 4042 4043 snprintf(t, size, "current correction %d sec", dtls); 4044 t += strlen(t); 4045 4046 if (wnlsf < 990) 4047 wnlsf += 1024; 4048 4049 if (wnt < 990) 4050 wnt += 1024; 4051 4052 gpstolfp((unsigned short)wnlsf, (unsigned short)dn, 0, &leapdate); 4053 4054 if ((dtlsf != dtls) && 4055 ((wnlsf - wnt) < 52)) 4056 { 4057 snprintf(t, BUFFER_SIZES(start, t, size), ", next correction %d sec on %s, new GPS-UTC offset %d", 4058 dtlsf - dtls, gmprettydate(&leapdate), dtlsf); 4059 } 4060 else 4061 { 4062 snprintf(t, BUFFER_SIZES(start, t, size), ", last correction on %s", 4063 gmprettydate(&leapdate)); 4064 } 4065 } 4066 4067 #ifdef CLOCK_MEINBERG 4068 /**=========================================================================== 4069 ** Meinberg GPS166/GPS167 support 4070 **/ 4071 4072 /*------------------------------------------------------------ 4073 * gps16x_message - process GPS16x messages 4074 */ 4075 static void 4076 gps16x_message( 4077 struct parseunit *parse, 4078 parsetime_t *parsetime 4079 ) 4080 { 4081 if (parse->timedata.parse_msglen && parsetime->parse_msg[0] == SOH) 4082 { 4083 GPS_MSG_HDR header; 4084 unsigned char *bufp = (unsigned char *)parsetime->parse_msg + 1; 4085 4086 #ifdef DEBUG 4087 if (debug > 2) 4088 { 4089 char msgbuffer[600]; 4090 4091 mkreadable(msgbuffer, sizeof(msgbuffer), (char *)parsetime->parse_msg, parsetime->parse_msglen, 1); 4092 printf("PARSE receiver #%d: received message (%d bytes) >%s<\n", 4093 CLK_UNIT(parse->peer), 4094 parsetime->parse_msglen, 4095 msgbuffer); 4096 } 4097 #endif 4098 get_mbg_header(&bufp, &header); 4099 if (header.gps_hdr_csum == mbg_csum(parsetime->parse_msg + 1, 6) && 4100 (header.gps_len == 0 || 4101 (header.gps_len < sizeof(parsetime->parse_msg) && 4102 header.gps_data_csum == mbg_csum(bufp, header.gps_len)))) 4103 { 4104 /* 4105 * clean message 4106 */ 4107 switch (header.gps_cmd) 4108 { 4109 case GPS_SW_REV: 4110 { 4111 char buffer[64]; 4112 SW_REV gps_sw_rev; 4113 4114 get_mbg_sw_rev(&bufp, &gps_sw_rev); 4115 snprintf(buffer, sizeof(buffer), "meinberg_gps_version=\"%x.%02x%s%s\"", 4116 (gps_sw_rev.code >> 8) & 0xFF, 4117 gps_sw_rev.code & 0xFF, 4118 gps_sw_rev.name[0] ? " " : "", 4119 gps_sw_rev.name); 4120 set_var(&parse->kv, buffer, strlen(buffer)+1, RO|DEF); 4121 } 4122 break; 4123 4124 case GPS_STAT: 4125 { 4126 static struct state 4127 { 4128 unsigned short flag; /* status flag */ 4129 unsigned const char *string; /* bit name */ 4130 } states[] = 4131 { 4132 { TM_ANT_DISCONN, (const unsigned char *)"ANTENNA FAULTY" }, 4133 { TM_SYN_FLAG, (const unsigned char *)"NO SYNC SIGNAL" }, 4134 { TM_NO_SYNC, (const unsigned char *)"NO SYNC POWERUP" }, 4135 { TM_NO_POS, (const unsigned char *)"NO POSITION" }, 4136 { 0, (const unsigned char *)"" } 4137 }; 4138 unsigned short status; 4139 struct state *s = states; 4140 char buffer[512]; 4141 char *p, *b; 4142 4143 status = get_lsb_short(&bufp); 4144 snprintf(buffer, sizeof(buffer), "meinberg_gps_status=\"[0x%04x] ", status); 4145 4146 if (status) 4147 { 4148 p = b = buffer + strlen(buffer); 4149 while (s->flag) 4150 { 4151 if (status & s->flag) 4152 { 4153 if (p != b) 4154 { 4155 *p++ = ','; 4156 *p++ = ' '; 4157 } 4158 4159 strncat(p, (const char *)s->string, sizeof(buffer)); 4160 } 4161 s++; 4162 } 4163 4164 *p++ = '"'; 4165 *p = '\0'; 4166 } 4167 else 4168 { 4169 strncat(buffer, "<OK>\"", sizeof(buffer)); 4170 } 4171 4172 set_var(&parse->kv, buffer, strlen(buffer)+1, RO|DEF); 4173 } 4174 break; 4175 4176 case GPS_POS_XYZ: 4177 { 4178 XYZ xyz; 4179 char buffer[256]; 4180 4181 get_mbg_xyz(&bufp, xyz); 4182 snprintf(buffer, sizeof(buffer), "gps_position(XYZ)=\"%s m, %s m, %s m\"", 4183 mfptoa(xyz[XP].l_ui, xyz[XP].l_uf, 1), 4184 mfptoa(xyz[YP].l_ui, xyz[YP].l_uf, 1), 4185 mfptoa(xyz[ZP].l_ui, xyz[ZP].l_uf, 1)); 4186 4187 set_var(&parse->kv, buffer, sizeof(buffer), RO|DEF); 4188 } 4189 break; 4190 4191 case GPS_POS_LLA: 4192 { 4193 LLA lla; 4194 char buffer[256]; 4195 4196 get_mbg_lla(&bufp, lla); 4197 4198 snprintf(buffer, sizeof(buffer), "gps_position(LLA)=\"%s deg, %s deg, %s m\"", 4199 mfptoa(lla[LAT].l_ui, lla[LAT].l_uf, 4), 4200 mfptoa(lla[LON].l_ui, lla[LON].l_uf, 4), 4201 mfptoa(lla[ALT].l_ui, lla[ALT].l_uf, 1)); 4202 4203 set_var(&parse->kv, buffer, sizeof(buffer), RO|DEF); 4204 } 4205 break; 4206 4207 case GPS_TZDL: 4208 break; 4209 4210 case GPS_PORT_PARM: 4211 break; 4212 4213 case GPS_SYNTH: 4214 break; 4215 4216 case GPS_ANT_INFO: 4217 { 4218 ANT_INFO antinfo; 4219 char buffer[512]; 4220 char *p; 4221 4222 get_mbg_antinfo(&bufp, &antinfo); 4223 snprintf(buffer, sizeof(buffer), "meinberg_antenna_status=\""); 4224 p = buffer + strlen(buffer); 4225 4226 switch (antinfo.status) 4227 { 4228 case ANT_INVALID: 4229 strncat(p, "<OK>", BUFFER_SIZE(buffer, p)); 4230 p += strlen(p); 4231 break; 4232 4233 case ANT_DISCONN: 4234 strncat(p, "DISCONNECTED since ", BUFFER_SIZE(buffer, p)); 4235 NLOG(NLOG_CLOCKSTATUS) 4236 ERR(ERR_BADSTATUS) 4237 msyslog(LOG_ERR,"PARSE receiver #%d: ANTENNA FAILURE: %s", 4238 CLK_UNIT(parse->peer), p); 4239 4240 p += strlen(p); 4241 mbg_tm_str(&p, &antinfo.tm_disconn, BUFFER_SIZE(buffer, p)); 4242 *p = '\0'; 4243 break; 4244 4245 case ANT_RECONN: 4246 strncat(p, "RECONNECTED on ", BUFFER_SIZE(buffer, p)); 4247 p += strlen(p); 4248 mbg_tm_str(&p, &antinfo.tm_reconn, BUFFER_SIZE(buffer, p)); 4249 snprintf(p, BUFFER_SIZE(buffer, p), ", reconnect clockoffset %c%ld.%07ld s, disconnect time ", 4250 (antinfo.delta_t < 0) ? '-' : '+', 4251 ABS(antinfo.delta_t) / 10000, 4252 ABS(antinfo.delta_t) % 10000); 4253 p += strlen(p); 4254 mbg_tm_str(&p, &antinfo.tm_disconn, BUFFER_SIZE(buffer, p)); 4255 *p = '\0'; 4256 break; 4257 4258 default: 4259 snprintf(p, BUFFER_SIZE(buffer, p), "bad status 0x%04x", antinfo.status); 4260 p += strlen(p); 4261 break; 4262 } 4263 4264 strncat(p, "\"", BUFFER_SIZE(buffer, p)); 4265 4266 set_var(&parse->kv, buffer, strlen(buffer)+1, RO|DEF); 4267 } 4268 break; 4269 4270 case GPS_UCAP: 4271 break; 4272 4273 case GPS_CFGH: 4274 { 4275 CFGH cfgh; 4276 char buffer[512]; 4277 char *p; 4278 4279 get_mbg_cfgh(&bufp, &cfgh); 4280 if (cfgh.valid) 4281 { 4282 int i; 4283 4284 p = buffer; 4285 strncpy(buffer, "gps_tot_51=\"", BUFFER_SIZE(buffer, p)); 4286 p += strlen(p); 4287 mbg_tgps_str(&p, &cfgh.tot_51, BUFFER_SIZE(buffer, p)); 4288 strncpy(p, "\"", BUFFER_SIZE(buffer, p)); 4289 set_var(&parse->kv, buffer, strlen(buffer)+1, RO); 4290 4291 p = buffer; 4292 strncpy(buffer, "gps_tot_63=\"", BUFFER_SIZE(buffer, p)); 4293 p += strlen(p); 4294 mbg_tgps_str(&p, &cfgh.tot_63, BUFFER_SIZE(buffer, p)); 4295 strncpy(p, "\"", BUFFER_SIZE(buffer, p)); 4296 set_var(&parse->kv, buffer, strlen(buffer)+1, RO); 4297 4298 p = buffer; 4299 strncpy(buffer, "gps_t0a=\"", BUFFER_SIZE(buffer, p)); 4300 p += strlen(p); 4301 mbg_tgps_str(&p, &cfgh.t0a, BUFFER_SIZE(buffer, p)); 4302 strncpy(p, "\"", BUFFER_SIZE(buffer, p)); 4303 set_var(&parse->kv, buffer, strlen(buffer)+1, RO); 4304 4305 for (i = MIN_SVNO; i < MAX_SVNO; i++) 4306 { 4307 p = buffer; 4308 snprintf(p, BUFFER_SIZE(buffer, p), "gps_cfg[%d]=\"[0x%x] ", i, cfgh.cfg[i]); 4309 p += strlen(p); 4310 switch (cfgh.cfg[i] & 0x7) 4311 { 4312 case 0: 4313 strncpy(p, "BLOCK I", BUFFER_SIZE(buffer, p)); 4314 break; 4315 case 1: 4316 strncpy(p, "BLOCK II", BUFFER_SIZE(buffer, p)); 4317 break; 4318 default: 4319 strncpy(p, "bad CFG", BUFFER_SIZE(buffer, p)); 4320 break; 4321 } 4322 strncat(p, "\"", BUFFER_SIZE(buffer, p)); 4323 set_var(&parse->kv, buffer, strlen(buffer)+1, RO); 4324 4325 p = buffer; 4326 snprintf(p, BUFFER_SIZE(buffer, p), "gps_health[%d]=\"[0x%x] ", i, cfgh.health[i]); 4327 p += strlen(p); 4328 switch ((cfgh.health[i] >> 5) & 0x7 ) 4329 { 4330 case 0: 4331 strncpy(p, "OK;", BUFFER_SIZE(buffer, p)); 4332 break; 4333 case 1: 4334 strncpy(p, "PARITY;", BUFFER_SIZE(buffer, p)); 4335 break; 4336 case 2: 4337 strncpy(p, "TLM/HOW;", BUFFER_SIZE(buffer, p)); 4338 break; 4339 case 3: 4340 strncpy(p, "Z-COUNT;", BUFFER_SIZE(buffer, p)); 4341 break; 4342 case 4: 4343 strncpy(p, "SUBFRAME 1,2,3;", BUFFER_SIZE(buffer, p)); 4344 break; 4345 case 5: 4346 strncpy(p, "SUBFRAME 4,5;", BUFFER_SIZE(buffer, p)); 4347 break; 4348 case 6: 4349 strncpy(p, "UPLOAD BAD;", BUFFER_SIZE(buffer, p)); 4350 break; 4351 case 7: 4352 strncpy(p, "DATA BAD;", BUFFER_SIZE(buffer, p)); 4353 break; 4354 } 4355 4356 p += strlen(p); 4357 4358 switch (cfgh.health[i] & 0x1F) 4359 { 4360 case 0: 4361 strncpy(p, "SIGNAL OK", BUFFER_SIZE(buffer, p)); 4362 break; 4363 case 0x1C: 4364 strncpy(p, "SV TEMP OUT", BUFFER_SIZE(buffer, p)); 4365 break; 4366 case 0x1D: 4367 strncpy(p, "SV WILL BE TEMP OUT", BUFFER_SIZE(buffer, p)); 4368 break; 4369 case 0x1E: 4370 break; 4371 case 0x1F: 4372 strncpy(p, "MULTIPLE ERRS", BUFFER_SIZE(buffer, p)); 4373 break; 4374 default: 4375 strncpy(p, "TRANSMISSION PROBLEMS", BUFFER_SIZE(buffer, p)); 4376 break; 4377 } 4378 4379 strncat(p, "\"", sizeof(buffer)); 4380 set_var(&parse->kv, buffer, strlen(buffer)+1, RO); 4381 } 4382 } 4383 } 4384 break; 4385 4386 case GPS_ALM: 4387 break; 4388 4389 case GPS_EPH: 4390 break; 4391 4392 case GPS_UTC: 4393 { 4394 UTC utc; 4395 char buffer[512]; 4396 char *p; 4397 4398 p = buffer; 4399 4400 get_mbg_utc(&bufp, &utc); 4401 4402 if (utc.valid) 4403 { 4404 strncpy(p, "gps_utc_correction=\"", sizeof(buffer)); 4405 p += strlen(p); 4406 mk_utcinfo(p, utc.t0t.wn, utc.WNlsf, utc.DNt, utc.delta_tls, utc.delta_tlsf, BUFFER_SIZE(buffer, p)); 4407 strncat(p, "\"", BUFFER_SIZE(buffer, p)); 4408 } 4409 else 4410 { 4411 strncpy(p, "gps_utc_correction=\"<NO UTC DATA>\"", BUFFER_SIZE(buffer, p)); 4412 } 4413 set_var(&parse->kv, buffer, strlen(buffer)+1, RO|DEF); 4414 } 4415 break; 4416 4417 case GPS_IONO: 4418 break; 4419 4420 case GPS_ASCII_MSG: 4421 { 4422 ASCII_MSG gps_ascii_msg; 4423 char buffer[128]; 4424 4425 get_mbg_ascii_msg(&bufp, &gps_ascii_msg); 4426 4427 if (gps_ascii_msg.valid) 4428 { 4429 char buffer1[128]; 4430 mkreadable(buffer1, sizeof(buffer1), gps_ascii_msg.s, strlen(gps_ascii_msg.s), (int)0); 4431 4432 snprintf(buffer, sizeof(buffer), "gps_message=\"%s\"", buffer1); 4433 } 4434 else 4435 strncpy(buffer, "gps_message=<NONE>", sizeof(buffer)); 4436 4437 set_var(&parse->kv, buffer, strlen(buffer)+1, RO|DEF); 4438 } 4439 4440 break; 4441 4442 default: 4443 break; 4444 } 4445 } 4446 else 4447 { 4448 msyslog(LOG_DEBUG, "PARSE receiver #%d: gps16x_message: message checksum error: hdr_csum = 0x%x (expected 0x%lx), data_len = %d, data_csum = 0x%x (expected 0x%lx)", 4449 CLK_UNIT(parse->peer), 4450 header.gps_hdr_csum, mbg_csum(parsetime->parse_msg + 1, 6), 4451 header.gps_len, 4452 header.gps_data_csum, mbg_csum(bufp, (unsigned)((header.gps_len < sizeof(parsetime->parse_msg)) ? header.gps_len : 0))); 4453 } 4454 } 4455 4456 return; 4457 } 4458 4459 /*------------------------------------------------------------ 4460 * gps16x_poll - query the reciver peridically 4461 */ 4462 static void 4463 gps16x_poll( 4464 struct peer *peer 4465 ) 4466 { 4467 struct parseunit *parse = (struct parseunit *)peer->procptr->unitptr; 4468 4469 static GPS_MSG_HDR sequence[] = 4470 { 4471 { GPS_SW_REV, 0, 0, 0 }, 4472 { GPS_STAT, 0, 0, 0 }, 4473 { GPS_UTC, 0, 0, 0 }, 4474 { GPS_ASCII_MSG, 0, 0, 0 }, 4475 { GPS_ANT_INFO, 0, 0, 0 }, 4476 { GPS_CFGH, 0, 0, 0 }, 4477 { GPS_POS_XYZ, 0, 0, 0 }, 4478 { GPS_POS_LLA, 0, 0, 0 }, 4479 { (unsigned short)~0, 0, 0, 0 } 4480 }; 4481 4482 int rtc; 4483 unsigned char cmd_buffer[64]; 4484 unsigned char *outp = cmd_buffer; 4485 GPS_MSG_HDR *header; 4486 4487 if (((poll_info_t *)parse->parse_type->cl_data)->rate) 4488 { 4489 parse->peer->nextaction = current_time + ((poll_info_t *)parse->parse_type->cl_data)->rate; 4490 } 4491 4492 if (sequence[parse->localstate].gps_cmd == (unsigned short)~0) 4493 parse->localstate = 0; 4494 4495 header = sequence + parse->localstate++; 4496 4497 *outp++ = SOH; /* start command */ 4498 4499 put_mbg_header(&outp, header); 4500 outp = cmd_buffer + 1; 4501 4502 header->gps_hdr_csum = (short)mbg_csum(outp, 6); 4503 put_mbg_header(&outp, header); 4504 4505 #ifdef DEBUG 4506 if (debug > 2) 4507 { 4508 char buffer[128]; 4509 4510 mkreadable(buffer, sizeof(buffer), (char *)cmd_buffer, (unsigned)(outp - cmd_buffer), 1); 4511 printf("PARSE receiver #%d: transmitted message #%ld (%d bytes) >%s<\n", 4512 CLK_UNIT(parse->peer), 4513 parse->localstate - 1, 4514 (int)(outp - cmd_buffer), 4515 buffer); 4516 } 4517 #endif 4518 4519 rtc = write(parse->generic->io.fd, cmd_buffer, (unsigned long)(outp - cmd_buffer)); 4520 4521 if (rtc < 0) 4522 { 4523 ERR(ERR_BADIO) 4524 msyslog(LOG_ERR, "PARSE receiver #%d: gps16x_poll: failed to send cmd to clock: %m", CLK_UNIT(parse->peer)); 4525 } 4526 else 4527 if (rtc != outp - cmd_buffer) 4528 { 4529 ERR(ERR_BADIO) 4530 msyslog(LOG_ERR, "PARSE receiver #%d: gps16x_poll: failed to send cmd incomplete (%d of %d bytes sent)", CLK_UNIT(parse->peer), rtc, (int)(outp - cmd_buffer)); 4531 } 4532 4533 clear_err(parse, ERR_BADIO); 4534 return; 4535 } 4536 4537 /*-------------------------------------------------- 4538 * init routine - setup timer 4539 */ 4540 static int 4541 gps16x_poll_init( 4542 struct parseunit *parse 4543 ) 4544 { 4545 if (((poll_info_t *)parse->parse_type->cl_data)->rate) 4546 { 4547 parse->peer->action = gps16x_poll; 4548 gps16x_poll(parse->peer); 4549 } 4550 4551 return 0; 4552 } 4553 4554 #else 4555 static void 4556 gps16x_message( 4557 struct parseunit *parse, 4558 parsetime_t *parsetime 4559 ) 4560 {} 4561 static int 4562 gps16x_poll_init( 4563 struct parseunit *parse 4564 ) 4565 { 4566 return 1; 4567 } 4568 #endif /* CLOCK_MEINBERG */ 4569 4570 /**=========================================================================== 4571 ** clock polling support 4572 **/ 4573 4574 /*-------------------------------------------------- 4575 * direct poll routine 4576 */ 4577 static void 4578 poll_dpoll( 4579 struct parseunit *parse 4580 ) 4581 { 4582 int rtc; 4583 const char *ps = ((poll_info_t *)parse->parse_type->cl_data)->string; 4584 int ct = ((poll_info_t *)parse->parse_type->cl_data)->count; 4585 4586 rtc = write(parse->generic->io.fd, ps, (unsigned long)ct); 4587 if (rtc < 0) 4588 { 4589 ERR(ERR_BADIO) 4590 msyslog(LOG_ERR, "PARSE receiver #%d: poll_dpoll: failed to send cmd to clock: %m", CLK_UNIT(parse->peer)); 4591 } 4592 else 4593 if (rtc != ct) 4594 { 4595 ERR(ERR_BADIO) 4596 msyslog(LOG_ERR, "PARSE receiver #%d: poll_dpoll: failed to send cmd incomplete (%d of %d bytes sent)", CLK_UNIT(parse->peer), rtc, ct); 4597 } 4598 clear_err(parse, ERR_BADIO); 4599 } 4600 4601 /*-------------------------------------------------- 4602 * periodic poll routine 4603 */ 4604 static void 4605 poll_poll( 4606 struct peer *peer 4607 ) 4608 { 4609 struct parseunit *parse = (struct parseunit *)peer->procptr->unitptr; 4610 4611 if (parse->parse_type->cl_poll) 4612 parse->parse_type->cl_poll(parse); 4613 4614 if (((poll_info_t *)parse->parse_type->cl_data)->rate) 4615 { 4616 parse->peer->nextaction = current_time + ((poll_info_t *)parse->parse_type->cl_data)->rate; 4617 } 4618 } 4619 4620 /*-------------------------------------------------- 4621 * init routine - setup timer 4622 */ 4623 static int 4624 poll_init( 4625 struct parseunit *parse 4626 ) 4627 { 4628 if (((poll_info_t *)parse->parse_type->cl_data)->rate) 4629 { 4630 parse->peer->action = poll_poll; 4631 poll_poll(parse->peer); 4632 } 4633 4634 return 0; 4635 } 4636 4637 /**=========================================================================== 4638 ** Trimble support 4639 **/ 4640 4641 /*------------------------------------------------------------- 4642 * trimble TAIP init routine - setup EOL and then do poll_init. 4643 */ 4644 static int 4645 trimbletaip_init( 4646 struct parseunit *parse 4647 ) 4648 { 4649 #ifdef HAVE_TERMIOS 4650 struct termios tio; 4651 #endif 4652 #ifdef HAVE_SYSV_TTYS 4653 struct termio tio; 4654 #endif 4655 /* 4656 * configure terminal line for trimble receiver 4657 */ 4658 if (TTY_GETATTR(parse->generic->io.fd, &tio) == -1) 4659 { 4660 msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_init: tcgetattr(fd, &tio): %m", CLK_UNIT(parse->peer)); 4661 return 0; 4662 } 4663 else 4664 { 4665 tio.c_cc[VEOL] = TRIMBLETAIP_EOL; 4666 4667 if (TTY_SETATTR(parse->generic->io.fd, &tio) == -1) 4668 { 4669 msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_init: tcsetattr(fd, &tio): %m", CLK_UNIT(parse->peer)); 4670 return 0; 4671 } 4672 } 4673 return poll_init(parse); 4674 } 4675 4676 /*-------------------------------------------------- 4677 * trimble TAIP event routine - reset receiver upon data format trouble 4678 */ 4679 static const char *taipinit[] = { 4680 ">FPV00000000<", 4681 ">SRM;ID_FLAG=F;CS_FLAG=T;EC_FLAG=F;FR_FLAG=T;CR_FLAG=F<", 4682 ">FTM00020001<", 4683 (char *)0 4684 }; 4685 4686 static void 4687 trimbletaip_event( 4688 struct parseunit *parse, 4689 int event 4690 ) 4691 { 4692 switch (event) 4693 { 4694 case CEVNT_BADREPLY: /* reset on garbled input */ 4695 case CEVNT_TIMEOUT: /* reset on no input */ 4696 { 4697 const char **iv; 4698 4699 iv = taipinit; 4700 while (*iv) 4701 { 4702 int rtc = write(parse->generic->io.fd, *iv, strlen(*iv)); 4703 if (rtc < 0) 4704 { 4705 msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_event: failed to send cmd to clock: %m", CLK_UNIT(parse->peer)); 4706 return; 4707 } 4708 else 4709 { 4710 if (rtc != strlen(*iv)) 4711 { 4712 msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_event: failed to send cmd incomplete (%d of %d bytes sent)", 4713 CLK_UNIT(parse->peer), rtc, (int)strlen(*iv)); 4714 return; 4715 } 4716 } 4717 iv++; 4718 } 4719 4720 NLOG(NLOG_CLOCKINFO) 4721 ERR(ERR_BADIO) 4722 msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_event: RECEIVER INITIALIZED", 4723 CLK_UNIT(parse->peer)); 4724 } 4725 break; 4726 4727 default: /* ignore */ 4728 break; 4729 } 4730 } 4731 4732 /* 4733 * This driver supports the Trimble SVee Six Plus GPS receiver module. 4734 * It should support other Trimble receivers which use the Trimble Standard 4735 * Interface Protocol (see below). 4736 * 4737 * The module has a serial I/O port for command/data and a 1 pulse-per-second 4738 * output, about 1 microsecond wide. The leading edge of the pulse is 4739 * coincident with the change of the GPS second. This is the same as 4740 * the change of the UTC second +/- ~1 microsecond. Some other clocks 4741 * specifically use a feature in the data message as a timing reference, but 4742 * the SVee Six Plus does not do this. In fact there is considerable jitter 4743 * on the timing of the messages, so this driver only supports the use 4744 * of the PPS pulse for accurate timing. Where it is determined that 4745 * the offset is way off, when first starting up ntpd for example, 4746 * the timing of the data stream is used until the offset becomes low enough 4747 * (|offset| < CLOCK_MAX), at which point the pps offset is used. 4748 * 4749 * It can use either option for receiving PPS information - the 'ppsclock' 4750 * stream pushed onto the serial data interface to timestamp the Carrier 4751 * Detect interrupts, where the 1PPS connects to the CD line. This only 4752 * works on SunOS 4.1.x currently. To select this, define PPSPPS in 4753 * Config.local. The other option is to use a pulse-stretcher/level-converter 4754 * to convert the PPS pulse into a RS232 start pulse & feed this into another 4755 * tty port. To use this option, define PPSCLK in Config.local. The pps input, 4756 * by whichever method, is handled in ntp_loopfilter.c 4757 * 4758 * The receiver uses a serial message protocol called Trimble Standard 4759 * Interface Protocol (it can support others but this driver only supports 4760 * TSIP). Messages in this protocol have the following form: 4761 * 4762 * <DLE><id> ... <data> ... <DLE><ETX> 4763 * 4764 * Any bytes within the <data> portion of value 10 hex (<DLE>) are doubled 4765 * on transmission and compressed back to one on reception. Otherwise 4766 * the values of data bytes can be anything. The serial interface is RS-422 4767 * asynchronous using 9600 baud, 8 data bits with odd party (**note** 9 bits 4768 * in total!), and 1 stop bit. The protocol supports byte, integer, single, 4769 * and double datatypes. Integers are two bytes, sent most significant first. 4770 * Singles are IEEE754 single precision floating point numbers (4 byte) sent 4771 * sign & exponent first. Doubles are IEEE754 double precision floating point 4772 * numbers (8 byte) sent sign & exponent first. 4773 * The receiver supports a large set of messages, only a small subset of 4774 * which are used here. From driver to receiver the following are used: 4775 * 4776 * ID Description 4777 * 4778 * 21 Request current time 4779 * 22 Mode Select 4780 * 2C Set/Request operating parameters 4781 * 2F Request UTC info 4782 * 35 Set/Request I/O options 4783 4784 * From receiver to driver the following are recognised: 4785 * 4786 * ID Description 4787 * 4788 * 41 GPS Time 4789 * 44 Satellite selection, PDOP, mode 4790 * 46 Receiver health 4791 * 4B Machine code/status 4792 * 4C Report operating parameters (debug only) 4793 * 4F UTC correction data (used to get leap second warnings) 4794 * 55 I/O options (debug only) 4795 * 4796 * All others are accepted but ignored. 4797 * 4798 */ 4799 4800 #define PI 3.1415926535898 /* lots of sig figs */ 4801 #define D2R PI/180.0 4802 4803 /*------------------------------------------------------------------- 4804 * sendcmd, sendbyte, sendetx, sendflt, sendint implement the command 4805 * interface to the receiver. 4806 * 4807 * CAVEAT: the sendflt, sendint routines are byte order dependend and 4808 * float implementation dependend - these must be converted to portable 4809 * versions ! 4810 * 4811 * CURRENT LIMITATION: float implementation. This runs only on systems 4812 * with IEEE754 floats as native floats 4813 */ 4814 4815 typedef struct trimble 4816 { 4817 u_long last_msg; /* last message received */ 4818 u_long last_reset; /* last time a reset was issued */ 4819 u_char qtracking; /* query tracking status */ 4820 u_long ctrack; /* current tracking set */ 4821 u_long ltrack; /* last tracking set */ 4822 } trimble_t; 4823 4824 union uval { 4825 u_char bd[8]; 4826 int iv; 4827 float fv; 4828 double dv; 4829 }; 4830 4831 struct txbuf 4832 { 4833 short idx; /* index to first unused byte */ 4834 u_char *txt; /* pointer to actual data buffer */ 4835 }; 4836 4837 void sendcmd P((struct txbuf *buf, int c)); 4838 void sendbyte P((struct txbuf *buf, int b)); 4839 void sendetx P((struct txbuf *buf, struct parseunit *parse)); 4840 void sendint P((struct txbuf *buf, int a)); 4841 void sendflt P((struct txbuf *buf, double a)); 4842 4843 void 4844 sendcmd( 4845 struct txbuf *buf, 4846 int c 4847 ) 4848 { 4849 buf->txt[0] = DLE; 4850 buf->txt[1] = (u_char)c; 4851 buf->idx = 2; 4852 } 4853 4854 void sendcmd P((struct txbuf *buf, int c)); 4855 void sendbyte P((struct txbuf *buf, int b)); 4856 void sendetx P((struct txbuf *buf, struct parseunit *parse)); 4857 void sendint P((struct txbuf *buf, int a)); 4858 void sendflt P((struct txbuf *buf, double a)); 4859 4860 void 4861 sendbyte( 4862 struct txbuf *buf, 4863 int b 4864 ) 4865 { 4866 if (b == DLE) 4867 buf->txt[buf->idx++] = DLE; 4868 buf->txt[buf->idx++] = (u_char)b; 4869 } 4870 4871 void 4872 sendetx( 4873 struct txbuf *buf, 4874 struct parseunit *parse 4875 ) 4876 { 4877 buf->txt[buf->idx++] = DLE; 4878 buf->txt[buf->idx++] = ETX; 4879 4880 if (write(parse->generic->io.fd, buf->txt, (unsigned long)buf->idx) != buf->idx) 4881 { 4882 ERR(ERR_BADIO) 4883 msyslog(LOG_ERR, "PARSE receiver #%d: sendetx: failed to send cmd to clock: %m", CLK_UNIT(parse->peer)); 4884 } 4885 else 4886 { 4887 #ifdef DEBUG 4888 if (debug > 2) 4889 { 4890 char buffer[256]; 4891 4892 mkreadable(buffer, sizeof(buffer), (char *)buf->txt, (unsigned)buf->idx, 1); 4893 printf("PARSE receiver #%d: transmitted message (%d bytes) >%s<\n", 4894 CLK_UNIT(parse->peer), 4895 buf->idx, buffer); 4896 } 4897 #endif 4898 clear_err(parse, ERR_BADIO); 4899 } 4900 } 4901 4902 void 4903 sendint( 4904 struct txbuf *buf, 4905 int a 4906 ) 4907 { 4908 /* send 16bit int, msbyte first */ 4909 sendbyte(buf, (u_char)((a>>8) & 0xff)); 4910 sendbyte(buf, (u_char)(a & 0xff)); 4911 } 4912 4913 void 4914 sendflt( 4915 struct txbuf *buf, 4916 double a 4917 ) 4918 { 4919 int i; 4920 union uval uval; 4921 4922 uval.fv = a; 4923 #ifdef WORDS_BIGENDIAN 4924 for (i=0; i<=3; i++) 4925 #else 4926 for (i=3; i>=0; i--) 4927 #endif 4928 sendbyte(buf, uval.bd[i]); 4929 } 4930 4931 #define TRIM_POS_OPT 0x13 /* output position with high precision */ 4932 #define TRIM_TIME_OPT 0x03 /* use UTC time stamps, on second */ 4933 4934 /*-------------------------------------------------- 4935 * trimble TSIP setup routine 4936 */ 4937 static int 4938 trimbletsip_setup( 4939 struct parseunit *parse, 4940 const char *reason 4941 ) 4942 { 4943 u_char buffer[256]; 4944 struct txbuf buf; 4945 trimble_t *t = parse->localdata; 4946 4947 if (t && t->last_reset && 4948 ((t->last_reset + TRIMBLE_RESET_HOLDOFF) > current_time)) { 4949 return 1; /* not yet */ 4950 } 4951 4952 if (t) 4953 t->last_reset = current_time; 4954 4955 buf.txt = buffer; 4956 4957 sendcmd(&buf, CMD_CVERSION); /* request software versions */ 4958 sendetx(&buf, parse); 4959 4960 sendcmd(&buf, CMD_COPERPARAM); /* set operating parameters */ 4961 sendbyte(&buf, 4); /* static */ 4962 sendflt(&buf, 5.0*D2R); /* elevation angle mask = 10 deg XXX */ 4963 sendflt(&buf, 4.0); /* s/n ratio mask = 6 XXX */ 4964 sendflt(&buf, 12.0); /* PDOP mask = 12 */ 4965 sendflt(&buf, 8.0); /* PDOP switch level = 8 */ 4966 sendetx(&buf, parse); 4967 4968 sendcmd(&buf, CMD_CMODESEL); /* fix mode select */ 4969 sendbyte(&buf, 1); /* time transfer mode */ 4970 sendetx(&buf, parse); 4971 4972 sendcmd(&buf, CMD_CMESSAGE); /* request system message */ 4973 sendetx(&buf, parse); 4974 4975 sendcmd(&buf, CMD_CSUPER); /* superpacket fix */ 4976 sendbyte(&buf, 0x2); /* binary mode */ 4977 sendetx(&buf, parse); 4978 4979 sendcmd(&buf, CMD_CIOOPTIONS); /* set I/O options */ 4980 sendbyte(&buf, TRIM_POS_OPT); /* position output */ 4981 sendbyte(&buf, 0x00); /* no velocity output */ 4982 sendbyte(&buf, TRIM_TIME_OPT); /* UTC, compute on seconds */ 4983 sendbyte(&buf, 0x00); /* no raw measurements */ 4984 sendetx(&buf, parse); 4985 4986 sendcmd(&buf, CMD_CUTCPARAM); /* request UTC correction data */ 4987 sendetx(&buf, parse); 4988 4989 NLOG(NLOG_CLOCKINFO) 4990 ERR(ERR_BADIO) 4991 msyslog(LOG_ERR, "PARSE receiver #%d: trimbletsip_setup: RECEIVER RE-INITIALIZED (%s)", CLK_UNIT(parse->peer), reason); 4992 4993 return 0; 4994 } 4995 4996 /*-------------------------------------------------- 4997 * TRIMBLE TSIP check routine 4998 */ 4999 static void 5000 trimble_check( 5001 struct peer *peer 5002 ) 5003 { 5004 struct parseunit *parse = (struct parseunit *)peer->procptr->unitptr; 5005 trimble_t *t = parse->localdata; 5006 u_char buffer[256]; 5007 struct txbuf buf; 5008 buf.txt = buffer; 5009 5010 if (t) 5011 { 5012 if (current_time > t->last_msg + TRIMBLETSIP_IDLE_TIME) 5013 (void)trimbletsip_setup(parse, "message timeout"); 5014 } 5015 5016 poll_poll(parse->peer); /* emit query string and re-arm timer */ 5017 5018 if (t && t->qtracking) 5019 { 5020 u_long oldsats = t->ltrack & ~t->ctrack; 5021 5022 t->qtracking = 0; 5023 t->ltrack = t->ctrack; 5024 5025 if (oldsats) 5026 { 5027 int i; 5028 5029 for (i = 0; oldsats; i++) { 5030 if (oldsats & (1 << i)) 5031 { 5032 sendcmd(&buf, CMD_CSTATTRACK); 5033 sendbyte(&buf, i+1); /* old sat */ 5034 sendetx(&buf, parse); 5035 } 5036 oldsats &= ~(1 << i); 5037 } 5038 } 5039 5040 sendcmd(&buf, CMD_CSTATTRACK); 5041 sendbyte(&buf, 0x00); /* current tracking set */ 5042 sendetx(&buf, parse); 5043 } 5044 } 5045 5046 /*-------------------------------------------------- 5047 * TRIMBLE TSIP end routine 5048 */ 5049 static void 5050 trimbletsip_end( 5051 struct parseunit *parse 5052 ) 5053 { trimble_t *t = parse->localdata; 5054 5055 if (t) 5056 { 5057 free(t); 5058 parse->localdata = (void *)0; 5059 } 5060 parse->peer->nextaction = 0; 5061 parse->peer->action = (void (*) P((struct peer *)))0; 5062 } 5063 5064 /*-------------------------------------------------- 5065 * TRIMBLE TSIP init routine 5066 */ 5067 static int 5068 trimbletsip_init( 5069 struct parseunit *parse 5070 ) 5071 { 5072 #if defined(VEOL) || defined(VEOL2) 5073 #ifdef HAVE_TERMIOS 5074 struct termios tio; /* NEEDED FOR A LONG TIME ! */ 5075 #endif 5076 #ifdef HAVE_SYSV_TTYS 5077 struct termio tio; /* NEEDED FOR A LONG TIME ! */ 5078 #endif 5079 /* 5080 * allocate local data area 5081 */ 5082 if (!parse->localdata) 5083 { 5084 trimble_t *t; 5085 5086 t = (trimble_t *)(parse->localdata = emalloc(sizeof(trimble_t))); 5087 5088 if (t) 5089 { 5090 memset((char *)t, 0, sizeof(trimble_t)); 5091 t->last_msg = current_time; 5092 } 5093 } 5094 5095 parse->peer->action = trimble_check; 5096 parse->peer->nextaction = current_time; 5097 5098 /* 5099 * configure terminal line for ICANON mode with VEOL characters 5100 */ 5101 if (TTY_GETATTR(parse->generic->io.fd, &tio) == -1) 5102 { 5103 msyslog(LOG_ERR, "PARSE receiver #%d: trimbletsip_init: tcgetattr(%d, &tio): %m", CLK_UNIT(parse->peer), parse->generic->io.fd); 5104 return 0; 5105 } 5106 else 5107 { 5108 if ((parse_clockinfo[CLK_TYPE(parse->peer)].cl_lflag & ICANON)) 5109 { 5110 #ifdef VEOL 5111 tio.c_cc[VEOL] = ETX; 5112 #endif 5113 #ifdef VEOL2 5114 tio.c_cc[VEOL2] = DLE; 5115 #endif 5116 } 5117 5118 if (TTY_SETATTR(parse->generic->io.fd, &tio) == -1) 5119 { 5120 msyslog(LOG_ERR, "PARSE receiver #%d: trimbletsip_init: tcsetattr(%d, &tio): %m", CLK_UNIT(parse->peer), parse->generic->io.fd); 5121 return 0; 5122 } 5123 } 5124 #endif 5125 return trimbletsip_setup(parse, "initial startup"); 5126 } 5127 5128 /*------------------------------------------------------------ 5129 * trimbletsip_event - handle Trimble events 5130 * simple evente handler - attempt to re-initialize receiver 5131 */ 5132 static void 5133 trimbletsip_event( 5134 struct parseunit *parse, 5135 int event 5136 ) 5137 { 5138 switch (event) 5139 { 5140 case CEVNT_BADREPLY: /* reset on garbled input */ 5141 case CEVNT_TIMEOUT: /* reset on no input */ 5142 (void)trimbletsip_setup(parse, "event BAD_REPLY/TIMEOUT"); 5143 break; 5144 5145 default: /* ignore */ 5146 break; 5147 } 5148 } 5149 5150 /* 5151 * getflt, getint convert fields in the incoming data into the 5152 * appropriate type of item 5153 * 5154 * CAVEAT: these routines are currently definitely byte order dependent 5155 * and assume Representation(float) == IEEE754 5156 * These functions MUST be converted to portable versions (especially 5157 * converting the float representation into ntp_fp formats in order 5158 * to avoid floating point operations at all! 5159 */ 5160 5161 static float 5162 getflt( 5163 u_char *bp 5164 ) 5165 { 5166 union uval uval; 5167 5168 #ifdef WORDS_BIGENDIAN 5169 uval.bd[0] = *bp++; 5170 uval.bd[1] = *bp++; 5171 uval.bd[2] = *bp++; 5172 uval.bd[3] = *bp; 5173 #else /* ! WORDS_BIGENDIAN */ 5174 uval.bd[3] = *bp++; 5175 uval.bd[2] = *bp++; 5176 uval.bd[1] = *bp++; 5177 uval.bd[0] = *bp; 5178 #endif /* ! WORDS_BIGENDIAN */ 5179 return uval.fv; 5180 } 5181 5182 static double 5183 getdbl( 5184 u_char *bp 5185 ) 5186 { 5187 union uval uval; 5188 5189 #ifdef WORDS_BIGENDIAN 5190 uval.bd[0] = *bp++; 5191 uval.bd[1] = *bp++; 5192 uval.bd[2] = *bp++; 5193 uval.bd[3] = *bp++; 5194 uval.bd[4] = *bp++; 5195 uval.bd[5] = *bp++; 5196 uval.bd[6] = *bp++; 5197 uval.bd[7] = *bp; 5198 #else /* ! WORDS_BIGENDIAN */ 5199 uval.bd[7] = *bp++; 5200 uval.bd[6] = *bp++; 5201 uval.bd[5] = *bp++; 5202 uval.bd[4] = *bp++; 5203 uval.bd[3] = *bp++; 5204 uval.bd[2] = *bp++; 5205 uval.bd[1] = *bp++; 5206 uval.bd[0] = *bp; 5207 #endif /* ! WORDS_BIGENDIAN */ 5208 return uval.dv; 5209 } 5210 5211 static int 5212 getshort( 5213 unsigned char *p 5214 ) 5215 { 5216 return get_msb_short(&p); 5217 } 5218 5219 /*-------------------------------------------------- 5220 * trimbletsip_message - process trimble messages 5221 */ 5222 #define RTOD (180.0 / 3.1415926535898) 5223 #define mb(_X_) (buffer[2+(_X_)]) /* shortcut for buffer access */ 5224 5225 static void 5226 trimbletsip_message( 5227 struct parseunit *parse, 5228 parsetime_t *parsetime 5229 ) 5230 { 5231 unsigned char *buffer = parsetime->parse_msg; 5232 unsigned int size = parsetime->parse_msglen; 5233 5234 if ((size < 4) || 5235 (buffer[0] != DLE) || 5236 (buffer[size-1] != ETX) || 5237 (buffer[size-2] != DLE)) 5238 { 5239 #ifdef DEBUG 5240 if (debug > 2) { 5241 int i; 5242 5243 printf("TRIMBLE BAD packet, size %d:\n ", size); 5244 for (i = 0; i < size; i++) { 5245 printf ("%2.2x, ", buffer[i]&0xff); 5246 if (i%16 == 15) printf("\n\t"); 5247 } 5248 printf("\n"); 5249 } 5250 #endif 5251 return; 5252 } 5253 else 5254 { 5255 int var_flag; 5256 trimble_t *tr = parse->localdata; 5257 unsigned int cmd = buffer[1]; 5258 char pbuffer[200]; 5259 char *t = pbuffer; 5260 cmd_info_t *s; 5261 5262 #ifdef DEBUG 5263 if (debug > 3) { 5264 int i; 5265 5266 printf("TRIMBLE packet 0x%02x, size %d:\n ", cmd, size); 5267 for (i = 0; i < size; i++) { 5268 printf ("%2.2x, ", buffer[i]&0xff); 5269 if (i%16 == 15) printf("\n\t"); 5270 } 5271 printf("\n"); 5272 } 5273 #endif 5274 5275 if (tr) 5276 tr->last_msg = current_time; 5277 5278 s = trimble_convert(cmd, trimble_rcmds); 5279 5280 if (s) 5281 { 5282 snprintf(t, BUFFER_SIZE(pbuffer, t), "%s=\"", s->varname); 5283 } 5284 else 5285 { 5286 DPRINTF(1, ("TRIMBLE UNKNOWN COMMAND 0x%02x\n", cmd)); 5287 return; 5288 } 5289 5290 var_flag = s->varmode; 5291 5292 t += strlen(t); 5293 5294 switch(cmd) 5295 { 5296 case CMD_RCURTIME: 5297 snprintf(t, BUFFER_SIZE(pbuffer, t), "%f, %d, %f", 5298 getflt((unsigned char *)&mb(0)), getshort((unsigned char *)&mb(4)), 5299 getflt((unsigned char *)&mb(6))); 5300 break; 5301 5302 case CMD_RBEST4: 5303 strncpy(t, "mode: ", BUFFER_SIZE(pbuffer, t)); 5304 t += strlen(t); 5305 switch (mb(0) & 0xF) 5306 { 5307 default: 5308 snprintf(t, BUFFER_SIZE(pbuffer, t), "0x%x", mb(0) & 0x7); 5309 break; 5310 5311 case 1: 5312 strncpy(t, "0D", BUFFER_SIZE(pbuffer, t)); 5313 break; 5314 5315 case 3: 5316 strncpy(t, "2D", BUFFER_SIZE(pbuffer, t)); 5317 break; 5318 5319 case 4: 5320 strncpy(t, "3D", BUFFER_SIZE(pbuffer, t)); 5321 break; 5322 } 5323 t += strlen(t); 5324 if (mb(0) & 0x10) 5325 strncpy(t, "-MANUAL, ", BUFFER_SIZE(pbuffer, t)); 5326 else 5327 strncpy(t, "-AUTO, ", BUFFER_SIZE(pbuffer, t)); 5328 t += strlen(t); 5329 5330 snprintf(t, BUFFER_SIZE(pbuffer, t), "satellites %02d %02d %02d %02d, PDOP %.2f, HDOP %.2f, VDOP %.2f, TDOP %.2f", 5331 mb(1), mb(2), mb(3), mb(4), 5332 getflt((unsigned char *)&mb(5)), 5333 getflt((unsigned char *)&mb(9)), 5334 getflt((unsigned char *)&mb(13)), 5335 getflt((unsigned char *)&mb(17))); 5336 5337 break; 5338 5339 case CMD_RVERSION: 5340 snprintf(t, BUFFER_SIZE(pbuffer, t), "%d.%d (%d/%d/%d)", 5341 mb(0)&0xff, mb(1)&0xff, 1900+(mb(4)&0xff), mb(2)&0xff, mb(3)&0xff); 5342 break; 5343 5344 case CMD_RRECVHEALTH: 5345 { 5346 static const char *msgs[] = 5347 { 5348 "Battery backup failed", 5349 "Signal processor error", 5350 "Alignment error, channel or chip 1", 5351 "Alignment error, channel or chip 2", 5352 "Antenna feed line fault", 5353 "Excessive ref freq. error", 5354 "<BIT 6>", 5355 "<BIT 7>" 5356 }; 5357 5358 int i, bits; 5359 5360 switch (mb(0) & 0xFF) 5361 { 5362 default: 5363 snprintf(t, BUFFER_SIZE(pbuffer, t), "illegal value 0x%02x", mb(0) & 0xFF); 5364 break; 5365 case 0x00: 5366 strncpy(t, "doing position fixes", BUFFER_SIZE(pbuffer, t)); 5367 break; 5368 case 0x01: 5369 strncpy(t, "no GPS time yet", BUFFER_SIZE(pbuffer, t)); 5370 break; 5371 case 0x03: 5372 strncpy(t, "PDOP too high", BUFFER_SIZE(pbuffer, t)); 5373 break; 5374 case 0x08: 5375 strncpy(t, "no usable satellites", BUFFER_SIZE(pbuffer, t)); 5376 break; 5377 case 0x09: 5378 strncpy(t, "only ONE usable satellite", BUFFER_SIZE(pbuffer, t)); 5379 break; 5380 case 0x0A: 5381 strncpy(t, "only TWO usable satellites", BUFFER_SIZE(pbuffer, t)); 5382 break; 5383 case 0x0B: 5384 strncpy(t, "only THREE usable satellites", BUFFER_SIZE(pbuffer, t)); 5385 break; 5386 case 0x0C: 5387 strncpy(t, "the chosen satellite is unusable", BUFFER_SIZE(pbuffer, t)); 5388 break; 5389 } 5390 5391 t += strlen(t); 5392 5393 bits = mb(1) & 0xFF; 5394 5395 for (i = 0; i < 8; i++) 5396 if (bits & (0x1<<i)) 5397 { 5398 snprintf(t, BUFFER_SIZE(pbuffer, t), ", %s", msgs[i]); 5399 t += strlen(t); 5400 } 5401 } 5402 break; 5403 5404 case CMD_RMESSAGE: 5405 mkreadable(t, (int)BUFFER_SIZE(pbuffer, t), (char *)&mb(0), (unsigned)(size - 2 - (&mb(0) - buffer)), 0); 5406 break; 5407 5408 case CMD_RMACHSTAT: 5409 { 5410 static const char *msgs[] = 5411 { 5412 "Synthesizer Fault", 5413 "Battery Powered Time Clock Fault", 5414 "A-to-D Converter Fault", 5415 "The almanac stored in the receiver is not complete and current", 5416 "<BIT 4>", 5417 "<BIT 5", 5418 "<BIT 6>", 5419 "<BIT 7>" 5420 }; 5421 5422 int i, bits; 5423 5424 snprintf(t, BUFFER_SIZE(pbuffer, t), "machine id 0x%02x", mb(0) & 0xFF); 5425 t += strlen(t); 5426 5427 bits = mb(1) & 0xFF; 5428 5429 for (i = 0; i < 8; i++) 5430 if (bits & (0x1<<i)) 5431 { 5432 snprintf(t, BUFFER_SIZE(pbuffer, t), ", %s", msgs[i]); 5433 t += strlen(t); 5434 } 5435 5436 snprintf(t, BUFFER_SIZE(pbuffer, t), ", Superpackets %ssupported", (mb(2) & 0xFF) ? "" :"un" ); 5437 } 5438 break; 5439 5440 case CMD_ROPERPARAM: 5441 snprintf(t, BUFFER_SIZE(pbuffer, t), "%2x %.1f %.1f %.1f %.1f", 5442 mb(0), getflt((unsigned char *)&mb(1)), getflt((unsigned char *)&mb(5)), 5443 getflt((unsigned char *)&mb(9)), getflt((unsigned char *)&mb(13))); 5444 break; 5445 5446 case CMD_RUTCPARAM: 5447 { 5448 float t0t = getflt((unsigned char *)&mb(14)); 5449 short wnt = getshort((unsigned char *)&mb(18)); 5450 short dtls = getshort((unsigned char *)&mb(12)); 5451 short wnlsf = getshort((unsigned char *)&mb(20)); 5452 short dn = getshort((unsigned char *)&mb(22)); 5453 short dtlsf = getshort((unsigned char *)&mb(24)); 5454 5455 if ((int)t0t != 0) 5456 { 5457 mk_utcinfo(t, wnt, wnlsf, dn, dtls, dtlsf, BUFFER_SIZE(pbuffer, t)); 5458 } 5459 else 5460 { 5461 strncpy(t, "<NO UTC DATA>", BUFFER_SIZE(pbuffer, t)); 5462 } 5463 } 5464 break; 5465 5466 case CMD_RSAT1BIAS: 5467 snprintf(t, BUFFER_SIZE(pbuffer, t), "%.1fm %.2fm/s at %.1fs", 5468 getflt(&mb(0)), getflt(&mb(4)), getflt(&mb(8))); 5469 break; 5470 5471 case CMD_RIOOPTIONS: 5472 { 5473 snprintf(t, BUFFER_SIZE(pbuffer, t), "%02x %02x %02x %02x", 5474 mb(0), mb(1), mb(2), mb(3)); 5475 if (mb(0) != TRIM_POS_OPT || 5476 mb(2) != TRIM_TIME_OPT) 5477 { 5478 (void)trimbletsip_setup(parse, "bad io options"); 5479 } 5480 } 5481 break; 5482 5483 case CMD_RSPOSXYZ: 5484 { 5485 double x = getflt((unsigned char *)&mb(0)); 5486 double y = getflt((unsigned char *)&mb(4)); 5487 double z = getflt((unsigned char *)&mb(8)); 5488 double f = getflt((unsigned char *)&mb(12)); 5489 5490 if (f > 0.0) 5491 snprintf(t, BUFFER_SIZE(pbuffer, t), "x= %.1fm, y= %.1fm, z= %.1fm, time_of_fix= %f sec", 5492 x, y, z, 5493 f); 5494 else 5495 return; 5496 } 5497 break; 5498 5499 case CMD_RSLLAPOS: 5500 { 5501 double lat = getflt((unsigned char *)&mb(0)); 5502 double lng = getflt((unsigned char *)&mb(4)); 5503 double f = getflt((unsigned char *)&mb(12)); 5504 5505 if (f > 0.0) 5506 snprintf(t, BUFFER_SIZE(pbuffer, t), "lat %f %c, long %f %c, alt %.2fm", 5507 ((lat < 0.0) ? (-lat) : (lat))*RTOD, (lat < 0.0 ? 'S' : 'N'), 5508 ((lng < 0.0) ? (-lng) : (lng))*RTOD, (lng < 0.0 ? 'W' : 'E'), 5509 getflt((unsigned char *)&mb(8))); 5510 else 5511 return; 5512 } 5513 break; 5514 5515 case CMD_RDOUBLEXYZ: 5516 { 5517 double x = getdbl((unsigned char *)&mb(0)); 5518 double y = getdbl((unsigned char *)&mb(8)); 5519 double z = getdbl((unsigned char *)&mb(16)); 5520 snprintf(t, BUFFER_SIZE(pbuffer, t), "x= %.1fm, y= %.1fm, z= %.1fm", 5521 x, y, z); 5522 } 5523 break; 5524 5525 case CMD_RDOUBLELLA: 5526 { 5527 double lat = getdbl((unsigned char *)&mb(0)); 5528 double lng = getdbl((unsigned char *)&mb(8)); 5529 snprintf(t, BUFFER_SIZE(pbuffer, t), "lat %f %c, lon %f %c, alt %.2fm", 5530 ((lat < 0.0) ? (-lat) : (lat))*RTOD, (lat < 0.0 ? 'S' : 'N'), 5531 ((lng < 0.0) ? (-lng) : (lng))*RTOD, (lng < 0.0 ? 'W' : 'E'), 5532 getdbl((unsigned char *)&mb(16))); 5533 } 5534 break; 5535 5536 case CMD_RALLINVIEW: 5537 { 5538 int i, sats; 5539 5540 strncpy(t, "mode: ", BUFFER_SIZE(pbuffer, t)); 5541 t += strlen(t); 5542 switch (mb(0) & 0x7) 5543 { 5544 default: 5545 snprintf(t, BUFFER_SIZE(pbuffer, t), "0x%x", mb(0) & 0x7); 5546 break; 5547 5548 case 3: 5549 strncpy(t, "2D", BUFFER_SIZE(pbuffer, t)); 5550 break; 5551 5552 case 4: 5553 strncpy(t, "3D", BUFFER_SIZE(pbuffer, t)); 5554 break; 5555 } 5556 t += strlen(t); 5557 if (mb(0) & 0x8) 5558 strncpy(t, "-MANUAL, ", BUFFER_SIZE(pbuffer, t)); 5559 else 5560 strncpy(t, "-AUTO, ", BUFFER_SIZE(pbuffer, t)); 5561 t += strlen(t); 5562 5563 sats = (mb(0)>>4) & 0xF; 5564 5565 snprintf(t, BUFFER_SIZE(pbuffer, t), "PDOP %.2f, HDOP %.2f, VDOP %.2f, TDOP %.2f, %d satellite%s in view: ", 5566 getflt((unsigned char *)&mb(1)), 5567 getflt((unsigned char *)&mb(5)), 5568 getflt((unsigned char *)&mb(9)), 5569 getflt((unsigned char *)&mb(13)), 5570 sats, (sats == 1) ? "" : "s"); 5571 t += strlen(t); 5572 5573 for (i=0; i < sats; i++) 5574 { 5575 snprintf(t, BUFFER_SIZE(pbuffer, t), "%s%02d", i ? ", " : "", mb(17+i)); 5576 t += strlen(t); 5577 if (tr) 5578 tr->ctrack |= (1 << (mb(17+i)-1)); 5579 } 5580 5581 if (tr) 5582 { /* mark for tracking status query */ 5583 tr->qtracking = 1; 5584 } 5585 } 5586 break; 5587 5588 case CMD_RSTATTRACK: 5589 { 5590 snprintf(t-2, BUFFER_SIZE(pbuffer, t-2), "[%02d]=\"", mb(0)); /* add index to var name */ 5591 t += strlen(t); 5592 5593 if (getflt((unsigned char *)&mb(4)) < 0.0) 5594 { 5595 strncpy(t, "<NO MEASUREMENTS>", BUFFER_SIZE(pbuffer, t)); 5596 var_flag &= ~DEF; 5597 } 5598 else 5599 { 5600 snprintf(t, BUFFER_SIZE(pbuffer, t), "ch=%d, acq=%s, eph=%d, signal_level= %5.2f, elevation= %5.2f, azimuth= %6.2f", 5601 (mb(1) & 0xFF)>>3, 5602 mb(2) ? ((mb(2) == 1) ? "ACQ" : "SRCH") : "NEVER", 5603 mb(3), 5604 getflt((unsigned char *)&mb(4)), 5605 getflt((unsigned char *)&mb(12)) * RTOD, 5606 getflt((unsigned char *)&mb(16)) * RTOD); 5607 t += strlen(t); 5608 if (mb(20)) 5609 { 5610 var_flag &= ~DEF; 5611 strncpy(t, ", OLD", BUFFER_SIZE(pbuffer, t)); 5612 } 5613 t += strlen(t); 5614 if (mb(22)) 5615 { 5616 if (mb(22) == 1) 5617 strncpy(t, ", BAD PARITY", BUFFER_SIZE(pbuffer, t)); 5618 else 5619 if (mb(22) == 2) 5620 strncpy(t, ", BAD EPH HEALTH", BUFFER_SIZE(pbuffer, t)); 5621 } 5622 t += strlen(t); 5623 if (mb(23)) 5624 strncpy(t, ", collecting data", BUFFER_SIZE(pbuffer, t)); 5625 } 5626 } 5627 break; 5628 5629 default: 5630 strncpy(t, "<UNDECODED>", BUFFER_SIZE(pbuffer, t)); 5631 break; 5632 } 5633 t += strlen(t); 5634 5635 strncpy(t,"\"", BUFFER_SIZE(pbuffer, t)); 5636 set_var(&parse->kv, pbuffer, sizeof(pbuffer), var_flag); 5637 } 5638 } 5639 5640 5641 /**============================================================ 5642 ** RAWDCF support 5643 **/ 5644 5645 /*-------------------------------------------------- 5646 * rawdcf_init_1 - set up modem lines for RAWDCF receivers 5647 * SET DTR line 5648 */ 5649 #if defined(TIOCMSET) && (defined(TIOCM_DTR) || defined(CIOCM_DTR)) 5650 static int 5651 rawdcf_init_1( 5652 struct parseunit *parse 5653 ) 5654 { 5655 /* fixed 2000 for using with Linux by Wolfram Pienkoss <wp@bszh.de> */ 5656 /* 5657 * You can use the RS232 to supply the power for a DCF77 receiver. 5658 * Here a voltage between the DTR and the RTS line is used. Unfortunately 5659 * the name has changed from CIOCM_DTR to TIOCM_DTR recently. 5660 */ 5661 int sl232; 5662 5663 if (ioctl(parse->generic->io.fd, TIOCMGET, (caddr_t)&sl232) == -1) 5664 { 5665 msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_1: WARNING: ioctl(fd, TIOCMGET, [C|T]IOCM_DTR): %m", CLK_UNIT(parse->peer)); 5666 return 0; 5667 } 5668 5669 #ifdef TIOCM_DTR 5670 sl232 = (sl232 & ~TIOCM_RTS) | TIOCM_DTR; /* turn on DTR, clear RTS for power supply */ 5671 #else 5672 sl232 = (sl232 & ~CIOCM_RTS) | CIOCM_DTR; /* turn on DTR, clear RTS for power supply */ 5673 #endif 5674 5675 if (ioctl(parse->generic->io.fd, TIOCMSET, (caddr_t)&sl232) == -1) 5676 { 5677 msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_1: WARNING: ioctl(fd, TIOCMSET, [C|T]IOCM_DTR): %m", CLK_UNIT(parse->peer)); 5678 } 5679 return 0; 5680 } 5681 #else 5682 static int 5683 rawdcfdtr_init_1( 5684 struct parseunit *parse 5685 ) 5686 { 5687 msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_1: WARNING: OS interface incapable of setting DTR to power DCF modules", CLK_UNIT(parse->peer)); 5688 return 0; 5689 } 5690 #endif /* DTR initialisation type */ 5691 5692 /*-------------------------------------------------- 5693 * rawdcf_init_2 - set up modem lines for RAWDCF receivers 5694 * CLR DTR line, SET RTS line 5695 */ 5696 #if defined(TIOCMSET) && (defined(TIOCM_RTS) || defined(CIOCM_RTS)) 5697 static int 5698 rawdcf_init_2( 5699 struct parseunit *parse 5700 ) 5701 { 5702 /* fixed 2000 for using with Linux by Wolfram Pienkoss <wp@bszh.de> */ 5703 /* 5704 * You can use the RS232 to supply the power for a DCF77 receiver. 5705 * Here a voltage between the DTR and the RTS line is used. Unfortunately 5706 * the name has changed from CIOCM_DTR to TIOCM_DTR recently. 5707 */ 5708 int sl232; 5709 5710 if (ioctl(parse->generic->io.fd, TIOCMGET, (caddr_t)&sl232) == -1) 5711 { 5712 msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_2: WARNING: ioctl(fd, TIOCMGET, [C|T]IOCM_RTS): %m", CLK_UNIT(parse->peer)); 5713 return 0; 5714 } 5715 5716 #ifdef TIOCM_RTS 5717 sl232 = (sl232 & ~TIOCM_DTR) | TIOCM_RTS; /* turn on RTS, clear DTR for power supply */ 5718 #else 5719 sl232 = (sl232 & ~CIOCM_DTR) | CIOCM_RTS; /* turn on RTS, clear DTR for power supply */ 5720 #endif 5721 5722 if (ioctl(parse->generic->io.fd, TIOCMSET, (caddr_t)&sl232) == -1) 5723 { 5724 msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_2: WARNING: ioctl(fd, TIOCMSET, [C|T]IOCM_RTS): %m", CLK_UNIT(parse->peer)); 5725 } 5726 return 0; 5727 } 5728 #else 5729 static int 5730 rawdcf_init_2( 5731 struct parseunit *parse 5732 ) 5733 { 5734 msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_2: WARNING: OS interface incapable of setting RTS to power DCF modules", CLK_UNIT(parse->peer)); 5735 return 0; 5736 } 5737 #endif /* DTR initialisation type */ 5738 5739 #else /* defined(REFCLOCK) && defined(PARSE) */ 5740 int refclock_parse_bs; 5741 #endif /* defined(REFCLOCK) && defined(PARSE) */ 5742 5743 /* 5744 * History: 5745 * 5746 * refclock_parse.c,v 5747 * Revision 4.80 2007/08/11 12:06:29 kardel 5748 * update comments wrt/ to PPS 5749 * 5750 * Revision 4.79 2007/08/11 11:52:23 kardel 5751 * - terminate io bindings before io_closeclock() will close our file descriptor 5752 * 5753 * Revision 4.78 2006/12/22 20:08:27 kardel 5754 * Bug 746 (RFE): add configuration for Expert mouseCLOCK USB v2.0 as mode 19 5755 * 5756 * Revision 4.77 2006/08/05 07:44:49 kardel 5757 * support optionally separate PPS devices via /dev/refclockpps-{0..3} 5758 * 5759 * Revision 4.76 2006/06/22 18:40:47 kardel 5760 * clean up signedness (gcc 4) 5761 * 5762 * Revision 4.75 2006/06/22 16:58:10 kardel 5763 * Bug #632: call parse_ppsapi() in parse_ctl() when updating 5764 * the PPS offset. Fix sign of offset passed to kernel. 5765 * 5766 * Revision 4.74 2006/06/18 21:18:37 kardel 5767 * NetBSD Coverity CID 3796: possible NULL deref 5768 * 5769 * Revision 4.73 2006/05/26 14:23:46 kardel 5770 * cleanup of copyright info 5771 * 5772 * Revision 4.72 2006/05/26 14:19:43 kardel 5773 * cleanup of ioctl cruft 5774 * 5775 * Revision 4.71 2006/05/26 14:15:57 kardel 5776 * delay adding refclock to async refclock io after all initializations 5777 * 5778 * Revision 4.70 2006/05/25 18:20:50 kardel 5779 * bug #619 5780 * terminate parse io engine after de-registering 5781 * from refclock io engine 5782 * 5783 * Revision 4.69 2006/05/25 17:28:02 kardel 5784 * complete refclock io structure initialization *before* inserting it into the 5785 * refclock input machine (avoids null pointer deref) (bug #619) 5786 * 5787 * Revision 4.68 2006/05/01 17:02:51 kardel 5788 * copy receiver method also for newlwy created receive buffers 5789 * 5790 * Revision 4.67 2006/05/01 14:37:29 kardel 5791 * If an input buffer parses into more than one message do insert the 5792 * parsed message in a new input buffer instead of processing it 5793 * directly. This avoids deed complicated processing in signal 5794 * handling. 5795 * 5796 * Revision 4.66 2006/03/18 00:45:30 kardel 5797 * coverity fixes found in NetBSD coverity scan 5798 * 5799 * Revision 4.65 2006/01/26 06:08:33 kardel 5800 * output errno on PPS setup failure 5801 * 5802 * Revision 4.64 2005/11/09 20:44:47 kardel 5803 * utilize full PPS timestamp resolution from PPS API 5804 * 5805 * Revision 4.63 2005/10/07 22:10:25 kardel 5806 * bounded buffer implementation 5807 * 5808 * Revision 4.62.2.2 2005/09/25 10:20:16 kardel 5809 * avoid unexpected buffer overflows due to sprintf("%f") on strange floats: 5810 * replace almost all str* and *printf functions be their buffer bounded 5811 * counterparts 5812 * 5813 * Revision 4.62.2.1 2005/08/27 16:19:27 kardel 5814 * limit re-set rate of trimble clocks 5815 * 5816 * Revision 4.62 2005/08/06 17:40:00 kardel 5817 * cleanup size handling wrt/ to buffer boundaries 5818 * 5819 * Revision 4.61 2005/07/27 21:16:19 kardel 5820 * fix a long (> 11 years) misconfiguration wrt/ Meinberg cflag factory 5821 * default setup. CSTOPB was missing for the 7E2 default data format of 5822 * the DCF77 clocks. 5823 * 5824 * Revision 4.60 2005/07/17 21:14:44 kardel 5825 * change contents of version string to include the RCS/CVS Id 5826 * 5827 * Revision 4.59 2005/07/06 06:56:38 kardel 5828 * syntax error 5829 * 5830 * Revision 4.58 2005/07/04 13:10:40 kardel 5831 * fix bug 455: tripping over NULL pointer on cleanup 5832 * fix shadow storage logic for ppsphaseadjust and trustime wrt/ time2 5833 * fix compiler warnings for some platforms wrt/ printf formatstrings and 5834 * varying structure element sizes 5835 * reorder assignment in binding to avoid tripping over NULL pointers 5836 * 5837 * Revision 4.57 2005/06/25 09:25:19 kardel 5838 * sort out log output sequence 5839 * 5840 * Revision 4.56 2005/06/14 21:47:27 kardel 5841 * collect samples only if samples are ok (sync or trusted flywheel) 5842 * propagate pps phase adjustment value to kernel via PPSAPI to help HARDPPS 5843 * en- and dis-able HARDPPS in correlation to receiver sync state 5844 * 5845 * Revision 4.55 2005/06/02 21:28:31 kardel 5846 * clarify trust logic 5847 * 5848 * Revision 4.54 2005/06/02 17:06:49 kardel 5849 * change status reporting to use fixed refclock_report() 5850 * 5851 * Revision 4.53 2005/06/02 16:33:31 kardel 5852 * fix acceptance of clocks unsync clocks right at start 5853 * 5854 * Revision 4.52 2005/05/26 21:55:06 kardel 5855 * cleanup status reporting 5856 * 5857 * Revision 4.51 2005/05/26 19:19:14 kardel 5858 * implement fast refclock startup 5859 * 5860 * Revision 4.50 2005/04/16 20:51:35 kardel 5861 * set pps_enable = 1 when binding a kernel PPS source 5862 * 5863 * Revision 4.49 2005/04/16 17:29:26 kardel 5864 * add non polling clock type 18 for just listenning to Meinberg clocks 5865 * 5866 * Revision 4.48 2005/04/16 16:22:27 kardel 5867 * bk sync 20050415 ntp-dev 5868 * 5869 * Revision 4.47 2004/11/29 10:42:48 kardel 5870 * bk sync ntp-dev 20041129 5871 * 5872 * Revision 4.46 2004/11/29 10:26:29 kardel 5873 * keep fudgetime2 in sync with trusttime/ppsphaseadjust depending in flag1 5874 * 5875 * Revision 4.45 2004/11/14 20:53:20 kardel 5876 * clear PPS flags after using them 5877 * 5878 * Revision 4.44 2004/11/14 15:29:41 kardel 5879 * support PPSAPI, upgrade Copyright to Berkeley style 5880 * 5881 * Revision 4.43 2001/05/26 22:53:16 kardel 5882 * 20010526 reconcilation 5883 * 5884 * Revision 4.42 2000/05/14 15:31:51 kardel 5885 * PPSAPI && RAWDCF modemline support 5886 * 5887 * Revision 4.41 2000/04/09 19:50:45 kardel 5888 * fixed rawdcfdtr_init() -> rawdcf_init_1 5889 * 5890 * Revision 4.40 2000/04/09 15:27:55 kardel 5891 * modem line fiddle in rawdcf_init_2 5892 * 5893 * Revision 4.39 2000/03/18 09:16:55 kardel 5894 * PPSAPI integration 5895 * 5896 * Revision 4.38 2000/03/05 20:25:06 kardel 5897 * support PPSAPI 5898 * 5899 * Revision 4.37 2000/03/05 20:11:14 kardel 5900 * 4.0.99g reconcilation 5901 * 5902 * Revision 4.36 1999/11/28 17:18:20 kardel 5903 * disabled burst mode 5904 * 5905 * Revision 4.35 1999/11/28 09:14:14 kardel 5906 * RECON_4_0_98F 5907 * 5908 * Revision 4.34 1999/05/14 06:08:05 kardel 5909 * store current_time in a suitable container (u_long) 5910 * 5911 * Revision 4.33 1999/05/13 21:48:38 kardel 5912 * double the no response timeout interval 5913 * 5914 * Revision 4.32 1999/05/13 20:09:13 kardel 5915 * complain only about missing polls after a full poll interval 5916 * 5917 * Revision 4.31 1999/05/13 19:59:32 kardel 5918 * add clock type 16 for RTS set DTR clr in RAWDCF 5919 * 5920 * Revision 4.30 1999/02/28 20:36:43 kardel 5921 * fixed printf fmt 5922 * 5923 * Revision 4.29 1999/02/28 19:58:23 kardel 5924 * updated copyright information 5925 * 5926 * Revision 4.28 1999/02/28 19:01:50 kardel 5927 * improved debug out on sent Meinberg messages 5928 * 5929 * Revision 4.27 1999/02/28 18:05:55 kardel 5930 * no linux/ppsclock.h stuff 5931 * 5932 * Revision 4.26 1999/02/28 15:27:27 kardel 5933 * wharton clock integration 5934 * 5935 * Revision 4.25 1999/02/28 14:04:46 kardel 5936 * added missing double quotes to UTC information string 5937 * 5938 * Revision 4.24 1999/02/28 12:06:50 kardel 5939 * (parse_control): using gmprettydate instead of prettydate() 5940 * (mk_utcinfo): new function for formatting GPS derived UTC information 5941 * (gps16x_message): changed to use mk_utcinfo() 5942 * (trimbletsip_message): changed to use mk_utcinfo() 5943 * ignoring position information in unsynchronized mode 5944 * (parse_start): augument linux support for optional ASYNC_LOW_LATENCY 5945 * 5946 * Revision 4.23 1999/02/23 19:47:53 kardel 5947 * fixed #endifs 5948 * (stream_receive): fixed formats 5949 * 5950 * Revision 4.22 1999/02/22 06:21:02 kardel 5951 * use new autoconfig symbols 5952 * 5953 * Revision 4.21 1999/02/21 12:18:13 kardel 5954 * 4.91f reconcilation 5955 * 5956 * Revision 4.20 1999/02/21 10:53:36 kardel 5957 * initial Linux PPSkit version 5958 * 5959 * Revision 4.19 1999/02/07 09:10:45 kardel 5960 * clarify STREAMS mitigation rules in comment 5961 * 5962 * Revision 4.18 1998/12/20 23:45:34 kardel 5963 * fix types and warnings 5964 * 5965 * Revision 4.17 1998/11/15 21:24:51 kardel 5966 * cannot access mbg_ routines when CLOCK_MEINBERG 5967 * is not defined 5968 * 5969 * Revision 4.16 1998/11/15 20:28:17 kardel 5970 * Release 4.0.73e13 reconcilation 5971 * 5972 * Revision 4.15 1998/08/22 21:56:08 kardel 5973 * fixed IO handling for non-STREAM IO 5974 * 5975 * Revision 4.14 1998/08/16 19:00:48 kardel 5976 * (gps16x_message): reduced UTC parameter information (dropped A0,A1) 5977 * made uval a local variable (killed one of the last globals) 5978 * (sendetx): added logging of messages when in debug mode 5979 * (trimble_check): added periodic checks to facilitate re-initialization 5980 * (trimbletsip_init): made use of EOL character if in non-kernel operation 5981 * (trimbletsip_message): extended message interpretation 5982 * (getdbl): fixed data conversion 5983 * 5984 * Revision 4.13 1998/08/09 22:29:13 kardel 5985 * Trimble TSIP support 5986 * 5987 * Revision 4.12 1998/07/11 10:05:34 kardel 5988 * Release 4.0.73d reconcilation 5989 * 5990 * Revision 4.11 1998/06/14 21:09:42 kardel 5991 * Sun acc cleanup 5992 * 5993 * Revision 4.10 1998/06/13 12:36:45 kardel 5994 * signed/unsigned, name clashes 5995 * 5996 * Revision 4.9 1998/06/12 15:30:00 kardel 5997 * prototype fixes 5998 * 5999 * Revision 4.8 1998/06/12 11:19:42 kardel 6000 * added direct input processing routine for refclocks in 6001 * order to avaiod that single character io gobbles up all 6002 * receive buffers and drops input data. (Problem started 6003 * with fast machines so a character a buffer was possible 6004 * one of the few cases where faster machines break existing 6005 * allocation algorithms) 6006 * 6007 * Revision 4.7 1998/06/06 18:35:20 kardel 6008 * (parse_start): added BURST mode initialisation 6009 * 6010 * Revision 4.6 1998/05/27 06:12:46 kardel 6011 * RAWDCF_BASEDELAY default added 6012 * old comment removed 6013 * casts for ioctl() 6014 * 6015 * Revision 4.5 1998/05/25 22:05:09 kardel 6016 * RAWDCF_SETDTR option removed 6017 * clock type 14 attempts to set DTR for 6018 * power supply of RAWDCF receivers 6019 * 6020 * Revision 4.4 1998/05/24 16:20:47 kardel 6021 * updated comments referencing Meinberg clocks 6022 * added RAWDCF clock with DTR set option as type 14 6023 * 6024 * Revision 4.3 1998/05/24 10:48:33 kardel 6025 * calibrated CONRAD RAWDCF default fudge factor 6026 * 6027 * Revision 4.2 1998/05/24 09:59:35 kardel 6028 * corrected version information (ntpq support) 6029 * 6030 * Revision 4.1 1998/05/24 09:52:31 kardel 6031 * use fixed format only (new IO model) 6032 * output debug to stdout instead of msyslog() 6033 * don't include >"< in ASCII output in order not to confuse 6034 * ntpq parsing 6035 * 6036 * Revision 4.0 1998/04/10 19:52:11 kardel 6037 * Start 4.0 release version numbering 6038 * 6039 * Revision 1.2 1998/04/10 19:28:04 kardel 6040 * initial NTP VERSION 4 integration of PARSE with GPS166 binary support 6041 * derived from 3.105.1.2 from V3 tree 6042 * 6043 * Revision information 3.1 - 3.105 from log deleted 1998/04/10 kardel 6044 * 6045 */ 6046