refclock_parse.c revision 56746
154359Sroberto/* 256746Sroberto * /src/NTP/ntp-4/ntpd/refclock_parse.c,v 4.36 1999/11/28 17:18:20 kardel RELEASE_19991128_A 354359Sroberto * 456746Sroberto * refclock_parse.c,v 4.36 1999/11/28 17:18:20 kardel RELEASE_19991128_A 554359Sroberto * 654359Sroberto * generic reference clock driver for receivers 754359Sroberto * 854359Sroberto * optionally make use of a STREAMS module for input processing where 954359Sroberto * available and configured. Currently the STREAMS module 1054359Sroberto * is only available for Suns running SunOS 4.x and SunOS5.x 1154359Sroberto * 1254359Sroberto * the STREAMS module is not required for operation and may be omitted 1354359Sroberto * at the cost of reduced accuracy. As new kernel interfaces emerger this 1454359Sroberto * restriction may be lifted in future. 1554359Sroberto * 1654359Sroberto * Copyright (c) 1995-1999 by Frank Kardel <kardel@acm.org> 1754359Sroberto * Copyright (c) 1989-1994 by Frank Kardel, Friedrich-Alexander Universit�t Erlangen-N�rnberg, Germany 1854359Sroberto * 1954359Sroberto * This software may not be sold for profit without a written consent 2054359Sroberto * from the author. 2154359Sroberto * 2254359Sroberto * This program is distributed in the hope that it will be useful, 2354359Sroberto * but WITHOUT ANY WARRANTY; without even the implied warranty of 2454359Sroberto * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 2554359Sroberto * 2654359Sroberto */ 2754359Sroberto 2854359Sroberto#ifdef HAVE_CONFIG_H 2954359Sroberto# include <config.h> 3054359Sroberto#endif 3154359Sroberto 3254359Sroberto#if defined(REFCLOCK) && defined(CLOCK_PARSE) 3354359Sroberto 3454359Sroberto/* 3554359Sroberto * This driver currently provides the support for 3654359Sroberto * - Meinberg receiver DCF77 PZF 535 (TCXO version) (DCF) 3754359Sroberto * - Meinberg receiver DCF77 PZF 535 (OCXO version) (DCF) 3854359Sroberto * - Meinberg receiver DCF77 PZF 509 (DCF) 3954359Sroberto * - Meinberg receiver DCF77 AM receivers (e.g. C51) (DCF) 4054359Sroberto * - IGEL CLOCK (DCF) 4154359Sroberto * - ELV DCF7000 (DCF) 4254359Sroberto * - Schmid clock (DCF) 4354359Sroberto * - Conrad DCF77 receiver module (DCF) 4454359Sroberto * - FAU DCF77 NTP receiver (TimeBrick) (DCF) 4554359Sroberto * 4654359Sroberto * - Meinberg GPS166/GPS167 (GPS) 4754359Sroberto * - Trimble (TSIP and TAIP protocol) (GPS) 4854359Sroberto * 4954359Sroberto * - RCC8000 MSF Receiver (MSF) 5054359Sroberto * - WHARTON 400A Series clock (DCF) 5154359Sroberto * - VARITEXT clock (MSF) 5254359Sroberto */ 5354359Sroberto 5454359Sroberto/* 5554359Sroberto * Meinberg receivers are usually connected via a 5654359Sroberto * 9600 baud serial line 5754359Sroberto * 5854359Sroberto * The Meinberg GPS receivers also have a special NTP time stamp 5954359Sroberto * format. The firmware release is Uni-Erlangen. 6054359Sroberto * 6154359Sroberto * Meinberg generic receiver setup: 6254359Sroberto * output time code every second 6354359Sroberto * Baud rate 9600 7E2S 6454359Sroberto * 6554359Sroberto * Meinberg GPS16x setup: 6654359Sroberto * output time code every second 6754359Sroberto * Baudrate 19200 8N1 6854359Sroberto * 6954359Sroberto * This software supports the standard data formats used 7054359Sroberto * in Meinberg receivers. 7154359Sroberto * 7254359Sroberto * Special software versions are only sensible for the 7354359Sroberto * GPS 16x family of receivers. 7454359Sroberto * 7554359Sroberto * Meinberg can be reached via: http://www.meinberg.de/ 7654359Sroberto */ 7754359Sroberto 7854359Sroberto#include "ntpd.h" 7954359Sroberto#include "ntp_refclock.h" 8054359Sroberto#include "ntp_unixtime.h" /* includes <sys/time.h> */ 8154359Sroberto#include "ntp_control.h" 8254359Sroberto 8354359Sroberto#include <stdio.h> 8454359Sroberto#include <ctype.h> 8554359Sroberto#ifndef TM_IN_SYS_TIME 8654359Sroberto# include <time.h> 8754359Sroberto#endif 8854359Sroberto 8954359Sroberto#if !defined(STREAM) && !defined(HAVE_SYSV_TTYS) && !defined(HAVE_BSD_TTYS) && !defined(HAVE_TERMIOS) 9054359Sroberto# include "Bletch: Define one of {STREAM,HAVE_SYSV_TTYS,HAVE_TERMIOS}" 9154359Sroberto#endif 9254359Sroberto 9354359Sroberto#ifdef STREAM 9454359Sroberto# include <sys/stream.h> 9554359Sroberto# include <sys/stropts.h> 9654359Sroberto#endif 9754359Sroberto 9854359Sroberto#ifdef HAVE_TERMIOS 9954359Sroberto# define TTY_GETATTR(_FD_, _ARG_) tcgetattr((_FD_), (_ARG_)) 10054359Sroberto# define TTY_SETATTR(_FD_, _ARG_) tcsetattr((_FD_), TCSANOW, (_ARG_)) 10154359Sroberto# undef HAVE_SYSV_TTYS 10254359Sroberto#endif 10354359Sroberto 10454359Sroberto#ifdef HAVE_SYSV_TTYS 10554359Sroberto# define TTY_GETATTR(_FD_, _ARG_) ioctl((_FD_), TCGETA, (_ARG_)) 10654359Sroberto# define TTY_SETATTR(_FD_, _ARG_) ioctl((_FD_), TCSETAW, (_ARG_)) 10754359Sroberto#endif 10854359Sroberto 10954359Sroberto#ifdef HAVE_BSD_TTYS 11054359Sroberto/* #error CURRENTLY NO BSD TTY SUPPORT */ 11154359Sroberto# include "Bletch: BSD TTY not currently supported" 11254359Sroberto#endif 11354359Sroberto 11454359Sroberto#ifdef HAVE_SYS_IOCTL_H 11554359Sroberto# include <sys/ioctl.h> 11654359Sroberto#endif 11754359Sroberto 11854359Sroberto#ifdef PPS 11954359Sroberto#ifdef HAVE_SYS_PPSCLOCK_H 12054359Sroberto#include <sys/ppsclock.h> 12154359Sroberto#endif 12254359Sroberto#ifdef HAVE_TIO_SERIAL_STUFF 12354359Sroberto#include <linux/serial.h> 12454359Sroberto#endif 12554359Sroberto#endif 12654359Sroberto 12754359Sroberto#include "ntp_io.h" 12854359Sroberto#include "ntp_stdlib.h" 12954359Sroberto 13054359Sroberto#include "parse.h" 13154359Sroberto#include "mbg_gps166.h" 13254359Sroberto#include "trimble.h" 13354359Sroberto#include "binio.h" 13454359Sroberto#include "ascii.h" 13554359Sroberto#include "ieee754io.h" 13654359Sroberto 13756746Srobertostatic char rcsid[]="refclock_parse.c,v 4.36 1999/11/28 17:18:20 kardel RELEASE_19991128_A"; 13854359Sroberto 13954359Sroberto/**=========================================================================== 14054359Sroberto ** external interface to ntp mechanism 14154359Sroberto **/ 14254359Sroberto 14354359Srobertostatic void parse_init P((void)); 14454359Srobertostatic int parse_start P((int, struct peer *)); 14554359Srobertostatic void parse_shutdown P((int, struct peer *)); 14654359Srobertostatic void parse_poll P((int, struct peer *)); 14754359Srobertostatic void parse_control P((int, struct refclockstat *, struct refclockstat *, struct peer *)); 14854359Sroberto 14954359Sroberto#define parse_buginfo noentry 15054359Sroberto 15154359Srobertostruct refclock refclock_parse = { 15254359Sroberto parse_start, 15354359Sroberto parse_shutdown, 15454359Sroberto parse_poll, 15554359Sroberto parse_control, 15654359Sroberto parse_init, 15754359Sroberto parse_buginfo, 15854359Sroberto NOFLAGS 15954359Sroberto}; 16054359Sroberto 16154359Sroberto/* 16254359Sroberto * Definitions 16354359Sroberto */ 16454359Sroberto#define MAXUNITS 4 /* maximum number of "PARSE" units permitted */ 16554359Sroberto#define PARSEDEVICE "/dev/refclock-%d" /* device to open %d is unit number */ 16654359Sroberto 16754359Sroberto#undef ABS 16854359Sroberto#define ABS(_X_) (((_X_) < 0) ? -(_X_) : (_X_)) 16954359Sroberto 17054359Sroberto/**=========================================================================== 17154359Sroberto ** function vector for dynamically binding io handling mechanism 17254359Sroberto **/ 17354359Sroberto 17454359Srobertostruct parseunit; /* to keep inquiring minds happy */ 17554359Sroberto 17654359Srobertotypedef struct bind 17754359Sroberto{ 17854359Sroberto const char *bd_description; /* name of type of binding */ 17954359Sroberto int (*bd_init) P((struct parseunit *)); /* initialize */ 18054359Sroberto void (*bd_end) P((struct parseunit *)); /* end */ 18154359Sroberto int (*bd_setcs) P((struct parseunit *, parsectl_t *)); /* set character size */ 18254359Sroberto int (*bd_disable) P((struct parseunit *)); /* disable */ 18354359Sroberto int (*bd_enable) P((struct parseunit *)); /* enable */ 18454359Sroberto int (*bd_getfmt) P((struct parseunit *, parsectl_t *)); /* get format */ 18554359Sroberto int (*bd_setfmt) P((struct parseunit *, parsectl_t *)); /* setfmt */ 18654359Sroberto int (*bd_timecode) P((struct parseunit *, parsectl_t *)); /* get time code */ 18754359Sroberto void (*bd_receive) P((struct recvbuf *)); /* receive operation */ 18854359Sroberto int (*bd_io_input) P((struct recvbuf *)); /* input operation */ 18954359Sroberto} bind_t; 19054359Sroberto 19154359Sroberto#define PARSE_END(_X_) (*(_X_)->binding->bd_end)(_X_) 19254359Sroberto#define PARSE_SETCS(_X_, _CS_) (*(_X_)->binding->bd_setcs)(_X_, _CS_) 19354359Sroberto#define PARSE_ENABLE(_X_) (*(_X_)->binding->bd_enable)(_X_) 19454359Sroberto#define PARSE_DISABLE(_X_) (*(_X_)->binding->bd_disable)(_X_) 19554359Sroberto#define PARSE_GETFMT(_X_, _DCT_) (*(_X_)->binding->bd_getfmt)(_X_, _DCT_) 19654359Sroberto#define PARSE_SETFMT(_X_, _DCT_) (*(_X_)->binding->bd_setfmt)(_X_, _DCT_) 19754359Sroberto#define PARSE_GETTIMECODE(_X_, _DCT_) (*(_X_)->binding->bd_timecode)(_X_, _DCT_) 19854359Sroberto 19954359Sroberto/* 20054359Sroberto * io modes 20154359Sroberto */ 20254359Sroberto#define PARSE_F_PPSPPS 0x0001 /* use loopfilter PPS code (CIOGETEV) */ 20354359Sroberto#define PARSE_F_PPSONSECOND 0x0002 /* PPS pulses are on second */ 20454359Sroberto 20554359Sroberto 20654359Sroberto/**=========================================================================== 20754359Sroberto ** error message regression handling 20854359Sroberto ** 20954359Sroberto ** there are quite a few errors that can occur in rapid succession such as 21054359Sroberto ** noisy input data or no data at all. in order to reduce the amount of 21154359Sroberto ** syslog messages in such case, we are using a backoff algorithm. We limit 21254359Sroberto ** the number of error messages of a certain class to 1 per time unit. if a 21354359Sroberto ** configurable number of messages is displayed that way, we move on to the 21454359Sroberto ** next time unit / count for that class. a count of messages that have been 21554359Sroberto ** suppressed is held and displayed whenever a corresponding message is 21654359Sroberto ** displayed. the time units for a message class will also be displayed. 21754359Sroberto ** whenever an error condition clears we reset the error message state, 21854359Sroberto ** thus we would still generate much output on pathological conditions 21954359Sroberto ** where the system oscillates between OK and NOT OK states. coping 22054359Sroberto ** with that condition is currently considered too complicated. 22154359Sroberto **/ 22254359Sroberto 22354359Sroberto#define ERR_ALL (unsigned)~0 /* "all" errors */ 22454359Sroberto#define ERR_BADDATA (unsigned)0 /* unusable input data/conversion errors */ 22554359Sroberto#define ERR_NODATA (unsigned)1 /* no input data */ 22654359Sroberto#define ERR_BADIO (unsigned)2 /* read/write/select errors */ 22754359Sroberto#define ERR_BADSTATUS (unsigned)3 /* unsync states */ 22854359Sroberto#define ERR_BADEVENT (unsigned)4 /* non nominal events */ 22954359Sroberto#define ERR_INTERNAL (unsigned)5 /* internal error */ 23054359Sroberto#define ERR_CNT (unsigned)(ERR_INTERNAL+1) 23154359Sroberto 23254359Sroberto#define ERR(_X_) if (list_err(parse, (_X_))) 23354359Sroberto 23454359Srobertostruct errorregression 23554359Sroberto{ 23654359Sroberto u_long err_count; /* number of repititions per class */ 23754359Sroberto u_long err_delay; /* minimum delay between messages */ 23854359Sroberto}; 23954359Sroberto 24054359Srobertostatic struct errorregression 24154359Srobertoerr_baddata[] = /* error messages for bad input data */ 24254359Sroberto{ 24354359Sroberto { 1, 0 }, /* output first message immediately */ 24454359Sroberto { 5, 60 }, /* output next five messages in 60 second intervals */ 24554359Sroberto { 3, 3600 }, /* output next 3 messages in hour intervals */ 24654359Sroberto { 0, 12*3600 } /* repeat messages only every 12 hours */ 24754359Sroberto}; 24854359Sroberto 24954359Srobertostatic struct errorregression 25054359Srobertoerr_nodata[] = /* error messages for missing input data */ 25154359Sroberto{ 25254359Sroberto { 1, 0 }, /* output first message immediately */ 25354359Sroberto { 5, 60 }, /* output next five messages in 60 second intervals */ 25454359Sroberto { 3, 3600 }, /* output next 3 messages in hour intervals */ 25554359Sroberto { 0, 12*3600 } /* repeat messages only every 12 hours */ 25654359Sroberto}; 25754359Sroberto 25854359Srobertostatic struct errorregression 25954359Srobertoerr_badstatus[] = /* unsynchronized state messages */ 26054359Sroberto{ 26154359Sroberto { 1, 0 }, /* output first message immediately */ 26254359Sroberto { 5, 60 }, /* output next five messages in 60 second intervals */ 26354359Sroberto { 3, 3600 }, /* output next 3 messages in hour intervals */ 26454359Sroberto { 0, 12*3600 } /* repeat messages only every 12 hours */ 26554359Sroberto}; 26654359Sroberto 26754359Srobertostatic struct errorregression 26854359Srobertoerr_badio[] = /* io failures (bad reads, selects, ...) */ 26954359Sroberto{ 27054359Sroberto { 1, 0 }, /* output first message immediately */ 27154359Sroberto { 5, 60 }, /* output next five messages in 60 second intervals */ 27254359Sroberto { 5, 3600 }, /* output next 3 messages in hour intervals */ 27354359Sroberto { 0, 12*3600 } /* repeat messages only every 12 hours */ 27454359Sroberto}; 27554359Sroberto 27654359Srobertostatic struct errorregression 27754359Srobertoerr_badevent[] = /* non nominal events */ 27854359Sroberto{ 27954359Sroberto { 20, 0 }, /* output first message immediately */ 28054359Sroberto { 6, 60 }, /* output next five messages in 60 second intervals */ 28154359Sroberto { 5, 3600 }, /* output next 3 messages in hour intervals */ 28254359Sroberto { 0, 12*3600 } /* repeat messages only every 12 hours */ 28354359Sroberto}; 28454359Sroberto 28554359Srobertostatic struct errorregression 28654359Srobertoerr_internal[] = /* really bad things - basically coding/OS errors */ 28754359Sroberto{ 28854359Sroberto { 0, 0 }, /* output all messages immediately */ 28954359Sroberto}; 29054359Sroberto 29154359Srobertostatic struct errorregression * 29254359Srobertoerr_tbl[] = 29354359Sroberto{ 29454359Sroberto err_baddata, 29554359Sroberto err_nodata, 29654359Sroberto err_badio, 29754359Sroberto err_badstatus, 29854359Sroberto err_badevent, 29954359Sroberto err_internal 30054359Sroberto}; 30154359Sroberto 30254359Srobertostruct errorinfo 30354359Sroberto{ 30454359Sroberto u_long err_started; /* begin time (ntp) of error condition */ 30554359Sroberto u_long err_last; /* last time (ntp) error occurred */ 30654359Sroberto u_long err_cnt; /* number of error repititions */ 30754359Sroberto u_long err_suppressed; /* number of suppressed messages */ 30854359Sroberto struct errorregression *err_stage; /* current error stage */ 30954359Sroberto}; 31054359Sroberto 31154359Sroberto/**=========================================================================== 31254359Sroberto ** refclock instance data 31354359Sroberto **/ 31454359Sroberto 31554359Srobertostruct parseunit 31654359Sroberto{ 31754359Sroberto /* 31854359Sroberto * NTP management 31954359Sroberto */ 32054359Sroberto struct peer *peer; /* backlink to peer structure - refclock inactive if 0 */ 32154359Sroberto struct refclockproc *generic; /* backlink to refclockproc structure */ 32254359Sroberto 32354359Sroberto /* 32454359Sroberto * PARSE io 32554359Sroberto */ 32654359Sroberto bind_t *binding; /* io handling binding */ 32754359Sroberto 32854359Sroberto /* 32954359Sroberto * parse state 33054359Sroberto */ 33154359Sroberto parse_t parseio; /* io handling structure (user level parsing) */ 33254359Sroberto 33354359Sroberto /* 33454359Sroberto * type specific parameters 33554359Sroberto */ 33654359Sroberto struct parse_clockinfo *parse_type; /* link to clock description */ 33754359Sroberto 33854359Sroberto /* 33954359Sroberto * clock state handling/reporting 34054359Sroberto */ 34154359Sroberto u_char flags; /* flags (leap_control) */ 34254359Sroberto u_long lastchange; /* time (ntp) when last state change accured */ 34354359Sroberto u_long statetime[CEVNT_MAX+1]; /* accumulated time of clock states */ 34456746Sroberto u_long pollneeddata; /* current_time(!=0) for receive sample expected in PPS mode */ 34554359Sroberto u_short lastformat; /* last format used */ 34654359Sroberto u_long lastsync; /* time (ntp) when clock was last seen fully synchronized */ 34754359Sroberto u_long lastmissed; /* time (ntp) when poll didn't get data (powerup heuristic) */ 34854359Sroberto u_long ppsserial; /* magic cookie for ppsclock serials (avoids stale ppsclock data) */ 34954359Sroberto parsetime_t time; /* last (parse module) data */ 35054359Sroberto void *localdata; /* optional local, receiver-specific data */ 35154359Sroberto unsigned long localstate; /* private local state */ 35254359Sroberto struct errorinfo errors[ERR_CNT]; /* error state table for suppressing excessive error messages */ 35354359Sroberto struct ctl_var *kv; /* additional pseudo variables */ 35454359Sroberto u_long laststatistic; /* time when staticstics where output */ 35554359Sroberto}; 35654359Sroberto 35754359Sroberto 35854359Sroberto/**=========================================================================== 35954359Sroberto ** Clockinfo section all parameter for specific clock types 36054359Sroberto ** includes NTP parameters, TTY parameters and IO handling parameters 36154359Sroberto **/ 36254359Sroberto 36354359Srobertostatic void poll_dpoll P((struct parseunit *)); 36454359Srobertostatic void poll_poll P((struct peer *)); 36554359Srobertostatic int poll_init P((struct parseunit *)); 36654359Sroberto 36754359Srobertotypedef struct poll_info 36854359Sroberto{ 36954359Sroberto u_long rate; /* poll rate - once every "rate" seconds - 0 off */ 37054359Sroberto const char *string; /* string to send for polling */ 37154359Sroberto u_long count; /* number of characters in string */ 37254359Sroberto} poll_info_t; 37354359Sroberto 37454359Sroberto#define NO_CL_FLAGS 0 37554359Sroberto#define NO_POLL 0 37654359Sroberto#define NO_INIT 0 37754359Sroberto#define NO_END 0 37854359Sroberto#define NO_EVENT 0 37954359Sroberto#define NO_DATA 0 38054359Sroberto#define NO_MESSAGE 0 38154359Sroberto#define NO_PPSDELAY 0 38254359Sroberto 38354359Sroberto#define DCF_ID "DCF" /* generic DCF */ 38454359Sroberto#define DCF_A_ID "DCFa" /* AM demodulation */ 38554359Sroberto#define DCF_P_ID "DCFp" /* psuedo random phase shift */ 38654359Sroberto#define GPS_ID "GPS" /* GPS receiver */ 38754359Sroberto 38854359Sroberto#define NOCLOCK_ROOTDELAY 0.0 38954359Sroberto#define NOCLOCK_BASEDELAY 0.0 39054359Sroberto#define NOCLOCK_DESCRIPTION 0 39154359Sroberto#define NOCLOCK_MAXUNSYNC 0 39254359Sroberto#define NOCLOCK_CFLAG 0 39354359Sroberto#define NOCLOCK_IFLAG 0 39454359Sroberto#define NOCLOCK_OFLAG 0 39554359Sroberto#define NOCLOCK_LFLAG 0 39654359Sroberto#define NOCLOCK_ID "TILT" 39754359Sroberto#define NOCLOCK_POLL NO_POLL 39854359Sroberto#define NOCLOCK_INIT NO_INIT 39954359Sroberto#define NOCLOCK_END NO_END 40054359Sroberto#define NOCLOCK_DATA NO_DATA 40154359Sroberto#define NOCLOCK_FORMAT "" 40254359Sroberto#define NOCLOCK_TYPE CTL_SST_TS_UNSPEC 40354359Sroberto#define NOCLOCK_SAMPLES 0 40454359Sroberto#define NOCLOCK_KEEP 0 40554359Sroberto 40654359Sroberto#define DCF_TYPE CTL_SST_TS_LF 40754359Sroberto#define GPS_TYPE CTL_SST_TS_UHF 40854359Sroberto 40954359Sroberto/* 41054359Sroberto * receiver specific constants 41154359Sroberto */ 41254359Sroberto#define MBG_SPEED (B9600) 41354359Sroberto#define MBG_CFLAG (CS7|PARENB|CREAD|CLOCAL|HUPCL) 41454359Sroberto#define MBG_IFLAG (IGNBRK|IGNPAR|ISTRIP) 41554359Sroberto#define MBG_OFLAG 0 41654359Sroberto#define MBG_LFLAG 0 41754359Sroberto#define MBG_FLAGS PARSE_F_PPSONSECOND 41854359Sroberto 41954359Sroberto/* 42054359Sroberto * Meinberg DCF77 receivers 42154359Sroberto */ 42254359Sroberto#define DCFUA31_ROOTDELAY 0.0 /* 0 */ 42354359Sroberto#define DCFUA31_BASEDELAY 0.010 /* 10.7421875ms: 10 ms (+/- 3 ms) */ 42454359Sroberto#define DCFUA31_DESCRIPTION "Meinberg DCF77 C51 or compatible" 42554359Sroberto#define DCFUA31_MAXUNSYNC 60*30 /* only trust clock for 1/2 hour */ 42654359Sroberto#define DCFUA31_SPEED MBG_SPEED 42754359Sroberto#define DCFUA31_CFLAG MBG_CFLAG 42854359Sroberto#define DCFUA31_IFLAG MBG_IFLAG 42954359Sroberto#define DCFUA31_OFLAG MBG_OFLAG 43054359Sroberto#define DCFUA31_LFLAG MBG_LFLAG 43154359Sroberto#define DCFUA31_SAMPLES 5 43254359Sroberto#define DCFUA31_KEEP 3 43354359Sroberto#define DCFUA31_FORMAT "Meinberg Standard" 43454359Sroberto 43554359Sroberto/* 43654359Sroberto * Meinberg DCF PZF535/TCXO (FM/PZF) receiver 43754359Sroberto */ 43854359Sroberto#define DCFPZF535_ROOTDELAY 0.0 43954359Sroberto#define DCFPZF535_BASEDELAY 0.001968 /* 1.968ms +- 104us (oscilloscope) - relative to start (end of STX) */ 44054359Sroberto#define DCFPZF535_DESCRIPTION "Meinberg DCF PZF 535/509 / TCXO" 44154359Sroberto#define DCFPZF535_MAXUNSYNC 60*60*12 /* only trust clock for 12 hours 44254359Sroberto * @ 5e-8df/f we have accumulated 44354359Sroberto * at most 2.16 ms (thus we move to 44454359Sroberto * NTP synchronisation */ 44554359Sroberto#define DCFPZF535_SPEED MBG_SPEED 44654359Sroberto#define DCFPZF535_CFLAG MBG_CFLAG 44754359Sroberto#define DCFPZF535_IFLAG MBG_IFLAG 44854359Sroberto#define DCFPZF535_OFLAG MBG_OFLAG 44954359Sroberto#define DCFPZF535_LFLAG MBG_LFLAG 45054359Sroberto#define DCFPZF535_SAMPLES 5 45154359Sroberto#define DCFPZF535_KEEP 3 45254359Sroberto#define DCFPZF535_FORMAT "Meinberg Standard" 45354359Sroberto 45454359Sroberto/* 45554359Sroberto * Meinberg DCF PZF535/OCXO receiver 45654359Sroberto */ 45754359Sroberto#define DCFPZF535OCXO_ROOTDELAY 0.0 45854359Sroberto#define DCFPZF535OCXO_BASEDELAY 0.001968 /* 1.968ms +- 104us (oscilloscope) - relative to start (end of STX) */ 45954359Sroberto#define DCFPZF535OCXO_DESCRIPTION "Meinberg DCF PZF 535/509 / OCXO" 46054359Sroberto#define DCFPZF535OCXO_MAXUNSYNC 60*60*96 /* only trust clock for 4 days 46154359Sroberto * @ 5e-9df/f we have accumulated 46254359Sroberto * at most an error of 1.73 ms 46354359Sroberto * (thus we move to NTP synchronisation) */ 46454359Sroberto#define DCFPZF535OCXO_SPEED MBG_SPEED 46554359Sroberto#define DCFPZF535OCXO_CFLAG MBG_CFLAG 46654359Sroberto#define DCFPZF535OCXO_IFLAG MBG_IFLAG 46754359Sroberto#define DCFPZF535OCXO_OFLAG MBG_OFLAG 46854359Sroberto#define DCFPZF535OCXO_LFLAG MBG_LFLAG 46954359Sroberto#define DCFPZF535OCXO_SAMPLES 5 47054359Sroberto#define DCFPZF535OCXO_KEEP 3 47154359Sroberto#define DCFPZF535OCXO_FORMAT "Meinberg Standard" 47254359Sroberto 47354359Sroberto/* 47454359Sroberto * Meinberg GPS16X receiver 47554359Sroberto */ 47654359Srobertostatic void gps16x_message P((struct parseunit *, parsetime_t *)); 47754359Srobertostatic int gps16x_poll_init P((struct parseunit *)); 47854359Sroberto 47954359Sroberto#define GPS16X_ROOTDELAY 0.0 /* nothing here */ 48054359Sroberto#define GPS16X_BASEDELAY 0.001968 /* XXX to be fixed ! 1.968ms +- 104us (oscilloscope) - relative to start (end of STX) */ 48154359Sroberto#define GPS16X_DESCRIPTION "Meinberg GPS16x receiver" 48254359Sroberto#define GPS16X_MAXUNSYNC 60*60*96 /* only trust clock for 4 days 48354359Sroberto * @ 5e-9df/f we have accumulated 48454359Sroberto * at most an error of 1.73 ms 48554359Sroberto * (thus we move to NTP synchronisation) */ 48654359Sroberto#define GPS16X_SPEED B19200 48754359Sroberto#define GPS16X_CFLAG (CS8|CREAD|CLOCAL|HUPCL) 48854359Sroberto#define GPS16X_IFLAG (IGNBRK|IGNPAR) 48954359Sroberto#define GPS16X_OFLAG MBG_OFLAG 49054359Sroberto#define GPS16X_LFLAG MBG_LFLAG 49154359Sroberto#define GPS16X_POLLRATE 6 49254359Sroberto#define GPS16X_POLLCMD "" 49354359Sroberto#define GPS16X_CMDSIZE 0 49454359Sroberto 49554359Srobertostatic poll_info_t gps16x_pollinfo = { GPS16X_POLLRATE, GPS16X_POLLCMD, GPS16X_CMDSIZE }; 49654359Sroberto 49754359Sroberto#define GPS16X_INIT gps16x_poll_init 49854359Sroberto#define GPS16X_POLL 0 49954359Sroberto#define GPS16X_END 0 50054359Sroberto#define GPS16X_DATA ((void *)(&gps16x_pollinfo)) 50154359Sroberto#define GPS16X_MESSAGE gps16x_message 50254359Sroberto#define GPS16X_ID GPS_ID 50354359Sroberto#define GPS16X_FORMAT "Meinberg GPS Extended" 50454359Sroberto#define GPS16X_SAMPLES 5 50554359Sroberto#define GPS16X_KEEP 3 50654359Sroberto 50754359Sroberto/* 50854359Sroberto * ELV DCF7000 Wallclock-Receiver/Switching Clock (Kit) 50954359Sroberto * 51054359Sroberto * This is really not the hottest clock - but before you have nothing ... 51154359Sroberto */ 51254359Sroberto#define DCF7000_ROOTDELAY 0.0 /* 0 */ 51354359Sroberto#define DCF7000_BASEDELAY 0.405 /* slow blow */ 51454359Sroberto#define DCF7000_DESCRIPTION "ELV DCF7000" 51554359Sroberto#define DCF7000_MAXUNSYNC (60*5) /* sorry - but it just was not build as a clock */ 51654359Sroberto#define DCF7000_SPEED (B9600) 51754359Sroberto#define DCF7000_CFLAG (CS8|CREAD|PARENB|PARODD|CLOCAL|HUPCL) 51854359Sroberto#define DCF7000_IFLAG (IGNBRK) 51954359Sroberto#define DCF7000_OFLAG 0 52054359Sroberto#define DCF7000_LFLAG 0 52154359Sroberto#define DCF7000_SAMPLES 5 52254359Sroberto#define DCF7000_KEEP 3 52354359Sroberto#define DCF7000_FORMAT "ELV DCF7000" 52454359Sroberto 52554359Sroberto/* 52654359Sroberto * Schmid DCF Receiver Kit 52754359Sroberto * 52854359Sroberto * When the WSDCF clock is operating optimally we want the primary clock 52954359Sroberto * distance to come out at 300 ms. Thus, peer.distance in the WSDCF peer 53054359Sroberto * structure is set to 290 ms and we compute delays which are at least 53154359Sroberto * 10 ms long. The following are 290 ms and 10 ms expressed in u_fp format 53254359Sroberto */ 53354359Sroberto#define WS_POLLRATE 1 /* every second - watch interdependency with poll routine */ 53454359Sroberto#define WS_POLLCMD "\163" 53554359Sroberto#define WS_CMDSIZE 1 53654359Sroberto 53754359Srobertostatic poll_info_t wsdcf_pollinfo = { WS_POLLRATE, WS_POLLCMD, WS_CMDSIZE }; 53854359Sroberto 53954359Sroberto#define WSDCF_INIT poll_init 54054359Sroberto#define WSDCF_POLL poll_dpoll 54154359Sroberto#define WSDCF_END 0 54254359Sroberto#define WSDCF_DATA ((void *)(&wsdcf_pollinfo)) 54354359Sroberto#define WSDCF_ROOTDELAY 0.0 /* 0 */ 54454359Sroberto#define WSDCF_BASEDELAY 0.010 /* ~ 10ms */ 54554359Sroberto#define WSDCF_DESCRIPTION "WS/DCF Receiver" 54654359Sroberto#define WSDCF_FORMAT "Schmid" 54754359Sroberto#define WSDCF_MAXUNSYNC (60*60) /* assume this beast hold at 1 h better than 2 ms XXX-must verify */ 54854359Sroberto#define WSDCF_SPEED (B1200) 54954359Sroberto#define WSDCF_CFLAG (CS8|CREAD|CLOCAL) 55054359Sroberto#define WSDCF_IFLAG 0 55154359Sroberto#define WSDCF_OFLAG 0 55254359Sroberto#define WSDCF_LFLAG 0 55354359Sroberto#define WSDCF_SAMPLES 5 55454359Sroberto#define WSDCF_KEEP 3 55554359Sroberto 55654359Sroberto/* 55754359Sroberto * RAW DCF77 - input of DCF marks via RS232 - many variants 55854359Sroberto */ 55954359Sroberto#define RAWDCF_FLAGS 0 56054359Sroberto#define RAWDCF_ROOTDELAY 0.0 /* 0 */ 56154359Sroberto#define RAWDCF_BASEDELAY 0.258 56254359Sroberto#define RAWDCF_FORMAT "RAW DCF77 Timecode" 56354359Sroberto#define RAWDCF_MAXUNSYNC (0) /* sorry - its a true receiver - no signal - no time */ 56454359Sroberto#define RAWDCF_SPEED (B50) 56554359Sroberto#ifdef NO_PARENB_IGNPAR /* Was: defined(SYS_IRIX4) || defined(SYS_IRIX5) */ 56654359Sroberto/* somehow doesn't grok PARENB & IGNPAR (mj) */ 56754359Sroberto# define RAWDCF_CFLAG (CS8|CREAD|CLOCAL) 56854359Sroberto#else 56954359Sroberto# define RAWDCF_CFLAG (CS8|CREAD|CLOCAL|PARENB) 57054359Sroberto#endif 57154359Sroberto#ifdef RAWDCF_NO_IGNPAR /* Was: defined(SYS_LINUX) && defined(CLOCK_RAWDCF) */ 57254359Sroberto# define RAWDCF_IFLAG 0 57354359Sroberto#else 57454359Sroberto# define RAWDCF_IFLAG (IGNPAR) 57554359Sroberto#endif 57654359Sroberto#define RAWDCF_OFLAG 0 57754359Sroberto#define RAWDCF_LFLAG 0 57854359Sroberto#define RAWDCF_SAMPLES 20 57954359Sroberto#define RAWDCF_KEEP 12 58054359Sroberto#define RAWDCF_INIT 0 58154359Sroberto 58254359Sroberto/* 58354359Sroberto * RAW DCF variants 58454359Sroberto */ 58554359Sroberto/* 58654359Sroberto * Conrad receiver 58754359Sroberto * 58854359Sroberto * simplest (cheapest) DCF clock - e. g. DCF77 receiver by Conrad 58954359Sroberto * (~40DM - roughly $30 ) followed by a level converter for RS232 59054359Sroberto */ 59154359Sroberto#define CONRAD_BASEDELAY 0.292 /* Conrad receiver @ 50 Baud on a Sun */ 59254359Sroberto#define CONRAD_DESCRIPTION "RAW DCF77 CODE (Conrad DCF77 receiver module)" 59354359Sroberto 59454359Sroberto/* 59554359Sroberto * TimeBrick receiver 59654359Sroberto */ 59754359Sroberto#define TIMEBRICK_BASEDELAY 0.210 /* TimeBrick @ 50 Baud on a Sun */ 59854359Sroberto#define TIMEBRICK_DESCRIPTION "RAW DCF77 CODE (TimeBrick)" 59954359Sroberto 60054359Sroberto/* 60154359Sroberto * IGEL:clock receiver 60254359Sroberto */ 60354359Sroberto#define IGELCLOCK_BASEDELAY 0.258 /* IGEL:clock receiver */ 60454359Sroberto#define IGELCLOCK_DESCRIPTION "RAW DCF77 CODE (IGEL:clock)" 60554359Sroberto#define IGELCLOCK_SPEED (B1200) 60654359Sroberto#define IGELCLOCK_CFLAG (CS8|CREAD|HUPCL|CLOCAL) 60754359Sroberto 60854359Sroberto/* 60954359Sroberto * RAWDCF receivers that need to be powered from DTR 61054359Sroberto * (like Expert mouse clock) 61154359Sroberto */ 61256746Srobertostatic int rawdcf_init_1 P((struct parseunit *)); 61356746Sroberto#define RAWDCFDTRSET_DESCRIPTION "RAW DCF77 CODE (DTR SET/RTS CLR)" 61456746Sroberto#define RAWDCFDTRSET_INIT rawdcf_init_1 61554359Sroberto 61654359Sroberto/* 61756746Sroberto * RAWDCF receivers that need to be powered from 61856746Sroberto * DTR CLR and RTS SET 61954359Sroberto */ 62056746Srobertostatic int rawdcf_init_2 P((struct parseunit *)); 62156746Sroberto#define RAWDCFDTRCLRRTSSET_DESCRIPTION "RAW DCF77 CODE (DTR CLR/RTS SET)" 62256746Sroberto#define RAWDCFDTRCLRRTSSET_INIT rawdcf_init_2 62354359Sroberto 62454359Sroberto/* 62554359Sroberto * Trimble GPS receivers (TAIP and TSIP protocols) 62654359Sroberto */ 62754359Sroberto#ifndef TRIM_POLLRATE 62854359Sroberto#define TRIM_POLLRATE 0 /* only true direct polling */ 62954359Sroberto#endif 63054359Sroberto 63154359Sroberto#define TRIM_TAIPPOLLCMD ">SRM;FR_FLAG=F;EC_FLAG=F<>QTM<" 63254359Sroberto#define TRIM_TAIPCMDSIZE (sizeof(TRIM_TAIPPOLLCMD)-1) 63354359Sroberto 63454359Srobertostatic poll_info_t trimbletaip_pollinfo = { TRIM_POLLRATE, TRIM_TAIPPOLLCMD, TRIM_TAIPCMDSIZE }; 63554359Srobertostatic int trimbletaip_init P((struct parseunit *)); 63654359Srobertostatic void trimbletaip_event P((struct parseunit *, int)); 63754359Sroberto 63854359Sroberto/* query time & UTC correction data */ 63954359Srobertostatic char tsipquery[] = { DLE, 0x21, DLE, ETX, DLE, 0x2F, DLE, ETX }; 64054359Sroberto 64154359Srobertostatic poll_info_t trimbletsip_pollinfo = { TRIM_POLLRATE, tsipquery, sizeof(tsipquery) }; 64254359Srobertostatic int trimbletsip_init P((struct parseunit *)); 64354359Srobertostatic void trimbletsip_end P((struct parseunit *)); 64454359Srobertostatic void trimbletsip_message P((struct parseunit *, parsetime_t *)); 64554359Srobertostatic void trimbletsip_event P((struct parseunit *, int)); 64654359Sroberto 64754359Sroberto#define TRIMBLETSIP_IDLE_TIME (300) /* 5 minutes silence at most */ 64854359Sroberto 64954359Sroberto#define TRIMBLETAIP_SPEED (B4800) 65054359Sroberto#define TRIMBLETAIP_CFLAG (CS8|CREAD|CLOCAL) 65154359Sroberto#define TRIMBLETAIP_IFLAG (BRKINT|IGNPAR|ISTRIP|ICRNL|IXON) 65254359Sroberto#define TRIMBLETAIP_OFLAG (OPOST|ONLCR) 65354359Sroberto#define TRIMBLETAIP_LFLAG (0) 65454359Sroberto 65554359Sroberto#define TRIMBLETSIP_SPEED (B9600) 65654359Sroberto#define TRIMBLETSIP_CFLAG (CS8|CLOCAL|CREAD|PARENB|PARODD) 65754359Sroberto#define TRIMBLETSIP_IFLAG (IGNBRK) 65854359Sroberto#define TRIMBLETSIP_OFLAG (0) 65954359Sroberto#define TRIMBLETSIP_LFLAG (ICANON) 66054359Sroberto 66154359Sroberto#define TRIMBLETSIP_SAMPLES 5 66254359Sroberto#define TRIMBLETSIP_KEEP 3 66354359Sroberto#define TRIMBLETAIP_SAMPLES 5 66454359Sroberto#define TRIMBLETAIP_KEEP 3 66554359Sroberto 66654359Sroberto#define TRIMBLETAIP_FLAGS (PARSE_F_PPSONSECOND) 66754359Sroberto#define TRIMBLETSIP_FLAGS (TRIMBLETAIP_FLAGS) 66854359Sroberto 66954359Sroberto#define TRIMBLETAIP_POLL poll_dpoll 67054359Sroberto#define TRIMBLETSIP_POLL poll_dpoll 67154359Sroberto 67254359Sroberto#define TRIMBLETAIP_INIT trimbletaip_init 67354359Sroberto#define TRIMBLETSIP_INIT trimbletsip_init 67454359Sroberto 67554359Sroberto#define TRIMBLETAIP_EVENT trimbletaip_event 67654359Sroberto 67754359Sroberto#define TRIMBLETSIP_EVENT trimbletsip_event 67854359Sroberto#define TRIMBLETSIP_MESSAGE trimbletsip_message 67954359Sroberto 68054359Sroberto#define TRIMBLETAIP_END 0 68154359Sroberto#define TRIMBLETSIP_END trimbletsip_end 68254359Sroberto 68354359Sroberto#define TRIMBLETAIP_DATA ((void *)(&trimbletaip_pollinfo)) 68454359Sroberto#define TRIMBLETSIP_DATA ((void *)(&trimbletsip_pollinfo)) 68554359Sroberto 68654359Sroberto#define TRIMBLETAIP_ID GPS_ID 68754359Sroberto#define TRIMBLETSIP_ID GPS_ID 68854359Sroberto 68954359Sroberto#define TRIMBLETAIP_FORMAT "Trimble TAIP" 69054359Sroberto#define TRIMBLETSIP_FORMAT "Trimble TSIP" 69154359Sroberto 69254359Sroberto#define TRIMBLETAIP_ROOTDELAY 0x0 69354359Sroberto#define TRIMBLETSIP_ROOTDELAY 0x0 69454359Sroberto 69554359Sroberto#define TRIMBLETAIP_BASEDELAY 0.0 69654359Sroberto#define TRIMBLETSIP_BASEDELAY 0.020 /* GPS time message latency */ 69754359Sroberto 69854359Sroberto#define TRIMBLETAIP_DESCRIPTION "Trimble GPS (TAIP) receiver" 69954359Sroberto#define TRIMBLETSIP_DESCRIPTION "Trimble GPS (TSIP) receiver" 70054359Sroberto 70154359Sroberto#define TRIMBLETAIP_MAXUNSYNC 0 70254359Sroberto#define TRIMBLETSIP_MAXUNSYNC 0 70354359Sroberto 70454359Sroberto#define TRIMBLETAIP_EOL '<' 70554359Sroberto 70654359Sroberto/* 70754359Sroberto * RadioCode Clocks RCC 800 receiver 70854359Sroberto */ 70954359Sroberto#define RCC_POLLRATE 0 /* only true direct polling */ 71054359Sroberto#define RCC_POLLCMD "\r" 71154359Sroberto#define RCC_CMDSIZE 1 71254359Sroberto 71354359Srobertostatic poll_info_t rcc8000_pollinfo = { RCC_POLLRATE, RCC_POLLCMD, RCC_CMDSIZE }; 71454359Sroberto#define RCC8000_FLAGS 0 71554359Sroberto#define RCC8000_POLL poll_dpoll 71654359Sroberto#define RCC8000_INIT poll_init 71754359Sroberto#define RCC8000_END 0 71854359Sroberto#define RCC8000_DATA ((void *)(&rcc8000_pollinfo)) 71954359Sroberto#define RCC8000_ROOTDELAY 0.0 72054359Sroberto#define RCC8000_BASEDELAY 0.0 72154359Sroberto#define RCC8000_ID "MSF" 72254359Sroberto#define RCC8000_DESCRIPTION "RCC 8000 MSF Receiver" 72354359Sroberto#define RCC8000_FORMAT "Radiocode RCC8000" 72454359Sroberto#define RCC8000_MAXUNSYNC (60*60) /* should be ok for an hour */ 72554359Sroberto#define RCC8000_SPEED (B2400) 72654359Sroberto#define RCC8000_CFLAG (CS8|CREAD|CLOCAL) 72754359Sroberto#define RCC8000_IFLAG (IGNBRK|IGNPAR) 72854359Sroberto#define RCC8000_OFLAG 0 72954359Sroberto#define RCC8000_LFLAG 0 73054359Sroberto#define RCC8000_SAMPLES 5 73154359Sroberto#define RCC8000_KEEP 3 73254359Sroberto 73354359Sroberto/* 73454359Sroberto * Hopf Radio clock 6021 Format 73554359Sroberto * 73654359Sroberto */ 73754359Sroberto#define HOPF6021_ROOTDELAY 0.0 73854359Sroberto#define HOPF6021_BASEDELAY 0.0 73954359Sroberto#define HOPF6021_DESCRIPTION "HOPF 6021" 74054359Sroberto#define HOPF6021_FORMAT "hopf Funkuhr 6021" 74154359Sroberto#define HOPF6021_MAXUNSYNC (60*60) /* should be ok for an hour */ 74254359Sroberto#define HOPF6021_SPEED (B9600) 74354359Sroberto#define HOPF6021_CFLAG (CS8|CREAD|CLOCAL) 74454359Sroberto#define HOPF6021_IFLAG (IGNBRK|ISTRIP) 74554359Sroberto#define HOPF6021_OFLAG 0 74654359Sroberto#define HOPF6021_LFLAG 0 74754359Sroberto#define HOPF6021_FLAGS 0 74854359Sroberto#define HOPF6021_SAMPLES 5 74954359Sroberto#define HOPF6021_KEEP 3 75054359Sroberto 75154359Sroberto/* 75254359Sroberto * Diem's Computime Radio Clock Receiver 75354359Sroberto */ 75454359Sroberto#define COMPUTIME_FLAGS 0 75554359Sroberto#define COMPUTIME_ROOTDELAY 0.0 75654359Sroberto#define COMPUTIME_BASEDELAY 0.0 75754359Sroberto#define COMPUTIME_ID DCF_ID 75854359Sroberto#define COMPUTIME_DESCRIPTION "Diem's Computime receiver" 75954359Sroberto#define COMPUTIME_FORMAT "Diem's Computime Radio Clock" 76054359Sroberto#define COMPUTIME_TYPE DCF_TYPE 76154359Sroberto#define COMPUTIME_MAXUNSYNC (60*60) /* only trust clock for 1 hour */ 76254359Sroberto#define COMPUTIME_SPEED (B9600) 76354359Sroberto#define COMPUTIME_CFLAG (CSTOPB|CS7|CREAD|CLOCAL) 76454359Sroberto#define COMPUTIME_IFLAG (IGNBRK|IGNPAR|ISTRIP) 76554359Sroberto#define COMPUTIME_OFLAG 0 76654359Sroberto#define COMPUTIME_LFLAG 0 76754359Sroberto#define COMPUTIME_SAMPLES 5 76854359Sroberto#define COMPUTIME_KEEP 3 76954359Sroberto 77056746Srobertostatic poll_info_t we400a_pollinfo = { 60, "T", 1 }; 77156746Sroberto 77254359Sroberto/* 77354359Sroberto * Varitext Radio Clock Receiver 77454359Sroberto */ 77554359Sroberto#define VARITEXT_FLAGS 0 77654359Sroberto#define VARITEXT_ROOTDELAY 0.0 77754359Sroberto#define VARITEXT_BASEDELAY 0.0 77854359Sroberto#define VARITEXT_ID "MSF" 77954359Sroberto#define VARITEXT_DESCRIPTION "Varitext receiver" 78054359Sroberto#define VARITEXT_FORMAT "Varitext Radio Clock" 78154359Sroberto#define VARITEXT_TYPE DCF_TYPE 78254359Sroberto#define VARITEXT_MAXUNSYNC (60*60) /* only trust clock for 1 hour */ 78354359Sroberto#define VARITEXT_SPEED (B9600) 78454359Sroberto#define VARITEXT_CFLAG (CS7|CREAD|CLOCAL|PARENB|PARODD) 78554359Sroberto#define VARITEXT_IFLAG (IGNPAR|IGNBRK|INPCK) /*|ISTRIP)*/ 78654359Sroberto#define VARITEXT_OFLAG 0 78754359Sroberto#define VARITEXT_LFLAG 0 78854359Sroberto#define VARITEXT_SAMPLES 32 78954359Sroberto#define VARITEXT_KEEP 20 79054359Sroberto 79154359Srobertostatic struct parse_clockinfo 79254359Sroberto{ 79354359Sroberto u_long cl_flags; /* operation flags (io modes) */ 79454359Sroberto void (*cl_poll) P((struct parseunit *)); /* active poll routine */ 79554359Sroberto int (*cl_init) P((struct parseunit *)); /* active poll init routine */ 79654359Sroberto void (*cl_event) P((struct parseunit *, int)); /* special event handling (e.g. reset clock) */ 79754359Sroberto void (*cl_end) P((struct parseunit *)); /* active poll end routine */ 79854359Sroberto void (*cl_message) P((struct parseunit *, parsetime_t *)); /* process a lower layer message */ 79954359Sroberto void *cl_data; /* local data area for "poll" mechanism */ 80054359Sroberto double cl_rootdelay; /* rootdelay */ 80154359Sroberto double cl_basedelay; /* current offset by which the RS232 80254359Sroberto time code is delayed from the actual time */ 80354359Sroberto const char *cl_id; /* ID code */ 80454359Sroberto const char *cl_description; /* device name */ 80554359Sroberto const char *cl_format; /* fixed format */ 80654359Sroberto u_char cl_type; /* clock type (ntp control) */ 80754359Sroberto u_long cl_maxunsync; /* time to trust oscillator after loosing synch */ 80854359Sroberto u_long cl_speed; /* terminal input & output baudrate */ 80954359Sroberto u_long cl_cflag; /* terminal control flags */ 81054359Sroberto u_long cl_iflag; /* terminal input flags */ 81154359Sroberto u_long cl_oflag; /* terminal output flags */ 81254359Sroberto u_long cl_lflag; /* terminal local flags */ 81354359Sroberto u_long cl_samples; /* samples for median filter */ 81454359Sroberto u_long cl_keep; /* samples for median filter to keep */ 81554359Sroberto} parse_clockinfo[] = 81654359Sroberto{ 81754359Sroberto { /* mode 0 */ 81854359Sroberto MBG_FLAGS, 81954359Sroberto NO_POLL, 82054359Sroberto NO_INIT, 82154359Sroberto NO_EVENT, 82254359Sroberto NO_END, 82354359Sroberto NO_MESSAGE, 82454359Sroberto NO_DATA, 82554359Sroberto DCFPZF535_ROOTDELAY, 82654359Sroberto DCFPZF535_BASEDELAY, 82754359Sroberto DCF_P_ID, 82854359Sroberto DCFPZF535_DESCRIPTION, 82954359Sroberto DCFPZF535_FORMAT, 83054359Sroberto DCF_TYPE, 83154359Sroberto DCFPZF535_MAXUNSYNC, 83254359Sroberto DCFPZF535_SPEED, 83354359Sroberto DCFPZF535_CFLAG, 83454359Sroberto DCFPZF535_IFLAG, 83554359Sroberto DCFPZF535_OFLAG, 83654359Sroberto DCFPZF535_LFLAG, 83754359Sroberto DCFPZF535_SAMPLES, 83854359Sroberto DCFPZF535_KEEP 83954359Sroberto }, 84054359Sroberto { /* mode 1 */ 84154359Sroberto MBG_FLAGS, 84254359Sroberto NO_POLL, 84354359Sroberto NO_INIT, 84454359Sroberto NO_EVENT, 84554359Sroberto NO_END, 84654359Sroberto NO_MESSAGE, 84754359Sroberto NO_DATA, 84854359Sroberto DCFPZF535OCXO_ROOTDELAY, 84954359Sroberto DCFPZF535OCXO_BASEDELAY, 85054359Sroberto DCF_P_ID, 85154359Sroberto DCFPZF535OCXO_DESCRIPTION, 85254359Sroberto DCFPZF535OCXO_FORMAT, 85354359Sroberto DCF_TYPE, 85454359Sroberto DCFPZF535OCXO_MAXUNSYNC, 85554359Sroberto DCFPZF535OCXO_SPEED, 85654359Sroberto DCFPZF535OCXO_CFLAG, 85754359Sroberto DCFPZF535OCXO_IFLAG, 85854359Sroberto DCFPZF535OCXO_OFLAG, 85954359Sroberto DCFPZF535OCXO_LFLAG, 86054359Sroberto DCFPZF535OCXO_SAMPLES, 86154359Sroberto DCFPZF535OCXO_KEEP 86254359Sroberto }, 86354359Sroberto { /* mode 2 */ 86454359Sroberto MBG_FLAGS, 86554359Sroberto NO_POLL, 86654359Sroberto NO_INIT, 86754359Sroberto NO_EVENT, 86854359Sroberto NO_END, 86954359Sroberto NO_MESSAGE, 87054359Sroberto NO_DATA, 87154359Sroberto DCFUA31_ROOTDELAY, 87254359Sroberto DCFUA31_BASEDELAY, 87354359Sroberto DCF_A_ID, 87454359Sroberto DCFUA31_DESCRIPTION, 87554359Sroberto DCFUA31_FORMAT, 87654359Sroberto DCF_TYPE, 87754359Sroberto DCFUA31_MAXUNSYNC, 87854359Sroberto DCFUA31_SPEED, 87954359Sroberto DCFUA31_CFLAG, 88054359Sroberto DCFUA31_IFLAG, 88154359Sroberto DCFUA31_OFLAG, 88254359Sroberto DCFUA31_LFLAG, 88354359Sroberto DCFUA31_SAMPLES, 88454359Sroberto DCFUA31_KEEP 88554359Sroberto }, 88654359Sroberto { /* mode 3 */ 88754359Sroberto MBG_FLAGS, 88854359Sroberto NO_POLL, 88954359Sroberto NO_INIT, 89054359Sroberto NO_EVENT, 89154359Sroberto NO_END, 89254359Sroberto NO_MESSAGE, 89354359Sroberto NO_DATA, 89454359Sroberto DCF7000_ROOTDELAY, 89554359Sroberto DCF7000_BASEDELAY, 89654359Sroberto DCF_A_ID, 89754359Sroberto DCF7000_DESCRIPTION, 89854359Sroberto DCF7000_FORMAT, 89954359Sroberto DCF_TYPE, 90054359Sroberto DCF7000_MAXUNSYNC, 90154359Sroberto DCF7000_SPEED, 90254359Sroberto DCF7000_CFLAG, 90354359Sroberto DCF7000_IFLAG, 90454359Sroberto DCF7000_OFLAG, 90554359Sroberto DCF7000_LFLAG, 90654359Sroberto DCF7000_SAMPLES, 90754359Sroberto DCF7000_KEEP 90854359Sroberto }, 90954359Sroberto { /* mode 4 */ 91054359Sroberto NO_CL_FLAGS, 91154359Sroberto WSDCF_POLL, 91254359Sroberto WSDCF_INIT, 91354359Sroberto NO_EVENT, 91454359Sroberto WSDCF_END, 91554359Sroberto NO_MESSAGE, 91654359Sroberto WSDCF_DATA, 91754359Sroberto WSDCF_ROOTDELAY, 91854359Sroberto WSDCF_BASEDELAY, 91954359Sroberto DCF_A_ID, 92054359Sroberto WSDCF_DESCRIPTION, 92154359Sroberto WSDCF_FORMAT, 92254359Sroberto DCF_TYPE, 92354359Sroberto WSDCF_MAXUNSYNC, 92454359Sroberto WSDCF_SPEED, 92554359Sroberto WSDCF_CFLAG, 92654359Sroberto WSDCF_IFLAG, 92754359Sroberto WSDCF_OFLAG, 92854359Sroberto WSDCF_LFLAG, 92954359Sroberto WSDCF_SAMPLES, 93054359Sroberto WSDCF_KEEP 93154359Sroberto }, 93254359Sroberto { /* mode 5 */ 93354359Sroberto RAWDCF_FLAGS, 93454359Sroberto NO_POLL, 93554359Sroberto RAWDCF_INIT, 93654359Sroberto NO_EVENT, 93754359Sroberto NO_END, 93854359Sroberto NO_MESSAGE, 93954359Sroberto NO_DATA, 94054359Sroberto RAWDCF_ROOTDELAY, 94154359Sroberto CONRAD_BASEDELAY, 94254359Sroberto DCF_A_ID, 94354359Sroberto CONRAD_DESCRIPTION, 94454359Sroberto RAWDCF_FORMAT, 94554359Sroberto DCF_TYPE, 94654359Sroberto RAWDCF_MAXUNSYNC, 94754359Sroberto RAWDCF_SPEED, 94854359Sroberto RAWDCF_CFLAG, 94954359Sroberto RAWDCF_IFLAG, 95054359Sroberto RAWDCF_OFLAG, 95154359Sroberto RAWDCF_LFLAG, 95254359Sroberto RAWDCF_SAMPLES, 95354359Sroberto RAWDCF_KEEP 95454359Sroberto }, 95554359Sroberto { /* mode 6 */ 95654359Sroberto RAWDCF_FLAGS, 95754359Sroberto NO_POLL, 95854359Sroberto RAWDCF_INIT, 95954359Sroberto NO_EVENT, 96054359Sroberto NO_END, 96154359Sroberto NO_MESSAGE, 96254359Sroberto NO_DATA, 96354359Sroberto RAWDCF_ROOTDELAY, 96454359Sroberto TIMEBRICK_BASEDELAY, 96554359Sroberto DCF_A_ID, 96654359Sroberto TIMEBRICK_DESCRIPTION, 96754359Sroberto RAWDCF_FORMAT, 96854359Sroberto DCF_TYPE, 96954359Sroberto RAWDCF_MAXUNSYNC, 97054359Sroberto RAWDCF_SPEED, 97154359Sroberto RAWDCF_CFLAG, 97254359Sroberto RAWDCF_IFLAG, 97354359Sroberto RAWDCF_OFLAG, 97454359Sroberto RAWDCF_LFLAG, 97554359Sroberto RAWDCF_SAMPLES, 97654359Sroberto RAWDCF_KEEP 97754359Sroberto }, 97854359Sroberto { /* mode 7 */ 97954359Sroberto MBG_FLAGS, 98054359Sroberto GPS16X_POLL, 98154359Sroberto GPS16X_INIT, 98254359Sroberto NO_EVENT, 98354359Sroberto GPS16X_END, 98454359Sroberto GPS16X_MESSAGE, 98554359Sroberto GPS16X_DATA, 98654359Sroberto GPS16X_ROOTDELAY, 98754359Sroberto GPS16X_BASEDELAY, 98854359Sroberto GPS16X_ID, 98954359Sroberto GPS16X_DESCRIPTION, 99054359Sroberto GPS16X_FORMAT, 99154359Sroberto GPS_TYPE, 99254359Sroberto GPS16X_MAXUNSYNC, 99354359Sroberto GPS16X_SPEED, 99454359Sroberto GPS16X_CFLAG, 99554359Sroberto GPS16X_IFLAG, 99654359Sroberto GPS16X_OFLAG, 99754359Sroberto GPS16X_LFLAG, 99854359Sroberto GPS16X_SAMPLES, 99954359Sroberto GPS16X_KEEP 100054359Sroberto }, 100154359Sroberto { /* mode 8 */ 100254359Sroberto RAWDCF_FLAGS, 100354359Sroberto NO_POLL, 100454359Sroberto NO_INIT, 100554359Sroberto NO_EVENT, 100654359Sroberto NO_END, 100754359Sroberto NO_MESSAGE, 100854359Sroberto NO_DATA, 100954359Sroberto RAWDCF_ROOTDELAY, 101054359Sroberto IGELCLOCK_BASEDELAY, 101154359Sroberto DCF_A_ID, 101254359Sroberto IGELCLOCK_DESCRIPTION, 101354359Sroberto RAWDCF_FORMAT, 101454359Sroberto DCF_TYPE, 101554359Sroberto RAWDCF_MAXUNSYNC, 101654359Sroberto IGELCLOCK_SPEED, 101754359Sroberto IGELCLOCK_CFLAG, 101854359Sroberto RAWDCF_IFLAG, 101954359Sroberto RAWDCF_OFLAG, 102054359Sroberto RAWDCF_LFLAG, 102154359Sroberto RAWDCF_SAMPLES, 102254359Sroberto RAWDCF_KEEP 102354359Sroberto }, 102454359Sroberto { /* mode 9 */ 102554359Sroberto TRIMBLETAIP_FLAGS, 102654359Sroberto#if TRIM_POLLRATE /* DHD940515: Allow user config */ 102754359Sroberto NO_POLL, 102854359Sroberto#else 102954359Sroberto TRIMBLETAIP_POLL, 103054359Sroberto#endif 103154359Sroberto TRIMBLETAIP_INIT, 103254359Sroberto TRIMBLETAIP_EVENT, 103354359Sroberto TRIMBLETAIP_END, 103454359Sroberto NO_MESSAGE, 103554359Sroberto TRIMBLETAIP_DATA, 103654359Sroberto TRIMBLETAIP_ROOTDELAY, 103754359Sroberto TRIMBLETAIP_BASEDELAY, 103854359Sroberto TRIMBLETAIP_ID, 103954359Sroberto TRIMBLETAIP_DESCRIPTION, 104054359Sroberto TRIMBLETAIP_FORMAT, 104154359Sroberto GPS_TYPE, 104254359Sroberto TRIMBLETAIP_MAXUNSYNC, 104354359Sroberto TRIMBLETAIP_SPEED, 104454359Sroberto TRIMBLETAIP_CFLAG, 104554359Sroberto TRIMBLETAIP_IFLAG, 104654359Sroberto TRIMBLETAIP_OFLAG, 104754359Sroberto TRIMBLETAIP_LFLAG, 104854359Sroberto TRIMBLETAIP_SAMPLES, 104954359Sroberto TRIMBLETAIP_KEEP 105054359Sroberto }, 105154359Sroberto { /* mode 10 */ 105254359Sroberto TRIMBLETSIP_FLAGS, 105354359Sroberto#if TRIM_POLLRATE /* DHD940515: Allow user config */ 105454359Sroberto NO_POLL, 105554359Sroberto#else 105654359Sroberto TRIMBLETSIP_POLL, 105754359Sroberto#endif 105854359Sroberto TRIMBLETSIP_INIT, 105954359Sroberto TRIMBLETSIP_EVENT, 106054359Sroberto TRIMBLETSIP_END, 106154359Sroberto TRIMBLETSIP_MESSAGE, 106254359Sroberto TRIMBLETSIP_DATA, 106354359Sroberto TRIMBLETSIP_ROOTDELAY, 106454359Sroberto TRIMBLETSIP_BASEDELAY, 106554359Sroberto TRIMBLETSIP_ID, 106654359Sroberto TRIMBLETSIP_DESCRIPTION, 106754359Sroberto TRIMBLETSIP_FORMAT, 106854359Sroberto GPS_TYPE, 106954359Sroberto TRIMBLETSIP_MAXUNSYNC, 107054359Sroberto TRIMBLETSIP_SPEED, 107154359Sroberto TRIMBLETSIP_CFLAG, 107254359Sroberto TRIMBLETSIP_IFLAG, 107354359Sroberto TRIMBLETSIP_OFLAG, 107454359Sroberto TRIMBLETSIP_LFLAG, 107554359Sroberto TRIMBLETSIP_SAMPLES, 107654359Sroberto TRIMBLETSIP_KEEP 107754359Sroberto }, 107854359Sroberto { /* mode 11 */ 107954359Sroberto NO_CL_FLAGS, 108054359Sroberto RCC8000_POLL, 108154359Sroberto RCC8000_INIT, 108254359Sroberto NO_EVENT, 108354359Sroberto RCC8000_END, 108454359Sroberto NO_MESSAGE, 108554359Sroberto RCC8000_DATA, 108654359Sroberto RCC8000_ROOTDELAY, 108754359Sroberto RCC8000_BASEDELAY, 108854359Sroberto RCC8000_ID, 108954359Sroberto RCC8000_DESCRIPTION, 109054359Sroberto RCC8000_FORMAT, 109154359Sroberto DCF_TYPE, 109254359Sroberto RCC8000_MAXUNSYNC, 109354359Sroberto RCC8000_SPEED, 109454359Sroberto RCC8000_CFLAG, 109554359Sroberto RCC8000_IFLAG, 109654359Sroberto RCC8000_OFLAG, 109754359Sroberto RCC8000_LFLAG, 109854359Sroberto RCC8000_SAMPLES, 109954359Sroberto RCC8000_KEEP 110054359Sroberto }, 110154359Sroberto { /* mode 12 */ 110254359Sroberto HOPF6021_FLAGS, 110354359Sroberto NO_POLL, 110454359Sroberto NO_INIT, 110554359Sroberto NO_EVENT, 110654359Sroberto NO_END, 110754359Sroberto NO_MESSAGE, 110854359Sroberto NO_DATA, 110954359Sroberto HOPF6021_ROOTDELAY, 111054359Sroberto HOPF6021_BASEDELAY, 111154359Sroberto DCF_ID, 111254359Sroberto HOPF6021_DESCRIPTION, 111354359Sroberto HOPF6021_FORMAT, 111454359Sroberto DCF_TYPE, 111554359Sroberto HOPF6021_MAXUNSYNC, 111654359Sroberto HOPF6021_SPEED, 111754359Sroberto HOPF6021_CFLAG, 111854359Sroberto HOPF6021_IFLAG, 111954359Sroberto HOPF6021_OFLAG, 112054359Sroberto HOPF6021_LFLAG, 112154359Sroberto HOPF6021_SAMPLES, 112254359Sroberto HOPF6021_KEEP 112354359Sroberto }, 112454359Sroberto { /* mode 13 */ 112554359Sroberto COMPUTIME_FLAGS, 112654359Sroberto NO_POLL, 112754359Sroberto NO_INIT, 112854359Sroberto NO_EVENT, 112954359Sroberto NO_END, 113054359Sroberto NO_MESSAGE, 113154359Sroberto NO_DATA, 113254359Sroberto COMPUTIME_ROOTDELAY, 113354359Sroberto COMPUTIME_BASEDELAY, 113454359Sroberto COMPUTIME_ID, 113554359Sroberto COMPUTIME_DESCRIPTION, 113654359Sroberto COMPUTIME_FORMAT, 113754359Sroberto COMPUTIME_TYPE, 113854359Sroberto COMPUTIME_MAXUNSYNC, 113954359Sroberto COMPUTIME_SPEED, 114054359Sroberto COMPUTIME_CFLAG, 114154359Sroberto COMPUTIME_IFLAG, 114254359Sroberto COMPUTIME_OFLAG, 114354359Sroberto COMPUTIME_LFLAG, 114454359Sroberto COMPUTIME_SAMPLES, 114554359Sroberto COMPUTIME_KEEP 114654359Sroberto }, 114754359Sroberto { /* mode 14 */ 114854359Sroberto RAWDCF_FLAGS, 114954359Sroberto NO_POLL, 115056746Sroberto RAWDCFDTRSET_INIT, 115154359Sroberto NO_EVENT, 115254359Sroberto NO_END, 115354359Sroberto NO_MESSAGE, 115454359Sroberto NO_DATA, 115554359Sroberto RAWDCF_ROOTDELAY, 115654359Sroberto RAWDCF_BASEDELAY, 115754359Sroberto DCF_A_ID, 115856746Sroberto RAWDCFDTRSET_DESCRIPTION, 115954359Sroberto RAWDCF_FORMAT, 116054359Sroberto DCF_TYPE, 116154359Sroberto RAWDCF_MAXUNSYNC, 116254359Sroberto RAWDCF_SPEED, 116354359Sroberto RAWDCF_CFLAG, 116454359Sroberto RAWDCF_IFLAG, 116554359Sroberto RAWDCF_OFLAG, 116654359Sroberto RAWDCF_LFLAG, 116754359Sroberto RAWDCF_SAMPLES, 116854359Sroberto RAWDCF_KEEP 116954359Sroberto }, 117054359Sroberto { /* mode 15 */ 117156746Sroberto 0, /* operation flags (io modes) */ 117256746Sroberto poll_dpoll, /* active poll routine */ 117356746Sroberto poll_init, /* active poll init routine */ 117456746Sroberto NO_EVENT, /* special event handling (e.g. reset clock) */ 117556746Sroberto NO_END, /* active poll end routine */ 117656746Sroberto NO_MESSAGE, /* process a lower layer message */ 117756746Sroberto ((void *)(&we400a_pollinfo)), /* local data area for "poll" mechanism */ 117856746Sroberto 0, /* rootdelay */ 117956746Sroberto 1.0 / 960, /* current offset by which the RS232 118056746Sroberto time code is delayed from the actual time */ 118156746Sroberto DCF_ID, /* ID code */ 118256746Sroberto "WHARTON 400A Series clock", /* device name */ 118356746Sroberto "WHARTON 400A Series clock Output Format 5", /* fixed format */ 118456746Sroberto /* Must match a format-name in a libparse/clk_xxx.c file */ 118556746Sroberto DCF_TYPE, /* clock type (ntp control) */ 118656746Sroberto (1*60*60), /* time to trust oscillator after loosing synch */ 118756746Sroberto B9600, /* terminal input & output baudrate */ 118856746Sroberto (CS8|CREAD|PARENB|CLOCAL|HUPCL),/* terminal control flags */ 118956746Sroberto 0, /* terminal input flags */ 119056746Sroberto 0, /* terminal output flags */ 119156746Sroberto 0, /* terminal local flags */ 119256746Sroberto 5, /* samples for median filter */ 119356746Sroberto 3, /* samples for median filter to keep */ 119454359Sroberto }, 119556746Sroberto { /* mode 16 - RAWDCF RTS set, DTR clr */ 119656746Sroberto RAWDCF_FLAGS, 119756746Sroberto NO_POLL, 119856746Sroberto RAWDCFDTRCLRRTSSET_INIT, 119956746Sroberto NO_EVENT, 120056746Sroberto NO_END, 120156746Sroberto NO_MESSAGE, 120256746Sroberto NO_DATA, 120356746Sroberto RAWDCF_ROOTDELAY, 120456746Sroberto RAWDCF_BASEDELAY, 120556746Sroberto DCF_A_ID, 120656746Sroberto RAWDCFDTRCLRRTSSET_DESCRIPTION, 120756746Sroberto RAWDCF_FORMAT, 120856746Sroberto DCF_TYPE, 120956746Sroberto RAWDCF_MAXUNSYNC, 121056746Sroberto RAWDCF_SPEED, 121156746Sroberto RAWDCF_CFLAG, 121256746Sroberto RAWDCF_IFLAG, 121356746Sroberto RAWDCF_OFLAG, 121456746Sroberto RAWDCF_LFLAG, 121556746Sroberto RAWDCF_SAMPLES, 121656746Sroberto RAWDCF_KEEP 121756746Sroberto }, 121856746Sroberto { /* mode 17 */ 121954359Sroberto VARITEXT_FLAGS, 122054359Sroberto NO_POLL, 122154359Sroberto NO_INIT, 122254359Sroberto NO_EVENT, 122354359Sroberto NO_END, 122454359Sroberto NO_MESSAGE, 122554359Sroberto NO_DATA, 122654359Sroberto VARITEXT_ROOTDELAY, 122754359Sroberto VARITEXT_BASEDELAY, 122854359Sroberto VARITEXT_ID, 122954359Sroberto VARITEXT_DESCRIPTION, 123054359Sroberto VARITEXT_FORMAT, 123154359Sroberto VARITEXT_TYPE, 123254359Sroberto VARITEXT_MAXUNSYNC, 123354359Sroberto VARITEXT_SPEED, 123454359Sroberto VARITEXT_CFLAG, 123554359Sroberto VARITEXT_IFLAG, 123654359Sroberto VARITEXT_OFLAG, 123754359Sroberto VARITEXT_LFLAG, 123854359Sroberto VARITEXT_SAMPLES, 123954359Sroberto VARITEXT_KEEP 124056746Sroberto } 124154359Sroberto}; 124254359Sroberto 124354359Srobertostatic int ncltypes = sizeof(parse_clockinfo) / sizeof(struct parse_clockinfo); 124454359Sroberto 124554359Sroberto#define CLK_REALTYPE(x) ((int)(((x)->ttl) & 0x7F)) 124654359Sroberto#define CLK_TYPE(x) ((CLK_REALTYPE(x) >= ncltypes) ? ~0 : CLK_REALTYPE(x)) 124754359Sroberto#define CLK_UNIT(x) ((int)REFCLOCKUNIT(&(x)->srcadr)) 124854359Sroberto#define CLK_PPS(x) (((x)->ttl) & 0x80) 124954359Sroberto 125054359Sroberto/* 125154359Sroberto * Other constant stuff 125254359Sroberto */ 125354359Sroberto#define PARSEHSREFID 0x7f7f08ff /* 127.127.8.255 refid for hi strata */ 125454359Sroberto 125554359Sroberto#define PARSESTATISTICS (60*60) /* output state statistics every hour */ 125654359Sroberto 125754359Srobertostatic struct parseunit *parseunits[MAXUNITS]; 125854359Sroberto 125954359Srobertostatic int notice = 0; 126054359Sroberto 126154359Sroberto#define PARSE_STATETIME(parse, i) ((parse->generic->currentstatus == i) ? parse->statetime[i] + current_time - parse->lastchange : parse->statetime[i]) 126254359Sroberto 126354359Srobertostatic void parse_event P((struct parseunit *, int)); 126454359Srobertostatic void parse_process P((struct parseunit *, parsetime_t *)); 126554359Srobertostatic void clear_err P((struct parseunit *, u_long)); 126654359Srobertostatic int list_err P((struct parseunit *, u_long)); 126754359Srobertostatic char * l_mktime P((u_long)); 126854359Sroberto 126954359Sroberto/**=========================================================================== 127054359Sroberto ** implementation error message regression module 127154359Sroberto **/ 127254359Srobertostatic void 127354359Srobertoclear_err( 127454359Sroberto struct parseunit *parse, 127554359Sroberto u_long lstate 127654359Sroberto ) 127754359Sroberto{ 127854359Sroberto if (lstate == ERR_ALL) 127954359Sroberto { 128054359Sroberto int i; 128154359Sroberto 128254359Sroberto for (i = 0; i < ERR_CNT; i++) 128354359Sroberto { 128454359Sroberto parse->errors[i].err_stage = err_tbl[i]; 128554359Sroberto parse->errors[i].err_cnt = 0; 128654359Sroberto parse->errors[i].err_last = 0; 128754359Sroberto parse->errors[i].err_started = 0; 128854359Sroberto parse->errors[i].err_suppressed = 0; 128954359Sroberto } 129054359Sroberto } 129154359Sroberto else 129254359Sroberto { 129354359Sroberto parse->errors[lstate].err_stage = err_tbl[lstate]; 129454359Sroberto parse->errors[lstate].err_cnt = 0; 129554359Sroberto parse->errors[lstate].err_last = 0; 129654359Sroberto parse->errors[lstate].err_started = 0; 129754359Sroberto parse->errors[lstate].err_suppressed = 0; 129854359Sroberto } 129954359Sroberto} 130054359Sroberto 130154359Srobertostatic int 130254359Srobertolist_err( 130354359Sroberto struct parseunit *parse, 130454359Sroberto u_long lstate 130554359Sroberto ) 130654359Sroberto{ 130754359Sroberto int do_it; 130854359Sroberto struct errorinfo *err = &parse->errors[lstate]; 130954359Sroberto 131054359Sroberto if (err->err_started == 0) 131154359Sroberto { 131254359Sroberto err->err_started = current_time; 131354359Sroberto } 131454359Sroberto 131554359Sroberto do_it = (current_time - err->err_last) >= err->err_stage->err_delay; 131654359Sroberto 131754359Sroberto if (do_it) 131854359Sroberto err->err_cnt++; 131954359Sroberto 132054359Sroberto if (err->err_stage->err_count && 132154359Sroberto (err->err_cnt >= err->err_stage->err_count)) 132254359Sroberto { 132354359Sroberto err->err_stage++; 132454359Sroberto err->err_cnt = 0; 132554359Sroberto } 132654359Sroberto 132754359Sroberto if (!err->err_cnt && do_it) 132854359Sroberto msyslog(LOG_INFO, "PARSE receiver #%d: interval for following error message class is at least %s", 132954359Sroberto CLK_UNIT(parse->peer), l_mktime(err->err_stage->err_delay)); 133054359Sroberto 133154359Sroberto if (!do_it) 133254359Sroberto err->err_suppressed++; 133354359Sroberto else 133454359Sroberto err->err_last = current_time; 133554359Sroberto 133654359Sroberto if (do_it && err->err_suppressed) 133754359Sroberto { 133854359Sroberto msyslog(LOG_INFO, "PARSE receiver #%d: %ld message%s suppressed, error condition class persists for %s", 133954359Sroberto CLK_UNIT(parse->peer), err->err_suppressed, (err->err_suppressed == 1) ? " was" : "s where", 134054359Sroberto l_mktime(current_time - err->err_started)); 134154359Sroberto err->err_suppressed = 0; 134254359Sroberto } 134354359Sroberto 134454359Sroberto return do_it; 134554359Sroberto} 134654359Sroberto 134754359Sroberto/*-------------------------------------------------- 134854359Sroberto * mkreadable - make a printable ascii string (without 134954359Sroberto * embedded quotes so that the ntpq protocol isn't 135054359Sroberto * fooled 135154359Sroberto */ 135254359Sroberto#ifndef isprint 135354359Sroberto#define isprint(_X_) (((_X_) > 0x1F) && ((_X_) < 0x7F)) 135454359Sroberto#endif 135554359Sroberto 135654359Srobertostatic char * 135754359Srobertomkreadable( 135854359Sroberto char *buffer, 135954359Sroberto long blen, 136054359Sroberto const char *src, 136154359Sroberto u_long srclen, 136254359Sroberto int hex 136354359Sroberto ) 136454359Sroberto{ 136554359Sroberto char *b = buffer; 136654359Sroberto char *endb = (char *)0; 136754359Sroberto 136854359Sroberto if (blen < 4) 136954359Sroberto return (char *)0; /* don't bother with mini buffers */ 137054359Sroberto 137154359Sroberto endb = buffer + blen - 4; 137254359Sroberto 137354359Sroberto blen--; /* account for '\0' */ 137454359Sroberto 137554359Sroberto while (blen && srclen--) 137654359Sroberto { 137754359Sroberto if (!hex && /* no binary only */ 137854359Sroberto (*src != '\\') && /* no plain \ */ 137954359Sroberto (*src != '"') && /* no " */ 138054359Sroberto isprint((int)*src)) /* only printables */ 138154359Sroberto { /* they are easy... */ 138254359Sroberto *buffer++ = *src++; 138354359Sroberto blen--; 138454359Sroberto } 138554359Sroberto else 138654359Sroberto { 138754359Sroberto if (blen < 4) 138854359Sroberto { 138954359Sroberto while (blen--) 139054359Sroberto { 139154359Sroberto *buffer++ = '.'; 139254359Sroberto } 139354359Sroberto *buffer = '\0'; 139454359Sroberto return b; 139554359Sroberto } 139654359Sroberto else 139754359Sroberto { 139854359Sroberto if (*src == '\\') 139954359Sroberto { 140054359Sroberto strcpy(buffer,"\\\\"); 140154359Sroberto buffer += 2; 140254359Sroberto blen -= 2; 140354359Sroberto src++; 140454359Sroberto } 140554359Sroberto else 140654359Sroberto { 140754359Sroberto sprintf(buffer, "\\x%02x", *src++); 140854359Sroberto blen -= 4; 140954359Sroberto buffer += 4; 141054359Sroberto } 141154359Sroberto } 141254359Sroberto } 141354359Sroberto if (srclen && !blen && endb) /* overflow - set last chars to ... */ 141454359Sroberto strcpy(endb, "..."); 141554359Sroberto } 141654359Sroberto 141754359Sroberto *buffer = '\0'; 141854359Sroberto return b; 141954359Sroberto} 142054359Sroberto 142154359Sroberto 142254359Sroberto/*-------------------------------------------------- 142354359Sroberto * mkascii - make a printable ascii string 142454359Sroberto * assumes (unless defined better) 7-bit ASCII 142554359Sroberto */ 142654359Srobertostatic char * 142754359Srobertomkascii( 142854359Sroberto char *buffer, 142954359Sroberto long blen, 143054359Sroberto const char *src, 143154359Sroberto u_long srclen 143254359Sroberto ) 143354359Sroberto{ 143454359Sroberto return mkreadable(buffer, blen, src, srclen, 0); 143554359Sroberto} 143654359Sroberto 143754359Sroberto/**=========================================================================== 143854359Sroberto ** implementation of i/o handling methods 143954359Sroberto ** (all STREAM, partial STREAM, user level) 144054359Sroberto **/ 144154359Sroberto 144254359Sroberto/* 144354359Sroberto * define possible io handling methods 144454359Sroberto */ 144554359Sroberto#ifdef STREAM 144654359Srobertostatic int ppsclock_init P((struct parseunit *)); 144754359Srobertostatic int stream_init P((struct parseunit *)); 144854359Srobertostatic void stream_end P((struct parseunit *)); 144954359Srobertostatic int stream_enable P((struct parseunit *)); 145054359Srobertostatic int stream_disable P((struct parseunit *)); 145154359Srobertostatic int stream_setcs P((struct parseunit *, parsectl_t *)); 145254359Srobertostatic int stream_getfmt P((struct parseunit *, parsectl_t *)); 145354359Srobertostatic int stream_setfmt P((struct parseunit *, parsectl_t *)); 145454359Srobertostatic int stream_timecode P((struct parseunit *, parsectl_t *)); 145554359Srobertostatic void stream_receive P((struct recvbuf *)); 145654359Sroberto#endif 145754359Sroberto 145854359Srobertostatic int local_init P((struct parseunit *)); 145954359Srobertostatic void local_end P((struct parseunit *)); 146054359Srobertostatic int local_nop P((struct parseunit *)); 146154359Srobertostatic int local_setcs P((struct parseunit *, parsectl_t *)); 146254359Srobertostatic int local_getfmt P((struct parseunit *, parsectl_t *)); 146354359Srobertostatic int local_setfmt P((struct parseunit *, parsectl_t *)); 146454359Srobertostatic int local_timecode P((struct parseunit *, parsectl_t *)); 146554359Srobertostatic void local_receive P((struct recvbuf *)); 146654359Srobertostatic int local_input P((struct recvbuf *)); 146754359Sroberto 146854359Srobertostatic bind_t io_bindings[] = 146954359Sroberto{ 147054359Sroberto#ifdef STREAM 147154359Sroberto { 147254359Sroberto "parse STREAM", 147354359Sroberto stream_init, 147454359Sroberto stream_end, 147554359Sroberto stream_setcs, 147654359Sroberto stream_disable, 147754359Sroberto stream_enable, 147854359Sroberto stream_getfmt, 147954359Sroberto stream_setfmt, 148054359Sroberto stream_timecode, 148154359Sroberto stream_receive, 148254359Sroberto 0, 148354359Sroberto }, 148454359Sroberto { 148554359Sroberto "ppsclock STREAM", 148654359Sroberto ppsclock_init, 148754359Sroberto local_end, 148854359Sroberto local_setcs, 148954359Sroberto local_nop, 149054359Sroberto local_nop, 149154359Sroberto local_getfmt, 149254359Sroberto local_setfmt, 149354359Sroberto local_timecode, 149454359Sroberto local_receive, 149554359Sroberto local_input, 149654359Sroberto }, 149754359Sroberto#endif 149854359Sroberto { 149954359Sroberto "normal", 150054359Sroberto local_init, 150154359Sroberto local_end, 150254359Sroberto local_setcs, 150354359Sroberto local_nop, 150454359Sroberto local_nop, 150554359Sroberto local_getfmt, 150654359Sroberto local_setfmt, 150754359Sroberto local_timecode, 150854359Sroberto local_receive, 150954359Sroberto local_input, 151054359Sroberto }, 151154359Sroberto { 151254359Sroberto (char *)0, 151354359Sroberto } 151454359Sroberto}; 151554359Sroberto 151654359Sroberto#ifdef STREAM 151754359Sroberto 151854359Sroberto#define fix_ts(_X_) \ 151954359Sroberto if ((&(_X_))->tv.tv_usec >= 1000000) \ 152054359Sroberto { \ 152154359Sroberto (&(_X_))->tv.tv_usec -= 1000000; \ 152254359Sroberto (&(_X_))->tv.tv_sec += 1; \ 152354359Sroberto } 152454359Sroberto 152554359Sroberto#define cvt_ts(_X_, _Y_) \ 152654359Sroberto { \ 152754359Sroberto l_fp ts; \ 152854359Sroberto fix_ts((_X_)); \ 152954359Sroberto if (!buftvtots((const char *)&(&(_X_))->tv, &ts)) \ 153054359Sroberto { \ 153154359Sroberto ERR(ERR_BADDATA) \ 153254359Sroberto msyslog(LOG_ERR,"parse: stream_receive: timestamp conversion error (buftvtots) (%s) (%ld.%06ld) ", (_Y_), (long)(&(_X_))->tv.tv_sec, (long)(&(_X_))->tv.tv_usec);\ 153354359Sroberto return; \ 153454359Sroberto } \ 153554359Sroberto else \ 153654359Sroberto { \ 153754359Sroberto (&(_X_))->fp = ts; \ 153854359Sroberto } \ 153954359Sroberto } 154054359Sroberto 154154359Sroberto/*-------------------------------------------------- 154254359Sroberto * ppsclock STREAM init 154354359Sroberto */ 154454359Srobertostatic int 154554359Srobertoppsclock_init( 154654359Sroberto struct parseunit *parse 154754359Sroberto ) 154854359Sroberto{ 154954359Sroberto static char m1[] = "ppsclocd"; 155054359Sroberto static char m2[] = "ppsclock"; 155154359Sroberto 155254359Sroberto /* 155354359Sroberto * now push the parse streams module 155454359Sroberto * it will ensure exclusive access to the device 155554359Sroberto */ 155654359Sroberto if (ioctl(parse->generic->io.fd, I_PUSH, (caddr_t)m1) == -1 && 155754359Sroberto ioctl(parse->generic->io.fd, I_PUSH, (caddr_t)m2) == -1) 155854359Sroberto { 155954359Sroberto if (errno != EINVAL) 156056746Sroberto { 156156746Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: ppsclock_init: ioctl(fd, I_PUSH, \"ppsclock\"): %m", 156256746Sroberto CLK_UNIT(parse->peer)); 156354359Sroberto } 156454359Sroberto return 0; 156554359Sroberto } 156654359Sroberto if (!local_init(parse)) 156754359Sroberto { 156854359Sroberto (void)ioctl(parse->generic->io.fd, I_POP, (caddr_t)0); 156954359Sroberto return 0; 157054359Sroberto } 157154359Sroberto 157254359Sroberto parse->flags |= PARSE_PPSCLOCK; 157354359Sroberto return 1; 157454359Sroberto} 157554359Sroberto 157654359Sroberto/*-------------------------------------------------- 157754359Sroberto * parse STREAM init 157854359Sroberto */ 157954359Srobertostatic int 158054359Srobertostream_init( 158154359Sroberto struct parseunit *parse 158254359Sroberto ) 158354359Sroberto{ 158454359Sroberto static char m1[] = "parse"; 158554359Sroberto /* 158654359Sroberto * now push the parse streams module 158754359Sroberto * to test whether it is there (neat interface 8-( ) 158854359Sroberto */ 158954359Sroberto if (ioctl(parse->generic->io.fd, I_PUSH, (caddr_t)m1) == -1) 159054359Sroberto { 159154359Sroberto if (errno != EINVAL) /* accept non-existence */ 159256746Sroberto { 159356746Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: stream_init: ioctl(fd, I_PUSH, \"parse\"): %m", CLK_UNIT(parse->peer)); 159454359Sroberto } 159554359Sroberto return 0; 159654359Sroberto } 159754359Sroberto else 159854359Sroberto { 159954359Sroberto while(ioctl(parse->generic->io.fd, I_POP, (caddr_t)0) == 0) 160054359Sroberto /* empty loop */; 160154359Sroberto 160254359Sroberto /* 160354359Sroberto * now push it a second time after we have removed all 160454359Sroberto * module garbage 160554359Sroberto */ 160654359Sroberto if (ioctl(parse->generic->io.fd, I_PUSH, (caddr_t)m1) == -1) 160754359Sroberto { 160854359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: stream_init: ioctl(fd, I_PUSH, \"parse\"): %m", CLK_UNIT(parse->peer)); 160954359Sroberto return 0; 161054359Sroberto } 161154359Sroberto else 161254359Sroberto { 161354359Sroberto return 1; 161454359Sroberto } 161554359Sroberto } 161654359Sroberto} 161754359Sroberto 161854359Sroberto/*-------------------------------------------------- 161954359Sroberto * parse STREAM end 162054359Sroberto */ 162154359Srobertostatic void 162254359Srobertostream_end( 162354359Sroberto struct parseunit *parse 162454359Sroberto ) 162554359Sroberto{ 162654359Sroberto while(ioctl(parse->generic->io.fd, I_POP, (caddr_t)0) == 0) 162754359Sroberto /* empty loop */; 162854359Sroberto} 162954359Sroberto 163054359Sroberto/*-------------------------------------------------- 163154359Sroberto * STREAM setcs 163254359Sroberto */ 163354359Srobertostatic int 163454359Srobertostream_setcs( 163554359Sroberto struct parseunit *parse, 163654359Sroberto parsectl_t *tcl 163754359Sroberto ) 163854359Sroberto{ 163954359Sroberto struct strioctl strioc; 164054359Sroberto 164154359Sroberto strioc.ic_cmd = PARSEIOC_SETCS; 164254359Sroberto strioc.ic_timout = 0; 164354359Sroberto strioc.ic_dp = (char *)tcl; 164454359Sroberto strioc.ic_len = sizeof (*tcl); 164554359Sroberto 164654359Sroberto if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1) 164754359Sroberto { 164854359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: stream_setcs: ioctl(fd, I_STR, PARSEIOC_SETCS): %m", CLK_UNIT(parse->peer)); 164954359Sroberto return 0; 165054359Sroberto } 165154359Sroberto return 1; 165254359Sroberto} 165354359Sroberto 165454359Sroberto/*-------------------------------------------------- 165554359Sroberto * STREAM enable 165654359Sroberto */ 165754359Srobertostatic int 165854359Srobertostream_enable( 165954359Sroberto struct parseunit *parse 166054359Sroberto ) 166154359Sroberto{ 166254359Sroberto struct strioctl strioc; 166354359Sroberto 166454359Sroberto strioc.ic_cmd = PARSEIOC_ENABLE; 166554359Sroberto strioc.ic_timout = 0; 166654359Sroberto strioc.ic_dp = (char *)0; 166754359Sroberto strioc.ic_len = 0; 166854359Sroberto 166954359Sroberto if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1) 167054359Sroberto { 167154359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: stream_enable: ioctl(fd, I_STR, PARSEIOC_ENABLE): %m", CLK_UNIT(parse->peer)); 167254359Sroberto return 0; 167354359Sroberto } 167454359Sroberto parse->generic->io.clock_recv = stream_receive; /* ok - parse input in kernel */ 167554359Sroberto return 1; 167654359Sroberto} 167754359Sroberto 167854359Sroberto/*-------------------------------------------------- 167954359Sroberto * STREAM disable 168054359Sroberto */ 168154359Srobertostatic int 168254359Srobertostream_disable( 168354359Sroberto struct parseunit *parse 168454359Sroberto ) 168554359Sroberto{ 168654359Sroberto struct strioctl strioc; 168754359Sroberto 168854359Sroberto strioc.ic_cmd = PARSEIOC_DISABLE; 168954359Sroberto strioc.ic_timout = 0; 169054359Sroberto strioc.ic_dp = (char *)0; 169154359Sroberto strioc.ic_len = 0; 169254359Sroberto 169354359Sroberto if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1) 169454359Sroberto { 169554359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: stream_disable: ioctl(fd, I_STR, PARSEIOC_DISABLE): %m", CLK_UNIT(parse->peer)); 169654359Sroberto return 0; 169754359Sroberto } 169854359Sroberto parse->generic->io.clock_recv = local_receive; /* ok - parse input in daemon */ 169954359Sroberto return 1; 170054359Sroberto} 170154359Sroberto 170254359Sroberto/*-------------------------------------------------- 170354359Sroberto * STREAM getfmt 170454359Sroberto */ 170554359Srobertostatic int 170654359Srobertostream_getfmt( 170754359Sroberto struct parseunit *parse, 170854359Sroberto parsectl_t *tcl 170954359Sroberto ) 171054359Sroberto{ 171154359Sroberto struct strioctl strioc; 171254359Sroberto 171354359Sroberto strioc.ic_cmd = PARSEIOC_GETFMT; 171454359Sroberto strioc.ic_timout = 0; 171554359Sroberto strioc.ic_dp = (char *)tcl; 171654359Sroberto strioc.ic_len = sizeof (*tcl); 171754359Sroberto if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1) 171854359Sroberto { 171954359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: ioctl(fd, I_STR, PARSEIOC_GETFMT): %m", CLK_UNIT(parse->peer)); 172054359Sroberto return 0; 172154359Sroberto } 172254359Sroberto return 1; 172354359Sroberto} 172454359Sroberto 172554359Sroberto/*-------------------------------------------------- 172654359Sroberto * STREAM setfmt 172754359Sroberto */ 172854359Srobertostatic int 172954359Srobertostream_setfmt( 173054359Sroberto struct parseunit *parse, 173154359Sroberto parsectl_t *tcl 173254359Sroberto ) 173354359Sroberto{ 173454359Sroberto struct strioctl strioc; 173554359Sroberto 173654359Sroberto strioc.ic_cmd = PARSEIOC_SETFMT; 173754359Sroberto strioc.ic_timout = 0; 173854359Sroberto strioc.ic_dp = (char *)tcl; 173954359Sroberto strioc.ic_len = sizeof (*tcl); 174054359Sroberto 174154359Sroberto if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1) 174254359Sroberto { 174354359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: stream_setfmt: ioctl(fd, I_STR, PARSEIOC_SETFMT): %m", CLK_UNIT(parse->peer)); 174454359Sroberto return 0; 174554359Sroberto } 174654359Sroberto return 1; 174754359Sroberto} 174854359Sroberto 174954359Sroberto 175054359Sroberto/*-------------------------------------------------- 175154359Sroberto * STREAM timecode 175254359Sroberto */ 175354359Srobertostatic int 175454359Srobertostream_timecode( 175554359Sroberto struct parseunit *parse, 175654359Sroberto parsectl_t *tcl 175754359Sroberto ) 175854359Sroberto{ 175954359Sroberto struct strioctl strioc; 176054359Sroberto 176154359Sroberto strioc.ic_cmd = PARSEIOC_TIMECODE; 176254359Sroberto strioc.ic_timout = 0; 176354359Sroberto strioc.ic_dp = (char *)tcl; 176454359Sroberto strioc.ic_len = sizeof (*tcl); 176554359Sroberto 176654359Sroberto if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1) 176754359Sroberto { 176854359Sroberto ERR(ERR_INTERNAL) 176954359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: stream_timecode: ioctl(fd, I_STR, PARSEIOC_TIMECODE): %m", CLK_UNIT(parse->peer)); 177054359Sroberto return 0; 177154359Sroberto } 177254359Sroberto clear_err(parse, ERR_INTERNAL); 177354359Sroberto return 1; 177454359Sroberto} 177554359Sroberto 177654359Sroberto/*-------------------------------------------------- 177754359Sroberto * STREAM receive 177854359Sroberto */ 177954359Srobertostatic void 178054359Srobertostream_receive( 178154359Sroberto struct recvbuf *rbufp 178254359Sroberto ) 178354359Sroberto{ 178454359Sroberto struct parseunit *parse = (struct parseunit *)((void *)rbufp->recv_srcclock); 178554359Sroberto parsetime_t parsetime; 178654359Sroberto 178754359Sroberto if (!parse->peer) 178854359Sroberto return; 178954359Sroberto 179054359Sroberto if (rbufp->recv_length != sizeof(parsetime_t)) 179154359Sroberto { 179254359Sroberto ERR(ERR_BADIO) 179354359Sroberto msyslog(LOG_ERR,"PARSE receiver #%d: stream_receive: bad size (got %d expected %d)", 179454359Sroberto CLK_UNIT(parse->peer), rbufp->recv_length, (int)sizeof(parsetime_t)); 179554359Sroberto parse->generic->baddata++; 179654359Sroberto parse_event(parse, CEVNT_BADREPLY); 179754359Sroberto return; 179854359Sroberto } 179954359Sroberto clear_err(parse, ERR_BADIO); 180054359Sroberto 180154359Sroberto memmove((caddr_t)&parsetime, 180254359Sroberto (caddr_t)rbufp->recv_buffer, 180354359Sroberto sizeof(parsetime_t)); 180454359Sroberto 180554359Sroberto#ifdef DEBUG 180654359Sroberto if (debug > 3) 180754359Sroberto { 180854359Sroberto printf("PARSE receiver #%d: status %06x, state %08x, time %lx.%08lx, stime %lx.%08lx, ptime %lx.%08lx\n", 180954359Sroberto CLK_UNIT(parse->peer), 181054359Sroberto (unsigned int)parsetime.parse_status, 181154359Sroberto (unsigned int)parsetime.parse_state, 181254359Sroberto (long)parsetime.parse_time.tv.tv_sec, 181354359Sroberto (long)parsetime.parse_time.tv.tv_usec, 181454359Sroberto (long)parsetime.parse_stime.tv.tv_sec, 181554359Sroberto (long)parsetime.parse_stime.tv.tv_usec, 181654359Sroberto (long)parsetime.parse_ptime.tv.tv_sec, 181754359Sroberto (long)parsetime.parse_ptime.tv.tv_usec); 181854359Sroberto } 181954359Sroberto#endif 182054359Sroberto 182154359Sroberto /* 182254359Sroberto * switch time stamp world - be sure to normalize small usec field 182354359Sroberto * errors. 182454359Sroberto */ 182554359Sroberto 182654359Sroberto cvt_ts(parsetime.parse_stime, "parse_stime"); 182754359Sroberto 182854359Sroberto if (PARSE_TIMECODE(parsetime.parse_state)) 182954359Sroberto { 183054359Sroberto cvt_ts(parsetime.parse_time, "parse_time"); 183154359Sroberto } 183254359Sroberto 183354359Sroberto if (PARSE_PPS(parsetime.parse_state)) 183454359Sroberto cvt_ts(parsetime.parse_ptime, "parse_ptime"); 183554359Sroberto 183654359Sroberto parse_process(parse, &parsetime); 183754359Sroberto} 183854359Sroberto#endif 183954359Sroberto 184054359Sroberto/*-------------------------------------------------- 184154359Sroberto * local init 184254359Sroberto */ 184354359Srobertostatic int 184454359Srobertolocal_init( 184554359Sroberto struct parseunit *parse 184654359Sroberto ) 184754359Sroberto{ 184854359Sroberto return parse_ioinit(&parse->parseio); 184954359Sroberto} 185054359Sroberto 185154359Sroberto/*-------------------------------------------------- 185254359Sroberto * local end 185354359Sroberto */ 185454359Srobertostatic void 185554359Srobertolocal_end( 185654359Sroberto struct parseunit *parse 185754359Sroberto ) 185854359Sroberto{ 185954359Sroberto parse_ioend(&parse->parseio); 186054359Sroberto} 186154359Sroberto 186254359Sroberto 186354359Sroberto/*-------------------------------------------------- 186454359Sroberto * local nop 186554359Sroberto */ 186654359Srobertostatic int 186754359Srobertolocal_nop( 186854359Sroberto struct parseunit *parse 186954359Sroberto ) 187054359Sroberto{ 187154359Sroberto return 1; 187254359Sroberto} 187354359Sroberto 187454359Sroberto/*-------------------------------------------------- 187554359Sroberto * local setcs 187654359Sroberto */ 187754359Srobertostatic int 187854359Srobertolocal_setcs( 187954359Sroberto struct parseunit *parse, 188054359Sroberto parsectl_t *tcl 188154359Sroberto ) 188254359Sroberto{ 188354359Sroberto return parse_setcs(tcl, &parse->parseio); 188454359Sroberto} 188554359Sroberto 188654359Sroberto/*-------------------------------------------------- 188754359Sroberto * local getfmt 188854359Sroberto */ 188954359Srobertostatic int 189054359Srobertolocal_getfmt( 189154359Sroberto struct parseunit *parse, 189254359Sroberto parsectl_t *tcl 189354359Sroberto ) 189454359Sroberto{ 189554359Sroberto return parse_getfmt(tcl, &parse->parseio); 189654359Sroberto} 189754359Sroberto 189854359Sroberto/*-------------------------------------------------- 189954359Sroberto * local setfmt 190054359Sroberto */ 190154359Srobertostatic int 190254359Srobertolocal_setfmt( 190354359Sroberto struct parseunit *parse, 190454359Sroberto parsectl_t *tcl 190554359Sroberto ) 190654359Sroberto{ 190754359Sroberto return parse_setfmt(tcl, &parse->parseio); 190854359Sroberto} 190954359Sroberto 191054359Sroberto/*-------------------------------------------------- 191154359Sroberto * local timecode 191254359Sroberto */ 191354359Srobertostatic int 191454359Srobertolocal_timecode( 191554359Sroberto struct parseunit *parse, 191654359Sroberto parsectl_t *tcl 191754359Sroberto ) 191854359Sroberto{ 191954359Sroberto return parse_timecode(tcl, &parse->parseio); 192054359Sroberto} 192154359Sroberto 192254359Sroberto 192354359Sroberto/*-------------------------------------------------- 192454359Sroberto * local input 192554359Sroberto */ 192654359Srobertostatic int 192754359Srobertolocal_input( 192854359Sroberto struct recvbuf *rbufp 192954359Sroberto ) 193054359Sroberto{ 193154359Sroberto struct parseunit *parse = (struct parseunit *)((void *)rbufp->recv_srcclock); 193254359Sroberto int count; 193354359Sroberto unsigned char *s; 193454359Sroberto timestamp_t ts; 193554359Sroberto 193654359Sroberto if (!parse->peer) 193754359Sroberto return 0; 193854359Sroberto 193954359Sroberto /* 194054359Sroberto * eat all characters, parsing then and feeding complete samples 194154359Sroberto */ 194254359Sroberto count = rbufp->recv_length; 194354359Sroberto s = (unsigned char *)rbufp->recv_buffer; 194454359Sroberto ts.fp = rbufp->recv_time; 194554359Sroberto 194654359Sroberto while (count--) 194754359Sroberto { 194854359Sroberto if (parse_ioread(&parse->parseio, (unsigned int)(*s++), &ts)) 194954359Sroberto { 195054359Sroberto struct recvbuf buf; 195154359Sroberto 195254359Sroberto /* 195354359Sroberto * got something good to eat 195454359Sroberto */ 195554359Sroberto if (!PARSE_PPS(parse->parseio.parse_dtime.parse_state)) 195654359Sroberto { 195754359Sroberto#ifdef TIOCDCDTIMESTAMP 195854359Sroberto struct timeval dcd_time; 195954359Sroberto 196054359Sroberto if (ioctl(rbufp->fd, TIOCDCDTIMESTAMP, &dcd_time) != -1) 196154359Sroberto { 196254359Sroberto l_fp tstmp; 196354359Sroberto 196454359Sroberto TVTOTS(&dcd_time, &tstmp); 196554359Sroberto tstmp.l_ui += JAN_1970; 196654359Sroberto L_SUB(&ts.fp, &tstmp); 196754359Sroberto if (ts.fp.l_ui == 0) 196854359Sroberto { 196954359Sroberto#ifdef DEBUG 197054359Sroberto if (debug) 197154359Sroberto { 197254359Sroberto printf( 197354359Sroberto "parse: local_receive: fd %d DCDTIMESTAMP %s\n", 197454359Sroberto rbufp->fd, 197554359Sroberto lfptoa(&tstmp, 6)); 197654359Sroberto printf(" sigio %s\n", 197754359Sroberto lfptoa(&ts.fp, 6)); 197854359Sroberto } 197954359Sroberto#endif 198054359Sroberto parse->parseio.parse_dtime.parse_ptime.fp = tstmp; 198154359Sroberto parse->parseio.parse_dtime.parse_state |= PARSEB_PPS|PARSEB_S_PPS; 198254359Sroberto } 198354359Sroberto } 198454359Sroberto#else /* TIOCDCDTIMESTAMP */ 198554359Sroberto#if defined(HAVE_STRUCT_PPSCLOCKEV) && (defined(HAVE_CIOGETEV) || defined(HAVE_TIOCGPPSEV)) 198654359Sroberto if (parse->flags & PARSE_PPSCLOCK) 198754359Sroberto { 198854359Sroberto l_fp tts; 198954359Sroberto struct ppsclockev ev; 199054359Sroberto 199154359Sroberto#ifdef HAVE_CIOGETEV 199254359Sroberto if (ioctl(parse->generic->io.fd, CIOGETEV, (caddr_t)&ev) == 0) 199354359Sroberto#endif 199454359Sroberto#ifdef HAVE_TIOCGPPSEV 199554359Sroberto if (ioctl(parse->generic->io.fd, TIOCGPPSEV, (caddr_t)&ev) == 0) 199654359Sroberto#endif 199754359Sroberto { 199854359Sroberto if (ev.serial != parse->ppsserial) 199954359Sroberto { 200054359Sroberto /* 200154359Sroberto * add PPS time stamp if available via ppsclock module 200254359Sroberto * and not supplied already. 200354359Sroberto */ 200454359Sroberto if (!buftvtots((const char *)&ev.tv, &tts)) 200554359Sroberto { 200654359Sroberto ERR(ERR_BADDATA) 200754359Sroberto msyslog(LOG_ERR,"parse: local_receive: timestamp conversion error (buftvtots) (ppsclockev.tv)"); 200854359Sroberto } 200954359Sroberto else 201054359Sroberto { 201154359Sroberto parse->parseio.parse_dtime.parse_ptime.fp = tts; 201254359Sroberto parse->parseio.parse_dtime.parse_state |= PARSEB_PPS|PARSEB_S_PPS; 201354359Sroberto } 201454359Sroberto } 201554359Sroberto parse->ppsserial = ev.serial; 201654359Sroberto } 201754359Sroberto } 201854359Sroberto#endif 201954359Sroberto#endif /* TIOCDCDTIMESTAMP */ 202054359Sroberto } 202154359Sroberto if (count) 202254359Sroberto { /* simulate receive */ 202354359Sroberto memmove((caddr_t)buf.recv_buffer, 202454359Sroberto (caddr_t)&parse->parseio.parse_dtime, 202554359Sroberto sizeof(parsetime_t)); 202654359Sroberto parse_iodone(&parse->parseio); 202754359Sroberto buf.recv_length = sizeof(parsetime_t); 202854359Sroberto buf.recv_time = rbufp->recv_time; 202954359Sroberto buf.srcadr = rbufp->srcadr; 203054359Sroberto buf.dstadr = rbufp->dstadr; 203154359Sroberto buf.fd = rbufp->fd; 203254359Sroberto buf.next = 0; 203354359Sroberto buf.X_from_where = rbufp->X_from_where; 203454359Sroberto rbufp->receiver(&buf); 203554359Sroberto } 203654359Sroberto else 203754359Sroberto { 203856746Sroberto memmove((caddr_t)rbufp->recv_buffer, 203956746Sroberto (caddr_t)&parse->parseio.parse_dtime, 204056746Sroberto sizeof(parsetime_t)); 204156746Sroberto parse_iodone(&parse->parseio); 204254359Sroberto rbufp->recv_length = sizeof(parsetime_t); 204354359Sroberto return 1; /* got something & in place return */ 204454359Sroberto } 204554359Sroberto } 204654359Sroberto } 204754359Sroberto return 0; /* nothing to pass up */ 204854359Sroberto} 204954359Sroberto 205054359Sroberto/*-------------------------------------------------- 205154359Sroberto * local receive 205254359Sroberto */ 205354359Srobertostatic void 205454359Srobertolocal_receive( 205554359Sroberto struct recvbuf *rbufp 205654359Sroberto ) 205754359Sroberto{ 205854359Sroberto struct parseunit *parse = (struct parseunit *)((void *)rbufp->recv_srcclock); 205954359Sroberto parsetime_t parsetime; 206054359Sroberto 206154359Sroberto if (!parse->peer) 206254359Sroberto return; 206354359Sroberto 206454359Sroberto if (rbufp->recv_length != sizeof(parsetime_t)) 206554359Sroberto { 206654359Sroberto ERR(ERR_BADIO) 206754359Sroberto msyslog(LOG_ERR,"PARSE receiver #%d: local_receive: bad size (got %d expected %d)", 206854359Sroberto CLK_UNIT(parse->peer), rbufp->recv_length, (int)sizeof(parsetime_t)); 206954359Sroberto parse->generic->baddata++; 207054359Sroberto parse_event(parse, CEVNT_BADREPLY); 207154359Sroberto return; 207254359Sroberto } 207354359Sroberto clear_err(parse, ERR_BADIO); 207454359Sroberto 207554359Sroberto memmove((caddr_t)&parsetime, 207654359Sroberto (caddr_t)rbufp->recv_buffer, 207754359Sroberto sizeof(parsetime_t)); 207854359Sroberto 207954359Sroberto#ifdef DEBUG 208054359Sroberto if (debug > 3) 208154359Sroberto { 208254359Sroberto printf("PARSE receiver #%d: status %06x, state %08x, time %lx.%08lx, stime %lx.%08lx, ptime %lx.%08lx\n", 208354359Sroberto CLK_UNIT(parse->peer), 208454359Sroberto (unsigned int)parsetime.parse_status, 208554359Sroberto (unsigned int)parsetime.parse_state, 208654359Sroberto (long)parsetime.parse_time.tv.tv_sec, 208754359Sroberto (long)parsetime.parse_time.tv.tv_usec, 208854359Sroberto (long)parsetime.parse_stime.tv.tv_sec, 208954359Sroberto (long)parsetime.parse_stime.tv.tv_usec, 209054359Sroberto (long)parsetime.parse_ptime.tv.tv_sec, 209154359Sroberto (long)parsetime.parse_ptime.tv.tv_usec); 209254359Sroberto } 209354359Sroberto#endif 209454359Sroberto 209554359Sroberto parse_process(parse, &parsetime); 209654359Sroberto} 209754359Sroberto 209854359Sroberto/*-------------------------------------------------- 209954359Sroberto * init_iobinding - find and initialize lower layers 210054359Sroberto */ 210154359Srobertostatic bind_t * 210254359Srobertoinit_iobinding( 210354359Sroberto struct parseunit *parse 210454359Sroberto ) 210554359Sroberto{ 210654359Sroberto bind_t *b = io_bindings; 210754359Sroberto 210854359Sroberto while (b->bd_description != (char *)0) 210954359Sroberto { 211054359Sroberto if ((*b->bd_init)(parse)) 211154359Sroberto { 211254359Sroberto return b; 211354359Sroberto } 211454359Sroberto b++; 211554359Sroberto } 211654359Sroberto return (bind_t *)0; 211754359Sroberto} 211854359Sroberto 211954359Sroberto/**=========================================================================== 212054359Sroberto ** support routines 212154359Sroberto **/ 212254359Sroberto 212354359Sroberto/*-------------------------------------------------- 212454359Sroberto * convert a flag field to a string 212554359Sroberto */ 212654359Srobertostatic char * 212754359Srobertoparsestate( 212854359Sroberto u_long lstate, 212954359Sroberto char *buffer 213054359Sroberto ) 213154359Sroberto{ 213254359Sroberto static struct bits 213354359Sroberto { 213454359Sroberto u_long bit; 213554359Sroberto const char *name; 213654359Sroberto } flagstrings[] = 213754359Sroberto { 213856746Sroberto { PARSEB_ANNOUNCE, "DST SWITCH WARNING" }, 213956746Sroberto { PARSEB_POWERUP, "NOT SYNCHRONIZED" }, 214056746Sroberto { PARSEB_NOSYNC, "TIME CODE NOT CONFIRMED" }, 214156746Sroberto { PARSEB_DST, "DST" }, 214256746Sroberto { PARSEB_UTC, "UTC DISPLAY" }, 214356746Sroberto { PARSEB_LEAPADD, "LEAP ADD WARNING" }, 214456746Sroberto { PARSEB_LEAPDEL, "LEAP DELETE WARNING" }, 214554359Sroberto { PARSEB_LEAPSECOND, "LEAP SECOND" }, 214656746Sroberto { PARSEB_ALTERNATE, "ALTERNATE ANTENNA" }, 214756746Sroberto { PARSEB_TIMECODE, "TIME CODE" }, 214856746Sroberto { PARSEB_PPS, "PPS" }, 214956746Sroberto { PARSEB_POSITION, "POSITION" }, 215054359Sroberto { 0 } 215154359Sroberto }; 215254359Sroberto 215354359Sroberto static struct sbits 215454359Sroberto { 215554359Sroberto u_long bit; 215654359Sroberto const char *name; 215754359Sroberto } sflagstrings[] = 215854359Sroberto { 215954359Sroberto { PARSEB_S_LEAP, "LEAP INDICATION" }, 216054359Sroberto { PARSEB_S_PPS, "PPS SIGNAL" }, 216154359Sroberto { PARSEB_S_ANTENNA, "ANTENNA" }, 216254359Sroberto { PARSEB_S_POSITION, "POSITION" }, 216354359Sroberto { 0 } 216454359Sroberto }; 216554359Sroberto int i; 216654359Sroberto 216754359Sroberto *buffer = '\0'; 216854359Sroberto 216954359Sroberto i = 0; 217054359Sroberto while (flagstrings[i].bit) 217154359Sroberto { 217254359Sroberto if (flagstrings[i].bit & lstate) 217354359Sroberto { 217454359Sroberto if (buffer[0]) 217554359Sroberto strcat(buffer, "; "); 217654359Sroberto strcat(buffer, flagstrings[i].name); 217754359Sroberto } 217854359Sroberto i++; 217954359Sroberto } 218054359Sroberto 218154359Sroberto if (lstate & (PARSEB_S_LEAP|PARSEB_S_ANTENNA|PARSEB_S_PPS|PARSEB_S_POSITION)) 218254359Sroberto { 218354359Sroberto char *s, *t; 218454359Sroberto 218554359Sroberto if (buffer[0]) 218654359Sroberto strcat(buffer, "; "); 218754359Sroberto 218854359Sroberto strcat(buffer, "("); 218954359Sroberto 219054359Sroberto t = s = buffer + strlen(buffer); 219154359Sroberto 219254359Sroberto i = 0; 219354359Sroberto while (sflagstrings[i].bit) 219454359Sroberto { 219554359Sroberto if (sflagstrings[i].bit & lstate) 219654359Sroberto { 219754359Sroberto if (t != s) 219854359Sroberto { 219954359Sroberto strcpy(t, "; "); 220054359Sroberto t += 2; 220154359Sroberto } 220254359Sroberto 220354359Sroberto strcpy(t, sflagstrings[i].name); 220454359Sroberto t += strlen(t); 220554359Sroberto } 220654359Sroberto i++; 220754359Sroberto } 220854359Sroberto strcpy(t, ")"); 220954359Sroberto } 221054359Sroberto return buffer; 221154359Sroberto} 221254359Sroberto 221354359Sroberto/*-------------------------------------------------- 221454359Sroberto * convert a status flag field to a string 221554359Sroberto */ 221654359Srobertostatic char * 221754359Srobertoparsestatus( 221854359Sroberto u_long lstate, 221954359Sroberto char *buffer 222054359Sroberto ) 222154359Sroberto{ 222254359Sroberto static struct bits 222354359Sroberto { 222454359Sroberto u_long bit; 222554359Sroberto const char *name; 222654359Sroberto } flagstrings[] = 222754359Sroberto { 222854359Sroberto { CVT_OK, "CONVERSION SUCCESSFUL" }, 222954359Sroberto { CVT_NONE, "NO CONVERSION" }, 223054359Sroberto { CVT_FAIL, "CONVERSION FAILED" }, 223154359Sroberto { CVT_BADFMT, "ILLEGAL FORMAT" }, 223254359Sroberto { CVT_BADDATE, "DATE ILLEGAL" }, 223354359Sroberto { CVT_BADTIME, "TIME ILLEGAL" }, 223454359Sroberto { CVT_ADDITIONAL, "ADDITIONAL DATA" }, 223554359Sroberto { 0 } 223654359Sroberto }; 223754359Sroberto int i; 223854359Sroberto 223954359Sroberto *buffer = '\0'; 224054359Sroberto 224154359Sroberto i = 0; 224254359Sroberto while (flagstrings[i].bit) 224354359Sroberto { 224454359Sroberto if (flagstrings[i].bit & lstate) 224554359Sroberto { 224654359Sroberto if (buffer[0]) 224754359Sroberto strcat(buffer, "; "); 224854359Sroberto strcat(buffer, flagstrings[i].name); 224954359Sroberto } 225054359Sroberto i++; 225154359Sroberto } 225254359Sroberto 225354359Sroberto return buffer; 225454359Sroberto} 225554359Sroberto 225654359Sroberto/*-------------------------------------------------- 225754359Sroberto * convert a clock status flag field to a string 225854359Sroberto */ 225954359Srobertostatic const char * 226054359Srobertoclockstatus( 226154359Sroberto u_long lstate 226254359Sroberto ) 226354359Sroberto{ 226454359Sroberto static char buffer[20]; 226554359Sroberto static struct status 226654359Sroberto { 226754359Sroberto u_long value; 226854359Sroberto const char *name; 226954359Sroberto } flagstrings[] = 227054359Sroberto { 227154359Sroberto { CEVNT_NOMINAL, "NOMINAL" }, 227254359Sroberto { CEVNT_TIMEOUT, "NO RESPONSE" }, 227354359Sroberto { CEVNT_BADREPLY,"BAD FORMAT" }, 227454359Sroberto { CEVNT_FAULT, "FAULT" }, 227554359Sroberto { CEVNT_PROP, "PROPAGATION DELAY" }, 227654359Sroberto { CEVNT_BADDATE, "ILLEGAL DATE" }, 227754359Sroberto { CEVNT_BADTIME, "ILLEGAL TIME" }, 227854359Sroberto { (unsigned)~0L } 227954359Sroberto }; 228054359Sroberto int i; 228154359Sroberto 228254359Sroberto i = 0; 228354359Sroberto while (flagstrings[i].value != ~0) 228454359Sroberto { 228554359Sroberto if (flagstrings[i].value == lstate) 228654359Sroberto { 228754359Sroberto return flagstrings[i].name; 228854359Sroberto } 228954359Sroberto i++; 229054359Sroberto } 229154359Sroberto 229254359Sroberto sprintf(buffer, "unknown #%ld", (u_long)lstate); 229354359Sroberto 229454359Sroberto return buffer; 229554359Sroberto} 229654359Sroberto 229754359Sroberto 229854359Sroberto/*-------------------------------------------------- 229954359Sroberto * l_mktime - make representation of a relative time 230054359Sroberto */ 230154359Srobertostatic char * 230254359Srobertol_mktime( 230354359Sroberto u_long delta 230454359Sroberto ) 230554359Sroberto{ 230654359Sroberto u_long tmp, m, s; 230754359Sroberto static char buffer[40]; 230854359Sroberto 230954359Sroberto buffer[0] = '\0'; 231054359Sroberto 231154359Sroberto if ((tmp = delta / (60*60*24)) != 0) 231254359Sroberto { 231354359Sroberto sprintf(buffer, "%ldd+", (u_long)tmp); 231454359Sroberto delta -= tmp * 60*60*24; 231554359Sroberto } 231654359Sroberto 231754359Sroberto s = delta % 60; 231854359Sroberto delta /= 60; 231954359Sroberto m = delta % 60; 232054359Sroberto delta /= 60; 232154359Sroberto 232254359Sroberto sprintf(buffer+strlen(buffer), "%02d:%02d:%02d", 232354359Sroberto (int)delta, (int)m, (int)s); 232454359Sroberto 232554359Sroberto return buffer; 232654359Sroberto} 232754359Sroberto 232854359Sroberto 232954359Sroberto/*-------------------------------------------------- 233054359Sroberto * parse_statistics - list summary of clock states 233154359Sroberto */ 233254359Srobertostatic void 233354359Srobertoparse_statistics( 233454359Sroberto struct parseunit *parse 233554359Sroberto ) 233654359Sroberto{ 233754359Sroberto int i; 233854359Sroberto 233954359Sroberto NLOG(NLOG_CLOCKSTATIST) /* conditional if clause for conditional syslog */ 234054359Sroberto { 234154359Sroberto msyslog(LOG_INFO, "PARSE receiver #%d: running time: %s", 234254359Sroberto CLK_UNIT(parse->peer), 234354359Sroberto l_mktime(current_time - parse->generic->timestarted)); 234454359Sroberto 234554359Sroberto msyslog(LOG_INFO, "PARSE receiver #%d: current status: %s", 234654359Sroberto CLK_UNIT(parse->peer), 234754359Sroberto clockstatus(parse->generic->currentstatus)); 234854359Sroberto 234954359Sroberto for (i = 0; i <= CEVNT_MAX; i++) 235054359Sroberto { 235154359Sroberto u_long s_time; 235254359Sroberto u_long percent, d = current_time - parse->generic->timestarted; 235354359Sroberto 235454359Sroberto percent = s_time = PARSE_STATETIME(parse, i); 235554359Sroberto 235654359Sroberto while (((u_long)(~0) / 10000) < percent) 235754359Sroberto { 235854359Sroberto percent /= 10; 235954359Sroberto d /= 10; 236054359Sroberto } 236154359Sroberto 236254359Sroberto if (d) 236354359Sroberto percent = (percent * 10000) / d; 236454359Sroberto else 236554359Sroberto percent = 10000; 236654359Sroberto 236754359Sroberto if (s_time) 236854359Sroberto msyslog(LOG_INFO, "PARSE receiver #%d: state %18s: %13s (%3ld.%02ld%%)", 236954359Sroberto CLK_UNIT(parse->peer), 237054359Sroberto clockstatus((unsigned int)i), 237154359Sroberto l_mktime(s_time), 237254359Sroberto percent / 100, percent % 100); 237354359Sroberto } 237454359Sroberto } 237554359Sroberto} 237654359Sroberto 237754359Sroberto/*-------------------------------------------------- 237854359Sroberto * cparse_statistics - wrapper for statistics call 237954359Sroberto */ 238054359Srobertostatic void 238154359Srobertocparse_statistics( 238254359Sroberto register struct parseunit *parse 238354359Sroberto ) 238454359Sroberto{ 238554359Sroberto if (parse->laststatistic + PARSESTATISTICS < current_time) 238654359Sroberto parse_statistics(parse); 238754359Sroberto parse->laststatistic = current_time; 238854359Sroberto} 238954359Sroberto 239054359Sroberto/**=========================================================================== 239154359Sroberto ** ntp interface routines 239254359Sroberto **/ 239354359Sroberto 239454359Sroberto/*-------------------------------------------------- 239554359Sroberto * parse_init - initialize internal parse driver data 239654359Sroberto */ 239754359Srobertostatic void 239854359Srobertoparse_init(void) 239954359Sroberto{ 240054359Sroberto memset((caddr_t)parseunits, 0, sizeof parseunits); 240154359Sroberto} 240254359Sroberto 240354359Sroberto 240454359Sroberto/*-------------------------------------------------- 240554359Sroberto * parse_shutdown - shut down a PARSE clock 240654359Sroberto */ 240754359Srobertostatic void 240854359Srobertoparse_shutdown( 240954359Sroberto int unit, 241054359Sroberto struct peer *peer 241154359Sroberto ) 241254359Sroberto{ 241354359Sroberto struct parseunit *parse = (struct parseunit *)peer->procptr->unitptr; 241454359Sroberto 241554359Sroberto if (parse && !parse->peer) 241654359Sroberto { 241754359Sroberto msyslog(LOG_ERR, 241854359Sroberto "PARSE receiver #%d: parse_shutdown: INTERNAL ERROR, unit not in use", unit); 241954359Sroberto return; 242054359Sroberto } 242154359Sroberto 242254359Sroberto /* 242354359Sroberto * print statistics a last time and 242454359Sroberto * stop statistics machine 242554359Sroberto */ 242654359Sroberto parse_statistics(parse); 242754359Sroberto 242854359Sroberto if (parse->parse_type->cl_end) 242954359Sroberto { 243054359Sroberto parse->parse_type->cl_end(parse); 243154359Sroberto } 243254359Sroberto 243354359Sroberto if (parse->binding) 243454359Sroberto PARSE_END(parse); 243554359Sroberto 243654359Sroberto /* 243754359Sroberto * Tell the I/O module to turn us off. We're history. 243854359Sroberto */ 243954359Sroberto io_closeclock(&parse->generic->io); 244054359Sroberto 244154359Sroberto free_varlist(parse->kv); 244254359Sroberto 244354359Sroberto NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */ 244454359Sroberto msyslog(LOG_INFO, "PARSE receiver #%d: reference clock \"%s\" removed", 244554359Sroberto CLK_UNIT(parse->peer), parse->parse_type->cl_description); 244654359Sroberto 244754359Sroberto parse->peer = (struct peer *)0; /* unused now */ 244854359Sroberto free(parse); 244954359Sroberto} 245054359Sroberto 245154359Sroberto/*-------------------------------------------------- 245254359Sroberto * parse_start - open the PARSE devices and initialize data for processing 245354359Sroberto */ 245454359Srobertostatic int 245554359Srobertoparse_start( 245654359Sroberto int sysunit, 245754359Sroberto struct peer *peer 245854359Sroberto ) 245954359Sroberto{ 246054359Sroberto u_int unit; 246154359Sroberto int fd232; 246254359Sroberto#ifdef HAVE_TERMIOS 246354359Sroberto struct termios tio; /* NEEDED FOR A LONG TIME ! */ 246454359Sroberto#endif 246554359Sroberto#ifdef HAVE_SYSV_TTYS 246654359Sroberto struct termio tio; /* NEEDED FOR A LONG TIME ! */ 246754359Sroberto#endif 246854359Sroberto struct parseunit * parse; 246954359Sroberto char parsedev[sizeof(PARSEDEVICE)+20]; 247054359Sroberto parsectl_t tmp_ctl; 247154359Sroberto u_int type; 247254359Sroberto 247354359Sroberto type = CLK_TYPE(peer); 247454359Sroberto unit = CLK_UNIT(peer); 247554359Sroberto 247654359Sroberto if ((type == ~0) || (parse_clockinfo[type].cl_description == (char *)0)) 247754359Sroberto { 247854359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: unsupported clock type %d (max %d)", 247954359Sroberto unit, CLK_REALTYPE(peer), ncltypes-1); 248054359Sroberto return 0; 248154359Sroberto } 248254359Sroberto 248354359Sroberto /* 248454359Sroberto * Unit okay, attempt to open the device. 248554359Sroberto */ 248654359Sroberto (void) sprintf(parsedev, PARSEDEVICE, unit); 248754359Sroberto 248854359Sroberto#ifndef O_NOCTTY 248954359Sroberto#define O_NOCTTY 0 249054359Sroberto#endif 249154359Sroberto 249254359Sroberto fd232 = open(parsedev, O_RDWR | O_NOCTTY 249354359Sroberto#ifdef O_NONBLOCK 249454359Sroberto | O_NONBLOCK 249554359Sroberto#endif 249654359Sroberto , 0777); 249754359Sroberto 249854359Sroberto if (fd232 == -1) 249954359Sroberto { 250054359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: open of %s failed: %m", unit, parsedev); 250154359Sroberto return 0; 250254359Sroberto } 250354359Sroberto 250454359Sroberto parse = (struct parseunit *)emalloc(sizeof(struct parseunit)); 250554359Sroberto 250654359Sroberto memset((char *)parse, 0, sizeof(struct parseunit)); 250754359Sroberto 250854359Sroberto parse->generic = peer->procptr; /* link up */ 250954359Sroberto parse->generic->unitptr = (caddr_t)parse; /* link down */ 251054359Sroberto 251154359Sroberto /* 251254359Sroberto * Set up the structures 251354359Sroberto */ 251454359Sroberto parse->generic->timestarted = current_time; 251554359Sroberto parse->lastchange = current_time; 251654359Sroberto 251754359Sroberto parse->generic->currentstatus = CEVNT_TIMEOUT; /* expect the worst */ 251854359Sroberto 251954359Sroberto parse->flags = 0; 252054359Sroberto parse->pollneeddata = 0; 252154359Sroberto parse->laststatistic = current_time; 252254359Sroberto parse->lastformat = (unsigned short)~0; /* assume no format known */ 252354359Sroberto parse->time.parse_status = (unsigned short)~0; /* be sure to mark initial status change */ 252454359Sroberto parse->lastmissed = 0; /* assume got everything */ 252554359Sroberto parse->ppsserial = 0; 252654359Sroberto parse->localdata = (void *)0; 252754359Sroberto parse->localstate = 0; 252854359Sroberto parse->kv = (struct ctl_var *)0; 252954359Sroberto 253054359Sroberto clear_err(parse, ERR_ALL); 253154359Sroberto 253254359Sroberto parse->parse_type = &parse_clockinfo[type]; 253354359Sroberto 253454359Sroberto parse->generic->fudgetime1 = parse->parse_type->cl_basedelay; 253554359Sroberto 253654359Sroberto parse->generic->fudgetime2 = 0.0; 253754359Sroberto 253854359Sroberto parse->generic->clockdesc = parse->parse_type->cl_description; 253954359Sroberto 254054359Sroberto peer->rootdelay = parse->parse_type->cl_rootdelay; 254154359Sroberto peer->sstclktype = parse->parse_type->cl_type; 254254359Sroberto peer->precision = sys_precision; 254354359Sroberto 254454359Sroberto peer->stratum = STRATUM_REFCLOCK; 254554359Sroberto if (peer->stratum <= 1) 254654359Sroberto memmove((char *)&parse->generic->refid, parse->parse_type->cl_id, 4); 254754359Sroberto else 254854359Sroberto parse->generic->refid = htonl(PARSEHSREFID); 254954359Sroberto 255054359Sroberto parse->generic->io.fd = fd232; 255154359Sroberto 255254359Sroberto parse->peer = peer; /* marks it also as busy */ 255354359Sroberto 255454359Sroberto /* 255554359Sroberto * configure terminal line 255654359Sroberto */ 255754359Sroberto if (TTY_GETATTR(fd232, &tio) == -1) 255854359Sroberto { 255954359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: tcgetattr(%d, &tio): %m", unit, fd232); 256054359Sroberto parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */ 256154359Sroberto return 0; 256254359Sroberto } 256354359Sroberto else 256454359Sroberto { 256554359Sroberto#ifndef _PC_VDISABLE 256654359Sroberto memset((char *)tio.c_cc, 0, sizeof(tio.c_cc)); 256754359Sroberto#else 256854359Sroberto int disablec; 256954359Sroberto errno = 0; /* pathconf can deliver -1 without changing errno ! */ 257054359Sroberto 257154359Sroberto disablec = fpathconf(parse->generic->io.fd, _PC_VDISABLE); 257254359Sroberto if (disablec == -1 && errno) 257354359Sroberto { 257454359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: fpathconf(fd, _PC_VDISABLE): %m", CLK_UNIT(parse->peer)); 257554359Sroberto memset((char *)tio.c_cc, 0, sizeof(tio.c_cc)); /* best guess */ 257654359Sroberto } 257754359Sroberto else 257854359Sroberto if (disablec != -1) 257954359Sroberto memset((char *)tio.c_cc, disablec, sizeof(tio.c_cc)); 258054359Sroberto#endif 258154359Sroberto 258254359Sroberto#if defined (VMIN) || defined(VTIME) 258354359Sroberto if ((parse_clockinfo[type].cl_lflag & ICANON) == 0) 258454359Sroberto { 258554359Sroberto#ifdef VMIN 258654359Sroberto tio.c_cc[VMIN] = 1; 258754359Sroberto#endif 258854359Sroberto#ifdef VTIME 258954359Sroberto tio.c_cc[VTIME] = 0; 259054359Sroberto#endif 259154359Sroberto } 259254359Sroberto#endif 259354359Sroberto 259454359Sroberto tio.c_cflag = parse_clockinfo[type].cl_cflag; 259554359Sroberto tio.c_iflag = parse_clockinfo[type].cl_iflag; 259654359Sroberto tio.c_oflag = parse_clockinfo[type].cl_oflag; 259754359Sroberto tio.c_lflag = parse_clockinfo[type].cl_lflag; 259854359Sroberto 259954359Sroberto 260054359Sroberto#ifdef HAVE_TERMIOS 260154359Sroberto if ((cfsetospeed(&tio, parse_clockinfo[type].cl_speed) == -1) || 260254359Sroberto (cfsetispeed(&tio, parse_clockinfo[type].cl_speed) == -1)) 260354359Sroberto { 260454359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: tcset{i,o}speed(&tio, speed): %m", unit); 260554359Sroberto parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */ 260654359Sroberto return 0; 260754359Sroberto } 260854359Sroberto#else 260954359Sroberto tio.c_cflag |= parse_clockinfo[type].cl_speed; 261054359Sroberto#endif 261154359Sroberto 261254359Sroberto#if defined(HAVE_TIO_SERIAL_STUFF) /* Linux hack: define PPS interface */ 261354359Sroberto { 261454359Sroberto struct serial_struct ss; 261554359Sroberto if (ioctl(fd232, TIOCGSERIAL, &ss) < 0 || 261654359Sroberto ( 261754359Sroberto#ifdef ASYNC_LOW_LATENCY 261854359Sroberto ss.flags |= ASYNC_LOW_LATENCY, 261954359Sroberto#endif 262054359Sroberto#ifdef ASYNC_PPS_CD_NEG 262154359Sroberto ss.flags |= ASYNC_PPS_CD_NEG, 262254359Sroberto#endif 262354359Sroberto ioctl(fd232, TIOCSSERIAL, &ss)) < 0) { 262454359Sroberto msyslog(LOG_NOTICE, "refclock_parse: TIOCSSERIAL fd %d, %m", fd232); 262554359Sroberto msyslog(LOG_NOTICE, 262654359Sroberto "refclock_parse: optional PPS processing not available"); 262754359Sroberto } else { 262854359Sroberto parse->flags |= PARSE_PPSCLOCK; 262954359Sroberto msyslog(LOG_INFO, 263054359Sroberto "refclock_parse: PPS detection on"); 263154359Sroberto } 263254359Sroberto } 263354359Sroberto#endif 263454359Sroberto#ifdef HAVE_TIOCSPPS /* SUN PPS support */ 263554359Sroberto if (CLK_PPS(parse->peer)) 263654359Sroberto { 263754359Sroberto int i = 1; 263854359Sroberto 263954359Sroberto if (ioctl(fd232, TIOCSPPS, (caddr_t)&i) == 0) 264054359Sroberto { 264154359Sroberto parse->flags |= PARSE_PPSCLOCK; 264254359Sroberto } 264354359Sroberto } 264454359Sroberto#endif 264554359Sroberto 264654359Sroberto if (TTY_SETATTR(fd232, &tio) == -1) 264754359Sroberto { 264854359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: tcsetattr(%d, &tio): %m", unit, fd232); 264954359Sroberto parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */ 265054359Sroberto return 0; 265154359Sroberto } 265254359Sroberto } 265354359Sroberto 265454359Sroberto /* 265554359Sroberto * Insert in async io device list. 265654359Sroberto */ 265754359Sroberto parse->generic->io.srcclock = (caddr_t)parse; 265854359Sroberto parse->generic->io.datalen = 0; 265954359Sroberto 266054359Sroberto if (!io_addclock(&parse->generic->io)) 266154359Sroberto { 266254359Sroberto msyslog(LOG_ERR, 266354359Sroberto "PARSE receiver #%d: parse_start: addclock %s fails (ABORT - clock type requires async io)", CLK_UNIT(parse->peer), parsedev); 266454359Sroberto parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */ 266554359Sroberto return 0; 266654359Sroberto } 266754359Sroberto 266854359Sroberto parse->binding = init_iobinding(parse); 266954359Sroberto parse->generic->io.clock_recv = parse->binding->bd_receive; /* pick correct receive routine */ 267054359Sroberto parse->generic->io.io_input = parse->binding->bd_io_input; /* pick correct input routine */ 267154359Sroberto 267254359Sroberto if (parse->binding == (bind_t *)0) 267354359Sroberto { 267454359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: io sub system initialisation failed.", CLK_UNIT(parse->peer)); 267554359Sroberto parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */ 267654359Sroberto return 0; /* well, ok - special initialisation broke */ 267754359Sroberto } 267854359Sroberto 267954359Sroberto /* 268054359Sroberto * as we always(?) get 8 bit chars we want to be 268154359Sroberto * sure, that the upper bits are zero for less 268254359Sroberto * than 8 bit I/O - so we pass that information on. 268354359Sroberto * note that there can be only one bit count format 268454359Sroberto * per file descriptor 268554359Sroberto */ 268654359Sroberto 268754359Sroberto switch (tio.c_cflag & CSIZE) 268854359Sroberto { 268954359Sroberto case CS5: 269054359Sroberto tmp_ctl.parsesetcs.parse_cs = PARSE_IO_CS5; 269154359Sroberto break; 269254359Sroberto 269354359Sroberto case CS6: 269454359Sroberto tmp_ctl.parsesetcs.parse_cs = PARSE_IO_CS6; 269554359Sroberto break; 269654359Sroberto 269754359Sroberto case CS7: 269854359Sroberto tmp_ctl.parsesetcs.parse_cs = PARSE_IO_CS7; 269954359Sroberto break; 270054359Sroberto 270154359Sroberto case CS8: 270254359Sroberto tmp_ctl.parsesetcs.parse_cs = PARSE_IO_CS8; 270354359Sroberto break; 270454359Sroberto } 270554359Sroberto 270654359Sroberto if (!PARSE_SETCS(parse, &tmp_ctl)) 270754359Sroberto { 270854359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: parse_setcs() FAILED.", unit); 270954359Sroberto parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */ 271054359Sroberto return 0; /* well, ok - special initialisation broke */ 271154359Sroberto } 271254359Sroberto 271354359Sroberto strcpy(tmp_ctl.parseformat.parse_buffer, parse->parse_type->cl_format); 271454359Sroberto tmp_ctl.parseformat.parse_count = strlen(tmp_ctl.parseformat.parse_buffer); 271554359Sroberto 271654359Sroberto if (!PARSE_SETFMT(parse, &tmp_ctl)) 271754359Sroberto { 271854359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: parse_setfmt() FAILED.", unit); 271954359Sroberto parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */ 272054359Sroberto return 0; /* well, ok - special initialisation broke */ 272154359Sroberto } 272254359Sroberto 272354359Sroberto /* 272454359Sroberto * get rid of all IO accumulated so far 272554359Sroberto */ 272654359Sroberto#ifdef HAVE_TERMIOS 272754359Sroberto (void) tcflush(parse->generic->io.fd, TCIOFLUSH); 272854359Sroberto#else 272954359Sroberto#ifdef TCFLSH 273054359Sroberto { 273154359Sroberto#ifndef TCIOFLUSH 273254359Sroberto#define TCIOFLUSH 2 273354359Sroberto#endif 273454359Sroberto int flshcmd = TCIOFLUSH; 273554359Sroberto 273654359Sroberto (void) ioctl(parse->generic->io.fd, TCFLSH, (caddr_t)&flshcmd); 273754359Sroberto } 273854359Sroberto#endif 273954359Sroberto#endif 274056746Sroberto 274154359Sroberto /* 274254359Sroberto * try to do any special initializations 274354359Sroberto */ 274454359Sroberto if (parse->parse_type->cl_init) 274554359Sroberto { 274654359Sroberto if (parse->parse_type->cl_init(parse)) 274754359Sroberto { 274854359Sroberto parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */ 274954359Sroberto return 0; /* well, ok - special initialisation broke */ 275054359Sroberto } 275154359Sroberto } 275254359Sroberto 275354359Sroberto /* 275454359Sroberto * get out Copyright information once 275554359Sroberto */ 275654359Sroberto if (!notice) 275754359Sroberto { 275854359Sroberto NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */ 275954359Sroberto msyslog(LOG_INFO, "NTP PARSE support: Copyright (c) 1989-1999, Frank Kardel"); 276054359Sroberto notice = 1; 276154359Sroberto } 276254359Sroberto 276354359Sroberto /* 276454359Sroberto * print out configuration 276554359Sroberto */ 276654359Sroberto NLOG(NLOG_CLOCKINFO) 276754359Sroberto { 276854359Sroberto /* conditional if clause for conditional syslog */ 276954359Sroberto msyslog(LOG_INFO, "PARSE receiver #%d: reference clock \"%s\" (device %s) added", 277054359Sroberto CLK_UNIT(parse->peer), 277154359Sroberto parse->parse_type->cl_description, parsedev); 277254359Sroberto 277354359Sroberto msyslog(LOG_INFO, "PARSE receiver #%d: Stratum %d, %sPPS support, trust time %s, precision %d", 277454359Sroberto CLK_UNIT(parse->peer), 277554359Sroberto parse->peer->stratum, CLK_PPS(parse->peer) ? "" : "no ", 277654359Sroberto l_mktime(parse->parse_type->cl_maxunsync), parse->peer->precision); 277754359Sroberto 277854359Sroberto msyslog(LOG_INFO, "PARSE receiver #%d: rootdelay %.6f s, phaseadjust %.6f s, %s IO handling", 277954359Sroberto CLK_UNIT(parse->peer), 278054359Sroberto parse->parse_type->cl_rootdelay, 278154359Sroberto parse->generic->fudgetime1, 278254359Sroberto parse->binding->bd_description); 278354359Sroberto 278454359Sroberto msyslog(LOG_INFO, "PARSE receiver #%d: Format recognition: %s", CLK_UNIT(parse->peer), 278554359Sroberto parse->parse_type->cl_format); 278654359Sroberto#ifdef PPS 278754359Sroberto msyslog(LOG_INFO, "PARSE receiver #%d: %sPPS ioctl support", CLK_UNIT(parse->peer), 278854359Sroberto (parse->flags & PARSE_PPSCLOCK) ? "" : "NO "); 278954359Sroberto#endif 279054359Sroberto } 279154359Sroberto 279254359Sroberto return 1; 279354359Sroberto} 279454359Sroberto 279554359Sroberto/*-------------------------------------------------- 279654359Sroberto * parse_poll - called by the transmit procedure 279754359Sroberto */ 279854359Srobertostatic void 279954359Srobertoparse_poll( 280054359Sroberto int unit, 280154359Sroberto struct peer *peer 280254359Sroberto ) 280354359Sroberto{ 280454359Sroberto struct parseunit *parse = (struct parseunit *)peer->procptr->unitptr; 280554359Sroberto 280654359Sroberto if (peer != parse->peer) 280754359Sroberto { 280854359Sroberto msyslog(LOG_ERR, 280954359Sroberto "PARSE receiver #%d: poll: INTERNAL: peer incorrect", 281054359Sroberto unit); 281154359Sroberto return; 281254359Sroberto } 281354359Sroberto 281454359Sroberto /* 281554359Sroberto * Update clock stat counters 281654359Sroberto */ 281754359Sroberto parse->generic->polls++; 281854359Sroberto 281956746Sroberto if (parse->pollneeddata && 282056746Sroberto ((current_time - parse->pollneeddata) > (1<<(max(min(parse->peer->hpoll, parse->peer->ppoll), parse->peer->minpoll))))) 282154359Sroberto { 282254359Sroberto /* 282356746Sroberto * start worrying when exceeding a poll inteval 282454359Sroberto * bad news - didn't get a response last time 282554359Sroberto */ 282654359Sroberto parse->generic->noreply++; 282754359Sroberto parse->lastmissed = current_time; 282854359Sroberto parse_event(parse, CEVNT_TIMEOUT); 282954359Sroberto 283054359Sroberto ERR(ERR_NODATA) 283154359Sroberto msyslog(LOG_WARNING, "PARSE receiver #%d: no data from device within poll interval (check receiver / cableling)", CLK_UNIT(parse->peer)); 283254359Sroberto } 283354359Sroberto 283454359Sroberto /* 283554359Sroberto * we just mark that we want the next sample for the clock filter 283654359Sroberto */ 283756746Sroberto parse->pollneeddata = current_time; 283854359Sroberto 283954359Sroberto if (parse->parse_type->cl_poll) 284054359Sroberto { 284154359Sroberto parse->parse_type->cl_poll(parse); 284254359Sroberto } 284354359Sroberto 284454359Sroberto cparse_statistics(parse); 284554359Sroberto 284654359Sroberto return; 284754359Sroberto} 284854359Sroberto 284954359Sroberto#define LEN_STATES 300 /* length of state string */ 285054359Sroberto 285154359Sroberto/*-------------------------------------------------- 285254359Sroberto * parse_control - set fudge factors, return statistics 285354359Sroberto */ 285454359Srobertostatic void 285554359Srobertoparse_control( 285654359Sroberto int unit, 285754359Sroberto struct refclockstat *in, 285854359Sroberto struct refclockstat *out, 285954359Sroberto struct peer *peer 286054359Sroberto ) 286154359Sroberto{ 286254359Sroberto register struct parseunit *parse = (struct parseunit *)peer->procptr->unitptr; 286354359Sroberto parsectl_t tmpctl; 286454359Sroberto 286554359Sroberto static char outstatus[400]; /* status output buffer */ 286654359Sroberto 286754359Sroberto if (out) 286854359Sroberto { 286954359Sroberto out->lencode = 0; 287054359Sroberto out->p_lastcode = 0; 287154359Sroberto out->kv_list = (struct ctl_var *)0; 287254359Sroberto } 287354359Sroberto 287454359Sroberto if (!parse || !parse->peer) 287554359Sroberto { 287654359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: parse_control: unit invalid (UNIT INACTIVE)", 287754359Sroberto unit); 287854359Sroberto return; 287954359Sroberto } 288054359Sroberto 288154359Sroberto unit = CLK_UNIT(parse->peer); 288254359Sroberto 288354359Sroberto if (in) 288454359Sroberto { 288554359Sroberto if (in->haveflags & (CLK_HAVEFLAG1|CLK_HAVEFLAG2|CLK_HAVEFLAG3|CLK_HAVEFLAG4)) 288654359Sroberto { 288754359Sroberto parse->flags = in->flags & (CLK_FLAG1|CLK_FLAG2|CLK_FLAG3|CLK_FLAG4); 288854359Sroberto } 288954359Sroberto } 289054359Sroberto 289154359Sroberto if (out) 289254359Sroberto { 289354359Sroberto u_long sum = 0; 289454359Sroberto char *t, *tt, *start; 289554359Sroberto int i; 289654359Sroberto 289754359Sroberto outstatus[0] = '\0'; 289854359Sroberto 289954359Sroberto out->type = REFCLK_PARSE; 290054359Sroberto out->haveflags |= CLK_HAVETIME2; 290154359Sroberto 290254359Sroberto /* 290354359Sroberto * figure out skew between PPS and RS232 - just for informational 290454359Sroberto * purposes - returned in time2 value 290554359Sroberto */ 290654359Sroberto if (PARSE_SYNC(parse->time.parse_state)) 290754359Sroberto { 290854359Sroberto if (PARSE_PPS(parse->time.parse_state) && PARSE_TIMECODE(parse->time.parse_state)) 290954359Sroberto { 291054359Sroberto l_fp off; 291154359Sroberto 291254359Sroberto /* 291354359Sroberto * we have a PPS and RS232 signal - calculate the skew 291454359Sroberto * WARNING: assumes on TIMECODE == PULSE (timecode after pulse) 291554359Sroberto */ 291654359Sroberto off = parse->time.parse_stime.fp; 291754359Sroberto L_SUB(&off, &parse->time.parse_ptime.fp); /* true offset */ 291854359Sroberto tt = add_var(&out->kv_list, 80, RO); 291954359Sroberto sprintf(tt, "refclock_ppsskew=%s", lfptoms(&off, 6)); 292054359Sroberto } 292154359Sroberto } 292254359Sroberto 292354359Sroberto if (PARSE_PPS(parse->time.parse_state)) 292454359Sroberto { 292554359Sroberto tt = add_var(&out->kv_list, 80, RO|DEF); 292654359Sroberto sprintf(tt, "refclock_ppstime=\"%s\"", gmprettydate(&parse->time.parse_ptime.fp)); 292754359Sroberto } 292854359Sroberto 292954359Sroberto tt = add_var(&out->kv_list, 128, RO|DEF); 293054359Sroberto sprintf(tt, "refclock_time=\""); 293154359Sroberto tt += strlen(tt); 293254359Sroberto 293354359Sroberto if (parse->time.parse_time.fp.l_ui == 0) 293454359Sroberto { 293554359Sroberto strcpy(tt, "<UNDEFINED>\""); 293654359Sroberto } 293754359Sroberto else 293854359Sroberto { 293954359Sroberto sprintf(tt, "%s\"", gmprettydate(&parse->time.parse_time.fp)); 294054359Sroberto t = tt + strlen(tt); 294154359Sroberto } 294254359Sroberto 294354359Sroberto if (!PARSE_GETTIMECODE(parse, &tmpctl)) 294454359Sroberto { 294554359Sroberto ERR(ERR_INTERNAL) 294654359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: parse_control: parse_timecode() FAILED", unit); 294754359Sroberto } 294854359Sroberto else 294954359Sroberto { 295054359Sroberto tt = add_var(&out->kv_list, 512, RO|DEF); 295154359Sroberto sprintf(tt, "refclock_status=\""); 295254359Sroberto tt += strlen(tt); 295354359Sroberto 295454359Sroberto /* 295554359Sroberto * copy PPS flags from last read transaction (informational only) 295654359Sroberto */ 295754359Sroberto tmpctl.parsegettc.parse_state |= parse->time.parse_state & 295854359Sroberto (PARSEB_PPS|PARSEB_S_PPS); 295954359Sroberto 296054359Sroberto (void) parsestate(tmpctl.parsegettc.parse_state, tt); 296154359Sroberto 296254359Sroberto strcat(tt, "\""); 296354359Sroberto 296454359Sroberto if (tmpctl.parsegettc.parse_count) 296554359Sroberto mkascii(outstatus+strlen(outstatus), (int)(sizeof(outstatus)- strlen(outstatus) - 1), 296654359Sroberto tmpctl.parsegettc.parse_buffer, (unsigned)(tmpctl.parsegettc.parse_count - 1)); 296754359Sroberto 296854359Sroberto parse->generic->badformat += tmpctl.parsegettc.parse_badformat; 296954359Sroberto } 297054359Sroberto 297154359Sroberto tmpctl.parseformat.parse_format = tmpctl.parsegettc.parse_format; 297254359Sroberto 297354359Sroberto if (!PARSE_GETFMT(parse, &tmpctl)) 297454359Sroberto { 297554359Sroberto ERR(ERR_INTERNAL) 297654359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: parse_control: parse_getfmt() FAILED", unit); 297754359Sroberto } 297854359Sroberto else 297954359Sroberto { 298054359Sroberto tt = add_var(&out->kv_list, 80, RO|DEF); 298154359Sroberto sprintf(tt, "refclock_format=\""); 298254359Sroberto 298354359Sroberto strncat(tt, tmpctl.parseformat.parse_buffer, tmpctl.parseformat.parse_count); 298454359Sroberto strcat(tt,"\""); 298554359Sroberto } 298654359Sroberto 298754359Sroberto /* 298854359Sroberto * gather state statistics 298954359Sroberto */ 299054359Sroberto 299154359Sroberto start = tt = add_var(&out->kv_list, LEN_STATES, RO|DEF); 299254359Sroberto strcpy(tt, "refclock_states=\""); 299354359Sroberto tt += strlen(tt); 299454359Sroberto 299554359Sroberto for (i = 0; i <= CEVNT_MAX; i++) 299654359Sroberto { 299754359Sroberto u_long s_time; 299854359Sroberto u_long d = current_time - parse->generic->timestarted; 299954359Sroberto u_long percent; 300054359Sroberto 300154359Sroberto percent = s_time = PARSE_STATETIME(parse, i); 300254359Sroberto 300354359Sroberto while (((u_long)(~0) / 10000) < percent) 300454359Sroberto { 300554359Sroberto percent /= 10; 300654359Sroberto d /= 10; 300754359Sroberto } 300854359Sroberto 300954359Sroberto if (d) 301054359Sroberto percent = (percent * 10000) / d; 301154359Sroberto else 301254359Sroberto percent = 10000; 301354359Sroberto 301454359Sroberto if (s_time) 301554359Sroberto { 301654359Sroberto char item[80]; 301754359Sroberto int count; 301854359Sroberto 301954359Sroberto sprintf(item, "%s%s%s: %s (%d.%02d%%)", 302054359Sroberto sum ? "; " : "", 302154359Sroberto (parse->generic->currentstatus == i) ? "*" : "", 302254359Sroberto clockstatus((unsigned int)i), 302354359Sroberto l_mktime(s_time), 302454359Sroberto (int)(percent / 100), (int)(percent % 100)); 302554359Sroberto if ((count = strlen(item)) < (LEN_STATES - 40 - (tt - start))) 302654359Sroberto { 302754359Sroberto strcpy(tt, item); 302854359Sroberto tt += count; 302954359Sroberto } 303054359Sroberto sum += s_time; 303154359Sroberto } 303254359Sroberto } 303354359Sroberto 303454359Sroberto sprintf(tt, "; running time: %s\"", l_mktime(sum)); 303554359Sroberto 303654359Sroberto tt = add_var(&out->kv_list, 32, RO); 303754359Sroberto sprintf(tt, "refclock_id=\"%s\"", parse->parse_type->cl_id); 303854359Sroberto 303954359Sroberto tt = add_var(&out->kv_list, 80, RO); 304054359Sroberto sprintf(tt, "refclock_iomode=\"%s\"", parse->binding->bd_description); 304154359Sroberto 304254359Sroberto tt = add_var(&out->kv_list, 128, RO); 304354359Sroberto sprintf(tt, "refclock_driver_version=\"%s\"", rcsid); 304454359Sroberto 304554359Sroberto { 304654359Sroberto struct ctl_var *k; 304754359Sroberto 304854359Sroberto k = parse->kv; 304954359Sroberto while (k && !(k->flags & EOV)) 305054359Sroberto { 305154359Sroberto set_var(&out->kv_list, k->text, strlen(k->text)+1, k->flags); 305254359Sroberto k++; 305354359Sroberto } 305454359Sroberto } 305554359Sroberto 305654359Sroberto out->lencode = strlen(outstatus); 305754359Sroberto out->p_lastcode = outstatus; 305854359Sroberto } 305954359Sroberto} 306054359Sroberto 306154359Sroberto/**=========================================================================== 306254359Sroberto ** processing routines 306354359Sroberto **/ 306454359Sroberto 306554359Sroberto/*-------------------------------------------------- 306654359Sroberto * event handling - note that nominal events will also be posted 306754359Sroberto */ 306854359Srobertostatic void 306954359Srobertoparse_event( 307054359Sroberto struct parseunit *parse, 307154359Sroberto int event 307254359Sroberto ) 307354359Sroberto{ 307454359Sroberto if (parse->generic->currentstatus != (u_char) event) 307554359Sroberto { 307654359Sroberto parse->statetime[parse->generic->currentstatus] += current_time - parse->lastchange; 307754359Sroberto parse->lastchange = current_time; 307854359Sroberto 307954359Sroberto parse->generic->currentstatus = (u_char)event; 308054359Sroberto 308154359Sroberto if (parse->parse_type->cl_event) 308254359Sroberto parse->parse_type->cl_event(parse, event); 308354359Sroberto 308454359Sroberto if (event != CEVNT_NOMINAL) 308554359Sroberto { 308654359Sroberto parse->generic->lastevent = parse->generic->currentstatus; 308754359Sroberto } 308854359Sroberto else 308954359Sroberto { 309054359Sroberto NLOG(NLOG_CLOCKSTATUS) 309154359Sroberto msyslog(LOG_INFO, "PARSE receiver #%d: SYNCHRONIZED", 309254359Sroberto CLK_UNIT(parse->peer)); 309354359Sroberto } 309454359Sroberto 309554359Sroberto if (event == CEVNT_FAULT) 309654359Sroberto { 309754359Sroberto NLOG(NLOG_CLOCKEVENT) /* conditional if clause for conditional syslog */ 309854359Sroberto ERR(ERR_BADEVENT) 309954359Sroberto msyslog(LOG_ERR, 310054359Sroberto "clock %s fault '%s' (0x%02x)", refnumtoa(parse->peer->srcadr.sin_addr.s_addr), ceventstr(event), 310154359Sroberto (u_int)event); 310254359Sroberto } 310354359Sroberto else 310454359Sroberto { 310554359Sroberto NLOG(NLOG_CLOCKEVENT) /* conditional if clause for conditional syslog */ 310654359Sroberto if (event == CEVNT_NOMINAL || list_err(parse, ERR_BADEVENT)) 310754359Sroberto msyslog(LOG_INFO, 310854359Sroberto "clock %s event '%s' (0x%02x)", refnumtoa(parse->peer->srcadr.sin_addr.s_addr), ceventstr(event), 310954359Sroberto (u_int)event); 311054359Sroberto } 311154359Sroberto 311254359Sroberto report_event(EVNT_PEERCLOCK, parse->peer); 311354359Sroberto report_event(EVNT_CLOCKEXCPT, parse->peer); 311454359Sroberto } 311554359Sroberto} 311654359Sroberto 311754359Sroberto/*-------------------------------------------------- 311854359Sroberto * process a PARSE time sample 311954359Sroberto */ 312054359Srobertostatic void 312154359Srobertoparse_process( 312254359Sroberto struct parseunit *parse, 312354359Sroberto parsetime_t *parsetime 312454359Sroberto ) 312554359Sroberto{ 312654359Sroberto l_fp off, rectime, reftime; 312754359Sroberto double fudge; 312854359Sroberto 312954359Sroberto /* 313054359Sroberto * check for changes in conversion status 313154359Sroberto * (only one for each new status !) 313254359Sroberto */ 313354359Sroberto if (((parsetime->parse_status & CVT_MASK) != CVT_OK) && 313454359Sroberto ((parsetime->parse_status & CVT_MASK) != CVT_NONE) && 313554359Sroberto (parse->time.parse_status != parsetime->parse_status)) 313654359Sroberto { 313754359Sroberto char buffer[400]; 313854359Sroberto 313954359Sroberto NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */ 314054359Sroberto msyslog(LOG_WARNING, "PARSE receiver #%d: conversion status \"%s\"", 314154359Sroberto CLK_UNIT(parse->peer), parsestatus(parsetime->parse_status, buffer)); 314254359Sroberto 314354359Sroberto if ((parsetime->parse_status & CVT_MASK) == CVT_FAIL) 314454359Sroberto { 314554359Sroberto /* 314654359Sroberto * tell more about the story - list time code 314754359Sroberto * there is a slight change for a race condition and 314854359Sroberto * the time code might be overwritten by the next packet 314954359Sroberto */ 315054359Sroberto parsectl_t tmpctl; 315154359Sroberto 315254359Sroberto if (!PARSE_GETTIMECODE(parse, &tmpctl)) 315354359Sroberto { 315454359Sroberto ERR(ERR_INTERNAL) 315554359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: parse_process: parse_timecode() FAILED", CLK_UNIT(parse->peer)); 315654359Sroberto } 315754359Sroberto else 315854359Sroberto { 315954359Sroberto ERR(ERR_BADDATA) 316054359Sroberto msyslog(LOG_WARNING, "PARSE receiver #%d: FAILED TIMECODE: \"%s\" (check receiver configuration / cableling)", 316154359Sroberto CLK_UNIT(parse->peer), mkascii(buffer, sizeof buffer, tmpctl.parsegettc.parse_buffer, (unsigned)(tmpctl.parsegettc.parse_count - 1))); 316254359Sroberto parse->generic->badformat += tmpctl.parsegettc.parse_badformat; 316354359Sroberto } 316454359Sroberto } 316554359Sroberto } 316654359Sroberto 316754359Sroberto /* 316854359Sroberto * examine status and post appropriate events 316954359Sroberto */ 317054359Sroberto if ((parsetime->parse_status & CVT_MASK) != CVT_OK) 317154359Sroberto { 317254359Sroberto /* 317354359Sroberto * got bad data - tell the rest of the system 317454359Sroberto */ 317554359Sroberto switch (parsetime->parse_status & CVT_MASK) 317654359Sroberto { 317754359Sroberto case CVT_NONE: 317854359Sroberto if ((parsetime->parse_status & CVT_ADDITIONAL) && 317954359Sroberto parse->parse_type->cl_message) 318054359Sroberto parse->parse_type->cl_message(parse, parsetime); 318154359Sroberto break; /* well, still waiting - timeout is handled at higher levels */ 318254359Sroberto 318354359Sroberto case CVT_FAIL: 318454359Sroberto parse->generic->badformat++; 318554359Sroberto if (parsetime->parse_status & CVT_BADFMT) 318654359Sroberto { 318754359Sroberto parse_event(parse, CEVNT_BADREPLY); 318854359Sroberto } 318954359Sroberto else 319054359Sroberto if (parsetime->parse_status & CVT_BADDATE) 319154359Sroberto { 319254359Sroberto parse_event(parse, CEVNT_BADDATE); 319354359Sroberto } 319454359Sroberto else 319554359Sroberto if (parsetime->parse_status & CVT_BADTIME) 319654359Sroberto { 319754359Sroberto parse_event(parse, CEVNT_BADTIME); 319854359Sroberto } 319954359Sroberto else 320054359Sroberto { 320154359Sroberto parse_event(parse, CEVNT_BADREPLY); /* for the lack of something better */ 320254359Sroberto } 320354359Sroberto } 320454359Sroberto return; /* skip the rest - useless */ 320554359Sroberto } 320654359Sroberto 320754359Sroberto /* 320854359Sroberto * check for format changes 320954359Sroberto * (in case somebody has swapped clocks 8-) 321054359Sroberto */ 321154359Sroberto if (parse->lastformat != parsetime->parse_format) 321254359Sroberto { 321354359Sroberto parsectl_t tmpctl; 321454359Sroberto 321554359Sroberto tmpctl.parseformat.parse_format = parsetime->parse_format; 321654359Sroberto 321754359Sroberto if (!PARSE_GETFMT(parse, &tmpctl)) 321854359Sroberto { 321954359Sroberto ERR(ERR_INTERNAL) 322054359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: parse_getfmt() FAILED", CLK_UNIT(parse->peer)); 322154359Sroberto } 322254359Sroberto else 322354359Sroberto { 322454359Sroberto NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */ 322554359Sroberto msyslog(LOG_INFO, "PARSE receiver #%d: packet format \"%s\"", 322654359Sroberto CLK_UNIT(parse->peer), tmpctl.parseformat.parse_buffer); 322754359Sroberto } 322854359Sroberto parse->lastformat = parsetime->parse_format; 322954359Sroberto } 323054359Sroberto 323154359Sroberto /* 323254359Sroberto * now, any changes ? 323354359Sroberto */ 323454359Sroberto if (parse->time.parse_state != parsetime->parse_state) 323554359Sroberto { 323654359Sroberto char tmp1[200]; 323754359Sroberto char tmp2[200]; 323854359Sroberto /* 323954359Sroberto * something happend 324054359Sroberto */ 324154359Sroberto 324254359Sroberto (void) parsestate(parsetime->parse_state, tmp1); 324354359Sroberto (void) parsestate(parse->time.parse_state, tmp2); 324454359Sroberto 324554359Sroberto NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */ 324654359Sroberto msyslog(LOG_INFO,"PARSE receiver #%d: STATE CHANGE: %s -> %s", 324754359Sroberto CLK_UNIT(parse->peer), tmp2, tmp1); 324854359Sroberto } 324954359Sroberto 325054359Sroberto /* 325154359Sroberto * remember for future 325254359Sroberto */ 325354359Sroberto parse->time = *parsetime; 325454359Sroberto 325554359Sroberto /* 325654359Sroberto * check to see, whether the clock did a complete powerup or lost PZF signal 325754359Sroberto * and post correct events for current condition 325854359Sroberto */ 325954359Sroberto if (PARSE_POWERUP(parsetime->parse_state)) 326054359Sroberto { 326154359Sroberto /* 326254359Sroberto * this is bad, as we have completely lost synchronisation 326354359Sroberto * well this is a problem with the receiver here 326454359Sroberto * for PARSE Meinberg DCF77 receivers the lost synchronisation 326554359Sroberto * is true as it is the powerup state and the time is taken 326654359Sroberto * from a crude real time clock chip 326754359Sroberto * for the PZF series this is only partly true, as 326854359Sroberto * PARSE_POWERUP only means that the pseudo random 326954359Sroberto * phase shift sequence cannot be found. this is only 327054359Sroberto * bad, if we have never seen the clock in the SYNC 327154359Sroberto * state, where the PHASE and EPOCH are correct. 327254359Sroberto * for reporting events the above business does not 327354359Sroberto * really matter, but we can use the time code 327454359Sroberto * even in the POWERUP state after having seen 327554359Sroberto * the clock in the synchronized state (PZF class 327654359Sroberto * receivers) unless we have had a telegram disruption 327754359Sroberto * after having seen the clock in the SYNC state. we 327854359Sroberto * thus require having seen the clock in SYNC state 327954359Sroberto * *after* having missed telegrams (noresponse) from 328054359Sroberto * the clock. one problem remains: we might use erroneously 328154359Sroberto * POWERUP data if the disruption is shorter than 1 polling 328254359Sroberto * interval. fortunately powerdowns last usually longer than 64 328354359Sroberto * seconds and the receiver is at least 2 minutes in the 328454359Sroberto * POWERUP or NOSYNC state before switching to SYNC 328554359Sroberto */ 328654359Sroberto parse_event(parse, CEVNT_FAULT); 328754359Sroberto NLOG(NLOG_CLOCKSTATUS) 328854359Sroberto ERR(ERR_BADSTATUS) 328954359Sroberto msyslog(LOG_ERR,"PARSE receiver #%d: NOT SYNCHRONIZED", 329054359Sroberto CLK_UNIT(parse->peer)); 329154359Sroberto } 329254359Sroberto else 329354359Sroberto { 329454359Sroberto /* 329554359Sroberto * we have two states left 329654359Sroberto * 329754359Sroberto * SYNC: 329854359Sroberto * this state means that the EPOCH (timecode) and PHASE 329954359Sroberto * information has be read correctly (at least two 330054359Sroberto * successive PARSE timecodes were received correctly) 330154359Sroberto * this is the best possible state - full trust 330254359Sroberto * 330354359Sroberto * NOSYNC: 330454359Sroberto * The clock should be on phase with respect to the second 330554359Sroberto * signal, but the timecode has not been received correctly within 330654359Sroberto * at least the last two minutes. this is a sort of half baked state 330754359Sroberto * for PARSE Meinberg DCF77 clocks this is bad news (clock running 330854359Sroberto * without timecode confirmation) 330954359Sroberto * PZF 535 has also no time confirmation, but the phase should be 331054359Sroberto * very precise as the PZF signal can be decoded 331154359Sroberto */ 331254359Sroberto 331354359Sroberto if (PARSE_SYNC(parsetime->parse_state)) 331454359Sroberto { 331554359Sroberto /* 331654359Sroberto * currently completely synchronized - best possible state 331754359Sroberto */ 331854359Sroberto parse->lastsync = current_time; 331954359Sroberto clear_err(parse, ERR_BADSTATUS); 332054359Sroberto } 332154359Sroberto else 332254359Sroberto { 332354359Sroberto /* 332454359Sroberto * we have had some problems receiving the time code 332554359Sroberto */ 332654359Sroberto parse_event(parse, CEVNT_PROP); 332754359Sroberto NLOG(NLOG_CLOCKSTATUS) 332854359Sroberto ERR(ERR_BADSTATUS) 332954359Sroberto msyslog(LOG_ERR,"PARSE receiver #%d: TIMECODE NOT CONFIRMED", 333054359Sroberto CLK_UNIT(parse->peer)); 333154359Sroberto } 333254359Sroberto } 333354359Sroberto 333454359Sroberto fudge = parse->generic->fudgetime1; /* standard RS232 Fudgefactor */ 333554359Sroberto 333654359Sroberto if (PARSE_TIMECODE(parsetime->parse_state)) 333754359Sroberto { 333854359Sroberto rectime = parsetime->parse_stime.fp; 333954359Sroberto off = reftime = parsetime->parse_time.fp; 334054359Sroberto 334154359Sroberto L_SUB(&off, &rectime); /* prepare for PPS adjustments logic */ 334254359Sroberto 334354359Sroberto#ifdef DEBUG 334454359Sroberto if (debug > 3) 334554359Sroberto printf("PARSE receiver #%d: Reftime %s, Recvtime %s - initial offset %s\n", 334654359Sroberto CLK_UNIT(parse->peer), 334754359Sroberto prettydate(&reftime), 334854359Sroberto prettydate(&rectime), 334954359Sroberto lfptoa(&off,6)); 335054359Sroberto#endif 335154359Sroberto } 335254359Sroberto 335354359Sroberto if (PARSE_PPS(parsetime->parse_state) && CLK_PPS(parse->peer)) 335454359Sroberto { 335554359Sroberto l_fp offset; 335654359Sroberto 335754359Sroberto /* 335854359Sroberto * we have a PPS signal - much better than the RS232 stuff (we hope) 335954359Sroberto */ 336054359Sroberto offset = parsetime->parse_ptime.fp; 336154359Sroberto 336254359Sroberto#ifdef DEBUG 336354359Sroberto if (debug > 3) 336454359Sroberto printf("PARSE receiver #%d: PPStime %s\n", 336554359Sroberto CLK_UNIT(parse->peer), 336654359Sroberto prettydate(&offset)); 336754359Sroberto#endif 336854359Sroberto if (PARSE_TIMECODE(parsetime->parse_state)) 336954359Sroberto { 337054359Sroberto if (M_ISGEQ(off.l_i, off.l_f, -1, 0x80000000) && 337154359Sroberto M_ISGEQ(0, 0x7fffffff, off.l_i, off.l_f)) 337254359Sroberto { 337354359Sroberto fudge = parse->generic->fudgetime2; /* pick PPS fudge factor */ 337454359Sroberto 337554359Sroberto /* 337654359Sroberto * RS232 offsets within [-0.5..0.5[ - take PPS offsets 337754359Sroberto */ 337854359Sroberto 337954359Sroberto if (parse->parse_type->cl_flags & PARSE_F_PPSONSECOND) 338054359Sroberto { 338154359Sroberto reftime = off = offset; 338254359Sroberto if (reftime.l_uf & (unsigned)0x80000000) 338354359Sroberto reftime.l_ui++; 338454359Sroberto reftime.l_uf = 0; 338556746Sroberto 338654359Sroberto 338754359Sroberto /* 338854359Sroberto * implied on second offset 338954359Sroberto */ 339054359Sroberto off.l_uf = ~off.l_uf; /* map [0.5..1[ -> [-0.5..0[ */ 339154359Sroberto off.l_ui = (off.l_f < 0) ? ~0 : 0; /* sign extend */ 339254359Sroberto } 339354359Sroberto else 339454359Sroberto { 339554359Sroberto /* 339654359Sroberto * time code describes pulse 339754359Sroberto */ 339854359Sroberto reftime = off = parsetime->parse_time.fp; 339954359Sroberto 340054359Sroberto L_SUB(&off, &offset); /* true offset */ 340154359Sroberto } 340254359Sroberto } 340354359Sroberto /* 340454359Sroberto * take RS232 offset when PPS when out of bounds 340554359Sroberto */ 340654359Sroberto } 340754359Sroberto else 340854359Sroberto { 340954359Sroberto fudge = parse->generic->fudgetime2; /* pick PPS fudge factor */ 341054359Sroberto /* 341154359Sroberto * Well, no time code to guide us - assume on second pulse 341254359Sroberto * and pray, that we are within [-0.5..0.5[ 341354359Sroberto */ 341454359Sroberto off = offset; 341554359Sroberto reftime = offset; 341654359Sroberto if (reftime.l_uf & (unsigned)0x80000000) 341754359Sroberto reftime.l_ui++; 341854359Sroberto reftime.l_uf = 0; 341954359Sroberto /* 342054359Sroberto * implied on second offset 342154359Sroberto */ 342254359Sroberto off.l_uf = ~off.l_uf; /* map [0.5..1[ -> [-0.5..0[ */ 342354359Sroberto off.l_ui = (off.l_f < 0) ? ~0 : 0; /* sign extend */ 342454359Sroberto } 342554359Sroberto } 342654359Sroberto else 342754359Sroberto { 342854359Sroberto if (!PARSE_TIMECODE(parsetime->parse_state)) 342954359Sroberto { 343054359Sroberto /* 343154359Sroberto * Well, no PPS, no TIMECODE, no more work ... 343254359Sroberto */ 343354359Sroberto if ((parsetime->parse_status & CVT_ADDITIONAL) && 343454359Sroberto parse->parse_type->cl_message) 343554359Sroberto parse->parse_type->cl_message(parse, parsetime); 343654359Sroberto return; 343754359Sroberto } 343854359Sroberto } 343954359Sroberto 344054359Sroberto#ifdef DEBUG 344154359Sroberto if (debug > 3) 344254359Sroberto printf("PARSE receiver #%d: Reftime %s, Recvtime %s - final offset %s\n", 344354359Sroberto CLK_UNIT(parse->peer), 344454359Sroberto prettydate(&reftime), 344554359Sroberto prettydate(&rectime), 344654359Sroberto lfptoa(&off,6)); 344754359Sroberto#endif 344854359Sroberto 344954359Sroberto 345054359Sroberto rectime = reftime; 345154359Sroberto L_SUB(&rectime, &off); /* just to keep the ntp interface happy */ 345254359Sroberto 345354359Sroberto#ifdef DEBUG 345454359Sroberto if (debug > 3) 345554359Sroberto printf("PARSE receiver #%d: calculated Reftime %s, Recvtime %s\n", 345654359Sroberto CLK_UNIT(parse->peer), 345754359Sroberto prettydate(&reftime), 345854359Sroberto prettydate(&rectime)); 345954359Sroberto#endif 346054359Sroberto 346154359Sroberto if ((parsetime->parse_status & CVT_ADDITIONAL) && 346254359Sroberto parse->parse_type->cl_message) 346354359Sroberto parse->parse_type->cl_message(parse, parsetime); 346454359Sroberto 346554359Sroberto if (PARSE_SYNC(parsetime->parse_state)) 346654359Sroberto { 346754359Sroberto /* 346854359Sroberto * log OK status 346954359Sroberto */ 347054359Sroberto parse_event(parse, CEVNT_NOMINAL); 347154359Sroberto } 347254359Sroberto 347354359Sroberto clear_err(parse, ERR_BADIO); 347454359Sroberto clear_err(parse, ERR_BADDATA); 347554359Sroberto clear_err(parse, ERR_NODATA); 347654359Sroberto clear_err(parse, ERR_INTERNAL); 347754359Sroberto 347854359Sroberto#ifdef DEBUG 347954359Sroberto if (debug > 2) 348054359Sroberto { 348154359Sroberto printf("PARSE receiver #%d: refclock_process_offset(reftime=%s, rectime=%s, Fudge=%f)\n", 348254359Sroberto CLK_UNIT(parse->peer), 348354359Sroberto prettydate(&reftime), 348454359Sroberto prettydate(&rectime), 348554359Sroberto fudge); 348654359Sroberto } 348754359Sroberto#endif 348854359Sroberto 348954359Sroberto refclock_process_offset(parse->generic, reftime, rectime, fudge); 349054359Sroberto if (PARSE_PPS(parsetime->parse_state) && CLK_PPS(parse->peer)) 349154359Sroberto { 349254359Sroberto (void) pps_sample(&parse->time.parse_ptime.fp); 349354359Sroberto } 349454359Sroberto 349554359Sroberto 349654359Sroberto /* 349754359Sroberto * and now stick it into the clock machine 349854359Sroberto * samples are only valid iff lastsync is not too old and 349954359Sroberto * we have seen the clock in sync at least once 350054359Sroberto * after the last time we didn't see an expected data telegram 350154359Sroberto * see the clock states section above for more reasoning 350254359Sroberto */ 350354359Sroberto if (((current_time - parse->lastsync) > parse->parse_type->cl_maxunsync) || 350454359Sroberto (parse->lastsync <= parse->lastmissed)) 350554359Sroberto { 350654359Sroberto parse->generic->leap = LEAP_NOTINSYNC; 350754359Sroberto } 350854359Sroberto else 350954359Sroberto { 351054359Sroberto if (PARSE_LEAPADD(parsetime->parse_state)) 351154359Sroberto { 351254359Sroberto /* 351354359Sroberto * we pick this state also for time code that pass leap warnings 351454359Sroberto * without direction information (as earth is currently slowing 351554359Sroberto * down). 351654359Sroberto */ 351754359Sroberto parse->generic->leap = (parse->flags & PARSE_LEAP_DELETE) ? LEAP_DELSECOND : LEAP_ADDSECOND; 351854359Sroberto } 351954359Sroberto else 352054359Sroberto if (PARSE_LEAPDEL(parsetime->parse_state)) 352154359Sroberto { 352254359Sroberto parse->generic->leap = LEAP_DELSECOND; 352354359Sroberto } 352454359Sroberto else 352554359Sroberto { 352654359Sroberto parse->generic->leap = LEAP_NOWARNING; 352754359Sroberto } 352854359Sroberto } 352954359Sroberto 353054359Sroberto /* 353154359Sroberto * ready, unless the machine wants a sample 353254359Sroberto */ 353354359Sroberto if (!parse->pollneeddata) 353454359Sroberto return; 353554359Sroberto 353654359Sroberto parse->pollneeddata = 0; 353754359Sroberto 353854359Sroberto refclock_receive(parse->peer); 353954359Sroberto} 354056746Sroberto 354154359Sroberto/**=========================================================================== 354254359Sroberto ** special code for special clocks 354354359Sroberto **/ 354454359Sroberto 354554359Srobertostatic void 354654359Srobertomk_utcinfo( 354754359Sroberto char *t, 354854359Sroberto int wnt, 354954359Sroberto int wnlsf, 355054359Sroberto int dn, 355154359Sroberto int dtls, 355254359Sroberto int dtlsf 355354359Sroberto ) 355454359Sroberto{ 355554359Sroberto l_fp leapdate; 355654359Sroberto 355754359Sroberto sprintf(t, "current correction %d sec", dtls); 355854359Sroberto t += strlen(t); 355954359Sroberto 356054359Sroberto if (wnlsf < 990) 356154359Sroberto wnlsf += 1024; 356254359Sroberto 356354359Sroberto if (wnt < 990) 356454359Sroberto wnt += 1024; 356554359Sroberto 356654359Sroberto gpstolfp((unsigned short)wnlsf, (unsigned short)dn, 0, &leapdate); 356754359Sroberto 356854359Sroberto if ((dtlsf != dtls) && 356954359Sroberto ((wnlsf - wnt) < 52)) 357054359Sroberto { 357154359Sroberto sprintf(t, ", next correction %d sec on %s, new GPS-UTC offset %d", 357254359Sroberto dtlsf - dtls, gmprettydate(&leapdate), dtlsf); 357354359Sroberto } 357454359Sroberto else 357554359Sroberto { 357654359Sroberto sprintf(t, ", last correction on %s", 357754359Sroberto gmprettydate(&leapdate)); 357854359Sroberto } 357954359Sroberto} 358054359Sroberto 358154359Sroberto#ifdef CLOCK_MEINBERG 358254359Sroberto/**=========================================================================== 358354359Sroberto ** Meinberg GPS166/GPS167 support 358454359Sroberto **/ 358554359Sroberto 358654359Sroberto/*------------------------------------------------------------ 358754359Sroberto * gps16x_message - process GPS16x messages 358854359Sroberto */ 358954359Srobertostatic void 359054359Srobertogps16x_message( 359154359Sroberto struct parseunit *parse, 359254359Sroberto parsetime_t *parsetime 359354359Sroberto ) 359454359Sroberto{ 359554359Sroberto if (parse->time.parse_msglen && parsetime->parse_msg[0] == SOH) 359654359Sroberto { 359754359Sroberto GPS_MSG_HDR header; 359854359Sroberto unsigned char *bufp = (unsigned char *)parsetime->parse_msg + 1; 359954359Sroberto 360054359Sroberto#ifdef DEBUG 360154359Sroberto if (debug > 2) 360254359Sroberto { 360354359Sroberto char msgbuffer[600]; 360454359Sroberto 360554359Sroberto mkreadable(msgbuffer, sizeof(msgbuffer), (char *)parsetime->parse_msg, parsetime->parse_msglen, 1); 360654359Sroberto printf("PARSE receiver #%d: received message (%d bytes) >%s<\n", 360754359Sroberto CLK_UNIT(parse->peer), 360854359Sroberto parsetime->parse_msglen, 360954359Sroberto msgbuffer); 361054359Sroberto } 361154359Sroberto#endif 361254359Sroberto get_mbg_header(&bufp, &header); 361354359Sroberto if (header.gps_hdr_csum == mbg_csum(parsetime->parse_msg + 1, 6) && 361454359Sroberto (header.gps_len == 0 || 361554359Sroberto (header.gps_len < sizeof(parsetime->parse_msg) && 361654359Sroberto header.gps_data_csum == mbg_csum(bufp, header.gps_len)))) 361754359Sroberto { 361854359Sroberto /* 361954359Sroberto * clean message 362054359Sroberto */ 362154359Sroberto switch (header.gps_cmd) 362254359Sroberto { 362354359Sroberto case GPS_SW_REV: 362454359Sroberto { 362554359Sroberto char buffer[64]; 362654359Sroberto SW_REV gps_sw_rev; 362754359Sroberto 362854359Sroberto get_mbg_sw_rev(&bufp, &gps_sw_rev); 362954359Sroberto sprintf(buffer, "meinberg_gps_version=\"%x.%02x%s%s\"", 363054359Sroberto (gps_sw_rev.code >> 8) & 0xFF, 363154359Sroberto gps_sw_rev.code & 0xFF, 363254359Sroberto gps_sw_rev.name[0] ? " " : "", 363354359Sroberto gps_sw_rev.name); 363454359Sroberto set_var(&parse->kv, buffer, 64, RO|DEF); 363554359Sroberto } 363654359Sroberto break; 363754359Sroberto 363854359Sroberto case GPS_STAT: 363954359Sroberto { 364054359Sroberto static struct state 364154359Sroberto { 364254359Sroberto unsigned short flag; /* status flag */ 364354359Sroberto unsigned const char *string; /* bit name */ 364454359Sroberto } states[] = 364554359Sroberto { 364654359Sroberto { TM_ANT_DISCONN, (const unsigned char *)"ANTENNA FAULTY" }, 364754359Sroberto { TM_SYN_FLAG, (const unsigned char *)"NO SYNC SIGNAL" }, 364854359Sroberto { TM_NO_SYNC, (const unsigned char *)"NO SYNC POWERUP" }, 364954359Sroberto { TM_NO_POS, (const unsigned char *)"NO POSITION" }, 365054359Sroberto { 0, (const unsigned char *)"" } 365154359Sroberto }; 365254359Sroberto unsigned short status; 365354359Sroberto struct state *s = states; 365454359Sroberto char buffer[512]; 365554359Sroberto char *p, *b; 365654359Sroberto 365754359Sroberto status = get_lsb_short(&bufp); 365854359Sroberto sprintf(buffer, "meinberg_gps_status=\"[0x%04x] ", status); 365954359Sroberto 366054359Sroberto if (status) 366154359Sroberto { 366254359Sroberto p = b = buffer + strlen(buffer); 366354359Sroberto while (s->flag) 366454359Sroberto { 366554359Sroberto if (status & s->flag) 366654359Sroberto { 366754359Sroberto if (p != b) 366854359Sroberto { 366954359Sroberto *p++ = ','; 367054359Sroberto *p++ = ' '; 367154359Sroberto } 367254359Sroberto 367354359Sroberto strcat(p, (const char *)s->string); 367454359Sroberto } 367554359Sroberto s++; 367654359Sroberto } 367754359Sroberto 367854359Sroberto *p++ = '"'; 367954359Sroberto *p = '\0'; 368054359Sroberto } 368154359Sroberto else 368254359Sroberto { 368354359Sroberto strcat(buffer, "<OK>\""); 368454359Sroberto } 368554359Sroberto 368654359Sroberto set_var(&parse->kv, buffer, 64, RO|DEF); 368754359Sroberto } 368854359Sroberto break; 368954359Sroberto 369054359Sroberto case GPS_POS_XYZ: 369154359Sroberto { 369254359Sroberto XYZ xyz; 369354359Sroberto char buffer[256]; 369454359Sroberto 369554359Sroberto get_mbg_xyz(&bufp, xyz); 369654359Sroberto sprintf(buffer, "gps_position(XYZ)=\"%s m, %s m, %s m\"", 369754359Sroberto mfptoa(xyz[XP].l_ui, xyz[XP].l_uf, 1), 369854359Sroberto mfptoa(xyz[YP].l_ui, xyz[YP].l_uf, 1), 369954359Sroberto mfptoa(xyz[ZP].l_ui, xyz[ZP].l_uf, 1)); 370054359Sroberto 370154359Sroberto set_var(&parse->kv, buffer, sizeof(buffer), RO|DEF); 370254359Sroberto } 370354359Sroberto break; 370454359Sroberto 370554359Sroberto case GPS_POS_LLA: 370654359Sroberto { 370754359Sroberto LLA lla; 370854359Sroberto char buffer[256]; 370954359Sroberto 371054359Sroberto get_mbg_lla(&bufp, lla); 371154359Sroberto 371254359Sroberto sprintf(buffer, "gps_position(LLA)=\"%s deg, %s deg, %s m\"", 371354359Sroberto mfptoa(lla[LAT].l_ui, lla[LAT].l_uf, 4), 371454359Sroberto mfptoa(lla[LON].l_ui, lla[LON].l_uf, 4), 371554359Sroberto mfptoa(lla[ALT].l_ui, lla[ALT].l_uf, 1)); 371654359Sroberto 371754359Sroberto set_var(&parse->kv, buffer, sizeof(buffer), RO|DEF); 371854359Sroberto } 371954359Sroberto break; 372054359Sroberto 372154359Sroberto case GPS_TZDL: 372254359Sroberto break; 372354359Sroberto 372454359Sroberto case GPS_PORT_PARM: 372554359Sroberto break; 372654359Sroberto 372754359Sroberto case GPS_SYNTH: 372854359Sroberto break; 372954359Sroberto 373054359Sroberto case GPS_ANT_INFO: 373154359Sroberto { 373254359Sroberto ANT_INFO antinfo; 373354359Sroberto char buffer[512]; 373454359Sroberto char *p; 373554359Sroberto 373654359Sroberto get_mbg_antinfo(&bufp, &antinfo); 373754359Sroberto sprintf((char *)buffer, "meinberg_antenna_status=\""); 373854359Sroberto p = buffer + strlen(buffer); 373954359Sroberto 374054359Sroberto switch (antinfo.status) 374154359Sroberto { 374254359Sroberto case ANT_INVALID: 374354359Sroberto strcat(p, "<OK>"); 374454359Sroberto p += strlen(p); 374554359Sroberto break; 374654359Sroberto 374754359Sroberto case ANT_DISCONN: 374854359Sroberto strcat(p, "DISCONNECTED since "); 374954359Sroberto NLOG(NLOG_CLOCKSTATUS) 375054359Sroberto ERR(ERR_BADSTATUS) 375154359Sroberto msyslog(LOG_ERR,"PARSE receiver #%d: ANTENNA FAILURE: %s", 375254359Sroberto CLK_UNIT(parse->peer), p); 375354359Sroberto 375454359Sroberto p += strlen(p); 375554359Sroberto mbg_tm_str((unsigned char **)&p, &antinfo.tm_disconn); 375654359Sroberto *p = '\0'; 375754359Sroberto break; 375854359Sroberto 375954359Sroberto case ANT_RECONN: 376054359Sroberto strcat(p, "RECONNECTED on "); 376154359Sroberto p += strlen(p); 376254359Sroberto mbg_tm_str((unsigned char **)&p, &antinfo.tm_reconn); 376354359Sroberto sprintf(p, ", reconnect clockoffset %c%ld.%07ld s, disconnect time ", 376454359Sroberto (antinfo.delta_t < 0) ? '-' : '+', 376554359Sroberto ABS(antinfo.delta_t) / 10000, 376654359Sroberto ABS(antinfo.delta_t) % 10000); 376754359Sroberto p += strlen(p); 376854359Sroberto mbg_tm_str((unsigned char **)&p, &antinfo.tm_disconn); 376954359Sroberto *p = '\0'; 377054359Sroberto break; 377154359Sroberto 377254359Sroberto default: 377354359Sroberto sprintf(p, "bad status 0x%04x", antinfo.status); 377454359Sroberto p += strlen(p); 377554359Sroberto break; 377654359Sroberto } 377754359Sroberto 377854359Sroberto *p++ = '"'; 377954359Sroberto *p = '\0'; 378054359Sroberto 378154359Sroberto set_var(&parse->kv, buffer, sizeof(buffer), RO|DEF); 378254359Sroberto } 378354359Sroberto break; 378454359Sroberto 378554359Sroberto case GPS_UCAP: 378654359Sroberto break; 378754359Sroberto 378854359Sroberto case GPS_CFGH: 378954359Sroberto { 379054359Sroberto CFGH cfgh; 379154359Sroberto char buffer[512]; 379254359Sroberto char *p; 379354359Sroberto 379454359Sroberto get_mbg_cfgh(&bufp, &cfgh); 379554359Sroberto if (cfgh.valid) 379654359Sroberto { 379754359Sroberto int i; 379854359Sroberto 379954359Sroberto p = buffer; 380054359Sroberto strcpy(buffer, "gps_tot_51=\""); 380154359Sroberto p += strlen(p); 380254359Sroberto mbg_tgps_str((unsigned char **)&p, &cfgh.tot_51); 380354359Sroberto *p++ = '"'; 380454359Sroberto *p = '\0'; 380554359Sroberto set_var(&parse->kv, buffer, sizeof(buffer), RO); 380654359Sroberto 380754359Sroberto p = buffer; 380854359Sroberto strcpy(buffer, "gps_tot_63=\""); 380954359Sroberto p += strlen(p); 381054359Sroberto mbg_tgps_str((unsigned char **)&p, &cfgh.tot_63); 381154359Sroberto *p++ = '"'; 381254359Sroberto *p = '\0'; 381354359Sroberto set_var(&parse->kv, buffer, sizeof(buffer), RO); 381454359Sroberto 381554359Sroberto p = buffer; 381654359Sroberto strcpy(buffer, "gps_t0a=\""); 381754359Sroberto p += strlen(p); 381854359Sroberto mbg_tgps_str((unsigned char **)&p, &cfgh.t0a); 381954359Sroberto *p++ = '"'; 382054359Sroberto *p = '\0'; 382154359Sroberto set_var(&parse->kv, buffer, sizeof(buffer), RO); 382254359Sroberto 382354359Sroberto for (i = MIN_SVNO; i <= MAX_SVNO; i++) 382454359Sroberto { 382554359Sroberto p = buffer; 382654359Sroberto sprintf(p, "gps_cfg[%d]=\"[0x%x] ", i, cfgh.cfg[i]); 382754359Sroberto p += strlen(p); 382854359Sroberto switch (cfgh.cfg[i] & 0x7) 382954359Sroberto { 383054359Sroberto case 0: 383154359Sroberto strcpy(p, "BLOCK I"); 383254359Sroberto break; 383354359Sroberto case 1: 383454359Sroberto strcpy(p, "BLOCK II"); 383554359Sroberto break; 383654359Sroberto default: 383754359Sroberto sprintf(p, "bad CFG"); 383854359Sroberto break; 383954359Sroberto } 384054359Sroberto strcat(p, "\""); 384154359Sroberto set_var(&parse->kv, buffer, sizeof(buffer), RO); 384254359Sroberto 384354359Sroberto p = buffer; 384454359Sroberto sprintf(p, "gps_health[%d]=\"[0x%x] ", i, cfgh.health[i]); 384554359Sroberto p += strlen(p); 384654359Sroberto switch ((cfgh.health[i] >> 5) & 0x7 ) 384754359Sroberto { 384854359Sroberto case 0: 384954359Sroberto strcpy(p, "OK;"); 385054359Sroberto break; 385154359Sroberto case 1: 385254359Sroberto strcpy(p, "PARITY;"); 385354359Sroberto break; 385454359Sroberto case 2: 385554359Sroberto strcpy(p, "TLM/HOW;"); 385654359Sroberto break; 385754359Sroberto case 3: 385854359Sroberto strcpy(p, "Z-COUNT;"); 385954359Sroberto break; 386054359Sroberto case 4: 386154359Sroberto strcpy(p, "SUBFRAME 1,2,3;"); 386254359Sroberto break; 386354359Sroberto case 5: 386454359Sroberto strcpy(p, "SUBFRAME 4,5;"); 386554359Sroberto break; 386654359Sroberto case 6: 386754359Sroberto strcpy(p, "UPLOAD BAD;"); 386854359Sroberto break; 386954359Sroberto case 7: 387054359Sroberto strcpy(p, "DATA BAD;"); 387154359Sroberto break; 387254359Sroberto } 387354359Sroberto 387454359Sroberto p += strlen(p); 387554359Sroberto 387654359Sroberto switch (cfgh.health[i] & 0x1F) 387754359Sroberto { 387854359Sroberto case 0: 387954359Sroberto strcpy(p, "SIGNAL OK"); 388054359Sroberto break; 388154359Sroberto case 0x1C: 388254359Sroberto strcpy(p, "SV TEMP OUT"); 388354359Sroberto break; 388454359Sroberto case 0x1D: 388554359Sroberto strcpy(p, "SV WILL BE TEMP OUT"); 388654359Sroberto break; 388754359Sroberto case 0x1E: 388854359Sroberto break; 388954359Sroberto case 0x1F: 389054359Sroberto strcpy(p, "MULTIPLE ERRS"); 389154359Sroberto break; 389254359Sroberto default: 389354359Sroberto strcpy(p, "TRANSMISSION PROBLEMS"); 389454359Sroberto break; 389554359Sroberto } 389654359Sroberto 389754359Sroberto strcat(p, "\""); 389854359Sroberto set_var(&parse->kv, buffer, sizeof(buffer), RO); 389954359Sroberto } 390054359Sroberto } 390154359Sroberto } 390254359Sroberto break; 390354359Sroberto 390454359Sroberto case GPS_ALM: 390554359Sroberto break; 390654359Sroberto 390754359Sroberto case GPS_EPH: 390854359Sroberto break; 390954359Sroberto 391054359Sroberto case GPS_UTC: 391154359Sroberto { 391254359Sroberto UTC utc; 391354359Sroberto char buffer[512]; 391454359Sroberto char *p; 391554359Sroberto 391654359Sroberto p = buffer; 391754359Sroberto 391854359Sroberto get_mbg_utc(&bufp, &utc); 391954359Sroberto 392054359Sroberto if (utc.valid) 392154359Sroberto { 392254359Sroberto strcpy(p, "gps_utc_correction=\""); 392354359Sroberto p += strlen(p); 392454359Sroberto mk_utcinfo(p, utc.t0t.wn, utc.WNlsf, utc.DNt, utc.delta_tls, utc.delta_tlsf); 392554359Sroberto strcat(p, "\""); 392654359Sroberto } 392754359Sroberto else 392854359Sroberto { 392954359Sroberto strcpy(p, "gps_utc_correction=\"<NO UTC DATA>\""); 393054359Sroberto } 393154359Sroberto set_var(&parse->kv, buffer, sizeof(buffer), RO|DEF); 393254359Sroberto } 393354359Sroberto break; 393454359Sroberto 393554359Sroberto case GPS_IONO: 393654359Sroberto break; 393754359Sroberto 393854359Sroberto case GPS_ASCII_MSG: 393954359Sroberto { 394054359Sroberto ASCII_MSG gps_ascii_msg; 394154359Sroberto char buffer[128]; 394254359Sroberto 394354359Sroberto get_mbg_ascii_msg(&bufp, &gps_ascii_msg); 394454359Sroberto 394554359Sroberto if (gps_ascii_msg.valid) 394654359Sroberto { 394754359Sroberto char buffer1[128]; 394854359Sroberto mkreadable(buffer1, sizeof(buffer1), gps_ascii_msg.s, strlen(gps_ascii_msg.s), (int)0); 394954359Sroberto 395054359Sroberto sprintf(buffer, "gps_message=\"%s\"", buffer1); 395154359Sroberto } 395254359Sroberto else 395354359Sroberto strcpy(buffer, "gps_message=<NONE>"); 395454359Sroberto 395554359Sroberto set_var(&parse->kv, buffer, 128, RO|DEF); 395654359Sroberto } 395754359Sroberto 395854359Sroberto break; 395954359Sroberto 396054359Sroberto default: 396154359Sroberto break; 396254359Sroberto } 396354359Sroberto } 396454359Sroberto else 396554359Sroberto { 396654359Sroberto 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)", 396754359Sroberto CLK_UNIT(parse->peer), 396854359Sroberto header.gps_hdr_csum, mbg_csum(parsetime->parse_msg + 1, 6), 396954359Sroberto header.gps_len, 397054359Sroberto header.gps_data_csum, mbg_csum(bufp, (unsigned)((header.gps_len < sizeof(parsetime->parse_msg)) ? header.gps_len : 0))); 397154359Sroberto } 397254359Sroberto } 397354359Sroberto 397454359Sroberto return; 397554359Sroberto} 397654359Sroberto 397754359Sroberto/*------------------------------------------------------------ 397854359Sroberto * gps16x_poll - query the reciver peridically 397954359Sroberto */ 398054359Srobertostatic void 398154359Srobertogps16x_poll( 398254359Sroberto struct peer *peer 398354359Sroberto ) 398454359Sroberto{ 398554359Sroberto struct parseunit *parse = (struct parseunit *)peer->procptr->unitptr; 398654359Sroberto 398754359Sroberto static GPS_MSG_HDR sequence[] = 398854359Sroberto { 398954359Sroberto { GPS_SW_REV, 0, 0, 0 }, 399054359Sroberto { GPS_STAT, 0, 0, 0 }, 399154359Sroberto { GPS_UTC, 0, 0, 0 }, 399254359Sroberto { GPS_ASCII_MSG, 0, 0, 0 }, 399354359Sroberto { GPS_ANT_INFO, 0, 0, 0 }, 399454359Sroberto { GPS_CFGH, 0, 0, 0 }, 399554359Sroberto { GPS_POS_XYZ, 0, 0, 0 }, 399654359Sroberto { GPS_POS_LLA, 0, 0, 0 }, 399754359Sroberto { (unsigned short)~0, 0, 0, 0 } 399854359Sroberto }; 399954359Sroberto 400054359Sroberto int rtc; 400154359Sroberto unsigned char cmd_buffer[64]; 400254359Sroberto unsigned char *outp = cmd_buffer; 400354359Sroberto GPS_MSG_HDR *header; 400454359Sroberto 400554359Sroberto if (((poll_info_t *)parse->parse_type->cl_data)->rate) 400654359Sroberto { 400754359Sroberto parse->peer->nextaction = current_time + ((poll_info_t *)parse->parse_type->cl_data)->rate; 400854359Sroberto } 400954359Sroberto 401054359Sroberto if (sequence[parse->localstate].gps_cmd == (unsigned short)~0) 401154359Sroberto parse->localstate = 0; 401254359Sroberto 401354359Sroberto header = sequence + parse->localstate++; 401454359Sroberto 401554359Sroberto *outp++ = SOH; /* start command */ 401654359Sroberto 401754359Sroberto put_mbg_header(&outp, header); 401854359Sroberto outp = cmd_buffer + 1; 401954359Sroberto 402054359Sroberto header->gps_hdr_csum = (short)mbg_csum(outp, 6); 402154359Sroberto put_mbg_header(&outp, header); 402254359Sroberto 402354359Sroberto#ifdef DEBUG 402454359Sroberto if (debug > 2) 402554359Sroberto { 402654359Sroberto char buffer[128]; 402754359Sroberto 402854359Sroberto mkreadable(buffer, sizeof(buffer), (char *)cmd_buffer, (unsigned)(outp - cmd_buffer), 1); 402954359Sroberto printf("PARSE receiver #%d: transmitted message #%ld (%d bytes) >%s<\n", 403054359Sroberto CLK_UNIT(parse->peer), 403154359Sroberto parse->localstate - 1, 403254359Sroberto (int)(outp - cmd_buffer), 403354359Sroberto buffer); 403454359Sroberto } 403554359Sroberto#endif 403654359Sroberto 403754359Sroberto rtc = write(parse->generic->io.fd, cmd_buffer, (unsigned long)(outp - cmd_buffer)); 403854359Sroberto 403954359Sroberto if (rtc < 0) 404054359Sroberto { 404154359Sroberto ERR(ERR_BADIO) 404254359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: gps16x_poll: failed to send cmd to clock: %m", CLK_UNIT(parse->peer)); 404354359Sroberto } 404454359Sroberto else 404554359Sroberto if (rtc != outp - cmd_buffer) 404654359Sroberto { 404754359Sroberto ERR(ERR_BADIO) 404854359Sroberto 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)); 404954359Sroberto } 405054359Sroberto 405154359Sroberto clear_err(parse, ERR_BADIO); 405254359Sroberto return; 405354359Sroberto} 405454359Sroberto 405554359Sroberto/*-------------------------------------------------- 405654359Sroberto * init routine - setup timer 405754359Sroberto */ 405854359Srobertostatic int 405954359Srobertogps16x_poll_init( 406054359Sroberto struct parseunit *parse 406154359Sroberto ) 406254359Sroberto{ 406354359Sroberto if (((poll_info_t *)parse->parse_type->cl_data)->rate) 406454359Sroberto { 406554359Sroberto parse->peer->action = gps16x_poll; 406654359Sroberto gps16x_poll(parse->peer); 406754359Sroberto } 406854359Sroberto 406954359Sroberto return 0; 407054359Sroberto} 407154359Sroberto 407254359Sroberto#else 407354359Srobertostatic void 407454359Srobertogps16x_message( 407554359Sroberto struct parseunit *parse, 407654359Sroberto parsetime_t *parsetime 407754359Sroberto ) 407854359Sroberto{} 407954359Srobertostatic int 408054359Srobertogps16x_poll_init( 408154359Sroberto struct parseunit *parse 408254359Sroberto ) 408354359Sroberto{ 408454359Sroberto return 1; 408554359Sroberto} 408654359Sroberto#endif /* CLOCK_MEINBERG */ 408754359Sroberto 408854359Sroberto/**=========================================================================== 408954359Sroberto ** clock polling support 409054359Sroberto **/ 409154359Sroberto 409254359Sroberto/*-------------------------------------------------- 409354359Sroberto * direct poll routine 409454359Sroberto */ 409554359Srobertostatic void 409654359Srobertopoll_dpoll( 409754359Sroberto struct parseunit *parse 409854359Sroberto ) 409954359Sroberto{ 410054359Sroberto int rtc; 410154359Sroberto const char *ps = ((poll_info_t *)parse->parse_type->cl_data)->string; 410254359Sroberto int ct = ((poll_info_t *)parse->parse_type->cl_data)->count; 410354359Sroberto 410454359Sroberto rtc = write(parse->generic->io.fd, ps, (unsigned long)ct); 410554359Sroberto if (rtc < 0) 410654359Sroberto { 410754359Sroberto ERR(ERR_BADIO) 410854359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: poll_dpoll: failed to send cmd to clock: %m", CLK_UNIT(parse->peer)); 410954359Sroberto } 411054359Sroberto else 411154359Sroberto if (rtc != ct) 411254359Sroberto { 411354359Sroberto ERR(ERR_BADIO) 411454359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: poll_dpoll: failed to send cmd incomplete (%d of %d bytes sent)", CLK_UNIT(parse->peer), rtc, ct); 411554359Sroberto } 411654359Sroberto clear_err(parse, ERR_BADIO); 411754359Sroberto} 411854359Sroberto 411954359Sroberto/*-------------------------------------------------- 412054359Sroberto * periodic poll routine 412154359Sroberto */ 412254359Srobertostatic void 412354359Srobertopoll_poll( 412454359Sroberto struct peer *peer 412554359Sroberto ) 412654359Sroberto{ 412754359Sroberto struct parseunit *parse = (struct parseunit *)peer->procptr->unitptr; 412854359Sroberto 412954359Sroberto if (parse->parse_type->cl_poll) 413054359Sroberto parse->parse_type->cl_poll(parse); 413154359Sroberto 413254359Sroberto if (((poll_info_t *)parse->parse_type->cl_data)->rate) 413354359Sroberto { 413454359Sroberto parse->peer->nextaction = current_time + ((poll_info_t *)parse->parse_type->cl_data)->rate; 413554359Sroberto } 413654359Sroberto} 413754359Sroberto 413854359Sroberto/*-------------------------------------------------- 413954359Sroberto * init routine - setup timer 414054359Sroberto */ 414154359Srobertostatic int 414254359Srobertopoll_init( 414354359Sroberto struct parseunit *parse 414454359Sroberto ) 414554359Sroberto{ 414654359Sroberto if (((poll_info_t *)parse->parse_type->cl_data)->rate) 414754359Sroberto { 414854359Sroberto parse->peer->action = poll_poll; 414954359Sroberto poll_poll(parse->peer); 415054359Sroberto } 415154359Sroberto 415254359Sroberto return 0; 415354359Sroberto} 415456746Sroberto 415554359Sroberto/**=========================================================================== 415654359Sroberto ** Trimble support 415754359Sroberto **/ 415854359Sroberto 415954359Sroberto/*------------------------------------------------------------- 416054359Sroberto * trimble TAIP init routine - setup EOL and then do poll_init. 416154359Sroberto */ 416254359Srobertostatic int 416354359Srobertotrimbletaip_init( 416454359Sroberto struct parseunit *parse 416554359Sroberto ) 416654359Sroberto{ 416754359Sroberto#ifdef HAVE_TERMIOS 416854359Sroberto struct termios tio; 416954359Sroberto#endif 417054359Sroberto#ifdef HAVE_SYSV_TTYS 417154359Sroberto struct termio tio; 417254359Sroberto#endif 417354359Sroberto /* 417454359Sroberto * configure terminal line for trimble receiver 417554359Sroberto */ 417654359Sroberto if (TTY_GETATTR(parse->generic->io.fd, &tio) == -1) 417754359Sroberto { 417854359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_init: tcgetattr(fd, &tio): %m", CLK_UNIT(parse->peer)); 417954359Sroberto return 0; 418054359Sroberto } 418154359Sroberto else 418254359Sroberto { 418354359Sroberto tio.c_cc[VEOL] = TRIMBLETAIP_EOL; 418454359Sroberto 418554359Sroberto if (TTY_SETATTR(parse->generic->io.fd, &tio) == -1) 418654359Sroberto { 418754359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_init: tcsetattr(fd, &tio): %m", CLK_UNIT(parse->peer)); 418854359Sroberto return 0; 418954359Sroberto } 419054359Sroberto } 419154359Sroberto return poll_init(parse); 419254359Sroberto} 419354359Sroberto 419454359Sroberto/*-------------------------------------------------- 419554359Sroberto * trimble TAIP event routine - reset receiver upon data format trouble 419654359Sroberto */ 419754359Srobertostatic const char *taipinit[] = { 419854359Sroberto ">FPV00000000<", 419954359Sroberto ">SRM;ID_FLAG=F;CS_FLAG=T;EC_FLAG=F;FR_FLAG=T;CR_FLAG=F<", 420054359Sroberto ">FTM00020001<", 420154359Sroberto (char *)0 420254359Sroberto}; 420354359Sroberto 420454359Srobertostatic void 420554359Srobertotrimbletaip_event( 420654359Sroberto struct parseunit *parse, 420754359Sroberto int event 420854359Sroberto ) 420954359Sroberto{ 421054359Sroberto switch (event) 421154359Sroberto { 421254359Sroberto case CEVNT_BADREPLY: /* reset on garbled input */ 421354359Sroberto case CEVNT_TIMEOUT: /* reset on no input */ 421454359Sroberto { 421554359Sroberto const char **iv; 421654359Sroberto 421754359Sroberto iv = taipinit; 421854359Sroberto while (*iv) 421954359Sroberto { 422054359Sroberto int rtc = write(parse->generic->io.fd, *iv, strlen(*iv)); 422154359Sroberto if (rtc < 0) 422254359Sroberto { 422354359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_event: failed to send cmd to clock: %m", CLK_UNIT(parse->peer)); 422454359Sroberto return; 422554359Sroberto } 422654359Sroberto else 422754359Sroberto { 422854359Sroberto if (rtc != strlen(*iv)) 422954359Sroberto { 423054359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_event: failed to send cmd incomplete (%d of %d bytes sent)", 423154359Sroberto CLK_UNIT(parse->peer), rtc, (int)strlen(*iv)); 423254359Sroberto return; 423354359Sroberto } 423454359Sroberto } 423554359Sroberto iv++; 423654359Sroberto } 423754359Sroberto 423854359Sroberto NLOG(NLOG_CLOCKINFO) 423954359Sroberto ERR(ERR_BADIO) 424054359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_event: RECEIVER INITIALIZED", 424154359Sroberto CLK_UNIT(parse->peer)); 424254359Sroberto } 424354359Sroberto break; 424454359Sroberto 424554359Sroberto default: /* ignore */ 424654359Sroberto break; 424754359Sroberto } 424854359Sroberto} 424954359Sroberto 425054359Sroberto/* 425154359Sroberto * This driver supports the Trimble SVee Six Plus GPS receiver module. 425254359Sroberto * It should support other Trimble receivers which use the Trimble Standard 425354359Sroberto * Interface Protocol (see below). 425454359Sroberto * 425554359Sroberto * The module has a serial I/O port for command/data and a 1 pulse-per-second 425654359Sroberto * output, about 1 microsecond wide. The leading edge of the pulse is 425754359Sroberto * coincident with the change of the GPS second. This is the same as 425854359Sroberto * the change of the UTC second +/- ~1 microsecond. Some other clocks 425954359Sroberto * specifically use a feature in the data message as a timing reference, but 426054359Sroberto * the SVee Six Plus does not do this. In fact there is considerable jitter 426154359Sroberto * on the timing of the messages, so this driver only supports the use 426254359Sroberto * of the PPS pulse for accurate timing. Where it is determined that 426354359Sroberto * the offset is way off, when first starting up ntpd for example, 426454359Sroberto * the timing of the data stream is used until the offset becomes low enough 426556746Sroberto * (|offset| < CLOCK_MAX), at which point the pps offset is used. 426654359Sroberto * 426754359Sroberto * It can use either option for receiving PPS information - the 'ppsclock' 426854359Sroberto * stream pushed onto the serial data interface to timestamp the Carrier 426954359Sroberto * Detect interrupts, where the 1PPS connects to the CD line. This only 427054359Sroberto * works on SunOS 4.1.x currently. To select this, define PPSPPS in 427154359Sroberto * Config.local. The other option is to use a pulse-stretcher/level-converter 427254359Sroberto * to convert the PPS pulse into a RS232 start pulse & feed this into another 427354359Sroberto * tty port. To use this option, define PPSCLK in Config.local. The pps input, 427454359Sroberto * by whichever method, is handled in ntp_loopfilter.c 427554359Sroberto * 427654359Sroberto * The receiver uses a serial message protocol called Trimble Standard 427754359Sroberto * Interface Protocol (it can support others but this driver only supports 427854359Sroberto * TSIP). Messages in this protocol have the following form: 427954359Sroberto * 428054359Sroberto * <DLE><id> ... <data> ... <DLE><ETX> 428154359Sroberto * 428254359Sroberto * Any bytes within the <data> portion of value 10 hex (<DLE>) are doubled 428354359Sroberto * on transmission and compressed back to one on reception. Otherwise 428454359Sroberto * the values of data bytes can be anything. The serial interface is RS-422 428554359Sroberto * asynchronous using 9600 baud, 8 data bits with odd party (**note** 9 bits 428654359Sroberto * in total!), and 1 stop bit. The protocol supports byte, integer, single, 428754359Sroberto * and double datatypes. Integers are two bytes, sent most significant first. 428854359Sroberto * Singles are IEEE754 single precision floating point numbers (4 byte) sent 428954359Sroberto * sign & exponent first. Doubles are IEEE754 double precision floating point 429054359Sroberto * numbers (8 byte) sent sign & exponent first. 429154359Sroberto * The receiver supports a large set of messages, only a small subset of 429254359Sroberto * which are used here. From driver to receiver the following are used: 429354359Sroberto * 429454359Sroberto * ID Description 429554359Sroberto * 429654359Sroberto * 21 Request current time 429754359Sroberto * 22 Mode Select 429854359Sroberto * 2C Set/Request operating parameters 429954359Sroberto * 2F Request UTC info 430054359Sroberto * 35 Set/Request I/O options 430154359Sroberto 430254359Sroberto * From receiver to driver the following are recognised: 430354359Sroberto * 430454359Sroberto * ID Description 430554359Sroberto * 430654359Sroberto * 41 GPS Time 430754359Sroberto * 44 Satellite selection, PDOP, mode 430854359Sroberto * 46 Receiver health 430954359Sroberto * 4B Machine code/status 431054359Sroberto * 4C Report operating parameters (debug only) 431154359Sroberto * 4F UTC correction data (used to get leap second warnings) 431254359Sroberto * 55 I/O options (debug only) 431354359Sroberto * 431454359Sroberto * All others are accepted but ignored. 431554359Sroberto * 431654359Sroberto */ 431754359Sroberto 431854359Sroberto#define PI 3.1415926535898 /* lots of sig figs */ 431954359Sroberto#define D2R PI/180.0 432054359Sroberto 432154359Sroberto/*------------------------------------------------------------------- 432254359Sroberto * sendcmd, sendbyte, sendetx, sendflt, sendint implement the command 432354359Sroberto * interface to the receiver. 432454359Sroberto * 432554359Sroberto * CAVEAT: the sendflt, sendint routines are byte order dependend and 432654359Sroberto * float implementation dependend - these must be converted to portable 432754359Sroberto * versions ! 432854359Sroberto * 432954359Sroberto * CURRENT LIMITATION: float implementation. This runs only on systems 433054359Sroberto * with IEEE754 floats as native floats 433154359Sroberto */ 433254359Sroberto 433354359Srobertotypedef struct trimble 433454359Sroberto{ 433554359Sroberto u_long last_msg; /* last message received */ 433654359Sroberto u_char qtracking; /* query tracking status */ 433754359Sroberto u_long ctrack; /* current tracking set */ 433854359Sroberto u_long ltrack; /* last tracking set */ 433954359Sroberto} trimble_t; 434054359Sroberto 434154359Srobertounion uval { 434254359Sroberto u_char bd[8]; 434354359Sroberto int iv; 434454359Sroberto float fv; 434554359Sroberto double dv; 434654359Sroberto}; 434754359Sroberto 434854359Srobertostruct txbuf 434954359Sroberto{ 435054359Sroberto short idx; /* index to first unused byte */ 435154359Sroberto u_char *txt; /* pointer to actual data buffer */ 435254359Sroberto}; 435354359Sroberto 435456746Srobertovoid sendcmd P((struct txbuf *buf, int c)); 435556746Srobertovoid sendbyte P((struct txbuf *buf, int b)); 435656746Srobertovoid sendetx P((struct txbuf *buf, struct parseunit *parse)); 435756746Srobertovoid sendint P((struct txbuf *buf, int a)); 435856746Srobertovoid sendflt P((struct txbuf *buf, double a)); 435956746Sroberto 436054359Srobertovoid 436154359Srobertosendcmd( 436254359Sroberto struct txbuf *buf, 436354359Sroberto int c 436454359Sroberto ) 436554359Sroberto{ 436654359Sroberto buf->txt[0] = DLE; 436754359Sroberto buf->txt[1] = (u_char)c; 436854359Sroberto buf->idx = 2; 436954359Sroberto} 437054359Sroberto 437154359Srobertovoid 437254359Srobertosendbyte( 437354359Sroberto struct txbuf *buf, 437454359Sroberto int b 437554359Sroberto ) 437654359Sroberto{ 437754359Sroberto if (b == DLE) 437854359Sroberto buf->txt[buf->idx++] = DLE; 437954359Sroberto buf->txt[buf->idx++] = (u_char)b; 438054359Sroberto} 438154359Sroberto 438254359Srobertovoid 438354359Srobertosendetx( 438454359Sroberto struct txbuf *buf, 438554359Sroberto struct parseunit *parse 438654359Sroberto ) 438754359Sroberto{ 438854359Sroberto buf->txt[buf->idx++] = DLE; 438954359Sroberto buf->txt[buf->idx++] = ETX; 439054359Sroberto 439154359Sroberto if (write(parse->generic->io.fd, buf->txt, (unsigned long)buf->idx) != buf->idx) 439254359Sroberto { 439354359Sroberto ERR(ERR_BADIO) 439454359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: sendetx: failed to send cmd to clock: %m", CLK_UNIT(parse->peer)); 439554359Sroberto } 439654359Sroberto else 439754359Sroberto { 439854359Sroberto#ifdef DEBUG 439954359Sroberto if (debug > 2) 440054359Sroberto { 440154359Sroberto char buffer[256]; 440254359Sroberto 440354359Sroberto mkreadable(buffer, sizeof(buffer), (char *)buf->txt, (unsigned)buf->idx, 1); 440454359Sroberto printf("PARSE receiver #%d: transmitted message (%d bytes) >%s<\n", 440554359Sroberto CLK_UNIT(parse->peer), 440654359Sroberto buf->idx, buffer); 440754359Sroberto } 440854359Sroberto#endif 440954359Sroberto clear_err(parse, ERR_BADIO); 441054359Sroberto } 441154359Sroberto} 441254359Sroberto 441354359Srobertovoid 441454359Srobertosendint( 441554359Sroberto struct txbuf *buf, 441654359Sroberto int a 441754359Sroberto ) 441854359Sroberto{ 441954359Sroberto /* send 16bit int, msbyte first */ 442054359Sroberto sendbyte(buf, (u_char)((a>>8) & 0xff)); 442154359Sroberto sendbyte(buf, (u_char)(a & 0xff)); 442254359Sroberto} 442354359Sroberto 442454359Srobertovoid 442554359Srobertosendflt( 442654359Sroberto struct txbuf *buf, 442754359Sroberto double a 442854359Sroberto ) 442954359Sroberto{ 443054359Sroberto int i; 443154359Sroberto union uval uval; 443254359Sroberto 443354359Sroberto uval.fv = a; 443454359Sroberto#ifdef WORDS_BIGENDIAN 443554359Sroberto for (i=0; i<=3; i++) 443654359Sroberto#else 443754359Sroberto for (i=3; i>=0; i--) 443854359Sroberto#endif 443954359Sroberto sendbyte(buf, uval.bd[i]); 444054359Sroberto} 444154359Sroberto 444254359Sroberto#define TRIM_POS_OPT 0x13 /* output position with high precision */ 444354359Sroberto#define TRIM_TIME_OPT 0x03 /* use UTC time stamps, on second */ 444454359Sroberto 444554359Sroberto/*-------------------------------------------------- 444654359Sroberto * trimble TSIP setup routine 444754359Sroberto */ 444854359Srobertostatic int 444954359Srobertotrimbletsip_setup( 445054359Sroberto struct parseunit *parse, 445154359Sroberto const char *reason 445256746Sroberto ) 445354359Sroberto{ 445454359Sroberto u_char buffer[256]; 445554359Sroberto struct txbuf buf; 445654359Sroberto 445754359Sroberto buf.txt = buffer; 445854359Sroberto 445954359Sroberto sendcmd(&buf, CMD_CVERSION); /* request software versions */ 446056746Sroberto sendetx(&buf, parse); 446156746Sroberto 446254359Sroberto sendcmd(&buf, CMD_COPERPARAM); /* set operating parameters */ 446356746Sroberto sendbyte(&buf, 4); /* static */ 446456746Sroberto sendflt(&buf, 5.0*D2R); /* elevation angle mask = 10 deg XXX */ 446556746Sroberto sendflt(&buf, 4.0); /* s/n ratio mask = 6 XXX */ 446656746Sroberto sendflt(&buf, 12.0); /* PDOP mask = 12 */ 446756746Sroberto sendflt(&buf, 8.0); /* PDOP switch level = 8 */ 446856746Sroberto sendetx(&buf, parse); 446956746Sroberto 447054359Sroberto sendcmd(&buf, CMD_CMODESEL); /* fix mode select */ 447156746Sroberto sendbyte(&buf, 0); /* automatic */ 447256746Sroberto sendetx(&buf, parse); 447356746Sroberto 447454359Sroberto sendcmd(&buf, CMD_CMESSAGE); /* request system message */ 447556746Sroberto sendetx(&buf, parse); 447656746Sroberto 447754359Sroberto sendcmd(&buf, CMD_CSUPER); /* superpacket fix */ 447856746Sroberto sendbyte(&buf, 0x2); /* binary mode */ 447956746Sroberto sendetx(&buf, parse); 448056746Sroberto 448154359Sroberto sendcmd(&buf, CMD_CIOOPTIONS); /* set I/O options */ 448254359Sroberto sendbyte(&buf, TRIM_POS_OPT); /* position output */ 448354359Sroberto sendbyte(&buf, 0x00); /* no velocity output */ 448454359Sroberto sendbyte(&buf, TRIM_TIME_OPT); /* UTC, compute on seconds */ 448554359Sroberto sendbyte(&buf, 0x00); /* no raw measurements */ 448656746Sroberto sendetx(&buf, parse); 448756746Sroberto 448854359Sroberto sendcmd(&buf, CMD_CUTCPARAM); /* request UTC correction data */ 448954359Sroberto sendetx(&buf, parse); 449054359Sroberto 449154359Sroberto NLOG(NLOG_CLOCKINFO) 449254359Sroberto ERR(ERR_BADIO) 449354359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: trimbletsip_setup: RECEIVER RE-INITIALIZED (%s)", CLK_UNIT(parse->peer), reason); 449454359Sroberto 449554359Sroberto return 0; 449654359Sroberto} 449754359Sroberto 449854359Sroberto/*-------------------------------------------------- 449954359Sroberto * TRIMBLE TSIP check routine 450054359Sroberto */ 450154359Srobertostatic void 450254359Srobertotrimble_check( 450354359Sroberto struct peer *peer 450454359Sroberto ) 450554359Sroberto{ 450654359Sroberto struct parseunit *parse = (struct parseunit *)peer->procptr->unitptr; 450754359Sroberto trimble_t *t = parse->localdata; 450854359Sroberto u_char buffer[256]; 450954359Sroberto struct txbuf buf; 451054359Sroberto buf.txt = buffer; 451154359Sroberto 451254359Sroberto if (t) 451354359Sroberto { 451454359Sroberto if (current_time > t->last_msg + TRIMBLETSIP_IDLE_TIME) 451554359Sroberto (void)trimbletsip_setup(parse, "message timeout"); 451654359Sroberto } 451754359Sroberto poll_poll(parse->peer); /* emit query string and re-arm timer */ 451854359Sroberto 451954359Sroberto if (t->qtracking) 452054359Sroberto { 452154359Sroberto u_long oldsats = t->ltrack & ~t->ctrack; 452254359Sroberto 452354359Sroberto t->qtracking = 0; 452454359Sroberto t->ltrack = t->ctrack; 452554359Sroberto 452654359Sroberto if (oldsats) 452754359Sroberto { 452854359Sroberto int i; 452954359Sroberto 453054359Sroberto for (i = 0; oldsats; i++) 453154359Sroberto if (oldsats & (1 << i)) 453254359Sroberto { 453354359Sroberto sendcmd(&buf, CMD_CSTATTRACK); 453454359Sroberto sendbyte(&buf, i+1); /* old sat */ 453554359Sroberto sendetx(&buf, parse); 453654359Sroberto } 453754359Sroberto oldsats &= ~(1 << i); 453854359Sroberto } 453954359Sroberto 454054359Sroberto sendcmd(&buf, CMD_CSTATTRACK); 454154359Sroberto sendbyte(&buf, 0x00); /* current tracking set */ 454254359Sroberto sendetx(&buf, parse); 454354359Sroberto } 454454359Sroberto} 454554359Sroberto 454654359Sroberto/*-------------------------------------------------- 454754359Sroberto * TRIMBLE TSIP end routine 454854359Sroberto */ 454954359Srobertostatic void 455054359Srobertotrimbletsip_end( 455154359Sroberto struct parseunit *parse 455254359Sroberto ) 455354359Sroberto{ trimble_t *t = parse->localdata; 455454359Sroberto 455554359Sroberto if (t) 455654359Sroberto { 455754359Sroberto free(t); 455854359Sroberto parse->localdata = (void *)0; 455954359Sroberto } 456054359Sroberto parse->peer->nextaction = 0; 456154359Sroberto parse->peer->action = (void (*) P((struct peer *)))0; 456254359Sroberto} 456354359Sroberto 456454359Sroberto/*-------------------------------------------------- 456554359Sroberto * TRIMBLE TSIP init routine 456654359Sroberto */ 456754359Srobertostatic int 456854359Srobertotrimbletsip_init( 456954359Sroberto struct parseunit *parse 457054359Sroberto ) 457154359Sroberto{ 457254359Sroberto#if defined(VEOL) || defined(VEOL2) 457354359Sroberto#ifdef HAVE_TERMIOS 457454359Sroberto struct termios tio; /* NEEDED FOR A LONG TIME ! */ 457554359Sroberto#endif 457654359Sroberto#ifdef HAVE_SYSV_TTYS 457754359Sroberto struct termio tio; /* NEEDED FOR A LONG TIME ! */ 457854359Sroberto#endif 457954359Sroberto /* 458054359Sroberto * allocate local data area 458154359Sroberto */ 458254359Sroberto if (!parse->localdata) 458354359Sroberto { 458454359Sroberto trimble_t *t; 458554359Sroberto 458654359Sroberto t = (trimble_t *)(parse->localdata = emalloc(sizeof(trimble_t))); 458754359Sroberto 458854359Sroberto if (t) 458954359Sroberto { 459054359Sroberto memset((char *)t, 0, sizeof(trimble_t)); 459154359Sroberto t->last_msg = current_time; 459254359Sroberto } 459354359Sroberto } 459454359Sroberto 459554359Sroberto parse->peer->action = trimble_check; 459654359Sroberto parse->peer->nextaction = current_time; 459754359Sroberto 459854359Sroberto /* 459954359Sroberto * configure terminal line for ICANON mode with VEOL characters 460054359Sroberto */ 460154359Sroberto if (TTY_GETATTR(parse->generic->io.fd, &tio) == -1) 460254359Sroberto { 460354359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: trimbletsip_init: tcgetattr(%d, &tio): %m", CLK_UNIT(parse->peer), parse->generic->io.fd); 460454359Sroberto return 0; 460554359Sroberto } 460654359Sroberto else 460754359Sroberto { 460854359Sroberto if ((parse_clockinfo[CLK_TYPE(parse->peer)].cl_lflag & ICANON)) 460954359Sroberto { 461054359Sroberto#ifdef VEOL 461154359Sroberto tio.c_cc[VEOL] = ETX; 461254359Sroberto#endif 461354359Sroberto#ifdef VEOL2 461454359Sroberto tio.c_cc[VEOL2] = DLE; 461554359Sroberto#endif 461656746Sroberto } 461754359Sroberto 461854359Sroberto if (TTY_SETATTR(parse->generic->io.fd, &tio) == -1) 461954359Sroberto { 462054359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: trimbletsip_init: tcsetattr(%d, &tio): %m", CLK_UNIT(parse->peer), parse->generic->io.fd); 462154359Sroberto return 0; 462254359Sroberto } 462354359Sroberto } 462454359Sroberto#endif 462554359Sroberto return trimbletsip_setup(parse, "initial startup"); 462654359Sroberto} 462754359Sroberto 462854359Sroberto/*------------------------------------------------------------ 462954359Sroberto * trimbletsip_event - handle Trimble events 463054359Sroberto * simple evente handler - attempt to re-initialize receiver 463154359Sroberto */ 463254359Srobertostatic void 463354359Srobertotrimbletsip_event( 463454359Sroberto struct parseunit *parse, 463554359Sroberto int event 463654359Sroberto ) 463754359Sroberto{ 463854359Sroberto switch (event) 463954359Sroberto { 464054359Sroberto case CEVNT_BADREPLY: /* reset on garbled input */ 464154359Sroberto case CEVNT_TIMEOUT: /* reset on no input */ 464254359Sroberto (void)trimbletsip_setup(parse, "event BAD_REPLY/TIMEOUT"); 464354359Sroberto break; 464454359Sroberto 464554359Sroberto default: /* ignore */ 464654359Sroberto break; 464754359Sroberto } 464854359Sroberto} 464954359Sroberto 465054359Sroberto/* 465154359Sroberto * getflt, getint convert fields in the incoming data into the 465254359Sroberto * appropriate type of item 465354359Sroberto * 465454359Sroberto * CAVEAT: these routines are currently definitely byte order dependent 465554359Sroberto * and assume Representation(float) == IEEE754 465654359Sroberto * These functions MUST be converted to portable versions (especially 465754359Sroberto * converting the float representation into ntp_fp formats in order 465854359Sroberto * to avoid floating point operations at all! 465954359Sroberto */ 466054359Sroberto 466154359Srobertostatic float 466254359Srobertogetflt( 466354359Sroberto u_char *bp 466454359Sroberto ) 466554359Sroberto{ 466654359Sroberto union uval uval; 466754359Sroberto 466854359Sroberto#ifdef WORDS_BIGENDIAN 466954359Sroberto uval.bd[0] = *bp++; 467054359Sroberto uval.bd[1] = *bp++; 467154359Sroberto uval.bd[2] = *bp++; 467254359Sroberto uval.bd[3] = *bp; 467354359Sroberto#else /* ! WORDS_BIGENDIAN */ 467454359Sroberto uval.bd[3] = *bp++; 467554359Sroberto uval.bd[2] = *bp++; 467654359Sroberto uval.bd[1] = *bp++; 467754359Sroberto uval.bd[0] = *bp; 467854359Sroberto#endif /* ! WORDS_BIGENDIAN */ 467954359Sroberto return uval.fv; 468054359Sroberto} 468154359Sroberto 468254359Srobertostatic double 468354359Srobertogetdbl( 468454359Sroberto u_char *bp 468554359Sroberto ) 468654359Sroberto{ 468754359Sroberto union uval uval; 468854359Sroberto 468954359Sroberto#ifdef WORDS_BIGENDIAN 469054359Sroberto uval.bd[0] = *bp++; 469154359Sroberto uval.bd[1] = *bp++; 469254359Sroberto uval.bd[2] = *bp++; 469354359Sroberto uval.bd[3] = *bp++; 469454359Sroberto uval.bd[4] = *bp++; 469554359Sroberto uval.bd[5] = *bp++; 469654359Sroberto uval.bd[6] = *bp++; 469754359Sroberto uval.bd[7] = *bp; 469854359Sroberto#else /* ! WORDS_BIGENDIAN */ 469954359Sroberto uval.bd[7] = *bp++; 470054359Sroberto uval.bd[6] = *bp++; 470154359Sroberto uval.bd[5] = *bp++; 470254359Sroberto uval.bd[4] = *bp++; 470354359Sroberto uval.bd[3] = *bp++; 470454359Sroberto uval.bd[2] = *bp++; 470554359Sroberto uval.bd[1] = *bp++; 470654359Sroberto uval.bd[0] = *bp; 470754359Sroberto#endif /* ! WORDS_BIGENDIAN */ 470854359Sroberto return uval.dv; 470954359Sroberto} 471054359Sroberto 471154359Srobertostatic int 471254359Srobertogetshort( 471354359Sroberto unsigned char *p 471454359Sroberto ) 471554359Sroberto{ 471654359Sroberto return get_msb_short(&p); 471754359Sroberto} 471854359Sroberto 471954359Sroberto/*-------------------------------------------------- 472054359Sroberto * trimbletsip_message - process trimble messages 472154359Sroberto */ 472254359Sroberto#define RTOD (180.0 / 3.1415926535898) 472354359Sroberto#define mb(_X_) (buffer[2+(_X_)]) /* shortcut for buffer access */ 472454359Sroberto 472554359Srobertostatic void 472654359Srobertotrimbletsip_message( 472754359Sroberto struct parseunit *parse, 472854359Sroberto parsetime_t *parsetime 472954359Sroberto ) 473054359Sroberto{ 473154359Sroberto unsigned char *buffer = parsetime->parse_msg; 473254359Sroberto unsigned int size = parsetime->parse_msglen; 473354359Sroberto 473454359Sroberto if ((size < 4) || 473554359Sroberto (buffer[0] != DLE) || 473654359Sroberto (buffer[size-1] != ETX) || 473754359Sroberto (buffer[size-2] != DLE)) 473854359Sroberto { 473954359Sroberto#ifdef DEBUG 474054359Sroberto if (debug > 2) { 474154359Sroberto int i; 474254359Sroberto 474354359Sroberto printf("TRIMBLE BAD packet, size %d:\n ", size); 474454359Sroberto for (i = 0; i < size; i++) { 474554359Sroberto printf ("%2.2x, ", buffer[i]&0xff); 474654359Sroberto if (i%16 == 15) printf("\n\t"); 474754359Sroberto } 474854359Sroberto printf("\n"); 474954359Sroberto } 475054359Sroberto#endif 475154359Sroberto return; 475254359Sroberto } 475354359Sroberto else 475454359Sroberto { 475554359Sroberto int var_flag; 475654359Sroberto trimble_t *tr = parse->localdata; 475754359Sroberto unsigned int cmd = buffer[1]; 475854359Sroberto char pbuffer[200]; 475954359Sroberto char *t = pbuffer; 476054359Sroberto cmd_info_t *s; 476154359Sroberto 476254359Sroberto#ifdef DEBUG 476354359Sroberto if (debug > 3) { 476454359Sroberto int i; 476554359Sroberto 476654359Sroberto printf("TRIMBLE packet 0x%02x, size %d:\n ", cmd, size); 476754359Sroberto for (i = 0; i < size; i++) { 476854359Sroberto printf ("%2.2x, ", buffer[i]&0xff); 476954359Sroberto if (i%16 == 15) printf("\n\t"); 477054359Sroberto } 477154359Sroberto printf("\n"); 477254359Sroberto } 477354359Sroberto#endif 477454359Sroberto 477554359Sroberto if (tr) 477654359Sroberto tr->last_msg = current_time; 477754359Sroberto 477854359Sroberto s = trimble_convert(cmd, trimble_rcmds); 477954359Sroberto 478054359Sroberto if (s) 478154359Sroberto { 478254359Sroberto sprintf(t, "%s=\"", s->varname); 478354359Sroberto } 478454359Sroberto else 478554359Sroberto { 478654359Sroberto printf("TRIMBLE unknown command 0x%02x\n", cmd); 478754359Sroberto return; 478854359Sroberto } 478954359Sroberto 479054359Sroberto var_flag = s->varmode; 479154359Sroberto 479254359Sroberto t += strlen(t); 479354359Sroberto 479454359Sroberto switch(cmd) 479554359Sroberto { 479654359Sroberto case CMD_RCURTIME: 479754359Sroberto sprintf(t, "%f, %d, %f", 479854359Sroberto getflt((unsigned char *)&mb(0)), getshort((unsigned char *)&mb(4)), 479954359Sroberto getflt((unsigned char *)&mb(6))); 480054359Sroberto break; 480154359Sroberto 480254359Sroberto case CMD_RBEST4: 480354359Sroberto strcpy(t, "mode: "); 480454359Sroberto t += strlen(t); 480554359Sroberto switch (mb(0) & 0xF) 480654359Sroberto { 480754359Sroberto default: 480854359Sroberto sprintf(t, "0x%x", mb(0) & 0x7); 480954359Sroberto break; 481054359Sroberto 481154359Sroberto case 1: 481254359Sroberto strcat(t, "0D"); 481354359Sroberto break; 481454359Sroberto 481554359Sroberto case 3: 481654359Sroberto strcat(t, "2D"); 481754359Sroberto break; 481854359Sroberto 481954359Sroberto case 4: 482054359Sroberto strcat(t, "3D"); 482154359Sroberto break; 482254359Sroberto } 482354359Sroberto t += strlen(t); 482454359Sroberto if (mb(0) & 0x10) 482554359Sroberto strcpy(t, "-MANUAL, "); 482654359Sroberto else 482754359Sroberto strcpy(t, "-AUTO, "); 482854359Sroberto t += strlen(t); 482954359Sroberto 483054359Sroberto sprintf(t, "satellites %02d %02d %02d %02d, PDOP %.2f, HDOP %.2f, VDOP %.2f, TDOP %.2f", 483154359Sroberto mb(1), mb(2), mb(3), mb(4), 483254359Sroberto getflt((unsigned char *)&mb(5)), 483354359Sroberto getflt((unsigned char *)&mb(9)), 483454359Sroberto getflt((unsigned char *)&mb(13)), 483554359Sroberto getflt((unsigned char *)&mb(17))); 483654359Sroberto 483754359Sroberto break; 483854359Sroberto 483954359Sroberto case CMD_RVERSION: 484054359Sroberto sprintf(t, "%d.%d (%d/%d/%d)", 484154359Sroberto mb(0)&0xff, mb(1)&0xff, 1900+(mb(4)&0xff), mb(2)&0xff, mb(3)&0xff); 484254359Sroberto break; 484354359Sroberto 484454359Sroberto case CMD_RRECVHEALTH: 484554359Sroberto { 484654359Sroberto static const char *msgs[] = 484754359Sroberto { 484854359Sroberto "Battery backup failed", 484954359Sroberto "Signal processor error", 485054359Sroberto "Alignment error, channel or chip 1", 485154359Sroberto "Alignment error, channel or chip 2", 485254359Sroberto "Antenna feed line fault", 485354359Sroberto "Excessive ref freq. error", 485454359Sroberto "<BIT 6>", 485554359Sroberto "<BIT 7>" 485654359Sroberto }; 485754359Sroberto 485854359Sroberto int i, bits; 485954359Sroberto 486054359Sroberto switch (mb(0) & 0xFF) 486154359Sroberto { 486254359Sroberto default: 486354359Sroberto sprintf(t, "illegal value 0x%02x", mb(0) & 0xFF); 486454359Sroberto break; 486554359Sroberto case 0x00: 486654359Sroberto strcpy(t, "doing position fixes"); 486754359Sroberto break; 486854359Sroberto case 0x01: 486954359Sroberto strcpy(t, "no GPS time yet"); 487054359Sroberto break; 487154359Sroberto case 0x03: 487254359Sroberto strcpy(t, "PDOP too high"); 487354359Sroberto break; 487454359Sroberto case 0x08: 487554359Sroberto strcpy(t, "no usable satellites"); 487654359Sroberto break; 487754359Sroberto case 0x09: 487854359Sroberto strcpy(t, "only ONE usable satellite"); 487954359Sroberto break; 488054359Sroberto case 0x0A: 488154359Sroberto strcpy(t, "only TWO usable satellites"); 488254359Sroberto break; 488354359Sroberto case 0x0B: 488454359Sroberto strcpy(t, "only THREE usable satellites"); 488554359Sroberto break; 488654359Sroberto case 0x0C: 488754359Sroberto strcpy(t, "the chosen satellite is unusable"); 488854359Sroberto break; 488954359Sroberto } 489054359Sroberto 489154359Sroberto t += strlen(t); 489254359Sroberto 489354359Sroberto bits = mb(1) & 0xFF; 489454359Sroberto 489554359Sroberto for (i = 0; i < 8; i++) 489654359Sroberto if (bits & (0x1<<i)) 489754359Sroberto { 489854359Sroberto sprintf(t, ", %s", msgs[i]); 489954359Sroberto t += strlen(t); 490054359Sroberto } 490154359Sroberto } 490254359Sroberto break; 490354359Sroberto 490454359Sroberto case CMD_RMESSAGE: 490554359Sroberto mkreadable(t, (int)(sizeof(pbuffer) - (t - pbuffer)), (char *)&mb(0), (unsigned)(size - 2 - (&mb(0) - buffer)), 0); 490654359Sroberto break; 490754359Sroberto 490854359Sroberto case CMD_RMACHSTAT: 490954359Sroberto { 491054359Sroberto static const char *msgs[] = 491154359Sroberto { 491254359Sroberto "Synthesizer Fault", 491354359Sroberto "Battery Powered Time Clock Fault", 491454359Sroberto "A-to-D Converter Fault", 491554359Sroberto "The almanac stored in the receiver is not complete and current", 491654359Sroberto "<BIT 4>", 491754359Sroberto "<BIT 5", 491854359Sroberto "<BIT 6>", 491954359Sroberto "<BIT 7>" 492054359Sroberto }; 492154359Sroberto 492254359Sroberto int i, bits; 492354359Sroberto 492454359Sroberto sprintf(t, "machine id 0x%02x", mb(0) & 0xFF); 492554359Sroberto t += strlen(t); 492654359Sroberto 492754359Sroberto bits = mb(1) & 0xFF; 492854359Sroberto 492954359Sroberto for (i = 0; i < 8; i++) 493054359Sroberto if (bits & (0x1<<i)) 493154359Sroberto { 493254359Sroberto sprintf(t, ", %s", msgs[i]); 493354359Sroberto t += strlen(t); 493454359Sroberto } 493554359Sroberto 493654359Sroberto sprintf(t, ", Superpackets %ssupported", (mb(2) & 0xFF) ? "" :"un" ); 493754359Sroberto } 493854359Sroberto break; 493954359Sroberto 494054359Sroberto case CMD_ROPERPARAM: 494154359Sroberto sprintf(t, "%2x %.1f %.1f %.1f %.1f", 494254359Sroberto mb(0), getflt((unsigned char *)&mb(1)), getflt((unsigned char *)&mb(5)), 494354359Sroberto getflt((unsigned char *)&mb(9)), getflt((unsigned char *)&mb(13))); 494454359Sroberto break; 494554359Sroberto 494654359Sroberto case CMD_RUTCPARAM: 494754359Sroberto { 494854359Sroberto float t0t = getflt((unsigned char *)&mb(14)); 494954359Sroberto short wnt = getshort((unsigned char *)&mb(18)); 495054359Sroberto short dtls = getshort((unsigned char *)&mb(12)); 495154359Sroberto short wnlsf = getshort((unsigned char *)&mb(20)); 495254359Sroberto short dn = getshort((unsigned char *)&mb(22)); 495354359Sroberto short dtlsf = getshort((unsigned char *)&mb(24)); 495454359Sroberto 495554359Sroberto if ((int)t0t != 0) 495654359Sroberto { 495754359Sroberto mk_utcinfo(t, wnt, wnlsf, dn, dtls, dtlsf); 495854359Sroberto } 495954359Sroberto else 496054359Sroberto { 496154359Sroberto strcpy(t, "<NO UTC DATA>"); 496254359Sroberto } 496354359Sroberto } 496454359Sroberto break; 496554359Sroberto 496654359Sroberto case CMD_RSAT1BIAS: 496754359Sroberto sprintf(t, "%.1fm %.2fm/s at %.1fs", 496854359Sroberto getflt(&mb(0)), getflt(&mb(4)), getflt(&mb(8))); 496954359Sroberto break; 497054359Sroberto 497154359Sroberto case CMD_RIOOPTIONS: 497254359Sroberto { 497354359Sroberto sprintf(t, "%02x %02x %02x %02x", 497454359Sroberto mb(0), mb(1), mb(2), mb(3)); 497554359Sroberto if (mb(0) != TRIM_POS_OPT || 497654359Sroberto mb(2) != TRIM_TIME_OPT) 497754359Sroberto { 497854359Sroberto (void)trimbletsip_setup(parse, "bad io options"); 497954359Sroberto } 498054359Sroberto } 498154359Sroberto break; 498254359Sroberto 498354359Sroberto case CMD_RSPOSXYZ: 498454359Sroberto { 498554359Sroberto double x = getflt((unsigned char *)&mb(0)); 498654359Sroberto double y = getflt((unsigned char *)&mb(4)); 498754359Sroberto double z = getflt((unsigned char *)&mb(8)); 498854359Sroberto double f = getflt((unsigned char *)&mb(12)); 498954359Sroberto 499054359Sroberto if (f > 0.0) 499154359Sroberto sprintf(t, "x= %.1fm, y= %.1fm, z= %.1fm, time_of_fix= %f sec", 499254359Sroberto x, y, z, 499354359Sroberto f); 499454359Sroberto else 499554359Sroberto return; 499654359Sroberto } 499754359Sroberto break; 499854359Sroberto 499954359Sroberto case CMD_RSLLAPOS: 500054359Sroberto { 500154359Sroberto double lat = getflt((unsigned char *)&mb(0)); 500254359Sroberto double lng = getflt((unsigned char *)&mb(4)); 500354359Sroberto double f = getflt((unsigned char *)&mb(12)); 500454359Sroberto 500554359Sroberto if (f > 0.0) 500654359Sroberto sprintf(t, "lat %f %c, long %f %c, alt %.2fm", 500754359Sroberto ((lat < 0.0) ? (-lat) : (lat))*RTOD, (lat < 0.0 ? 'S' : 'N'), 500854359Sroberto ((lng < 0.0) ? (-lng) : (lng))*RTOD, (lng < 0.0 ? 'W' : 'E'), 500954359Sroberto getflt((unsigned char *)&mb(8))); 501054359Sroberto else 501154359Sroberto return; 501254359Sroberto } 501354359Sroberto break; 501454359Sroberto 501554359Sroberto case CMD_RDOUBLEXYZ: 501654359Sroberto { 501754359Sroberto double x = getdbl((unsigned char *)&mb(0)); 501854359Sroberto double y = getdbl((unsigned char *)&mb(8)); 501954359Sroberto double z = getdbl((unsigned char *)&mb(16)); 502054359Sroberto sprintf(t, "x= %.1fm, y= %.1fm, z= %.1fm", 502154359Sroberto x, y, z); 502254359Sroberto } 502354359Sroberto break; 502454359Sroberto 502554359Sroberto case CMD_RDOUBLELLA: 502654359Sroberto { 502754359Sroberto double lat = getdbl((unsigned char *)&mb(0)); 502854359Sroberto double lng = getdbl((unsigned char *)&mb(8)); 502954359Sroberto sprintf(t, "lat %f %c, lon %f %c, alt %.2fm", 503054359Sroberto ((lat < 0.0) ? (-lat) : (lat))*RTOD, (lat < 0.0 ? 'S' : 'N'), 503154359Sroberto ((lng < 0.0) ? (-lng) : (lng))*RTOD, (lng < 0.0 ? 'W' : 'E'), 503254359Sroberto getdbl((unsigned char *)&mb(16))); 503354359Sroberto } 503454359Sroberto break; 503554359Sroberto 503654359Sroberto case CMD_RALLINVIEW: 503754359Sroberto { 503854359Sroberto int i, sats; 503954359Sroberto 504054359Sroberto strcpy(t, "mode: "); 504154359Sroberto t += strlen(t); 504254359Sroberto switch (mb(0) & 0x7) 504354359Sroberto { 504454359Sroberto default: 504554359Sroberto sprintf(t, "0x%x", mb(0) & 0x7); 504654359Sroberto break; 504754359Sroberto 504854359Sroberto case 3: 504954359Sroberto strcat(t, "2D"); 505054359Sroberto break; 505154359Sroberto 505254359Sroberto case 4: 505354359Sroberto strcat(t, "3D"); 505454359Sroberto break; 505554359Sroberto } 505654359Sroberto t += strlen(t); 505754359Sroberto if (mb(0) & 0x8) 505854359Sroberto strcpy(t, "-MANUAL, "); 505954359Sroberto else 506054359Sroberto strcpy(t, "-AUTO, "); 506154359Sroberto t += strlen(t); 506254359Sroberto 506354359Sroberto sats = (mb(0)>>4) & 0xF; 506454359Sroberto 506554359Sroberto sprintf(t, "PDOP %.2f, HDOP %.2f, VDOP %.2f, TDOP %.2f, %d satellite%s in view: ", 506654359Sroberto getflt((unsigned char *)&mb(1)), 506754359Sroberto getflt((unsigned char *)&mb(5)), 506854359Sroberto getflt((unsigned char *)&mb(9)), 506954359Sroberto getflt((unsigned char *)&mb(13)), 507054359Sroberto sats, (sats == 1) ? "" : "s"); 507154359Sroberto t += strlen(t); 507254359Sroberto 507354359Sroberto for (i=0; i < sats; i++) 507454359Sroberto { 507554359Sroberto sprintf(t, "%s%02d", i ? ", " : "", mb(17+i)); 507654359Sroberto t += strlen(t); 507754359Sroberto if (tr) 507854359Sroberto tr->ctrack |= (1 << (mb(17+i)-1)); 507954359Sroberto } 508054359Sroberto 508154359Sroberto if (tr) 508254359Sroberto { /* mark for tracking status query */ 508354359Sroberto tr->qtracking = 1; 508454359Sroberto } 508554359Sroberto } 508654359Sroberto break; 508754359Sroberto 508854359Sroberto case CMD_RSTATTRACK: 508954359Sroberto { 509054359Sroberto sprintf(t-2, "[%02d]=\"", mb(0)); /* add index to var name */ 509154359Sroberto t += strlen(t); 509254359Sroberto 509354359Sroberto if (getflt((unsigned char *)&mb(4)) < 0.0) 509454359Sroberto { 509554359Sroberto strcpy(t, "<NO MEASUREMENTS>"); 509654359Sroberto var_flag &= ~DEF; 509754359Sroberto } 509854359Sroberto else 509954359Sroberto { 510054359Sroberto sprintf(t, "ch=%d, acq=%s, eph=%d, signal_level= %5.2f, elevation= %5.2f, azimuth= %6.2f", 510154359Sroberto (mb(1) & 0xFF)>>3, 510254359Sroberto mb(2) ? ((mb(2) == 1) ? "ACQ" : "SRCH") : "NEVER", 510354359Sroberto mb(3), 510454359Sroberto getflt((unsigned char *)&mb(4)), 510554359Sroberto getflt((unsigned char *)&mb(12)) * RTOD, 510654359Sroberto getflt((unsigned char *)&mb(16)) * RTOD); 510754359Sroberto t += strlen(t); 510854359Sroberto if (mb(20)) 510954359Sroberto { 511054359Sroberto var_flag &= ~DEF; 511154359Sroberto strcpy(t, ", OLD"); 511254359Sroberto } 511354359Sroberto t += strlen(t); 511454359Sroberto if (mb(22)) 511554359Sroberto { 511654359Sroberto if (mb(22) == 1) 511754359Sroberto strcpy(t, ", BAD PARITY"); 511854359Sroberto else 511954359Sroberto if (mb(22) == 2) 512054359Sroberto strcpy(t, ", BAD EPH HEALTH"); 512154359Sroberto } 512254359Sroberto t += strlen(t); 512354359Sroberto if (mb(23)) 512454359Sroberto strcpy(t, ", collecting data"); 512554359Sroberto } 512654359Sroberto } 512754359Sroberto break; 512854359Sroberto 512954359Sroberto default: 513054359Sroberto strcpy(t, "<UNDECODED>"); 513154359Sroberto break; 513254359Sroberto } 513354359Sroberto strcat(t,"\""); 513454359Sroberto set_var(&parse->kv, pbuffer, sizeof(pbuffer), var_flag); 513554359Sroberto } 513654359Sroberto} 513754359Sroberto 513854359Sroberto 513954359Sroberto/**============================================================ 514054359Sroberto ** RAWDCF support 514154359Sroberto **/ 514254359Sroberto 514354359Sroberto/*-------------------------------------------------- 514456746Sroberto * rawdcf_init_1 - set up modem lines for RAWDCF receivers 514556746Sroberto * SET DTR line 514654359Sroberto */ 514754359Sroberto#if defined(TIOCMSET) && (defined(TIOCM_DTR) || defined(CIOCM_DTR)) 514854359Srobertostatic int 514956746Srobertorawdcf_init_1( 515054359Sroberto struct parseunit *parse 515154359Sroberto ) 515254359Sroberto{ 515354359Sroberto /* 515454359Sroberto * You can use the RS232 to supply the power for a DCF77 receiver. 515554359Sroberto * Here a voltage between the DTR and the RTS line is used. Unfortunately 515654359Sroberto * the name has changed from CIOCM_DTR to TIOCM_DTR recently. 515754359Sroberto */ 515854359Sroberto 515954359Sroberto#ifdef TIOCM_DTR 516054359Sroberto int sl232 = TIOCM_DTR; /* turn on DTR for power supply */ 516154359Sroberto#else 516254359Sroberto int sl232 = CIOCM_DTR; /* turn on DTR for power supply */ 516354359Sroberto#endif 516454359Sroberto 516554359Sroberto if (ioctl(parse->generic->io.fd, TIOCMSET, (caddr_t)&sl232) == -1) 516654359Sroberto { 516756746Sroberto msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_1: WARNING: ioctl(fd, TIOCMSET, [C|T]IOCM_DTR): %m", CLK_UNIT(parse->peer)); 516854359Sroberto } 516954359Sroberto return 0; 517054359Sroberto} 517154359Sroberto#else 517254359Srobertostatic int 517354359Srobertorawdcfdtr_init( 517454359Sroberto struct parseunit *parse 517554359Sroberto ) 517654359Sroberto{ 517756746Sroberto msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_1: WARNING: OS interface incapable of setting DTR to power DCF modules", CLK_UNIT(parse->peer)); 517854359Sroberto return 0; 517954359Sroberto} 518054359Sroberto#endif /* DTR initialisation type */ 518154359Sroberto 518254359Sroberto/*-------------------------------------------------- 518356746Sroberto * rawdcf_init_2 - set up modem lines for RAWDCF receivers 518456746Sroberto * CLR DTR line, SET RTS line 518554359Sroberto */ 518656746Sroberto#if defined(TIOCMSET) && (defined(TIOCM_RTS) || defined(CIOCM_RTS)) 518754359Srobertostatic int 518856746Srobertorawdcf_init_2( 518954359Sroberto struct parseunit *parse 519054359Sroberto ) 519154359Sroberto{ 519254359Sroberto /* 519354359Sroberto * You can use the RS232 to supply the power for a DCF77 receiver. 519456746Sroberto * Here a voltage between the DTR and the RTS line is used. Unfortunately 519556746Sroberto * the name has changed from CIOCM_DTR to TIOCM_DTR recently. 519654359Sroberto */ 519754359Sroberto 519854359Sroberto#ifdef TIOCM_RTS 519956746Sroberto int sl232 = TIOCM_RTS; /* turn on RTS, clear DTR for power supply */ 520054359Sroberto#else 520156746Sroberto int sl232 = CIOCM_RTS; /* turn on DTR for power supply */ 520254359Sroberto#endif 520354359Sroberto 520454359Sroberto if (ioctl(parse->generic->io.fd, TIOCMSET, (caddr_t)&sl232) == -1) 520554359Sroberto { 520656746Sroberto msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_2: WARNING: ioctl(fd, TIOCMSET, [C|T]IOCM_RTS): %m", CLK_UNIT(parse->peer)); 520754359Sroberto } 520854359Sroberto return 0; 520954359Sroberto} 521054359Sroberto#else 521154359Srobertostatic int 521256746Srobertorawdcf_init_2( 521354359Sroberto struct parseunit *parse 521454359Sroberto ) 521554359Sroberto{ 521656746Sroberto msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_2: WARNING: OS interface incapable of setting RTS to power DCF modules", CLK_UNIT(parse->peer)); 521754359Sroberto return 0; 521854359Sroberto} 521956746Sroberto#endif /* DTR initialisation type */ 522054359Sroberto 522154359Sroberto#else /* defined(REFCLOCK) && defined(PARSE) */ 522254359Srobertoint refclock_parse_bs; 522354359Sroberto#endif /* defined(REFCLOCK) && defined(PARSE) */ 522454359Sroberto 522554359Sroberto/* 522654359Sroberto * History: 522754359Sroberto * 522854359Sroberto * refclock_parse.c,v 522956746Sroberto * Revision 4.36 1999/11/28 17:18:20 kardel 523056746Sroberto * disabled burst mode 523156746Sroberto * 523256746Sroberto * Revision 4.35 1999/11/28 09:14:14 kardel 523356746Sroberto * RECON_4_0_98F 523456746Sroberto * 523556746Sroberto * Revision 4.34 1999/05/14 06:08:05 kardel 523656746Sroberto * store current_time in a suitable container (u_long) 523756746Sroberto * 523856746Sroberto * Revision 4.33 1999/05/13 21:48:38 kardel 523956746Sroberto * double the no response timeout interval 524056746Sroberto * 524156746Sroberto * Revision 4.32 1999/05/13 20:09:13 kardel 524256746Sroberto * complain only about missing polls after a full poll interval 524356746Sroberto * 524456746Sroberto * Revision 4.31 1999/05/13 19:59:32 kardel 524556746Sroberto * add clock type 16 for RTS set DTR clr in RAWDCF 524656746Sroberto * 524756746Sroberto * Revision 4.30 1999/02/28 20:36:43 kardel 524856746Sroberto * fixed printf fmt 524956746Sroberto * 525054359Sroberto * Revision 4.29 1999/02/28 19:58:23 kardel 525154359Sroberto * updated copyright information 525254359Sroberto * 525354359Sroberto * Revision 4.28 1999/02/28 19:01:50 kardel 525454359Sroberto * improved debug out on sent Meinberg messages 525554359Sroberto * 525654359Sroberto * Revision 4.27 1999/02/28 18:05:55 kardel 525754359Sroberto * no linux/ppsclock.h stuff 525854359Sroberto * 525954359Sroberto * Revision 4.26 1999/02/28 15:27:27 kardel 526054359Sroberto * wharton clock integration 526154359Sroberto * 526254359Sroberto * Revision 4.25 1999/02/28 14:04:46 kardel 526354359Sroberto * added missing double quotes to UTC information string 526454359Sroberto * 526554359Sroberto * Revision 4.24 1999/02/28 12:06:50 kardel 526654359Sroberto * (parse_control): using gmprettydate instead of prettydate() 526754359Sroberto * (mk_utcinfo): new function for formatting GPS derived UTC information 526854359Sroberto * (gps16x_message): changed to use mk_utcinfo() 526954359Sroberto * (trimbletsip_message): changed to use mk_utcinfo() 527054359Sroberto * ignoring position information in unsynchronized mode 527154359Sroberto * (parse_start): augument linux support for optional ASYNC_LOW_LATENCY 527254359Sroberto * 527354359Sroberto * Revision 4.23 1999/02/23 19:47:53 kardel 527454359Sroberto * fixed #endifs 527554359Sroberto * (stream_receive): fixed formats 527654359Sroberto * 527754359Sroberto * Revision 4.22 1999/02/22 06:21:02 kardel 527854359Sroberto * use new autoconfig symbols 527954359Sroberto * 528054359Sroberto * Revision 4.21 1999/02/21 12:18:13 kardel 528154359Sroberto * 4.91f reconcilation 528254359Sroberto * 528354359Sroberto * Revision 4.20 1999/02/21 10:53:36 kardel 528454359Sroberto * initial Linux PPSkit version 528554359Sroberto * 528654359Sroberto * Revision 4.19 1999/02/07 09:10:45 kardel 528754359Sroberto * clarify STREAMS mitigation rules in comment 528854359Sroberto * 528954359Sroberto * Revision 4.18 1998/12/20 23:45:34 kardel 529054359Sroberto * fix types and warnings 529154359Sroberto * 529254359Sroberto * Revision 4.17 1998/11/15 21:24:51 kardel 529354359Sroberto * cannot access mbg_ routines when CLOCK_MEINBERG 529454359Sroberto * is not defined 529554359Sroberto * 529654359Sroberto * Revision 4.16 1998/11/15 20:28:17 kardel 529754359Sroberto * Release 4.0.73e13 reconcilation 529854359Sroberto * 529954359Sroberto * Revision 4.15 1998/08/22 21:56:08 kardel 530054359Sroberto * fixed IO handling for non-STREAM IO 530154359Sroberto * 530254359Sroberto * Revision 4.14 1998/08/16 19:00:48 kardel 530354359Sroberto * (gps16x_message): reduced UTC parameter information (dropped A0,A1) 530454359Sroberto * made uval a local variable (killed one of the last globals) 530554359Sroberto * (sendetx): added logging of messages when in debug mode 530654359Sroberto * (trimble_check): added periodic checks to facilitate re-initialization 530754359Sroberto * (trimbletsip_init): made use of EOL character if in non-kernel operation 530854359Sroberto * (trimbletsip_message): extended message interpretation 530954359Sroberto * (getdbl): fixed data conversion 531054359Sroberto * 531154359Sroberto * Revision 4.13 1998/08/09 22:29:13 kardel 531254359Sroberto * Trimble TSIP support 531354359Sroberto * 531454359Sroberto * Revision 4.12 1998/07/11 10:05:34 kardel 531554359Sroberto * Release 4.0.73d reconcilation 531654359Sroberto * 531754359Sroberto * Revision 4.11 1998/06/14 21:09:42 kardel 531854359Sroberto * Sun acc cleanup 531954359Sroberto * 532054359Sroberto * Revision 4.10 1998/06/13 12:36:45 kardel 532154359Sroberto * signed/unsigned, name clashes 532254359Sroberto * 532354359Sroberto * Revision 4.9 1998/06/12 15:30:00 kardel 532454359Sroberto * prototype fixes 532554359Sroberto * 532654359Sroberto * Revision 4.8 1998/06/12 11:19:42 kardel 532754359Sroberto * added direct input processing routine for refclocks in 532854359Sroberto * order to avaiod that single character io gobbles up all 532954359Sroberto * receive buffers and drops input data. (Problem started 533054359Sroberto * with fast machines so a character a buffer was possible 533154359Sroberto * one of the few cases where faster machines break existing 533254359Sroberto * allocation algorithms) 533354359Sroberto * 533454359Sroberto * Revision 4.7 1998/06/06 18:35:20 kardel 533554359Sroberto * (parse_start): added BURST mode initialisation 533654359Sroberto * 533754359Sroberto * Revision 4.6 1998/05/27 06:12:46 kardel 533854359Sroberto * RAWDCF_BASEDELAY default added 533954359Sroberto * old comment removed 534054359Sroberto * casts for ioctl() 534154359Sroberto * 534254359Sroberto * Revision 4.5 1998/05/25 22:05:09 kardel 534354359Sroberto * RAWDCF_SETDTR option removed 534454359Sroberto * clock type 14 attempts to set DTR for 534554359Sroberto * power supply of RAWDCF receivers 534654359Sroberto * 534754359Sroberto * Revision 4.4 1998/05/24 16:20:47 kardel 534854359Sroberto * updated comments referencing Meinberg clocks 534954359Sroberto * added RAWDCF clock with DTR set option as type 14 535054359Sroberto * 535154359Sroberto * Revision 4.3 1998/05/24 10:48:33 kardel 535254359Sroberto * calibrated CONRAD RAWDCF default fudge factor 535354359Sroberto * 535454359Sroberto * Revision 4.2 1998/05/24 09:59:35 kardel 535554359Sroberto * corrected version information (ntpq support) 535654359Sroberto * 535754359Sroberto * Revision 4.1 1998/05/24 09:52:31 kardel 535854359Sroberto * use fixed format only (new IO model) 535954359Sroberto * output debug to stdout instead of msyslog() 536054359Sroberto * don't include >"< in ASCII output in order not to confuse 536154359Sroberto * ntpq parsing 536254359Sroberto * 536354359Sroberto * Revision 4.0 1998/04/10 19:52:11 kardel 536454359Sroberto * Start 4.0 release version numbering 536554359Sroberto * 536654359Sroberto * Revision 1.2 1998/04/10 19:28:04 kardel 536754359Sroberto * initial NTP VERSION 4 integration of PARSE with GPS166 binary support 536854359Sroberto * derived from 3.105.1.2 from V3 tree 536954359Sroberto * 537054359Sroberto * Revision information 3.1 - 3.105 from log deleted 1998/04/10 kardel 537154359Sroberto * 537254359Sroberto */ 5373