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