1 /* $NetBSD: refclock_parse.c,v 1.3 2010/12/04 23:08:35 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 size_t 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 NULL, 1627 NULL, 1628 NULL, 1629 NULL, 1630 NULL, 1631 NULL, 1632 NULL, 1633 NULL, 1634 NULL, 1635 NULL, 1636 } 1637 }; 1638 1639 #ifdef STREAM 1640 1641 #define fix_ts(_X_) \ 1642 if ((&(_X_))->tv.tv_usec >= 1000000) \ 1643 { \ 1644 (&(_X_))->tv.tv_usec -= 1000000; \ 1645 (&(_X_))->tv.tv_sec += 1; \ 1646 } 1647 1648 #define cvt_ts(_X_, _Y_) \ 1649 { \ 1650 l_fp ts; \ 1651 fix_ts((_X_)); \ 1652 if (!buftvtots((const char *)&(&(_X_))->tv, &ts)) \ 1653 { \ 1654 ERR(ERR_BADDATA) \ 1655 msyslog(LOG_ERR,"parse: stream_receive: timestamp conversion error (buftvtots) (%s) (%ld.%06ld) ", (_Y_), (long)(&(_X_))->tv.tv_sec, (long)(&(_X_))->tv.tv_usec);\ 1656 return; \ 1657 } \ 1658 else \ 1659 { \ 1660 (&(_X_))->fp = ts; \ 1661 } \ 1662 } 1663 1664 /*-------------------------------------------------- 1665 * ppsclock STREAM init 1666 */ 1667 static int 1668 ppsclock_init( 1669 struct parseunit *parse 1670 ) 1671 { 1672 static char m1[] = "ppsclocd"; 1673 static char m2[] = "ppsclock"; 1674 1675 /* 1676 * now push the parse streams module 1677 * it will ensure exclusive access to the device 1678 */ 1679 if (ioctl(parse->ppsfd, I_PUSH, (caddr_t)m1) == -1 && 1680 ioctl(parse->ppsfd, I_PUSH, (caddr_t)m2) == -1) 1681 { 1682 if (errno != EINVAL) 1683 { 1684 msyslog(LOG_ERR, "PARSE receiver #%d: ppsclock_init: ioctl(fd, I_PUSH, \"ppsclock\"): %m", 1685 CLK_UNIT(parse->peer)); 1686 } 1687 return 0; 1688 } 1689 if (!local_init(parse)) 1690 { 1691 (void)ioctl(parse->ppsfd, I_POP, (caddr_t)0); 1692 return 0; 1693 } 1694 1695 parse->flags |= PARSE_PPSCLOCK; 1696 return 1; 1697 } 1698 1699 /*-------------------------------------------------- 1700 * parse STREAM init 1701 */ 1702 static int 1703 stream_init( 1704 struct parseunit *parse 1705 ) 1706 { 1707 static char m1[] = "parse"; 1708 /* 1709 * now push the parse streams module 1710 * to test whether it is there (neat interface 8-( ) 1711 */ 1712 if (ioctl(parse->generic->io.fd, I_PUSH, (caddr_t)m1) == -1) 1713 { 1714 if (errno != EINVAL) /* accept non-existence */ 1715 { 1716 msyslog(LOG_ERR, "PARSE receiver #%d: stream_init: ioctl(fd, I_PUSH, \"parse\"): %m", CLK_UNIT(parse->peer)); 1717 } 1718 return 0; 1719 } 1720 else 1721 { 1722 while(ioctl(parse->generic->io.fd, I_POP, (caddr_t)0) == 0) 1723 /* empty loop */; 1724 1725 /* 1726 * now push it a second time after we have removed all 1727 * module garbage 1728 */ 1729 if (ioctl(parse->generic->io.fd, I_PUSH, (caddr_t)m1) == -1) 1730 { 1731 msyslog(LOG_ERR, "PARSE receiver #%d: stream_init: ioctl(fd, I_PUSH, \"parse\"): %m", CLK_UNIT(parse->peer)); 1732 return 0; 1733 } 1734 else 1735 { 1736 return 1; 1737 } 1738 } 1739 } 1740 1741 /*-------------------------------------------------- 1742 * parse STREAM end 1743 */ 1744 static void 1745 stream_end( 1746 struct parseunit *parse 1747 ) 1748 { 1749 while(ioctl(parse->generic->io.fd, I_POP, (caddr_t)0) == 0) 1750 /* empty loop */; 1751 } 1752 1753 /*-------------------------------------------------- 1754 * STREAM setcs 1755 */ 1756 static int 1757 stream_setcs( 1758 struct parseunit *parse, 1759 parsectl_t *tcl 1760 ) 1761 { 1762 struct strioctl strioc; 1763 1764 strioc.ic_cmd = PARSEIOC_SETCS; 1765 strioc.ic_timout = 0; 1766 strioc.ic_dp = (char *)tcl; 1767 strioc.ic_len = sizeof (*tcl); 1768 1769 if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1) 1770 { 1771 msyslog(LOG_ERR, "PARSE receiver #%d: stream_setcs: ioctl(fd, I_STR, PARSEIOC_SETCS): %m", CLK_UNIT(parse->peer)); 1772 return 0; 1773 } 1774 return 1; 1775 } 1776 1777 /*-------------------------------------------------- 1778 * STREAM enable 1779 */ 1780 static int 1781 stream_enable( 1782 struct parseunit *parse 1783 ) 1784 { 1785 struct strioctl strioc; 1786 1787 strioc.ic_cmd = PARSEIOC_ENABLE; 1788 strioc.ic_timout = 0; 1789 strioc.ic_dp = (char *)0; 1790 strioc.ic_len = 0; 1791 1792 if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1) 1793 { 1794 msyslog(LOG_ERR, "PARSE receiver #%d: stream_enable: ioctl(fd, I_STR, PARSEIOC_ENABLE): %m", CLK_UNIT(parse->peer)); 1795 return 0; 1796 } 1797 parse->generic->io.clock_recv = stream_receive; /* ok - parse input in kernel */ 1798 return 1; 1799 } 1800 1801 /*-------------------------------------------------- 1802 * STREAM disable 1803 */ 1804 static int 1805 stream_disable( 1806 struct parseunit *parse 1807 ) 1808 { 1809 struct strioctl strioc; 1810 1811 strioc.ic_cmd = PARSEIOC_DISABLE; 1812 strioc.ic_timout = 0; 1813 strioc.ic_dp = (char *)0; 1814 strioc.ic_len = 0; 1815 1816 if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1) 1817 { 1818 msyslog(LOG_ERR, "PARSE receiver #%d: stream_disable: ioctl(fd, I_STR, PARSEIOC_DISABLE): %m", CLK_UNIT(parse->peer)); 1819 return 0; 1820 } 1821 parse->generic->io.clock_recv = local_receive; /* ok - parse input in daemon */ 1822 return 1; 1823 } 1824 1825 /*-------------------------------------------------- 1826 * STREAM getfmt 1827 */ 1828 static int 1829 stream_getfmt( 1830 struct parseunit *parse, 1831 parsectl_t *tcl 1832 ) 1833 { 1834 struct strioctl strioc; 1835 1836 strioc.ic_cmd = PARSEIOC_GETFMT; 1837 strioc.ic_timout = 0; 1838 strioc.ic_dp = (char *)tcl; 1839 strioc.ic_len = sizeof (*tcl); 1840 if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1) 1841 { 1842 msyslog(LOG_ERR, "PARSE receiver #%d: ioctl(fd, I_STR, PARSEIOC_GETFMT): %m", CLK_UNIT(parse->peer)); 1843 return 0; 1844 } 1845 return 1; 1846 } 1847 1848 /*-------------------------------------------------- 1849 * STREAM setfmt 1850 */ 1851 static int 1852 stream_setfmt( 1853 struct parseunit *parse, 1854 parsectl_t *tcl 1855 ) 1856 { 1857 struct strioctl strioc; 1858 1859 strioc.ic_cmd = PARSEIOC_SETFMT; 1860 strioc.ic_timout = 0; 1861 strioc.ic_dp = (char *)tcl; 1862 strioc.ic_len = sizeof (*tcl); 1863 1864 if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1) 1865 { 1866 msyslog(LOG_ERR, "PARSE receiver #%d: stream_setfmt: ioctl(fd, I_STR, PARSEIOC_SETFMT): %m", CLK_UNIT(parse->peer)); 1867 return 0; 1868 } 1869 return 1; 1870 } 1871 1872 1873 /*-------------------------------------------------- 1874 * STREAM timecode 1875 */ 1876 static int 1877 stream_timecode( 1878 struct parseunit *parse, 1879 parsectl_t *tcl 1880 ) 1881 { 1882 struct strioctl strioc; 1883 1884 strioc.ic_cmd = PARSEIOC_TIMECODE; 1885 strioc.ic_timout = 0; 1886 strioc.ic_dp = (char *)tcl; 1887 strioc.ic_len = sizeof (*tcl); 1888 1889 if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1) 1890 { 1891 ERR(ERR_INTERNAL) 1892 msyslog(LOG_ERR, "PARSE receiver #%d: stream_timecode: ioctl(fd, I_STR, PARSEIOC_TIMECODE): %m", CLK_UNIT(parse->peer)); 1893 return 0; 1894 } 1895 clear_err(parse, ERR_INTERNAL); 1896 return 1; 1897 } 1898 1899 /*-------------------------------------------------- 1900 * STREAM receive 1901 */ 1902 static void 1903 stream_receive( 1904 struct recvbuf *rbufp 1905 ) 1906 { 1907 struct parseunit *parse = (struct parseunit *)((void *)rbufp->recv_srcclock); 1908 parsetime_t parsetime; 1909 1910 if (!parse->peer) 1911 return; 1912 1913 if (rbufp->recv_length != sizeof(parsetime_t)) 1914 { 1915 ERR(ERR_BADIO) 1916 msyslog(LOG_ERR,"PARSE receiver #%d: stream_receive: bad size (got %d expected %d)", 1917 CLK_UNIT(parse->peer), rbufp->recv_length, (int)sizeof(parsetime_t)); 1918 parse_event(parse, CEVNT_BADREPLY); 1919 return; 1920 } 1921 clear_err(parse, ERR_BADIO); 1922 1923 memmove((caddr_t)&parsetime, 1924 (caddr_t)rbufp->recv_buffer, 1925 sizeof(parsetime_t)); 1926 1927 #ifdef DEBUG 1928 if (debug > 3) 1929 { 1930 printf("PARSE receiver #%d: status %06x, state %08x, time %lx.%08lx, stime %lx.%08lx, ptime %lx.%08lx\n", 1931 CLK_UNIT(parse->peer), 1932 (unsigned int)parsetime.parse_status, 1933 (unsigned int)parsetime.parse_state, 1934 (unsigned long)parsetime.parse_time.tv.tv_sec, 1935 (unsigned long)parsetime.parse_time.tv.tv_usec, 1936 (unsigned long)parsetime.parse_stime.tv.tv_sec, 1937 (unsigned long)parsetime.parse_stime.tv.tv_usec, 1938 (unsigned long)parsetime.parse_ptime.tv.tv_sec, 1939 (unsigned long)parsetime.parse_ptime.tv.tv_usec); 1940 } 1941 #endif 1942 1943 /* 1944 * switch time stamp world - be sure to normalize small usec field 1945 * errors. 1946 */ 1947 1948 cvt_ts(parsetime.parse_stime, "parse_stime"); 1949 1950 if (PARSE_TIMECODE(parsetime.parse_state)) 1951 { 1952 cvt_ts(parsetime.parse_time, "parse_time"); 1953 } 1954 1955 if (PARSE_PPS(parsetime.parse_state)) 1956 cvt_ts(parsetime.parse_ptime, "parse_ptime"); 1957 1958 parse_process(parse, &parsetime); 1959 } 1960 #endif 1961 1962 /*-------------------------------------------------- 1963 * local init 1964 */ 1965 static int 1966 local_init( 1967 struct parseunit *parse 1968 ) 1969 { 1970 return parse_ioinit(&parse->parseio); 1971 } 1972 1973 /*-------------------------------------------------- 1974 * local end 1975 */ 1976 static void 1977 local_end( 1978 struct parseunit *parse 1979 ) 1980 { 1981 parse_ioend(&parse->parseio); 1982 } 1983 1984 1985 /*-------------------------------------------------- 1986 * local nop 1987 */ 1988 static int 1989 local_nop( 1990 struct parseunit *parse 1991 ) 1992 { 1993 return 1; 1994 } 1995 1996 /*-------------------------------------------------- 1997 * local setcs 1998 */ 1999 static int 2000 local_setcs( 2001 struct parseunit *parse, 2002 parsectl_t *tcl 2003 ) 2004 { 2005 return parse_setcs(tcl, &parse->parseio); 2006 } 2007 2008 /*-------------------------------------------------- 2009 * local getfmt 2010 */ 2011 static int 2012 local_getfmt( 2013 struct parseunit *parse, 2014 parsectl_t *tcl 2015 ) 2016 { 2017 return parse_getfmt(tcl, &parse->parseio); 2018 } 2019 2020 /*-------------------------------------------------- 2021 * local setfmt 2022 */ 2023 static int 2024 local_setfmt( 2025 struct parseunit *parse, 2026 parsectl_t *tcl 2027 ) 2028 { 2029 return parse_setfmt(tcl, &parse->parseio); 2030 } 2031 2032 /*-------------------------------------------------- 2033 * local timecode 2034 */ 2035 static int 2036 local_timecode( 2037 struct parseunit *parse, 2038 parsectl_t *tcl 2039 ) 2040 { 2041 return parse_timecode(tcl, &parse->parseio); 2042 } 2043 2044 2045 /*-------------------------------------------------- 2046 * local input 2047 */ 2048 static int 2049 local_input( 2050 struct recvbuf *rbufp 2051 ) 2052 { 2053 struct parseunit *parse = (struct parseunit *)((void *)rbufp->recv_srcclock); 2054 int count; 2055 unsigned char *s; 2056 timestamp_t ts; 2057 2058 if (!parse->peer) 2059 return 0; 2060 2061 /* 2062 * eat all characters, parsing then and feeding complete samples 2063 */ 2064 count = rbufp->recv_length; 2065 s = (unsigned char *)rbufp->recv_buffer; 2066 ts.fp = rbufp->recv_time; 2067 2068 while (count--) 2069 { 2070 if (parse_ioread(&parse->parseio, (unsigned int)(*s++), &ts)) 2071 { 2072 struct recvbuf *buf; 2073 2074 /* 2075 * got something good to eat 2076 */ 2077 if (!PARSE_PPS(parse->parseio.parse_dtime.parse_state)) 2078 { 2079 #ifdef HAVE_PPSAPI 2080 if (parse->flags & PARSE_PPSCLOCK) 2081 { 2082 struct timespec pps_timeout; 2083 pps_info_t pps_info; 2084 2085 pps_timeout.tv_sec = 0; 2086 pps_timeout.tv_nsec = 0; 2087 2088 if (time_pps_fetch(parse->atom.handle, PPS_TSFMT_TSPEC, &pps_info, 2089 &pps_timeout) == 0) 2090 { 2091 if (pps_info.assert_sequence + pps_info.clear_sequence != parse->ppsserial) 2092 { 2093 double dtemp; 2094 2095 struct timespec pts; 2096 /* 2097 * add PPS time stamp if available via ppsclock module 2098 * and not supplied already. 2099 */ 2100 if (parse->flags & PARSE_CLEAR) 2101 pts = pps_info.clear_timestamp; 2102 else 2103 pts = pps_info.assert_timestamp; 2104 2105 parse->parseio.parse_dtime.parse_ptime.fp.l_ui = pts.tv_sec + JAN_1970; 2106 2107 dtemp = pts.tv_nsec / 1e9; 2108 if (dtemp < 0.) { 2109 dtemp += 1; 2110 parse->parseio.parse_dtime.parse_ptime.fp.l_ui--; 2111 } 2112 if (dtemp > 1.) { 2113 dtemp -= 1; 2114 parse->parseio.parse_dtime.parse_ptime.fp.l_ui++; 2115 } 2116 parse->parseio.parse_dtime.parse_ptime.fp.l_uf = dtemp * FRAC; 2117 2118 parse->parseio.parse_dtime.parse_state |= PARSEB_PPS|PARSEB_S_PPS; 2119 #ifdef DEBUG 2120 if (debug > 3) 2121 { 2122 printf( 2123 "parse: local_receive: fd %d PPSAPI seq %ld - PPS %s\n", 2124 rbufp->fd, 2125 (long)pps_info.assert_sequence + (long)pps_info.clear_sequence, 2126 lfptoa(&parse->parseio.parse_dtime.parse_ptime.fp, 6)); 2127 } 2128 #endif 2129 } 2130 #ifdef DEBUG 2131 else 2132 { 2133 if (debug > 3) 2134 { 2135 printf( 2136 "parse: local_receive: fd %d PPSAPI seq assert %ld, seq clear %ld - NO PPS event\n", 2137 rbufp->fd, 2138 (long)pps_info.assert_sequence, (long)pps_info.clear_sequence); 2139 } 2140 } 2141 #endif 2142 parse->ppsserial = pps_info.assert_sequence + pps_info.clear_sequence; 2143 } 2144 #ifdef DEBUG 2145 else 2146 { 2147 if (debug > 3) 2148 { 2149 printf( 2150 "parse: local_receive: fd %d PPSAPI time_pps_fetch errno = %d\n", 2151 rbufp->fd, 2152 errno); 2153 } 2154 } 2155 #endif 2156 } 2157 #else 2158 #ifdef TIOCDCDTIMESTAMP 2159 struct timeval dcd_time; 2160 2161 if (ioctl(parse->ppsfd, TIOCDCDTIMESTAMP, &dcd_time) != -1) 2162 { 2163 l_fp tstmp; 2164 2165 TVTOTS(&dcd_time, &tstmp); 2166 tstmp.l_ui += JAN_1970; 2167 L_SUB(&ts.fp, &tstmp); 2168 if (ts.fp.l_ui == 0) 2169 { 2170 #ifdef DEBUG 2171 if (debug) 2172 { 2173 printf( 2174 "parse: local_receive: fd %d DCDTIMESTAMP %s\n", 2175 parse->ppsfd, 2176 lfptoa(&tstmp, 6)); 2177 printf(" sigio %s\n", 2178 lfptoa(&ts.fp, 6)); 2179 } 2180 #endif 2181 parse->parseio.parse_dtime.parse_ptime.fp = tstmp; 2182 parse->parseio.parse_dtime.parse_state |= PARSEB_PPS|PARSEB_S_PPS; 2183 } 2184 } 2185 #else /* TIOCDCDTIMESTAMP */ 2186 #if defined(HAVE_STRUCT_PPSCLOCKEV) && (defined(HAVE_CIOGETEV) || defined(HAVE_TIOCGPPSEV)) 2187 if (parse->flags & PARSE_PPSCLOCK) 2188 { 2189 l_fp tts; 2190 struct ppsclockev ev; 2191 2192 #ifdef HAVE_CIOGETEV 2193 if (ioctl(parse->ppsfd, CIOGETEV, (caddr_t)&ev) == 0) 2194 #endif 2195 #ifdef HAVE_TIOCGPPSEV 2196 if (ioctl(parse->ppsfd, TIOCGPPSEV, (caddr_t)&ev) == 0) 2197 #endif 2198 { 2199 if (ev.serial != parse->ppsserial) 2200 { 2201 /* 2202 * add PPS time stamp if available via ppsclock module 2203 * and not supplied already. 2204 */ 2205 if (!buftvtots((const char *)&ev.tv, &tts)) 2206 { 2207 ERR(ERR_BADDATA) 2208 msyslog(LOG_ERR,"parse: local_receive: timestamp conversion error (buftvtots) (ppsclockev.tv)"); 2209 } 2210 else 2211 { 2212 parse->parseio.parse_dtime.parse_ptime.fp = tts; 2213 parse->parseio.parse_dtime.parse_state |= PARSEB_PPS|PARSEB_S_PPS; 2214 } 2215 } 2216 parse->ppsserial = ev.serial; 2217 } 2218 } 2219 #endif 2220 #endif /* TIOCDCDTIMESTAMP */ 2221 #endif /* !HAVE_PPSAPI */ 2222 } 2223 if (count) 2224 { /* simulate receive */ 2225 buf = get_free_recv_buffer(); 2226 if (buf != NULL) { 2227 memmove((caddr_t)buf->recv_buffer, 2228 (caddr_t)&parse->parseio.parse_dtime, 2229 sizeof(parsetime_t)); 2230 buf->recv_length = sizeof(parsetime_t); 2231 buf->recv_time = rbufp->recv_time; 2232 buf->srcadr = rbufp->srcadr; 2233 buf->dstadr = rbufp->dstadr; 2234 buf->receiver = rbufp->receiver; 2235 buf->fd = rbufp->fd; 2236 buf->X_from_where = rbufp->X_from_where; 2237 add_full_recv_buffer(buf); 2238 } 2239 parse_iodone(&parse->parseio); 2240 } 2241 else 2242 { 2243 memmove((caddr_t)rbufp->recv_buffer, 2244 (caddr_t)&parse->parseio.parse_dtime, 2245 sizeof(parsetime_t)); 2246 parse_iodone(&parse->parseio); 2247 rbufp->recv_length = sizeof(parsetime_t); 2248 return 1; /* got something & in place return */ 2249 } 2250 } 2251 } 2252 return 0; /* nothing to pass up */ 2253 } 2254 2255 /*-------------------------------------------------- 2256 * local receive 2257 */ 2258 static void 2259 local_receive( 2260 struct recvbuf *rbufp 2261 ) 2262 { 2263 struct parseunit *parse = (struct parseunit *)((void *)rbufp->recv_srcclock); 2264 parsetime_t parsetime; 2265 2266 if (!parse->peer) 2267 return; 2268 2269 if (rbufp->recv_length != sizeof(parsetime_t)) 2270 { 2271 ERR(ERR_BADIO) 2272 msyslog(LOG_ERR,"PARSE receiver #%d: local_receive: bad size (got %d expected %d)", 2273 CLK_UNIT(parse->peer), rbufp->recv_length, (int)sizeof(parsetime_t)); 2274 parse_event(parse, CEVNT_BADREPLY); 2275 return; 2276 } 2277 clear_err(parse, ERR_BADIO); 2278 2279 memmove((caddr_t)&parsetime, 2280 (caddr_t)rbufp->recv_buffer, 2281 sizeof(parsetime_t)); 2282 2283 #ifdef DEBUG 2284 if (debug > 3) 2285 { 2286 printf("PARSE receiver #%d: status %06x, state %08x, time(fp) %lx.%08lx, stime(fp) %lx.%08lx, ptime(fp) %lx.%08lx\n", 2287 CLK_UNIT(parse->peer), 2288 (unsigned int)parsetime.parse_status, 2289 (unsigned int)parsetime.parse_state, 2290 (unsigned long)parsetime.parse_time.fp.l_ui, 2291 (unsigned long)parsetime.parse_time.fp.l_uf, 2292 (unsigned long)parsetime.parse_stime.fp.l_ui, 2293 (unsigned long)parsetime.parse_stime.fp.l_uf, 2294 (unsigned long)parsetime.parse_ptime.fp.l_ui, 2295 (unsigned long)parsetime.parse_ptime.fp.l_uf); 2296 } 2297 #endif 2298 2299 parse_process(parse, &parsetime); 2300 } 2301 2302 /*-------------------------------------------------- 2303 * init_iobinding - find and initialize lower layers 2304 */ 2305 static bind_t * 2306 init_iobinding( 2307 struct parseunit *parse 2308 ) 2309 { 2310 bind_t *b = io_bindings; 2311 2312 while (b->bd_description != (char *)0) 2313 { 2314 if ((*b->bd_init)(parse)) 2315 { 2316 return b; 2317 } 2318 b++; 2319 } 2320 return (bind_t *)0; 2321 } 2322 2323 /**=========================================================================== 2324 ** support routines 2325 **/ 2326 2327 /*-------------------------------------------------- 2328 * convert a flag field to a string 2329 */ 2330 static char * 2331 parsestate( 2332 u_long lstate, 2333 char *buffer, 2334 int size 2335 ) 2336 { 2337 static struct bits 2338 { 2339 u_long bit; 2340 const char *name; 2341 } flagstrings[] = 2342 { 2343 { PARSEB_ANNOUNCE, "DST SWITCH WARNING" }, 2344 { PARSEB_POWERUP, "NOT SYNCHRONIZED" }, 2345 { PARSEB_NOSYNC, "TIME CODE NOT CONFIRMED" }, 2346 { PARSEB_DST, "DST" }, 2347 { PARSEB_UTC, "UTC DISPLAY" }, 2348 { PARSEB_LEAPADD, "LEAP ADD WARNING" }, 2349 { PARSEB_LEAPDEL, "LEAP DELETE WARNING" }, 2350 { PARSEB_LEAPSECOND, "LEAP SECOND" }, 2351 { PARSEB_ALTERNATE, "ALTERNATE ANTENNA" }, 2352 { PARSEB_TIMECODE, "TIME CODE" }, 2353 { PARSEB_PPS, "PPS" }, 2354 { PARSEB_POSITION, "POSITION" }, 2355 { 0, NULL } 2356 }; 2357 2358 static struct sbits 2359 { 2360 u_long bit; 2361 const char *name; 2362 } sflagstrings[] = 2363 { 2364 { PARSEB_S_LEAP, "LEAP INDICATION" }, 2365 { PARSEB_S_PPS, "PPS SIGNAL" }, 2366 { PARSEB_S_ANTENNA, "ANTENNA" }, 2367 { PARSEB_S_POSITION, "POSITION" }, 2368 { 0, NULL } 2369 }; 2370 int i; 2371 char *s, *t; 2372 2373 2374 *buffer = '\0'; 2375 s = t = buffer; 2376 2377 i = 0; 2378 while (flagstrings[i].bit) 2379 { 2380 if (flagstrings[i].bit & lstate) 2381 { 2382 if (s != t) 2383 strncpy(t, "; ", BUFFER_SIZES(buffer, t, size)); 2384 strncat(t, flagstrings[i].name, BUFFER_SIZES(buffer, t, size)); 2385 t += strlen(t); 2386 } 2387 i++; 2388 } 2389 2390 if (lstate & (PARSEB_S_LEAP|PARSEB_S_ANTENNA|PARSEB_S_PPS|PARSEB_S_POSITION)) 2391 { 2392 if (s != t) 2393 strncpy(t, "; ", BUFFER_SIZES(buffer, t, size)); 2394 2395 t += strlen(t); 2396 2397 strncpy(t, "(", BUFFER_SIZES(buffer, t, size)); 2398 2399 s = t = t + strlen(t); 2400 2401 i = 0; 2402 while (sflagstrings[i].bit) 2403 { 2404 if (sflagstrings[i].bit & lstate) 2405 { 2406 if (t != s) 2407 { 2408 strncpy(t, "; ", BUFFER_SIZES(buffer, t, size)); 2409 t += 2; 2410 } 2411 2412 strncpy(t, sflagstrings[i].name, BUFFER_SIZES(buffer, t, size)); 2413 t += strlen(t); 2414 } 2415 i++; 2416 } 2417 strncpy(t, ")", BUFFER_SIZES(buffer, t, size)); 2418 } 2419 return buffer; 2420 } 2421 2422 /*-------------------------------------------------- 2423 * convert a status flag field to a string 2424 */ 2425 static char * 2426 parsestatus( 2427 u_long lstate, 2428 char *buffer, 2429 int size 2430 ) 2431 { 2432 static struct bits 2433 { 2434 u_long bit; 2435 const char *name; 2436 } flagstrings[] = 2437 { 2438 { CVT_OK, "CONVERSION SUCCESSFUL" }, 2439 { CVT_NONE, "NO CONVERSION" }, 2440 { CVT_FAIL, "CONVERSION FAILED" }, 2441 { CVT_BADFMT, "ILLEGAL FORMAT" }, 2442 { CVT_BADDATE, "DATE ILLEGAL" }, 2443 { CVT_BADTIME, "TIME ILLEGAL" }, 2444 { CVT_ADDITIONAL, "ADDITIONAL DATA" }, 2445 { 0, NULL } 2446 }; 2447 int i; 2448 2449 *buffer = '\0'; 2450 2451 i = 0; 2452 while (flagstrings[i].bit) 2453 { 2454 if (flagstrings[i].bit & lstate) 2455 { 2456 if (buffer[0]) 2457 strncat(buffer, "; ", size); 2458 strncat(buffer, flagstrings[i].name, size); 2459 } 2460 i++; 2461 } 2462 2463 return buffer; 2464 } 2465 2466 /*-------------------------------------------------- 2467 * convert a clock status flag field to a string 2468 */ 2469 static const char * 2470 clockstatus( 2471 u_long lstate 2472 ) 2473 { 2474 static char buffer[20]; 2475 static struct status 2476 { 2477 u_long value; 2478 const char *name; 2479 } flagstrings[] = 2480 { 2481 { CEVNT_NOMINAL, "NOMINAL" }, 2482 { CEVNT_TIMEOUT, "NO RESPONSE" }, 2483 { CEVNT_BADREPLY,"BAD FORMAT" }, 2484 { CEVNT_FAULT, "FAULT" }, 2485 { CEVNT_PROP, "PROPAGATION DELAY" }, 2486 { CEVNT_BADDATE, "ILLEGAL DATE" }, 2487 { CEVNT_BADTIME, "ILLEGAL TIME" }, 2488 { (unsigned)~0L, NULL } 2489 }; 2490 int i; 2491 2492 i = 0; 2493 while (flagstrings[i].value != (u_int)~0) 2494 { 2495 if (flagstrings[i].value == lstate) 2496 { 2497 return flagstrings[i].name; 2498 } 2499 i++; 2500 } 2501 2502 snprintf(buffer, sizeof(buffer), "unknown #%ld", (u_long)lstate); 2503 2504 return buffer; 2505 } 2506 2507 2508 /*-------------------------------------------------- 2509 * l_mktime - make representation of a relative time 2510 */ 2511 static char * 2512 l_mktime( 2513 u_long delta 2514 ) 2515 { 2516 u_long tmp, m, s; 2517 static char buffer[40]; 2518 char *t; 2519 2520 buffer[0] = '\0'; 2521 2522 if ((tmp = delta / (60*60*24)) != 0) 2523 { 2524 snprintf(buffer, BUFFER_SIZE(buffer, buffer), "%ldd+", (u_long)tmp); 2525 delta -= tmp * 60*60*24; 2526 } 2527 2528 s = delta % 60; 2529 delta /= 60; 2530 m = delta % 60; 2531 delta /= 60; 2532 2533 t = buffer + strlen(buffer); 2534 2535 snprintf(t, BUFFER_SIZE(buffer, t), "%02d:%02d:%02d", 2536 (int)delta, (int)m, (int)s); 2537 2538 return buffer; 2539 } 2540 2541 2542 /*-------------------------------------------------- 2543 * parse_statistics - list summary of clock states 2544 */ 2545 static void 2546 parse_statistics( 2547 struct parseunit *parse 2548 ) 2549 { 2550 int i; 2551 2552 NLOG(NLOG_CLOCKSTATIST) /* conditional if clause for conditional syslog */ 2553 { 2554 msyslog(LOG_INFO, "PARSE receiver #%d: running time: %s", 2555 CLK_UNIT(parse->peer), 2556 l_mktime(current_time - parse->generic->timestarted)); 2557 2558 msyslog(LOG_INFO, "PARSE receiver #%d: current status: %s", 2559 CLK_UNIT(parse->peer), 2560 clockstatus(parse->generic->currentstatus)); 2561 2562 for (i = 0; i <= CEVNT_MAX; i++) 2563 { 2564 u_long s_time; 2565 u_long percent, d = current_time - parse->generic->timestarted; 2566 2567 percent = s_time = PARSE_STATETIME(parse, i); 2568 2569 while (((u_long)(~0) / 10000) < percent) 2570 { 2571 percent /= 10; 2572 d /= 10; 2573 } 2574 2575 if (d) 2576 percent = (percent * 10000) / d; 2577 else 2578 percent = 10000; 2579 2580 if (s_time) 2581 msyslog(LOG_INFO, "PARSE receiver #%d: state %18s: %13s (%3ld.%02ld%%)", 2582 CLK_UNIT(parse->peer), 2583 clockstatus((unsigned int)i), 2584 l_mktime(s_time), 2585 percent / 100, percent % 100); 2586 } 2587 } 2588 } 2589 2590 /*-------------------------------------------------- 2591 * cparse_statistics - wrapper for statistics call 2592 */ 2593 static void 2594 cparse_statistics( 2595 struct parseunit *parse 2596 ) 2597 { 2598 if (parse->laststatistic + PARSESTATISTICS < current_time) 2599 parse_statistics(parse); 2600 parse->laststatistic = current_time; 2601 } 2602 2603 /**=========================================================================== 2604 ** ntp interface routines 2605 **/ 2606 2607 /*-------------------------------------------------- 2608 * parse_shutdown - shut down a PARSE clock 2609 */ 2610 static void 2611 parse_shutdown( 2612 int unit, 2613 struct peer *peer 2614 ) 2615 { 2616 struct parseunit *parse = (struct parseunit *)0; 2617 2618 if (peer && peer->procptr) 2619 parse = (struct parseunit *)peer->procptr->unitptr; 2620 2621 if (!parse) 2622 { 2623 /* nothing to clean up */ 2624 return; 2625 } 2626 2627 if (!parse->peer) 2628 { 2629 msyslog(LOG_INFO, "PARSE receiver #%d: INTERNAL ERROR - unit already inactive - shutdown ignored", unit); 2630 return; 2631 } 2632 2633 #ifdef HAVE_PPSAPI 2634 if (parse->flags & PARSE_PPSCLOCK) 2635 { 2636 (void)time_pps_destroy(parse->atom.handle); 2637 } 2638 #endif 2639 if (parse->generic->io.fd != parse->ppsfd && parse->ppsfd != -1) 2640 (void)close(parse->ppsfd); /* close separate PPS source */ 2641 2642 /* 2643 * print statistics a last time and 2644 * stop statistics machine 2645 */ 2646 parse_statistics(parse); 2647 2648 if (parse->parse_type->cl_end) 2649 { 2650 parse->parse_type->cl_end(parse); 2651 } 2652 2653 /* 2654 * cleanup before leaving this world 2655 */ 2656 if (parse->binding) 2657 PARSE_END(parse); 2658 2659 /* 2660 * Tell the I/O module to turn us off. We're history. 2661 */ 2662 io_closeclock(&parse->generic->io); 2663 2664 free_varlist(parse->kv); 2665 2666 NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */ 2667 msyslog(LOG_INFO, "PARSE receiver #%d: reference clock \"%s\" removed", 2668 CLK_UNIT(parse->peer), parse->parse_type->cl_description); 2669 2670 parse->peer = (struct peer *)0; /* unused now */ 2671 peer->procptr->unitptr = (caddr_t)0; 2672 free(parse); 2673 } 2674 2675 #ifdef HAVE_PPSAPI 2676 /*---------------------------------------- 2677 * set up HARDPPS via PPSAPI 2678 */ 2679 static void 2680 parse_hardpps( 2681 struct parseunit *parse, 2682 int mode 2683 ) 2684 { 2685 if (parse->hardppsstate == mode) 2686 return; 2687 2688 if (CLK_PPS(parse->peer) && (parse->flags & PARSE_PPSKERNEL)) { 2689 int i = 0; 2690 2691 if (mode == PARSE_HARDPPS_ENABLE) 2692 { 2693 if (parse->flags & PARSE_CLEAR) 2694 i = PPS_CAPTURECLEAR; 2695 else 2696 i = PPS_CAPTUREASSERT; 2697 } 2698 2699 if (time_pps_kcbind(parse->atom.handle, PPS_KC_HARDPPS, i, 2700 PPS_TSFMT_TSPEC) < 0) { 2701 msyslog(LOG_ERR, "PARSE receiver #%d: time_pps_kcbind failed: %m", 2702 CLK_UNIT(parse->peer)); 2703 } else { 2704 NLOG(NLOG_CLOCKINFO) 2705 msyslog(LOG_INFO, "PARSE receiver #%d: kernel PPS synchronisation %sabled", 2706 CLK_UNIT(parse->peer), (mode == PARSE_HARDPPS_ENABLE) ? "en" : "dis"); 2707 /* 2708 * tell the rest, that we have a kernel PPS source, iff we ever enable HARDPPS 2709 */ 2710 if (mode == PARSE_HARDPPS_ENABLE) 2711 pps_enable = 1; 2712 } 2713 } 2714 2715 parse->hardppsstate = mode; 2716 } 2717 2718 /*---------------------------------------- 2719 * set up PPS via PPSAPI 2720 */ 2721 static int 2722 parse_ppsapi( 2723 struct parseunit *parse 2724 ) 2725 { 2726 int cap, mode_ppsoffset; 2727 const char *cp; 2728 2729 parse->flags &= ~PARSE_PPSCLOCK; 2730 2731 /* 2732 * collect PPSAPI offset capability - should move into generic handling 2733 */ 2734 if (time_pps_getcap(parse->atom.handle, &cap) < 0) { 2735 msyslog(LOG_ERR, "PARSE receiver #%d: parse_ppsapi: time_pps_getcap failed: %m", 2736 CLK_UNIT(parse->peer)); 2737 2738 return 0; 2739 } 2740 2741 /* 2742 * initialize generic PPSAPI interface 2743 * 2744 * we leave out CLK_FLAG3 as time_pps_kcbind() 2745 * is handled here for now. Ideally this should also 2746 * be part of the generic PPSAPI interface 2747 */ 2748 if (!refclock_params(parse->flags & (CLK_FLAG1|CLK_FLAG2|CLK_FLAG4), &parse->atom)) 2749 return 0; 2750 2751 /* nb. only turn things on, if someone else has turned something 2752 * on before we get here, leave it alone! 2753 */ 2754 2755 if (parse->flags & PARSE_CLEAR) { 2756 cp = "CLEAR"; 2757 mode_ppsoffset = PPS_OFFSETCLEAR; 2758 } else { 2759 cp = "ASSERT"; 2760 mode_ppsoffset = PPS_OFFSETASSERT; 2761 } 2762 2763 msyslog(LOG_INFO, "PARSE receiver #%d: initializing PPS to %s", 2764 CLK_UNIT(parse->peer), cp); 2765 2766 if (!(mode_ppsoffset & cap)) { 2767 msyslog(LOG_WARNING, "PARSE receiver #%d: Cannot set PPS_%sCLEAR, this will increase jitter (PPS API capabilities=0x%x)", 2768 CLK_UNIT(parse->peer), cp, cap); 2769 mode_ppsoffset = 0; 2770 } else { 2771 if (mode_ppsoffset == PPS_OFFSETCLEAR) 2772 { 2773 parse->atom.pps_params.clear_offset.tv_sec = -parse->ppsphaseadjust; 2774 parse->atom.pps_params.clear_offset.tv_nsec = -1e9*(parse->ppsphaseadjust - (long)parse->ppsphaseadjust); 2775 } 2776 2777 if (mode_ppsoffset == PPS_OFFSETASSERT) 2778 { 2779 parse->atom.pps_params.assert_offset.tv_sec = -parse->ppsphaseadjust; 2780 parse->atom.pps_params.assert_offset.tv_nsec = -1e9*(parse->ppsphaseadjust - (long)parse->ppsphaseadjust); 2781 } 2782 } 2783 2784 parse->atom.pps_params.mode |= mode_ppsoffset; 2785 2786 if (time_pps_setparams(parse->atom.handle, &parse->atom.pps_params) < 0) { 2787 msyslog(LOG_ERR, "PARSE receiver #%d: FAILED set PPS parameters: %m", 2788 CLK_UNIT(parse->peer)); 2789 return 0; 2790 } 2791 2792 parse->flags |= PARSE_PPSCLOCK; 2793 return 1; 2794 } 2795 #else 2796 #define parse_hardpps(_PARSE_, _MODE_) /* empty */ 2797 #endif 2798 2799 /*-------------------------------------------------- 2800 * parse_start - open the PARSE devices and initialize data for processing 2801 */ 2802 static int 2803 parse_start( 2804 int sysunit, 2805 struct peer *peer 2806 ) 2807 { 2808 u_int unit; 2809 int fd232; 2810 #ifdef HAVE_TERMIOS 2811 struct termios tio; /* NEEDED FOR A LONG TIME ! */ 2812 #endif 2813 #ifdef HAVE_SYSV_TTYS 2814 struct termio tio; /* NEEDED FOR A LONG TIME ! */ 2815 #endif 2816 struct parseunit * parse; 2817 char parsedev[sizeof(PARSEDEVICE)+20]; 2818 char parseppsdev[sizeof(PARSEPPSDEVICE)+20]; 2819 parsectl_t tmp_ctl; 2820 u_int type; 2821 2822 /* 2823 * get out Copyright information once 2824 */ 2825 if (!notice) 2826 { 2827 NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */ 2828 msyslog(LOG_INFO, "NTP PARSE support: Copyright (c) 1989-2009, Frank Kardel"); 2829 notice = 1; 2830 } 2831 2832 type = CLK_TYPE(peer); 2833 unit = CLK_UNIT(peer); 2834 2835 if ((type == (u_int)~0) || (parse_clockinfo[type].cl_description == (char *)0)) 2836 { 2837 msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: unsupported clock type %d (max %d)", 2838 unit, CLK_REALTYPE(peer), ncltypes-1); 2839 return 0; 2840 } 2841 2842 /* 2843 * Unit okay, attempt to open the device. 2844 */ 2845 (void) snprintf(parsedev, sizeof(parsedev), PARSEDEVICE, unit); 2846 (void) snprintf(parseppsdev, sizeof(parsedev), PARSEPPSDEVICE, unit); 2847 2848 #ifndef O_NOCTTY 2849 #define O_NOCTTY 0 2850 #endif 2851 2852 fd232 = open(parsedev, O_RDWR | O_NOCTTY 2853 #ifdef O_NONBLOCK 2854 | O_NONBLOCK 2855 #endif 2856 , 0777); 2857 2858 if (fd232 == -1) 2859 { 2860 msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: open of %s failed: %m", unit, parsedev); 2861 return 0; 2862 } 2863 2864 parse = (struct parseunit *)emalloc(sizeof(struct parseunit)); 2865 2866 memset((char *)parse, 0, sizeof(struct parseunit)); 2867 2868 parse->generic = peer->procptr; /* link up */ 2869 parse->generic->unitptr = (caddr_t)parse; /* link down */ 2870 2871 /* 2872 * Set up the structures 2873 */ 2874 parse->generic->timestarted = current_time; 2875 parse->lastchange = current_time; 2876 2877 parse->flags = 0; 2878 parse->pollneeddata = 0; 2879 parse->laststatistic = current_time; 2880 parse->lastformat = (unsigned short)~0; /* assume no format known */ 2881 parse->timedata.parse_status = (unsigned short)~0; /* be sure to mark initial status change */ 2882 parse->lastmissed = 0; /* assume got everything */ 2883 parse->ppsserial = 0; 2884 parse->ppsfd = -1; 2885 parse->localdata = (void *)0; 2886 parse->localstate = 0; 2887 parse->kv = (struct ctl_var *)0; 2888 2889 clear_err(parse, ERR_ALL); 2890 2891 parse->parse_type = &parse_clockinfo[type]; 2892 2893 parse->maxunsync = parse->parse_type->cl_maxunsync; 2894 2895 parse->generic->fudgetime1 = parse->parse_type->cl_basedelay; 2896 2897 parse->generic->fudgetime2 = 0.0; 2898 parse->ppsphaseadjust = parse->generic->fudgetime2; 2899 2900 parse->generic->clockdesc = parse->parse_type->cl_description; 2901 2902 peer->rootdelay = parse->parse_type->cl_rootdelay; 2903 peer->sstclktype = parse->parse_type->cl_type; 2904 peer->precision = sys_precision; 2905 2906 peer->stratum = STRATUM_REFCLOCK; 2907 2908 if (peer->stratum <= 1) 2909 memmove((char *)&parse->generic->refid, parse->parse_type->cl_id, 4); 2910 else 2911 parse->generic->refid = htonl(PARSEHSREFID); 2912 2913 parse->generic->io.fd = fd232; 2914 2915 parse->peer = peer; /* marks it also as busy */ 2916 2917 /* 2918 * configure terminal line 2919 */ 2920 if (TTY_GETATTR(fd232, &tio) == -1) 2921 { 2922 msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: tcgetattr(%d, &tio): %m", unit, fd232); 2923 parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */ 2924 return 0; 2925 } 2926 else 2927 { 2928 #ifndef _PC_VDISABLE 2929 memset((char *)tio.c_cc, 0, sizeof(tio.c_cc)); 2930 #else 2931 int disablec; 2932 errno = 0; /* pathconf can deliver -1 without changing errno ! */ 2933 2934 disablec = fpathconf(parse->generic->io.fd, _PC_VDISABLE); 2935 if (disablec == -1 && errno) 2936 { 2937 msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: fpathconf(fd, _PC_VDISABLE): %m", CLK_UNIT(parse->peer)); 2938 memset((char *)tio.c_cc, 0, sizeof(tio.c_cc)); /* best guess */ 2939 } 2940 else 2941 if (disablec != -1) 2942 memset((char *)tio.c_cc, disablec, sizeof(tio.c_cc)); 2943 #endif 2944 2945 #if defined (VMIN) || defined(VTIME) 2946 if ((parse_clockinfo[type].cl_lflag & ICANON) == 0) 2947 { 2948 #ifdef VMIN 2949 tio.c_cc[VMIN] = 1; 2950 #endif 2951 #ifdef VTIME 2952 tio.c_cc[VTIME] = 0; 2953 #endif 2954 } 2955 #endif 2956 2957 tio.c_cflag = parse_clockinfo[type].cl_cflag; 2958 tio.c_iflag = parse_clockinfo[type].cl_iflag; 2959 tio.c_oflag = parse_clockinfo[type].cl_oflag; 2960 tio.c_lflag = parse_clockinfo[type].cl_lflag; 2961 2962 2963 #ifdef HAVE_TERMIOS 2964 if ((cfsetospeed(&tio, parse_clockinfo[type].cl_speed) == -1) || 2965 (cfsetispeed(&tio, parse_clockinfo[type].cl_speed) == -1)) 2966 { 2967 msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: tcset{i,o}speed(&tio, speed): %m", unit); 2968 parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */ 2969 return 0; 2970 } 2971 #else 2972 tio.c_cflag |= parse_clockinfo[type].cl_speed; 2973 #endif 2974 2975 /* 2976 * set up pps device 2977 * if the PARSEPPSDEVICE can be opened that will be used 2978 * for PPS else PARSEDEVICE will be used 2979 */ 2980 parse->ppsfd = open(parseppsdev, O_RDWR | O_NOCTTY 2981 #ifdef O_NONBLOCK 2982 | O_NONBLOCK 2983 #endif 2984 , 0777); 2985 2986 if (parse->ppsfd == -1) 2987 { 2988 parse->ppsfd = fd232; 2989 } 2990 2991 /* 2992 * Linux PPS - the old way 2993 */ 2994 #if defined(HAVE_TIO_SERIAL_STUFF) /* Linux hack: define PPS interface */ 2995 { 2996 struct serial_struct ss; 2997 if (ioctl(parse->ppsfd, TIOCGSERIAL, &ss) < 0 || 2998 ( 2999 #ifdef ASYNC_LOW_LATENCY 3000 ss.flags |= ASYNC_LOW_LATENCY, 3001 #endif 3002 #ifndef HAVE_PPSAPI 3003 #ifdef ASYNC_PPS_CD_NEG 3004 ss.flags |= ASYNC_PPS_CD_NEG, 3005 #endif 3006 #endif 3007 ioctl(parse->ppsfd, TIOCSSERIAL, &ss)) < 0) { 3008 msyslog(LOG_NOTICE, "refclock_parse: TIOCSSERIAL fd %d, %m", parse->ppsfd); 3009 msyslog(LOG_NOTICE, 3010 "refclock_parse: optional PPS processing not available"); 3011 } else { 3012 parse->flags |= PARSE_PPSCLOCK; 3013 #ifdef ASYNC_PPS_CD_NEG 3014 NLOG(NLOG_CLOCKINFO) 3015 msyslog(LOG_INFO, 3016 "refclock_parse: PPS detection on"); 3017 #endif 3018 } 3019 } 3020 #endif 3021 3022 /* 3023 * SUN the Solaris way 3024 */ 3025 #ifdef HAVE_TIOCSPPS /* SUN PPS support */ 3026 if (CLK_PPS(parse->peer)) 3027 { 3028 int i = 1; 3029 3030 if (ioctl(parse->ppsfd, TIOCSPPS, (caddr_t)&i) == 0) 3031 { 3032 parse->flags |= PARSE_PPSCLOCK; 3033 } 3034 } 3035 #endif 3036 3037 /* 3038 * PPS via PPSAPI 3039 */ 3040 #if defined(HAVE_PPSAPI) 3041 parse->hardppsstate = PARSE_HARDPPS_DISABLE; 3042 if (CLK_PPS(parse->peer)) 3043 { 3044 if (!refclock_ppsapi(parse->ppsfd, &parse->atom)) 3045 { 3046 msyslog(LOG_NOTICE, "PARSE receiver #%d: parse_start: could not set up PPS: %m", CLK_UNIT(parse->peer)); 3047 } 3048 else 3049 { 3050 parse_ppsapi(parse); 3051 } 3052 } 3053 #endif 3054 3055 if (TTY_SETATTR(fd232, &tio) == -1) 3056 { 3057 msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: tcsetattr(%d, &tio): %m", unit, fd232); 3058 parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */ 3059 return 0; 3060 } 3061 } 3062 3063 /* 3064 * pick correct input machine 3065 */ 3066 parse->generic->io.srcclock = (caddr_t)parse; 3067 parse->generic->io.datalen = 0; 3068 3069 parse->binding = init_iobinding(parse); 3070 3071 if (parse->binding == (bind_t *)0) 3072 { 3073 msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: io sub system initialisation failed.", CLK_UNIT(parse->peer)); 3074 parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */ 3075 return 0; /* well, ok - special initialisation broke */ 3076 } 3077 3078 parse->generic->io.clock_recv = parse->binding->bd_receive; /* pick correct receive routine */ 3079 parse->generic->io.io_input = parse->binding->bd_io_input; /* pick correct input routine */ 3080 3081 /* 3082 * as we always(?) get 8 bit chars we want to be 3083 * sure, that the upper bits are zero for less 3084 * than 8 bit I/O - so we pass that information on. 3085 * note that there can be only one bit count format 3086 * per file descriptor 3087 */ 3088 3089 switch (tio.c_cflag & CSIZE) 3090 { 3091 case CS5: 3092 tmp_ctl.parsesetcs.parse_cs = PARSE_IO_CS5; 3093 break; 3094 3095 case CS6: 3096 tmp_ctl.parsesetcs.parse_cs = PARSE_IO_CS6; 3097 break; 3098 3099 case CS7: 3100 tmp_ctl.parsesetcs.parse_cs = PARSE_IO_CS7; 3101 break; 3102 3103 case CS8: 3104 tmp_ctl.parsesetcs.parse_cs = PARSE_IO_CS8; 3105 break; 3106 } 3107 3108 if (!PARSE_SETCS(parse, &tmp_ctl)) 3109 { 3110 msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: parse_setcs() 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 strncpy(tmp_ctl.parseformat.parse_buffer, parse->parse_type->cl_format, sizeof(tmp_ctl.parseformat.parse_buffer)); 3116 tmp_ctl.parseformat.parse_count = strlen(tmp_ctl.parseformat.parse_buffer); 3117 3118 if (!PARSE_SETFMT(parse, &tmp_ctl)) 3119 { 3120 msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: parse_setfmt() FAILED.", unit); 3121 parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */ 3122 return 0; /* well, ok - special initialisation broke */ 3123 } 3124 3125 /* 3126 * get rid of all IO accumulated so far 3127 */ 3128 #ifdef HAVE_TERMIOS 3129 (void) tcflush(parse->generic->io.fd, TCIOFLUSH); 3130 #else 3131 #if defined(TCFLSH) && defined(TCIOFLUSH) 3132 { 3133 int flshcmd = TCIOFLUSH; 3134 3135 (void) ioctl(parse->generic->io.fd, TCFLSH, (caddr_t)&flshcmd); 3136 } 3137 #endif 3138 #endif 3139 3140 /* 3141 * try to do any special initializations 3142 */ 3143 if (parse->parse_type->cl_init) 3144 { 3145 if (parse->parse_type->cl_init(parse)) 3146 { 3147 parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */ 3148 return 0; /* well, ok - special initialisation broke */ 3149 } 3150 } 3151 3152 /* 3153 * Insert in async io device list. 3154 */ 3155 if (!io_addclock(&parse->generic->io)) 3156 { 3157 msyslog(LOG_ERR, 3158 "PARSE receiver #%d: parse_start: addclock %s fails (ABORT - clock type requires async io)", CLK_UNIT(parse->peer), parsedev); 3159 parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */ 3160 return 0; 3161 } 3162 3163 /* 3164 * print out configuration 3165 */ 3166 NLOG(NLOG_CLOCKINFO) 3167 { 3168 /* conditional if clause for conditional syslog */ 3169 msyslog(LOG_INFO, "PARSE receiver #%d: reference clock \"%s\" (I/O device %s, PPS device %s) added", 3170 CLK_UNIT(parse->peer), 3171 parse->parse_type->cl_description, parsedev, 3172 (parse->ppsfd != parse->generic->io.fd) ? parseppsdev : parsedev); 3173 3174 msyslog(LOG_INFO, "PARSE receiver #%d: Stratum %d, trust time %s, precision %d", 3175 CLK_UNIT(parse->peer), 3176 parse->peer->stratum, 3177 l_mktime(parse->maxunsync), parse->peer->precision); 3178 3179 msyslog(LOG_INFO, "PARSE receiver #%d: rootdelay %.6f s, phase adjustment %.6f s, PPS phase adjustment %.6f s, %s IO handling", 3180 CLK_UNIT(parse->peer), 3181 parse->parse_type->cl_rootdelay, 3182 parse->generic->fudgetime1, 3183 parse->ppsphaseadjust, 3184 parse->binding->bd_description); 3185 3186 msyslog(LOG_INFO, "PARSE receiver #%d: Format recognition: %s", CLK_UNIT(parse->peer), 3187 parse->parse_type->cl_format); 3188 msyslog(LOG_INFO, "PARSE receiver #%d: %sPPS support%s", CLK_UNIT(parse->peer), 3189 CLK_PPS(parse->peer) ? "" : "NO ", 3190 CLK_PPS(parse->peer) ? 3191 #ifdef PPS_METHOD 3192 " (implementation " PPS_METHOD ")" 3193 #else 3194 "" 3195 #endif 3196 : "" 3197 ); 3198 } 3199 3200 return 1; 3201 } 3202 3203 /*-------------------------------------------------- 3204 * parse_ctl - process changes on flags/time values 3205 */ 3206 static void 3207 parse_ctl( 3208 struct parseunit *parse, 3209 struct refclockstat *in 3210 ) 3211 { 3212 if (in) 3213 { 3214 if (in->haveflags & (CLK_HAVEFLAG1|CLK_HAVEFLAG2|CLK_HAVEFLAG3|CLK_HAVEFLAG4)) 3215 { 3216 parse->flags = (parse->flags & ~(CLK_FLAG1|CLK_FLAG2|CLK_FLAG3|CLK_FLAG4)) | 3217 (in->flags & (CLK_FLAG1|CLK_FLAG2|CLK_FLAG3|CLK_FLAG4)); 3218 #if defined(HAVE_PPSAPI) 3219 if (CLK_PPS(parse->peer)) 3220 { 3221 parse_ppsapi(parse); 3222 } 3223 #endif 3224 } 3225 3226 if (in->haveflags & CLK_HAVETIME1) 3227 { 3228 parse->generic->fudgetime1 = in->fudgetime1; 3229 msyslog(LOG_INFO, "PARSE receiver #%d: new phase adjustment %.6f s", 3230 CLK_UNIT(parse->peer), 3231 parse->generic->fudgetime1); 3232 } 3233 3234 if (in->haveflags & CLK_HAVETIME2) 3235 { 3236 parse->generic->fudgetime2 = in->fudgetime2; 3237 if (parse->flags & PARSE_TRUSTTIME) 3238 { 3239 parse->maxunsync = (u_long)ABS(in->fudgetime2); 3240 msyslog(LOG_INFO, "PARSE receiver #%d: new trust time %s", 3241 CLK_UNIT(parse->peer), 3242 l_mktime(parse->maxunsync)); 3243 } 3244 else 3245 { 3246 parse->ppsphaseadjust = in->fudgetime2; 3247 msyslog(LOG_INFO, "PARSE receiver #%d: new PPS phase adjustment %.6f s", 3248 CLK_UNIT(parse->peer), 3249 parse->ppsphaseadjust); 3250 #if defined(HAVE_PPSAPI) 3251 if (CLK_PPS(parse->peer)) 3252 { 3253 parse_ppsapi(parse); 3254 } 3255 #endif 3256 } 3257 } 3258 } 3259 } 3260 3261 /*-------------------------------------------------- 3262 * parse_poll - called by the transmit procedure 3263 */ 3264 static void 3265 parse_poll( 3266 int unit, 3267 struct peer *peer 3268 ) 3269 { 3270 struct parseunit *parse = (struct parseunit *)peer->procptr->unitptr; 3271 3272 if (peer != parse->peer) 3273 { 3274 msyslog(LOG_ERR, 3275 "PARSE receiver #%d: poll: INTERNAL: peer incorrect", 3276 unit); 3277 return; 3278 } 3279 3280 /* 3281 * Update clock stat counters 3282 */ 3283 parse->generic->polls++; 3284 3285 if (parse->pollneeddata && 3286 ((int)(current_time - parse->pollneeddata) > (1<<(max(min(parse->peer->hpoll, parse->peer->ppoll), parse->peer->minpoll))))) 3287 { 3288 /* 3289 * start worrying when exceeding a poll inteval 3290 * bad news - didn't get a response last time 3291 */ 3292 parse->lastmissed = current_time; 3293 parse_event(parse, CEVNT_TIMEOUT); 3294 3295 ERR(ERR_NODATA) 3296 msyslog(LOG_WARNING, "PARSE receiver #%d: no data from device within poll interval (check receiver / wiring)", CLK_UNIT(parse->peer)); 3297 } 3298 3299 /* 3300 * we just mark that we want the next sample for the clock filter 3301 */ 3302 parse->pollneeddata = current_time; 3303 3304 if (parse->parse_type->cl_poll) 3305 { 3306 parse->parse_type->cl_poll(parse); 3307 } 3308 3309 cparse_statistics(parse); 3310 3311 return; 3312 } 3313 3314 #define LEN_STATES 300 /* length of state string */ 3315 3316 /*-------------------------------------------------- 3317 * parse_control - set fudge factors, return statistics 3318 */ 3319 static void 3320 parse_control( 3321 int unit, 3322 struct refclockstat *in, 3323 struct refclockstat *out, 3324 struct peer *peer 3325 ) 3326 { 3327 struct parseunit *parse = (struct parseunit *)peer->procptr->unitptr; 3328 parsectl_t tmpctl; 3329 3330 static char outstatus[400]; /* status output buffer */ 3331 3332 if (out) 3333 { 3334 out->lencode = 0; 3335 out->p_lastcode = 0; 3336 out->kv_list = (struct ctl_var *)0; 3337 } 3338 3339 if (!parse || !parse->peer) 3340 { 3341 msyslog(LOG_ERR, "PARSE receiver #%d: parse_control: unit invalid (UNIT INACTIVE)", 3342 unit); 3343 return; 3344 } 3345 3346 unit = CLK_UNIT(parse->peer); 3347 3348 /* 3349 * handle changes 3350 */ 3351 parse_ctl(parse, in); 3352 3353 /* 3354 * supply data 3355 */ 3356 if (out) 3357 { 3358 u_long sum = 0; 3359 char *tt, *start; 3360 int i; 3361 3362 outstatus[0] = '\0'; 3363 3364 out->type = REFCLK_PARSE; 3365 3366 /* 3367 * keep fudgetime2 in sync with TRUSTTIME/MAXUNSYNC flag1 3368 */ 3369 parse->generic->fudgetime2 = (parse->flags & PARSE_TRUSTTIME) ? (double)parse->maxunsync : parse->ppsphaseadjust; 3370 3371 /* 3372 * figure out skew between PPS and RS232 - just for informational 3373 * purposes 3374 */ 3375 if (PARSE_SYNC(parse->timedata.parse_state)) 3376 { 3377 if (PARSE_PPS(parse->timedata.parse_state) && PARSE_TIMECODE(parse->timedata.parse_state)) 3378 { 3379 l_fp off; 3380 3381 /* 3382 * we have a PPS and RS232 signal - calculate the skew 3383 * WARNING: assumes on TIMECODE == PULSE (timecode after pulse) 3384 */ 3385 off = parse->timedata.parse_stime.fp; 3386 L_SUB(&off, &parse->timedata.parse_ptime.fp); /* true offset */ 3387 tt = add_var(&out->kv_list, 80, RO); 3388 snprintf(tt, 80, "refclock_ppsskew=%s", lfptoms(&off, 6)); 3389 } 3390 } 3391 3392 if (PARSE_PPS(parse->timedata.parse_state)) 3393 { 3394 tt = add_var(&out->kv_list, 80, RO|DEF); 3395 snprintf(tt, 80, "refclock_ppstime=\"%s\"", gmprettydate(&parse->timedata.parse_ptime.fp)); 3396 } 3397 3398 start = tt = add_var(&out->kv_list, 128, RO|DEF); 3399 snprintf(tt, 128, "refclock_time=\""); 3400 tt += strlen(tt); 3401 3402 if (parse->timedata.parse_time.fp.l_ui == 0) 3403 { 3404 strncpy(tt, "<UNDEFINED>\"", BUFFER_SIZES(start, tt, 128)); 3405 } 3406 else 3407 { 3408 snprintf(tt, 128, "%s\"", gmprettydate(&parse->timedata.parse_time.fp)); 3409 } 3410 3411 if (!PARSE_GETTIMECODE(parse, &tmpctl)) 3412 { 3413 ERR(ERR_INTERNAL) 3414 msyslog(LOG_ERR, "PARSE receiver #%d: parse_control: parse_timecode() FAILED", unit); 3415 } 3416 else 3417 { 3418 start = tt = add_var(&out->kv_list, 512, RO|DEF); 3419 snprintf(tt, 512, "refclock_status=\""); 3420 tt += strlen(tt); 3421 3422 /* 3423 * copy PPS flags from last read transaction (informational only) 3424 */ 3425 tmpctl.parsegettc.parse_state |= parse->timedata.parse_state & 3426 (PARSEB_PPS|PARSEB_S_PPS); 3427 3428 (void) parsestate(tmpctl.parsegettc.parse_state, tt, BUFFER_SIZES(start, tt, 512)); 3429 3430 strncat(tt, "\"", BUFFER_SIZES(start, tt, 512)); 3431 3432 if (tmpctl.parsegettc.parse_count) 3433 mkascii(outstatus+strlen(outstatus), (int)(sizeof(outstatus)- strlen(outstatus) - 1), 3434 tmpctl.parsegettc.parse_buffer, (unsigned)(tmpctl.parsegettc.parse_count)); 3435 3436 } 3437 3438 tmpctl.parseformat.parse_format = tmpctl.parsegettc.parse_format; 3439 3440 if (!PARSE_GETFMT(parse, &tmpctl)) 3441 { 3442 ERR(ERR_INTERNAL) 3443 msyslog(LOG_ERR, "PARSE receiver #%d: parse_control: parse_getfmt() FAILED", unit); 3444 } 3445 else 3446 { 3447 tt = add_var(&out->kv_list, 80, RO|DEF); 3448 snprintf(tt, 80, "refclock_format=\""); 3449 3450 strncat(tt, tmpctl.parseformat.parse_buffer, tmpctl.parseformat.parse_count); 3451 strncat(tt,"\"", 80); 3452 } 3453 3454 /* 3455 * gather state statistics 3456 */ 3457 3458 start = tt = add_var(&out->kv_list, LEN_STATES, RO|DEF); 3459 strncpy(tt, "refclock_states=\"", LEN_STATES); 3460 tt += strlen(tt); 3461 3462 for (i = 0; i <= CEVNT_MAX; i++) 3463 { 3464 u_long s_time; 3465 u_long d = current_time - parse->generic->timestarted; 3466 u_long percent; 3467 3468 percent = s_time = PARSE_STATETIME(parse, i); 3469 3470 while (((u_long)(~0) / 10000) < percent) 3471 { 3472 percent /= 10; 3473 d /= 10; 3474 } 3475 3476 if (d) 3477 percent = (percent * 10000) / d; 3478 else 3479 percent = 10000; 3480 3481 if (s_time) 3482 { 3483 char item[80]; 3484 int count; 3485 3486 snprintf(item, 80, "%s%s%s: %s (%d.%02d%%)", 3487 sum ? "; " : "", 3488 (parse->generic->currentstatus == i) ? "*" : "", 3489 clockstatus((unsigned int)i), 3490 l_mktime(s_time), 3491 (int)(percent / 100), (int)(percent % 100)); 3492 if ((count = strlen(item)) < (LEN_STATES - 40 - (tt - start))) 3493 { 3494 strncpy(tt, item, BUFFER_SIZES(start, tt, LEN_STATES)); 3495 tt += count; 3496 } 3497 sum += s_time; 3498 } 3499 } 3500 3501 snprintf(tt, BUFFER_SIZES(start, tt, LEN_STATES), "; running time: %s\"", l_mktime(sum)); 3502 3503 tt = add_var(&out->kv_list, 32, RO); 3504 snprintf(tt, 32, "refclock_id=\"%s\"", parse->parse_type->cl_id); 3505 3506 tt = add_var(&out->kv_list, 80, RO); 3507 snprintf(tt, 80, "refclock_iomode=\"%s\"", parse->binding->bd_description); 3508 3509 tt = add_var(&out->kv_list, 128, RO); 3510 snprintf(tt, 128, "refclock_driver_version=\"%s\"", rcsid); 3511 3512 { 3513 struct ctl_var *k; 3514 3515 k = parse->kv; 3516 while (k && !(k->flags & EOV)) 3517 { 3518 set_var(&out->kv_list, k->text, strlen(k->text)+1, k->flags); 3519 k++; 3520 } 3521 } 3522 3523 out->lencode = strlen(outstatus); 3524 out->p_lastcode = outstatus; 3525 } 3526 } 3527 3528 /**=========================================================================== 3529 ** processing routines 3530 **/ 3531 3532 /*-------------------------------------------------- 3533 * event handling - note that nominal events will also be posted 3534 * keep track of state dwelling times 3535 */ 3536 static void 3537 parse_event( 3538 struct parseunit *parse, 3539 int event 3540 ) 3541 { 3542 if (parse->generic->currentstatus != (u_char) event) 3543 { 3544 parse->statetime[parse->generic->currentstatus] += current_time - parse->lastchange; 3545 parse->lastchange = current_time; 3546 3547 if (parse->parse_type->cl_event) 3548 parse->parse_type->cl_event(parse, event); 3549 3550 if (event == CEVNT_NOMINAL) 3551 { 3552 NLOG(NLOG_CLOCKSTATUS) 3553 msyslog(LOG_INFO, "PARSE receiver #%d: SYNCHRONIZED", 3554 CLK_UNIT(parse->peer)); 3555 } 3556 3557 refclock_report(parse->peer, event); 3558 } 3559 } 3560 3561 /*-------------------------------------------------- 3562 * process a PARSE time sample 3563 */ 3564 static void 3565 parse_process( 3566 struct parseunit *parse, 3567 parsetime_t *parsetime 3568 ) 3569 { 3570 l_fp off, rectime, reftime; 3571 double fudge; 3572 3573 /* 3574 * check for changes in conversion status 3575 * (only one for each new status !) 3576 */ 3577 if (((parsetime->parse_status & CVT_MASK) != CVT_OK) && 3578 ((parsetime->parse_status & CVT_MASK) != CVT_NONE) && 3579 (parse->timedata.parse_status != parsetime->parse_status)) 3580 { 3581 char buffer[400]; 3582 3583 NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */ 3584 msyslog(LOG_WARNING, "PARSE receiver #%d: conversion status \"%s\"", 3585 CLK_UNIT(parse->peer), parsestatus(parsetime->parse_status, buffer, sizeof(buffer))); 3586 3587 if ((parsetime->parse_status & CVT_MASK) == CVT_FAIL) 3588 { 3589 /* 3590 * tell more about the story - list time code 3591 * there is a slight change for a race condition and 3592 * the time code might be overwritten by the next packet 3593 */ 3594 parsectl_t tmpctl; 3595 3596 if (!PARSE_GETTIMECODE(parse, &tmpctl)) 3597 { 3598 ERR(ERR_INTERNAL) 3599 msyslog(LOG_ERR, "PARSE receiver #%d: parse_process: parse_timecode() FAILED", CLK_UNIT(parse->peer)); 3600 } 3601 else 3602 { 3603 ERR(ERR_BADDATA) 3604 msyslog(LOG_WARNING, "PARSE receiver #%d: FAILED TIMECODE: \"%s\" (check receiver configuration / wiring)", 3605 CLK_UNIT(parse->peer), mkascii(buffer, sizeof buffer, tmpctl.parsegettc.parse_buffer, (unsigned)(tmpctl.parsegettc.parse_count - 1))); 3606 } 3607 } 3608 } 3609 3610 /* 3611 * examine status and post appropriate events 3612 */ 3613 if ((parsetime->parse_status & CVT_MASK) != CVT_OK) 3614 { 3615 /* 3616 * got bad data - tell the rest of the system 3617 */ 3618 switch (parsetime->parse_status & CVT_MASK) 3619 { 3620 case CVT_NONE: 3621 if ((parsetime->parse_status & CVT_ADDITIONAL) && 3622 parse->parse_type->cl_message) 3623 parse->parse_type->cl_message(parse, parsetime); 3624 /* 3625 * save PPS information that comes piggyback 3626 */ 3627 if (PARSE_PPS(parsetime->parse_state)) 3628 { 3629 parse->timedata.parse_state |= PARSEB_PPS|PARSEB_S_PPS; 3630 parse->timedata.parse_ptime = parsetime->parse_ptime; 3631 } 3632 break; /* well, still waiting - timeout is handled at higher levels */ 3633 3634 case CVT_FAIL: 3635 if (parsetime->parse_status & CVT_BADFMT) 3636 { 3637 parse_event(parse, CEVNT_BADREPLY); 3638 } 3639 else 3640 if (parsetime->parse_status & CVT_BADDATE) 3641 { 3642 parse_event(parse, CEVNT_BADDATE); 3643 } 3644 else 3645 if (parsetime->parse_status & CVT_BADTIME) 3646 { 3647 parse_event(parse, CEVNT_BADTIME); 3648 } 3649 else 3650 { 3651 parse_event(parse, CEVNT_BADREPLY); /* for the lack of something better */ 3652 } 3653 } 3654 return; /* skip the rest - useless */ 3655 } 3656 3657 /* 3658 * check for format changes 3659 * (in case somebody has swapped clocks 8-) 3660 */ 3661 if (parse->lastformat != parsetime->parse_format) 3662 { 3663 parsectl_t tmpctl; 3664 3665 tmpctl.parseformat.parse_format = parsetime->parse_format; 3666 3667 if (!PARSE_GETFMT(parse, &tmpctl)) 3668 { 3669 ERR(ERR_INTERNAL) 3670 msyslog(LOG_ERR, "PARSE receiver #%d: parse_getfmt() FAILED", CLK_UNIT(parse->peer)); 3671 } 3672 else 3673 { 3674 NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */ 3675 msyslog(LOG_INFO, "PARSE receiver #%d: packet format \"%s\"", 3676 CLK_UNIT(parse->peer), tmpctl.parseformat.parse_buffer); 3677 } 3678 parse->lastformat = parsetime->parse_format; 3679 } 3680 3681 /* 3682 * now, any changes ? 3683 */ 3684 if ((parse->timedata.parse_state ^ parsetime->parse_state) & 3685 ~(unsigned)(PARSEB_PPS|PARSEB_S_PPS)) 3686 { 3687 char tmp1[200]; 3688 char tmp2[200]; 3689 /* 3690 * something happend - except for PPS events 3691 */ 3692 3693 (void) parsestate(parsetime->parse_state, tmp1, sizeof(tmp1)); 3694 (void) parsestate(parse->timedata.parse_state, tmp2, sizeof(tmp2)); 3695 3696 NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */ 3697 msyslog(LOG_INFO,"PARSE receiver #%d: STATE CHANGE: %s -> %s", 3698 CLK_UNIT(parse->peer), tmp2, tmp1); 3699 } 3700 3701 /* 3702 * carry on PPS information if still usable 3703 */ 3704 if (PARSE_PPS(parse->timedata.parse_state) && !PARSE_PPS(parsetime->parse_state)) 3705 { 3706 parsetime->parse_state |= PARSEB_PPS|PARSEB_S_PPS; 3707 parsetime->parse_ptime = parse->timedata.parse_ptime; 3708 } 3709 3710 /* 3711 * remember for future 3712 */ 3713 parse->timedata = *parsetime; 3714 3715 /* 3716 * check to see, whether the clock did a complete powerup or lost PZF signal 3717 * and post correct events for current condition 3718 */ 3719 if (PARSE_POWERUP(parsetime->parse_state)) 3720 { 3721 /* 3722 * this is bad, as we have completely lost synchronisation 3723 * well this is a problem with the receiver here 3724 * for PARSE Meinberg DCF77 receivers the lost synchronisation 3725 * is true as it is the powerup state and the time is taken 3726 * from a crude real time clock chip 3727 * for the PZF series this is only partly true, as 3728 * PARSE_POWERUP only means that the pseudo random 3729 * phase shift sequence cannot be found. this is only 3730 * bad, if we have never seen the clock in the SYNC 3731 * state, where the PHASE and EPOCH are correct. 3732 * for reporting events the above business does not 3733 * really matter, but we can use the time code 3734 * even in the POWERUP state after having seen 3735 * the clock in the synchronized state (PZF class 3736 * receivers) unless we have had a telegram disruption 3737 * after having seen the clock in the SYNC state. we 3738 * thus require having seen the clock in SYNC state 3739 * *after* having missed telegrams (noresponse) from 3740 * the clock. one problem remains: we might use erroneously 3741 * POWERUP data if the disruption is shorter than 1 polling 3742 * interval. fortunately powerdowns last usually longer than 64 3743 * seconds and the receiver is at least 2 minutes in the 3744 * POWERUP or NOSYNC state before switching to SYNC 3745 */ 3746 parse_event(parse, CEVNT_FAULT); 3747 NLOG(NLOG_CLOCKSTATUS) 3748 ERR(ERR_BADSTATUS) 3749 msyslog(LOG_ERR,"PARSE receiver #%d: NOT SYNCHRONIZED", 3750 CLK_UNIT(parse->peer)); 3751 } 3752 else 3753 { 3754 /* 3755 * we have two states left 3756 * 3757 * SYNC: 3758 * this state means that the EPOCH (timecode) and PHASE 3759 * information has be read correctly (at least two 3760 * successive PARSE timecodes were received correctly) 3761 * this is the best possible state - full trust 3762 * 3763 * NOSYNC: 3764 * The clock should be on phase with respect to the second 3765 * signal, but the timecode has not been received correctly within 3766 * at least the last two minutes. this is a sort of half baked state 3767 * for PARSE Meinberg DCF77 clocks this is bad news (clock running 3768 * without timecode confirmation) 3769 * PZF 535 has also no time confirmation, but the phase should be 3770 * very precise as the PZF signal can be decoded 3771 */ 3772 3773 if (PARSE_SYNC(parsetime->parse_state)) 3774 { 3775 /* 3776 * currently completely synchronized - best possible state 3777 */ 3778 parse->lastsync = current_time; 3779 clear_err(parse, ERR_BADSTATUS); 3780 } 3781 else 3782 { 3783 /* 3784 * we have had some problems receiving the time code 3785 */ 3786 parse_event(parse, CEVNT_PROP); 3787 NLOG(NLOG_CLOCKSTATUS) 3788 ERR(ERR_BADSTATUS) 3789 msyslog(LOG_ERR,"PARSE receiver #%d: TIMECODE NOT CONFIRMED", 3790 CLK_UNIT(parse->peer)); 3791 } 3792 } 3793 3794 fudge = parse->generic->fudgetime1; /* standard RS232 Fudgefactor */ 3795 3796 if (PARSE_TIMECODE(parsetime->parse_state)) 3797 { 3798 rectime = parsetime->parse_stime.fp; 3799 off = reftime = parsetime->parse_time.fp; 3800 3801 L_SUB(&off, &rectime); /* prepare for PPS adjustments logic */ 3802 3803 #ifdef DEBUG 3804 if (debug > 3) 3805 printf("PARSE receiver #%d: Reftime %s, Recvtime %s - initial offset %s\n", 3806 CLK_UNIT(parse->peer), 3807 prettydate(&reftime), 3808 prettydate(&rectime), 3809 lfptoa(&off,6)); 3810 #endif 3811 } 3812 3813 if (PARSE_PPS(parsetime->parse_state) && CLK_PPS(parse->peer)) 3814 { 3815 l_fp offset; 3816 double ppsphaseadjust = parse->ppsphaseadjust; 3817 3818 #ifdef HAVE_PPSAPI 3819 /* 3820 * set fudge = 0.0 if already included in PPS time stamps 3821 */ 3822 if (parse->atom.pps_params.mode & (PPS_OFFSETCLEAR|PPS_OFFSETASSERT)) 3823 { 3824 ppsphaseadjust = 0.0; 3825 } 3826 #endif 3827 3828 /* 3829 * we have a PPS signal - much better than the RS232 stuff (we hope) 3830 */ 3831 offset = parsetime->parse_ptime.fp; 3832 3833 #ifdef DEBUG 3834 if (debug > 3) 3835 printf("PARSE receiver #%d: PPStime %s\n", 3836 CLK_UNIT(parse->peer), 3837 prettydate(&offset)); 3838 #endif 3839 if (PARSE_TIMECODE(parsetime->parse_state)) 3840 { 3841 if (M_ISGEQ(off.l_i, off.l_f, -1, 0x80000000) && 3842 M_ISGEQ(0, 0x7fffffff, off.l_i, off.l_f)) 3843 { 3844 fudge = ppsphaseadjust; /* pick PPS fudge factor */ 3845 3846 /* 3847 * RS232 offsets within [-0.5..0.5[ - take PPS offsets 3848 */ 3849 3850 if (parse->parse_type->cl_flags & PARSE_F_PPSONSECOND) 3851 { 3852 reftime = off = offset; 3853 if (reftime.l_uf & (unsigned)0x80000000) 3854 reftime.l_ui++; 3855 reftime.l_uf = 0; 3856 3857 3858 /* 3859 * implied on second offset 3860 */ 3861 off.l_uf = ~off.l_uf; /* map [0.5..1[ -> [-0.5..0[ */ 3862 off.l_ui = (off.l_f < 0) ? ~0 : 0; /* sign extend */ 3863 } 3864 else 3865 { 3866 /* 3867 * time code describes pulse 3868 */ 3869 reftime = off = parsetime->parse_time.fp; 3870 3871 L_SUB(&off, &offset); /* true offset */ 3872 } 3873 } 3874 /* 3875 * take RS232 offset when PPS when out of bounds 3876 */ 3877 } 3878 else 3879 { 3880 fudge = ppsphaseadjust; /* pick PPS fudge factor */ 3881 /* 3882 * Well, no time code to guide us - assume on second pulse 3883 * and pray, that we are within [-0.5..0.5[ 3884 */ 3885 off = offset; 3886 reftime = offset; 3887 if (reftime.l_uf & (unsigned)0x80000000) 3888 reftime.l_ui++; 3889 reftime.l_uf = 0; 3890 /* 3891 * implied on second offset 3892 */ 3893 off.l_uf = ~off.l_uf; /* map [0.5..1[ -> [-0.5..0[ */ 3894 off.l_ui = (off.l_f < 0) ? ~0 : 0; /* sign extend */ 3895 } 3896 } 3897 else 3898 { 3899 if (!PARSE_TIMECODE(parsetime->parse_state)) 3900 { 3901 /* 3902 * Well, no PPS, no TIMECODE, no more work ... 3903 */ 3904 if ((parsetime->parse_status & CVT_ADDITIONAL) && 3905 parse->parse_type->cl_message) 3906 parse->parse_type->cl_message(parse, parsetime); 3907 return; 3908 } 3909 } 3910 3911 #ifdef DEBUG 3912 if (debug > 3) 3913 printf("PARSE receiver #%d: Reftime %s, Recvtime %s - final offset %s\n", 3914 CLK_UNIT(parse->peer), 3915 prettydate(&reftime), 3916 prettydate(&rectime), 3917 lfptoa(&off,6)); 3918 #endif 3919 3920 3921 rectime = reftime; 3922 L_SUB(&rectime, &off); /* just to keep the ntp interface happy */ 3923 3924 #ifdef DEBUG 3925 if (debug > 3) 3926 printf("PARSE receiver #%d: calculated Reftime %s, Recvtime %s\n", 3927 CLK_UNIT(parse->peer), 3928 prettydate(&reftime), 3929 prettydate(&rectime)); 3930 #endif 3931 3932 if ((parsetime->parse_status & CVT_ADDITIONAL) && 3933 parse->parse_type->cl_message) 3934 parse->parse_type->cl_message(parse, parsetime); 3935 3936 if (PARSE_SYNC(parsetime->parse_state)) 3937 { 3938 /* 3939 * log OK status 3940 */ 3941 parse_event(parse, CEVNT_NOMINAL); 3942 } 3943 3944 clear_err(parse, ERR_BADIO); 3945 clear_err(parse, ERR_BADDATA); 3946 clear_err(parse, ERR_NODATA); 3947 clear_err(parse, ERR_INTERNAL); 3948 3949 /* 3950 * and now stick it into the clock machine 3951 * samples are only valid iff lastsync is not too old and 3952 * we have seen the clock in sync at least once 3953 * after the last time we didn't see an expected data telegram 3954 * at startup being not in sync is also bad just like 3955 * POWERUP state 3956 * see the clock states section above for more reasoning 3957 */ 3958 if (((current_time - parse->lastsync) > parse->maxunsync) || 3959 (parse->lastsync < parse->lastmissed) || 3960 ((parse->lastsync == 0) && !PARSE_SYNC(parsetime->parse_state)) || 3961 PARSE_POWERUP(parsetime->parse_state)) 3962 { 3963 parse->generic->leap = LEAP_NOTINSYNC; 3964 parse->lastsync = 0; /* wait for full sync again */ 3965 } 3966 else 3967 { 3968 if (PARSE_LEAPADD(parsetime->parse_state)) 3969 { 3970 /* 3971 * we pick this state also for time code that pass leap warnings 3972 * without direction information (as earth is currently slowing 3973 * down). 3974 */ 3975 parse->generic->leap = (parse->flags & PARSE_LEAP_DELETE) ? LEAP_DELSECOND : LEAP_ADDSECOND; 3976 } 3977 else 3978 if (PARSE_LEAPDEL(parsetime->parse_state)) 3979 { 3980 parse->generic->leap = LEAP_DELSECOND; 3981 } 3982 else 3983 { 3984 parse->generic->leap = LEAP_NOWARNING; 3985 } 3986 } 3987 3988 if (parse->generic->leap != LEAP_NOTINSYNC) 3989 { 3990 /* 3991 * only good/trusted samples are interesting 3992 */ 3993 #ifdef DEBUG 3994 if (debug > 2) 3995 { 3996 printf("PARSE receiver #%d: refclock_process_offset(reftime=%s, rectime=%s, Fudge=%f)\n", 3997 CLK_UNIT(parse->peer), 3998 prettydate(&reftime), 3999 prettydate(&rectime), 4000 fudge); 4001 } 4002 #endif 4003 parse->generic->lastref = reftime; 4004 4005 refclock_process_offset(parse->generic, reftime, rectime, fudge); 4006 4007 #ifdef HAVE_PPSAPI 4008 /* 4009 * pass PPS information on to PPS clock 4010 */ 4011 if (PARSE_PPS(parsetime->parse_state) && CLK_PPS(parse->peer)) 4012 { 4013 /* refclock_pps includes fudgetime1 - we keep the RS232 offset in there :-( */ 4014 double savedtime1 = parse->generic->fudgetime1; 4015 4016 parse->generic->fudgetime1 = fudge; 4017 4018 if (refclock_pps(parse->peer, &parse->atom, 4019 parse->flags & (CLK_FLAG1|CLK_FLAG2|CLK_FLAG3|CLK_FLAG4))) { 4020 parse->peer->flags |= FLAG_PPS; 4021 } else { 4022 parse->peer->flags &= ~FLAG_PPS; 4023 } 4024 4025 parse->generic->fudgetime1 = savedtime1; 4026 4027 parse_hardpps(parse, PARSE_HARDPPS_ENABLE); 4028 } 4029 #endif 4030 } else { 4031 parse_hardpps(parse, PARSE_HARDPPS_DISABLE); 4032 parse->peer->flags &= ~FLAG_PPS; 4033 } 4034 4035 /* 4036 * ready, unless the machine wants a sample or 4037 * we are in fast startup mode (peer->dist > MAXDISTANCE) 4038 */ 4039 if (!parse->pollneeddata && parse->peer->disp <= MAXDISTANCE) 4040 return; 4041 4042 parse->pollneeddata = 0; 4043 4044 parse->timedata.parse_state &= ~(unsigned)(PARSEB_PPS|PARSEB_S_PPS); 4045 4046 refclock_receive(parse->peer); 4047 } 4048 4049 /**=========================================================================== 4050 ** special code for special clocks 4051 **/ 4052 4053 static void 4054 mk_utcinfo( 4055 char *t, 4056 int wnt, 4057 int wnlsf, 4058 int dn, 4059 int dtls, 4060 int dtlsf, 4061 int size 4062 ) 4063 { 4064 l_fp leapdate; 4065 char *start = t; 4066 4067 snprintf(t, size, "current correction %d sec", dtls); 4068 t += strlen(t); 4069 4070 if (wnlsf < 990) 4071 wnlsf += 1024; 4072 4073 if (wnt < 990) 4074 wnt += 1024; 4075 4076 gpstolfp((unsigned short)wnlsf, (unsigned short)dn, 0, &leapdate); 4077 4078 if ((dtlsf != dtls) && 4079 ((wnlsf - wnt) < 52)) 4080 { 4081 snprintf(t, BUFFER_SIZES(start, t, size), ", next correction %d sec on %s, new GPS-UTC offset %d", 4082 dtlsf - dtls, gmprettydate(&leapdate), dtlsf); 4083 } 4084 else 4085 { 4086 snprintf(t, BUFFER_SIZES(start, t, size), ", last correction on %s", 4087 gmprettydate(&leapdate)); 4088 } 4089 } 4090 4091 #ifdef CLOCK_MEINBERG 4092 /**=========================================================================== 4093 ** Meinberg GPS166/GPS167 support 4094 **/ 4095 4096 /*------------------------------------------------------------ 4097 * gps16x_message - process GPS16x messages 4098 */ 4099 static void 4100 gps16x_message( 4101 struct parseunit *parse, 4102 parsetime_t *parsetime 4103 ) 4104 { 4105 if (parse->timedata.parse_msglen && parsetime->parse_msg[0] == SOH) 4106 { 4107 GPS_MSG_HDR header; 4108 unsigned char *bufp = (unsigned char *)parsetime->parse_msg + 1; 4109 4110 #ifdef DEBUG 4111 if (debug > 2) 4112 { 4113 char msgbuffer[600]; 4114 4115 mkreadable(msgbuffer, sizeof(msgbuffer), (char *)parsetime->parse_msg, parsetime->parse_msglen, 1); 4116 printf("PARSE receiver #%d: received message (%d bytes) >%s<\n", 4117 CLK_UNIT(parse->peer), 4118 parsetime->parse_msglen, 4119 msgbuffer); 4120 } 4121 #endif 4122 get_mbg_header(&bufp, &header); 4123 if (header.gps_hdr_csum == mbg_csum(parsetime->parse_msg + 1, 6) && 4124 (header.gps_len == 0 || 4125 (header.gps_len < sizeof(parsetime->parse_msg) && 4126 header.gps_data_csum == mbg_csum(bufp, header.gps_len)))) 4127 { 4128 /* 4129 * clean message 4130 */ 4131 switch (header.gps_cmd) 4132 { 4133 case GPS_SW_REV: 4134 { 4135 char buffer[64]; 4136 SW_REV gps_sw_rev; 4137 4138 get_mbg_sw_rev(&bufp, &gps_sw_rev); 4139 snprintf(buffer, sizeof(buffer), "meinberg_gps_version=\"%x.%02x%s%s\"", 4140 (gps_sw_rev.code >> 8) & 0xFF, 4141 gps_sw_rev.code & 0xFF, 4142 gps_sw_rev.name[0] ? " " : "", 4143 gps_sw_rev.name); 4144 set_var(&parse->kv, buffer, strlen(buffer)+1, RO|DEF); 4145 } 4146 break; 4147 4148 case GPS_STAT: 4149 { 4150 static struct state 4151 { 4152 unsigned short flag; /* status flag */ 4153 unsigned const char *string; /* bit name */ 4154 } states[] = 4155 { 4156 { TM_ANT_DISCONN, (const unsigned char *)"ANTENNA FAULTY" }, 4157 { TM_SYN_FLAG, (const unsigned char *)"NO SYNC SIGNAL" }, 4158 { TM_NO_SYNC, (const unsigned char *)"NO SYNC POWERUP" }, 4159 { TM_NO_POS, (const unsigned char *)"NO POSITION" }, 4160 { 0, (const unsigned char *)"" } 4161 }; 4162 unsigned short status; 4163 struct state *s = states; 4164 char buffer[512]; 4165 char *p, *b; 4166 4167 status = get_lsb_short(&bufp); 4168 snprintf(buffer, sizeof(buffer), "meinberg_gps_status=\"[0x%04x] ", status); 4169 4170 if (status) 4171 { 4172 p = b = buffer + strlen(buffer); 4173 while (s->flag) 4174 { 4175 if (status & s->flag) 4176 { 4177 if (p != b) 4178 { 4179 *p++ = ','; 4180 *p++ = ' '; 4181 } 4182 4183 strncat(p, (const char *)s->string, sizeof(buffer)); 4184 } 4185 s++; 4186 } 4187 4188 *p++ = '"'; 4189 *p = '\0'; 4190 } 4191 else 4192 { 4193 strncat(buffer, "<OK>\"", sizeof(buffer)); 4194 } 4195 4196 set_var(&parse->kv, buffer, strlen(buffer)+1, RO|DEF); 4197 } 4198 break; 4199 4200 case GPS_POS_XYZ: 4201 { 4202 XYZ xyz; 4203 char buffer[256]; 4204 4205 get_mbg_xyz(&bufp, xyz); 4206 snprintf(buffer, sizeof(buffer), "gps_position(XYZ)=\"%s m, %s m, %s m\"", 4207 mfptoa(xyz[XP].l_ui, xyz[XP].l_uf, 1), 4208 mfptoa(xyz[YP].l_ui, xyz[YP].l_uf, 1), 4209 mfptoa(xyz[ZP].l_ui, xyz[ZP].l_uf, 1)); 4210 4211 set_var(&parse->kv, buffer, sizeof(buffer), RO|DEF); 4212 } 4213 break; 4214 4215 case GPS_POS_LLA: 4216 { 4217 LLA lla; 4218 char buffer[256]; 4219 4220 get_mbg_lla(&bufp, lla); 4221 4222 snprintf(buffer, sizeof(buffer), "gps_position(LLA)=\"%s deg, %s deg, %s m\"", 4223 mfptoa(lla[LAT].l_ui, lla[LAT].l_uf, 4), 4224 mfptoa(lla[LON].l_ui, lla[LON].l_uf, 4), 4225 mfptoa(lla[ALT].l_ui, lla[ALT].l_uf, 1)); 4226 4227 set_var(&parse->kv, buffer, sizeof(buffer), RO|DEF); 4228 } 4229 break; 4230 4231 case GPS_TZDL: 4232 break; 4233 4234 case GPS_PORT_PARM: 4235 break; 4236 4237 case GPS_SYNTH: 4238 break; 4239 4240 case GPS_ANT_INFO: 4241 { 4242 ANT_INFO antinfo; 4243 char buffer[512]; 4244 char *p; 4245 4246 get_mbg_antinfo(&bufp, &antinfo); 4247 snprintf(buffer, sizeof(buffer), "meinberg_antenna_status=\""); 4248 p = buffer + strlen(buffer); 4249 4250 switch (antinfo.status) 4251 { 4252 case ANT_INVALID: 4253 strncat(p, "<OK>", BUFFER_SIZE(buffer, p)); 4254 p += strlen(p); 4255 break; 4256 4257 case ANT_DISCONN: 4258 strncat(p, "DISCONNECTED since ", BUFFER_SIZE(buffer, p)); 4259 NLOG(NLOG_CLOCKSTATUS) 4260 ERR(ERR_BADSTATUS) 4261 msyslog(LOG_ERR,"PARSE receiver #%d: ANTENNA FAILURE: %s", 4262 CLK_UNIT(parse->peer), p); 4263 4264 p += strlen(p); 4265 mbg_tm_str(&p, &antinfo.tm_disconn, BUFFER_SIZE(buffer, p)); 4266 *p = '\0'; 4267 break; 4268 4269 case ANT_RECONN: 4270 strncat(p, "RECONNECTED on ", BUFFER_SIZE(buffer, p)); 4271 p += strlen(p); 4272 mbg_tm_str(&p, &antinfo.tm_reconn, BUFFER_SIZE(buffer, p)); 4273 snprintf(p, BUFFER_SIZE(buffer, p), ", reconnect clockoffset %c%ld.%07ld s, disconnect time ", 4274 (antinfo.delta_t < 0) ? '-' : '+', 4275 ABS(antinfo.delta_t) / 10000, 4276 ABS(antinfo.delta_t) % 10000); 4277 p += strlen(p); 4278 mbg_tm_str(&p, &antinfo.tm_disconn, BUFFER_SIZE(buffer, p)); 4279 *p = '\0'; 4280 break; 4281 4282 default: 4283 snprintf(p, BUFFER_SIZE(buffer, p), "bad status 0x%04x", antinfo.status); 4284 p += strlen(p); 4285 break; 4286 } 4287 4288 strncat(p, "\"", BUFFER_SIZE(buffer, p)); 4289 4290 set_var(&parse->kv, buffer, strlen(buffer)+1, RO|DEF); 4291 } 4292 break; 4293 4294 case GPS_UCAP: 4295 break; 4296 4297 case GPS_CFGH: 4298 { 4299 CFGH cfgh; 4300 char buffer[512]; 4301 char *p; 4302 4303 get_mbg_cfgh(&bufp, &cfgh); 4304 if (cfgh.valid) 4305 { 4306 int i; 4307 4308 p = buffer; 4309 strncpy(buffer, "gps_tot_51=\"", BUFFER_SIZE(buffer, p)); 4310 p += strlen(p); 4311 mbg_tgps_str(&p, &cfgh.tot_51, BUFFER_SIZE(buffer, p)); 4312 strncpy(p, "\"", BUFFER_SIZE(buffer, p)); 4313 set_var(&parse->kv, buffer, strlen(buffer)+1, RO); 4314 4315 p = buffer; 4316 strncpy(buffer, "gps_tot_63=\"", BUFFER_SIZE(buffer, p)); 4317 p += strlen(p); 4318 mbg_tgps_str(&p, &cfgh.tot_63, BUFFER_SIZE(buffer, p)); 4319 strncpy(p, "\"", BUFFER_SIZE(buffer, p)); 4320 set_var(&parse->kv, buffer, strlen(buffer)+1, RO); 4321 4322 p = buffer; 4323 strncpy(buffer, "gps_t0a=\"", BUFFER_SIZE(buffer, p)); 4324 p += strlen(p); 4325 mbg_tgps_str(&p, &cfgh.t0a, BUFFER_SIZE(buffer, p)); 4326 strncpy(p, "\"", BUFFER_SIZE(buffer, p)); 4327 set_var(&parse->kv, buffer, strlen(buffer)+1, RO); 4328 4329 for (i = MIN_SVNO; i < MAX_SVNO; i++) 4330 { 4331 p = buffer; 4332 snprintf(p, BUFFER_SIZE(buffer, p), "gps_cfg[%d]=\"[0x%x] ", i, cfgh.cfg[i]); 4333 p += strlen(p); 4334 switch (cfgh.cfg[i] & 0x7) 4335 { 4336 case 0: 4337 strncpy(p, "BLOCK I", BUFFER_SIZE(buffer, p)); 4338 break; 4339 case 1: 4340 strncpy(p, "BLOCK II", BUFFER_SIZE(buffer, p)); 4341 break; 4342 default: 4343 strncpy(p, "bad CFG", BUFFER_SIZE(buffer, p)); 4344 break; 4345 } 4346 strncat(p, "\"", BUFFER_SIZE(buffer, p)); 4347 set_var(&parse->kv, buffer, strlen(buffer)+1, RO); 4348 4349 p = buffer; 4350 snprintf(p, BUFFER_SIZE(buffer, p), "gps_health[%d]=\"[0x%x] ", i, cfgh.health[i]); 4351 p += strlen(p); 4352 switch ((cfgh.health[i] >> 5) & 0x7 ) 4353 { 4354 case 0: 4355 strncpy(p, "OK;", BUFFER_SIZE(buffer, p)); 4356 break; 4357 case 1: 4358 strncpy(p, "PARITY;", BUFFER_SIZE(buffer, p)); 4359 break; 4360 case 2: 4361 strncpy(p, "TLM/HOW;", BUFFER_SIZE(buffer, p)); 4362 break; 4363 case 3: 4364 strncpy(p, "Z-COUNT;", BUFFER_SIZE(buffer, p)); 4365 break; 4366 case 4: 4367 strncpy(p, "SUBFRAME 1,2,3;", BUFFER_SIZE(buffer, p)); 4368 break; 4369 case 5: 4370 strncpy(p, "SUBFRAME 4,5;", BUFFER_SIZE(buffer, p)); 4371 break; 4372 case 6: 4373 strncpy(p, "UPLOAD BAD;", BUFFER_SIZE(buffer, p)); 4374 break; 4375 case 7: 4376 strncpy(p, "DATA BAD;", BUFFER_SIZE(buffer, p)); 4377 break; 4378 } 4379 4380 p += strlen(p); 4381 4382 switch (cfgh.health[i] & 0x1F) 4383 { 4384 case 0: 4385 strncpy(p, "SIGNAL OK", BUFFER_SIZE(buffer, p)); 4386 break; 4387 case 0x1C: 4388 strncpy(p, "SV TEMP OUT", BUFFER_SIZE(buffer, p)); 4389 break; 4390 case 0x1D: 4391 strncpy(p, "SV WILL BE TEMP OUT", BUFFER_SIZE(buffer, p)); 4392 break; 4393 case 0x1E: 4394 break; 4395 case 0x1F: 4396 strncpy(p, "MULTIPLE ERRS", BUFFER_SIZE(buffer, p)); 4397 break; 4398 default: 4399 strncpy(p, "TRANSMISSION PROBLEMS", BUFFER_SIZE(buffer, p)); 4400 break; 4401 } 4402 4403 strncat(p, "\"", sizeof(buffer)); 4404 set_var(&parse->kv, buffer, strlen(buffer)+1, RO); 4405 } 4406 } 4407 } 4408 break; 4409 4410 case GPS_ALM: 4411 break; 4412 4413 case GPS_EPH: 4414 break; 4415 4416 case GPS_UTC: 4417 { 4418 UTC utc; 4419 char buffer[512]; 4420 char *p; 4421 4422 p = buffer; 4423 4424 get_mbg_utc(&bufp, &utc); 4425 4426 if (utc.valid) 4427 { 4428 strncpy(p, "gps_utc_correction=\"", sizeof(buffer)); 4429 p += strlen(p); 4430 mk_utcinfo(p, utc.t0t.wn, utc.WNlsf, utc.DNt, utc.delta_tls, utc.delta_tlsf, BUFFER_SIZE(buffer, p)); 4431 strncat(p, "\"", BUFFER_SIZE(buffer, p)); 4432 } 4433 else 4434 { 4435 strncpy(p, "gps_utc_correction=\"<NO UTC DATA>\"", BUFFER_SIZE(buffer, p)); 4436 } 4437 set_var(&parse->kv, buffer, strlen(buffer)+1, RO|DEF); 4438 } 4439 break; 4440 4441 case GPS_IONO: 4442 break; 4443 4444 case GPS_ASCII_MSG: 4445 { 4446 ASCII_MSG gps_ascii_msg; 4447 char buffer[128]; 4448 4449 get_mbg_ascii_msg(&bufp, &gps_ascii_msg); 4450 4451 if (gps_ascii_msg.valid) 4452 { 4453 char buffer1[128]; 4454 mkreadable(buffer1, sizeof(buffer1), gps_ascii_msg.s, strlen(gps_ascii_msg.s), (int)0); 4455 4456 snprintf(buffer, sizeof(buffer), "gps_message=\"%s\"", buffer1); 4457 } 4458 else 4459 strncpy(buffer, "gps_message=<NONE>", sizeof(buffer)); 4460 4461 set_var(&parse->kv, buffer, strlen(buffer)+1, RO|DEF); 4462 } 4463 4464 break; 4465 4466 default: 4467 break; 4468 } 4469 } 4470 else 4471 { 4472 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)", 4473 CLK_UNIT(parse->peer), 4474 header.gps_hdr_csum, mbg_csum(parsetime->parse_msg + 1, 6), 4475 header.gps_len, 4476 header.gps_data_csum, mbg_csum(bufp, (unsigned)((header.gps_len < sizeof(parsetime->parse_msg)) ? header.gps_len : 0))); 4477 } 4478 } 4479 4480 return; 4481 } 4482 4483 /*------------------------------------------------------------ 4484 * gps16x_poll - query the reciver peridically 4485 */ 4486 static void 4487 gps16x_poll( 4488 struct peer *peer 4489 ) 4490 { 4491 struct parseunit *parse = (struct parseunit *)peer->procptr->unitptr; 4492 4493 static GPS_MSG_HDR sequence[] = 4494 { 4495 { GPS_SW_REV, 0, 0, 0 }, 4496 { GPS_STAT, 0, 0, 0 }, 4497 { GPS_UTC, 0, 0, 0 }, 4498 { GPS_ASCII_MSG, 0, 0, 0 }, 4499 { GPS_ANT_INFO, 0, 0, 0 }, 4500 { GPS_CFGH, 0, 0, 0 }, 4501 { GPS_POS_XYZ, 0, 0, 0 }, 4502 { GPS_POS_LLA, 0, 0, 0 }, 4503 { (unsigned short)~0, 0, 0, 0 } 4504 }; 4505 4506 int rtc; 4507 unsigned char cmd_buffer[64]; 4508 unsigned char *outp = cmd_buffer; 4509 GPS_MSG_HDR *header; 4510 4511 if (((poll_info_t *)parse->parse_type->cl_data)->rate) 4512 { 4513 parse->peer->nextaction = current_time + ((poll_info_t *)parse->parse_type->cl_data)->rate; 4514 } 4515 4516 if (sequence[parse->localstate].gps_cmd == (unsigned short)~0) 4517 parse->localstate = 0; 4518 4519 header = sequence + parse->localstate++; 4520 4521 *outp++ = SOH; /* start command */ 4522 4523 put_mbg_header(&outp, header); 4524 outp = cmd_buffer + 1; 4525 4526 header->gps_hdr_csum = (short)mbg_csum(outp, 6); 4527 put_mbg_header(&outp, header); 4528 4529 #ifdef DEBUG 4530 if (debug > 2) 4531 { 4532 char buffer[128]; 4533 4534 mkreadable(buffer, sizeof(buffer), (char *)cmd_buffer, (unsigned)(outp - cmd_buffer), 1); 4535 printf("PARSE receiver #%d: transmitted message #%ld (%d bytes) >%s<\n", 4536 CLK_UNIT(parse->peer), 4537 parse->localstate - 1, 4538 (int)(outp - cmd_buffer), 4539 buffer); 4540 } 4541 #endif 4542 4543 rtc = write(parse->generic->io.fd, cmd_buffer, (unsigned long)(outp - cmd_buffer)); 4544 4545 if (rtc < 0) 4546 { 4547 ERR(ERR_BADIO) 4548 msyslog(LOG_ERR, "PARSE receiver #%d: gps16x_poll: failed to send cmd to clock: %m", CLK_UNIT(parse->peer)); 4549 } 4550 else 4551 if (rtc != outp - cmd_buffer) 4552 { 4553 ERR(ERR_BADIO) 4554 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)); 4555 } 4556 4557 clear_err(parse, ERR_BADIO); 4558 return; 4559 } 4560 4561 /*-------------------------------------------------- 4562 * init routine - setup timer 4563 */ 4564 static int 4565 gps16x_poll_init( 4566 struct parseunit *parse 4567 ) 4568 { 4569 if (((poll_info_t *)parse->parse_type->cl_data)->rate) 4570 { 4571 parse->peer->action = gps16x_poll; 4572 gps16x_poll(parse->peer); 4573 } 4574 4575 return 0; 4576 } 4577 4578 #else 4579 static void 4580 gps16x_message( 4581 struct parseunit *parse, 4582 parsetime_t *parsetime 4583 ) 4584 {} 4585 static int 4586 gps16x_poll_init( 4587 struct parseunit *parse 4588 ) 4589 { 4590 return 1; 4591 } 4592 #endif /* CLOCK_MEINBERG */ 4593 4594 /**=========================================================================== 4595 ** clock polling support 4596 **/ 4597 4598 /*-------------------------------------------------- 4599 * direct poll routine 4600 */ 4601 static void 4602 poll_dpoll( 4603 struct parseunit *parse 4604 ) 4605 { 4606 int rtc; 4607 const char *ps = ((poll_info_t *)parse->parse_type->cl_data)->string; 4608 int ct = ((poll_info_t *)parse->parse_type->cl_data)->count; 4609 4610 rtc = write(parse->generic->io.fd, ps, (unsigned long)ct); 4611 if (rtc < 0) 4612 { 4613 ERR(ERR_BADIO) 4614 msyslog(LOG_ERR, "PARSE receiver #%d: poll_dpoll: failed to send cmd to clock: %m", CLK_UNIT(parse->peer)); 4615 } 4616 else 4617 if (rtc != ct) 4618 { 4619 ERR(ERR_BADIO) 4620 msyslog(LOG_ERR, "PARSE receiver #%d: poll_dpoll: failed to send cmd incomplete (%d of %d bytes sent)", CLK_UNIT(parse->peer), rtc, ct); 4621 } 4622 clear_err(parse, ERR_BADIO); 4623 } 4624 4625 /*-------------------------------------------------- 4626 * periodic poll routine 4627 */ 4628 static void 4629 poll_poll( 4630 struct peer *peer 4631 ) 4632 { 4633 struct parseunit *parse = (struct parseunit *)peer->procptr->unitptr; 4634 4635 if (parse->parse_type->cl_poll) 4636 parse->parse_type->cl_poll(parse); 4637 4638 if (((poll_info_t *)parse->parse_type->cl_data)->rate) 4639 { 4640 parse->peer->nextaction = current_time + ((poll_info_t *)parse->parse_type->cl_data)->rate; 4641 } 4642 } 4643 4644 /*-------------------------------------------------- 4645 * init routine - setup timer 4646 */ 4647 static int 4648 poll_init( 4649 struct parseunit *parse 4650 ) 4651 { 4652 if (((poll_info_t *)parse->parse_type->cl_data)->rate) 4653 { 4654 parse->peer->action = poll_poll; 4655 poll_poll(parse->peer); 4656 } 4657 4658 return 0; 4659 } 4660 4661 /**=========================================================================== 4662 ** Trimble support 4663 **/ 4664 4665 /*------------------------------------------------------------- 4666 * trimble TAIP init routine - setup EOL and then do poll_init. 4667 */ 4668 static int 4669 trimbletaip_init( 4670 struct parseunit *parse 4671 ) 4672 { 4673 #ifdef HAVE_TERMIOS 4674 struct termios tio; 4675 #endif 4676 #ifdef HAVE_SYSV_TTYS 4677 struct termio tio; 4678 #endif 4679 /* 4680 * configure terminal line for trimble receiver 4681 */ 4682 if (TTY_GETATTR(parse->generic->io.fd, &tio) == -1) 4683 { 4684 msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_init: tcgetattr(fd, &tio): %m", CLK_UNIT(parse->peer)); 4685 return 0; 4686 } 4687 else 4688 { 4689 tio.c_cc[VEOL] = TRIMBLETAIP_EOL; 4690 4691 if (TTY_SETATTR(parse->generic->io.fd, &tio) == -1) 4692 { 4693 msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_init: tcsetattr(fd, &tio): %m", CLK_UNIT(parse->peer)); 4694 return 0; 4695 } 4696 } 4697 return poll_init(parse); 4698 } 4699 4700 /*-------------------------------------------------- 4701 * trimble TAIP event routine - reset receiver upon data format trouble 4702 */ 4703 static const char *taipinit[] = { 4704 ">FPV00000000<", 4705 ">SRM;ID_FLAG=F;CS_FLAG=T;EC_FLAG=F;FR_FLAG=T;CR_FLAG=F<", 4706 ">FTM00020001<", 4707 (char *)0 4708 }; 4709 4710 static void 4711 trimbletaip_event( 4712 struct parseunit *parse, 4713 int event 4714 ) 4715 { 4716 switch (event) 4717 { 4718 case CEVNT_BADREPLY: /* reset on garbled input */ 4719 case CEVNT_TIMEOUT: /* reset on no input */ 4720 { 4721 const char **iv; 4722 4723 iv = taipinit; 4724 while (*iv) 4725 { 4726 int rtc = write(parse->generic->io.fd, *iv, strlen(*iv)); 4727 if (rtc < 0) 4728 { 4729 msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_event: failed to send cmd to clock: %m", CLK_UNIT(parse->peer)); 4730 return; 4731 } 4732 else 4733 { 4734 if (rtc != (int)strlen(*iv)) 4735 { 4736 msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_event: failed to send cmd incomplete (%d of %d bytes sent)", 4737 CLK_UNIT(parse->peer), rtc, (int)strlen(*iv)); 4738 return; 4739 } 4740 } 4741 iv++; 4742 } 4743 4744 NLOG(NLOG_CLOCKINFO) 4745 ERR(ERR_BADIO) 4746 msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_event: RECEIVER INITIALIZED", 4747 CLK_UNIT(parse->peer)); 4748 } 4749 break; 4750 4751 default: /* ignore */ 4752 break; 4753 } 4754 } 4755 4756 /* 4757 * This driver supports the Trimble SVee Six Plus GPS receiver module. 4758 * It should support other Trimble receivers which use the Trimble Standard 4759 * Interface Protocol (see below). 4760 * 4761 * The module has a serial I/O port for command/data and a 1 pulse-per-second 4762 * output, about 1 microsecond wide. The leading edge of the pulse is 4763 * coincident with the change of the GPS second. This is the same as 4764 * the change of the UTC second +/- ~1 microsecond. Some other clocks 4765 * specifically use a feature in the data message as a timing reference, but 4766 * the SVee Six Plus does not do this. In fact there is considerable jitter 4767 * on the timing of the messages, so this driver only supports the use 4768 * of the PPS pulse for accurate timing. Where it is determined that 4769 * the offset is way off, when first starting up ntpd for example, 4770 * the timing of the data stream is used until the offset becomes low enough 4771 * (|offset| < CLOCK_MAX), at which point the pps offset is used. 4772 * 4773 * It can use either option for receiving PPS information - the 'ppsclock' 4774 * stream pushed onto the serial data interface to timestamp the Carrier 4775 * Detect interrupts, where the 1PPS connects to the CD line. This only 4776 * works on SunOS 4.1.x currently. To select this, define PPSPPS in 4777 * Config.local. The other option is to use a pulse-stretcher/level-converter 4778 * to convert the PPS pulse into a RS232 start pulse & feed this into another 4779 * tty port. To use this option, define PPSCLK in Config.local. The pps input, 4780 * by whichever method, is handled in ntp_loopfilter.c 4781 * 4782 * The receiver uses a serial message protocol called Trimble Standard 4783 * Interface Protocol (it can support others but this driver only supports 4784 * TSIP). Messages in this protocol have the following form: 4785 * 4786 * <DLE><id> ... <data> ... <DLE><ETX> 4787 * 4788 * Any bytes within the <data> portion of value 10 hex (<DLE>) are doubled 4789 * on transmission and compressed back to one on reception. Otherwise 4790 * the values of data bytes can be anything. The serial interface is RS-422 4791 * asynchronous using 9600 baud, 8 data bits with odd party (**note** 9 bits 4792 * in total!), and 1 stop bit. The protocol supports byte, integer, single, 4793 * and double datatypes. Integers are two bytes, sent most significant first. 4794 * Singles are IEEE754 single precision floating point numbers (4 byte) sent 4795 * sign & exponent first. Doubles are IEEE754 double precision floating point 4796 * numbers (8 byte) sent sign & exponent first. 4797 * The receiver supports a large set of messages, only a small subset of 4798 * which are used here. From driver to receiver the following are used: 4799 * 4800 * ID Description 4801 * 4802 * 21 Request current time 4803 * 22 Mode Select 4804 * 2C Set/Request operating parameters 4805 * 2F Request UTC info 4806 * 35 Set/Request I/O options 4807 4808 * From receiver to driver the following are recognised: 4809 * 4810 * ID Description 4811 * 4812 * 41 GPS Time 4813 * 44 Satellite selection, PDOP, mode 4814 * 46 Receiver health 4815 * 4B Machine code/status 4816 * 4C Report operating parameters (debug only) 4817 * 4F UTC correction data (used to get leap second warnings) 4818 * 55 I/O options (debug only) 4819 * 4820 * All others are accepted but ignored. 4821 * 4822 */ 4823 4824 #define PI 3.1415926535898 /* lots of sig figs */ 4825 #define D2R PI/180.0 4826 4827 /*------------------------------------------------------------------- 4828 * sendcmd, sendbyte, sendetx, sendflt, sendint implement the command 4829 * interface to the receiver. 4830 * 4831 * CAVEAT: the sendflt, sendint routines are byte order dependend and 4832 * float implementation dependend - these must be converted to portable 4833 * versions ! 4834 * 4835 * CURRENT LIMITATION: float implementation. This runs only on systems 4836 * with IEEE754 floats as native floats 4837 */ 4838 4839 typedef struct trimble 4840 { 4841 u_long last_msg; /* last message received */ 4842 u_long last_reset; /* last time a reset was issued */ 4843 u_char qtracking; /* query tracking status */ 4844 u_long ctrack; /* current tracking set */ 4845 u_long ltrack; /* last tracking set */ 4846 } trimble_t; 4847 4848 union uval { 4849 u_char bd[8]; 4850 int iv; 4851 float fv; 4852 double dv; 4853 }; 4854 4855 struct txbuf 4856 { 4857 short idx; /* index to first unused byte */ 4858 u_char *txt; /* pointer to actual data buffer */ 4859 }; 4860 4861 void sendcmd (struct txbuf *buf, int c); 4862 void sendbyte (struct txbuf *buf, int b); 4863 void sendetx (struct txbuf *buf, struct parseunit *parse); 4864 void sendint (struct txbuf *buf, int a); 4865 void sendflt (struct txbuf *buf, double a); 4866 4867 void 4868 sendcmd( 4869 struct txbuf *buf, 4870 int c 4871 ) 4872 { 4873 buf->txt[0] = DLE; 4874 buf->txt[1] = (u_char)c; 4875 buf->idx = 2; 4876 } 4877 4878 void sendcmd (struct txbuf *buf, int c); 4879 void sendbyte (struct txbuf *buf, int b); 4880 void sendetx (struct txbuf *buf, struct parseunit *parse); 4881 void sendint (struct txbuf *buf, int a); 4882 void sendflt (struct txbuf *buf, double a); 4883 4884 void 4885 sendbyte( 4886 struct txbuf *buf, 4887 int b 4888 ) 4889 { 4890 if (b == DLE) 4891 buf->txt[buf->idx++] = DLE; 4892 buf->txt[buf->idx++] = (u_char)b; 4893 } 4894 4895 void 4896 sendetx( 4897 struct txbuf *buf, 4898 struct parseunit *parse 4899 ) 4900 { 4901 buf->txt[buf->idx++] = DLE; 4902 buf->txt[buf->idx++] = ETX; 4903 4904 if (write(parse->generic->io.fd, buf->txt, (unsigned long)buf->idx) != buf->idx) 4905 { 4906 ERR(ERR_BADIO) 4907 msyslog(LOG_ERR, "PARSE receiver #%d: sendetx: failed to send cmd to clock: %m", CLK_UNIT(parse->peer)); 4908 } 4909 else 4910 { 4911 #ifdef DEBUG 4912 if (debug > 2) 4913 { 4914 char buffer[256]; 4915 4916 mkreadable(buffer, sizeof(buffer), (char *)buf->txt, (unsigned)buf->idx, 1); 4917 printf("PARSE receiver #%d: transmitted message (%d bytes) >%s<\n", 4918 CLK_UNIT(parse->peer), 4919 buf->idx, buffer); 4920 } 4921 #endif 4922 clear_err(parse, ERR_BADIO); 4923 } 4924 } 4925 4926 void 4927 sendint( 4928 struct txbuf *buf, 4929 int a 4930 ) 4931 { 4932 /* send 16bit int, msbyte first */ 4933 sendbyte(buf, (u_char)((a>>8) & 0xff)); 4934 sendbyte(buf, (u_char)(a & 0xff)); 4935 } 4936 4937 void 4938 sendflt( 4939 struct txbuf *buf, 4940 double a 4941 ) 4942 { 4943 int i; 4944 union uval uval; 4945 4946 uval.fv = a; 4947 #ifdef WORDS_BIGENDIAN 4948 for (i=0; i<=3; i++) 4949 #else 4950 for (i=3; i>=0; i--) 4951 #endif 4952 sendbyte(buf, uval.bd[i]); 4953 } 4954 4955 #define TRIM_POS_OPT 0x13 /* output position with high precision */ 4956 #define TRIM_TIME_OPT 0x03 /* use UTC time stamps, on second */ 4957 4958 /*-------------------------------------------------- 4959 * trimble TSIP setup routine 4960 */ 4961 static int 4962 trimbletsip_setup( 4963 struct parseunit *parse, 4964 const char *reason 4965 ) 4966 { 4967 u_char buffer[256]; 4968 struct txbuf buf; 4969 trimble_t *t = parse->localdata; 4970 4971 if (t && t->last_reset && 4972 ((t->last_reset + TRIMBLE_RESET_HOLDOFF) > current_time)) { 4973 return 1; /* not yet */ 4974 } 4975 4976 if (t) 4977 t->last_reset = current_time; 4978 4979 buf.txt = buffer; 4980 4981 sendcmd(&buf, CMD_CVERSION); /* request software versions */ 4982 sendetx(&buf, parse); 4983 4984 sendcmd(&buf, CMD_COPERPARAM); /* set operating parameters */ 4985 sendbyte(&buf, 4); /* static */ 4986 sendflt(&buf, 5.0*D2R); /* elevation angle mask = 10 deg XXX */ 4987 sendflt(&buf, 4.0); /* s/n ratio mask = 6 XXX */ 4988 sendflt(&buf, 12.0); /* PDOP mask = 12 */ 4989 sendflt(&buf, 8.0); /* PDOP switch level = 8 */ 4990 sendetx(&buf, parse); 4991 4992 sendcmd(&buf, CMD_CMODESEL); /* fix mode select */ 4993 sendbyte(&buf, 1); /* time transfer mode */ 4994 sendetx(&buf, parse); 4995 4996 sendcmd(&buf, CMD_CMESSAGE); /* request system message */ 4997 sendetx(&buf, parse); 4998 4999 sendcmd(&buf, CMD_CSUPER); /* superpacket fix */ 5000 sendbyte(&buf, 0x2); /* binary mode */ 5001 sendetx(&buf, parse); 5002 5003 sendcmd(&buf, CMD_CIOOPTIONS); /* set I/O options */ 5004 sendbyte(&buf, TRIM_POS_OPT); /* position output */ 5005 sendbyte(&buf, 0x00); /* no velocity output */ 5006 sendbyte(&buf, TRIM_TIME_OPT); /* UTC, compute on seconds */ 5007 sendbyte(&buf, 0x00); /* no raw measurements */ 5008 sendetx(&buf, parse); 5009 5010 sendcmd(&buf, CMD_CUTCPARAM); /* request UTC correction data */ 5011 sendetx(&buf, parse); 5012 5013 NLOG(NLOG_CLOCKINFO) 5014 ERR(ERR_BADIO) 5015 msyslog(LOG_ERR, "PARSE receiver #%d: trimbletsip_setup: RECEIVER RE-INITIALIZED (%s)", CLK_UNIT(parse->peer), reason); 5016 5017 return 0; 5018 } 5019 5020 /*-------------------------------------------------- 5021 * TRIMBLE TSIP check routine 5022 */ 5023 static void 5024 trimble_check( 5025 struct peer *peer 5026 ) 5027 { 5028 struct parseunit *parse = (struct parseunit *)peer->procptr->unitptr; 5029 trimble_t *t = parse->localdata; 5030 u_char buffer[256]; 5031 struct txbuf buf; 5032 buf.txt = buffer; 5033 5034 if (t) 5035 { 5036 if (current_time > t->last_msg + TRIMBLETSIP_IDLE_TIME) 5037 (void)trimbletsip_setup(parse, "message timeout"); 5038 } 5039 5040 poll_poll(parse->peer); /* emit query string and re-arm timer */ 5041 5042 if (t && t->qtracking) 5043 { 5044 u_long oldsats = t->ltrack & ~t->ctrack; 5045 5046 t->qtracking = 0; 5047 t->ltrack = t->ctrack; 5048 5049 if (oldsats) 5050 { 5051 int i; 5052 5053 for (i = 0; oldsats; i++) { 5054 if (oldsats & (1 << i)) 5055 { 5056 sendcmd(&buf, CMD_CSTATTRACK); 5057 sendbyte(&buf, i+1); /* old sat */ 5058 sendetx(&buf, parse); 5059 } 5060 oldsats &= ~(1 << i); 5061 } 5062 } 5063 5064 sendcmd(&buf, CMD_CSTATTRACK); 5065 sendbyte(&buf, 0x00); /* current tracking set */ 5066 sendetx(&buf, parse); 5067 } 5068 } 5069 5070 /*-------------------------------------------------- 5071 * TRIMBLE TSIP end routine 5072 */ 5073 static void 5074 trimbletsip_end( 5075 struct parseunit *parse 5076 ) 5077 { trimble_t *t = parse->localdata; 5078 5079 if (t) 5080 { 5081 free(t); 5082 parse->localdata = (void *)0; 5083 } 5084 parse->peer->nextaction = 0; 5085 parse->peer->action = (void (*) (struct peer *))0; 5086 } 5087 5088 /*-------------------------------------------------- 5089 * TRIMBLE TSIP init routine 5090 */ 5091 static int 5092 trimbletsip_init( 5093 struct parseunit *parse 5094 ) 5095 { 5096 #if defined(VEOL) || defined(VEOL2) 5097 #ifdef HAVE_TERMIOS 5098 struct termios tio; /* NEEDED FOR A LONG TIME ! */ 5099 #endif 5100 #ifdef HAVE_SYSV_TTYS 5101 struct termio tio; /* NEEDED FOR A LONG TIME ! */ 5102 #endif 5103 /* 5104 * allocate local data area 5105 */ 5106 if (!parse->localdata) 5107 { 5108 trimble_t *t; 5109 5110 t = (trimble_t *)(parse->localdata = emalloc(sizeof(trimble_t))); 5111 5112 if (t) 5113 { 5114 memset((char *)t, 0, sizeof(trimble_t)); 5115 t->last_msg = current_time; 5116 } 5117 } 5118 5119 parse->peer->action = trimble_check; 5120 parse->peer->nextaction = current_time; 5121 5122 /* 5123 * configure terminal line for ICANON mode with VEOL characters 5124 */ 5125 if (TTY_GETATTR(parse->generic->io.fd, &tio) == -1) 5126 { 5127 msyslog(LOG_ERR, "PARSE receiver #%d: trimbletsip_init: tcgetattr(%d, &tio): %m", CLK_UNIT(parse->peer), parse->generic->io.fd); 5128 return 0; 5129 } 5130 else 5131 { 5132 if ((parse_clockinfo[CLK_TYPE(parse->peer)].cl_lflag & ICANON)) 5133 { 5134 #ifdef VEOL 5135 tio.c_cc[VEOL] = ETX; 5136 #endif 5137 #ifdef VEOL2 5138 tio.c_cc[VEOL2] = DLE; 5139 #endif 5140 } 5141 5142 if (TTY_SETATTR(parse->generic->io.fd, &tio) == -1) 5143 { 5144 msyslog(LOG_ERR, "PARSE receiver #%d: trimbletsip_init: tcsetattr(%d, &tio): %m", CLK_UNIT(parse->peer), parse->generic->io.fd); 5145 return 0; 5146 } 5147 } 5148 #endif 5149 return trimbletsip_setup(parse, "initial startup"); 5150 } 5151 5152 /*------------------------------------------------------------ 5153 * trimbletsip_event - handle Trimble events 5154 * simple evente handler - attempt to re-initialize receiver 5155 */ 5156 static void 5157 trimbletsip_event( 5158 struct parseunit *parse, 5159 int event 5160 ) 5161 { 5162 switch (event) 5163 { 5164 case CEVNT_BADREPLY: /* reset on garbled input */ 5165 case CEVNT_TIMEOUT: /* reset on no input */ 5166 (void)trimbletsip_setup(parse, "event BAD_REPLY/TIMEOUT"); 5167 break; 5168 5169 default: /* ignore */ 5170 break; 5171 } 5172 } 5173 5174 /* 5175 * getflt, getint convert fields in the incoming data into the 5176 * appropriate type of item 5177 * 5178 * CAVEAT: these routines are currently definitely byte order dependent 5179 * and assume Representation(float) == IEEE754 5180 * These functions MUST be converted to portable versions (especially 5181 * converting the float representation into ntp_fp formats in order 5182 * to avoid floating point operations at all! 5183 */ 5184 5185 static float 5186 getflt( 5187 u_char *bp 5188 ) 5189 { 5190 union uval uval; 5191 5192 #ifdef WORDS_BIGENDIAN 5193 uval.bd[0] = *bp++; 5194 uval.bd[1] = *bp++; 5195 uval.bd[2] = *bp++; 5196 uval.bd[3] = *bp; 5197 #else /* ! WORDS_BIGENDIAN */ 5198 uval.bd[3] = *bp++; 5199 uval.bd[2] = *bp++; 5200 uval.bd[1] = *bp++; 5201 uval.bd[0] = *bp; 5202 #endif /* ! WORDS_BIGENDIAN */ 5203 return uval.fv; 5204 } 5205 5206 static double 5207 getdbl( 5208 u_char *bp 5209 ) 5210 { 5211 union uval uval; 5212 5213 #ifdef WORDS_BIGENDIAN 5214 uval.bd[0] = *bp++; 5215 uval.bd[1] = *bp++; 5216 uval.bd[2] = *bp++; 5217 uval.bd[3] = *bp++; 5218 uval.bd[4] = *bp++; 5219 uval.bd[5] = *bp++; 5220 uval.bd[6] = *bp++; 5221 uval.bd[7] = *bp; 5222 #else /* ! WORDS_BIGENDIAN */ 5223 uval.bd[7] = *bp++; 5224 uval.bd[6] = *bp++; 5225 uval.bd[5] = *bp++; 5226 uval.bd[4] = *bp++; 5227 uval.bd[3] = *bp++; 5228 uval.bd[2] = *bp++; 5229 uval.bd[1] = *bp++; 5230 uval.bd[0] = *bp; 5231 #endif /* ! WORDS_BIGENDIAN */ 5232 return uval.dv; 5233 } 5234 5235 static int 5236 getshort( 5237 unsigned char *p 5238 ) 5239 { 5240 return get_msb_short(&p); 5241 } 5242 5243 /*-------------------------------------------------- 5244 * trimbletsip_message - process trimble messages 5245 */ 5246 #define RTOD (180.0 / 3.1415926535898) 5247 #define mb(_X_) (buffer[2+(_X_)]) /* shortcut for buffer access */ 5248 5249 static void 5250 trimbletsip_message( 5251 struct parseunit *parse, 5252 parsetime_t *parsetime 5253 ) 5254 { 5255 unsigned char *buffer = parsetime->parse_msg; 5256 unsigned int size = parsetime->parse_msglen; 5257 5258 if ((size < 4) || 5259 (buffer[0] != DLE) || 5260 (buffer[size-1] != ETX) || 5261 (buffer[size-2] != DLE)) 5262 { 5263 #ifdef DEBUG 5264 if (debug > 2) { 5265 size_t i; 5266 5267 printf("TRIMBLE BAD packet, size %d:\n ", size); 5268 for (i = 0; i < size; i++) { 5269 printf ("%2.2x, ", buffer[i]&0xff); 5270 if (i%16 == 15) printf("\n\t"); 5271 } 5272 printf("\n"); 5273 } 5274 #endif 5275 return; 5276 } 5277 else 5278 { 5279 int var_flag; 5280 trimble_t *tr = parse->localdata; 5281 unsigned int cmd = buffer[1]; 5282 char pbuffer[200]; 5283 char *t = pbuffer; 5284 cmd_info_t *s; 5285 5286 #ifdef DEBUG 5287 if (debug > 3) { 5288 size_t i; 5289 5290 printf("TRIMBLE packet 0x%02x, size %d:\n ", cmd, size); 5291 for (i = 0; i < size; i++) { 5292 printf ("%2.2x, ", buffer[i]&0xff); 5293 if (i%16 == 15) printf("\n\t"); 5294 } 5295 printf("\n"); 5296 } 5297 #endif 5298 5299 if (tr) 5300 tr->last_msg = current_time; 5301 5302 s = trimble_convert(cmd, trimble_rcmds); 5303 5304 if (s) 5305 { 5306 snprintf(t, BUFFER_SIZE(pbuffer, t), "%s=\"", s->varname); 5307 } 5308 else 5309 { 5310 DPRINTF(1, ("TRIMBLE UNKNOWN COMMAND 0x%02x\n", cmd)); 5311 return; 5312 } 5313 5314 var_flag = s->varmode; 5315 5316 t += strlen(t); 5317 5318 switch(cmd) 5319 { 5320 case CMD_RCURTIME: 5321 snprintf(t, BUFFER_SIZE(pbuffer, t), "%f, %d, %f", 5322 getflt((unsigned char *)&mb(0)), getshort((unsigned char *)&mb(4)), 5323 getflt((unsigned char *)&mb(6))); 5324 break; 5325 5326 case CMD_RBEST4: 5327 strncpy(t, "mode: ", BUFFER_SIZE(pbuffer, t)); 5328 t += strlen(t); 5329 switch (mb(0) & 0xF) 5330 { 5331 default: 5332 snprintf(t, BUFFER_SIZE(pbuffer, t), "0x%x", mb(0) & 0x7); 5333 break; 5334 5335 case 1: 5336 strncpy(t, "0D", BUFFER_SIZE(pbuffer, t)); 5337 break; 5338 5339 case 3: 5340 strncpy(t, "2D", BUFFER_SIZE(pbuffer, t)); 5341 break; 5342 5343 case 4: 5344 strncpy(t, "3D", BUFFER_SIZE(pbuffer, t)); 5345 break; 5346 } 5347 t += strlen(t); 5348 if (mb(0) & 0x10) 5349 strncpy(t, "-MANUAL, ", BUFFER_SIZE(pbuffer, t)); 5350 else 5351 strncpy(t, "-AUTO, ", BUFFER_SIZE(pbuffer, t)); 5352 t += strlen(t); 5353 5354 snprintf(t, BUFFER_SIZE(pbuffer, t), "satellites %02d %02d %02d %02d, PDOP %.2f, HDOP %.2f, VDOP %.2f, TDOP %.2f", 5355 mb(1), mb(2), mb(3), mb(4), 5356 getflt((unsigned char *)&mb(5)), 5357 getflt((unsigned char *)&mb(9)), 5358 getflt((unsigned char *)&mb(13)), 5359 getflt((unsigned char *)&mb(17))); 5360 5361 break; 5362 5363 case CMD_RVERSION: 5364 snprintf(t, BUFFER_SIZE(pbuffer, t), "%d.%d (%d/%d/%d)", 5365 mb(0)&0xff, mb(1)&0xff, 1900+(mb(4)&0xff), mb(2)&0xff, mb(3)&0xff); 5366 break; 5367 5368 case CMD_RRECVHEALTH: 5369 { 5370 static const char *msgs[] = 5371 { 5372 "Battery backup failed", 5373 "Signal processor error", 5374 "Alignment error, channel or chip 1", 5375 "Alignment error, channel or chip 2", 5376 "Antenna feed line fault", 5377 "Excessive ref freq. error", 5378 "<BIT 6>", 5379 "<BIT 7>" 5380 }; 5381 5382 int i, bits; 5383 5384 switch (mb(0) & 0xFF) 5385 { 5386 default: 5387 snprintf(t, BUFFER_SIZE(pbuffer, t), "illegal value 0x%02x", mb(0) & 0xFF); 5388 break; 5389 case 0x00: 5390 strncpy(t, "doing position fixes", BUFFER_SIZE(pbuffer, t)); 5391 break; 5392 case 0x01: 5393 strncpy(t, "no GPS time yet", BUFFER_SIZE(pbuffer, t)); 5394 break; 5395 case 0x03: 5396 strncpy(t, "PDOP too high", BUFFER_SIZE(pbuffer, t)); 5397 break; 5398 case 0x08: 5399 strncpy(t, "no usable satellites", BUFFER_SIZE(pbuffer, t)); 5400 break; 5401 case 0x09: 5402 strncpy(t, "only ONE usable satellite", BUFFER_SIZE(pbuffer, t)); 5403 break; 5404 case 0x0A: 5405 strncpy(t, "only TWO usable satellites", BUFFER_SIZE(pbuffer, t)); 5406 break; 5407 case 0x0B: 5408 strncpy(t, "only THREE usable satellites", BUFFER_SIZE(pbuffer, t)); 5409 break; 5410 case 0x0C: 5411 strncpy(t, "the chosen satellite is unusable", BUFFER_SIZE(pbuffer, t)); 5412 break; 5413 } 5414 5415 t += strlen(t); 5416 5417 bits = mb(1) & 0xFF; 5418 5419 for (i = 0; i < 8; i++) 5420 if (bits & (0x1<<i)) 5421 { 5422 snprintf(t, BUFFER_SIZE(pbuffer, t), ", %s", msgs[i]); 5423 t += strlen(t); 5424 } 5425 } 5426 break; 5427 5428 case CMD_RMESSAGE: 5429 mkreadable(t, (int)BUFFER_SIZE(pbuffer, t), (char *)&mb(0), (unsigned)(size - 2 - (&mb(0) - buffer)), 0); 5430 break; 5431 5432 case CMD_RMACHSTAT: 5433 { 5434 static const char *msgs[] = 5435 { 5436 "Synthesizer Fault", 5437 "Battery Powered Time Clock Fault", 5438 "A-to-D Converter Fault", 5439 "The almanac stored in the receiver is not complete and current", 5440 "<BIT 4>", 5441 "<BIT 5", 5442 "<BIT 6>", 5443 "<BIT 7>" 5444 }; 5445 5446 int i, bits; 5447 5448 snprintf(t, BUFFER_SIZE(pbuffer, t), "machine id 0x%02x", mb(0) & 0xFF); 5449 t += strlen(t); 5450 5451 bits = mb(1) & 0xFF; 5452 5453 for (i = 0; i < 8; i++) 5454 if (bits & (0x1<<i)) 5455 { 5456 snprintf(t, BUFFER_SIZE(pbuffer, t), ", %s", msgs[i]); 5457 t += strlen(t); 5458 } 5459 5460 snprintf(t, BUFFER_SIZE(pbuffer, t), ", Superpackets %ssupported", (mb(2) & 0xFF) ? "" :"un" ); 5461 } 5462 break; 5463 5464 case CMD_ROPERPARAM: 5465 snprintf(t, BUFFER_SIZE(pbuffer, t), "%2x %.1f %.1f %.1f %.1f", 5466 mb(0), getflt((unsigned char *)&mb(1)), getflt((unsigned char *)&mb(5)), 5467 getflt((unsigned char *)&mb(9)), getflt((unsigned char *)&mb(13))); 5468 break; 5469 5470 case CMD_RUTCPARAM: 5471 { 5472 float t0t = getflt((unsigned char *)&mb(14)); 5473 short wnt = getshort((unsigned char *)&mb(18)); 5474 short dtls = getshort((unsigned char *)&mb(12)); 5475 short wnlsf = getshort((unsigned char *)&mb(20)); 5476 short dn = getshort((unsigned char *)&mb(22)); 5477 short dtlsf = getshort((unsigned char *)&mb(24)); 5478 5479 if ((int)t0t != 0) 5480 { 5481 mk_utcinfo(t, wnt, wnlsf, dn, dtls, dtlsf, BUFFER_SIZE(pbuffer, t)); 5482 } 5483 else 5484 { 5485 strncpy(t, "<NO UTC DATA>", BUFFER_SIZE(pbuffer, t)); 5486 } 5487 } 5488 break; 5489 5490 case CMD_RSAT1BIAS: 5491 snprintf(t, BUFFER_SIZE(pbuffer, t), "%.1fm %.2fm/s at %.1fs", 5492 getflt(&mb(0)), getflt(&mb(4)), getflt(&mb(8))); 5493 break; 5494 5495 case CMD_RIOOPTIONS: 5496 { 5497 snprintf(t, BUFFER_SIZE(pbuffer, t), "%02x %02x %02x %02x", 5498 mb(0), mb(1), mb(2), mb(3)); 5499 if (mb(0) != TRIM_POS_OPT || 5500 mb(2) != TRIM_TIME_OPT) 5501 { 5502 (void)trimbletsip_setup(parse, "bad io options"); 5503 } 5504 } 5505 break; 5506 5507 case CMD_RSPOSXYZ: 5508 { 5509 double x = getflt((unsigned char *)&mb(0)); 5510 double y = getflt((unsigned char *)&mb(4)); 5511 double z = getflt((unsigned char *)&mb(8)); 5512 double f = getflt((unsigned char *)&mb(12)); 5513 5514 if (f > 0.0) 5515 snprintf(t, BUFFER_SIZE(pbuffer, t), "x= %.1fm, y= %.1fm, z= %.1fm, time_of_fix= %f sec", 5516 x, y, z, 5517 f); 5518 else 5519 return; 5520 } 5521 break; 5522 5523 case CMD_RSLLAPOS: 5524 { 5525 double lat = getflt((unsigned char *)&mb(0)); 5526 double lng = getflt((unsigned char *)&mb(4)); 5527 double f = getflt((unsigned char *)&mb(12)); 5528 5529 if (f > 0.0) 5530 snprintf(t, BUFFER_SIZE(pbuffer, t), "lat %f %c, long %f %c, alt %.2fm", 5531 ((lat < 0.0) ? (-lat) : (lat))*RTOD, (lat < 0.0 ? 'S' : 'N'), 5532 ((lng < 0.0) ? (-lng) : (lng))*RTOD, (lng < 0.0 ? 'W' : 'E'), 5533 getflt((unsigned char *)&mb(8))); 5534 else 5535 return; 5536 } 5537 break; 5538 5539 case CMD_RDOUBLEXYZ: 5540 { 5541 double x = getdbl((unsigned char *)&mb(0)); 5542 double y = getdbl((unsigned char *)&mb(8)); 5543 double z = getdbl((unsigned char *)&mb(16)); 5544 snprintf(t, BUFFER_SIZE(pbuffer, t), "x= %.1fm, y= %.1fm, z= %.1fm", 5545 x, y, z); 5546 } 5547 break; 5548 5549 case CMD_RDOUBLELLA: 5550 { 5551 double lat = getdbl((unsigned char *)&mb(0)); 5552 double lng = getdbl((unsigned char *)&mb(8)); 5553 snprintf(t, BUFFER_SIZE(pbuffer, t), "lat %f %c, lon %f %c, alt %.2fm", 5554 ((lat < 0.0) ? (-lat) : (lat))*RTOD, (lat < 0.0 ? 'S' : 'N'), 5555 ((lng < 0.0) ? (-lng) : (lng))*RTOD, (lng < 0.0 ? 'W' : 'E'), 5556 getdbl((unsigned char *)&mb(16))); 5557 } 5558 break; 5559 5560 case CMD_RALLINVIEW: 5561 { 5562 int i, sats; 5563 5564 strncpy(t, "mode: ", BUFFER_SIZE(pbuffer, t)); 5565 t += strlen(t); 5566 switch (mb(0) & 0x7) 5567 { 5568 default: 5569 snprintf(t, BUFFER_SIZE(pbuffer, t), "0x%x", mb(0) & 0x7); 5570 break; 5571 5572 case 3: 5573 strncpy(t, "2D", BUFFER_SIZE(pbuffer, t)); 5574 break; 5575 5576 case 4: 5577 strncpy(t, "3D", BUFFER_SIZE(pbuffer, t)); 5578 break; 5579 } 5580 t += strlen(t); 5581 if (mb(0) & 0x8) 5582 strncpy(t, "-MANUAL, ", BUFFER_SIZE(pbuffer, t)); 5583 else 5584 strncpy(t, "-AUTO, ", BUFFER_SIZE(pbuffer, t)); 5585 t += strlen(t); 5586 5587 sats = (mb(0)>>4) & 0xF; 5588 5589 snprintf(t, BUFFER_SIZE(pbuffer, t), "PDOP %.2f, HDOP %.2f, VDOP %.2f, TDOP %.2f, %d satellite%s in view: ", 5590 getflt((unsigned char *)&mb(1)), 5591 getflt((unsigned char *)&mb(5)), 5592 getflt((unsigned char *)&mb(9)), 5593 getflt((unsigned char *)&mb(13)), 5594 sats, (sats == 1) ? "" : "s"); 5595 t += strlen(t); 5596 5597 for (i=0; i < sats; i++) 5598 { 5599 snprintf(t, BUFFER_SIZE(pbuffer, t), "%s%02d", i ? ", " : "", mb(17+i)); 5600 t += strlen(t); 5601 if (tr) 5602 tr->ctrack |= (1 << (mb(17+i)-1)); 5603 } 5604 5605 if (tr) 5606 { /* mark for tracking status query */ 5607 tr->qtracking = 1; 5608 } 5609 } 5610 break; 5611 5612 case CMD_RSTATTRACK: 5613 { 5614 snprintf(t-2, BUFFER_SIZE(pbuffer, t-2), "[%02d]=\"", mb(0)); /* add index to var name */ 5615 t += strlen(t); 5616 5617 if (getflt((unsigned char *)&mb(4)) < 0.0) 5618 { 5619 strncpy(t, "<NO MEASUREMENTS>", BUFFER_SIZE(pbuffer, t)); 5620 var_flag &= ~DEF; 5621 } 5622 else 5623 { 5624 snprintf(t, BUFFER_SIZE(pbuffer, t), "ch=%d, acq=%s, eph=%d, signal_level= %5.2f, elevation= %5.2f, azimuth= %6.2f", 5625 (mb(1) & 0xFF)>>3, 5626 mb(2) ? ((mb(2) == 1) ? "ACQ" : "SRCH") : "NEVER", 5627 mb(3), 5628 getflt((unsigned char *)&mb(4)), 5629 getflt((unsigned char *)&mb(12)) * RTOD, 5630 getflt((unsigned char *)&mb(16)) * RTOD); 5631 t += strlen(t); 5632 if (mb(20)) 5633 { 5634 var_flag &= ~DEF; 5635 strncpy(t, ", OLD", BUFFER_SIZE(pbuffer, t)); 5636 } 5637 t += strlen(t); 5638 if (mb(22)) 5639 { 5640 if (mb(22) == 1) 5641 strncpy(t, ", BAD PARITY", BUFFER_SIZE(pbuffer, t)); 5642 else 5643 if (mb(22) == 2) 5644 strncpy(t, ", BAD EPH HEALTH", BUFFER_SIZE(pbuffer, t)); 5645 } 5646 t += strlen(t); 5647 if (mb(23)) 5648 strncpy(t, ", collecting data", BUFFER_SIZE(pbuffer, t)); 5649 } 5650 } 5651 break; 5652 5653 default: 5654 strncpy(t, "<UNDECODED>", BUFFER_SIZE(pbuffer, t)); 5655 break; 5656 } 5657 t += strlen(t); 5658 5659 strncpy(t,"\"", BUFFER_SIZE(pbuffer, t)); 5660 set_var(&parse->kv, pbuffer, sizeof(pbuffer), var_flag); 5661 } 5662 } 5663 5664 5665 /**============================================================ 5666 ** RAWDCF support 5667 **/ 5668 5669 /*-------------------------------------------------- 5670 * rawdcf_init_1 - set up modem lines for RAWDCF receivers 5671 * SET DTR line 5672 */ 5673 #if defined(TIOCMSET) && (defined(TIOCM_DTR) || defined(CIOCM_DTR)) 5674 static int 5675 rawdcf_init_1( 5676 struct parseunit *parse 5677 ) 5678 { 5679 /* fixed 2000 for using with Linux by Wolfram Pienkoss <wp@bszh.de> */ 5680 /* 5681 * You can use the RS232 to supply the power for a DCF77 receiver. 5682 * Here a voltage between the DTR and the RTS line is used. Unfortunately 5683 * the name has changed from CIOCM_DTR to TIOCM_DTR recently. 5684 */ 5685 int sl232; 5686 5687 if (ioctl(parse->generic->io.fd, TIOCMGET, (caddr_t)&sl232) == -1) 5688 { 5689 msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_1: WARNING: ioctl(fd, TIOCMGET, [C|T]IOCM_DTR): %m", CLK_UNIT(parse->peer)); 5690 return 0; 5691 } 5692 5693 #ifdef TIOCM_DTR 5694 sl232 = (sl232 & ~TIOCM_RTS) | TIOCM_DTR; /* turn on DTR, clear RTS for power supply */ 5695 #else 5696 sl232 = (sl232 & ~CIOCM_RTS) | CIOCM_DTR; /* turn on DTR, clear RTS for power supply */ 5697 #endif 5698 5699 if (ioctl(parse->generic->io.fd, TIOCMSET, (caddr_t)&sl232) == -1) 5700 { 5701 msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_1: WARNING: ioctl(fd, TIOCMSET, [C|T]IOCM_DTR): %m", CLK_UNIT(parse->peer)); 5702 } 5703 return 0; 5704 } 5705 #else 5706 static int 5707 rawdcfdtr_init_1( 5708 struct parseunit *parse 5709 ) 5710 { 5711 msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_1: WARNING: OS interface incapable of setting DTR to power DCF modules", CLK_UNIT(parse->peer)); 5712 return 0; 5713 } 5714 #endif /* DTR initialisation type */ 5715 5716 /*-------------------------------------------------- 5717 * rawdcf_init_2 - set up modem lines for RAWDCF receivers 5718 * CLR DTR line, SET RTS line 5719 */ 5720 #if defined(TIOCMSET) && (defined(TIOCM_RTS) || defined(CIOCM_RTS)) 5721 static int 5722 rawdcf_init_2( 5723 struct parseunit *parse 5724 ) 5725 { 5726 /* fixed 2000 for using with Linux by Wolfram Pienkoss <wp@bszh.de> */ 5727 /* 5728 * You can use the RS232 to supply the power for a DCF77 receiver. 5729 * Here a voltage between the DTR and the RTS line is used. Unfortunately 5730 * the name has changed from CIOCM_DTR to TIOCM_DTR recently. 5731 */ 5732 int sl232; 5733 5734 if (ioctl(parse->generic->io.fd, TIOCMGET, (caddr_t)&sl232) == -1) 5735 { 5736 msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_2: WARNING: ioctl(fd, TIOCMGET, [C|T]IOCM_RTS): %m", CLK_UNIT(parse->peer)); 5737 return 0; 5738 } 5739 5740 #ifdef TIOCM_RTS 5741 sl232 = (sl232 & ~TIOCM_DTR) | TIOCM_RTS; /* turn on RTS, clear DTR for power supply */ 5742 #else 5743 sl232 = (sl232 & ~CIOCM_DTR) | CIOCM_RTS; /* turn on RTS, clear DTR for power supply */ 5744 #endif 5745 5746 if (ioctl(parse->generic->io.fd, TIOCMSET, (caddr_t)&sl232) == -1) 5747 { 5748 msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_2: WARNING: ioctl(fd, TIOCMSET, [C|T]IOCM_RTS): %m", CLK_UNIT(parse->peer)); 5749 } 5750 return 0; 5751 } 5752 #else 5753 static int 5754 rawdcf_init_2( 5755 struct parseunit *parse 5756 ) 5757 { 5758 msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_2: WARNING: OS interface incapable of setting RTS to power DCF modules", CLK_UNIT(parse->peer)); 5759 return 0; 5760 } 5761 #endif /* DTR initialisation type */ 5762 5763 #else /* defined(REFCLOCK) && defined(PARSE) */ 5764 int refclock_parse_bs; 5765 #endif /* defined(REFCLOCK) && defined(PARSE) */ 5766 5767 /* 5768 * History: 5769 * 5770 * refclock_parse.c,v 5771 * Revision 4.81 2009/05/01 10:15:29 kardel 5772 * use new refclock_ppsapi interface 5773 * 5774 * Revision 4.80 2007/08/11 12:06:29 kardel 5775 * update comments wrt/ to PPS 5776 * 5777 * Revision 4.79 2007/08/11 11:52:23 kardel 5778 * - terminate io bindings before io_closeclock() will close our file descriptor 5779 * 5780 * Revision 4.78 2006/12/22 20:08:27 kardel 5781 * Bug 746 (RFE): add configuration for Expert mouseCLOCK USB v2.0 as mode 19 5782 * 5783 * Revision 4.77 2006/08/05 07:44:49 kardel 5784 * support optionally separate PPS devices via /dev/refclockpps-{0..3} 5785 * 5786 * Revision 4.76 2006/06/22 18:40:47 kardel 5787 * clean up signedness (gcc 4) 5788 * 5789 * Revision 4.75 2006/06/22 16:58:10 kardel 5790 * Bug #632: call parse_ppsapi() in parse_ctl() when updating 5791 * the PPS offset. Fix sign of offset passed to kernel. 5792 * 5793 * Revision 4.74 2006/06/18 21:18:37 kardel 5794 * NetBSD Coverity CID 3796: possible NULL deref 5795 * 5796 * Revision 4.73 2006/05/26 14:23:46 kardel 5797 * cleanup of copyright info 5798 * 5799 * Revision 4.72 2006/05/26 14:19:43 kardel 5800 * cleanup of ioctl cruft 5801 * 5802 * Revision 4.71 2006/05/26 14:15:57 kardel 5803 * delay adding refclock to async refclock io after all initializations 5804 * 5805 * Revision 4.70 2006/05/25 18:20:50 kardel 5806 * bug #619 5807 * terminate parse io engine after de-registering 5808 * from refclock io engine 5809 * 5810 * Revision 4.69 2006/05/25 17:28:02 kardel 5811 * complete refclock io structure initialization *before* inserting it into the 5812 * refclock input machine (avoids null pointer deref) (bug #619) 5813 * 5814 * Revision 4.68 2006/05/01 17:02:51 kardel 5815 * copy receiver method also for newlwy created receive buffers 5816 * 5817 * Revision 4.67 2006/05/01 14:37:29 kardel 5818 * If an input buffer parses into more than one message do insert the 5819 * parsed message in a new input buffer instead of processing it 5820 * directly. This avoids deed complicated processing in signal 5821 * handling. 5822 * 5823 * Revision 4.66 2006/03/18 00:45:30 kardel 5824 * coverity fixes found in NetBSD coverity scan 5825 * 5826 * Revision 4.65 2006/01/26 06:08:33 kardel 5827 * output errno on PPS setup failure 5828 * 5829 * Revision 4.64 2005/11/09 20:44:47 kardel 5830 * utilize full PPS timestamp resolution from PPS API 5831 * 5832 * Revision 4.63 2005/10/07 22:10:25 kardel 5833 * bounded buffer implementation 5834 * 5835 * Revision 4.62.2.2 2005/09/25 10:20:16 kardel 5836 * avoid unexpected buffer overflows due to sprintf("%f") on strange floats: 5837 * replace almost all str* and *printf functions be their buffer bounded 5838 * counterparts 5839 * 5840 * Revision 4.62.2.1 2005/08/27 16:19:27 kardel 5841 * limit re-set rate of trimble clocks 5842 * 5843 * Revision 4.62 2005/08/06 17:40:00 kardel 5844 * cleanup size handling wrt/ to buffer boundaries 5845 * 5846 * Revision 4.61 2005/07/27 21:16:19 kardel 5847 * fix a long (> 11 years) misconfiguration wrt/ Meinberg cflag factory 5848 * default setup. CSTOPB was missing for the 7E2 default data format of 5849 * the DCF77 clocks. 5850 * 5851 * Revision 4.60 2005/07/17 21:14:44 kardel 5852 * change contents of version string to include the RCS/CVS Id 5853 * 5854 * Revision 4.59 2005/07/06 06:56:38 kardel 5855 * syntax error 5856 * 5857 * Revision 4.58 2005/07/04 13:10:40 kardel 5858 * fix bug 455: tripping over NULL pointer on cleanup 5859 * fix shadow storage logic for ppsphaseadjust and trustime wrt/ time2 5860 * fix compiler warnings for some platforms wrt/ printf formatstrings and 5861 * varying structure element sizes 5862 * reorder assignment in binding to avoid tripping over NULL pointers 5863 * 5864 * Revision 4.57 2005/06/25 09:25:19 kardel 5865 * sort out log output sequence 5866 * 5867 * Revision 4.56 2005/06/14 21:47:27 kardel 5868 * collect samples only if samples are ok (sync or trusted flywheel) 5869 * propagate pps phase adjustment value to kernel via PPSAPI to help HARDPPS 5870 * en- and dis-able HARDPPS in correlation to receiver sync state 5871 * 5872 * Revision 4.55 2005/06/02 21:28:31 kardel 5873 * clarify trust logic 5874 * 5875 * Revision 4.54 2005/06/02 17:06:49 kardel 5876 * change status reporting to use fixed refclock_report() 5877 * 5878 * Revision 4.53 2005/06/02 16:33:31 kardel 5879 * fix acceptance of clocks unsync clocks right at start 5880 * 5881 * Revision 4.52 2005/05/26 21:55:06 kardel 5882 * cleanup status reporting 5883 * 5884 * Revision 4.51 2005/05/26 19:19:14 kardel 5885 * implement fast refclock startup 5886 * 5887 * Revision 4.50 2005/04/16 20:51:35 kardel 5888 * set pps_enable = 1 when binding a kernel PPS source 5889 * 5890 * Revision 4.49 2005/04/16 17:29:26 kardel 5891 * add non polling clock type 18 for just listenning to Meinberg clocks 5892 * 5893 * Revision 4.48 2005/04/16 16:22:27 kardel 5894 * bk sync 20050415 ntp-dev 5895 * 5896 * Revision 4.47 2004/11/29 10:42:48 kardel 5897 * bk sync ntp-dev 20041129 5898 * 5899 * Revision 4.46 2004/11/29 10:26:29 kardel 5900 * keep fudgetime2 in sync with trusttime/ppsphaseadjust depending in flag1 5901 * 5902 * Revision 4.45 2004/11/14 20:53:20 kardel 5903 * clear PPS flags after using them 5904 * 5905 * Revision 4.44 2004/11/14 15:29:41 kardel 5906 * support PPSAPI, upgrade Copyright to Berkeley style 5907 * 5908 * Revision 4.43 2001/05/26 22:53:16 kardel 5909 * 20010526 reconcilation 5910 * 5911 * Revision 4.42 2000/05/14 15:31:51 kardel 5912 * PPSAPI && RAWDCF modemline support 5913 * 5914 * Revision 4.41 2000/04/09 19:50:45 kardel 5915 * fixed rawdcfdtr_init() -> rawdcf_init_1 5916 * 5917 * Revision 4.40 2000/04/09 15:27:55 kardel 5918 * modem line fiddle in rawdcf_init_2 5919 * 5920 * Revision 4.39 2000/03/18 09:16:55 kardel 5921 * PPSAPI integration 5922 * 5923 * Revision 4.38 2000/03/05 20:25:06 kardel 5924 * support PPSAPI 5925 * 5926 * Revision 4.37 2000/03/05 20:11:14 kardel 5927 * 4.0.99g reconcilation 5928 * 5929 * Revision 4.36 1999/11/28 17:18:20 kardel 5930 * disabled burst mode 5931 * 5932 * Revision 4.35 1999/11/28 09:14:14 kardel 5933 * RECON_4_0_98F 5934 * 5935 * Revision 4.34 1999/05/14 06:08:05 kardel 5936 * store current_time in a suitable container (u_long) 5937 * 5938 * Revision 4.33 1999/05/13 21:48:38 kardel 5939 * double the no response timeout interval 5940 * 5941 * Revision 4.32 1999/05/13 20:09:13 kardel 5942 * complain only about missing polls after a full poll interval 5943 * 5944 * Revision 4.31 1999/05/13 19:59:32 kardel 5945 * add clock type 16 for RTS set DTR clr in RAWDCF 5946 * 5947 * Revision 4.30 1999/02/28 20:36:43 kardel 5948 * fixed printf fmt 5949 * 5950 * Revision 4.29 1999/02/28 19:58:23 kardel 5951 * updated copyright information 5952 * 5953 * Revision 4.28 1999/02/28 19:01:50 kardel 5954 * improved debug out on sent Meinberg messages 5955 * 5956 * Revision 4.27 1999/02/28 18:05:55 kardel 5957 * no linux/ppsclock.h stuff 5958 * 5959 * Revision 4.26 1999/02/28 15:27:27 kardel 5960 * wharton clock integration 5961 * 5962 * Revision 4.25 1999/02/28 14:04:46 kardel 5963 * added missing double quotes to UTC information string 5964 * 5965 * Revision 4.24 1999/02/28 12:06:50 kardel 5966 * (parse_control): using gmprettydate instead of prettydate() 5967 * (mk_utcinfo): new function for formatting GPS derived UTC information 5968 * (gps16x_message): changed to use mk_utcinfo() 5969 * (trimbletsip_message): changed to use mk_utcinfo() 5970 * ignoring position information in unsynchronized mode 5971 * (parse_start): augument linux support for optional ASYNC_LOW_LATENCY 5972 * 5973 * Revision 4.23 1999/02/23 19:47:53 kardel 5974 * fixed #endifs 5975 * (stream_receive): fixed formats 5976 * 5977 * Revision 4.22 1999/02/22 06:21:02 kardel 5978 * use new autoconfig symbols 5979 * 5980 * Revision 4.21 1999/02/21 12:18:13 kardel 5981 * 4.91f reconcilation 5982 * 5983 * Revision 4.20 1999/02/21 10:53:36 kardel 5984 * initial Linux PPSkit version 5985 * 5986 * Revision 4.19 1999/02/07 09:10:45 kardel 5987 * clarify STREAMS mitigation rules in comment 5988 * 5989 * Revision 4.18 1998/12/20 23:45:34 kardel 5990 * fix types and warnings 5991 * 5992 * Revision 4.17 1998/11/15 21:24:51 kardel 5993 * cannot access mbg_ routines when CLOCK_MEINBERG 5994 * is not defined 5995 * 5996 * Revision 4.16 1998/11/15 20:28:17 kardel 5997 * Release 4.0.73e13 reconcilation 5998 * 5999 * Revision 4.15 1998/08/22 21:56:08 kardel 6000 * fixed IO handling for non-STREAM IO 6001 * 6002 * Revision 4.14 1998/08/16 19:00:48 kardel 6003 * (gps16x_message): reduced UTC parameter information (dropped A0,A1) 6004 * made uval a local variable (killed one of the last globals) 6005 * (sendetx): added logging of messages when in debug mode 6006 * (trimble_check): added periodic checks to facilitate re-initialization 6007 * (trimbletsip_init): made use of EOL character if in non-kernel operation 6008 * (trimbletsip_message): extended message interpretation 6009 * (getdbl): fixed data conversion 6010 * 6011 * Revision 4.13 1998/08/09 22:29:13 kardel 6012 * Trimble TSIP support 6013 * 6014 * Revision 4.12 1998/07/11 10:05:34 kardel 6015 * Release 4.0.73d reconcilation 6016 * 6017 * Revision 4.11 1998/06/14 21:09:42 kardel 6018 * Sun acc cleanup 6019 * 6020 * Revision 4.10 1998/06/13 12:36:45 kardel 6021 * signed/unsigned, name clashes 6022 * 6023 * Revision 4.9 1998/06/12 15:30:00 kardel 6024 * prototype fixes 6025 * 6026 * Revision 4.8 1998/06/12 11:19:42 kardel 6027 * added direct input processing routine for refclocks in 6028 * order to avaiod that single character io gobbles up all 6029 * receive buffers and drops input data. (Problem started 6030 * with fast machines so a character a buffer was possible 6031 * one of the few cases where faster machines break existing 6032 * allocation algorithms) 6033 * 6034 * Revision 4.7 1998/06/06 18:35:20 kardel 6035 * (parse_start): added BURST mode initialisation 6036 * 6037 * Revision 4.6 1998/05/27 06:12:46 kardel 6038 * RAWDCF_BASEDELAY default added 6039 * old comment removed 6040 * casts for ioctl() 6041 * 6042 * Revision 4.5 1998/05/25 22:05:09 kardel 6043 * RAWDCF_SETDTR option removed 6044 * clock type 14 attempts to set DTR for 6045 * power supply of RAWDCF receivers 6046 * 6047 * Revision 4.4 1998/05/24 16:20:47 kardel 6048 * updated comments referencing Meinberg clocks 6049 * added RAWDCF clock with DTR set option as type 14 6050 * 6051 * Revision 4.3 1998/05/24 10:48:33 kardel 6052 * calibrated CONRAD RAWDCF default fudge factor 6053 * 6054 * Revision 4.2 1998/05/24 09:59:35 kardel 6055 * corrected version information (ntpq support) 6056 * 6057 * Revision 4.1 1998/05/24 09:52:31 kardel 6058 * use fixed format only (new IO model) 6059 * output debug to stdout instead of msyslog() 6060 * don't include >"< in ASCII output in order not to confuse 6061 * ntpq parsing 6062 * 6063 * Revision 4.0 1998/04/10 19:52:11 kardel 6064 * Start 4.0 release version numbering 6065 * 6066 * Revision 1.2 1998/04/10 19:28:04 kardel 6067 * initial NTP VERSION 4 integration of PARSE with GPS166 binary support 6068 * derived from 3.105.1.2 from V3 tree 6069 * 6070 * Revision information 3.1 - 3.105 from log deleted 1998/04/10 kardel 6071 * 6072 */ 6073