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