#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#if defined(REFCLOCK) && defined(CLOCK_PARSE)
#include "ntpd.h"
#include "ntp_refclock.h"
#include "ntp_unixtime.h"
#include "ntp_control.h"
#include "ntp_string.h"
#include <stdio.h>
#include <ctype.h>
#ifndef TM_IN_SYS_TIME
# include <time.h>
#endif
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#if !defined(STREAM) && !defined(HAVE_SYSV_TTYS) && !defined(HAVE_BSD_TTYS) && !defined(HAVE_TERMIOS)
# include "Bletch: Define one of {STREAM,HAVE_SYSV_TTYS,HAVE_TERMIOS}"
#endif
#ifdef STREAM
# include <sys/stream.h>
# include <sys/stropts.h>
#endif
#ifdef HAVE_TERMIOS
# define TTY_GETATTR(_FD_, _ARG_) tcgetattr((_FD_), (_ARG_))
# define TTY_SETATTR(_FD_, _ARG_) tcsetattr((_FD_), TCSANOW, (_ARG_))
# undef HAVE_SYSV_TTYS
#endif
#ifdef HAVE_SYSV_TTYS
# define TTY_GETATTR(_FD_, _ARG_) ioctl((_FD_), TCGETA, (_ARG_))
# define TTY_SETATTR(_FD_, _ARG_) ioctl((_FD_), TCSETAW, (_ARG_))
#endif
#ifdef HAVE_BSD_TTYS
# include "Bletch: BSD TTY not currently supported"
#endif
#ifdef HAVE_SYS_IOCTL_H
# include <sys/ioctl.h>
#endif
#ifdef HAVE_PPSAPI
# include "ppsapi_timepps.h"
# include "refclock_atom.h"
#endif
#ifdef PPS
# ifdef HAVE_SYS_PPSCLOCK_H
# include <sys/ppsclock.h>
# endif
# ifdef HAVE_TIO_SERIAL_STUFF
# include <linux/serial.h>
# endif
#endif
#define BUFFER_SIZE(_BUF, _PTR) ((_BUF) + sizeof(_BUF) - (_PTR))
#define BUFFER_SIZES(_BUF, _PTR, _SZ) ((_BUF) + (_SZ) - (_PTR))
#undef PPS_METHOD
#ifdef HAVE_PPSAPI
#define PPS_METHOD "PPS API"
#else
#ifdef TIOCDCDTIMESTAMP
#define PPS_METHOD "TIOCDCDTIMESTAMP"
#else
#if defined(HAVE_STRUCT_PPSCLOCKEV) && (defined(HAVE_CIOGETEV) || defined(HAVE_TIOCGPPSEV))
#ifdef HAVE_CIOGETEV
#define PPS_METHOD "CIOGETEV"
#endif
#ifdef HAVE_TIOCGPPSEV
#define PPS_METHOD "TIOCGPPSEV"
#endif
#endif
#endif
#endif
#include "ntp_io.h"
#include "ntp_stdlib.h"
#include "parse.h"
#include "mbg_gps166.h"
#include "trimble.h"
#include "binio.h"
#include "ascii.h"
#include "ieee754io.h"
#include "recvbuff.h"
static char rcsid[] = "refclock_parse.c,v 4.81 2009/05/01 10:15:29 kardel RELEASE_20090105_A";
static int parse_start (int, struct peer *);
static void parse_shutdown (int, struct peer *);
static void parse_poll (int, struct peer *);
static void parse_control (int, struct refclockstat *, struct refclockstat *, struct peer *);
struct refclock refclock_parse = {
parse_start,
parse_shutdown,
parse_poll,
parse_control,
noentry,
noentry,
NOFLAGS
};
#define MAXUNITS 4
#define PARSEDEVICE "/dev/refclock-%d"
#define PARSEPPSDEVICE "/dev/refclockpps-%d"
#undef ABS
#define ABS(_X_) (((_X_) < 0) ? -(_X_) : (_X_))
#define PARSE_HARDPPS_DISABLE 0
#define PARSE_HARDPPS_ENABLE 1
struct parseunit;
typedef struct bind
{
const char *bd_description;
int (*bd_init) (struct parseunit *);
void (*bd_end) (struct parseunit *);
int (*bd_setcs) (struct parseunit *, parsectl_t *);
int (*bd_disable) (struct parseunit *);
int (*bd_enable) (struct parseunit *);
int (*bd_getfmt) (struct parseunit *, parsectl_t *);
int (*bd_setfmt) (struct parseunit *, parsectl_t *);
int (*bd_timecode) (struct parseunit *, parsectl_t *);
void (*bd_receive) (struct recvbuf *);
int (*bd_io_input) (struct recvbuf *);
} bind_t;
#define PARSE_END(_X_) (*(_X_)->binding->bd_end)(_X_)
#define PARSE_SETCS(_X_, _CS_) (*(_X_)->binding->bd_setcs)(_X_, _CS_)
#define PARSE_ENABLE(_X_) (*(_X_)->binding->bd_enable)(_X_)
#define PARSE_DISABLE(_X_) (*(_X_)->binding->bd_disable)(_X_)
#define PARSE_GETFMT(_X_, _DCT_) (*(_X_)->binding->bd_getfmt)(_X_, _DCT_)
#define PARSE_SETFMT(_X_, _DCT_) (*(_X_)->binding->bd_setfmt)(_X_, _DCT_)
#define PARSE_GETTIMECODE(_X_, _DCT_) (*(_X_)->binding->bd_timecode)(_X_, _DCT_)
#define PARSE_F_PPSPPS 0x0001
#define PARSE_F_PPSONSECOND 0x0002
#define ERR_ALL (unsigned)~0
#define ERR_BADDATA (unsigned)0
#define ERR_NODATA (unsigned)1
#define ERR_BADIO (unsigned)2
#define ERR_BADSTATUS (unsigned)3
#define ERR_BADEVENT (unsigned)4
#define ERR_INTERNAL (unsigned)5
#define ERR_CNT (unsigned)(ERR_INTERNAL+1)
#define ERR(_X_) if (list_err(parse, (_X_)))
struct errorregression
{
u_long err_count;
u_long err_delay;
};
static struct errorregression
err_baddata[] =
{
{ 1, 0 },
{ 5, 60 },
{ 3, 3600 },
{ 0, 12*3600 }
};
static struct errorregression
err_nodata[] =
{
{ 1, 0 },
{ 5, 60 },
{ 3, 3600 },
{ 0, 12*3600 }
};
static struct errorregression
err_badstatus[] =
{
{ 1, 0 },
{ 5, 60 },
{ 3, 3600 },
{ 0, 12*3600 }
};
static struct errorregression
err_badio[] =
{
{ 1, 0 },
{ 5, 60 },
{ 5, 3600 },
{ 0, 12*3600 }
};
static struct errorregression
err_badevent[] =
{
{ 20, 0 },
{ 6, 60 },
{ 5, 3600 },
{ 0, 12*3600 }
};
static struct errorregression
err_internal[] =
{
{ 0, 0 },
};
static struct errorregression *
err_tbl[] =
{
err_baddata,
err_nodata,
err_badio,
err_badstatus,
err_badevent,
err_internal
};
struct errorinfo
{
u_long err_started;
u_long err_last;
u_long err_cnt;
u_long err_suppressed;
struct errorregression *err_stage;
};
struct parseunit
{
struct peer *peer;
struct refclockproc *generic;
bind_t *binding;
parse_t parseio;
struct parse_clockinfo *parse_type;
u_char flags;
u_long lastchange;
u_long statetime[CEVNT_MAX+1];
u_long pollneeddata;
u_short lastformat;
u_long lastsync;
u_long maxunsync;
double ppsphaseadjust;
u_long lastmissed;
u_long ppsserial;
int ppsfd;
#ifdef HAVE_PPSAPI
int hardppsstate;
struct refclock_atom atom;
#endif
parsetime_t timedata;
void *localdata;
unsigned long localstate;
struct errorinfo errors[ERR_CNT];
struct ctl_var *kv;
u_long laststatistic;
};
static void poll_dpoll (struct parseunit *);
static void poll_poll (struct peer *);
static int poll_init (struct parseunit *);
typedef struct poll_info
{
u_long rate;
const char *string;
u_long count;
} poll_info_t;
#define NO_CL_FLAGS 0
#define NO_POLL 0
#define NO_INIT 0
#define NO_END 0
#define NO_EVENT 0
#define NO_LCLDATA 0
#define NO_MESSAGE 0
#define NO_PPSDELAY 0
#define DCF_ID "DCF"
#define DCF_A_ID "DCFa"
#define DCF_P_ID "DCFp"
#define GPS_ID "GPS"
#define NOCLOCK_ROOTDELAY 0.0
#define NOCLOCK_BASEDELAY 0.0
#define NOCLOCK_DESCRIPTION 0
#define NOCLOCK_MAXUNSYNC 0
#define NOCLOCK_CFLAG 0
#define NOCLOCK_IFLAG 0
#define NOCLOCK_OFLAG 0
#define NOCLOCK_LFLAG 0
#define NOCLOCK_ID "TILT"
#define NOCLOCK_POLL NO_POLL
#define NOCLOCK_INIT NO_INIT
#define NOCLOCK_END NO_END
#define NOCLOCK_DATA NO_LCLDATA
#define NOCLOCK_FORMAT ""
#define NOCLOCK_TYPE CTL_SST_TS_UNSPEC
#define NOCLOCK_SAMPLES 0
#define NOCLOCK_KEEP 0
#define DCF_TYPE CTL_SST_TS_LF
#define GPS_TYPE CTL_SST_TS_UHF
#define MBG_SPEED (B9600)
#define MBG_CFLAG (CS7|PARENB|CREAD|CLOCAL|HUPCL|CSTOPB)
#define MBG_IFLAG (IGNBRK|IGNPAR|ISTRIP)
#define MBG_OFLAG 0
#define MBG_LFLAG 0
#define MBG_FLAGS PARSE_F_PPSONSECOND
#define DCFUA31_ROOTDELAY 0.0
#define DCFUA31_BASEDELAY 0.010
#define DCFUA31_DESCRIPTION "Meinberg DCF77 C51 or compatible"
#define DCFUA31_MAXUNSYNC 60*30
#define DCFUA31_SPEED MBG_SPEED
#define DCFUA31_CFLAG MBG_CFLAG
#define DCFUA31_IFLAG MBG_IFLAG
#define DCFUA31_OFLAG MBG_OFLAG
#define DCFUA31_LFLAG MBG_LFLAG
#define DCFUA31_SAMPLES 5
#define DCFUA31_KEEP 3
#define DCFUA31_FORMAT "Meinberg Standard"
#define DCFPZF535_ROOTDELAY 0.0
#define DCFPZF535_BASEDELAY 0.001968
#define DCFPZF535_DESCRIPTION "Meinberg DCF PZF 535/509 / TCXO"
#define DCFPZF535_MAXUNSYNC 60*60*12
#define DCFPZF535_SPEED MBG_SPEED
#define DCFPZF535_CFLAG MBG_CFLAG
#define DCFPZF535_IFLAG MBG_IFLAG
#define DCFPZF535_OFLAG MBG_OFLAG
#define DCFPZF535_LFLAG MBG_LFLAG
#define DCFPZF535_SAMPLES 5
#define DCFPZF535_KEEP 3
#define DCFPZF535_FORMAT "Meinberg Standard"
#define DCFPZF535OCXO_ROOTDELAY 0.0
#define DCFPZF535OCXO_BASEDELAY 0.001968
#define DCFPZF535OCXO_DESCRIPTION "Meinberg DCF PZF 535/509 / OCXO"
#define DCFPZF535OCXO_MAXUNSYNC 60*60*96
#define DCFPZF535OCXO_SPEED MBG_SPEED
#define DCFPZF535OCXO_CFLAG MBG_CFLAG
#define DCFPZF535OCXO_IFLAG MBG_IFLAG
#define DCFPZF535OCXO_OFLAG MBG_OFLAG
#define DCFPZF535OCXO_LFLAG MBG_LFLAG
#define DCFPZF535OCXO_SAMPLES 5
#define DCFPZF535OCXO_KEEP 3
#define DCFPZF535OCXO_FORMAT "Meinberg Standard"
static void gps16x_message (struct parseunit *, parsetime_t *);
static int gps16x_poll_init (struct parseunit *);
#define GPS16X_ROOTDELAY 0.0
#define GPS16X_BASEDELAY 0.001968
#define GPS16X_DESCRIPTION "Meinberg GPS16x receiver"
#define GPS16X_MAXUNSYNC 60*60*96
#define GPS16X_SPEED B19200
#define GPS16X_CFLAG (CS8|CREAD|CLOCAL|HUPCL)
#define GPS16X_IFLAG (IGNBRK|IGNPAR)
#define GPS16X_OFLAG MBG_OFLAG
#define GPS16X_LFLAG MBG_LFLAG
#define GPS16X_POLLRATE 6
#define GPS16X_POLLCMD ""
#define GPS16X_CMDSIZE 0
static poll_info_t gps16x_pollinfo = { GPS16X_POLLRATE, GPS16X_POLLCMD, GPS16X_CMDSIZE };
#define GPS16X_INIT gps16x_poll_init
#define GPS16X_POLL 0
#define GPS16X_END 0
#define GPS16X_DATA ((void *)(&gps16x_pollinfo))
#define GPS16X_MESSAGE gps16x_message
#define GPS16X_ID GPS_ID
#define GPS16X_FORMAT "Meinberg GPS Extended"
#define GPS16X_SAMPLES 5
#define GPS16X_KEEP 3
#define DCF7000_ROOTDELAY 0.0
#define DCF7000_BASEDELAY 0.405
#define DCF7000_DESCRIPTION "ELV DCF7000"
#define DCF7000_MAXUNSYNC (60*5)
#define DCF7000_SPEED (B9600)
#define DCF7000_CFLAG (CS8|CREAD|PARENB|PARODD|CLOCAL|HUPCL)
#define DCF7000_IFLAG (IGNBRK)
#define DCF7000_OFLAG 0
#define DCF7000_LFLAG 0
#define DCF7000_SAMPLES 5
#define DCF7000_KEEP 3
#define DCF7000_FORMAT "ELV DCF7000"
#define WS_POLLRATE 1
#define WS_POLLCMD "\163"
#define WS_CMDSIZE 1
static poll_info_t wsdcf_pollinfo = { WS_POLLRATE, WS_POLLCMD, WS_CMDSIZE };
#define WSDCF_INIT poll_init
#define WSDCF_POLL poll_dpoll
#define WSDCF_END 0
#define WSDCF_DATA ((void *)(&wsdcf_pollinfo))
#define WSDCF_ROOTDELAY 0.0
#define WSDCF_BASEDELAY 0.010
#define WSDCF_DESCRIPTION "WS/DCF Receiver"
#define WSDCF_FORMAT "Schmid"
#define WSDCF_MAXUNSYNC (60*60)
#define WSDCF_SPEED (B1200)
#define WSDCF_CFLAG (CS8|CREAD|CLOCAL)
#define WSDCF_IFLAG 0
#define WSDCF_OFLAG 0
#define WSDCF_LFLAG 0
#define WSDCF_SAMPLES 5
#define WSDCF_KEEP 3
#define RAWDCF_FLAGS 0
#define RAWDCF_ROOTDELAY 0.0
#define RAWDCF_BASEDELAY 0.258
#define RAWDCF_FORMAT "RAW DCF77 Timecode"
#define RAWDCF_MAXUNSYNC (0)
#define RAWDCF_SPEED (B50)
#ifdef NO_PARENB_IGNPAR
# define RAWDCF_CFLAG (CS8|CREAD|CLOCAL)
#else
# define RAWDCF_CFLAG (CS8|CREAD|CLOCAL|PARENB)
#endif
#ifdef RAWDCF_NO_IGNPAR
# define RAWDCF_IFLAG 0
#else
# define RAWDCF_IFLAG (IGNPAR)
#endif
#define RAWDCF_OFLAG 0
#define RAWDCF_LFLAG 0
#define RAWDCF_SAMPLES 20
#define RAWDCF_KEEP 12
#define RAWDCF_INIT 0
#define CONRAD_BASEDELAY 0.292
#define CONRAD_DESCRIPTION "RAW DCF77 CODE (Conrad DCF77 receiver module)"
#define GUDE_EMC_USB_V20_SPEED (B4800)
#define GUDE_EMC_USB_V20_BASEDELAY 0.425
#define GUDE_EMC_USB_V20_DESCRIPTION "RAW DCF77 CODE (Expert mouseCLOCK USB v2.0)"
#define TIMEBRICK_BASEDELAY 0.210
#define TIMEBRICK_DESCRIPTION "RAW DCF77 CODE (TimeBrick)"
#define IGELCLOCK_BASEDELAY 0.258
#define IGELCLOCK_DESCRIPTION "RAW DCF77 CODE (IGEL:clock)"
#define IGELCLOCK_SPEED (B1200)
#define IGELCLOCK_CFLAG (CS8|CREAD|HUPCL|CLOCAL)
static int rawdcf_init_1 (struct parseunit *);
#define RAWDCFDTRSET_DESCRIPTION "RAW DCF77 CODE (DTR SET/RTS CLR)"
#define RAWDCFDTRSET_INIT rawdcf_init_1
static int rawdcf_init_2 (struct parseunit *);
#define RAWDCFDTRCLRRTSSET_DESCRIPTION "RAW DCF77 CODE (DTR CLR/RTS SET)"
#define RAWDCFDTRCLRRTSSET_INIT rawdcf_init_2
#ifndef TRIM_POLLRATE
#define TRIM_POLLRATE 0
#endif
#define TRIM_TAIPPOLLCMD ">SRM;FR_FLAG=F;EC_FLAG=F<>QTM<"
#define TRIM_TAIPCMDSIZE (sizeof(TRIM_TAIPPOLLCMD)-1)
static poll_info_t trimbletaip_pollinfo = { TRIM_POLLRATE, TRIM_TAIPPOLLCMD, TRIM_TAIPCMDSIZE };
static int trimbletaip_init (struct parseunit *);
static void trimbletaip_event (struct parseunit *, int);
static char tsipquery[] = { DLE, 0x21, DLE, ETX, DLE, 0x2F, DLE, ETX };
static poll_info_t trimbletsip_pollinfo = { TRIM_POLLRATE, tsipquery, sizeof(tsipquery) };
static int trimbletsip_init (struct parseunit *);
static void trimbletsip_end (struct parseunit *);
static void trimbletsip_message (struct parseunit *, parsetime_t *);
static void trimbletsip_event (struct parseunit *, int);
#define TRIMBLETSIP_IDLE_TIME (300)
#define TRIMBLE_RESET_HOLDOFF TRIMBLETSIP_IDLE_TIME
#define TRIMBLETAIP_SPEED (B4800)
#define TRIMBLETAIP_CFLAG (CS8|CREAD|CLOCAL)
#define TRIMBLETAIP_IFLAG (BRKINT|IGNPAR|ISTRIP|ICRNL|IXON)
#define TRIMBLETAIP_OFLAG (OPOST|ONLCR)
#define TRIMBLETAIP_LFLAG (0)
#define TRIMBLETSIP_SPEED (B9600)
#define TRIMBLETSIP_CFLAG (CS8|CLOCAL|CREAD|PARENB|PARODD)
#define TRIMBLETSIP_IFLAG (IGNBRK)
#define TRIMBLETSIP_OFLAG (0)
#define TRIMBLETSIP_LFLAG (ICANON)
#define TRIMBLETSIP_SAMPLES 5
#define TRIMBLETSIP_KEEP 3
#define TRIMBLETAIP_SAMPLES 5
#define TRIMBLETAIP_KEEP 3
#define TRIMBLETAIP_FLAGS (PARSE_F_PPSONSECOND)
#define TRIMBLETSIP_FLAGS (TRIMBLETAIP_FLAGS)
#define TRIMBLETAIP_POLL poll_dpoll
#define TRIMBLETSIP_POLL poll_dpoll
#define TRIMBLETAIP_INIT trimbletaip_init
#define TRIMBLETSIP_INIT trimbletsip_init
#define TRIMBLETAIP_EVENT trimbletaip_event
#define TRIMBLETSIP_EVENT trimbletsip_event
#define TRIMBLETSIP_MESSAGE trimbletsip_message
#define TRIMBLETAIP_END 0
#define TRIMBLETSIP_END trimbletsip_end
#define TRIMBLETAIP_DATA ((void *)(&trimbletaip_pollinfo))
#define TRIMBLETSIP_DATA ((void *)(&trimbletsip_pollinfo))
#define TRIMBLETAIP_ID GPS_ID
#define TRIMBLETSIP_ID GPS_ID
#define TRIMBLETAIP_FORMAT "Trimble TAIP"
#define TRIMBLETSIP_FORMAT "Trimble TSIP"
#define TRIMBLETAIP_ROOTDELAY 0x0
#define TRIMBLETSIP_ROOTDELAY 0x0
#define TRIMBLETAIP_BASEDELAY 0.0
#define TRIMBLETSIP_BASEDELAY 0.020
#define TRIMBLETAIP_DESCRIPTION "Trimble GPS (TAIP) receiver"
#define TRIMBLETSIP_DESCRIPTION "Trimble GPS (TSIP) receiver"
#define TRIMBLETAIP_MAXUNSYNC 0
#define TRIMBLETSIP_MAXUNSYNC 0
#define TRIMBLETAIP_EOL '<'
#define RCC_POLLRATE 0
#define RCC_POLLCMD "\r"
#define RCC_CMDSIZE 1
static poll_info_t rcc8000_pollinfo = { RCC_POLLRATE, RCC_POLLCMD, RCC_CMDSIZE };
#define RCC8000_FLAGS 0
#define RCC8000_POLL poll_dpoll
#define RCC8000_INIT poll_init
#define RCC8000_END 0
#define RCC8000_DATA ((void *)(&rcc8000_pollinfo))
#define RCC8000_ROOTDELAY 0.0
#define RCC8000_BASEDELAY 0.0
#define RCC8000_ID "MSF"
#define RCC8000_DESCRIPTION "RCC 8000 MSF Receiver"
#define RCC8000_FORMAT "Radiocode RCC8000"
#define RCC8000_MAXUNSYNC (60*60)
#define RCC8000_SPEED (B2400)
#define RCC8000_CFLAG (CS8|CREAD|CLOCAL)
#define RCC8000_IFLAG (IGNBRK|IGNPAR)
#define RCC8000_OFLAG 0
#define RCC8000_LFLAG 0
#define RCC8000_SAMPLES 5
#define RCC8000_KEEP 3
#define HOPF6021_ROOTDELAY 0.0
#define HOPF6021_BASEDELAY 0.0
#define HOPF6021_DESCRIPTION "HOPF 6021"
#define HOPF6021_FORMAT "hopf Funkuhr 6021"
#define HOPF6021_MAXUNSYNC (60*60)
#define HOPF6021_SPEED (B9600)
#define HOPF6021_CFLAG (CS8|CREAD|CLOCAL)
#define HOPF6021_IFLAG (IGNBRK|ISTRIP)
#define HOPF6021_OFLAG 0
#define HOPF6021_LFLAG 0
#define HOPF6021_FLAGS 0
#define HOPF6021_SAMPLES 5
#define HOPF6021_KEEP 3
#define COMPUTIME_FLAGS 0
#define COMPUTIME_ROOTDELAY 0.0
#define COMPUTIME_BASEDELAY 0.0
#define COMPUTIME_ID DCF_ID
#define COMPUTIME_DESCRIPTION "Diem's Computime receiver"
#define COMPUTIME_FORMAT "Diem's Computime Radio Clock"
#define COMPUTIME_TYPE DCF_TYPE
#define COMPUTIME_MAXUNSYNC (60*60)
#define COMPUTIME_SPEED (B9600)
#define COMPUTIME_CFLAG (CSTOPB|CS7|CREAD|CLOCAL)
#define COMPUTIME_IFLAG (IGNBRK|IGNPAR|ISTRIP)
#define COMPUTIME_OFLAG 0
#define COMPUTIME_LFLAG 0
#define COMPUTIME_SAMPLES 5
#define COMPUTIME_KEEP 3
#define VARITEXT_FLAGS 0
#define VARITEXT_ROOTDELAY 0.0
#define VARITEXT_BASEDELAY 0.0
#define VARITEXT_ID "MSF"
#define VARITEXT_DESCRIPTION "Varitext receiver"
#define VARITEXT_FORMAT "Varitext Radio Clock"
#define VARITEXT_TYPE DCF_TYPE
#define VARITEXT_MAXUNSYNC (60*60)
#define VARITEXT_SPEED (B9600)
#define VARITEXT_CFLAG (CS7|CREAD|CLOCAL|PARENB|PARODD)
#define VARITEXT_IFLAG (IGNPAR|IGNBRK|INPCK)
#define VARITEXT_OFLAG 0
#define VARITEXT_LFLAG 0
#define VARITEXT_SAMPLES 32
#define VARITEXT_KEEP 20
static struct parse_clockinfo
{
u_long cl_flags;
void (*cl_poll) (struct parseunit *);
int (*cl_init) (struct parseunit *);
void (*cl_event) (struct parseunit *, int);
void (*cl_end) (struct parseunit *);
void (*cl_message) (struct parseunit *, parsetime_t *);
void *cl_data;
double cl_rootdelay;
double cl_basedelay;
const char *cl_id;
const char *cl_description;
const char *cl_format;
u_char cl_type;
u_long cl_maxunsync;
u_long cl_speed;
u_long cl_cflag;
u_long cl_iflag;
u_long cl_oflag;
u_long cl_lflag;
u_long cl_samples;
u_long cl_keep;
} parse_clockinfo[] =
{
{
MBG_FLAGS,
NO_POLL,
NO_INIT,
NO_EVENT,
NO_END,
NO_MESSAGE,
NO_LCLDATA,
DCFPZF535_ROOTDELAY,
DCFPZF535_BASEDELAY,
DCF_P_ID,
DCFPZF535_DESCRIPTION,
DCFPZF535_FORMAT,
DCF_TYPE,
DCFPZF535_MAXUNSYNC,
DCFPZF535_SPEED,
DCFPZF535_CFLAG,
DCFPZF535_IFLAG,
DCFPZF535_OFLAG,
DCFPZF535_LFLAG,
DCFPZF535_SAMPLES,
DCFPZF535_KEEP
},
{
MBG_FLAGS,
NO_POLL,
NO_INIT,
NO_EVENT,
NO_END,
NO_MESSAGE,
NO_LCLDATA,
DCFPZF535OCXO_ROOTDELAY,
DCFPZF535OCXO_BASEDELAY,
DCF_P_ID,
DCFPZF535OCXO_DESCRIPTION,
DCFPZF535OCXO_FORMAT,
DCF_TYPE,
DCFPZF535OCXO_MAXUNSYNC,
DCFPZF535OCXO_SPEED,
DCFPZF535OCXO_CFLAG,
DCFPZF535OCXO_IFLAG,
DCFPZF535OCXO_OFLAG,
DCFPZF535OCXO_LFLAG,
DCFPZF535OCXO_SAMPLES,
DCFPZF535OCXO_KEEP
},
{
MBG_FLAGS,
NO_POLL,
NO_INIT,
NO_EVENT,
NO_END,
NO_MESSAGE,
NO_LCLDATA,
DCFUA31_ROOTDELAY,
DCFUA31_BASEDELAY,
DCF_A_ID,
DCFUA31_DESCRIPTION,
DCFUA31_FORMAT,
DCF_TYPE,
DCFUA31_MAXUNSYNC,
DCFUA31_SPEED,
DCFUA31_CFLAG,
DCFUA31_IFLAG,
DCFUA31_OFLAG,
DCFUA31_LFLAG,
DCFUA31_SAMPLES,
DCFUA31_KEEP
},
{
MBG_FLAGS,
NO_POLL,
NO_INIT,
NO_EVENT,
NO_END,
NO_MESSAGE,
NO_LCLDATA,
DCF7000_ROOTDELAY,
DCF7000_BASEDELAY,
DCF_A_ID,
DCF7000_DESCRIPTION,
DCF7000_FORMAT,
DCF_TYPE,
DCF7000_MAXUNSYNC,
DCF7000_SPEED,
DCF7000_CFLAG,
DCF7000_IFLAG,
DCF7000_OFLAG,
DCF7000_LFLAG,
DCF7000_SAMPLES,
DCF7000_KEEP
},
{
NO_CL_FLAGS,
WSDCF_POLL,
WSDCF_INIT,
NO_EVENT,
WSDCF_END,
NO_MESSAGE,
WSDCF_DATA,
WSDCF_ROOTDELAY,
WSDCF_BASEDELAY,
DCF_A_ID,
WSDCF_DESCRIPTION,
WSDCF_FORMAT,
DCF_TYPE,
WSDCF_MAXUNSYNC,
WSDCF_SPEED,
WSDCF_CFLAG,
WSDCF_IFLAG,
WSDCF_OFLAG,
WSDCF_LFLAG,
WSDCF_SAMPLES,
WSDCF_KEEP
},
{
RAWDCF_FLAGS,
NO_POLL,
RAWDCF_INIT,
NO_EVENT,
NO_END,
NO_MESSAGE,
NO_LCLDATA,
RAWDCF_ROOTDELAY,
CONRAD_BASEDELAY,
DCF_A_ID,
CONRAD_DESCRIPTION,
RAWDCF_FORMAT,
DCF_TYPE,
RAWDCF_MAXUNSYNC,
RAWDCF_SPEED,
RAWDCF_CFLAG,
RAWDCF_IFLAG,
RAWDCF_OFLAG,
RAWDCF_LFLAG,
RAWDCF_SAMPLES,
RAWDCF_KEEP
},
{
RAWDCF_FLAGS,
NO_POLL,
RAWDCF_INIT,
NO_EVENT,
NO_END,
NO_MESSAGE,
NO_LCLDATA,
RAWDCF_ROOTDELAY,
TIMEBRICK_BASEDELAY,
DCF_A_ID,
TIMEBRICK_DESCRIPTION,
RAWDCF_FORMAT,
DCF_TYPE,
RAWDCF_MAXUNSYNC,
RAWDCF_SPEED,
RAWDCF_CFLAG,
RAWDCF_IFLAG,
RAWDCF_OFLAG,
RAWDCF_LFLAG,
RAWDCF_SAMPLES,
RAWDCF_KEEP
},
{
MBG_FLAGS,
GPS16X_POLL,
GPS16X_INIT,
NO_EVENT,
GPS16X_END,
GPS16X_MESSAGE,
GPS16X_DATA,
GPS16X_ROOTDELAY,
GPS16X_BASEDELAY,
GPS16X_ID,
GPS16X_DESCRIPTION,
GPS16X_FORMAT,
GPS_TYPE,
GPS16X_MAXUNSYNC,
GPS16X_SPEED,
GPS16X_CFLAG,
GPS16X_IFLAG,
GPS16X_OFLAG,
GPS16X_LFLAG,
GPS16X_SAMPLES,
GPS16X_KEEP
},
{
RAWDCF_FLAGS,
NO_POLL,
NO_INIT,
NO_EVENT,
NO_END,
NO_MESSAGE,
NO_LCLDATA,
RAWDCF_ROOTDELAY,
IGELCLOCK_BASEDELAY,
DCF_A_ID,
IGELCLOCK_DESCRIPTION,
RAWDCF_FORMAT,
DCF_TYPE,
RAWDCF_MAXUNSYNC,
IGELCLOCK_SPEED,
IGELCLOCK_CFLAG,
RAWDCF_IFLAG,
RAWDCF_OFLAG,
RAWDCF_LFLAG,
RAWDCF_SAMPLES,
RAWDCF_KEEP
},
{
TRIMBLETAIP_FLAGS,
#if TRIM_POLLRATE
NO_POLL,
#else
TRIMBLETAIP_POLL,
#endif
TRIMBLETAIP_INIT,
TRIMBLETAIP_EVENT,
TRIMBLETAIP_END,
NO_MESSAGE,
TRIMBLETAIP_DATA,
TRIMBLETAIP_ROOTDELAY,
TRIMBLETAIP_BASEDELAY,
TRIMBLETAIP_ID,
TRIMBLETAIP_DESCRIPTION,
TRIMBLETAIP_FORMAT,
GPS_TYPE,
TRIMBLETAIP_MAXUNSYNC,
TRIMBLETAIP_SPEED,
TRIMBLETAIP_CFLAG,
TRIMBLETAIP_IFLAG,
TRIMBLETAIP_OFLAG,
TRIMBLETAIP_LFLAG,
TRIMBLETAIP_SAMPLES,
TRIMBLETAIP_KEEP
},
{
TRIMBLETSIP_FLAGS,
#if TRIM_POLLRATE
NO_POLL,
#else
TRIMBLETSIP_POLL,
#endif
TRIMBLETSIP_INIT,
TRIMBLETSIP_EVENT,
TRIMBLETSIP_END,
TRIMBLETSIP_MESSAGE,
TRIMBLETSIP_DATA,
TRIMBLETSIP_ROOTDELAY,
TRIMBLETSIP_BASEDELAY,
TRIMBLETSIP_ID,
TRIMBLETSIP_DESCRIPTION,
TRIMBLETSIP_FORMAT,
GPS_TYPE,
TRIMBLETSIP_MAXUNSYNC,
TRIMBLETSIP_SPEED,
TRIMBLETSIP_CFLAG,
TRIMBLETSIP_IFLAG,
TRIMBLETSIP_OFLAG,
TRIMBLETSIP_LFLAG,
TRIMBLETSIP_SAMPLES,
TRIMBLETSIP_KEEP
},
{
NO_CL_FLAGS,
RCC8000_POLL,
RCC8000_INIT,
NO_EVENT,
RCC8000_END,
NO_MESSAGE,
RCC8000_DATA,
RCC8000_ROOTDELAY,
RCC8000_BASEDELAY,
RCC8000_ID,
RCC8000_DESCRIPTION,
RCC8000_FORMAT,
DCF_TYPE,
RCC8000_MAXUNSYNC,
RCC8000_SPEED,
RCC8000_CFLAG,
RCC8000_IFLAG,
RCC8000_OFLAG,
RCC8000_LFLAG,
RCC8000_SAMPLES,
RCC8000_KEEP
},
{
HOPF6021_FLAGS,
NO_POLL,
NO_INIT,
NO_EVENT,
NO_END,
NO_MESSAGE,
NO_LCLDATA,
HOPF6021_ROOTDELAY,
HOPF6021_BASEDELAY,
DCF_ID,
HOPF6021_DESCRIPTION,
HOPF6021_FORMAT,
DCF_TYPE,
HOPF6021_MAXUNSYNC,
HOPF6021_SPEED,
HOPF6021_CFLAG,
HOPF6021_IFLAG,
HOPF6021_OFLAG,
HOPF6021_LFLAG,
HOPF6021_SAMPLES,
HOPF6021_KEEP
},
{
COMPUTIME_FLAGS,
NO_POLL,
NO_INIT,
NO_EVENT,
NO_END,
NO_MESSAGE,
NO_LCLDATA,
COMPUTIME_ROOTDELAY,
COMPUTIME_BASEDELAY,
COMPUTIME_ID,
COMPUTIME_DESCRIPTION,
COMPUTIME_FORMAT,
COMPUTIME_TYPE,
COMPUTIME_MAXUNSYNC,
COMPUTIME_SPEED,
COMPUTIME_CFLAG,
COMPUTIME_IFLAG,
COMPUTIME_OFLAG,
COMPUTIME_LFLAG,
COMPUTIME_SAMPLES,
COMPUTIME_KEEP
},
{
RAWDCF_FLAGS,
NO_POLL,
RAWDCFDTRSET_INIT,
NO_EVENT,
NO_END,
NO_MESSAGE,
NO_LCLDATA,
RAWDCF_ROOTDELAY,
RAWDCF_BASEDELAY,
DCF_A_ID,
RAWDCFDTRSET_DESCRIPTION,
RAWDCF_FORMAT,
DCF_TYPE,
RAWDCF_MAXUNSYNC,
RAWDCF_SPEED,
RAWDCF_CFLAG,
RAWDCF_IFLAG,
RAWDCF_OFLAG,
RAWDCF_LFLAG,
RAWDCF_SAMPLES,
RAWDCF_KEEP
},
{
0,
NO_POLL,
NO_INIT,
NO_EVENT,
NO_END,
NO_MESSAGE,
NO_LCLDATA,
0,
11.0 / 9600,
DCF_ID,
"WHARTON 400A Series clock",
"WHARTON 400A Series clock Output Format 1",
DCF_TYPE,
(1*60*60),
B9600,
(CS8|CREAD|PARENB|CLOCAL|HUPCL),
0,
0,
0,
5,
3,
},
{
RAWDCF_FLAGS,
NO_POLL,
RAWDCFDTRCLRRTSSET_INIT,
NO_EVENT,
NO_END,
NO_MESSAGE,
NO_LCLDATA,
RAWDCF_ROOTDELAY,
RAWDCF_BASEDELAY,
DCF_A_ID,
RAWDCFDTRCLRRTSSET_DESCRIPTION,
RAWDCF_FORMAT,
DCF_TYPE,
RAWDCF_MAXUNSYNC,
RAWDCF_SPEED,
RAWDCF_CFLAG,
RAWDCF_IFLAG,
RAWDCF_OFLAG,
RAWDCF_LFLAG,
RAWDCF_SAMPLES,
RAWDCF_KEEP
},
{
VARITEXT_FLAGS,
NO_POLL,
NO_INIT,
NO_EVENT,
NO_END,
NO_MESSAGE,
NO_LCLDATA,
VARITEXT_ROOTDELAY,
VARITEXT_BASEDELAY,
VARITEXT_ID,
VARITEXT_DESCRIPTION,
VARITEXT_FORMAT,
VARITEXT_TYPE,
VARITEXT_MAXUNSYNC,
VARITEXT_SPEED,
VARITEXT_CFLAG,
VARITEXT_IFLAG,
VARITEXT_OFLAG,
VARITEXT_LFLAG,
VARITEXT_SAMPLES,
VARITEXT_KEEP
},
{
MBG_FLAGS,
NO_POLL,
NO_INIT,
NO_EVENT,
GPS16X_END,
GPS16X_MESSAGE,
GPS16X_DATA,
GPS16X_ROOTDELAY,
GPS16X_BASEDELAY,
GPS16X_ID,
GPS16X_DESCRIPTION,
GPS16X_FORMAT,
GPS_TYPE,
GPS16X_MAXUNSYNC,
GPS16X_SPEED,
GPS16X_CFLAG,
GPS16X_IFLAG,
GPS16X_OFLAG,
GPS16X_LFLAG,
GPS16X_SAMPLES,
GPS16X_KEEP
},
{
RAWDCF_FLAGS,
NO_POLL,
RAWDCF_INIT,
NO_EVENT,
NO_END,
NO_MESSAGE,
NO_LCLDATA,
RAWDCF_ROOTDELAY,
GUDE_EMC_USB_V20_BASEDELAY,
DCF_A_ID,
GUDE_EMC_USB_V20_DESCRIPTION,
RAWDCF_FORMAT,
DCF_TYPE,
RAWDCF_MAXUNSYNC,
GUDE_EMC_USB_V20_SPEED,
RAWDCF_CFLAG,
RAWDCF_IFLAG,
RAWDCF_OFLAG,
RAWDCF_LFLAG,
RAWDCF_SAMPLES,
RAWDCF_KEEP
},
};
static int ncltypes = sizeof(parse_clockinfo) / sizeof(struct parse_clockinfo);
#define CLK_REALTYPE(x) ((int)(((x)->ttl) & 0x7F))
#define CLK_TYPE(x) ((CLK_REALTYPE(x) >= ncltypes) ? ~0 : CLK_REALTYPE(x))
#define CLK_UNIT(x) ((int)REFCLOCKUNIT(&(x)->srcadr))
#define CLK_PPS(x) (((x)->ttl) & 0x80)
#define PARSEHSREFID 0x7f7f08ff
#define PARSESTATISTICS (60*60)
static int notice = 0;
#define PARSE_STATETIME(parse, i) ((parse->generic->currentstatus == i) ? parse->statetime[i] + current_time - parse->lastchange : parse->statetime[i])
static void parse_event (struct parseunit *, int);
static void parse_process (struct parseunit *, parsetime_t *);
static void clear_err (struct parseunit *, u_long);
static int list_err (struct parseunit *, u_long);
static char * l_mktime (u_long);
static void
clear_err(
struct parseunit *parse,
u_long lstate
)
{
if (lstate == ERR_ALL)
{
int i;
for (i = 0; i < ERR_CNT; i++)
{
parse->errors[i].err_stage = err_tbl[i];
parse->errors[i].err_cnt = 0;
parse->errors[i].err_last = 0;
parse->errors[i].err_started = 0;
parse->errors[i].err_suppressed = 0;
}
}
else
{
parse->errors[lstate].err_stage = err_tbl[lstate];
parse->errors[lstate].err_cnt = 0;
parse->errors[lstate].err_last = 0;
parse->errors[lstate].err_started = 0;
parse->errors[lstate].err_suppressed = 0;
}
}
static int
list_err(
struct parseunit *parse,
u_long lstate
)
{
int do_it;
struct errorinfo *err = &parse->errors[lstate];
if (err->err_started == 0)
{
err->err_started = current_time;
}
do_it = (current_time - err->err_last) >= err->err_stage->err_delay;
if (do_it)
err->err_cnt++;
if (err->err_stage->err_count &&
(err->err_cnt >= err->err_stage->err_count))
{
err->err_stage++;
err->err_cnt = 0;
}
if (!err->err_cnt && do_it)
msyslog(LOG_INFO, "PARSE receiver #%d: interval for following error message class is at least %s",
CLK_UNIT(parse->peer), l_mktime(err->err_stage->err_delay));
if (!do_it)
err->err_suppressed++;
else
err->err_last = current_time;
if (do_it && err->err_suppressed)
{
msyslog(LOG_INFO, "PARSE receiver #%d: %ld message%s suppressed, error condition class persists for %s",
CLK_UNIT(parse->peer), err->err_suppressed, (err->err_suppressed == 1) ? " was" : "s where",
l_mktime(current_time - err->err_started));
err->err_suppressed = 0;
}
return do_it;
}
#ifndef isprint
#define isprint(_X_) (((_X_) > 0x1F) && ((_X_) < 0x7F))
#endif
static char *
mkreadable(
char *buffer,
long blen,
const char *src,
u_long srclen,
int hex
)
{
char *b = buffer;
char *endb = (char *)0;
if (blen < 4)
return (char *)0;
endb = buffer + blen - 4;
blen--;
while (blen && srclen--)
{
if (!hex &&
(*src != '\\') &&
(*src != '"') &&
isprint((int)*src))
{
*buffer++ = *src++;
blen--;
}
else
{
if (blen < 4)
{
while (blen--)
{
*buffer++ = '.';
}
*buffer = '\0';
return b;
}
else
{
if (*src == '\\')
{
strcpy(buffer,"\\\\");
buffer += 2;
blen -= 2;
src++;
}
else
{
sprintf(buffer, "\\x%02x", *src++);
blen -= 4;
buffer += 4;
}
}
}
if (srclen && !blen && endb)
strcpy(endb, "...");
}
*buffer = '\0';
return b;
}
static char *
mkascii(
char *buffer,
long blen,
const char *src,
u_long srclen
)
{
return mkreadable(buffer, blen, src, srclen, 0);
}
#ifdef STREAM
static int ppsclock_init (struct parseunit *);
static int stream_init (struct parseunit *);
static void stream_end (struct parseunit *);
static int stream_enable (struct parseunit *);
static int stream_disable (struct parseunit *);
static int stream_setcs (struct parseunit *, parsectl_t *);
static int stream_getfmt (struct parseunit *, parsectl_t *);
static int stream_setfmt (struct parseunit *, parsectl_t *);
static int stream_timecode (struct parseunit *, parsectl_t *);
static void stream_receive (struct recvbuf *);
#endif
static int local_init (struct parseunit *);
static void local_end (struct parseunit *);
static int local_nop (struct parseunit *);
static int local_setcs (struct parseunit *, parsectl_t *);
static int local_getfmt (struct parseunit *, parsectl_t *);
static int local_setfmt (struct parseunit *, parsectl_t *);
static int local_timecode (struct parseunit *, parsectl_t *);
static void local_receive (struct recvbuf *);
static int local_input (struct recvbuf *);
static bind_t io_bindings[] =
{
#ifdef STREAM
{
"parse STREAM",
stream_init,
stream_end,
stream_setcs,
stream_disable,
stream_enable,
stream_getfmt,
stream_setfmt,
stream_timecode,
stream_receive,
0,
},
{
"ppsclock STREAM",
ppsclock_init,
local_end,
local_setcs,
local_nop,
local_nop,
local_getfmt,
local_setfmt,
local_timecode,
local_receive,
local_input,
},
#endif
{
"normal",
local_init,
local_end,
local_setcs,
local_nop,
local_nop,
local_getfmt,
local_setfmt,
local_timecode,
local_receive,
local_input,
},
{
(char *)0,
}
};
#ifdef STREAM
#define fix_ts(_X_) \
if ((&(_X_))->tv.tv_usec >= 1000000) \
{ \
(&(_X_))->tv.tv_usec -= 1000000; \
(&(_X_))->tv.tv_sec += 1; \
}
#define cvt_ts(_X_, _Y_) \
{ \
l_fp ts; \
fix_ts((_X_)); \
if (!buftvtots((const char *)&(&(_X_))->tv, &ts)) \
{ \
ERR(ERR_BADDATA) \
msyslog(LOG_ERR,"parse: stream_receive: timestamp conversion error (buftvtots) (%s) (%ld.%06ld) ", (_Y_), (long)(&(_X_))->tv.tv_sec, (long)(&(_X_))->tv.tv_usec);\
return; \
} \
else \
{ \
(&(_X_))->fp = ts; \
} \
}
static int
ppsclock_init(
struct parseunit *parse
)
{
static char m1[] = "ppsclocd";
static char m2[] = "ppsclock";
if (ioctl(parse->ppsfd, I_PUSH, (caddr_t)m1) == -1 &&
ioctl(parse->ppsfd, I_PUSH, (caddr_t)m2) == -1)
{
if (errno != EINVAL)
{
msyslog(LOG_ERR, "PARSE receiver #%d: ppsclock_init: ioctl(fd, I_PUSH, \"ppsclock\"): %m",
CLK_UNIT(parse->peer));
}
return 0;
}
if (!local_init(parse))
{
(void)ioctl(parse->ppsfd, I_POP, (caddr_t)0);
return 0;
}
parse->flags |= PARSE_PPSCLOCK;
return 1;
}
static int
stream_init(
struct parseunit *parse
)
{
static char m1[] = "parse";
if (ioctl(parse->generic->io.fd, I_PUSH, (caddr_t)m1) == -1)
{
if (errno != EINVAL)
{
msyslog(LOG_ERR, "PARSE receiver #%d: stream_init: ioctl(fd, I_PUSH, \"parse\"): %m", CLK_UNIT(parse->peer));
}
return 0;
}
else
{
while(ioctl(parse->generic->io.fd, I_POP, (caddr_t)0) == 0)
;
if (ioctl(parse->generic->io.fd, I_PUSH, (caddr_t)m1) == -1)
{
msyslog(LOG_ERR, "PARSE receiver #%d: stream_init: ioctl(fd, I_PUSH, \"parse\"): %m", CLK_UNIT(parse->peer));
return 0;
}
else
{
return 1;
}
}
}
static void
stream_end(
struct parseunit *parse
)
{
while(ioctl(parse->generic->io.fd, I_POP, (caddr_t)0) == 0)
;
}
static int
stream_setcs(
struct parseunit *parse,
parsectl_t *tcl
)
{
struct strioctl strioc;
strioc.ic_cmd = PARSEIOC_SETCS;
strioc.ic_timout = 0;
strioc.ic_dp = (char *)tcl;
strioc.ic_len = sizeof (*tcl);
if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1)
{
msyslog(LOG_ERR, "PARSE receiver #%d: stream_setcs: ioctl(fd, I_STR, PARSEIOC_SETCS): %m", CLK_UNIT(parse->peer));
return 0;
}
return 1;
}
static int
stream_enable(
struct parseunit *parse
)
{
struct strioctl strioc;
strioc.ic_cmd = PARSEIOC_ENABLE;
strioc.ic_timout = 0;
strioc.ic_dp = (char *)0;
strioc.ic_len = 0;
if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1)
{
msyslog(LOG_ERR, "PARSE receiver #%d: stream_enable: ioctl(fd, I_STR, PARSEIOC_ENABLE): %m", CLK_UNIT(parse->peer));
return 0;
}
parse->generic->io.clock_recv = stream_receive;
return 1;
}
static int
stream_disable(
struct parseunit *parse
)
{
struct strioctl strioc;
strioc.ic_cmd = PARSEIOC_DISABLE;
strioc.ic_timout = 0;
strioc.ic_dp = (char *)0;
strioc.ic_len = 0;
if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1)
{
msyslog(LOG_ERR, "PARSE receiver #%d: stream_disable: ioctl(fd, I_STR, PARSEIOC_DISABLE): %m", CLK_UNIT(parse->peer));
return 0;
}
parse->generic->io.clock_recv = local_receive;
return 1;
}
static int
stream_getfmt(
struct parseunit *parse,
parsectl_t *tcl
)
{
struct strioctl strioc;
strioc.ic_cmd = PARSEIOC_GETFMT;
strioc.ic_timout = 0;
strioc.ic_dp = (char *)tcl;
strioc.ic_len = sizeof (*tcl);
if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1)
{
msyslog(LOG_ERR, "PARSE receiver #%d: ioctl(fd, I_STR, PARSEIOC_GETFMT): %m", CLK_UNIT(parse->peer));
return 0;
}
return 1;
}
static int
stream_setfmt(
struct parseunit *parse,
parsectl_t *tcl
)
{
struct strioctl strioc;
strioc.ic_cmd = PARSEIOC_SETFMT;
strioc.ic_timout = 0;
strioc.ic_dp = (char *)tcl;
strioc.ic_len = sizeof (*tcl);
if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1)
{
msyslog(LOG_ERR, "PARSE receiver #%d: stream_setfmt: ioctl(fd, I_STR, PARSEIOC_SETFMT): %m", CLK_UNIT(parse->peer));
return 0;
}
return 1;
}
static int
stream_timecode(
struct parseunit *parse,
parsectl_t *tcl
)
{
struct strioctl strioc;
strioc.ic_cmd = PARSEIOC_TIMECODE;
strioc.ic_timout = 0;
strioc.ic_dp = (char *)tcl;
strioc.ic_len = sizeof (*tcl);
if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1)
{
ERR(ERR_INTERNAL)
msyslog(LOG_ERR, "PARSE receiver #%d: stream_timecode: ioctl(fd, I_STR, PARSEIOC_TIMECODE): %m", CLK_UNIT(parse->peer));
return 0;
}
clear_err(parse, ERR_INTERNAL);
return 1;
}
static void
stream_receive(
struct recvbuf *rbufp
)
{
struct parseunit *parse = (struct parseunit *)((void *)rbufp->recv_srcclock);
parsetime_t parsetime;
if (!parse->peer)
return;
if (rbufp->recv_length != sizeof(parsetime_t))
{
ERR(ERR_BADIO)
msyslog(LOG_ERR,"PARSE receiver #%d: stream_receive: bad size (got %d expected %d)",
CLK_UNIT(parse->peer), rbufp->recv_length, (int)sizeof(parsetime_t));
parse_event(parse, CEVNT_BADREPLY);
return;
}
clear_err(parse, ERR_BADIO);
memmove((caddr_t)&parsetime,
(caddr_t)rbufp->recv_buffer,
sizeof(parsetime_t));
#ifdef DEBUG
if (debug > 3)
{
printf("PARSE receiver #%d: status %06x, state %08x, time %lx.%08lx, stime %lx.%08lx, ptime %lx.%08lx\n",
CLK_UNIT(parse->peer),
(unsigned int)parsetime.parse_status,
(unsigned int)parsetime.parse_state,
(unsigned long)parsetime.parse_time.tv.tv_sec,
(unsigned long)parsetime.parse_time.tv.tv_usec,
(unsigned long)parsetime.parse_stime.tv.tv_sec,
(unsigned long)parsetime.parse_stime.tv.tv_usec,
(unsigned long)parsetime.parse_ptime.tv.tv_sec,
(unsigned long)parsetime.parse_ptime.tv.tv_usec);
}
#endif
cvt_ts(parsetime.parse_stime, "parse_stime");
if (PARSE_TIMECODE(parsetime.parse_state))
{
cvt_ts(parsetime.parse_time, "parse_time");
}
if (PARSE_PPS(parsetime.parse_state))
cvt_ts(parsetime.parse_ptime, "parse_ptime");
parse_process(parse, &parsetime);
}
#endif
static int
local_init(
struct parseunit *parse
)
{
return parse_ioinit(&parse->parseio);
}
static void
local_end(
struct parseunit *parse
)
{
parse_ioend(&parse->parseio);
}
static int
local_nop(
struct parseunit *parse
)
{
return 1;
}
static int
local_setcs(
struct parseunit *parse,
parsectl_t *tcl
)
{
return parse_setcs(tcl, &parse->parseio);
}
static int
local_getfmt(
struct parseunit *parse,
parsectl_t *tcl
)
{
return parse_getfmt(tcl, &parse->parseio);
}
static int
local_setfmt(
struct parseunit *parse,
parsectl_t *tcl
)
{
return parse_setfmt(tcl, &parse->parseio);
}
static int
local_timecode(
struct parseunit *parse,
parsectl_t *tcl
)
{
return parse_timecode(tcl, &parse->parseio);
}
static int
local_input(
struct recvbuf *rbufp
)
{
struct parseunit *parse = (struct parseunit *)((void *)rbufp->recv_srcclock);
int count;
unsigned char *s;
timestamp_t ts;
if (!parse->peer)
return 0;
count = rbufp->recv_length;
s = (unsigned char *)rbufp->recv_buffer;
ts.fp = rbufp->recv_time;
while (count--)
{
if (parse_ioread(&parse->parseio, (unsigned int)(*s++), &ts))
{
struct recvbuf *buf;
if (!PARSE_PPS(parse->parseio.parse_dtime.parse_state))
{
#ifdef HAVE_PPSAPI
if (parse->flags & PARSE_PPSCLOCK)
{
struct timespec pps_timeout;
pps_info_t pps_info;
pps_timeout.tv_sec = 0;
pps_timeout.tv_nsec = 0;
if (time_pps_fetch(parse->atom.handle, PPS_TSFMT_TSPEC, &pps_info,
&pps_timeout) == 0)
{
if (pps_info.assert_sequence + pps_info.clear_sequence != parse->ppsserial)
{
double dtemp;
struct timespec pts;
if (parse->flags & PARSE_CLEAR)
pts = pps_info.clear_timestamp;
else
pts = pps_info.assert_timestamp;
parse->parseio.parse_dtime.parse_ptime.fp.l_ui = pts.tv_sec + JAN_1970;
dtemp = pts.tv_nsec / 1e9;
if (dtemp < 0.) {
dtemp += 1;
parse->parseio.parse_dtime.parse_ptime.fp.l_ui--;
}
if (dtemp > 1.) {
dtemp -= 1;
parse->parseio.parse_dtime.parse_ptime.fp.l_ui++;
}
parse->parseio.parse_dtime.parse_ptime.fp.l_uf = dtemp * FRAC;
parse->parseio.parse_dtime.parse_state |= PARSEB_PPS|PARSEB_S_PPS;
#ifdef DEBUG
if (debug > 3)
{
printf(
"parse: local_receive: fd %d PPSAPI seq %ld - PPS %s\n",
rbufp->fd,
(long)pps_info.assert_sequence + (long)pps_info.clear_sequence,
lfptoa(&parse->parseio.parse_dtime.parse_ptime.fp, 6));
}
#endif
}
#ifdef DEBUG
else
{
if (debug > 3)
{
printf(
"parse: local_receive: fd %d PPSAPI seq assert %ld, seq clear %ld - NO PPS event\n",
rbufp->fd,
(long)pps_info.assert_sequence, (long)pps_info.clear_sequence);
}
}
#endif
parse->ppsserial = pps_info.assert_sequence + pps_info.clear_sequence;
}
#ifdef DEBUG
else
{
if (debug > 3)
{
printf(
"parse: local_receive: fd %d PPSAPI time_pps_fetch errno = %d\n",
rbufp->fd,
errno);
}
}
#endif
}
#else
#ifdef TIOCDCDTIMESTAMP
struct timeval dcd_time;
if (ioctl(parse->ppsfd, TIOCDCDTIMESTAMP, &dcd_time) != -1)
{
l_fp tstmp;
TVTOTS(&dcd_time, &tstmp);
tstmp.l_ui += JAN_1970;
L_SUB(&ts.fp, &tstmp);
if (ts.fp.l_ui == 0)
{
#ifdef DEBUG
if (debug)
{
printf(
"parse: local_receive: fd %d DCDTIMESTAMP %s\n",
parse->ppsfd,
lfptoa(&tstmp, 6));
printf(" sigio %s\n",
lfptoa(&ts.fp, 6));
}
#endif
parse->parseio.parse_dtime.parse_ptime.fp = tstmp;
parse->parseio.parse_dtime.parse_state |= PARSEB_PPS|PARSEB_S_PPS;
}
}
#else
#if defined(HAVE_STRUCT_PPSCLOCKEV) && (defined(HAVE_CIOGETEV) || defined(HAVE_TIOCGPPSEV))
if (parse->flags & PARSE_PPSCLOCK)
{
l_fp tts;
struct ppsclockev ev;
#ifdef HAVE_CIOGETEV
if (ioctl(parse->ppsfd, CIOGETEV, (caddr_t)&ev) == 0)
#endif
#ifdef HAVE_TIOCGPPSEV
if (ioctl(parse->ppsfd, TIOCGPPSEV, (caddr_t)&ev) == 0)
#endif
{
if (ev.serial != parse->ppsserial)
{
if (!buftvtots((const char *)&ev.tv, &tts))
{
ERR(ERR_BADDATA)
msyslog(LOG_ERR,"parse: local_receive: timestamp conversion error (buftvtots) (ppsclockev.tv)");
}
else
{
parse->parseio.parse_dtime.parse_ptime.fp = tts;
parse->parseio.parse_dtime.parse_state |= PARSEB_PPS|PARSEB_S_PPS;
}
}
parse->ppsserial = ev.serial;
}
}
#endif
#endif
#endif
}
if (count)
{
buf = get_free_recv_buffer();
if (buf != NULL) {
memmove((caddr_t)buf->recv_buffer,
(caddr_t)&parse->parseio.parse_dtime,
sizeof(parsetime_t));
buf->recv_length = sizeof(parsetime_t);
buf->recv_time = rbufp->recv_time;
buf->srcadr = rbufp->srcadr;
buf->dstadr = rbufp->dstadr;
buf->receiver = rbufp->receiver;
buf->fd = rbufp->fd;
buf->X_from_where = rbufp->X_from_where;
add_full_recv_buffer(buf);
}
parse_iodone(&parse->parseio);
}
else
{
memmove((caddr_t)rbufp->recv_buffer,
(caddr_t)&parse->parseio.parse_dtime,
sizeof(parsetime_t));
parse_iodone(&parse->parseio);
rbufp->recv_length = sizeof(parsetime_t);
return 1;
}
}
}
return 0;
}
static void
local_receive(
struct recvbuf *rbufp
)
{
struct parseunit *parse = (struct parseunit *)((void *)rbufp->recv_srcclock);
parsetime_t parsetime;
if (!parse->peer)
return;
if (rbufp->recv_length != sizeof(parsetime_t))
{
ERR(ERR_BADIO)
msyslog(LOG_ERR,"PARSE receiver #%d: local_receive: bad size (got %d expected %d)",
CLK_UNIT(parse->peer), rbufp->recv_length, (int)sizeof(parsetime_t));
parse_event(parse, CEVNT_BADREPLY);
return;
}
clear_err(parse, ERR_BADIO);
memmove((caddr_t)&parsetime,
(caddr_t)rbufp->recv_buffer,
sizeof(parsetime_t));
#ifdef DEBUG
if (debug > 3)
{
printf("PARSE receiver #%d: status %06x, state %08x, time(fp) %lx.%08lx, stime(fp) %lx.%08lx, ptime(fp) %lx.%08lx\n",
CLK_UNIT(parse->peer),
(unsigned int)parsetime.parse_status,
(unsigned int)parsetime.parse_state,
(unsigned long)parsetime.parse_time.fp.l_ui,
(unsigned long)parsetime.parse_time.fp.l_uf,
(unsigned long)parsetime.parse_stime.fp.l_ui,
(unsigned long)parsetime.parse_stime.fp.l_uf,
(unsigned long)parsetime.parse_ptime.fp.l_ui,
(unsigned long)parsetime.parse_ptime.fp.l_uf);
}
#endif
parse_process(parse, &parsetime);
}
static bind_t *
init_iobinding(
struct parseunit *parse
)
{
bind_t *b = io_bindings;
while (b->bd_description != (char *)0)
{
if ((*b->bd_init)(parse))
{
return b;
}
b++;
}
return (bind_t *)0;
}
static char *
parsestate(
u_long lstate,
char *buffer,
int size
)
{
static struct bits
{
u_long bit;
const char *name;
} flagstrings[] =
{
{ PARSEB_ANNOUNCE, "DST SWITCH WARNING" },
{ PARSEB_POWERUP, "NOT SYNCHRONIZED" },
{ PARSEB_NOSYNC, "TIME CODE NOT CONFIRMED" },
{ PARSEB_DST, "DST" },
{ PARSEB_UTC, "UTC DISPLAY" },
{ PARSEB_LEAPADD, "LEAP ADD WARNING" },
{ PARSEB_LEAPDEL, "LEAP DELETE WARNING" },
{ PARSEB_LEAPSECOND, "LEAP SECOND" },
{ PARSEB_ALTERNATE, "ALTERNATE ANTENNA" },
{ PARSEB_TIMECODE, "TIME CODE" },
{ PARSEB_PPS, "PPS" },
{ PARSEB_POSITION, "POSITION" },
{ 0 }
};
static struct sbits
{
u_long bit;
const char *name;
} sflagstrings[] =
{
{ PARSEB_S_LEAP, "LEAP INDICATION" },
{ PARSEB_S_PPS, "PPS SIGNAL" },
{ PARSEB_S_ANTENNA, "ANTENNA" },
{ PARSEB_S_POSITION, "POSITION" },
{ 0 }
};
int i;
char *s, *t;
*buffer = '\0';
s = t = buffer;
i = 0;
while (flagstrings[i].bit)
{
if (flagstrings[i].bit & lstate)
{
if (s != t)
strncpy(t, "; ", BUFFER_SIZES(buffer, t, size));
strncat(t, flagstrings[i].name, BUFFER_SIZES(buffer, t, size));
t += strlen(t);
}
i++;
}
if (lstate & (PARSEB_S_LEAP|PARSEB_S_ANTENNA|PARSEB_S_PPS|PARSEB_S_POSITION))
{
if (s != t)
strncpy(t, "; ", BUFFER_SIZES(buffer, t, size));
t += strlen(t);
strncpy(t, "(", BUFFER_SIZES(buffer, t, size));
s = t = t + strlen(t);
i = 0;
while (sflagstrings[i].bit)
{
if (sflagstrings[i].bit & lstate)
{
if (t != s)
{
strncpy(t, "; ", BUFFER_SIZES(buffer, t, size));
t += 2;
}
strncpy(t, sflagstrings[i].name, BUFFER_SIZES(buffer, t, size));
t += strlen(t);
}
i++;
}
strncpy(t, ")", BUFFER_SIZES(buffer, t, size));
}
return buffer;
}
static char *
parsestatus(
u_long lstate,
char *buffer,
int size
)
{
static struct bits
{
u_long bit;
const char *name;
} flagstrings[] =
{
{ CVT_OK, "CONVERSION SUCCESSFUL" },
{ CVT_NONE, "NO CONVERSION" },
{ CVT_FAIL, "CONVERSION FAILED" },
{ CVT_BADFMT, "ILLEGAL FORMAT" },
{ CVT_BADDATE, "DATE ILLEGAL" },
{ CVT_BADTIME, "TIME ILLEGAL" },
{ CVT_ADDITIONAL, "ADDITIONAL DATA" },
{ 0 }
};
int i;
*buffer = '\0';
i = 0;
while (flagstrings[i].bit)
{
if (flagstrings[i].bit & lstate)
{
if (buffer[0])
strncat(buffer, "; ", size);
strncat(buffer, flagstrings[i].name, size);
}
i++;
}
return buffer;
}
static const char *
clockstatus(
u_long lstate
)
{
static char buffer[20];
static struct status
{
u_long value;
const char *name;
} flagstrings[] =
{
{ CEVNT_NOMINAL, "NOMINAL" },
{ CEVNT_TIMEOUT, "NO RESPONSE" },
{ CEVNT_BADREPLY,"BAD FORMAT" },
{ CEVNT_FAULT, "FAULT" },
{ CEVNT_PROP, "PROPAGATION DELAY" },
{ CEVNT_BADDATE, "ILLEGAL DATE" },
{ CEVNT_BADTIME, "ILLEGAL TIME" },
{ (unsigned)~0L }
};
int i;
i = 0;
while (flagstrings[i].value != ~0)
{
if (flagstrings[i].value == lstate)
{
return flagstrings[i].name;
}
i++;
}
snprintf(buffer, sizeof(buffer), "unknown #%ld", (u_long)lstate);
return buffer;
}
static char *
l_mktime(
u_long delta
)
{
u_long tmp, m, s;
static char buffer[40];
char *t;
buffer[0] = '\0';
if ((tmp = delta / (60*60*24)) != 0)
{
snprintf(buffer, BUFFER_SIZE(buffer, buffer), "%ldd+", (u_long)tmp);
delta -= tmp * 60*60*24;
}
s = delta % 60;
delta /= 60;
m = delta % 60;
delta /= 60;
t = buffer + strlen(buffer);
snprintf(t, BUFFER_SIZE(buffer, t), "%02d:%02d:%02d",
(int)delta, (int)m, (int)s);
return buffer;
}
static void
parse_statistics(
struct parseunit *parse
)
{
int i;
NLOG(NLOG_CLOCKSTATIST)
{
msyslog(LOG_INFO, "PARSE receiver #%d: running time: %s",
CLK_UNIT(parse->peer),
l_mktime(current_time - parse->generic->timestarted));
msyslog(LOG_INFO, "PARSE receiver #%d: current status: %s",
CLK_UNIT(parse->peer),
clockstatus(parse->generic->currentstatus));
for (i = 0; i <= CEVNT_MAX; i++)
{
u_long s_time;
u_long percent, d = current_time - parse->generic->timestarted;
percent = s_time = PARSE_STATETIME(parse, i);
while (((u_long)(~0) / 10000) < percent)
{
percent /= 10;
d /= 10;
}
if (d)
percent = (percent * 10000) / d;
else
percent = 10000;
if (s_time)
msyslog(LOG_INFO, "PARSE receiver #%d: state %18s: %13s (%3ld.%02ld%%)",
CLK_UNIT(parse->peer),
clockstatus((unsigned int)i),
l_mktime(s_time),
percent / 100, percent % 100);
}
}
}
static void
cparse_statistics(
struct parseunit *parse
)
{
if (parse->laststatistic + PARSESTATISTICS < current_time)
parse_statistics(parse);
parse->laststatistic = current_time;
}
static void
parse_shutdown(
int unit,
struct peer *peer
)
{
struct parseunit *parse = (struct parseunit *)0;
if (peer && peer->procptr)
parse = (struct parseunit *)peer->procptr->unitptr;
if (!parse)
{
return;
}
if (!parse->peer)
{
msyslog(LOG_INFO, "PARSE receiver #%d: INTERNAL ERROR - unit already inactive - shutdown ignored", unit);
return;
}
#ifdef HAVE_PPSAPI
if (parse->flags & PARSE_PPSCLOCK)
{
(void)time_pps_destroy(parse->atom.handle);
}
#endif
if (parse->generic->io.fd != parse->ppsfd && parse->ppsfd != -1)
(void)close(parse->ppsfd);
parse_statistics(parse);
if (parse->parse_type->cl_end)
{
parse->parse_type->cl_end(parse);
}
if (parse->binding)
PARSE_END(parse);
io_closeclock(&parse->generic->io);
free_varlist(parse->kv);
NLOG(NLOG_CLOCKINFO)
msyslog(LOG_INFO, "PARSE receiver #%d: reference clock \"%s\" removed",
CLK_UNIT(parse->peer), parse->parse_type->cl_description);
parse->peer = (struct peer *)0;
peer->procptr->unitptr = (caddr_t)0;
free(parse);
}
#ifdef HAVE_PPSAPI
static void
parse_hardpps(
struct parseunit *parse,
int mode
)
{
if (parse->hardppsstate == mode)
return;
if (CLK_PPS(parse->peer) && (parse->flags & PARSE_PPSKERNEL)) {
int i = 0;
if (mode == PARSE_HARDPPS_ENABLE)
{
if (parse->flags & PARSE_CLEAR)
i = PPS_CAPTURECLEAR;
else
i = PPS_CAPTUREASSERT;
}
if (time_pps_kcbind(parse->atom.handle, PPS_KC_HARDPPS, i,
PPS_TSFMT_TSPEC) < 0) {
msyslog(LOG_ERR, "PARSE receiver #%d: time_pps_kcbind failed: %m",
CLK_UNIT(parse->peer));
} else {
NLOG(NLOG_CLOCKINFO)
msyslog(LOG_INFO, "PARSE receiver #%d: kernel PPS synchronisation %sabled",
CLK_UNIT(parse->peer), (mode == PARSE_HARDPPS_ENABLE) ? "en" : "dis");
if (mode == PARSE_HARDPPS_ENABLE)
pps_enable = 1;
}
}
parse->hardppsstate = mode;
}
static int
parse_ppsapi(
struct parseunit *parse
)
{
int cap, mode_ppsoffset;
char *cp;
parse->flags &= ~PARSE_PPSCLOCK;
if (time_pps_getcap(parse->atom.handle, &cap) < 0) {
msyslog(LOG_ERR, "PARSE receiver #%d: parse_ppsapi: time_pps_getcap failed: %m",
CLK_UNIT(parse->peer));
return 0;
}
if (!refclock_params(parse->flags & (CLK_FLAG1|CLK_FLAG2|CLK_FLAG4), &parse->atom))
return 0;
if (parse->flags & PARSE_CLEAR) {
cp = "CLEAR";
mode_ppsoffset = PPS_OFFSETCLEAR;
} else {
cp = "ASSERT";
mode_ppsoffset = PPS_OFFSETASSERT;
}
msyslog(LOG_INFO, "PARSE receiver #%d: initializing PPS to %s",
CLK_UNIT(parse->peer), cp);
if (!(mode_ppsoffset & cap)) {
msyslog(LOG_WARNING, "PARSE receiver #%d: Cannot set PPS_%sCLEAR, this will increase jitter (PPS API capabilities=0x%x)",
CLK_UNIT(parse->peer), cp, cap);
mode_ppsoffset = 0;
} else {
if (mode_ppsoffset == PPS_OFFSETCLEAR)
{
parse->atom.pps_params.clear_offset.tv_sec = -parse->ppsphaseadjust;
parse->atom.pps_params.clear_offset.tv_nsec = -1e9*(parse->ppsphaseadjust - (long)parse->ppsphaseadjust);
}
if (mode_ppsoffset == PPS_OFFSETASSERT)
{
parse->atom.pps_params.assert_offset.tv_sec = -parse->ppsphaseadjust;
parse->atom.pps_params.assert_offset.tv_nsec = -1e9*(parse->ppsphaseadjust - (long)parse->ppsphaseadjust);
}
}
parse->atom.pps_params.mode |= mode_ppsoffset;
if (time_pps_setparams(parse->atom.handle, &parse->atom.pps_params) < 0) {
msyslog(LOG_ERR, "PARSE receiver #%d: FAILED set PPS parameters: %m",
CLK_UNIT(parse->peer));
return 0;
}
parse->flags |= PARSE_PPSCLOCK;
return 1;
}
#else
#define parse_hardpps(_PARSE_, _MODE_)
#endif
static int
parse_start(
int sysunit,
struct peer *peer
)
{
u_int unit;
int fd232;
#ifdef HAVE_TERMIOS
struct termios tio;
#endif
#ifdef HAVE_SYSV_TTYS
struct termio tio;
#endif
struct parseunit * parse;
char parsedev[sizeof(PARSEDEVICE)+20];
char parseppsdev[sizeof(PARSEPPSDEVICE)+20];
parsectl_t tmp_ctl;
u_int type;
if (!notice)
{
NLOG(NLOG_CLOCKINFO)
msyslog(LOG_INFO, "NTP PARSE support: Copyright (c) 1989-2009, Frank Kardel");
notice = 1;
}
type = CLK_TYPE(peer);
unit = CLK_UNIT(peer);
if ((type == ~0) || (parse_clockinfo[type].cl_description == (char *)0))
{
msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: unsupported clock type %d (max %d)",
unit, CLK_REALTYPE(peer), ncltypes-1);
return 0;
}
(void) snprintf(parsedev, sizeof(parsedev), PARSEDEVICE, unit);
(void) snprintf(parseppsdev, sizeof(parsedev), PARSEPPSDEVICE, unit);
#ifndef O_NOCTTY
#define O_NOCTTY 0
#endif
fd232 = open(parsedev, O_RDWR | O_NOCTTY
#ifdef O_NONBLOCK
| O_NONBLOCK
#endif
, 0777);
if (fd232 == -1)
{
msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: open of %s failed: %m", unit, parsedev);
return 0;
}
parse = (struct parseunit *)emalloc(sizeof(struct parseunit));
memset((char *)parse, 0, sizeof(struct parseunit));
parse->generic = peer->procptr;
parse->generic->unitptr = (caddr_t)parse;
parse->generic->timestarted = current_time;
parse->lastchange = current_time;
parse->flags = 0;
parse->pollneeddata = 0;
parse->laststatistic = current_time;
parse->lastformat = (unsigned short)~0;
parse->timedata.parse_status = (unsigned short)~0;
parse->lastmissed = 0;
parse->ppsserial = 0;
parse->ppsfd = -1;
parse->localdata = (void *)0;
parse->localstate = 0;
parse->kv = (struct ctl_var *)0;
clear_err(parse, ERR_ALL);
parse->parse_type = &parse_clockinfo[type];
parse->maxunsync = parse->parse_type->cl_maxunsync;
parse->generic->fudgetime1 = parse->parse_type->cl_basedelay;
parse->generic->fudgetime2 = 0.0;
parse->ppsphaseadjust = parse->generic->fudgetime2;
parse->generic->clockdesc = parse->parse_type->cl_description;
peer->rootdelay = parse->parse_type->cl_rootdelay;
peer->sstclktype = parse->parse_type->cl_type;
peer->precision = sys_precision;
peer->stratum = STRATUM_REFCLOCK;
if (peer->stratum <= 1)
memmove((char *)&parse->generic->refid, parse->parse_type->cl_id, 4);
else
parse->generic->refid = htonl(PARSEHSREFID);
parse->generic->io.fd = fd232;
parse->peer = peer;
if (TTY_GETATTR(fd232, &tio) == -1)
{
msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: tcgetattr(%d, &tio): %m", unit, fd232);
parse_shutdown(CLK_UNIT(parse->peer), peer);
return 0;
}
else
{
#ifndef _PC_VDISABLE
memset((char *)tio.c_cc, 0, sizeof(tio.c_cc));
#else
int disablec;
errno = 0;
disablec = fpathconf(parse->generic->io.fd, _PC_VDISABLE);
if (disablec == -1 && errno)
{
msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: fpathconf(fd, _PC_VDISABLE): %m", CLK_UNIT(parse->peer));
memset((char *)tio.c_cc, 0, sizeof(tio.c_cc));
}
else
if (disablec != -1)
memset((char *)tio.c_cc, disablec, sizeof(tio.c_cc));
#endif
#if defined (VMIN) || defined(VTIME)
if ((parse_clockinfo[type].cl_lflag & ICANON) == 0)
{
#ifdef VMIN
tio.c_cc[VMIN] = 1;
#endif
#ifdef VTIME
tio.c_cc[VTIME] = 0;
#endif
}
#endif
tio.c_cflag = parse_clockinfo[type].cl_cflag;
tio.c_iflag = parse_clockinfo[type].cl_iflag;
tio.c_oflag = parse_clockinfo[type].cl_oflag;
tio.c_lflag = parse_clockinfo[type].cl_lflag;
#ifdef HAVE_TERMIOS
if ((cfsetospeed(&tio, parse_clockinfo[type].cl_speed) == -1) ||
(cfsetispeed(&tio, parse_clockinfo[type].cl_speed) == -1))
{
msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: tcset{i,o}speed(&tio, speed): %m", unit);
parse_shutdown(CLK_UNIT(parse->peer), peer);
return 0;
}
#else
tio.c_cflag |= parse_clockinfo[type].cl_speed;
#endif
parse->ppsfd = open(parseppsdev, O_RDWR | O_NOCTTY
#ifdef O_NONBLOCK
| O_NONBLOCK
#endif
, 0777);
if (parse->ppsfd == -1)
{
parse->ppsfd = fd232;
}
#if defined(HAVE_TIO_SERIAL_STUFF)
{
struct serial_struct ss;
if (ioctl(parse->ppsfd, TIOCGSERIAL, &ss) < 0 ||
(
#ifdef ASYNC_LOW_LATENCY
ss.flags |= ASYNC_LOW_LATENCY,
#endif
#ifndef HAVE_PPSAPI
#ifdef ASYNC_PPS_CD_NEG
ss.flags |= ASYNC_PPS_CD_NEG,
#endif
#endif
ioctl(parse->ppsfd, TIOCSSERIAL, &ss)) < 0) {
msyslog(LOG_NOTICE, "refclock_parse: TIOCSSERIAL fd %d, %m", parse->ppsfd);
msyslog(LOG_NOTICE,
"refclock_parse: optional PPS processing not available");
} else {
parse->flags |= PARSE_PPSCLOCK;
#ifdef ASYNC_PPS_CD_NEG
NLOG(NLOG_CLOCKINFO)
msyslog(LOG_INFO,
"refclock_parse: PPS detection on");
#endif
}
}
#endif
#ifdef HAVE_TIOCSPPS
if (CLK_PPS(parse->peer))
{
int i = 1;
if (ioctl(parse->ppsfd, TIOCSPPS, (caddr_t)&i) == 0)
{
parse->flags |= PARSE_PPSCLOCK;
}
}
#endif
#if defined(HAVE_PPSAPI)
parse->hardppsstate = PARSE_HARDPPS_DISABLE;
if (CLK_PPS(parse->peer))
{
if (!refclock_ppsapi(parse->ppsfd, &parse->atom))
{
msyslog(LOG_NOTICE, "PARSE receiver #%d: parse_start: could not set up PPS: %m", CLK_UNIT(parse->peer));
}
else
{
parse_ppsapi(parse);
}
}
#endif
if (TTY_SETATTR(fd232, &tio) == -1)
{
msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: tcsetattr(%d, &tio): %m", unit, fd232);
parse_shutdown(CLK_UNIT(parse->peer), peer);
return 0;
}
}
parse->generic->io.srcclock = (caddr_t)parse;
parse->generic->io.datalen = 0;
parse->binding = init_iobinding(parse);
if (parse->binding == (bind_t *)0)
{
msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: io sub system initialisation failed.", CLK_UNIT(parse->peer));
parse_shutdown(CLK_UNIT(parse->peer), peer);
return 0;
}
parse->generic->io.clock_recv = parse->binding->bd_receive;
parse->generic->io.io_input = parse->binding->bd_io_input;
switch (tio.c_cflag & CSIZE)
{
case CS5:
tmp_ctl.parsesetcs.parse_cs = PARSE_IO_CS5;
break;
case CS6:
tmp_ctl.parsesetcs.parse_cs = PARSE_IO_CS6;
break;
case CS7:
tmp_ctl.parsesetcs.parse_cs = PARSE_IO_CS7;
break;
case CS8:
tmp_ctl.parsesetcs.parse_cs = PARSE_IO_CS8;
break;
}
if (!PARSE_SETCS(parse, &tmp_ctl))
{
msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: parse_setcs() FAILED.", unit);
parse_shutdown(CLK_UNIT(parse->peer), peer);
return 0;
}
strncpy(tmp_ctl.parseformat.parse_buffer, parse->parse_type->cl_format, sizeof(tmp_ctl.parseformat.parse_buffer));
tmp_ctl.parseformat.parse_count = strlen(tmp_ctl.parseformat.parse_buffer);
if (!PARSE_SETFMT(parse, &tmp_ctl))
{
msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: parse_setfmt() FAILED.", unit);
parse_shutdown(CLK_UNIT(parse->peer), peer);
return 0;
}
#ifdef HAVE_TERMIOS
(void) tcflush(parse->generic->io.fd, TCIOFLUSH);
#else
#if defined(TCFLSH) && defined(TCIOFLUSH)
{
int flshcmd = TCIOFLUSH;
(void) ioctl(parse->generic->io.fd, TCFLSH, (caddr_t)&flshcmd);
}
#endif
#endif
if (parse->parse_type->cl_init)
{
if (parse->parse_type->cl_init(parse))
{
parse_shutdown(CLK_UNIT(parse->peer), peer);
return 0;
}
}
if (!io_addclock(&parse->generic->io))
{
msyslog(LOG_ERR,
"PARSE receiver #%d: parse_start: addclock %s fails (ABORT - clock type requires async io)", CLK_UNIT(parse->peer), parsedev);
parse_shutdown(CLK_UNIT(parse->peer), peer);
return 0;
}
NLOG(NLOG_CLOCKINFO)
{
msyslog(LOG_INFO, "PARSE receiver #%d: reference clock \"%s\" (I/O device %s, PPS device %s) added",
CLK_UNIT(parse->peer),
parse->parse_type->cl_description, parsedev,
(parse->ppsfd != parse->generic->io.fd) ? parseppsdev : parsedev);
msyslog(LOG_INFO, "PARSE receiver #%d: Stratum %d, trust time %s, precision %d",
CLK_UNIT(parse->peer),
parse->peer->stratum,
l_mktime(parse->maxunsync), parse->peer->precision);
msyslog(LOG_INFO, "PARSE receiver #%d: rootdelay %.6f s, phase adjustment %.6f s, PPS phase adjustment %.6f s, %s IO handling",
CLK_UNIT(parse->peer),
parse->parse_type->cl_rootdelay,
parse->generic->fudgetime1,
parse->ppsphaseadjust,
parse->binding->bd_description);
msyslog(LOG_INFO, "PARSE receiver #%d: Format recognition: %s", CLK_UNIT(parse->peer),
parse->parse_type->cl_format);
msyslog(LOG_INFO, "PARSE receiver #%d: %sPPS support%s", CLK_UNIT(parse->peer),
CLK_PPS(parse->peer) ? "" : "NO ",
CLK_PPS(parse->peer) ?
#ifdef PPS_METHOD
" (implementation " PPS_METHOD ")"
#else
""
#endif
: ""
);
}
return 1;
}
static void
parse_ctl(
struct parseunit *parse,
struct refclockstat *in
)
{
if (in)
{
if (in->haveflags & (CLK_HAVEFLAG1|CLK_HAVEFLAG2|CLK_HAVEFLAG3|CLK_HAVEFLAG4))
{
parse->flags = (parse->flags & ~(CLK_FLAG1|CLK_FLAG2|CLK_FLAG3|CLK_FLAG4)) |
(in->flags & (CLK_FLAG1|CLK_FLAG2|CLK_FLAG3|CLK_FLAG4));
#if defined(HAVE_PPSAPI)
if (CLK_PPS(parse->peer))
{
parse_ppsapi(parse);
}
#endif
}
if (in->haveflags & CLK_HAVETIME1)
{
parse->generic->fudgetime1 = in->fudgetime1;
msyslog(LOG_INFO, "PARSE receiver #%d: new phase adjustment %.6f s",
CLK_UNIT(parse->peer),
parse->generic->fudgetime1);
}
if (in->haveflags & CLK_HAVETIME2)
{
parse->generic->fudgetime2 = in->fudgetime2;
if (parse->flags & PARSE_TRUSTTIME)
{
parse->maxunsync = (u_long)ABS(in->fudgetime2);
msyslog(LOG_INFO, "PARSE receiver #%d: new trust time %s",
CLK_UNIT(parse->peer),
l_mktime(parse->maxunsync));
}
else
{
parse->ppsphaseadjust = in->fudgetime2;
msyslog(LOG_INFO, "PARSE receiver #%d: new PPS phase adjustment %.6f s",
CLK_UNIT(parse->peer),
parse->ppsphaseadjust);
#if defined(HAVE_PPSAPI)
if (CLK_PPS(parse->peer))
{
parse_ppsapi(parse);
}
#endif
}
}
}
}
static void
parse_poll(
int unit,
struct peer *peer
)
{
struct parseunit *parse = (struct parseunit *)peer->procptr->unitptr;
if (peer != parse->peer)
{
msyslog(LOG_ERR,
"PARSE receiver #%d: poll: INTERNAL: peer incorrect",
unit);
return;
}
parse->generic->polls++;
if (parse->pollneeddata &&
((current_time - parse->pollneeddata) > (1<<(max(min(parse->peer->hpoll, parse->peer->ppoll), parse->peer->minpoll)))))
{
parse->lastmissed = current_time;
parse_event(parse, CEVNT_TIMEOUT);
ERR(ERR_NODATA)
msyslog(LOG_WARNING, "PARSE receiver #%d: no data from device within poll interval (check receiver / wiring)", CLK_UNIT(parse->peer));
}
parse->pollneeddata = current_time;
if (parse->parse_type->cl_poll)
{
parse->parse_type->cl_poll(parse);
}
cparse_statistics(parse);
return;
}
#define LEN_STATES 300
static void
parse_control(
int unit,
struct refclockstat *in,
struct refclockstat *out,
struct peer *peer
)
{
struct parseunit *parse = (struct parseunit *)peer->procptr->unitptr;
parsectl_t tmpctl;
static char outstatus[400];
if (out)
{
out->lencode = 0;
out->p_lastcode = 0;
out->kv_list = (struct ctl_var *)0;
}
if (!parse || !parse->peer)
{
msyslog(LOG_ERR, "PARSE receiver #%d: parse_control: unit invalid (UNIT INACTIVE)",
unit);
return;
}
unit = CLK_UNIT(parse->peer);
parse_ctl(parse, in);
if (out)
{
u_long sum = 0;
char *tt, *start;
int i;
outstatus[0] = '\0';
out->type = REFCLK_PARSE;
parse->generic->fudgetime2 = (parse->flags & PARSE_TRUSTTIME) ? (double)parse->maxunsync : parse->ppsphaseadjust;
if (PARSE_SYNC(parse->timedata.parse_state))
{
if (PARSE_PPS(parse->timedata.parse_state) && PARSE_TIMECODE(parse->timedata.parse_state))
{
l_fp off;
off = parse->timedata.parse_stime.fp;
L_SUB(&off, &parse->timedata.parse_ptime.fp);
tt = add_var(&out->kv_list, 80, RO);
snprintf(tt, 80, "refclock_ppsskew=%s", lfptoms(&off, 6));
}
}
if (PARSE_PPS(parse->timedata.parse_state))
{
tt = add_var(&out->kv_list, 80, RO|DEF);
snprintf(tt, 80, "refclock_ppstime=\"%s\"", gmprettydate(&parse->timedata.parse_ptime.fp));
}
start = tt = add_var(&out->kv_list, 128, RO|DEF);
snprintf(tt, 128, "refclock_time=\"");
tt += strlen(tt);
if (parse->timedata.parse_time.fp.l_ui == 0)
{
strncpy(tt, "<UNDEFINED>\"", BUFFER_SIZES(start, tt, 128));
}
else
{
snprintf(tt, 128, "%s\"", gmprettydate(&parse->timedata.parse_time.fp));
}
if (!PARSE_GETTIMECODE(parse, &tmpctl))
{
ERR(ERR_INTERNAL)
msyslog(LOG_ERR, "PARSE receiver #%d: parse_control: parse_timecode() FAILED", unit);
}
else
{
start = tt = add_var(&out->kv_list, 512, RO|DEF);
snprintf(tt, 512, "refclock_status=\"");
tt += strlen(tt);
tmpctl.parsegettc.parse_state |= parse->timedata.parse_state &
(PARSEB_PPS|PARSEB_S_PPS);
(void) parsestate(tmpctl.parsegettc.parse_state, tt, BUFFER_SIZES(start, tt, 512));
strncat(tt, "\"", BUFFER_SIZES(start, tt, 512));
if (tmpctl.parsegettc.parse_count)
mkascii(outstatus+strlen(outstatus), (int)(sizeof(outstatus)- strlen(outstatus) - 1),
tmpctl.parsegettc.parse_buffer, (unsigned)(tmpctl.parsegettc.parse_count));
}
tmpctl.parseformat.parse_format = tmpctl.parsegettc.parse_format;
if (!PARSE_GETFMT(parse, &tmpctl))
{
ERR(ERR_INTERNAL)
msyslog(LOG_ERR, "PARSE receiver #%d: parse_control: parse_getfmt() FAILED", unit);
}
else
{
tt = add_var(&out->kv_list, 80, RO|DEF);
snprintf(tt, 80, "refclock_format=\"");
strncat(tt, tmpctl.parseformat.parse_buffer, tmpctl.parseformat.parse_count);
strncat(tt,"\"", 80);
}
start = tt = add_var(&out->kv_list, LEN_STATES, RO|DEF);
strncpy(tt, "refclock_states=\"", LEN_STATES);
tt += strlen(tt);
for (i = 0; i <= CEVNT_MAX; i++)
{
u_long s_time;
u_long d = current_time - parse->generic->timestarted;
u_long percent;
percent = s_time = PARSE_STATETIME(parse, i);
while (((u_long)(~0) / 10000) < percent)
{
percent /= 10;
d /= 10;
}
if (d)
percent = (percent * 10000) / d;
else
percent = 10000;
if (s_time)
{
char item[80];
int count;
snprintf(item, 80, "%s%s%s: %s (%d.%02d%%)",
sum ? "; " : "",
(parse->generic->currentstatus == i) ? "*" : "",
clockstatus((unsigned int)i),
l_mktime(s_time),
(int)(percent / 100), (int)(percent % 100));
if ((count = strlen(item)) < (LEN_STATES - 40 - (tt - start)))
{
strncpy(tt, item, BUFFER_SIZES(start, tt, LEN_STATES));
tt += count;
}
sum += s_time;
}
}
snprintf(tt, BUFFER_SIZES(start, tt, LEN_STATES), "; running time: %s\"", l_mktime(sum));
tt = add_var(&out->kv_list, 32, RO);
snprintf(tt, 32, "refclock_id=\"%s\"", parse->parse_type->cl_id);
tt = add_var(&out->kv_list, 80, RO);
snprintf(tt, 80, "refclock_iomode=\"%s\"", parse->binding->bd_description);
tt = add_var(&out->kv_list, 128, RO);
snprintf(tt, 128, "refclock_driver_version=\"%s\"", rcsid);
{
struct ctl_var *k;
k = parse->kv;
while (k && !(k->flags & EOV))
{
set_var(&out->kv_list, k->text, strlen(k->text)+1, k->flags);
k++;
}
}
out->lencode = strlen(outstatus);
out->p_lastcode = outstatus;
}
}
static void
parse_event(
struct parseunit *parse,
int event
)
{
if (parse->generic->currentstatus != (u_char) event)
{
parse->statetime[parse->generic->currentstatus] += current_time - parse->lastchange;
parse->lastchange = current_time;
if (parse->parse_type->cl_event)
parse->parse_type->cl_event(parse, event);
if (event == CEVNT_NOMINAL)
{
NLOG(NLOG_CLOCKSTATUS)
msyslog(LOG_INFO, "PARSE receiver #%d: SYNCHRONIZED",
CLK_UNIT(parse->peer));
}
refclock_report(parse->peer, event);
}
}
static void
parse_process(
struct parseunit *parse,
parsetime_t *parsetime
)
{
l_fp off, rectime, reftime;
double fudge;
if (((parsetime->parse_status & CVT_MASK) != CVT_OK) &&
((parsetime->parse_status & CVT_MASK) != CVT_NONE) &&
(parse->timedata.parse_status != parsetime->parse_status))
{
char buffer[400];
NLOG(NLOG_CLOCKINFO)
msyslog(LOG_WARNING, "PARSE receiver #%d: conversion status \"%s\"",
CLK_UNIT(parse->peer), parsestatus(parsetime->parse_status, buffer, sizeof(buffer)));
if ((parsetime->parse_status & CVT_MASK) == CVT_FAIL)
{
parsectl_t tmpctl;
if (!PARSE_GETTIMECODE(parse, &tmpctl))
{
ERR(ERR_INTERNAL)
msyslog(LOG_ERR, "PARSE receiver #%d: parse_process: parse_timecode() FAILED", CLK_UNIT(parse->peer));
}
else
{
ERR(ERR_BADDATA)
msyslog(LOG_WARNING, "PARSE receiver #%d: FAILED TIMECODE: \"%s\" (check receiver configuration / wiring)",
CLK_UNIT(parse->peer), mkascii(buffer, sizeof buffer, tmpctl.parsegettc.parse_buffer, (unsigned)(tmpctl.parsegettc.parse_count - 1)));
}
}
}
if ((parsetime->parse_status & CVT_MASK) != CVT_OK)
{
switch (parsetime->parse_status & CVT_MASK)
{
case CVT_NONE:
if ((parsetime->parse_status & CVT_ADDITIONAL) &&
parse->parse_type->cl_message)
parse->parse_type->cl_message(parse, parsetime);
if (PARSE_PPS(parsetime->parse_state))
{
parse->timedata.parse_state |= PARSEB_PPS|PARSEB_S_PPS;
parse->timedata.parse_ptime = parsetime->parse_ptime;
}
break;
case CVT_FAIL:
if (parsetime->parse_status & CVT_BADFMT)
{
parse_event(parse, CEVNT_BADREPLY);
}
else
if (parsetime->parse_status & CVT_BADDATE)
{
parse_event(parse, CEVNT_BADDATE);
}
else
if (parsetime->parse_status & CVT_BADTIME)
{
parse_event(parse, CEVNT_BADTIME);
}
else
{
parse_event(parse, CEVNT_BADREPLY);
}
}
return;
}
if (parse->lastformat != parsetime->parse_format)
{
parsectl_t tmpctl;
tmpctl.parseformat.parse_format = parsetime->parse_format;
if (!PARSE_GETFMT(parse, &tmpctl))
{
ERR(ERR_INTERNAL)
msyslog(LOG_ERR, "PARSE receiver #%d: parse_getfmt() FAILED", CLK_UNIT(parse->peer));
}
else
{
NLOG(NLOG_CLOCKINFO)
msyslog(LOG_INFO, "PARSE receiver #%d: packet format \"%s\"",
CLK_UNIT(parse->peer), tmpctl.parseformat.parse_buffer);
}
parse->lastformat = parsetime->parse_format;
}
if ((parse->timedata.parse_state ^ parsetime->parse_state) &
~(unsigned)(PARSEB_PPS|PARSEB_S_PPS))
{
char tmp1[200];
char tmp2[200];
(void) parsestate(parsetime->parse_state, tmp1, sizeof(tmp1));
(void) parsestate(parse->timedata.parse_state, tmp2, sizeof(tmp2));
NLOG(NLOG_CLOCKINFO)
msyslog(LOG_INFO,"PARSE receiver #%d: STATE CHANGE: %s -> %s",
CLK_UNIT(parse->peer), tmp2, tmp1);
}
if (PARSE_PPS(parse->timedata.parse_state) && !PARSE_PPS(parsetime->parse_state))
{
parsetime->parse_state |= PARSEB_PPS|PARSEB_S_PPS;
parsetime->parse_ptime = parse->timedata.parse_ptime;
}
parse->timedata = *parsetime;
if (PARSE_POWERUP(parsetime->parse_state))
{
parse_event(parse, CEVNT_FAULT);
NLOG(NLOG_CLOCKSTATUS)
ERR(ERR_BADSTATUS)
msyslog(LOG_ERR,"PARSE receiver #%d: NOT SYNCHRONIZED",
CLK_UNIT(parse->peer));
}
else
{
if (PARSE_SYNC(parsetime->parse_state))
{
parse->lastsync = current_time;
clear_err(parse, ERR_BADSTATUS);
}
else
{
parse_event(parse, CEVNT_PROP);
NLOG(NLOG_CLOCKSTATUS)
ERR(ERR_BADSTATUS)
msyslog(LOG_ERR,"PARSE receiver #%d: TIMECODE NOT CONFIRMED",
CLK_UNIT(parse->peer));
}
}
fudge = parse->generic->fudgetime1;
if (PARSE_TIMECODE(parsetime->parse_state))
{
rectime = parsetime->parse_stime.fp;
off = reftime = parsetime->parse_time.fp;
L_SUB(&off, &rectime);
#ifdef DEBUG
if (debug > 3)
printf("PARSE receiver #%d: Reftime %s, Recvtime %s - initial offset %s\n",
CLK_UNIT(parse->peer),
prettydate(&reftime),
prettydate(&rectime),
lfptoa(&off,6));
#endif
}
if (PARSE_PPS(parsetime->parse_state) && CLK_PPS(parse->peer))
{
l_fp offset;
double ppsphaseadjust = parse->ppsphaseadjust;
#ifdef HAVE_PPSAPI
if (parse->atom.pps_params.mode & (PPS_OFFSETCLEAR|PPS_OFFSETASSERT))
{
ppsphaseadjust = 0.0;
}
#endif
offset = parsetime->parse_ptime.fp;
#ifdef DEBUG
if (debug > 3)
printf("PARSE receiver #%d: PPStime %s\n",
CLK_UNIT(parse->peer),
prettydate(&offset));
#endif
if (PARSE_TIMECODE(parsetime->parse_state))
{
if (M_ISGEQ(off.l_i, off.l_f, -1, 0x80000000) &&
M_ISGEQ(0, 0x7fffffff, off.l_i, off.l_f))
{
fudge = ppsphaseadjust;
if (parse->parse_type->cl_flags & PARSE_F_PPSONSECOND)
{
reftime = off = offset;
if (reftime.l_uf & (unsigned)0x80000000)
reftime.l_ui++;
reftime.l_uf = 0;
off.l_uf = ~off.l_uf;
off.l_ui = (off.l_f < 0) ? ~0 : 0;
}
else
{
reftime = off = parsetime->parse_time.fp;
L_SUB(&off, &offset);
}
}
}
else
{
fudge = ppsphaseadjust;
off = offset;
reftime = offset;
if (reftime.l_uf & (unsigned)0x80000000)
reftime.l_ui++;
reftime.l_uf = 0;
off.l_uf = ~off.l_uf;
off.l_ui = (off.l_f < 0) ? ~0 : 0;
}
}
else
{
if (!PARSE_TIMECODE(parsetime->parse_state))
{
if ((parsetime->parse_status & CVT_ADDITIONAL) &&
parse->parse_type->cl_message)
parse->parse_type->cl_message(parse, parsetime);
return;
}
}
#ifdef DEBUG
if (debug > 3)
printf("PARSE receiver #%d: Reftime %s, Recvtime %s - final offset %s\n",
CLK_UNIT(parse->peer),
prettydate(&reftime),
prettydate(&rectime),
lfptoa(&off,6));
#endif
rectime = reftime;
L_SUB(&rectime, &off);
#ifdef DEBUG
if (debug > 3)
printf("PARSE receiver #%d: calculated Reftime %s, Recvtime %s\n",
CLK_UNIT(parse->peer),
prettydate(&reftime),
prettydate(&rectime));
#endif
if ((parsetime->parse_status & CVT_ADDITIONAL) &&
parse->parse_type->cl_message)
parse->parse_type->cl_message(parse, parsetime);
if (PARSE_SYNC(parsetime->parse_state))
{
parse_event(parse, CEVNT_NOMINAL);
}
clear_err(parse, ERR_BADIO);
clear_err(parse, ERR_BADDATA);
clear_err(parse, ERR_NODATA);
clear_err(parse, ERR_INTERNAL);
if (((current_time - parse->lastsync) > parse->maxunsync) ||
(parse->lastsync < parse->lastmissed) ||
((parse->lastsync == 0) && !PARSE_SYNC(parsetime->parse_state)) ||
PARSE_POWERUP(parsetime->parse_state))
{
parse->generic->leap = LEAP_NOTINSYNC;
parse->lastsync = 0;
}
else
{
if (PARSE_LEAPADD(parsetime->parse_state))
{
parse->generic->leap = (parse->flags & PARSE_LEAP_DELETE) ? LEAP_DELSECOND : LEAP_ADDSECOND;
}
else
if (PARSE_LEAPDEL(parsetime->parse_state))
{
parse->generic->leap = LEAP_DELSECOND;
}
else
{
parse->generic->leap = LEAP_NOWARNING;
}
}
if (parse->generic->leap != LEAP_NOTINSYNC)
{
#ifdef DEBUG
if (debug > 2)
{
printf("PARSE receiver #%d: refclock_process_offset(reftime=%s, rectime=%s, Fudge=%f)\n",
CLK_UNIT(parse->peer),
prettydate(&reftime),
prettydate(&rectime),
fudge);
}
#endif
parse->generic->lastref = reftime;
refclock_process_offset(parse->generic, reftime, rectime, fudge);
#ifdef HAVE_PPSAPI
if (PARSE_PPS(parsetime->parse_state) && CLK_PPS(parse->peer))
{
double savedtime1 = parse->generic->fudgetime1;
parse->generic->fudgetime1 = fudge;
if (refclock_pps(parse->peer, &parse->atom,
parse->flags & (CLK_FLAG1|CLK_FLAG2|CLK_FLAG3|CLK_FLAG4))) {
parse->peer->flags |= FLAG_PPS;
} else {
parse->peer->flags &= ~FLAG_PPS;
}
parse->generic->fudgetime1 = savedtime1;
parse_hardpps(parse, PARSE_HARDPPS_ENABLE);
}
#endif
} else {
parse_hardpps(parse, PARSE_HARDPPS_DISABLE);
parse->peer->flags &= ~FLAG_PPS;
}
if (!parse->pollneeddata && parse->peer->disp <= MAXDISTANCE)
return;
parse->pollneeddata = 0;
parse->timedata.parse_state &= ~(unsigned)(PARSEB_PPS|PARSEB_S_PPS);
refclock_receive(parse->peer);
}
static void
mk_utcinfo(
char *t,
int wnt,
int wnlsf,
int dn,
int dtls,
int dtlsf,
int size
)
{
l_fp leapdate;
char *start = t;
snprintf(t, size, "current correction %d sec", dtls);
t += strlen(t);
if (wnlsf < 990)
wnlsf += 1024;
if (wnt < 990)
wnt += 1024;
gpstolfp((unsigned short)wnlsf, (unsigned short)dn, 0, &leapdate);
if ((dtlsf != dtls) &&
((wnlsf - wnt) < 52))
{
snprintf(t, BUFFER_SIZES(start, t, size), ", next correction %d sec on %s, new GPS-UTC offset %d",
dtlsf - dtls, gmprettydate(&leapdate), dtlsf);
}
else
{
snprintf(t, BUFFER_SIZES(start, t, size), ", last correction on %s",
gmprettydate(&leapdate));
}
}
#ifdef CLOCK_MEINBERG
static void
gps16x_message(
struct parseunit *parse,
parsetime_t *parsetime
)
{
if (parse->timedata.parse_msglen && parsetime->parse_msg[0] == SOH)
{
GPS_MSG_HDR header;
unsigned char *bufp = (unsigned char *)parsetime->parse_msg + 1;
#ifdef DEBUG
if (debug > 2)
{
char msgbuffer[600];
mkreadable(msgbuffer, sizeof(msgbuffer), (char *)parsetime->parse_msg, parsetime->parse_msglen, 1);
printf("PARSE receiver #%d: received message (%d bytes) >%s<\n",
CLK_UNIT(parse->peer),
parsetime->parse_msglen,
msgbuffer);
}
#endif
get_mbg_header(&bufp, &header);
if (header.gps_hdr_csum == mbg_csum(parsetime->parse_msg + 1, 6) &&
(header.gps_len == 0 ||
(header.gps_len < sizeof(parsetime->parse_msg) &&
header.gps_data_csum == mbg_csum(bufp, header.gps_len))))
{
switch (header.gps_cmd)
{
case GPS_SW_REV:
{
char buffer[64];
SW_REV gps_sw_rev;
get_mbg_sw_rev(&bufp, &gps_sw_rev);
snprintf(buffer, sizeof(buffer), "meinberg_gps_version=\"%x.%02x%s%s\"",
(gps_sw_rev.code >> 8) & 0xFF,
gps_sw_rev.code & 0xFF,
gps_sw_rev.name[0] ? " " : "",
gps_sw_rev.name);
set_var(&parse->kv, buffer, strlen(buffer)+1, RO|DEF);
}
break;
case GPS_STAT:
{
static struct state
{
unsigned short flag;
unsigned const char *string;
} states[] =
{
{ TM_ANT_DISCONN, (const unsigned char *)"ANTENNA FAULTY" },
{ TM_SYN_FLAG, (const unsigned char *)"NO SYNC SIGNAL" },
{ TM_NO_SYNC, (const unsigned char *)"NO SYNC POWERUP" },
{ TM_NO_POS, (const unsigned char *)"NO POSITION" },
{ 0, (const unsigned char *)"" }
};
unsigned short status;
struct state *s = states;
char buffer[512];
char *p, *b;
status = get_lsb_short(&bufp);
snprintf(buffer, sizeof(buffer), "meinberg_gps_status=\"[0x%04x] ", status);
if (status)
{
p = b = buffer + strlen(buffer);
while (s->flag)
{
if (status & s->flag)
{
if (p != b)
{
*p++ = ',';
*p++ = ' ';
}
strncat(p, (const char *)s->string, sizeof(buffer));
}
s++;
}
*p++ = '"';
*p = '\0';
}
else
{
strncat(buffer, "<OK>\"", sizeof(buffer));
}
set_var(&parse->kv, buffer, strlen(buffer)+1, RO|DEF);
}
break;
case GPS_POS_XYZ:
{
XYZ xyz;
char buffer[256];
get_mbg_xyz(&bufp, xyz);
snprintf(buffer, sizeof(buffer), "gps_position(XYZ)=\"%s m, %s m, %s m\"",
mfptoa(xyz[XP].l_ui, xyz[XP].l_uf, 1),
mfptoa(xyz[YP].l_ui, xyz[YP].l_uf, 1),
mfptoa(xyz[ZP].l_ui, xyz[ZP].l_uf, 1));
set_var(&parse->kv, buffer, sizeof(buffer), RO|DEF);
}
break;
case GPS_POS_LLA:
{
LLA lla;
char buffer[256];
get_mbg_lla(&bufp, lla);
snprintf(buffer, sizeof(buffer), "gps_position(LLA)=\"%s deg, %s deg, %s m\"",
mfptoa(lla[LAT].l_ui, lla[LAT].l_uf, 4),
mfptoa(lla[LON].l_ui, lla[LON].l_uf, 4),
mfptoa(lla[ALT].l_ui, lla[ALT].l_uf, 1));
set_var(&parse->kv, buffer, sizeof(buffer), RO|DEF);
}
break;
case GPS_TZDL:
break;
case GPS_PORT_PARM:
break;
case GPS_SYNTH:
break;
case GPS_ANT_INFO:
{
ANT_INFO antinfo;
char buffer[512];
char *p;
get_mbg_antinfo(&bufp, &antinfo);
snprintf(buffer, sizeof(buffer), "meinberg_antenna_status=\"");
p = buffer + strlen(buffer);
switch (antinfo.status)
{
case ANT_INVALID:
strncat(p, "<OK>", BUFFER_SIZE(buffer, p));
p += strlen(p);
break;
case ANT_DISCONN:
strncat(p, "DISCONNECTED since ", BUFFER_SIZE(buffer, p));
NLOG(NLOG_CLOCKSTATUS)
ERR(ERR_BADSTATUS)
msyslog(LOG_ERR,"PARSE receiver #%d: ANTENNA FAILURE: %s",
CLK_UNIT(parse->peer), p);
p += strlen(p);
mbg_tm_str(&p, &antinfo.tm_disconn, BUFFER_SIZE(buffer, p));
*p = '\0';
break;
case ANT_RECONN:
strncat(p, "RECONNECTED on ", BUFFER_SIZE(buffer, p));
p += strlen(p);
mbg_tm_str(&p, &antinfo.tm_reconn, BUFFER_SIZE(buffer, p));
snprintf(p, BUFFER_SIZE(buffer, p), ", reconnect clockoffset %c%ld.%07ld s, disconnect time ",
(antinfo.delta_t < 0) ? '-' : '+',
ABS(antinfo.delta_t) / 10000,
ABS(antinfo.delta_t) % 10000);
p += strlen(p);
mbg_tm_str(&p, &antinfo.tm_disconn, BUFFER_SIZE(buffer, p));
*p = '\0';
break;
default:
snprintf(p, BUFFER_SIZE(buffer, p), "bad status 0x%04x", antinfo.status);
p += strlen(p);
break;
}
strncat(p, "\"", BUFFER_SIZE(buffer, p));
set_var(&parse->kv, buffer, strlen(buffer)+1, RO|DEF);
}
break;
case GPS_UCAP:
break;
case GPS_CFGH:
{
CFGH cfgh;
char buffer[512];
char *p;
get_mbg_cfgh(&bufp, &cfgh);
if (cfgh.valid)
{
int i;
p = buffer;
strncpy(buffer, "gps_tot_51=\"", BUFFER_SIZE(buffer, p));
p += strlen(p);
mbg_tgps_str(&p, &cfgh.tot_51, BUFFER_SIZE(buffer, p));
strncpy(p, "\"", BUFFER_SIZE(buffer, p));
set_var(&parse->kv, buffer, strlen(buffer)+1, RO);
p = buffer;
strncpy(buffer, "gps_tot_63=\"", BUFFER_SIZE(buffer, p));
p += strlen(p);
mbg_tgps_str(&p, &cfgh.tot_63, BUFFER_SIZE(buffer, p));
strncpy(p, "\"", BUFFER_SIZE(buffer, p));
set_var(&parse->kv, buffer, strlen(buffer)+1, RO);
p = buffer;
strncpy(buffer, "gps_t0a=\"", BUFFER_SIZE(buffer, p));
p += strlen(p);
mbg_tgps_str(&p, &cfgh.t0a, BUFFER_SIZE(buffer, p));
strncpy(p, "\"", BUFFER_SIZE(buffer, p));
set_var(&parse->kv, buffer, strlen(buffer)+1, RO);
for (i = MIN_SVNO; i < MAX_SVNO; i++)
{
p = buffer;
snprintf(p, BUFFER_SIZE(buffer, p), "gps_cfg[%d]=\"[0x%x] ", i, cfgh.cfg[i]);
p += strlen(p);
switch (cfgh.cfg[i] & 0x7)
{
case 0:
strncpy(p, "BLOCK I", BUFFER_SIZE(buffer, p));
break;
case 1:
strncpy(p, "BLOCK II", BUFFER_SIZE(buffer, p));
break;
default:
strncpy(p, "bad CFG", BUFFER_SIZE(buffer, p));
break;
}
strncat(p, "\"", BUFFER_SIZE(buffer, p));
set_var(&parse->kv, buffer, strlen(buffer)+1, RO);
p = buffer;
snprintf(p, BUFFER_SIZE(buffer, p), "gps_health[%d]=\"[0x%x] ", i, cfgh.health[i]);
p += strlen(p);
switch ((cfgh.health[i] >> 5) & 0x7 )
{
case 0:
strncpy(p, "OK;", BUFFER_SIZE(buffer, p));
break;
case 1:
strncpy(p, "PARITY;", BUFFER_SIZE(buffer, p));
break;
case 2:
strncpy(p, "TLM/HOW;", BUFFER_SIZE(buffer, p));
break;
case 3:
strncpy(p, "Z-COUNT;", BUFFER_SIZE(buffer, p));
break;
case 4:
strncpy(p, "SUBFRAME 1,2,3;", BUFFER_SIZE(buffer, p));
break;
case 5:
strncpy(p, "SUBFRAME 4,5;", BUFFER_SIZE(buffer, p));
break;
case 6:
strncpy(p, "UPLOAD BAD;", BUFFER_SIZE(buffer, p));
break;
case 7:
strncpy(p, "DATA BAD;", BUFFER_SIZE(buffer, p));
break;
}
p += strlen(p);
switch (cfgh.health[i] & 0x1F)
{
case 0:
strncpy(p, "SIGNAL OK", BUFFER_SIZE(buffer, p));
break;
case 0x1C:
strncpy(p, "SV TEMP OUT", BUFFER_SIZE(buffer, p));
break;
case 0x1D:
strncpy(p, "SV WILL BE TEMP OUT", BUFFER_SIZE(buffer, p));
break;
case 0x1E:
break;
case 0x1F:
strncpy(p, "MULTIPLE ERRS", BUFFER_SIZE(buffer, p));
break;
default:
strncpy(p, "TRANSMISSION PROBLEMS", BUFFER_SIZE(buffer, p));
break;
}
strncat(p, "\"", sizeof(buffer));
set_var(&parse->kv, buffer, strlen(buffer)+1, RO);
}
}
}
break;
case GPS_ALM:
break;
case GPS_EPH:
break;
case GPS_UTC:
{
UTC utc;
char buffer[512];
char *p;
p = buffer;
get_mbg_utc(&bufp, &utc);
if (utc.valid)
{
strncpy(p, "gps_utc_correction=\"", sizeof(buffer));
p += strlen(p);
mk_utcinfo(p, utc.t0t.wn, utc.WNlsf, utc.DNt, utc.delta_tls, utc.delta_tlsf, BUFFER_SIZE(buffer, p));
strncat(p, "\"", BUFFER_SIZE(buffer, p));
}
else
{
strncpy(p, "gps_utc_correction=\"<NO UTC DATA>\"", BUFFER_SIZE(buffer, p));
}
set_var(&parse->kv, buffer, strlen(buffer)+1, RO|DEF);
}
break;
case GPS_IONO:
break;
case GPS_ASCII_MSG:
{
ASCII_MSG gps_ascii_msg;
char buffer[128];
get_mbg_ascii_msg(&bufp, &gps_ascii_msg);
if (gps_ascii_msg.valid)
{
char buffer1[128];
mkreadable(buffer1, sizeof(buffer1), gps_ascii_msg.s, strlen(gps_ascii_msg.s), (int)0);
snprintf(buffer, sizeof(buffer), "gps_message=\"%s\"", buffer1);
}
else
strncpy(buffer, "gps_message=<NONE>", sizeof(buffer));
set_var(&parse->kv, buffer, strlen(buffer)+1, RO|DEF);
}
break;
default:
break;
}
}
else
{
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)",
CLK_UNIT(parse->peer),
header.gps_hdr_csum, mbg_csum(parsetime->parse_msg + 1, 6),
header.gps_len,
header.gps_data_csum, mbg_csum(bufp, (unsigned)((header.gps_len < sizeof(parsetime->parse_msg)) ? header.gps_len : 0)));
}
}
return;
}
static void
gps16x_poll(
struct peer *peer
)
{
struct parseunit *parse = (struct parseunit *)peer->procptr->unitptr;
static GPS_MSG_HDR sequence[] =
{
{ GPS_SW_REV, 0, 0, 0 },
{ GPS_STAT, 0, 0, 0 },
{ GPS_UTC, 0, 0, 0 },
{ GPS_ASCII_MSG, 0, 0, 0 },
{ GPS_ANT_INFO, 0, 0, 0 },
{ GPS_CFGH, 0, 0, 0 },
{ GPS_POS_XYZ, 0, 0, 0 },
{ GPS_POS_LLA, 0, 0, 0 },
{ (unsigned short)~0, 0, 0, 0 }
};
int rtc;
unsigned char cmd_buffer[64];
unsigned char *outp = cmd_buffer;
GPS_MSG_HDR *header;
if (((poll_info_t *)parse->parse_type->cl_data)->rate)
{
parse->peer->nextaction = current_time + ((poll_info_t *)parse->parse_type->cl_data)->rate;
}
if (sequence[parse->localstate].gps_cmd == (unsigned short)~0)
parse->localstate = 0;
header = sequence + parse->localstate++;
*outp++ = SOH;
put_mbg_header(&outp, header);
outp = cmd_buffer + 1;
header->gps_hdr_csum = (short)mbg_csum(outp, 6);
put_mbg_header(&outp, header);
#ifdef DEBUG
if (debug > 2)
{
char buffer[128];
mkreadable(buffer, sizeof(buffer), (char *)cmd_buffer, (unsigned)(outp - cmd_buffer), 1);
printf("PARSE receiver #%d: transmitted message #%ld (%d bytes) >%s<\n",
CLK_UNIT(parse->peer),
parse->localstate - 1,
(int)(outp - cmd_buffer),
buffer);
}
#endif
rtc = write(parse->generic->io.fd, cmd_buffer, (unsigned long)(outp - cmd_buffer));
if (rtc < 0)
{
ERR(ERR_BADIO)
msyslog(LOG_ERR, "PARSE receiver #%d: gps16x_poll: failed to send cmd to clock: %m", CLK_UNIT(parse->peer));
}
else
if (rtc != outp - cmd_buffer)
{
ERR(ERR_BADIO)
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));
}
clear_err(parse, ERR_BADIO);
return;
}
static int
gps16x_poll_init(
struct parseunit *parse
)
{
if (((poll_info_t *)parse->parse_type->cl_data)->rate)
{
parse->peer->action = gps16x_poll;
gps16x_poll(parse->peer);
}
return 0;
}
#else
static void
gps16x_message(
struct parseunit *parse,
parsetime_t *parsetime
)
{}
static int
gps16x_poll_init(
struct parseunit *parse
)
{
return 1;
}
#endif
static void
poll_dpoll(
struct parseunit *parse
)
{
int rtc;
const char *ps = ((poll_info_t *)parse->parse_type->cl_data)->string;
int ct = ((poll_info_t *)parse->parse_type->cl_data)->count;
rtc = write(parse->generic->io.fd, ps, (unsigned long)ct);
if (rtc < 0)
{
ERR(ERR_BADIO)
msyslog(LOG_ERR, "PARSE receiver #%d: poll_dpoll: failed to send cmd to clock: %m", CLK_UNIT(parse->peer));
}
else
if (rtc != ct)
{
ERR(ERR_BADIO)
msyslog(LOG_ERR, "PARSE receiver #%d: poll_dpoll: failed to send cmd incomplete (%d of %d bytes sent)", CLK_UNIT(parse->peer), rtc, ct);
}
clear_err(parse, ERR_BADIO);
}
static void
poll_poll(
struct peer *peer
)
{
struct parseunit *parse = (struct parseunit *)peer->procptr->unitptr;
if (parse->parse_type->cl_poll)
parse->parse_type->cl_poll(parse);
if (((poll_info_t *)parse->parse_type->cl_data)->rate)
{
parse->peer->nextaction = current_time + ((poll_info_t *)parse->parse_type->cl_data)->rate;
}
}
static int
poll_init(
struct parseunit *parse
)
{
if (((poll_info_t *)parse->parse_type->cl_data)->rate)
{
parse->peer->action = poll_poll;
poll_poll(parse->peer);
}
return 0;
}
static int
trimbletaip_init(
struct parseunit *parse
)
{
#ifdef HAVE_TERMIOS
struct termios tio;
#endif
#ifdef HAVE_SYSV_TTYS
struct termio tio;
#endif
if (TTY_GETATTR(parse->generic->io.fd, &tio) == -1)
{
msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_init: tcgetattr(fd, &tio): %m", CLK_UNIT(parse->peer));
return 0;
}
else
{
tio.c_cc[VEOL] = TRIMBLETAIP_EOL;
if (TTY_SETATTR(parse->generic->io.fd, &tio) == -1)
{
msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_init: tcsetattr(fd, &tio): %m", CLK_UNIT(parse->peer));
return 0;
}
}
return poll_init(parse);
}
static const char *taipinit[] = {
">FPV00000000<",
">SRM;ID_FLAG=F;CS_FLAG=T;EC_FLAG=F;FR_FLAG=T;CR_FLAG=F<",
">FTM00020001<",
(char *)0
};
static void
trimbletaip_event(
struct parseunit *parse,
int event
)
{
switch (event)
{
case CEVNT_BADREPLY:
case CEVNT_TIMEOUT:
{
const char **iv;
iv = taipinit;
while (*iv)
{
int rtc = write(parse->generic->io.fd, *iv, strlen(*iv));
if (rtc < 0)
{
msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_event: failed to send cmd to clock: %m", CLK_UNIT(parse->peer));
return;
}
else
{
if (rtc != strlen(*iv))
{
msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_event: failed to send cmd incomplete (%d of %d bytes sent)",
CLK_UNIT(parse->peer), rtc, (int)strlen(*iv));
return;
}
}
iv++;
}
NLOG(NLOG_CLOCKINFO)
ERR(ERR_BADIO)
msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_event: RECEIVER INITIALIZED",
CLK_UNIT(parse->peer));
}
break;
default:
break;
}
}
#define PI 3.1415926535898
#define D2R PI/180.0
typedef struct trimble
{
u_long last_msg;
u_long last_reset;
u_char qtracking;
u_long ctrack;
u_long ltrack;
} trimble_t;
union uval {
u_char bd[8];
int iv;
float fv;
double dv;
};
struct txbuf
{
short idx;
u_char *txt;
};
void sendcmd (struct txbuf *buf, int c);
void sendbyte (struct txbuf *buf, int b);
void sendetx (struct txbuf *buf, struct parseunit *parse);
void sendint (struct txbuf *buf, int a);
void sendflt (struct txbuf *buf, double a);
void
sendcmd(
struct txbuf *buf,
int c
)
{
buf->txt[0] = DLE;
buf->txt[1] = (u_char)c;
buf->idx = 2;
}
void sendcmd (struct txbuf *buf, int c);
void sendbyte (struct txbuf *buf, int b);
void sendetx (struct txbuf *buf, struct parseunit *parse);
void sendint (struct txbuf *buf, int a);
void sendflt (struct txbuf *buf, double a);
void
sendbyte(
struct txbuf *buf,
int b
)
{
if (b == DLE)
buf->txt[buf->idx++] = DLE;
buf->txt[buf->idx++] = (u_char)b;
}
void
sendetx(
struct txbuf *buf,
struct parseunit *parse
)
{
buf->txt[buf->idx++] = DLE;
buf->txt[buf->idx++] = ETX;
if (write(parse->generic->io.fd, buf->txt, (unsigned long)buf->idx) != buf->idx)
{
ERR(ERR_BADIO)
msyslog(LOG_ERR, "PARSE receiver #%d: sendetx: failed to send cmd to clock: %m", CLK_UNIT(parse->peer));
}
else
{
#ifdef DEBUG
if (debug > 2)
{
char buffer[256];
mkreadable(buffer, sizeof(buffer), (char *)buf->txt, (unsigned)buf->idx, 1);
printf("PARSE receiver #%d: transmitted message (%d bytes) >%s<\n",
CLK_UNIT(parse->peer),
buf->idx, buffer);
}
#endif
clear_err(parse, ERR_BADIO);
}
}
void
sendint(
struct txbuf *buf,
int a
)
{
sendbyte(buf, (u_char)((a>>8) & 0xff));
sendbyte(buf, (u_char)(a & 0xff));
}
void
sendflt(
struct txbuf *buf,
double a
)
{
int i;
union uval uval;
uval.fv = a;
#ifdef WORDS_BIGENDIAN
for (i=0; i<=3; i++)
#else
for (i=3; i>=0; i--)
#endif
sendbyte(buf, uval.bd[i]);
}
#define TRIM_POS_OPT 0x13
#define TRIM_TIME_OPT 0x03
static int
trimbletsip_setup(
struct parseunit *parse,
const char *reason
)
{
u_char buffer[256];
struct txbuf buf;
trimble_t *t = parse->localdata;
if (t && t->last_reset &&
((t->last_reset + TRIMBLE_RESET_HOLDOFF) > current_time)) {
return 1;
}
if (t)
t->last_reset = current_time;
buf.txt = buffer;
sendcmd(&buf, CMD_CVERSION);
sendetx(&buf, parse);
sendcmd(&buf, CMD_COPERPARAM);
sendbyte(&buf, 4);
sendflt(&buf, 5.0*D2R);
sendflt(&buf, 4.0);
sendflt(&buf, 12.0);
sendflt(&buf, 8.0);
sendetx(&buf, parse);
sendcmd(&buf, CMD_CMODESEL);
sendbyte(&buf, 1);
sendetx(&buf, parse);
sendcmd(&buf, CMD_CMESSAGE);
sendetx(&buf, parse);
sendcmd(&buf, CMD_CSUPER);
sendbyte(&buf, 0x2);
sendetx(&buf, parse);
sendcmd(&buf, CMD_CIOOPTIONS);
sendbyte(&buf, TRIM_POS_OPT);
sendbyte(&buf, 0x00);
sendbyte(&buf, TRIM_TIME_OPT);
sendbyte(&buf, 0x00);
sendetx(&buf, parse);
sendcmd(&buf, CMD_CUTCPARAM);
sendetx(&buf, parse);
NLOG(NLOG_CLOCKINFO)
ERR(ERR_BADIO)
msyslog(LOG_ERR, "PARSE receiver #%d: trimbletsip_setup: RECEIVER RE-INITIALIZED (%s)", CLK_UNIT(parse->peer), reason);
return 0;
}
static void
trimble_check(
struct peer *peer
)
{
struct parseunit *parse = (struct parseunit *)peer->procptr->unitptr;
trimble_t *t = parse->localdata;
u_char buffer[256];
struct txbuf buf;
buf.txt = buffer;
if (t)
{
if (current_time > t->last_msg + TRIMBLETSIP_IDLE_TIME)
(void)trimbletsip_setup(parse, "message timeout");
}
poll_poll(parse->peer);
if (t && t->qtracking)
{
u_long oldsats = t->ltrack & ~t->ctrack;
t->qtracking = 0;
t->ltrack = t->ctrack;
if (oldsats)
{
int i;
for (i = 0; oldsats; i++) {
if (oldsats & (1 << i))
{
sendcmd(&buf, CMD_CSTATTRACK);
sendbyte(&buf, i+1);
sendetx(&buf, parse);
}
oldsats &= ~(1 << i);
}
}
sendcmd(&buf, CMD_CSTATTRACK);
sendbyte(&buf, 0x00);
sendetx(&buf, parse);
}
}
static void
trimbletsip_end(
struct parseunit *parse
)
{ trimble_t *t = parse->localdata;
if (t)
{
free(t);
parse->localdata = (void *)0;
}
parse->peer->nextaction = 0;
parse->peer->action = (void (*) (struct peer *))0;
}
static int
trimbletsip_init(
struct parseunit *parse
)
{
#if defined(VEOL) || defined(VEOL2)
#ifdef HAVE_TERMIOS
struct termios tio;
#endif
#ifdef HAVE_SYSV_TTYS
struct termio tio;
#endif
if (!parse->localdata)
{
trimble_t *t;
t = (trimble_t *)(parse->localdata = emalloc(sizeof(trimble_t)));
if (t)
{
memset((char *)t, 0, sizeof(trimble_t));
t->last_msg = current_time;
}
}
parse->peer->action = trimble_check;
parse->peer->nextaction = current_time;
if (TTY_GETATTR(parse->generic->io.fd, &tio) == -1)
{
msyslog(LOG_ERR, "PARSE receiver #%d: trimbletsip_init: tcgetattr(%d, &tio): %m", CLK_UNIT(parse->peer), parse->generic->io.fd);
return 0;
}
else
{
if ((parse_clockinfo[CLK_TYPE(parse->peer)].cl_lflag & ICANON))
{
#ifdef VEOL
tio.c_cc[VEOL] = ETX;
#endif
#ifdef VEOL2
tio.c_cc[VEOL2] = DLE;
#endif
}
if (TTY_SETATTR(parse->generic->io.fd, &tio) == -1)
{
msyslog(LOG_ERR, "PARSE receiver #%d: trimbletsip_init: tcsetattr(%d, &tio): %m", CLK_UNIT(parse->peer), parse->generic->io.fd);
return 0;
}
}
#endif
return trimbletsip_setup(parse, "initial startup");
}
static void
trimbletsip_event(
struct parseunit *parse,
int event
)
{
switch (event)
{
case CEVNT_BADREPLY:
case CEVNT_TIMEOUT:
(void)trimbletsip_setup(parse, "event BAD_REPLY/TIMEOUT");
break;
default:
break;
}
}
static float
getflt(
u_char *bp
)
{
union uval uval;
#ifdef WORDS_BIGENDIAN
uval.bd[0] = *bp++;
uval.bd[1] = *bp++;
uval.bd[2] = *bp++;
uval.bd[3] = *bp;
#else
uval.bd[3] = *bp++;
uval.bd[2] = *bp++;
uval.bd[1] = *bp++;
uval.bd[0] = *bp;
#endif
return uval.fv;
}
static double
getdbl(
u_char *bp
)
{
union uval uval;
#ifdef WORDS_BIGENDIAN
uval.bd[0] = *bp++;
uval.bd[1] = *bp++;
uval.bd[2] = *bp++;
uval.bd[3] = *bp++;
uval.bd[4] = *bp++;
uval.bd[5] = *bp++;
uval.bd[6] = *bp++;
uval.bd[7] = *bp;
#else
uval.bd[7] = *bp++;
uval.bd[6] = *bp++;
uval.bd[5] = *bp++;
uval.bd[4] = *bp++;
uval.bd[3] = *bp++;
uval.bd[2] = *bp++;
uval.bd[1] = *bp++;
uval.bd[0] = *bp;
#endif
return uval.dv;
}
static int
getshort(
unsigned char *p
)
{
return get_msb_short(&p);
}
#define RTOD (180.0 / 3.1415926535898)
#define mb(_X_) (buffer[2+(_X_)])
static void
trimbletsip_message(
struct parseunit *parse,
parsetime_t *parsetime
)
{
unsigned char *buffer = parsetime->parse_msg;
unsigned int size = parsetime->parse_msglen;
if ((size < 4) ||
(buffer[0] != DLE) ||
(buffer[size-1] != ETX) ||
(buffer[size-2] != DLE))
{
#ifdef DEBUG
if (debug > 2) {
int i;
printf("TRIMBLE BAD packet, size %d:\n ", size);
for (i = 0; i < size; i++) {
printf ("%2.2x, ", buffer[i]&0xff);
if (i%16 == 15) printf("\n\t");
}
printf("\n");
}
#endif
return;
}
else
{
int var_flag;
trimble_t *tr = parse->localdata;
unsigned int cmd = buffer[1];
char pbuffer[200];
char *t = pbuffer;
cmd_info_t *s;
#ifdef DEBUG
if (debug > 3) {
int i;
printf("TRIMBLE packet 0x%02x, size %d:\n ", cmd, size);
for (i = 0; i < size; i++) {
printf ("%2.2x, ", buffer[i]&0xff);
if (i%16 == 15) printf("\n\t");
}
printf("\n");
}
#endif
if (tr)
tr->last_msg = current_time;
s = trimble_convert(cmd, trimble_rcmds);
if (s)
{
snprintf(t, BUFFER_SIZE(pbuffer, t), "%s=\"", s->varname);
}
else
{
DPRINTF(1, ("TRIMBLE UNKNOWN COMMAND 0x%02x\n", cmd));
return;
}
var_flag = s->varmode;
t += strlen(t);
switch(cmd)
{
case CMD_RCURTIME:
snprintf(t, BUFFER_SIZE(pbuffer, t), "%f, %d, %f",
getflt((unsigned char *)&mb(0)), getshort((unsigned char *)&mb(4)),
getflt((unsigned char *)&mb(6)));
break;
case CMD_RBEST4:
strncpy(t, "mode: ", BUFFER_SIZE(pbuffer, t));
t += strlen(t);
switch (mb(0) & 0xF)
{
default:
snprintf(t, BUFFER_SIZE(pbuffer, t), "0x%x", mb(0) & 0x7);
break;
case 1:
strncpy(t, "0D", BUFFER_SIZE(pbuffer, t));
break;
case 3:
strncpy(t, "2D", BUFFER_SIZE(pbuffer, t));
break;
case 4:
strncpy(t, "3D", BUFFER_SIZE(pbuffer, t));
break;
}
t += strlen(t);
if (mb(0) & 0x10)
strncpy(t, "-MANUAL, ", BUFFER_SIZE(pbuffer, t));
else
strncpy(t, "-AUTO, ", BUFFER_SIZE(pbuffer, t));
t += strlen(t);
snprintf(t, BUFFER_SIZE(pbuffer, t), "satellites %02d %02d %02d %02d, PDOP %.2f, HDOP %.2f, VDOP %.2f, TDOP %.2f",
mb(1), mb(2), mb(3), mb(4),
getflt((unsigned char *)&mb(5)),
getflt((unsigned char *)&mb(9)),
getflt((unsigned char *)&mb(13)),
getflt((unsigned char *)&mb(17)));
break;
case CMD_RVERSION:
snprintf(t, BUFFER_SIZE(pbuffer, t), "%d.%d (%d/%d/%d)",
mb(0)&0xff, mb(1)&0xff, 1900+(mb(4)&0xff), mb(2)&0xff, mb(3)&0xff);
break;
case CMD_RRECVHEALTH:
{
static const char *msgs[] =
{
"Battery backup failed",
"Signal processor error",
"Alignment error, channel or chip 1",
"Alignment error, channel or chip 2",
"Antenna feed line fault",
"Excessive ref freq. error",
"<BIT 6>",
"<BIT 7>"
};
int i, bits;
switch (mb(0) & 0xFF)
{
default:
snprintf(t, BUFFER_SIZE(pbuffer, t), "illegal value 0x%02x", mb(0) & 0xFF);
break;
case 0x00:
strncpy(t, "doing position fixes", BUFFER_SIZE(pbuffer, t));
break;
case 0x01:
strncpy(t, "no GPS time yet", BUFFER_SIZE(pbuffer, t));
break;
case 0x03:
strncpy(t, "PDOP too high", BUFFER_SIZE(pbuffer, t));
break;
case 0x08:
strncpy(t, "no usable satellites", BUFFER_SIZE(pbuffer, t));
break;
case 0x09:
strncpy(t, "only ONE usable satellite", BUFFER_SIZE(pbuffer, t));
break;
case 0x0A:
strncpy(t, "only TWO usable satellites", BUFFER_SIZE(pbuffer, t));
break;
case 0x0B:
strncpy(t, "only THREE usable satellites", BUFFER_SIZE(pbuffer, t));
break;
case 0x0C:
strncpy(t, "the chosen satellite is unusable", BUFFER_SIZE(pbuffer, t));
break;
}
t += strlen(t);
bits = mb(1) & 0xFF;
for (i = 0; i < 8; i++)
if (bits & (0x1<<i))
{
snprintf(t, BUFFER_SIZE(pbuffer, t), ", %s", msgs[i]);
t += strlen(t);
}
}
break;
case CMD_RMESSAGE:
mkreadable(t, (int)BUFFER_SIZE(pbuffer, t), (char *)&mb(0), (unsigned)(size - 2 - (&mb(0) - buffer)), 0);
break;
case CMD_RMACHSTAT:
{
static const char *msgs[] =
{
"Synthesizer Fault",
"Battery Powered Time Clock Fault",
"A-to-D Converter Fault",
"The almanac stored in the receiver is not complete and current",
"<BIT 4>",
"<BIT 5",
"<BIT 6>",
"<BIT 7>"
};
int i, bits;
snprintf(t, BUFFER_SIZE(pbuffer, t), "machine id 0x%02x", mb(0) & 0xFF);
t += strlen(t);
bits = mb(1) & 0xFF;
for (i = 0; i < 8; i++)
if (bits & (0x1<<i))
{
snprintf(t, BUFFER_SIZE(pbuffer, t), ", %s", msgs[i]);
t += strlen(t);
}
snprintf(t, BUFFER_SIZE(pbuffer, t), ", Superpackets %ssupported", (mb(2) & 0xFF) ? "" :"un" );
}
break;
case CMD_ROPERPARAM:
snprintf(t, BUFFER_SIZE(pbuffer, t), "%2x %.1f %.1f %.1f %.1f",
mb(0), getflt((unsigned char *)&mb(1)), getflt((unsigned char *)&mb(5)),
getflt((unsigned char *)&mb(9)), getflt((unsigned char *)&mb(13)));
break;
case CMD_RUTCPARAM:
{
float t0t = getflt((unsigned char *)&mb(14));
short wnt = getshort((unsigned char *)&mb(18));
short dtls = getshort((unsigned char *)&mb(12));
short wnlsf = getshort((unsigned char *)&mb(20));
short dn = getshort((unsigned char *)&mb(22));
short dtlsf = getshort((unsigned char *)&mb(24));
if ((int)t0t != 0)
{
mk_utcinfo(t, wnt, wnlsf, dn, dtls, dtlsf, BUFFER_SIZE(pbuffer, t));
}
else
{
strncpy(t, "<NO UTC DATA>", BUFFER_SIZE(pbuffer, t));
}
}
break;
case CMD_RSAT1BIAS:
snprintf(t, BUFFER_SIZE(pbuffer, t), "%.1fm %.2fm/s at %.1fs",
getflt(&mb(0)), getflt(&mb(4)), getflt(&mb(8)));
break;
case CMD_RIOOPTIONS:
{
snprintf(t, BUFFER_SIZE(pbuffer, t), "%02x %02x %02x %02x",
mb(0), mb(1), mb(2), mb(3));
if (mb(0) != TRIM_POS_OPT ||
mb(2) != TRIM_TIME_OPT)
{
(void)trimbletsip_setup(parse, "bad io options");
}
}
break;
case CMD_RSPOSXYZ:
{
double x = getflt((unsigned char *)&mb(0));
double y = getflt((unsigned char *)&mb(4));
double z = getflt((unsigned char *)&mb(8));
double f = getflt((unsigned char *)&mb(12));
if (f > 0.0)
snprintf(t, BUFFER_SIZE(pbuffer, t), "x= %.1fm, y= %.1fm, z= %.1fm, time_of_fix= %f sec",
x, y, z,
f);
else
return;
}
break;
case CMD_RSLLAPOS:
{
double lat = getflt((unsigned char *)&mb(0));
double lng = getflt((unsigned char *)&mb(4));
double f = getflt((unsigned char *)&mb(12));
if (f > 0.0)
snprintf(t, BUFFER_SIZE(pbuffer, t), "lat %f %c, long %f %c, alt %.2fm",
((lat < 0.0) ? (-lat) : (lat))*RTOD, (lat < 0.0 ? 'S' : 'N'),
((lng < 0.0) ? (-lng) : (lng))*RTOD, (lng < 0.0 ? 'W' : 'E'),
getflt((unsigned char *)&mb(8)));
else
return;
}
break;
case CMD_RDOUBLEXYZ:
{
double x = getdbl((unsigned char *)&mb(0));
double y = getdbl((unsigned char *)&mb(8));
double z = getdbl((unsigned char *)&mb(16));
snprintf(t, BUFFER_SIZE(pbuffer, t), "x= %.1fm, y= %.1fm, z= %.1fm",
x, y, z);
}
break;
case CMD_RDOUBLELLA:
{
double lat = getdbl((unsigned char *)&mb(0));
double lng = getdbl((unsigned char *)&mb(8));
snprintf(t, BUFFER_SIZE(pbuffer, t), "lat %f %c, lon %f %c, alt %.2fm",
((lat < 0.0) ? (-lat) : (lat))*RTOD, (lat < 0.0 ? 'S' : 'N'),
((lng < 0.0) ? (-lng) : (lng))*RTOD, (lng < 0.0 ? 'W' : 'E'),
getdbl((unsigned char *)&mb(16)));
}
break;
case CMD_RALLINVIEW:
{
int i, sats;
strncpy(t, "mode: ", BUFFER_SIZE(pbuffer, t));
t += strlen(t);
switch (mb(0) & 0x7)
{
default:
snprintf(t, BUFFER_SIZE(pbuffer, t), "0x%x", mb(0) & 0x7);
break;
case 3:
strncpy(t, "2D", BUFFER_SIZE(pbuffer, t));
break;
case 4:
strncpy(t, "3D", BUFFER_SIZE(pbuffer, t));
break;
}
t += strlen(t);
if (mb(0) & 0x8)
strncpy(t, "-MANUAL, ", BUFFER_SIZE(pbuffer, t));
else
strncpy(t, "-AUTO, ", BUFFER_SIZE(pbuffer, t));
t += strlen(t);
sats = (mb(0)>>4) & 0xF;
snprintf(t, BUFFER_SIZE(pbuffer, t), "PDOP %.2f, HDOP %.2f, VDOP %.2f, TDOP %.2f, %d satellite%s in view: ",
getflt((unsigned char *)&mb(1)),
getflt((unsigned char *)&mb(5)),
getflt((unsigned char *)&mb(9)),
getflt((unsigned char *)&mb(13)),
sats, (sats == 1) ? "" : "s");
t += strlen(t);
for (i=0; i < sats; i++)
{
snprintf(t, BUFFER_SIZE(pbuffer, t), "%s%02d", i ? ", " : "", mb(17+i));
t += strlen(t);
if (tr)
tr->ctrack |= (1 << (mb(17+i)-1));
}
if (tr)
{
tr->qtracking = 1;
}
}
break;
case CMD_RSTATTRACK:
{
snprintf(t-2, BUFFER_SIZE(pbuffer, t-2), "[%02d]=\"", mb(0));
t += strlen(t);
if (getflt((unsigned char *)&mb(4)) < 0.0)
{
strncpy(t, "<NO MEASUREMENTS>", BUFFER_SIZE(pbuffer, t));
var_flag &= ~DEF;
}
else
{
snprintf(t, BUFFER_SIZE(pbuffer, t), "ch=%d, acq=%s, eph=%d, signal_level= %5.2f, elevation= %5.2f, azimuth= %6.2f",
(mb(1) & 0xFF)>>3,
mb(2) ? ((mb(2) == 1) ? "ACQ" : "SRCH") : "NEVER",
mb(3),
getflt((unsigned char *)&mb(4)),
getflt((unsigned char *)&mb(12)) * RTOD,
getflt((unsigned char *)&mb(16)) * RTOD);
t += strlen(t);
if (mb(20))
{
var_flag &= ~DEF;
strncpy(t, ", OLD", BUFFER_SIZE(pbuffer, t));
}
t += strlen(t);
if (mb(22))
{
if (mb(22) == 1)
strncpy(t, ", BAD PARITY", BUFFER_SIZE(pbuffer, t));
else
if (mb(22) == 2)
strncpy(t, ", BAD EPH HEALTH", BUFFER_SIZE(pbuffer, t));
}
t += strlen(t);
if (mb(23))
strncpy(t, ", collecting data", BUFFER_SIZE(pbuffer, t));
}
}
break;
default:
strncpy(t, "<UNDECODED>", BUFFER_SIZE(pbuffer, t));
break;
}
t += strlen(t);
strncpy(t,"\"", BUFFER_SIZE(pbuffer, t));
set_var(&parse->kv, pbuffer, sizeof(pbuffer), var_flag);
}
}
#if defined(TIOCMSET) && (defined(TIOCM_DTR) || defined(CIOCM_DTR))
static int
rawdcf_init_1(
struct parseunit *parse
)
{
int sl232;
if (ioctl(parse->generic->io.fd, TIOCMGET, (caddr_t)&sl232) == -1)
{
msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_1: WARNING: ioctl(fd, TIOCMGET, [C|T]IOCM_DTR): %m", CLK_UNIT(parse->peer));
return 0;
}
#ifdef TIOCM_DTR
sl232 = (sl232 & ~TIOCM_RTS) | TIOCM_DTR;
#else
sl232 = (sl232 & ~CIOCM_RTS) | CIOCM_DTR;
#endif
if (ioctl(parse->generic->io.fd, TIOCMSET, (caddr_t)&sl232) == -1)
{
msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_1: WARNING: ioctl(fd, TIOCMSET, [C|T]IOCM_DTR): %m", CLK_UNIT(parse->peer));
}
return 0;
}
#else
static int
rawdcfdtr_init_1(
struct parseunit *parse
)
{
msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_1: WARNING: OS interface incapable of setting DTR to power DCF modules", CLK_UNIT(parse->peer));
return 0;
}
#endif
#if defined(TIOCMSET) && (defined(TIOCM_RTS) || defined(CIOCM_RTS))
static int
rawdcf_init_2(
struct parseunit *parse
)
{
int sl232;
if (ioctl(parse->generic->io.fd, TIOCMGET, (caddr_t)&sl232) == -1)
{
msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_2: WARNING: ioctl(fd, TIOCMGET, [C|T]IOCM_RTS): %m", CLK_UNIT(parse->peer));
return 0;
}
#ifdef TIOCM_RTS
sl232 = (sl232 & ~TIOCM_DTR) | TIOCM_RTS;
#else
sl232 = (sl232 & ~CIOCM_DTR) | CIOCM_RTS;
#endif
if (ioctl(parse->generic->io.fd, TIOCMSET, (caddr_t)&sl232) == -1)
{
msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_2: WARNING: ioctl(fd, TIOCMSET, [C|T]IOCM_RTS): %m", CLK_UNIT(parse->peer));
}
return 0;
}
#else
static int
rawdcf_init_2(
struct parseunit *parse
)
{
msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_2: WARNING: OS interface incapable of setting RTS to power DCF modules", CLK_UNIT(parse->peer));
return 0;
}
#endif
#else
int refclock_parse_bs;
#endif