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