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