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