summaryrefslogtreecommitdiffstats
path: root/contrib/ntp/ntpd
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/ntp/ntpd')
-rw-r--r--contrib/ntp/ntpd/Makefile.am2
-rw-r--r--contrib/ntp/ntpd/Makefile.in22
-rw-r--r--contrib/ntp/ntpd/ntp_control.c2
-rw-r--r--contrib/ntp/ntpd/ntp_loopfilter.c2
-rw-r--r--contrib/ntp/ntpd/refclock_conf.c16
-rw-r--r--contrib/ntp/ntpd/refclock_jjy.c2
-rw-r--r--contrib/ntp/ntpd/refclock_local.c1
-rw-r--r--contrib/ntp/ntpd/refclock_neoclock4x.c864
-rw-r--r--contrib/ntp/ntpd/refclock_ripencc.c4872
-rw-r--r--contrib/ntp/ntpd/refclock_zyfer.c2
10 files changed, 5774 insertions, 11 deletions
diff --git a/contrib/ntp/ntpd/Makefile.am b/contrib/ntp/ntpd/Makefile.am
index 0c1d4c1..94dfd09 100644
--- a/contrib/ntp/ntpd/Makefile.am
+++ b/contrib/ntp/ntpd/Makefile.am
@@ -37,7 +37,7 @@ ntpd_SOURCES = cmd_args.c jupiter.h map_vme.c ntp_config.c ntp_control.c \
refclock_pcf.c refclock_pst.c refclock_ptbacts.c refclock_shm.c \
refclock_tpro.c refclock_trak.c refclock_true.c refclock_tt560.c \
refclock_ulink.c refclock_usno.c refclock_wwv.c refclock_wwvb.c \
- refclock_zyfer.c
+ refclock_zyfer.c refclock_ripencc.c refclock_neoclock4x.c
$(PROGRAMS): $(LDADD)
diff --git a/contrib/ntp/ntpd/Makefile.in b/contrib/ntp/ntpd/Makefile.in
index 5eb698f..2622b3b 100644
--- a/contrib/ntp/ntpd/Makefile.in
+++ b/contrib/ntp/ntpd/Makefile.in
@@ -146,7 +146,7 @@ ntpd_SOURCES = cmd_args.c jupiter.h map_vme.c ntp_config.c ntp_control.c \
refclock_pcf.c refclock_pst.c refclock_ptbacts.c refclock_shm.c \
refclock_tpro.c refclock_trak.c refclock_true.c refclock_tt560.c \
refclock_ulink.c refclock_usno.c refclock_wwv.c refclock_wwvb.c \
- refclock_zyfer.c
+ refclock_zyfer.c refclock_ripencc.c refclock_neoclock4x.c
subdir = ntpd
mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
@@ -190,7 +190,8 @@ am_ntpd_OBJECTS = cmd_args$U.$(OBJEXT) map_vme$U.$(OBJEXT) \
refclock_trak$U.$(OBJEXT) refclock_true$U.$(OBJEXT) \
refclock_tt560$U.$(OBJEXT) refclock_ulink$U.$(OBJEXT) \
refclock_usno$U.$(OBJEXT) refclock_wwv$U.$(OBJEXT) \
- refclock_wwvb$U.$(OBJEXT) refclock_zyfer$U.$(OBJEXT)
+ refclock_wwvb$U.$(OBJEXT) refclock_zyfer$U.$(OBJEXT) \
+ refclock_ripencc$U.$(OBJEXT) refclock_neoclock4x$U.$(OBJEXT)
ntpd_OBJECTS = $(am_ntpd_OBJECTS)
ntpd_DEPENDENCIES = version.o ../libntp/libntp.a
ntpd_LDFLAGS =
@@ -238,6 +239,7 @@ depcomp = $(SHELL) $(top_srcdir)/depcomp
@AMDEP_TRUE@ $(DEPDIR)/refclock_local$U.Po \
@AMDEP_TRUE@ $(DEPDIR)/refclock_msfees$U.Po \
@AMDEP_TRUE@ $(DEPDIR)/refclock_mx4200$U.Po \
+@AMDEP_TRUE@ $(DEPDIR)/refclock_neoclock4x$U.Po \
@AMDEP_TRUE@ $(DEPDIR)/refclock_nmea$U.Po \
@AMDEP_TRUE@ $(DEPDIR)/refclock_oncore$U.Po \
@AMDEP_TRUE@ $(DEPDIR)/refclock_palisade$U.Po \
@@ -245,6 +247,7 @@ depcomp = $(SHELL) $(top_srcdir)/depcomp
@AMDEP_TRUE@ $(DEPDIR)/refclock_pcf$U.Po \
@AMDEP_TRUE@ $(DEPDIR)/refclock_pst$U.Po \
@AMDEP_TRUE@ $(DEPDIR)/refclock_ptbacts$U.Po \
+@AMDEP_TRUE@ $(DEPDIR)/refclock_ripencc$U.Po \
@AMDEP_TRUE@ $(DEPDIR)/refclock_shm$U.Po \
@AMDEP_TRUE@ $(DEPDIR)/refclock_tpro$U.Po \
@AMDEP_TRUE@ $(DEPDIR)/refclock_trak$U.Po \
@@ -363,6 +366,7 @@ mostlyclean-kr:
@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/refclock_local$U.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/refclock_msfees$U.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/refclock_mx4200$U.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/refclock_neoclock4x$U.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/refclock_nmea$U.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/refclock_oncore$U.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/refclock_palisade$U.Po@am__quote@
@@ -370,6 +374,7 @@ mostlyclean-kr:
@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/refclock_pcf$U.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/refclock_pst$U.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/refclock_ptbacts$U.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/refclock_ripencc$U.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/refclock_shm$U.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/refclock_tpro$U.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/refclock_trak$U.Po@am__quote@
@@ -482,6 +487,8 @@ refclock_msfees_.c: refclock_msfees.c $(ANSI2KNR)
$(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_msfees.c; then echo $(srcdir)/refclock_msfees.c; else echo refclock_msfees.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > refclock_msfees_.c || rm -f refclock_msfees_.c
refclock_mx4200_.c: refclock_mx4200.c $(ANSI2KNR)
$(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_mx4200.c; then echo $(srcdir)/refclock_mx4200.c; else echo refclock_mx4200.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > refclock_mx4200_.c || rm -f refclock_mx4200_.c
+refclock_neoclock4x_.c: refclock_neoclock4x.c $(ANSI2KNR)
+ $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_neoclock4x.c; then echo $(srcdir)/refclock_neoclock4x.c; else echo refclock_neoclock4x.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > refclock_neoclock4x_.c || rm -f refclock_neoclock4x_.c
refclock_nmea_.c: refclock_nmea.c $(ANSI2KNR)
$(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_nmea.c; then echo $(srcdir)/refclock_nmea.c; else echo refclock_nmea.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > refclock_nmea_.c || rm -f refclock_nmea_.c
refclock_oncore_.c: refclock_oncore.c $(ANSI2KNR)
@@ -496,6 +503,8 @@ refclock_pst_.c: refclock_pst.c $(ANSI2KNR)
$(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_pst.c; then echo $(srcdir)/refclock_pst.c; else echo refclock_pst.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > refclock_pst_.c || rm -f refclock_pst_.c
refclock_ptbacts_.c: refclock_ptbacts.c $(ANSI2KNR)
$(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_ptbacts.c; then echo $(srcdir)/refclock_ptbacts.c; else echo refclock_ptbacts.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > refclock_ptbacts_.c || rm -f refclock_ptbacts_.c
+refclock_ripencc_.c: refclock_ripencc.c $(ANSI2KNR)
+ $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_ripencc.c; then echo $(srcdir)/refclock_ripencc.c; else echo refclock_ripencc.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > refclock_ripencc_.c || rm -f refclock_ripencc_.c
refclock_shm_.c: refclock_shm.c $(ANSI2KNR)
$(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_shm.c; then echo $(srcdir)/refclock_shm.c; else echo refclock_shm.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > refclock_shm_.c || rm -f refclock_shm_.c
refclock_tpro_.c: refclock_tpro.c $(ANSI2KNR)
@@ -534,10 +543,11 @@ refclock_hpgps_.$(OBJEXT) refclock_irig_.$(OBJEXT) \
refclock_jjy_.$(OBJEXT) refclock_jupiter_.$(OBJEXT) \
refclock_leitch_.$(OBJEXT) refclock_local_.$(OBJEXT) \
refclock_msfees_.$(OBJEXT) refclock_mx4200_.$(OBJEXT) \
-refclock_nmea_.$(OBJEXT) refclock_oncore_.$(OBJEXT) \
-refclock_palisade_.$(OBJEXT) refclock_parse_.$(OBJEXT) \
-refclock_pcf_.$(OBJEXT) refclock_pst_.$(OBJEXT) \
-refclock_ptbacts_.$(OBJEXT) refclock_shm_.$(OBJEXT) \
+refclock_neoclock4x_.$(OBJEXT) refclock_nmea_.$(OBJEXT) \
+refclock_oncore_.$(OBJEXT) refclock_palisade_.$(OBJEXT) \
+refclock_parse_.$(OBJEXT) refclock_pcf_.$(OBJEXT) \
+refclock_pst_.$(OBJEXT) refclock_ptbacts_.$(OBJEXT) \
+refclock_ripencc_.$(OBJEXT) refclock_shm_.$(OBJEXT) \
refclock_tpro_.$(OBJEXT) refclock_trak_.$(OBJEXT) \
refclock_true_.$(OBJEXT) refclock_tt560_.$(OBJEXT) \
refclock_ulink_.$(OBJEXT) refclock_usno_.$(OBJEXT) \
diff --git a/contrib/ntp/ntpd/ntp_control.c b/contrib/ntp/ntpd/ntp_control.c
index 11686be..d7109ca 100644
--- a/contrib/ntp/ntpd/ntp_control.c
+++ b/contrib/ntp/ntpd/ntp_control.c
@@ -398,6 +398,8 @@ static u_char clocktypes[] = {
CTL_SST_TS_LF, /* REFCLK_JJY (40) */
CTL_SST_TS_UHF, /* REFCLK_TT560 (41) */
CTL_SST_TS_UHF, /* REFCLK_ZYFER (42) */
+ CTL_SST_TS_UHF, /* REFCLK_RIPENCC (43) */
+ CTL_SST_TS_UHF, /* REFCLK_NEOCLOCK4X (44) */
};
diff --git a/contrib/ntp/ntpd/ntp_loopfilter.c b/contrib/ntp/ntpd/ntp_loopfilter.c
index 21085aa..1d24897 100644
--- a/contrib/ntp/ntpd/ntp_loopfilter.c
+++ b/contrib/ntp/ntpd/ntp_loopfilter.c
@@ -292,7 +292,7 @@ local_clock(
step_systime(fp_offset);
NLOG(NLOG_SYNCEVENT|NLOG_SYSEVENT)
msyslog(LOG_NOTICE, "time set %.6f s", fp_offset);
- rstclock(S_FREQ, peer->epoch, fp_offset);
+ rstclock(S_FREQ, peer->epoch, 0);
return (1);
}
diff --git a/contrib/ntp/ntpd/refclock_conf.c b/contrib/ntp/ntpd/refclock_conf.c
index 478019f..04166d9 100644
--- a/contrib/ntp/ntpd/refclock_conf.c
+++ b/contrib/ntp/ntpd/refclock_conf.c
@@ -258,6 +258,18 @@ extern struct refclock refclock_zyfer;
#define refclock_zyfer refclock_none
#endif
+#ifdef CLOCK_RIPENCC
+extern struct refclock refclock_ripencc;
+#else
+#define refclock_ripencc refclock_none
+#endif
+
+#ifdef CLOCK_NEOCLOCK4X
+extern struct refclock refclock_neoclock4x;
+#else
+#define refclock_neoclock4x refclock_none
+#endif
+
/*
* Order is clock_start(), clock_shutdown(), clock_poll(),
* clock_control(), clock_init(), clock_buginfo, clock_flags;
@@ -307,7 +319,9 @@ struct refclock *refclock_conf[] = {
&refclock_hopfpci, /* 39 REFCLK_HOPF_PCI */
&refclock_jjy, /* 40 REFCLK_JJY */
&refclock_tt560, /* 41 REFCLK_TT560 */
- &refclock_zyfer /* 42 REFCLK_ZYFER */
+ &refclock_zyfer, /* 42 REFCLK_ZYFER */
+ &refclock_ripencc, /* 43 REFCLK_RIPENCC */
+ &refclock_neoclock4x /* 44 REFCLK_NEOCLOCK4X */
};
u_char num_refclock_conf = sizeof(refclock_conf)/sizeof(struct refclock *);
diff --git a/contrib/ntp/ntpd/refclock_jjy.c b/contrib/ntp/ntpd/refclock_jjy.c
index 18de93a..dba6070 100644
--- a/contrib/ntp/ntpd/refclock_jjy.c
+++ b/contrib/ntp/ntpd/refclock_jjy.c
@@ -701,7 +701,7 @@ jjy_poll_cdex_jst2000 ( int unit, struct peer *peer )
* Send "<ENQ>1J<ETX>" command
*/
- if ( write ( pp->io.fd, "\x051J\x03", 4 ) != 4 ) {
+ if ( write ( pp->io.fd, "\0051J\003", 4 ) != 4 ) {
refclock_report ( peer, CEVNT_FAULT ) ;
}
diff --git a/contrib/ntp/ntpd/refclock_local.c b/contrib/ntp/ntpd/refclock_local.c
index 345a7a2..0a0ecc0 100644
--- a/contrib/ntp/ntpd/refclock_local.c
+++ b/contrib/ntp/ntpd/refclock_local.c
@@ -252,6 +252,7 @@ local_poll(
ext_enable = 0;
}
#endif /* KERNEL_PLL STA_CLK */
+ pp->lastref = pp->lastrec;
refclock_receive(peer);
pp->fudgetime1 = 0;
}
diff --git a/contrib/ntp/ntpd/refclock_neoclock4x.c b/contrib/ntp/ntpd/refclock_neoclock4x.c
new file mode 100644
index 0000000..3b64017
--- /dev/null
+++ b/contrib/ntp/ntpd/refclock_neoclock4x.c
@@ -0,0 +1,864 @@
+/*
+ *
+ * refclock_neoclock4x.c
+ * - NeoClock4X driver for DCF77 or FIA Timecode
+ *
+ * Date: 2002-04-27 1.0
+ *
+ * see http://www.linum.com/redir/jump/id=neoclock4x&action=redir
+ * for details about the NeoClock4X device
+ *
+ * Copyright (C) 2002 by Linum Software GmbH <support@linum.com>
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#if defined(REFCLOCK) && (defined(CLOCK_NEOCLOCK4X))
+
+#include <unistd.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <termios.h>
+#include <sys/ioctl.h>
+#include <ctype.h>
+
+#include "ntpd.h"
+#include "ntp_io.h"
+#include "ntp_control.h"
+#include "ntp_refclock.h"
+#include "ntp_unixtime.h"
+#include "ntp_stdlib.h"
+
+#if defined HAVE_SYS_MODEM_H
+# include <sys/modem.h>
+# define TIOCMSET MCSETA
+# define TIOCMGET MCGETA
+# define TIOCM_RTS MRTS
+#endif
+
+#ifdef HAVE_TERMIOS_H
+# ifdef TERMIOS_NEEDS__SVID3
+# define _SVID3
+# endif
+# include <termios.h>
+# ifdef TERMIOS_NEEDS__SVID3
+# undef _SVID3
+# endif
+#endif
+
+#ifdef HAVE_SYS_IOCTL_H
+# include <sys/ioctl.h>
+#endif
+
+#define NEOCLOCK4X_TIMECODELEN 37
+
+#define NEOCLOCK4X_OFFSET_SERIAL 3
+#define NEOCLOCK4X_OFFSET_RADIOSIGNAL 9
+#define NEOCLOCK4X_OFFSET_DAY 12
+#define NEOCLOCK4X_OFFSET_MONTH 14
+#define NEOCLOCK4X_OFFSET_YEAR 16
+#define NEOCLOCK4X_OFFSET_HOUR 18
+#define NEOCLOCK4X_OFFSET_MINUTE 20
+#define NEOCLOCK4X_OFFSET_SECOND 22
+#define NEOCLOCK4X_OFFSET_HSEC 24
+#define NEOCLOCK4X_OFFSET_DOW 26
+#define NEOCLOCK4X_OFFSET_TIMESOURCE 28
+#define NEOCLOCK4X_OFFSET_DSTSTATUS 29
+#define NEOCLOCK4X_OFFSET_QUARZSTATUS 30
+#define NEOCLOCK4X_OFFSET_ANTENNA1 31
+#define NEOCLOCK4X_OFFSET_ANTENNA2 33
+#define NEOCLOCK4X_OFFSET_CRC 35
+
+struct neoclock4x_unit {
+ l_fp laststamp; /* last receive timestamp */
+ short unit; /* NTP refclock unit number */
+ u_long polled; /* flag to detect noreplies */
+ char leap_status; /* leap second flag */
+ int recvnow;
+
+ char firmware[80];
+ char serial[7];
+ char radiosignal[4];
+ char timesource;
+ char dststatus;
+ char quarzstatus;
+ int antenna1;
+ int antenna2;
+ int utc_year;
+ int utc_month;
+ int utc_day;
+ int utc_hour;
+ int utc_minute;
+ int utc_second;
+ int utc_msec;
+};
+
+static int neoclock4x_start P((int, struct peer *));
+static void neoclock4x_shutdown P((int, struct peer *));
+static void neoclock4x_receive P((struct recvbuf *));
+static void neoclock4x_poll P((int, struct peer *));
+static void neoclock4x_control P((int, struct refclockstat *, struct refclockstat *, struct peer *));
+
+static int neol_atoi_len P((const char str[], int *, int));
+static int neol_hexatoi_len P((const char str[], int *, int));
+static void neol_jdn_to_ymd P((unsigned long, int *, int *, int *));
+static void neol_localtime P((unsigned long, int* , int*, int*, int*, int*, int*));
+static unsigned long neol_mktime P((int, int, int, int, int, int));
+static void neol_mdelay P((int));
+static int neol_query_firmware P((int, int, char *, int));
+
+struct refclock refclock_neoclock4x = {
+ neoclock4x_start, /* start up driver */
+ neoclock4x_shutdown, /* shut down driver */
+ neoclock4x_poll, /* transmit poll message */
+ neoclock4x_control,
+ noentry, /* initialize driver (not used) */
+ noentry, /* not used */
+ NOFLAGS /* not used */
+};
+
+static int
+neoclock4x_start(int unit,
+ struct peer *peer)
+{
+ struct neoclock4x_unit *up;
+ struct refclockproc *pp;
+ int fd;
+ char dev[20];
+ int sl232;
+ struct termios termsettings;
+ int tries;
+
+ (void) sprintf(dev, "/dev/neoclock4x-%d", unit);
+
+ /* LDISC_STD, LDISC_RAW
+ * Open serial port. Use CLK line discipline, if available.
+ */
+ fd = refclock_open(dev, B2400, LDISC_CLK);
+ if(fd <= 0)
+ {
+ return (0);
+ }
+
+#if defined(TIOCMSET) && (defined(TIOCM_RTS) || defined(CIOCM_RTS))
+ /* turn on RTS, and DTR for power supply */
+ /* NeoClock4x is powered from serial line */
+ if(ioctl(fd, TIOCMGET, (caddr_t)&sl232) == -1)
+ {
+ msyslog(LOG_CRIT, "NeoClock4X(%d): can't query RTS/DTR state: %m", unit);
+ }
+#ifdef TIOCM_RTS
+ sl232 = sl232 | TIOCM_DTR | TIOCM_RTS; /* turn on RTS, and DTR for power supply */
+#else
+ sl232 = sl232 | CIOCM_DTR | CIOCM_RTS; /* turn on RTS, and DTR for power supply */
+#endif
+ if(ioctl(fd, TIOCMSET, (caddr_t)&sl232) == -1)
+ {
+ msyslog(LOG_CRIT, "NeoClock4X(%d): can't set RTS/DTR to power neoclock4x: %m", unit);
+ }
+
+ if(ioctl(fd, TCGETS, (caddr_t)&termsettings) == -1)
+ {
+ msyslog(LOG_CRIT, "NeoClock4X(%d): can't query serial port settings: %m", unit);
+ }
+
+ /* 2400 Baud mit 8N2 */
+ termsettings.c_cflag &= ~PARENB;
+ termsettings.c_cflag |= CSTOPB;
+ termsettings.c_cflag &= ~CSIZE;
+ termsettings.c_cflag |= CS8;
+
+ if(ioctl(fd, TCSETS, &termsettings) == -1)
+ {
+ msyslog(LOG_CRIT, "NeoClock4X(%d): can't set serial port to 2400 8N2: %m", unit);
+ }
+#else
+ msyslog(LOG_EMERG, "NeoClock4X(%d): OS interface is incapable of setting DTR/RTS to power NeoClock4X",
+ unit);
+#endif
+
+ up = (struct neoclock4x_unit *) emalloc(sizeof(struct neoclock4x_unit));
+ if(!(up))
+ {
+ msyslog(LOG_ERR, "NeoClock4X(%d): can't allocate memory for: %m",unit);
+ (void) close(fd);
+ return (0);
+ }
+
+ memset((char *)up, 0, sizeof(struct neoclock4x_unit));
+ pp = peer->procptr;
+ pp->clockdesc = "NeoClock4X";
+ pp->unitptr = (caddr_t)up;
+ pp->io.clock_recv = neoclock4x_receive;
+ pp->io.srcclock = (caddr_t)peer;
+ pp->io.datalen = 0;
+ pp->io.fd = fd;
+ /* no time is given by user! use 169.583333 ms to compensate the serial line delay
+ * formula is:
+ * 2400 Baud / 11 bit = 218.18 charaters per second
+ * (NeoClock4X timecode len)
+ */
+ pp->fudgetime1 = (NEOCLOCK4X_TIMECODELEN * 11) / 2400.0;
+
+ if (!io_addclock(&pp->io))
+ {
+ msyslog(LOG_ERR, "NeoClock4X(%d): error add peer to ntpd: %m",unit);
+ (void) close(fd);
+ free(up);
+ return (0);
+ }
+
+ /*
+ * Initialize miscellaneous variables
+ */
+ peer->precision = -10;
+ peer->burst = NSTAGE;
+ memcpy((char *)&pp->refid, "neol", 4);
+
+ up->leap_status = 0;
+ up->unit = unit;
+ strcpy(up->firmware, "?");
+ strcpy(up->serial, "?");
+ strcpy(up->radiosignal, "?");
+ up->timesource = '?';
+ up->dststatus = '?';
+ up->quarzstatus = '?';
+ up->antenna1 = -1;
+ up->antenna2 = -1;
+ up->utc_year = 0;
+ up->utc_month = 0;
+ up->utc_day = 0;
+ up->utc_hour = 0;
+ up->utc_minute = 0;
+ up->utc_second = 0;
+ up->utc_msec = 0;
+
+ for(tries=0; tries < 5; tries++)
+ {
+ /*
+ * Wait 3 second for receiver to power up
+ */
+ NLOG(NLOG_CLOCKINFO)
+ msyslog(LOG_INFO, "NeoClock4X(%d): try query NeoClock4X firmware version (%d/5)", unit, tries);
+ sleep(3);
+ if(neol_query_firmware(pp->io.fd, up->unit, up->firmware, sizeof(up->firmware)))
+ {
+ break;
+ }
+ }
+
+ NLOG(NLOG_CLOCKINFO)
+ msyslog(LOG_INFO, "NeoClock4X(%d): receiver setup successful done", unit);
+
+ return (1);
+}
+
+static void
+neoclock4x_shutdown(int unit,
+ struct peer *peer)
+{
+ struct neoclock4x_unit *up;
+ struct refclockproc *pp;
+ int sl232;
+
+ pp = peer->procptr;
+ up = (struct neoclock4x_unit *)pp->unitptr;
+
+#if defined(TIOCMSET) && (defined(TIOCM_RTS) || defined(CIOCM_RTS))
+ /* turn on RTS, and DTR for power supply */
+ /* NeoClock4x is powered from serial line */
+ if(ioctl(pp->io.fd, TIOCMGET, (caddr_t)&sl232) == -1)
+ {
+ msyslog(LOG_CRIT, "NeoClock4X(%d): can't query RTS/DTR state: %m", unit);
+ }
+#ifdef TIOCM_RTS
+ sl232 &= ~(TIOCM_DTR | TIOCM_RTS); /* turn on RTS, and DTR for power supply */
+#else
+ sl232 &= ~(CIOCM_DTR | CIOCM_RTS); /* turn on RTS, and DTR for power supply */
+#endif
+ if(ioctl(pp->io.fd, TIOCMSET, (caddr_t)&sl232) == -1)
+ {
+ msyslog(LOG_CRIT, "NeoClock4X(%d): can't set RTS/DTR to power neoclock4x: %m", unit);
+ }
+#endif
+ msyslog(LOG_ERR, "NeoClock4X(%d): shutdown", unit);
+
+ io_closeclock(&pp->io);
+ free(up);
+ NLOG(NLOG_CLOCKINFO)
+ msyslog(LOG_INFO, "NeoClock4X(%d): receiver shutdown done", unit);
+}
+
+static void
+neoclock4x_receive(struct recvbuf *rbufp)
+{
+ struct neoclock4x_unit *up;
+ struct refclockproc *pp;
+ struct peer *peer;
+ unsigned long calc_utc;
+ int day;
+ int month; /* ddd conversion */
+ int c;
+ unsigned char calc_chksum;
+ int recv_chksum;
+
+ peer = (struct peer *)rbufp->recv_srcclock;
+ pp = peer->procptr;
+ up = (struct neoclock4x_unit *)pp->unitptr;
+
+ /* wait till poll interval is reached */
+ if(0 == up->recvnow)
+ return;
+
+ /* reset poll interval flag */
+ up->recvnow = 0;
+
+ /* read last received timecode */
+ pp->lencode = refclock_gtlin(rbufp, pp->a_lastcode, BMAX, &pp->lastrec);
+
+ if(NEOCLOCK4X_TIMECODELEN != pp->lencode)
+ {
+ NLOG(NLOG_CLOCKEVENT)
+ msyslog(LOG_WARNING, "NeoClock4X(%d): received data has invalid length, expected %d bytes, received %d bytes: %s",
+ up->unit, NEOCLOCK4X_TIMECODELEN, pp->lencode, pp->a_lastcode);
+ refclock_report(peer, CEVNT_BADREPLY);
+ return;
+ }
+
+ neol_hexatoi_len(&pp->a_lastcode[NEOCLOCK4X_OFFSET_CRC], &recv_chksum, 2);
+
+ /* calculate checksum */
+ calc_chksum = 0;
+ for(c=0; c < NEOCLOCK4X_OFFSET_CRC; c++)
+ {
+ calc_chksum += pp->a_lastcode[c];
+ }
+ if(recv_chksum != calc_chksum)
+ {
+ NLOG(NLOG_CLOCKEVENT)
+ msyslog(LOG_WARNING, "NeoClock4X(%d): received data has invalid chksum: %s",
+ up->unit, pp->a_lastcode);
+ refclock_report(peer, CEVNT_BADREPLY);
+ return;
+ }
+
+ /* Allow synchronization even is quartz clock is
+ * never initialized.
+ * WARNING: This is dangerous!
+ */
+ up->quarzstatus = pp->a_lastcode[NEOCLOCK4X_OFFSET_QUARZSTATUS];
+ if(0==(pp->sloppyclockflag & CLK_FLAG2))
+ {
+ if('I' != up->quarzstatus)
+ {
+ NLOG(NLOG_CLOCKEVENT)
+ msyslog(LOG_NOTICE, "NeoClock4X(%d): quartz clock is not initialized: %s",
+ up->unit, pp->a_lastcode);
+ pp->leap = LEAP_NOTINSYNC;
+ refclock_report(peer, CEVNT_BADDATE);
+ return;
+ }
+ }
+ if('I' != up->quarzstatus)
+ {
+ NLOG(NLOG_CLOCKEVENT)
+ msyslog(LOG_NOTICE, "NeoClock4X(%d): using uninitialized quartz clock for time synchronization: %s",
+ up->unit, pp->a_lastcode);
+ }
+
+ /*
+ * If NeoClock4X is not synchronized to a radio clock
+ * check if we're allowed to synchronize with the quartz
+ * clock.
+ */
+ up->timesource = pp->a_lastcode[NEOCLOCK4X_OFFSET_TIMESOURCE];
+ if(0==(pp->sloppyclockflag & CLK_FLAG2))
+ {
+ if('A' != up->timesource)
+ {
+ /* not allowed to sync with quartz clock */
+ if(0==(pp->sloppyclockflag & CLK_FLAG1))
+ {
+ refclock_report(peer, CEVNT_BADTIME);
+ pp->leap = LEAP_NOTINSYNC;
+ return;
+ }
+ }
+ }
+
+ /* this should only used when first install is done */
+ if(pp->sloppyclockflag & CLK_FLAG4)
+ {
+ msyslog(LOG_DEBUG, "NeoClock4X(%d): received data: %s",
+ up->unit, pp->a_lastcode);
+ }
+
+ /* 123456789012345678901234567890123456789012345 */
+ /* S/N123456DCF1004021010001202ASX1213CR\r\n */
+
+ neol_atoi_len(&pp->a_lastcode[NEOCLOCK4X_OFFSET_YEAR], &pp->year, 2);
+ neol_atoi_len(&pp->a_lastcode[NEOCLOCK4X_OFFSET_MONTH], &month, 2);
+ neol_atoi_len(&pp->a_lastcode[NEOCLOCK4X_OFFSET_DAY], &day, 2);
+ neol_atoi_len(&pp->a_lastcode[NEOCLOCK4X_OFFSET_HOUR], &pp->hour, 2);
+ neol_atoi_len(&pp->a_lastcode[NEOCLOCK4X_OFFSET_MINUTE], &pp->minute, 2);
+ neol_atoi_len(&pp->a_lastcode[NEOCLOCK4X_OFFSET_SECOND], &pp->second, 2);
+ neol_atoi_len(&pp->a_lastcode[NEOCLOCK4X_OFFSET_HSEC], &pp->msec, 2);
+ pp->msec *= 10; /* convert 1/100s from neoclock to real miliseconds */
+
+ memcpy(up->radiosignal, &pp->a_lastcode[NEOCLOCK4X_OFFSET_RADIOSIGNAL], 3);
+ up->radiosignal[3] = 0;
+ memcpy(up->serial, &pp->a_lastcode[NEOCLOCK4X_OFFSET_SERIAL], 6);
+ up->serial[6] = 0;
+ up->dststatus = pp->a_lastcode[NEOCLOCK4X_OFFSET_DSTSTATUS];
+ neol_hexatoi_len(&pp->a_lastcode[NEOCLOCK4X_OFFSET_ANTENNA1], &up->antenna1, 2);
+ neol_hexatoi_len(&pp->a_lastcode[NEOCLOCK4X_OFFSET_ANTENNA2], &up->antenna2, 2);
+
+ /*
+ Validate received values at least enough to prevent internal
+ array-bounds problems, etc.
+ */
+ if((pp->hour < 0) || (pp->hour > 23) ||
+ (pp->minute < 0) || (pp->minute > 59) ||
+ (pp->second < 0) || (pp->second > 60) /*Allow for leap seconds.*/ ||
+ (day < 1) || (day > 31) ||
+ (month < 1) || (month > 12) ||
+ (pp->year < 0) || (pp->year > 99)) {
+ /* Data out of range. */
+ NLOG(NLOG_CLOCKEVENT)
+ msyslog(LOG_WARNING, "NeoClock4X(%d): date/time out of range: %s",
+ up->unit, pp->a_lastcode);
+ refclock_report(peer, CEVNT_BADDATE);
+ return;
+ }
+
+ /* Year-2000 check! */
+ /* wrap 2-digit date into 4-digit */
+
+ if(pp->year < YEAR_PIVOT) /* < 98 */
+ {
+ pp->year += 100;
+ }
+ pp->year += 1900;
+
+ calc_utc = neol_mktime(pp->year, month, day, pp->hour, pp->minute, pp->second);
+ calc_utc -= 3600;
+ if('S' == up->dststatus)
+ calc_utc -= 3600;
+ neol_localtime(calc_utc, &pp->year, &month, &day, &pp->hour, &pp->minute, &pp->second);
+
+ /*
+ some preparations
+ */
+ pp->day = ymd2yd(pp->year,month,day);
+ pp->leap = 0;
+
+
+ if(pp->sloppyclockflag & CLK_FLAG4)
+ {
+ msyslog(LOG_DEBUG, "NeoClock4X(%d): calculated UTC date/time: %04d-%02d-%02d %02d:%02d:%02d.%03d",
+ up->unit,
+ pp->year, month, day,
+ pp->hour, pp->minute, pp->second, pp->msec);
+ }
+
+ up->utc_year = pp->year;
+ up->utc_month = month;
+ up->utc_day = day;
+ up->utc_hour = pp->hour;
+ up->utc_minute = pp->minute;
+ up->utc_second = pp->second;
+ up->utc_msec = pp->msec;
+
+ if(!refclock_process(pp))
+ {
+ NLOG(NLOG_CLOCKEVENT)
+ msyslog(LOG_WARNING, "NeoClock4X(%d): refclock_process failed!", up->unit);
+ refclock_report(peer, CEVNT_FAULT);
+ return;
+ }
+ refclock_receive(peer);
+
+ record_clock_stats(&peer->srcadr, pp->a_lastcode);
+}
+
+static void
+neoclock4x_poll(int unit,
+ struct peer *peer)
+{
+ struct neoclock4x_unit *up;
+ struct refclockproc *pp;
+
+ pp = peer->procptr;
+ up = (struct neoclock4x_unit *)pp->unitptr;
+
+ pp->polls++;
+ up->recvnow = 1;
+}
+
+static void
+neoclock4x_control(int unit,
+ struct refclockstat *in,
+ struct refclockstat *out,
+ struct peer *peer)
+{
+ struct neoclock4x_unit *up;
+ struct refclockproc *pp;
+
+ if(NULL == peer)
+ {
+ msyslog(LOG_ERR, "NeoClock4X(%d): control: unit invalid/inactive", unit);
+ return;
+ }
+
+ pp = peer->procptr;
+ if(NULL == pp)
+ {
+ msyslog(LOG_ERR, "NeoClock4X(%d): control: unit invalid/inactive", unit);
+ return;
+ }
+
+ up = (struct neoclock4x_unit *)pp->unitptr;
+ if(NULL == up)
+ {
+ msyslog(LOG_ERR, "NeoClock4X(%d): control: unit invalid/inactive", unit);
+ return;
+ }
+
+ if(NULL != in)
+ {
+ /* check to see if a user supplied time offset is given */
+ if(in->haveflags & CLK_HAVETIME1)
+ {
+ pp->fudgetime1 = in->fudgetime1;
+ NLOG(NLOG_CLOCKINFO)
+ msyslog(LOG_NOTICE, "NeoClock4X(%d): using fudgetime1 with %0.5fs from ntp.conf.",
+ unit, pp->fudgetime1);
+ }
+
+ /* notify */
+ if(pp->sloppyclockflag & CLK_FLAG1)
+ {
+ NLOG(NLOG_CLOCKINFO)
+ msyslog(LOG_NOTICE, "NeoClock4X(%d): quartz clock is used to synchronize time if radio clock has no reception.", unit);
+ }
+ else
+ {
+ NLOG(NLOG_CLOCKINFO)
+ msyslog(LOG_NOTICE, "NeoClock4X(%d): time is only adjusted with radio signal reception.", unit);
+ }
+ }
+
+ if(NULL != out)
+ {
+ static char outstatus[800]; /* status output buffer */
+ char *tt;
+ char tmpbuf[80];
+
+ outstatus[0] = '\0';
+ out->kv_list = (struct ctl_var *)0;
+ out->type = REFCLK_NEOCLOCK4X;
+
+ sprintf(tmpbuf, "%04d-%02d-%02d %02d:%02d:%02d.%03d",
+ up->utc_year, up->utc_month, up->utc_day,
+ up->utc_hour, up->utc_minute, up->utc_second,
+ up->utc_msec);
+
+ tt = add_var(&out->kv_list, 512, RO|DEF);
+ tt += sprintf(tt, "calc_utc=\"%s\"", tmpbuf);
+ tt = add_var(&out->kv_list, 512, RO|DEF);
+ tt += sprintf(tt, "radiosignal=\"%s\"", up->radiosignal);
+ tt = add_var(&out->kv_list, 512, RO|DEF);
+ tt += sprintf(tt, "antenna1=\"%d\"", up->antenna1);
+ tt = add_var(&out->kv_list, 512, RO|DEF);
+ tt += sprintf(tt, "antenna2=\"%d\"", up->antenna2);
+ tt = add_var(&out->kv_list, 512, RO|DEF);
+ if('A' == up->timesource)
+ tt += sprintf(tt, "timesource=\"radio\"");
+ else if('C' == up->timesource)
+ tt += sprintf(tt, "timesource=\"quartz\"");
+ else
+ tt += sprintf(tt, "timesource=\"unknown\"");
+ tt = add_var(&out->kv_list, 512, RO|DEF);
+ if('I' == up->quarzstatus)
+ tt += sprintf(tt, "quartzstatus=\"synchronized\"");
+ else if('X' == up->quarzstatus)
+ tt += sprintf(tt, "quartzstatus=\"not synchronized\"");
+ else
+ tt += sprintf(tt, "quartzstatus=\"unknown\"");
+ tt = add_var(&out->kv_list, 512, RO|DEF);
+ if('S' == up->dststatus)
+ tt += sprintf(tt, "dststatus=\"summer\"");
+ else if('W' == up->dststatus)
+ tt += sprintf(tt, "dststatus=\"winter\"");
+ else
+ tt += sprintf(tt, "dststatus=\"unknown\"");
+ tt = add_var(&out->kv_list, 512, RO|DEF);
+ tt += sprintf(tt, "firmware=\"%s\"", up->firmware);
+ tt = add_var(&out->kv_list, 512, RO|DEF);
+ tt += sprintf(tt, "serialnumber=\"%s\"", up->serial);
+ tt = add_var(&out->kv_list, 512, RO|DEF);
+ }
+}
+
+static int neol_hexatoi_len(const char str[],
+ int *result,
+ int maxlen)
+{
+ int hexdigit;
+ int i;
+ int n = 0;
+
+ for(i=0; isxdigit(str[i]) && i < maxlen; i++)
+ {
+ hexdigit = isdigit(str[i]) ? toupper(str[i]) - '0' : toupper(str[i]) - 'A' + 10;
+ n = 16 * n + hexdigit;
+ }
+ *result = n;
+ return (n);
+}
+
+int neol_atoi_len(const char str[],
+ int *result,
+ int maxlen)
+{
+ int digit;
+ int i;
+ int n = 0;
+
+ for(i=0; isdigit(str[i]) && i < maxlen; i++)
+ {
+ digit = str[i] - '0';
+ n = 10 * n + digit;
+ }
+ *result = n;
+ return (n);
+}
+
+/* Converts Gregorian date to seconds since 1970-01-01 00:00:00.
+ * Assumes input in normal date format, i.e. 1980-12-31 23:59:59
+ * => year=1980, mon=12, day=31, hour=23, min=59, sec=59.
+ *
+ * [For the Julian calendar (which was used in Russia before 1917,
+ * Britain & colonies before 1752, anywhere else before 1582,
+ * and is still in use by some communities) leave out the
+ * -year/100+year/400 terms, and add 10.]
+ *
+ * This algorithm was first published by Gauss (I think).
+ *
+ * WARNING: this function will overflow on 2106-02-07 06:28:16 on
+ * machines were long is 32-bit! (However, as time_t is signed, we
+ * will already get problems at other places on 2038-01-19 03:14:08)
+ */
+static unsigned long neol_mktime(int year,
+ int mon,
+ int day,
+ int hour,
+ int min,
+ int sec)
+{
+ if (0 >= (int) (mon -= 2)) { /* 1..12 . 11,12,1..10 */
+ mon += 12; /* Puts Feb last since it has leap day */
+ year -= 1;
+ }
+ return (((
+ (unsigned long)(year/4 - year/100 + year/400 + 367*mon/12 + day) +
+ year*365 - 719499
+ )*24 + hour /* now have hours */
+ )*60 + min /* now have minutes */
+ )*60 + sec; /* finally seconds */
+}
+
+static void neol_localtime(unsigned long utc,
+ int* year,
+ int* month,
+ int* day,
+ int* hour,
+ int* minute,
+ int* second)
+{
+ ldiv_t d;
+
+ /* Sekunden */
+ d = ldiv(utc, 60);
+ *second = d.rem;
+
+ /* Minute */
+ d = ldiv(d.quot, 60);
+ *minute = d.rem;
+
+ /* Stunden */
+ d = ldiv(d.quot, 24);
+ *hour = d.rem;
+
+ /* JDN Date 1/1/1970 */
+ neol_jdn_to_ymd(d.quot + 2440588L, year, month, day);
+}
+
+static void neol_jdn_to_ymd(unsigned long jdn,
+ int *yy,
+ int *mm,
+ int *dd)
+{
+ unsigned long x, z, m, d, y;
+ unsigned long daysPer400Years = 146097UL;
+ unsigned long fudgedDaysPer4000Years = 1460970UL + 31UL;
+
+ x = jdn + 68569UL;
+ z = 4UL * x / daysPer400Years;
+ x = x - (daysPer400Years * z + 3UL) / 4UL;
+ y = 4000UL * (x + 1) / fudgedDaysPer4000Years;
+ x = x - 1461UL * y / 4UL + 31UL;
+ m = 80UL * x / 2447UL;
+ d = x - 2447UL * m / 80UL;
+ x = m / 11UL;
+ m = m + 2UL - 12UL * x;
+ y = 100UL * (z - 49UL) + y + x;
+
+ *yy = (int)y;
+ *mm = (int)m;
+ *dd = (int)d;
+}
+
+/*
+ * delay in milliseconds
+ */
+static void
+neol_mdelay(int milliseconds)
+{
+ struct timeval tv;
+
+ if (milliseconds)
+ {
+ tv.tv_sec = 0;
+ tv.tv_usec = milliseconds * 1000;
+ select(1, NULL, NULL, NULL, &tv);
+ }
+}
+
+static int
+neol_query_firmware(int fd,
+ int unit,
+ char *firmware,
+ int maxlen)
+{
+ unsigned char tmpbuf[256];
+ int len;
+ int lastsearch;
+ unsigned char c;
+ int last_c_was_crlf;
+ int last_crlf_conv_len;
+ int init;
+ int read_tries;
+ int flag = 0;
+
+ /* wait a little bit */
+ neol_mdelay(250);
+ if(-1 != write(fd, "V", 1))
+ {
+ /* wait a little bit */
+ neol_mdelay(250);
+ memset(tmpbuf, 0x00, sizeof(tmpbuf));
+
+ len = 0;
+ lastsearch = 0;
+ last_c_was_crlf = 0;
+ last_crlf_conv_len = 0;
+ init = 1;
+ read_tries = 0;
+ for(;;)
+ {
+ if(read_tries++ > 500)
+ {
+ msyslog(LOG_ERR, "NeoClock4X(%d): can't read firmware version (timeout)", unit);
+ strcpy(tmpbuf, "unknown due to timeout");
+ break;
+ }
+ if(-1 == read(fd, &c, 1))
+ {
+ neol_mdelay(25);
+ continue;
+ }
+ if(init)
+ {
+ if(0xA9 != c) /* wait for (c) char in input stream */
+ continue;
+
+ strcpy(tmpbuf, "(c)");
+ len = 3;
+ init = 0;
+ continue;
+ }
+
+ //msyslog(LOG_NOTICE, "NeoClock4X(%d): firmware %c = %02Xh", unit, c, c);
+ if(0x0A == c || 0x0D == c)
+ {
+ if(last_c_was_crlf)
+ {
+ char *ptr;
+ ptr = strstr(&tmpbuf[lastsearch], "S/N");
+ if(NULL != ptr)
+ {
+ tmpbuf[last_crlf_conv_len] = 0;
+ flag = 1;
+ break;
+ }
+ /* convert \n to / */
+ last_crlf_conv_len = len;
+ tmpbuf[len++] = ' ';
+ tmpbuf[len++] = '/';
+ tmpbuf[len++] = ' ';
+ lastsearch = len;
+ }
+ last_c_was_crlf = 1;
+ }
+ else
+ {
+ last_c_was_crlf = 0;
+ if(0x00 != c)
+ tmpbuf[len++] = c;
+ }
+ tmpbuf[len] = '\0';
+ if(len > sizeof(tmpbuf)-5)
+ break;
+ }
+ }
+ else
+ {
+ msyslog(LOG_ERR, "NeoClock4X(%d): can't query firmware version", unit);
+ strcpy(tmpbuf, "unknown error");
+ }
+ strncpy(firmware, tmpbuf, maxlen);
+ firmware[maxlen] = '\0';
+
+ if(flag)
+ {
+ NLOG(NLOG_CLOCKINFO)
+ msyslog(LOG_INFO, "NeoClock4X(%d): firmware version: %s", unit, firmware);
+ }
+
+ return (flag);
+}
+
+#else
+int refclock_neoclock4x_bs;
+#endif /* REFCLOCK */
+
+/*
+ * History:
+ * refclock_neoclock4x.c
+ *
+ * 2002/04/27 cjh
+ * Revision 1.0 first release
+ *
+ * 2002/0715 cjh
+ * preparing for bitkeeper reposity
+ *
+ */
diff --git a/contrib/ntp/ntpd/refclock_ripencc.c b/contrib/ntp/ntpd/refclock_ripencc.c
new file mode 100644
index 0000000..f18270e
--- /dev/null
+++ b/contrib/ntp/ntpd/refclock_ripencc.c
@@ -0,0 +1,4872 @@
+/*
+ * $Id: refclock_ripencc.c,v 1.13 2002/06/18 14:20:55 marks Exp marks $
+ *
+ * Copyright (c) 2002 RIPE NCC
+ *
+ * All Rights Reserved
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose and without fee is hereby granted,
+ * provided that the above copyright notice appear in all copies and that
+ * both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of the author not be
+ * used in advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission.
+ *
+ * THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL
+ * AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
+ * DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ *
+ *
+ * This driver was developed for use with the RIPE NCC TTM project.
+ *
+ *
+ * The initial driver was developed by Daniel Karrenberg <dfk@ripe.net>
+ * using the code made available by Trimble. This was for xntpd-3.x.x
+ *
+ * Rewrite of the driver for ntpd-4.x.x by Mark Santcroos <marks@ripe.net>
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#if defined(REFCLOCK) && defined(CLOCK_RIPENCC)
+
+#include "ntp_stdlib.h"
+#include "ntpd.h"
+#include "ntp_refclock.h"
+#include "ntp_unixtime.h"
+#include "ntp_io.h"
+
+#ifdef HAVE_TIMEPPS_H
+# include <timepps.h>
+#else /* HAVE_TIMEPPS_H */
+# ifdef HAVE_SYS_TIMEPPS_H
+# include <sys/timepps.h>
+# endif /* HAVE_SYS_TIMEPPS_H */
+#endif /* HAVE_TIMEPPS_H */
+
+/*
+ * Definitions
+ */
+
+/* we are on little endian */
+#define BYTESWAP
+
+/*
+ * DEBUG statements: uncomment if necessary
+ */
+/* #define DEBUG_NCC */ /* general debug statements */
+/* #define DEBUG_PPS */ /* debug pps */
+/* #define DEBUG_RAW */ /* print raw packets */
+
+#define TRIMBLE_OUTPUT_FUNC
+#define TSIP_VERNUM "7.12a"
+
+#ifndef FALSE
+#define FALSE (0)
+#define TRUE (!FALSE)
+#endif /* FALSE */
+
+#define GPS_PI (3.1415926535898)
+#define GPS_C (299792458.)
+#define D2R (GPS_PI/180.0)
+#define R2D (180.0/GPS_PI)
+#define WEEK (604800.)
+#define MAXCHAN (8)
+
+/* control characters for TSIP packets */
+#define DLE (0x10)
+#define ETX (0x03)
+
+#define MAX_RPTBUF (256)
+
+/* values of TSIPPKT.status */
+#define TSIP_PARSED_EMPTY 0
+#define TSIP_PARSED_FULL 1
+#define TSIP_PARSED_DLE_1 2
+#define TSIP_PARSED_DATA 3
+#define TSIP_PARSED_DLE_2 4
+
+#define UTCF_UTC_AVAIL (unsigned char) (1) /* UTC available */
+#define UTCF_LEAP_SCHD (unsigned char) (1<<4) /* Leap scheduled */
+#define UTCF_LEAP_PNDG (unsigned char) (1<<5) /* Leap pending, will occur at end of day */
+
+#define DEVICE "/dev/gps%d" /* name of radio device */
+#define PRECISION (-9) /* precision assumed (about 2 ms) */
+#define PPS_PRECISION (-20) /* precision assumed (about 1 us) */
+#define REFID "GPS\0" /* reference id */
+#define REFID_LEN 4
+#define DESCRIPTION "RIPE NCC GPS (Palisade)" /* Description */
+#define SPEED232 B9600 /* 9600 baud */
+
+#define NSAMPLES 3 /* stages of median filter */
+
+/* Structures */
+
+/* TSIP packets have the following structure, whether report or command. */
+typedef struct {
+ short
+ counter, /* counter */
+ len; /* size of buf; < MAX_RPTBUF unsigned chars */
+ unsigned char
+ status, /* TSIP packet format/parse status */
+ code, /* TSIP code */
+ buf[MAX_RPTBUF];/* report or command string */
+} TSIPPKT;
+
+/* TSIP binary data structures */
+typedef struct {
+ unsigned char
+ t_oa_raw, SV_health;
+ float
+ e, t_oa, i_0, OMEGADOT, sqrt_A,
+ OMEGA_0, omega, M_0, a_f0, a_f1,
+ Axis, n, OMEGA_n, ODOT_n, t_zc;
+ short
+ weeknum, wn_oa;
+} ALM_INFO;
+
+typedef struct { /* Almanac health page (25) parameters */
+ unsigned char
+ WN_a, SV_health[32], t_oa;
+} ALH_PARMS;
+
+typedef struct { /* Universal Coordinated Time (UTC) parms */
+ double
+ A_0;
+ float
+ A_1;
+ short
+ delta_t_LS;
+ float
+ t_ot;
+ short
+ WN_t, WN_LSF, DN, delta_t_LSF;
+} UTC_INFO;
+
+typedef struct { /* Ionospheric info (float) */
+ float
+ alpha_0, alpha_1, alpha_2, alpha_3,
+ beta_0, beta_1, beta_2, beta_3;
+} ION_INFO;
+
+typedef struct { /* Subframe 1 info (float) */
+ short
+ weeknum;
+ unsigned char
+ codeL2, L2Pdata, SVacc_raw, SV_health;
+ short
+ IODC;
+ float
+ T_GD, t_oc, a_f2, a_f1, a_f0, SVacc;
+} EPHEM_CLOCK;
+
+typedef struct { /* Ephemeris info (float) */
+ unsigned char
+ IODE, fit_interval;
+ float
+ C_rs, delta_n;
+ double
+ M_0;
+ float
+ C_uc;
+ double
+ e;
+ float
+ C_us;
+ double
+ sqrt_A;
+ float
+ t_oe, C_ic;
+ double
+ OMEGA_0;
+ float
+ C_is;
+ double
+ i_0;
+ float
+ C_rc;
+ double
+ omega;
+ float
+ OMEGADOT, IDOT;
+ double
+ Axis, n, r1me2, OMEGA_n, ODOT_n;
+} EPHEM_ORBIT;
+
+typedef struct { /* Navigation data structure */
+ short
+ sv_number; /* SV number (0 = no entry) */
+ float
+ t_ephem; /* time of ephemeris collection */
+ EPHEM_CLOCK
+ ephclk; /* subframe 1 data */
+ EPHEM_ORBIT
+ ephorb; /* ephemeris data */
+} NAV_INFO;
+
+typedef struct {
+ unsigned char
+ bSubcode,
+ operating_mode,
+ dgps_mode,
+ dyn_code,
+ trackmode;
+ float
+ elev_mask,
+ cno_mask,
+ dop_mask,
+ dop_switch;
+ unsigned char
+ dgps_age_limit;
+} TSIP_RCVR_CFG;
+
+
+#ifdef TRIMBLE_OUTPUT_FUNC
+static char
+ *dayname[7] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"},
+ old_baudnum[] = {0, 1, 4, 5, 6, 8, 9, 11, 28, 12},
+ *st_baud_text_app [] = {"", "", " 300", " 600", " 1200", " 2400",
+ " 4800", " 9600", "19200", "38400"},
+ *old_parity_text[] = {"EVEN", "ODD", "", "", "NONE"},
+ *parity_text [] = {"NONE", "ODD", "EVEN"},
+ *old_input_ch[] = { "TSIP", "RTCM (6 of 8 bits)"},
+ *old_output_ch[] = { "TSIP", "No output", "", "", "", "NMEA 0183"},
+ *protocols_in_text[] = { "", "TSIP", "", ""},
+ *protocols_out_text[] = { "", "TSIP", "NMEA"},
+ *rcvr_port_text [] = { "Port A ", "Port B ", "Current Port"},
+ *dyn_text [] = {"Unchanged", "Land", "Sea", "Air", "Static"},
+ *NavModeText0xBB[] = {"automatic", "time only (0-D)", "", "2-D",
+ "3-D", "", "", "OverDetermined Time"},
+ *PPSTimeBaseText[] = {"GPS", "UTC", "USER"},
+ *PPSPolarityText[] = {"Positive", "Negative"},
+ *MaskText[] = { "Almanac ", "Ephemeris", "UTC ", "Iono ",
+ "GPS Msg ", "Alm Hlth ", "Time Fix ", "SV Select",
+ "Ext Event", "Pos Fix ", "Raw Meas "};
+
+#endif /* TRIMBLE_OUTPUT_FUNC */
+
+/*
+ * Unit control structure
+ */
+struct ripencc_unit {
+ int unit; /* unit number */
+ int pollcnt; /* poll message counter */
+ int polled; /* Hand in a sample? */
+ char leapdelta; /* delta of next leap event */
+ unsigned char utcflags; /* delta of next leap event */
+ l_fp tstamp; /* timestamp of last poll */
+
+ struct timespec ts; /* last timestamp */
+ pps_params_t pps_params; /* pps parameters */
+ pps_info_t pps_info; /* last pps data */
+ pps_handle_t handle; /* pps handlebars */
+
+};
+
+
+/******************* PROTOYPES *****************/
+
+/* prototypes for report parsing primitives */
+short rpt_0x3D (TSIPPKT *rpt, unsigned char *tx_baud_index,
+ unsigned char *rx_baud_index, unsigned char *char_format_index,
+ unsigned char *stop_bits, unsigned char *tx_mode_index,
+ unsigned char *rx_mode_index);
+short rpt_0x40 (TSIPPKT *rpt, unsigned char *sv_prn, short *week_num,
+ float *t_zc, float *eccentricity, float *t_oa, float *i_0,
+ float *OMEGA_dot, float *sqrt_A, float *OMEGA_0, float *omega,
+ float *M_0);
+short rpt_0x41 (TSIPPKT *rpt, float *time_of_week, float *UTC_offset,
+ short *week_num);
+short rpt_0x42 (TSIPPKT *rpt, float ECEF_pos[3], float *time_of_fix);
+short rpt_0x43 (TSIPPKT *rpt, float ECEF_vel[3], float *freq_offset,
+ float *time_of_fix);
+short rpt_0x45 (TSIPPKT *rpt, unsigned char *major_nav_version,
+ unsigned char *minor_nav_version, unsigned char *nav_day,
+ unsigned char *nav_month, unsigned char *nav_year,
+ unsigned char *major_dsp_version, unsigned char *minor_dsp_version,
+ unsigned char *dsp_day, unsigned char *dsp_month,
+ unsigned char *dsp_year);
+short rpt_0x46 (TSIPPKT *rpt, unsigned char *status1, unsigned char *status2);
+short rpt_0x47 (TSIPPKT *rpt, unsigned char *nsvs, unsigned char *sv_prn,
+ float *snr);
+short rpt_0x48 (TSIPPKT *rpt, unsigned char *message);
+short rpt_0x49 (TSIPPKT *rpt, unsigned char *sv_health);
+short rpt_0x4A (TSIPPKT *rpt, float *lat, float *lon, float *alt,
+ float *clock_bias, float *time_of_fix);
+short rpt_0x4A_2 (TSIPPKT *rpt, float *alt, float *dummy,
+ unsigned char *alt_flag);
+short rpt_0x4B (TSIPPKT *rpt, unsigned char *machine_id,
+ unsigned char *status3, unsigned char *status4);
+short rpt_0x4C (TSIPPKT *rpt, unsigned char *dyn_code, float *el_mask,
+ float *snr_mask, float *dop_mask, float *dop_switch);
+short rpt_0x4D (TSIPPKT *rpt, float *osc_offset);
+short rpt_0x4E (TSIPPKT *rpt, unsigned char *response);
+short rpt_0x4F (TSIPPKT *rpt, double *a0, float *a1, float *time_of_data,
+ short *dt_ls, short *wn_t, short *wn_lsf, short *dn, short *dt_lsf);
+short rpt_0x54 (TSIPPKT *rpt, float *clock_bias, float *freq_offset,
+ float *time_of_fix);
+short rpt_0x55 (TSIPPKT *rpt, unsigned char *pos_code, unsigned char *vel_code,
+ unsigned char *time_code, unsigned char *aux_code);
+short rpt_0x56 (TSIPPKT *rpt, float vel_ENU[3], float *freq_offset,
+ float *time_of_fix);
+short rpt_0x57 (TSIPPKT *rpt, unsigned char *source_code,
+ unsigned char *diag_code, short *week_num, float *time_of_fix);
+short rpt_0x58 (TSIPPKT *rpt, unsigned char *op_code, unsigned char *data_type,
+ unsigned char *sv_prn, unsigned char *data_length,
+ unsigned char *data_packet);
+short rpt_0x59 (TSIPPKT *rpt, unsigned char *code_type,
+ unsigned char status_code[32]);
+short rpt_0x5A (TSIPPKT *rpt, unsigned char *sv_prn, float *sample_length,
+ float *signal_level, float *code_phase, float *Doppler,
+ double *time_of_fix);
+short rpt_0x5B (TSIPPKT *rpt, unsigned char *sv_prn, unsigned char *sv_health,
+ unsigned char *sv_iode, unsigned char *fit_interval_flag,
+ float *time_of_collection, float *time_of_eph, float *sv_accy);
+short rpt_0x5C (TSIPPKT *rpt, unsigned char *sv_prn, unsigned char *slot,
+ unsigned char *chan, unsigned char *acq_flag, unsigned char *eph_flag,
+ float *signal_level, float *time_of_last_msmt, float *elev,
+ float *azim, unsigned char *old_msmt_flag,
+ unsigned char *integer_msec_flag, unsigned char *bad_data_flag,
+ unsigned char *data_collect_flag);
+short rpt_0x6D (TSIPPKT *rpt, unsigned char *manual_mode, unsigned char *nsvs,
+ unsigned char *ndim, unsigned char sv_prn[], float *pdop,
+ float *hdop, float *vdop, float *tdop);
+short rpt_0x82 (TSIPPKT *rpt, unsigned char *diff_mode);
+short rpt_0x83 (TSIPPKT *rpt, double ECEF_pos[3], double *clock_bias,
+ float *time_of_fix);
+short rpt_0x84 (TSIPPKT *rpt, double *lat, double *lon, double *alt,
+ double *clock_bias, float *time_of_fix);
+short rpt_Paly0xBB(TSIPPKT *rpt, TSIP_RCVR_CFG *TsipxBB);
+short rpt_0xBC (TSIPPKT *rpt, unsigned char *port_num,
+ unsigned char *in_baud, unsigned char *out_baud,
+ unsigned char *data_bits, unsigned char *parity,
+ unsigned char *stop_bits, unsigned char *flow_control,
+ unsigned char *protocols_in, unsigned char *protocols_out,
+ unsigned char *reserved);
+
+/* prototypes for superpacket parsers */
+
+short rpt_0x8F0B (TSIPPKT *rpt, unsigned short *event, double *tow,
+ unsigned char *date, unsigned char *month, short *year,
+ unsigned char *dim_mode, short *utc_offset, double *bias, double *drift,
+ float *bias_unc, float *dr_unc, double *lat, double *lon, double *alt,
+ char sv_id[8]);
+short rpt_0x8F14 (TSIPPKT *rpt, short *datum_idx, double datum_coeffs[5]);
+short rpt_0x8F15 (TSIPPKT *rpt, short *datum_idx, double datum_coeffs[5]);
+short rpt_0x8F20 (TSIPPKT *rpt, unsigned char *info, double *lat,
+ double *lon, double *alt, double vel_enu[], double *time_of_fix,
+ short *week_num, unsigned char *nsvs, unsigned char sv_prn[],
+ short sv_IODC[], short *datum_index);
+short rpt_0x8F41 (TSIPPKT *rpt, unsigned char *bSearchRange,
+ unsigned char *bBoardOptions, unsigned long *iiSerialNumber,
+ unsigned char *bBuildYear, unsigned char *bBuildMonth,
+ unsigned char *bBuildDay, unsigned char *bBuildHour,
+ float *fOscOffset, unsigned short *iTestCodeId);
+short rpt_0x8F42 (TSIPPKT *rpt, unsigned char *bProdOptionsPre,
+ unsigned char *bProdNumberExt, unsigned short *iCaseSerialNumberPre,
+ unsigned long *iiCaseSerialNumber, unsigned long *iiProdNumber,
+ unsigned short *iPremiumOptions, unsigned short *iMachineID,
+ unsigned short *iKey);
+short rpt_0x8F45 (TSIPPKT *rpt, unsigned char *bSegMask);
+short rpt_0x8F4A_16 (TSIPPKT *rpt, unsigned char *pps_enabled,
+ unsigned char *pps_timebase, unsigned char *pos_polarity,
+ double *pps_offset, float *bias_unc_threshold);
+short rpt_0x8F4B (TSIPPKT *rpt, unsigned long *decorr_max);
+short rpt_0x8F4D (TSIPPKT *rpt, unsigned long *event_mask);
+short rpt_0x8FA5 (TSIPPKT *rpt, unsigned char *spktmask);
+short rpt_0x8FAD (TSIPPKT *rpt, unsigned short *COUNT, double *FracSec,
+ unsigned char *Hour, unsigned char *Minute, unsigned char *Second,
+ unsigned char *Day, unsigned char *Month, unsigned short *Year,
+ unsigned char *Status, unsigned char *Flags);
+
+/**/
+/* prototypes for command-encode primitives with suffix convention: */
+/* c = clear, s = set, q = query, e = enable, d = disable */
+void cmd_0x1F (TSIPPKT *cmd);
+void cmd_0x26 (TSIPPKT *cmd);
+void cmd_0x2F (TSIPPKT *cmd);
+void cmd_0x35s (TSIPPKT *cmd, unsigned char pos_code, unsigned char vel_code,
+ unsigned char time_code, unsigned char opts_code);
+void cmd_0x3C (TSIPPKT *cmd, unsigned char sv_prn);
+void cmd_0x3Ds (TSIPPKT *cmd, unsigned char baud_out, unsigned char baud_inp,
+ unsigned char char_code, unsigned char stopbitcode,
+ unsigned char output_mode, unsigned char input_mode);
+void cmd_0xBBq (TSIPPKT *cmd, unsigned char subcode) ;
+
+/* prototypes 8E commands */
+void cmd_0x8E0Bq (TSIPPKT *cmd);
+void cmd_0x8E41q (TSIPPKT *cmd);
+void cmd_0x8E42q (TSIPPKT *cmd);
+void cmd_0x8E4Aq (TSIPPKT *cmd);
+void cmd_0x8E4As (TSIPPKT *cmd, unsigned char PPSOnOff, unsigned char TimeBase,
+ unsigned char Polarity, double PPSOffset, float Uncertainty);
+void cmd_0x8E4Bq (TSIPPKT *cmd);
+void cmd_0x8E4Ds (TSIPPKT *cmd, unsigned long AutoOutputMask);
+void cmd_0x8EADq (TSIPPKT *cmd);
+
+/* header/source border XXXXXXXXXXXXXXXXXXXXXXXXXX */
+
+/* Trimble parse functions */
+static int parse0x8FAD P((TSIPPKT *, struct peer *));
+static int parse0x8F0B P((TSIPPKT *, struct peer *));
+#ifdef TRIMBLE_OUTPUT_FUNC
+static int parseany P((TSIPPKT *, struct peer *));
+static void TranslateTSIPReportToText P((TSIPPKT *, char *));
+#endif /* TRIMBLE_OUTPUT_FUNC */
+static int parse0x5C P((TSIPPKT *, struct peer *));
+static int parse0x4F P((TSIPPKT *, struct peer *));
+static void tsip_input_proc P((TSIPPKT *, int));
+
+/* Trimble helper functions */
+static void bPutFloat P((float *, unsigned char *));
+static void bPutDouble P((double *, unsigned char *));
+static void bPutULong P((unsigned long *, unsigned char *));
+static int print_msg_table_header P((int rptcode, char *HdrStr, int force));
+static char * show_time P((float time_of_week));
+
+/* RIPE NCC functions */
+static void ripencc_control P((int, struct refclockstat *, struct
+ refclockstat *, struct peer *));
+static int ripencc_ppsapi P((struct peer *, int, int));
+static int ripencc_get_pps_ts P((struct ripencc_unit *, l_fp *));
+static int ripencc_start P((int, struct peer *));
+static void ripencc_shutdown P((int, struct peer *));
+static void ripencc_poll P((int, struct peer *));
+static void ripencc_send P((struct peer *, TSIPPKT spt));
+static void ripencc_receive P((struct recvbuf *));
+
+/* fill in reflock structure for our clock */
+struct refclock refclock_ripencc = {
+ ripencc_start, /* start up driver */
+ ripencc_shutdown, /* shut down driver */
+ ripencc_poll, /* transmit poll message */
+ ripencc_control, /* control function */
+ noentry, /* initialize driver */
+ noentry, /* debug info */
+ NOFLAGS /* clock flags */
+};
+
+/*
+ * Tables to compute the ddd of year form icky dd/mm timecode. Viva la
+ * leap.
+ */
+static int day1tab[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
+static int day2tab[] = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
+
+extern int pps_hardpps;
+extern int pps_assert;
+
+/*
+ * ripencc_start - open the GPS devices and initialize data for processing
+ */
+static int
+ripencc_start(int unit, struct peer *peer)
+{
+ register struct ripencc_unit *up;
+ struct refclockproc *pp;
+ char device[40];
+ int fd;
+ struct termios tio;
+ TSIPPKT spt;
+
+ /*
+ * Open serial port
+ */
+ (void)snprintf(device, sizeof(device), DEVICE, unit);
+ if (!(fd = refclock_open(device, SPEED232, LDISC_RAW)))
+ return (0);
+
+ /* from refclock_palisade.c */
+ if (tcgetattr(fd, &tio) < 0) {
+ msyslog(LOG_ERR, "Palisade(%d) tcgetattr(fd, &tio): %m",unit);
+ return (0);
+ }
+
+ /*
+ * set flags
+ */
+ tio.c_cflag |= (PARENB|PARODD);
+ tio.c_iflag &= ~ICRNL;
+ if (tcsetattr(fd, TCSANOW, &tio) == -1) {
+ msyslog(LOG_ERR, "Palisade(%d) tcsetattr(fd, &tio): %m",unit);
+ return (0);
+ }
+
+ /*
+ * Allocate and initialize unit structure
+ */
+ if (!(up = (struct ripencc_unit *)
+ emalloc(sizeof(struct ripencc_unit)))) {
+ (void) close(fd);
+ return (0);
+ }
+ memset((char *)up, 0, sizeof(struct ripencc_unit));
+ pp = peer->procptr;
+ pp->io.clock_recv = ripencc_receive;
+ pp->io.srcclock = (caddr_t)peer;
+ pp->io.datalen = 0;
+ pp->io.fd = fd;
+ if (!io_addclock(&pp->io)) {
+ (void) close(fd);
+ free(up);
+ return (0);
+ }
+ pp->unitptr = (caddr_t)up;
+
+ /*
+ * Initialize miscellaneous variables
+ */
+ peer->precision = PRECISION;
+ pp->clockdesc = DESCRIPTION;
+ memcpy((char *)&pp->refid, REFID, REFID_LEN);
+ up->pollcnt = 2;
+ up->unit = unit;
+ up->leapdelta = 0;
+ up->utcflags = 0;
+
+ /*
+ * Initialize the Clock
+ */
+
+ /* query software versions */
+ cmd_0x1F(&spt);
+ ripencc_send(peer, spt);
+
+ /* query receiver health */
+ cmd_0x26(&spt);
+ ripencc_send(peer, spt);
+
+ /* query serial numbers */
+ cmd_0x8E42q(&spt);
+ ripencc_send(peer, spt);
+
+ /* query manuf params */
+ cmd_0x8E41q(&spt);
+ ripencc_send(peer, spt);
+
+ /* i/o opts */ /* trimble manual page A30 */
+ cmd_0x35s(&spt,
+ 0x1C, /* position */
+ 0x00, /* velocity */
+ 0x05, /* timing */
+ 0x0a); /* auxilary */
+ ripencc_send(peer, spt);
+
+ /* turn off port A */
+ cmd_0x3Ds (&spt,
+ 0x0B, /* baud_out */
+ 0x0B, /* baud_inp */
+ 0x07, /* char_code */
+ 0x07, /* stopbitcode */
+ 0x01, /* output_mode */
+ 0x00); /* input_mode */
+ ripencc_send(peer, spt);
+
+ /* set i/o options */
+ cmd_0x8E4As (&spt,
+ 0x01, /* PPS on */
+ 0x01, /* Timebase UTC */
+ 0x00, /* polarity positive */
+ 0., /* 100 ft. cable XXX make flag */
+ 1e-6 * GPS_C); /* turn of biasuncert. > (1us) */
+ ripencc_send(peer,spt);
+
+ /* all outomatic packet output off */
+ cmd_0x8E4Ds(&spt,
+ 0x00000000); /* AutoOutputMask */
+ ripencc_send(peer, spt);
+
+ cmd_0xBBq (&spt,
+ 0x00); /* query primary configuration */
+ ripencc_send(peer,spt);
+
+
+ /* query PPS parameters */
+ cmd_0x8E4Aq (&spt); /* query PPS params */
+ ripencc_send(peer,spt);
+
+ /* query survey limit */
+ cmd_0x8E4Bq (&spt); /* query survey limit */
+ ripencc_send(peer,spt);
+
+#ifdef DEBUG_NCC
+ if (debug)
+ printf("ripencc_start: success\n");
+#endif /* DEBUG_NCC */
+
+ /*
+ * Start the PPSAPI interface if it is there. Default to use
+ * the assert edge and do not enable the kernel hardpps.
+ */
+ if (time_pps_create(fd, &up->handle) < 0) {
+ up->handle = 0;
+ msyslog(LOG_ERR, "refclock_ripencc: time_pps_create failed: %m");
+ return (1);
+ }
+
+ return(ripencc_ppsapi(peer, pps_assert, pps_hardpps));
+}
+
+/*
+ * ripencc_control - fudge control
+ */
+static void
+ripencc_control(
+ int unit, /* unit (not used) */
+ struct refclockstat *in, /* input parameters (not used) */
+ struct refclockstat *out, /* output parameters (not used) */
+ struct peer *peer /* peer structure pointer */
+ )
+{
+ struct refclockproc *pp;
+
+#ifdef DEBUG_NCC
+ msyslog(LOG_INFO,"%s()",__FUNCTION__);
+#endif /* DEBUG_NCC */
+
+ pp = peer->procptr;
+ ripencc_ppsapi(peer, pp->sloppyclockflag & CLK_FLAG2,
+ pp->sloppyclockflag & CLK_FLAG3);
+}
+
+
+/*
+ * Initialize PPSAPI
+ */
+int
+ripencc_ppsapi(
+ struct peer *peer, /* peer structure pointer */
+ int enb_clear, /* clear enable */
+ int enb_hardpps /* hardpps enable */
+ )
+{
+ struct refclockproc *pp;
+ struct ripencc_unit *up;
+ int capability;
+
+ pp = peer->procptr;
+ up = (struct ripencc_unit *)pp->unitptr;
+ if (time_pps_getcap(up->handle, &capability) < 0) {
+ msyslog(LOG_ERR,
+ "refclock_ripencc: time_pps_getcap failed: %m");
+ return (0);
+ }
+ memset(&up->pps_params, 0, sizeof(pps_params_t));
+ if (enb_clear)
+ up->pps_params.mode = capability & PPS_CAPTURECLEAR;
+ else
+ up->pps_params.mode = capability & PPS_CAPTUREASSERT;
+ if (!up->pps_params.mode) {
+ msyslog(LOG_ERR,
+ "refclock_ripencc: invalid capture edge %d",
+ !enb_clear);
+ return (0);
+ }
+ up->pps_params.mode |= PPS_TSFMT_TSPEC;
+ if (time_pps_setparams(up->handle, &up->pps_params) < 0) {
+ msyslog(LOG_ERR,
+ "refclock_ripencc: time_pps_setparams failed: %m");
+ return (0);
+ }
+ if (enb_hardpps) {
+ if (time_pps_kcbind(up->handle, PPS_KC_HARDPPS,
+ up->pps_params.mode & ~PPS_TSFMT_TSPEC,
+ PPS_TSFMT_TSPEC) < 0) {
+ msyslog(LOG_ERR,
+ "refclock_ripencc: time_pps_kcbind failed: %m");
+ return (0);
+ }
+ pps_enable = 1;
+ }
+ peer->precision = PPS_PRECISION;
+
+#if DEBUG_NCC
+ if (debug) {
+ time_pps_getparams(up->handle, &up->pps_params);
+ printf(
+ "refclock_ripencc: capability 0x%x version %d mode 0x%x kern %d\n",
+ capability, up->pps_params.api_version,
+ up->pps_params.mode, enb_hardpps);
+ }
+#endif /* DEBUG_NCC */
+
+ return (1);
+}
+
+/*
+ * This function is called every 64 seconds from ripencc_receive
+ * It will fetch the pps time
+ *
+ * Return 0 on failure and 1 on success.
+ */
+static int
+ripencc_get_pps_ts(
+ struct ripencc_unit *up,
+ l_fp *tsptr
+ )
+{
+ pps_info_t pps_info;
+ struct timespec timeout, ts;
+ double dtemp;
+ l_fp tstmp;
+
+#ifdef DEBUG_PPS
+ msyslog(LOG_INFO,"ripencc_get_pps_ts\n");
+#endif /* DEBUG_PPS */
+
+
+ /*
+ * Convert the timespec nanoseconds field to ntp l_fp units.
+ */
+ if (up->handle == 0)
+ return (0);
+ timeout.tv_sec = 0;
+ timeout.tv_nsec = 0;
+ memcpy(&pps_info, &up->pps_info, sizeof(pps_info_t));
+ if (time_pps_fetch(up->handle, PPS_TSFMT_TSPEC, &up->pps_info,
+ &timeout) < 0)
+ return (0);
+ if (up->pps_params.mode & PPS_CAPTUREASSERT) {
+ if (pps_info.assert_sequence ==
+ up->pps_info.assert_sequence)
+ return (0);
+ ts = up->pps_info.assert_timestamp;
+ } else if (up->pps_params.mode & PPS_CAPTURECLEAR) {
+ if (pps_info.clear_sequence ==
+ up->pps_info.clear_sequence)
+ return (0);
+ ts = up->pps_info.clear_timestamp;
+ } else {
+ return (0);
+ }
+ if ((up->ts.tv_sec == ts.tv_sec) && (up->ts.tv_nsec == ts.tv_nsec))
+ return (0);
+ up->ts = ts;
+
+ tstmp.l_ui = ts.tv_sec + JAN_1970;
+ dtemp = ts.tv_nsec * FRAC / 1e9;
+ tstmp.l_uf = (u_int32)dtemp;
+
+#ifdef DEBUG_PPS
+ msyslog(LOG_INFO,"ts.tv_sec: %d\n",(int)ts.tv_sec);
+ msyslog(LOG_INFO,"ts.tv_nsec: %ld\n",ts.tv_nsec);
+#endif /* DEBUG_PPS */
+
+ *tsptr = tstmp;
+ return (1);
+}
+
+/*
+ * ripencc_shutdown - shut down a GPS clock
+ */
+static void
+ripencc_shutdown(int unit, struct peer *peer)
+{
+ register struct ripencc_unit *up;
+ struct refclockproc *pp;
+
+ pp = peer->procptr;
+ up = (struct ripencc_unit *)pp->unitptr;
+
+ if (up->handle != 0)
+ time_pps_destroy(up->handle);
+
+ io_closeclock(&pp->io);
+
+ free(up);
+}
+
+/*
+ * ripencc_poll - called by the transmit procedure
+ */
+static void
+ripencc_poll(int unit, struct peer *peer)
+{
+ register struct ripencc_unit *up;
+ struct refclockproc *pp;
+ TSIPPKT spt;
+
+#ifdef DEBUG_NCC
+ if (debug)
+ fprintf(stderr, "ripencc_poll(%d)\n", unit);
+#endif /* DEBUG_NCC */
+ pp = peer->procptr;
+ up = (struct ripencc_unit *)pp->unitptr;
+ if (up->pollcnt == 0)
+ refclock_report(peer, CEVNT_TIMEOUT);
+ else
+ up->pollcnt--;
+
+ pp->polls++;
+ up->polled = 1;
+
+ /* poll for UTC superpacket */
+ cmd_0x8EADq (&spt);
+ ripencc_send(peer,spt);
+}
+
+/*
+ * ripencc_send - send message to clock
+ * use the structures being created by the trimble functions!
+ * makes the code more readable/clean
+ */
+static void
+ripencc_send(struct peer *peer, TSIPPKT spt)
+{
+ unsigned char *ip, *op;
+ unsigned char obuf[512];
+
+#ifdef DEBUG_RAW
+ {
+ register struct ripencc_unit *up;
+ register struct refclockproc *pp;
+
+ pp = peer->procptr;
+ up = (struct ripencc_unit *)pp->unitptr;
+ if (debug)
+ printf("ripencc_send(%d, %02X)\n", up->unit, cmd);
+ }
+#endif /* DEBUG_RAW */
+
+ ip = spt.buf;
+ op = obuf;
+
+ *op++ = 0x10;
+ *op++ = spt.code;
+
+ while (spt.len--) {
+ if (op-obuf > sizeof(obuf)-5) {
+ msyslog(LOG_ERR, "ripencc_send obuf overflow!");
+ refclock_report(peer, CEVNT_FAULT);
+ return;
+ }
+
+ if (*ip == 0x10) /* byte stuffing */
+ *op++ = 0x10;
+ *op++ = *ip++;
+ }
+
+ *op++ = 0x10;
+ *op++ = 0x03;
+
+#ifdef DEBUG_RAW
+ if (debug) { /* print raw packet */
+ unsigned char *cp;
+ int i;
+
+ printf("ripencc_send: len %d\n", op-obuf);
+ for (i=1, cp=obuf; cp<op; i++, cp++) {
+ printf(" %02X", *cp);
+ if (i%10 == 0)
+ printf("\n");
+ }
+ printf("\n");
+ }
+#endif /* DEBUG_RAW */
+
+ if (write(peer->procptr->io.fd, obuf, op-obuf) == -1) {
+ refclock_report(peer, CEVNT_FAULT);
+ }
+}
+
+/*
+ * ripencc_receive()
+ *
+ * called when a packet is received on the serial port
+ * takes care of further processing
+ *
+ */
+static void
+ripencc_receive(struct recvbuf *rbufp)
+{
+ register struct ripencc_unit *up;
+ register struct refclockproc *pp;
+ struct peer *peer;
+ static TSIPPKT rpt; /* structure for current incoming TSIP report */
+ TSIPPKT spt; /* send packet */
+ int ns_since_pps;
+ int i;
+ char *cp;
+ /* Use these variables to hold data until we decide its worth keeping */
+ char rd_lastcode[BMAX];
+ l_fp rd_tmp;
+ u_short rd_lencode;
+
+ /* msyslog(LOG_INFO, "%s",__FUNCTION__); */
+
+ /*
+ * Initialize pointers and read the timecode and timestamp
+ */
+ peer = (struct peer *)rbufp->recv_srcclock;
+ pp = peer->procptr;
+ up = (struct ripencc_unit *)pp->unitptr;
+ rd_lencode = refclock_gtlin(rbufp, rd_lastcode, BMAX, &rd_tmp);
+
+#ifdef DEBUG_RAW
+ if (debug)
+ fprintf(stderr, "ripencc_receive(%d)\n", up->unit);
+#endif /* DEBUG_RAW */
+
+#ifdef DEBUG_RAW
+ if (debug) { /* print raw packet */
+ int i;
+ unsigned char *cp;
+
+ printf("ripencc_receive: len %d\n", rbufp->recv_length);
+ for (i=1, cp=(char*)&rbufp->recv_space; i <= rbufp->recv_length; i++, cp++) {
+ printf(" %02X", *cp);
+ if (i%10 == 0)
+ printf("\n");
+ }
+ printf("\n");
+ }
+#endif /* DEBUG_RAW */
+
+ cp = (char*) &rbufp->recv_space;
+ i=rbufp->recv_length;
+
+ while (i--) { /* loop over received chars */
+
+ tsip_input_proc(&rpt, (unsigned char) *cp++);
+
+ if (rpt.status != TSIP_PARSED_FULL)
+ continue;
+
+ switch (rpt.code) {
+
+ case 0x8F: /* superpacket */
+
+ switch (rpt.buf[0]) {
+
+ case 0xAD: /* UTC Time */
+ /*
+ * When polling on port B the timecode
+ * is the time of the previous PPS.
+ * If we completed receiving the packet
+ * less than 150ms after the turn of the second,
+ * it may have the code of the previous second.
+ * We do not trust that and simply poll again
+ * without even parsing it.
+ *
+ * More elegant would be to re-schedule the poll,
+ * but I do not know (yet) how to do that cleanly.
+ *
+ */
+ /* BLA ns_since_pps = ncc_tstmp(rbufp, &trtmp); */
+/* if (up->polled && ns_since_pps > -1 && ns_since_pps < 150) { */
+
+ ns_since_pps=200;
+ if (up->polled && ns_since_pps < 150) {
+ msyslog(LOG_INFO, "%s(): up->polled",__FUNCTION__);
+ ripencc_poll(up->unit, peer);
+ break;
+ }
+
+ /*
+ * Parse primary utc time packet
+ * and fill refclock structure
+ * from results.
+ */
+ if (parse0x8FAD(&rpt, peer) < 0) {
+ msyslog(LOG_INFO, "%s(): parse0x8FAD < 0",__FUNCTION__);
+ refclock_report(peer, CEVNT_BADREPLY);
+ break;
+ }
+ /*
+ * If the PPSAPI is working, rather use its
+ * timestamps.
+ * assume that the PPS occurs on the second
+ * so blow any msec
+ */
+ if (ripencc_get_pps_ts(up, &rd_tmp) == 1) {
+ pp->lastrec = up->tstamp = rd_tmp;
+ pp->msec = 0;
+ }
+ else
+ msyslog(LOG_INFO, "%s(): ripencc_get_pps_ts returns failure\n",__FUNCTION__);
+
+
+ if (!up->polled) {
+ msyslog(LOG_INFO, "%s(): unrequested packet\n",__FUNCTION__);
+ /* unrequested packet */
+ break;
+ }
+
+ /* we have been polled ! */
+ up->polled = 0;
+ up->pollcnt = 2;
+
+ /* poll for next packet */
+ cmd_0x8E0Bq(&spt);
+ ripencc_send(peer,spt);
+
+ if (ns_since_pps < 0) { /* no PPS */
+ msyslog(LOG_INFO, "%s(): ns_since_pps < 0",__FUNCTION__);
+ refclock_report(peer, CEVNT_BADTIME);
+ break;
+ }
+
+ /*
+ * Process the new sample in the median filter and determine the
+ * reference clock offset and dispersion.
+ */
+ if (!refclock_process(pp)) {
+ msyslog(LOG_INFO, "%s(): !refclock_process",__FUNCTION__);
+ refclock_report(peer, CEVNT_BADTIME);
+ break;
+ }
+
+ refclock_receive(peer);
+ break;
+
+ case 0x0B: /* comprehensive time packet */
+ parse0x8F0B(&rpt, peer);
+ break;
+
+ default: /* other superpackets */
+#ifdef DEBUG_NCC
+ msyslog(LOG_INFO, "%s(): calling parseany",__FUNCTION__);
+#endif /* DEBUG_NCC */
+#ifdef TRIMBLE_OUTPUT_FUNC
+ parseany(&rpt, peer);
+#endif /* TRIMBLE_OUTPUT_FUNC */
+ break;
+ }
+ break;
+
+ case 0x4F: /* UTC parameters, for leap info */
+ parse0x4F(&rpt, peer);
+ break;
+
+ case 0x5C: /* sat tracking data */
+ parse0x5C(&rpt, peer);
+ break;
+
+ default: /* other packets */
+#ifdef TRIMBLE_OUTPUT_FUNC
+ parseany(&rpt, peer);
+#endif /* TRIMBLE_OUTPUT_FUNC */
+ break;
+ }
+ rpt.status = TSIP_PARSED_EMPTY;
+ }
+}
+
+/*
+ * All trimble functions that are directly referenced from driver code
+ * (so not from parseany)
+ */
+
+void cmd_0x1F (TSIPPKT *cmd)
+/* request software versions */
+{
+ cmd->len = 0;
+ cmd->code = 0x1F;
+}
+
+void cmd_0x26 (TSIPPKT *cmd)
+/* request receiver health */
+{
+ cmd->len = 0;
+ cmd->code = 0x26;
+}
+
+
+
+
+void cmd_0x2F (TSIPPKT *cmd)
+/* request UTC params */
+{
+ cmd->len = 0;
+ cmd->code = 0x2F;
+}
+
+void cmd_0x35s (TSIPPKT *cmd, unsigned char pos_code, unsigned char vel_code,
+ unsigned char time_code, unsigned char opts_code)
+/* set serial I/O options */
+{
+ cmd->buf[0] = pos_code;
+ cmd->buf[1] = vel_code;
+ cmd->buf[2] = time_code;
+ cmd->buf[3] = opts_code;
+ cmd->len = 4;
+ cmd->code = 0x35;
+}
+void cmd_0x3C (TSIPPKT *cmd, unsigned char sv_prn)
+/* request tracking status */
+{
+ cmd->buf[0] = sv_prn;
+ cmd->len = 1;
+ cmd->code = 0x3C;
+}
+
+
+void cmd_0x3Ds (TSIPPKT *cmd,
+ unsigned char baud_out, unsigned char baud_inp,
+ unsigned char char_code, unsigned char stopbitcode,
+ unsigned char output_mode, unsigned char input_mode)
+/* set Channel A configuration for dual-port operation */
+{
+ cmd->buf[0] = baud_out; /* XMT baud rate */
+ cmd->buf[1] = baud_inp; /* RCV baud rate */
+ cmd->buf[2] = char_code; /* parity and #bits per byte */
+ cmd->buf[3] = stopbitcode; /* number of stop bits code */
+ cmd->buf[4] = output_mode; /* Ch. A transmission mode */
+ cmd->buf[5] = input_mode; /* Ch. A reception mode */
+ cmd->len = 6;
+ cmd->code = 0x3D;
+}
+
+
+/* query primary configuration */
+void cmd_0xBBq (TSIPPKT *cmd,
+ unsigned char subcode)
+{
+
+ cmd->len = 1;
+ cmd->code = 0xBB;
+ cmd->buf[0] = subcode;
+}
+
+
+/**** Superpackets ****/
+void cmd_0x8E0Bq (TSIPPKT *cmd)
+/* 8E-0B to query 8F-0B controls */
+{
+
+ cmd->len = 1;
+ cmd->code = 0x8E;
+ cmd->buf[0] = 0x0B;
+}
+
+
+void cmd_0x8E41q (TSIPPKT *cmd)
+/* 8F-41 to query board serial number */
+{
+
+ cmd->len = 1;
+ cmd->code = 0x8E;
+ cmd->buf[0] = 0x41;
+}
+
+
+void cmd_0x8E42q (TSIPPKT *cmd)
+/* 8F-42 to query product serial number */
+{
+
+ cmd->len = 1;
+ cmd->code = 0x8E;
+ cmd->buf[0] = 0x42;
+}
+void cmd_0x8E4Aq (TSIPPKT *cmd)
+/* 8F-4A to query PPS parameters */
+{
+ cmd->len = 1;
+ cmd->code = 0x8E;
+ cmd->buf[0] = 0x4A;
+}
+
+
+/* set i/o options */
+void cmd_0x8E4As (TSIPPKT *cmd,
+ unsigned char PPSOnOff,
+ unsigned char TimeBase,
+ unsigned char Polarity,
+ double PPSOffset,
+ float Uncertainty)
+{
+ cmd->len = 16;
+ cmd->code = 0x8E;
+ cmd->buf[0] = 0x4A;
+ cmd->buf[1] = PPSOnOff;
+ cmd->buf[2] = TimeBase;
+ cmd->buf[3] = Polarity;
+ bPutDouble (&PPSOffset, &cmd->buf[4]);
+ bPutFloat (&Uncertainty, &cmd->buf[12]);
+}
+void cmd_0x8E4Bq (TSIPPKT *cmd)
+/* 8F-4B query survey limit */
+{
+ cmd->len = 1;
+ cmd->code = 0x8E;
+ cmd->buf[0] = 0x4B;
+}
+
+
+/* poll for UTC superpacket */
+void cmd_0x8EADq (TSIPPKT *cmd)
+/* 8E-AD to query 8F-AD controls */
+{
+ cmd->len = 1;
+ cmd->code = 0x8E;
+ cmd->buf[0] = 0xAD;
+}
+
+/* all outomatic packet output off */
+void cmd_0x8E4Ds (TSIPPKT *cmd,
+ unsigned long AutoOutputMask)
+{
+ cmd->len = 5;
+ cmd->code = 0x8E;
+ cmd->buf[0] = 0x4D;
+ bPutULong (&AutoOutputMask, &cmd->buf[1]);
+}
+
+
+
+
+/* for DOS machines, reverse order of bytes as they come through the
+ * serial port. */
+#ifdef BYTESWAP
+static short bGetShort (unsigned char *bp)
+{
+ short outval;
+ unsigned char *optr;
+
+ optr = (unsigned char*)&outval + 1;
+ *optr-- = *bp++;
+ *optr = *bp;
+ return outval;
+}
+
+#ifdef TRIMBLE_OUTPUT_FUNC
+static unsigned short bGetUShort (unsigned char *bp)
+{
+ unsigned short outval;
+ unsigned char *optr;
+
+ optr = (unsigned char*)&outval + 1;
+ *optr-- = *bp++;
+ *optr = *bp;
+ return outval;
+}
+
+static long bGetLong (unsigned char *bp)
+{
+ long outval;
+ unsigned char *optr;
+
+ optr = (unsigned char*)&outval + 3;
+ *optr-- = *bp++;
+ *optr-- = *bp++;
+ *optr-- = *bp++;
+ *optr = *bp;
+ return outval;
+}
+
+static unsigned long bGetULong (unsigned char *bp)
+{
+ unsigned long outval;
+ unsigned char *optr;
+
+ optr = (unsigned char*)&outval + 3;
+ *optr-- = *bp++;
+ *optr-- = *bp++;
+ *optr-- = *bp++;
+ *optr = *bp;
+ return outval;
+}
+#endif /* TRIMBLE_OUTPUT_FUNC */
+
+static float bGetSingle (unsigned char *bp)
+{
+ float outval;
+ unsigned char *optr;
+
+ optr = (unsigned char*)&outval + 3;
+ *optr-- = *bp++;
+ *optr-- = *bp++;
+ *optr-- = *bp++;
+ *optr = *bp;
+ return outval;
+}
+
+static double bGetDouble (unsigned char *bp)
+{
+ double outval;
+ unsigned char *optr;
+
+ optr = (unsigned char*)&outval + 7;
+ *optr-- = *bp++;
+ *optr-- = *bp++;
+ *optr-- = *bp++;
+ *optr-- = *bp++;
+ *optr-- = *bp++;
+ *optr-- = *bp++;
+ *optr-- = *bp++;
+ *optr = *bp;
+ return outval;
+}
+
+#else /* not BYTESWAP */
+
+#define bGetShort(bp) (*(short*)(bp))
+#define bGetLong(bp) (*(long*)(bp))
+#define bGetULong(bp) (*(unsigned long*)(bp))
+#define bGetSingle(bp) (*(float*)(bp))
+#define bGetDouble(bp) (*(double*)(bp))
+
+#endif /* BYTESWAP */
+/*
+ * Byte-reversal is necessary for little-endian (Intel-based) machines.
+ * TSIP streams are Big-endian (Motorola-based).
+ */
+#ifdef BYTESWAP
+
+void
+bPutFloat (float *in, unsigned char *out)
+{
+ unsigned char *inptr;
+
+ inptr = (unsigned char*)in + 3;
+ *out++ = *inptr--;
+ *out++ = *inptr--;
+ *out++ = *inptr--;
+ *out = *inptr;
+}
+
+static void
+bPutULong (unsigned long *in, unsigned char *out)
+{
+ unsigned char *inptr;
+
+ inptr = (unsigned char*)in + 3;
+ *out++ = *inptr--;
+ *out++ = *inptr--;
+ *out++ = *inptr--;
+ *out = *inptr;
+}
+
+static void
+bPutDouble (double *in, unsigned char *out)
+{
+ unsigned char *inptr;
+
+ inptr = (unsigned char*)in + 7;
+ *out++ = *inptr--;
+ *out++ = *inptr--;
+ *out++ = *inptr--;
+ *out++ = *inptr--;
+ *out++ = *inptr--;
+ *out++ = *inptr--;
+ *out++ = *inptr--;
+ *out = *inptr;
+}
+
+#else /* not BYTESWAP */
+
+void bPutShort (short a, unsigned char *cmdbuf) {*(short*) cmdbuf = a;}
+void bPutULong (long a, unsigned char *cmdbuf) {*(long*) cmdbuf = a;}
+void bPutFloat (float a, unsigned char *cmdbuf) {*(float*) cmdbuf = a;}
+void bPutDouble (double a, unsigned char *cmdbuf){*(double*) cmdbuf = a;}
+
+#endif /* BYTESWAP */
+
+/*
+ * Parse primary utc time packet
+ * and fill refclock structure
+ * from results.
+ *
+ * 0 = success
+ * -1 = errors
+ */
+
+static int
+parse0x8FAD(rpt, peer)
+ TSIPPKT *rpt;
+ struct peer *peer;
+{
+ register struct refclockproc *pp;
+ register struct ripencc_unit *up;
+
+ unsigned day, month, year; /* data derived from received timecode */
+ unsigned hour, minute, second;
+ unsigned char trackstat, utcflags;
+
+ static char logbuf[1024]; /* logging string buffer */
+ int i;
+ unsigned char *buf;
+
+ buf = rpt->buf;
+ pp = peer->procptr;
+
+ if (rpt->len != 22)
+ return (-1);
+
+ if (bGetShort(&buf[1]) != 0) {
+#ifdef DEBUG_NCC
+ if (debug)
+ printf("parse0x8FAD: event count != 0\n");
+#endif /* DEBUG_NCC */
+ return(-1);
+ }
+
+
+ if (bGetDouble(&buf[3]) != 0.0) {
+#ifdef DEBUG_NCC
+ if (debug)
+ printf("parse0x8FAD: fracsecs != 0\n");
+#endif /* DEBUG_NCC */
+ return(-1);
+ }
+
+ hour = (unsigned int) buf[11];
+ minute = (unsigned int) buf[12];
+ second = (unsigned int) buf[13];
+ day = (unsigned int) buf[14];
+ month = (unsigned int) buf[15];
+ year = bGetShort(&buf[16]);
+ trackstat = buf[18];
+ utcflags = buf[19];
+
+
+ sprintf(logbuf, "U1 %d.%d.%d %02d:%02d:%02d %d %02x",
+ day, month, year, hour, minute, second, trackstat, utcflags);
+
+#ifdef DEBUG_NCC
+ if (debug)
+ puts(logbuf);
+#endif /* DEBUG_NCC */
+
+ record_clock_stats(&peer->srcadr, logbuf);
+
+ if (!utcflags & UTCF_UTC_AVAIL)
+ return(-1);
+
+ /* poll for UTC parameters once and then if UTC flag changed */
+ up = (struct ripencc_unit *) pp->unitptr;
+ if (utcflags != up->utcflags) {
+ TSIPPKT spt; /* local structure for send packet */
+ cmd_0x2F (&spt); /* request UTC params */
+ ripencc_send(peer,spt);
+ up->utcflags = utcflags;
+ }
+
+ /*
+ * If we hit the leap second, we choose to skip this sample
+ * rather than rely on other code to be perfectly correct.
+ * No offense, just defense ;-).
+ */
+ if (second == 60)
+ return(-1);
+
+ /* now check and convert the time we received */
+
+ pp->year = year;
+ if (month < 1 || month > 12 || day < 1 || day > 31)
+ return(-1);
+
+ if (pp->year % 4) {
+ if (day > day1tab[month - 1])
+ return(-1);
+ for (i = 0; i < month - 1; i++)
+ day += day1tab[i];
+ } else {
+ if (day > day2tab[month - 1])
+ return(-1);
+ for (i = 0; i < month - 1; i++)
+ day += day2tab[i];
+ }
+ pp->day = day;
+ pp->hour = hour;
+ pp->minute = minute;
+ pp-> second = second;
+ pp->msec = 0;
+
+ if ((utcflags&UTCF_LEAP_PNDG) && up->leapdelta != 0)
+ pp-> leap = (up->leapdelta > 0 ? LEAP_ADDSECOND : LEAP_DELSECOND);
+ else
+ pp-> leap = LEAP_NOWARNING;
+
+ return (0);
+}
+
+/*
+ * Parse comprehensive time packet
+ *
+ * 0 = success
+ * -1 = errors
+ */
+
+int parse0x8F0B(rpt, peer)
+ TSIPPKT *rpt;
+ struct peer *peer;
+{
+ register struct refclockproc *pp;
+
+ unsigned day, month, year; /* data derived from received timecode */
+ unsigned hour, minute, second;
+ unsigned utcoff;
+ unsigned char mode;
+ double bias, rate;
+ float biasunc, rateunc;
+ double lat, lon, alt;
+ short lat_deg, lon_deg;
+ float lat_min, lon_min;
+ unsigned char north_south, east_west;
+ char sv[9];
+
+ static char logbuf[1024]; /* logging string buffer */
+ unsigned char b;
+ int i;
+ unsigned char *buf;
+ double tow;
+
+ buf = rpt->buf;
+ pp = peer->procptr;
+
+ if (rpt->len != 74)
+ return (-1);
+
+ if (bGetShort(&buf[1]) != 0)
+ return(-1);;
+
+ tow = bGetDouble(&buf[3]);
+
+ if (tow == -1.0) {
+ return(-1);
+ }
+ else if ((tow >= 604800.0) || (tow < 0.0)) {
+ return(-1);
+ }
+ else
+ {
+ if (tow < 604799.9) tow = tow + .00000001;
+ second = (unsigned int) fmod(tow, 60.);
+ minute = (unsigned int) fmod(tow/60., 60.);
+ hour = (unsigned int )fmod(tow / 3600., 24.);
+ }
+
+
+ day = (unsigned int) buf[11];
+ month = (unsigned int) buf[12];
+ year = bGetShort(&buf[13]);
+ mode = buf[15];
+ utcoff = bGetShort(&buf[16]);
+ bias = bGetDouble(&buf[18]) / GPS_C * 1e9; /* ns */
+ rate = bGetDouble(&buf[26]) / GPS_C * 1e9; /* ppb */
+ biasunc = bGetSingle(&buf[34]) / GPS_C * 1e9; /* ns */
+ rateunc = bGetSingle(&buf[38]) / GPS_C * 1e9; /* ppb */
+ lat = bGetDouble(&buf[42]) * R2D;
+ lon = bGetDouble(&buf[50]) * R2D;
+ alt = bGetDouble(&buf[58]);
+
+ if (lat < 0.0) {
+ north_south = 'S';
+ lat = -lat;
+ }
+ else {
+ north_south = 'N';
+ }
+ lat_deg = (short)lat;
+ lat_min = (lat - lat_deg) * 60.0;
+
+ if (lon < 0.0) {
+ east_west = 'W';
+ lon = -lon;
+ }
+ else {
+ east_west = 'E';
+ }
+
+ lon_deg = (short)lon;
+ lon_min = (lon - lon_deg) * 60.0;
+
+ for (i=0; i<8; i++) {
+ sv[i] = buf[i + 66];
+ if (sv[i]) {
+ TSIPPKT spt; /* local structure for sendpacket */
+ b = (unsigned char) (sv[i]<0 ? -sv[i] : sv[i]);
+ /* request tracking status */
+ cmd_0x3C (&spt, b);
+ ripencc_send(peer,spt);
+ }
+ }
+
+
+ sprintf(logbuf, "C1 %02d%02d%04d %02d%02d%02d %d %7.0f %.1f %.0f %.1f %d %02d%09.6f %c %02d%09.6f %c %.0f %d %d %d %d %d %d %d %d",
+ day, month, year, hour, minute, second, mode, bias, biasunc, rate, rateunc, utcoff,
+ lat_deg, lat_min, north_south, lon_deg, lon_min, east_west, alt,
+ sv[0], sv[1], sv[2], sv[3], sv[4], sv[5], sv[6], sv[7]);
+
+#ifdef DEBUG_NCC
+ if (debug)
+ puts(logbuf);
+#endif /* DEBUG_NCC */
+
+ record_clock_stats(&peer->srcadr, logbuf);
+
+ return (0);
+}
+
+#ifdef TRIMBLE_OUTPUT_FUNC
+/*
+ * Parse any packet using Trimble machinery
+ */
+int parseany(rpt, peer)
+ TSIPPKT *rpt;
+ struct peer *peer;
+{
+ static char logbuf[1024]; /* logging string buffer */
+
+ TranslateTSIPReportToText (rpt, logbuf); /* anything else */
+#ifdef DEBUG_NCC
+ if (debug)
+ puts(&logbuf[1]);
+#endif /* DEBUG_NCC */
+ record_clock_stats(&peer->srcadr, &logbuf[1]);
+ return(0);
+}
+#endif /* TRIMBLE_OUTPUT_FUNC */
+
+
+/*
+ * Parse UTC Parameter Packet
+ *
+ * See the IDE for documentation!
+ *
+ * 0 = success
+ * -1 = errors
+ */
+
+int parse0x4F(rpt, peer)
+ TSIPPKT *rpt;
+ struct peer *peer;
+{
+ register struct ripencc_unit *up;
+
+ double a0;
+ float a1, tot;
+ int dt_ls, wn_t, wn_lsf, dn, dt_lsf;
+
+ static char logbuf[1024]; /* logging string buffer */
+ unsigned char *buf;
+
+ buf = rpt->buf;
+
+ if (rpt->len != 26)
+ return (-1);
+ a0 = bGetDouble (buf);
+ a1 = bGetSingle (&buf[8]);
+ dt_ls = bGetShort (&buf[12]);
+ tot = bGetSingle (&buf[14]);
+ wn_t = bGetShort (&buf[18]);
+ wn_lsf = bGetShort (&buf[20]);
+ dn = bGetShort (&buf[22]);
+ dt_lsf = bGetShort (&buf[24]);
+
+ sprintf(logbuf, "L1 %d %d %d %g %g %g %d %d %d",
+ dt_lsf - dt_ls, dt_ls, dt_lsf, a0, a1, tot, wn_t, wn_lsf, dn);
+
+#ifdef DEBUG_NCC
+ if (debug)
+ puts(logbuf);
+#endif /* DEBUG_NCC */
+
+ record_clock_stats(&peer->srcadr, logbuf);
+
+ up = (struct ripencc_unit *) peer->procptr->unitptr;
+ up->leapdelta = dt_lsf - dt_ls;
+
+ return (0);
+}
+
+/*
+ * Parse Tracking Status packet
+ *
+ * 0 = success
+ * -1 = errors
+ */
+
+int parse0x5C(rpt, peer)
+ TSIPPKT *rpt;
+ struct peer *peer;
+{
+ unsigned char prn, channel, aqflag, ephstat;
+ float snr, azinuth, elevation;
+
+ static char logbuf[1024]; /* logging string buffer */
+ unsigned char *buf;
+
+ buf = rpt->buf;
+
+ if (rpt->len != 24)
+ return(-1);
+
+ prn = buf[0];
+ channel = (unsigned char)(buf[1] >> 3);
+ if (channel == 0x10)
+ channel = 2;
+ else
+ channel++;
+ aqflag = buf[2];
+ ephstat = buf[3];
+ snr = bGetSingle(&buf[4]);
+ elevation = bGetSingle(&buf[12]) * R2D;
+ azinuth = bGetSingle(&buf[16]) * R2D;
+
+ sprintf(logbuf, "S1 %02d %d %d %02x %4.1f %5.1f %4.1f",
+ prn, channel, aqflag, ephstat, snr, azinuth, elevation);
+
+#ifdef DEBUG_NCC
+ if (debug)
+ puts(logbuf);
+#endif /* DEBUG_NCC */
+
+ record_clock_stats(&peer->srcadr, logbuf);
+
+ return (0);
+}
+
+/******* Code below is from Trimble Tsipchat *************/
+
+/*
+ * *************************************************************************
+ *
+ * Trimble Navigation, Ltd.
+ * OEM Products Development Group
+ * P.O. Box 3642
+ * 645 North Mary Avenue
+ * Sunnyvale, California 94088-3642
+ *
+ * Corporate Headquarter:
+ * Telephone: (408) 481-8000
+ * Fax: (408) 481-6005
+ *
+ * Technical Support Center:
+ * Telephone: (800) 767-4822 (U.S. and Canada)
+ * (408) 481-6940 (outside U.S. and Canada)
+ * Fax: (408) 481-6020
+ * BBS: (408) 481-7800
+ * e-mail: trimble_support@trimble.com
+ * ftp://ftp.trimble.com/pub/sct/embedded/bin
+ *
+ * *************************************************************************
+ *
+ * ------- BYTE-SWAPPING -------
+ * TSIP is big-endian (Motorola) protocol. To use on little-endian (Intel)
+ * systems, the bytes of all multi-byte types (shorts, floats, doubles, etc.)
+ * must be reversed. This is controlled by the MACRO BYTESWAP; if defined, it
+ * assumes little-endian protocol.
+ * --------------------------------
+ *
+ * T_PARSER.C and T_PARSER.H contains primitive functions that interpret
+ * reports received from the receiver. A second source file pair,
+ * T_FORMAT.C and T_FORMAT.H, contin the matching TSIP command formatters.
+ *
+ * The module is in very portable, basic C language. It can be used as is, or
+ * with minimal changes if a TSIP communications application is needed separate
+ * from TSIPCHAT. The construction of most argument lists avoid the use of
+ * structures, but the developer is encouraged to reconstruct them using such
+ * definitions to meet project requirements. Declarations of T_PARSER.C
+ * functions are included in T_PARSER.H to provide prototyping definitions.
+ *
+ * There are two types of functions: a serial input processing routine,
+ * tsip_input_proc()
+ * which assembles incoming bytes into a TSIPPKT structure, and the
+ * report parsers, rpt_0x??().
+ *
+ * 1) The function tsip_input_proc() accumulates bytes from the receiver,
+ * strips control bytes (DLE), and checks if the report end sequence (DLE ETX)
+ * has been received. rpt.status is defined as TSIP_PARSED_FULL (== 1)
+ * if a complete packet is available.
+ *
+ * 2) The functions rpt_0x??() are report string interpreters patterned after
+ * the document called "Trimble Standard Interface Protocol". It should be
+ * noted that if the report buffer is sent into the receiver with the wrong
+ * length (byte count), the rpt_0x??() returns the Boolean equivalence for
+ * TRUE.
+ *
+ * *************************************************************************
+ *
+ */
+
+
+/**/
+static void tsip_input_proc (
+ TSIPPKT *rpt,
+ int inbyte)
+/* reads bytes until serial buffer is empty or a complete report
+ * has been received; end of report is signified by DLE ETX.
+ */
+{
+ unsigned char newbyte;
+
+ if (inbyte < 0 || inbyte > 0xFF) return;
+
+ newbyte = (unsigned char)(inbyte);
+ switch (rpt->status)
+ {
+ case TSIP_PARSED_DLE_1:
+ switch (newbyte)
+ {
+ case 0:
+ case ETX:
+ /* illegal TSIP IDs */
+ rpt->len = 0;
+ rpt->status = TSIP_PARSED_EMPTY;
+ break;
+ case DLE:
+ /* try normal message start again */
+ rpt->len = 0;
+ rpt->status = TSIP_PARSED_DLE_1;
+ break;
+ default:
+ /* legal TSIP ID; start message */
+ rpt->code = newbyte;
+ rpt->len = 0;
+ rpt->status = TSIP_PARSED_DATA;
+ break;
+ }
+ break;
+ case TSIP_PARSED_DATA:
+ switch (newbyte) {
+ case DLE:
+ /* expect DLE or ETX next */
+ rpt->status = TSIP_PARSED_DLE_2;
+ break;
+ default:
+ /* normal data byte */
+ rpt->buf[rpt->len] = newbyte;
+ rpt->len++;
+ /* no change in rpt->status */
+ break;
+ }
+ break;
+ case TSIP_PARSED_DLE_2:
+ switch (newbyte) {
+ case DLE:
+ /* normal data byte */
+ rpt->buf[rpt->len] = newbyte;
+ rpt->len++;
+ rpt->status = TSIP_PARSED_DATA;
+ break;
+ case ETX:
+ /* end of message; return TRUE here. */
+ rpt->status = TSIP_PARSED_FULL;
+ break;
+ default:
+ /* error: treat as TSIP_PARSED_DLE_1; start new report packet */
+ rpt->code = newbyte;
+ rpt->len = 0;
+ rpt->status = TSIP_PARSED_DATA;
+ }
+ break;
+ case TSIP_PARSED_FULL:
+ case TSIP_PARSED_EMPTY:
+ default:
+ switch (newbyte) {
+ case DLE:
+ /* normal message start */
+ rpt->len = 0;
+ rpt->status = TSIP_PARSED_DLE_1;
+ break;
+ default:
+ /* error: ignore newbyte */
+ rpt->len = 0;
+ rpt->status = TSIP_PARSED_EMPTY;
+ }
+ break;
+ }
+ if (rpt->len > MAX_RPTBUF) {
+ /* error: start new report packet */
+ rpt->status = TSIP_PARSED_EMPTY;
+ rpt->len = 0;
+ }
+}
+
+#ifdef TRIMBLE_OUTPUT_FUNC
+
+/**/
+short rpt_0x3D (TSIPPKT *rpt,
+ unsigned char *tx_baud_index,
+ unsigned char *rx_baud_index,
+ unsigned char *char_format_index,
+ unsigned char *stop_bits,
+ unsigned char *tx_mode_index,
+ unsigned char *rx_mode_index)
+/* Channel A configuration for dual port operation */
+{
+ unsigned char *buf;
+ buf = rpt->buf;
+
+ if (rpt->len != 6) return TRUE;
+ *tx_baud_index = buf[0];
+ *rx_baud_index = buf[1];
+ *char_format_index = buf[2];
+ *stop_bits = (unsigned char)((buf[3] == 0x07) ? 1 : 2);
+ *tx_mode_index = buf[4];
+ *rx_mode_index = buf[5];
+ return FALSE;
+}
+
+/**/
+short rpt_0x40 (TSIPPKT *rpt,
+ unsigned char *sv_prn,
+ short *week_num,
+ float *t_zc,
+ float *eccentricity,
+ float *t_oa,
+ float *i_0,
+ float *OMEGA_dot,
+ float *sqrt_A,
+ float *OMEGA_0,
+ float *omega,
+ float *M_0)
+/* almanac data for specified satellite */
+{
+ unsigned char *buf;
+ buf = rpt->buf;
+
+ if (rpt->len != 39) return TRUE;
+ *sv_prn = buf[0];
+ *t_zc = bGetSingle (&buf[1]);
+ *week_num = bGetShort (&buf[5]);
+ *eccentricity = bGetSingle (&buf[7]);
+ *t_oa = bGetSingle (&buf[11]);
+ *i_0 = bGetSingle (&buf[15]);
+ *OMEGA_dot = bGetSingle (&buf[19]);
+ *sqrt_A = bGetSingle (&buf[23]);
+ *OMEGA_0 = bGetSingle (&buf[27]);
+ *omega = bGetSingle (&buf[31]);
+ *M_0 = bGetSingle (&buf[35]);
+ return FALSE;
+}
+
+short rpt_0x41 (TSIPPKT *rpt,
+ float *time_of_week,
+ float *UTC_offset,
+ short *week_num)
+/* GPS time */
+{
+ unsigned char *buf;
+ buf = rpt->buf;
+
+ if (rpt->len != 10) return TRUE;
+ *time_of_week = bGetSingle (buf);
+ *week_num = bGetShort (&buf[4]);
+ *UTC_offset = bGetSingle (&buf[6]);
+ return FALSE;
+}
+
+short rpt_0x42 (TSIPPKT *rpt,
+ float pos_ECEF[3],
+ float *time_of_fix)
+/* position in ECEF, single precision */
+{
+ unsigned char *buf;
+ buf = rpt->buf;
+
+ if (rpt->len != 16) return TRUE;
+ pos_ECEF[0] = bGetSingle (buf);
+ pos_ECEF[1]= bGetSingle (&buf[4]);
+ pos_ECEF[2]= bGetSingle (&buf[8]);
+ *time_of_fix = bGetSingle (&buf[12]);
+ return FALSE;
+}
+
+short rpt_0x43 (TSIPPKT *rpt,
+ float ECEF_vel[3],
+ float *freq_offset,
+ float *time_of_fix)
+/* velocity in ECEF, single precision */
+{
+ unsigned char *buf;
+ buf = rpt->buf;
+
+ if (rpt->len != 20) return TRUE;
+ ECEF_vel[0] = bGetSingle (buf);
+ ECEF_vel[1] = bGetSingle (&buf[4]);
+ ECEF_vel[2] = bGetSingle (&buf[8]);
+ *freq_offset = bGetSingle (&buf[12]);
+ *time_of_fix = bGetSingle (&buf[16]);
+ return FALSE;
+}
+
+short rpt_0x45 (TSIPPKT *rpt,
+ unsigned char *major_nav_version,
+ unsigned char *minor_nav_version,
+ unsigned char *nav_day,
+ unsigned char *nav_month,
+ unsigned char *nav_year,
+ unsigned char *major_dsp_version,
+ unsigned char *minor_dsp_version,
+ unsigned char *dsp_day,
+ unsigned char *dsp_month,
+ unsigned char *dsp_year)
+/* software versions */
+{
+ unsigned char *buf;
+ buf = rpt->buf;
+
+ if (rpt->len != 10) return TRUE;
+ *major_nav_version = buf[0];
+ *minor_nav_version = buf[1];
+ *nav_day = buf[2];
+ *nav_month = buf[3];
+ *nav_year = buf[4];
+ *major_dsp_version = buf[5];
+ *minor_dsp_version = buf[6];
+ *dsp_day = buf[7];
+ *dsp_month = buf[8];
+ *dsp_year = buf[9];
+ return FALSE;
+}
+
+short rpt_0x46 (TSIPPKT *rpt,
+ unsigned char *status1,
+ unsigned char *status2)
+/* receiver health and status */
+{
+ unsigned char *buf;
+ buf = rpt->buf;
+
+ if (rpt->len != 2) return TRUE;
+ *status1 = buf[0];
+ *status2 = buf[1];
+ return FALSE;
+}
+
+short rpt_0x47 (TSIPPKT *rpt,
+ unsigned char *nsvs, unsigned char *sv_prn,
+ float *snr)
+/* signal levels for all satellites tracked */
+{
+ short isv;
+ unsigned char *buf;
+ buf = rpt->buf;
+
+ if (rpt->len != 1 + 5*buf[0]) return TRUE;
+ *nsvs = buf[0];
+ for (isv = 0; isv < (*nsvs); isv++) {
+ sv_prn[isv] = buf[5*isv + 1];
+ snr[isv] = bGetSingle (&buf[5*isv + 2]);
+ }
+ return FALSE;
+}
+
+short rpt_0x48 (TSIPPKT *rpt,
+ unsigned char *message)
+/* GPS system message */
+{
+ unsigned char *buf;
+ buf = rpt->buf;
+
+ if (rpt->len != 22) return TRUE;
+ memcpy (message, buf, 22);
+ message[22] = 0;
+ return FALSE;
+}
+
+short rpt_0x49 (TSIPPKT *rpt,
+ unsigned char *sv_health)
+/* health for all satellites from almanac health page */
+{
+ short i;
+ unsigned char *buf;
+ buf = rpt->buf;
+
+ if (rpt->len != 32) return TRUE;
+ for (i = 0; i < 32; i++) sv_health [i]= buf[i];
+ return FALSE;
+}
+
+short rpt_0x4A (TSIPPKT *rpt,
+ float *lat,
+ float *lon,
+ float *alt,
+ float *clock_bias,
+ float *time_of_fix)
+/* position in lat-lon-alt, single precision */
+{
+ unsigned char *buf;
+ buf = rpt->buf;
+
+ if (rpt->len != 20) return TRUE;
+ *lat = bGetSingle (buf);
+ *lon = bGetSingle (&buf[4]);
+ *alt = bGetSingle (&buf[8]);
+ *clock_bias = bGetSingle (&buf[12]);
+ *time_of_fix = bGetSingle (&buf[16]);
+ return FALSE;
+}
+
+short rpt_0x4A_2 (TSIPPKT *rpt,
+ float *alt, float *dummy , unsigned char *alt_flag)
+/* reference altitude parameters */
+{
+ unsigned char *buf;
+
+ buf = rpt->buf;
+
+ if (rpt->len != 9) return TRUE;
+ *alt = bGetSingle (buf);
+ *dummy = bGetSingle (&buf[4]);
+ *alt_flag = buf[8];
+ return FALSE;
+}
+
+short rpt_0x4B (TSIPPKT *rpt,
+ unsigned char *machine_id,
+ unsigned char *status3,
+ unsigned char *status4)
+/* machine ID code, status */
+{
+ unsigned char *buf;
+ buf = rpt->buf;
+
+ if (rpt->len != 3) return TRUE;
+ *machine_id = buf[0];
+ *status3 = buf[1];
+ *status4 = buf[2];
+ return FALSE;
+}
+
+short rpt_0x4C (TSIPPKT *rpt,
+ unsigned char *dyn_code,
+ float *el_mask,
+ float *snr_mask,
+ float *dop_mask,
+ float *dop_switch)
+/* operating parameters and masks */
+{
+ unsigned char *buf;
+ buf = rpt->buf;
+
+ if (rpt->len != 17) return TRUE;
+ *dyn_code = buf[0];
+ *el_mask = bGetSingle (&buf[1]);
+ *snr_mask = bGetSingle (&buf[5]);
+ *dop_mask = bGetSingle (&buf[9]);
+ *dop_switch = bGetSingle (&buf[13]);
+ return FALSE;
+}
+
+short rpt_0x4D (TSIPPKT *rpt,
+ float *osc_offset)
+/* oscillator offset */
+{
+ unsigned char *buf;
+ buf = rpt->buf;
+
+ if (rpt->len != 4) return TRUE;
+ *osc_offset = bGetSingle (buf);
+ return FALSE;
+}
+
+short rpt_0x4E (TSIPPKT *rpt,
+ unsigned char *response)
+/* yes/no response to command to set GPS time */
+{
+ unsigned char *buf;
+ buf = rpt->buf;
+
+ if (rpt->len != 1) return TRUE;
+ *response = buf[0];
+ return FALSE;
+}
+
+short rpt_0x4F (TSIPPKT *rpt,
+ double *a0,
+ float *a1,
+ float *time_of_data,
+ short *dt_ls,
+ short *wn_t,
+ short *wn_lsf,
+ short *dn,
+ short *dt_lsf)
+/* UTC data */
+{
+ unsigned char *buf;
+ buf = rpt->buf;
+
+ if (rpt->len != 26) return TRUE;
+ *a0 = bGetDouble (buf);
+ *a1 = bGetSingle (&buf[8]);
+ *dt_ls = bGetShort (&buf[12]);
+ *time_of_data = bGetSingle (&buf[14]);
+ *wn_t = bGetShort (&buf[18]);
+ *wn_lsf = bGetShort (&buf[20]);
+ *dn = bGetShort (&buf[22]);
+ *dt_lsf = bGetShort (&buf[24]);
+ return FALSE;
+}
+
+/**/
+short rpt_0x54 (TSIPPKT *rpt,
+ float *clock_bias,
+ float *freq_offset,
+ float *time_of_fix)
+/* clock offset and frequency offset in 1-SV (0-D) mode */
+{
+ unsigned char *buf;
+ buf = rpt->buf;
+
+ if (rpt->len != 12) return TRUE;
+ *clock_bias = bGetSingle (buf);
+ *freq_offset = bGetSingle (&buf[4]);
+ *time_of_fix = bGetSingle (&buf[8]);
+ return FALSE;
+}
+
+short rpt_0x55 (TSIPPKT *rpt,
+ unsigned char *pos_code,
+ unsigned char *vel_code,
+ unsigned char *time_code,
+ unsigned char *aux_code)
+/* I/O serial options */
+{
+ unsigned char *buf;
+ buf = rpt->buf;
+
+ if (rpt->len != 4) return TRUE;
+ *pos_code = buf[0];
+ *vel_code = buf[1];
+ *time_code = buf[2];
+ *aux_code = buf[3];
+ return FALSE;
+}
+
+short rpt_0x56 (TSIPPKT *rpt,
+ float vel_ENU[3], float *freq_offset, float *time_of_fix)
+/* velocity in east-north-up coordinates */
+{
+ unsigned char *buf;
+ buf = rpt->buf;
+
+ if (rpt->len != 20) return TRUE;
+ /* east */
+ vel_ENU[0] = bGetSingle (buf);
+ /* north */
+ vel_ENU[1] = bGetSingle (&buf[4]);
+ /* up */
+ vel_ENU[2] = bGetSingle (&buf[8]);
+ *freq_offset = bGetSingle (&buf[12]);
+ *time_of_fix = bGetSingle (&buf[16]);
+ return FALSE;
+}
+
+short rpt_0x57 (TSIPPKT *rpt,
+ unsigned char *source_code, unsigned char *diag_code,
+ short *week_num,
+ float *time_of_fix)
+/* info about last computed fix */
+{
+ unsigned char *buf;
+ buf = rpt->buf;
+
+ if (rpt->len != 8) return TRUE;
+ *source_code = buf[0];
+ *diag_code = buf[1];
+ *time_of_fix = bGetSingle (&buf[2]);
+ *week_num = bGetShort (&buf[6]);
+ return FALSE;
+}
+
+short rpt_0x58 (TSIPPKT *rpt,
+ unsigned char *op_code, unsigned char *data_type, unsigned char *sv_prn,
+ unsigned char *data_length, unsigned char *data_packet)
+/* GPS system data or acknowledgment of GPS system data load */
+{
+ unsigned char *buf, *buf4;
+ short dl;
+ ALM_INFO* alminfo;
+ ION_INFO* ioninfo;
+ UTC_INFO* utcinfo;
+ NAV_INFO* navinfo;
+
+ buf = rpt->buf;
+
+ if (buf[0] == 2) {
+ if (rpt->len < 4) return TRUE;
+ if (rpt->len != 4+buf[3]) return TRUE;
+ }
+ else if (rpt->len != 3) {
+ return TRUE;
+ }
+ *op_code = buf[0];
+ *data_type = buf[1];
+ *sv_prn = buf[2];
+ if (*op_code == 2) {
+ dl = buf[3];
+ *data_length = (unsigned char)dl;
+ buf4 = &buf[4];
+ switch (*data_type) {
+ case 2:
+ /* Almanac */
+ if (*data_length != sizeof (ALM_INFO)) return TRUE;
+ alminfo = (ALM_INFO*)data_packet;
+ alminfo->t_oa_raw = buf4[0];
+ alminfo->SV_health = buf4[1];
+ alminfo->e = bGetSingle(&buf4[2]);
+ alminfo->t_oa = bGetSingle(&buf4[6]);
+ alminfo->i_0 = bGetSingle(&buf4[10]);
+ alminfo->OMEGADOT = bGetSingle(&buf4[14]);
+ alminfo->sqrt_A = bGetSingle(&buf4[18]);
+ alminfo->OMEGA_0 = bGetSingle(&buf4[22]);
+ alminfo->omega = bGetSingle(&buf4[26]);
+ alminfo->M_0 = bGetSingle(&buf4[30]);
+ alminfo->a_f0 = bGetSingle(&buf4[34]);
+ alminfo->a_f1 = bGetSingle(&buf4[38]);
+ alminfo->Axis = bGetSingle(&buf4[42]);
+ alminfo->n = bGetSingle(&buf4[46]);
+ alminfo->OMEGA_n = bGetSingle(&buf4[50]);
+ alminfo->ODOT_n = bGetSingle(&buf4[54]);
+ alminfo->t_zc = bGetSingle(&buf4[58]);
+ alminfo->weeknum = bGetShort(&buf4[62]);
+ alminfo->wn_oa = bGetShort(&buf4[64]);
+ break;
+
+ case 3:
+ /* Almanac health page */
+ if (*data_length != sizeof (ALH_PARMS) + 3) return TRUE;
+
+ /* this record is returned raw */
+ memcpy (data_packet, buf4, dl);
+ break;
+
+ case 4:
+ /* Ionosphere */
+ if (*data_length != sizeof (ION_INFO) + 8) return TRUE;
+ ioninfo = (ION_INFO*)data_packet;
+ ioninfo->alpha_0 = bGetSingle (&buf4[8]);
+ ioninfo->alpha_1 = bGetSingle (&buf4[12]);
+ ioninfo->alpha_2 = bGetSingle (&buf4[16]);
+ ioninfo->alpha_3 = bGetSingle (&buf4[20]);
+ ioninfo->beta_0 = bGetSingle (&buf4[24]);
+ ioninfo->beta_1 = bGetSingle (&buf4[28]);
+ ioninfo->beta_2 = bGetSingle (&buf4[32]);
+ ioninfo->beta_3 = bGetSingle (&buf4[36]);
+ break;
+
+ case 5:
+ /* UTC */
+ if (*data_length != sizeof (UTC_INFO) + 13) return TRUE;
+ utcinfo = (UTC_INFO*)data_packet;
+ utcinfo->A_0 = bGetDouble (&buf4[13]);
+ utcinfo->A_1 = bGetSingle (&buf4[21]);
+ utcinfo->delta_t_LS = bGetShort (&buf4[25]);
+ utcinfo->t_ot = bGetSingle(&buf4[27]);
+ utcinfo->WN_t = bGetShort (&buf4[31]);
+ utcinfo->WN_LSF = bGetShort (&buf4[33]);
+ utcinfo->DN = bGetShort (&buf4[35]);
+ utcinfo->delta_t_LSF = bGetShort (&buf4[37]);
+ break;
+
+ case 6:
+ /* Ephemeris */
+ if (*data_length != sizeof (NAV_INFO) - 1) return TRUE;
+
+ navinfo = (NAV_INFO*)data_packet;
+
+ navinfo->sv_number = buf4[0];
+ navinfo->t_ephem = bGetSingle (&buf4[1]);
+ navinfo->ephclk.weeknum = bGetShort (&buf4[5]);
+
+ navinfo->ephclk.codeL2 = buf4[7];
+ navinfo->ephclk.L2Pdata = buf4[8];
+ navinfo->ephclk.SVacc_raw = buf4[9];
+ navinfo->ephclk.SV_health = buf4[10];
+ navinfo->ephclk.IODC = bGetShort (&buf4[11]);
+ navinfo->ephclk.T_GD = bGetSingle (&buf4[13]);
+ navinfo->ephclk.t_oc = bGetSingle (&buf4[17]);
+ navinfo->ephclk.a_f2 = bGetSingle (&buf4[21]);
+ navinfo->ephclk.a_f1 = bGetSingle (&buf4[25]);
+ navinfo->ephclk.a_f0 = bGetSingle (&buf4[29]);
+ navinfo->ephclk.SVacc = bGetSingle (&buf4[33]);
+
+ navinfo->ephorb.IODE = buf4[37];
+ navinfo->ephorb.fit_interval = buf4[38];
+ navinfo->ephorb.C_rs = bGetSingle (&buf4[39]);
+ navinfo->ephorb.delta_n = bGetSingle (&buf4[43]);
+ navinfo->ephorb.M_0 = bGetDouble (&buf4[47]);
+ navinfo->ephorb.C_uc = bGetSingle (&buf4[55]);
+ navinfo->ephorb.e = bGetDouble (&buf4[59]);
+ navinfo->ephorb.C_us = bGetSingle (&buf4[67]);
+ navinfo->ephorb.sqrt_A = bGetDouble (&buf4[71]);
+ navinfo->ephorb.t_oe = bGetSingle (&buf4[79]);
+ navinfo->ephorb.C_ic = bGetSingle (&buf4[83]);
+ navinfo->ephorb.OMEGA_0 = bGetDouble (&buf4[87]);
+ navinfo->ephorb.C_is = bGetSingle (&buf4[95]);
+ navinfo->ephorb.i_0 = bGetDouble (&buf4[99]);
+ navinfo->ephorb.C_rc = bGetSingle (&buf4[107]);
+ navinfo->ephorb.omega = bGetDouble (&buf4[111]);
+ navinfo->ephorb.OMEGADOT=bGetSingle (&buf4[119]);
+ navinfo->ephorb.IDOT = bGetSingle (&buf4[123]);
+ navinfo->ephorb.Axis = bGetDouble (&buf4[127]);
+ navinfo->ephorb.n = bGetDouble (&buf4[135]);
+ navinfo->ephorb.r1me2 = bGetDouble (&buf4[143]);
+ navinfo->ephorb.OMEGA_n=bGetDouble (&buf4[151]);
+ navinfo->ephorb.ODOT_n = bGetDouble (&buf4[159]);
+ break;
+ }
+ }
+ return FALSE;
+}
+
+short rpt_0x59 (TSIPPKT *rpt,
+ unsigned char *code_type,
+ unsigned char status_code[32])
+/* satellite enable/disable or health heed/ignore list */
+{
+ short iprn;
+ unsigned char *buf;
+ buf = rpt->buf;
+
+ if (rpt->len != 33) return TRUE;
+ *code_type = buf[0];
+ for (iprn = 0; iprn < 32; iprn++)
+ status_code[iprn] = buf[iprn + 1];
+ return FALSE;
+}
+
+short rpt_0x5A (TSIPPKT *rpt,
+ unsigned char *sv_prn,
+ float *sample_length,
+ float *signal_level,
+ float *code_phase,
+ float *Doppler,
+ double *time_of_fix)
+/* raw measurement data - code phase/Doppler */
+{
+ unsigned char *buf;
+ buf = rpt->buf;
+
+ if (rpt->len != 25) return TRUE;
+ *sv_prn = buf[0];
+ *sample_length = bGetSingle (&buf[1]);
+ *signal_level = bGetSingle (&buf[5]);
+ *code_phase = bGetSingle (&buf[9]);
+ *Doppler = bGetSingle (&buf[13]);
+ *time_of_fix = bGetDouble (&buf[17]);
+ return FALSE;
+}
+
+short rpt_0x5B (TSIPPKT *rpt,
+ unsigned char *sv_prn,
+ unsigned char *sv_health,
+ unsigned char *sv_iode,
+ unsigned char *fit_interval_flag,
+ float *time_of_collection,
+ float *time_of_eph,
+ float *sv_accy)
+/* satellite ephorb status */
+{
+ unsigned char *buf;
+ buf = rpt->buf;
+
+ if (rpt->len != 16) return TRUE;
+ *sv_prn = buf[0];
+ *time_of_collection = bGetSingle (&buf[1]);
+ *sv_health = buf[5];
+ *sv_iode = buf[6];
+ *time_of_eph = bGetSingle (&buf[7]);
+ *fit_interval_flag = buf[11];
+ *sv_accy = bGetSingle (&buf[12]);
+ return FALSE;
+}
+
+short rpt_0x5C (TSIPPKT *rpt,
+ unsigned char *sv_prn,
+ unsigned char *slot,
+ unsigned char *chan,
+ unsigned char *acq_flag,
+ unsigned char *eph_flag,
+ float *signal_level,
+ float *time_of_last_msmt,
+ float *elev,
+ float *azim,
+ unsigned char *old_msmt_flag,
+ unsigned char *integer_msec_flag,
+ unsigned char *bad_data_flag,
+ unsigned char *data_collect_flag)
+/* satellite tracking status */
+{
+ unsigned char *buf;
+ buf = rpt->buf;
+
+ if (rpt->len != 24) return TRUE;
+ *sv_prn = buf[0];
+ *slot = (unsigned char)((buf[1] & 0x07) + 1);
+ *chan = (unsigned char)(buf[1] >> 3);
+ if (*chan == 0x10) *chan = 2;
+ else (*chan)++;
+ *acq_flag = buf[2];
+ *eph_flag = buf[3];
+ *signal_level = bGetSingle (&buf[4]);
+ *time_of_last_msmt = bGetSingle (&buf[8]);
+ *elev = bGetSingle (&buf[12]);
+ *azim = bGetSingle (&buf[16]);
+ *old_msmt_flag = buf[20];
+ *integer_msec_flag = buf[21];
+ *bad_data_flag = buf[22];
+ *data_collect_flag = buf[23];
+ return FALSE;
+}
+
+/**/
+short rpt_0x6D (TSIPPKT *rpt,
+ unsigned char *manual_mode,
+ unsigned char *nsvs,
+ unsigned char *ndim,
+ unsigned char sv_prn[],
+ float *pdop,
+ float *hdop,
+ float *vdop,
+ float *tdop)
+/* over-determined satellite selection for position fixes, PDOP, fix mode */
+{
+ short islot;
+ unsigned char *buf;
+ buf = rpt->buf;
+
+ *nsvs = (unsigned char)((buf[0] & 0xF0) >> 4);
+ if ((*nsvs)>8) return TRUE;
+ if (rpt->len != 17 + (*nsvs) ) return TRUE;
+
+ *manual_mode = (unsigned char)(buf[0] & 0x08);
+ *ndim = (unsigned char)((buf[0] & 0x07));
+ *pdop = bGetSingle (&buf[1]);
+ *hdop = bGetSingle (&buf[5]);
+ *vdop = bGetSingle (&buf[9]);
+ *tdop = bGetSingle (&buf[13]);
+ for (islot = 0; islot < (*nsvs); islot++)
+ sv_prn[islot] = buf[islot + 17];
+ return FALSE;
+}
+
+/**/
+short rpt_0x82 (TSIPPKT *rpt,
+ unsigned char *diff_mode)
+/* differential fix mode */
+{
+ unsigned char *buf;
+ buf = rpt->buf;
+
+ if (rpt->len != 1) return TRUE;
+ *diff_mode = buf[0];
+ return FALSE;
+}
+
+short rpt_0x83 (TSIPPKT *rpt,
+ double ECEF_pos[3],
+ double *clock_bias,
+ float *time_of_fix)
+/* position, ECEF double precision */
+{
+ unsigned char *buf;
+ buf = rpt->buf;
+
+ if (rpt->len != 36) return TRUE;
+ ECEF_pos[0] = bGetDouble (buf);
+ ECEF_pos[1] = bGetDouble (&buf[8]);
+ ECEF_pos[2] = bGetDouble (&buf[16]);
+ *clock_bias = bGetDouble (&buf[24]);
+ *time_of_fix = bGetSingle (&buf[32]);
+ return FALSE;
+}
+
+short rpt_0x84 (TSIPPKT *rpt,
+ double *lat,
+ double *lon,
+ double *alt,
+ double *clock_bias,
+ float *time_of_fix)
+/* position, lat-lon-alt double precision */
+{
+ unsigned char *buf;
+ buf = rpt->buf;
+
+ if (rpt->len != 36) return TRUE;
+ *lat = bGetDouble (buf);
+ *lon = bGetDouble (&buf[8]);
+ *alt = bGetDouble (&buf[16]);
+ *clock_bias = bGetDouble (&buf[24]);
+ *time_of_fix = bGetSingle (&buf[32]);
+ return FALSE;
+}
+
+short rpt_Paly0xBB(TSIPPKT *rpt,
+ TSIP_RCVR_CFG *TsipxBB)
+{
+
+ unsigned char *buf;
+ buf = rpt->buf;
+
+ /* Palisade is inconsistent with other TSIP, which has a kength of 40 */
+ /* if (rpt->len != 40) return TRUE; */
+ if (rpt->len != 43) return TRUE;
+
+ TsipxBB->bSubcode = buf[0];
+ TsipxBB->operating_mode = buf[1] ;
+ TsipxBB->dyn_code = buf[3] ;
+ TsipxBB->elev_mask = bGetSingle (&buf[5]);
+ TsipxBB->cno_mask = bGetSingle (&buf[9]);
+ TsipxBB->dop_mask = bGetSingle (&buf[13]);
+ TsipxBB->dop_switch = bGetSingle (&buf[17]);
+ return FALSE;
+}
+
+short rpt_0xBC (TSIPPKT *rpt,
+ unsigned char *port_num,
+ unsigned char *in_baud,
+ unsigned char *out_baud,
+ unsigned char *data_bits,
+ unsigned char *parity,
+ unsigned char *stop_bits,
+ unsigned char *flow_control,
+ unsigned char *protocols_in,
+ unsigned char *protocols_out,
+ unsigned char *reserved)
+/* Receiver serial port configuration */
+{
+ unsigned char *buf;
+ buf = rpt->buf;
+
+ if (rpt->len != 10) return TRUE;
+ *port_num = buf[0];
+ *in_baud = buf[1];
+ *out_baud = buf[2];
+ *data_bits = buf[3];
+ *parity = buf[4];
+ *stop_bits = buf[5];
+ *flow_control = buf[6];
+ *protocols_in = buf[7];
+ *protocols_out = buf[8];
+ *reserved = buf[9];
+
+ return FALSE;
+}
+
+/**** Superpackets ****/
+
+short rpt_0x8F0B(TSIPPKT *rpt,
+ unsigned short *event,
+ double *tow,
+ unsigned char *date,
+ unsigned char *month,
+ short *year,
+ unsigned char *dim_mode,
+ short *utc_offset,
+ double *bias,
+ double *drift,
+ float *bias_unc,
+ float *dr_unc,
+ double *lat,
+ double *lon,
+ double *alt,
+ char sv_id[8])
+{
+ short local_index;
+ unsigned char *buf;
+
+ buf = rpt->buf;
+ if (rpt->len != 74) return TRUE;
+ *event = bGetShort(&buf[1]);
+ *tow = bGetDouble(&buf[3]);
+ *date = buf[11];
+ *month = buf[12];
+ *year = bGetShort(&buf[13]);
+ *dim_mode = buf[15];
+ *utc_offset = bGetShort(&buf[16]);
+ *bias = bGetDouble(&buf[18]);
+ *drift = bGetDouble(&buf[26]);
+ *bias_unc = bGetSingle(&buf[34]);
+ *dr_unc = bGetSingle(&buf[38]);
+ *lat = bGetDouble(&buf[42]);
+ *lon = bGetDouble(&buf[50]);
+ *alt = bGetDouble(&buf[58]);
+
+ for (local_index=0; local_index<8; local_index++) sv_id[local_index] = buf[local_index + 66];
+ return FALSE;
+}
+
+short rpt_0x8F14 (TSIPPKT *rpt,
+ short *datum_idx,
+ double datum_coeffs[5])
+/* datum index and coefficients */
+{
+ unsigned char *buf;
+ buf = rpt->buf;
+
+ if (rpt->len != 43) return TRUE;
+ *datum_idx = bGetShort(&buf[1]);
+ datum_coeffs[0] = bGetDouble (&buf[3]);
+ datum_coeffs[1] = bGetDouble (&buf[11]);
+ datum_coeffs[2] = bGetDouble (&buf[19]);
+ datum_coeffs[3] = bGetDouble (&buf[27]);
+ datum_coeffs[4] = bGetDouble (&buf[35]);
+ return FALSE;
+}
+
+
+short rpt_0x8F15 (TSIPPKT *rpt,
+ short *datum_idx,
+ double datum_coeffs[5])
+/* datum index and coefficients */
+{
+ unsigned char *buf;
+ buf = rpt->buf;
+
+ if (rpt->len != 43) return TRUE;
+ *datum_idx = bGetShort(&buf[1]);
+ datum_coeffs[0] = bGetDouble (&buf[3]);
+ datum_coeffs[1] = bGetDouble (&buf[11]);
+ datum_coeffs[2] = bGetDouble (&buf[19]);
+ datum_coeffs[3] = bGetDouble (&buf[27]);
+ datum_coeffs[4] = bGetDouble (&buf[35]);
+ return FALSE;
+}
+
+
+#define MAX_LONG (2147483648.) /* 2**31 */
+
+short rpt_0x8F20 (TSIPPKT *rpt,
+ unsigned char *info,
+ double *lat,
+ double *lon,
+ double *alt,
+ double vel_enu[],
+ double *time_of_fix,
+ short *week_num,
+ unsigned char *nsvs,
+ unsigned char sv_prn[],
+ short sv_IODC[],
+ short *datum_index)
+{
+ short
+ isv;
+ unsigned char
+ *buf, prnx, iode;
+ unsigned long
+ ulongtemp;
+ long
+ longtemp;
+ double
+ vel_scale;
+
+ buf = rpt->buf;
+
+ if (rpt->len != 56) return TRUE;
+
+ vel_scale = (buf[24]&1)? 0.020 : 0.005;
+ vel_enu[0] = bGetShort (buf+2)*vel_scale;
+ vel_enu[1] = bGetShort (buf+4)*vel_scale;
+ vel_enu[2] = bGetShort (buf+6)*vel_scale;
+
+ *time_of_fix = bGetULong (buf+8)*.001;
+
+ longtemp = bGetLong (buf+12);
+ *lat = longtemp*(GPS_PI/MAX_LONG);
+
+ ulongtemp = bGetULong (buf+16);
+ *lon = ulongtemp*(GPS_PI/MAX_LONG);
+ if (*lon > GPS_PI) *lon -= 2.0*GPS_PI;
+
+ *alt = bGetLong (buf+20)*.001;
+ /* 25 blank; 29 = UTC */
+ (*datum_index) = (short)((short)buf[26]-1);
+ *info = buf[27];
+ *nsvs = buf[28];
+ *week_num = bGetShort (&buf[30]);
+ for (isv = 0; isv < 8; isv++) {
+ prnx = buf[32+2*isv];
+ sv_prn[isv] = (unsigned char)(prnx&0x3F);
+ iode = buf[33+2*isv];
+ sv_IODC[isv] = (short)(iode | ((prnx>>6)<<8));
+ }
+ return FALSE;
+}
+
+short rpt_0x8F41 (TSIPPKT *rpt,
+ unsigned char *bSearchRange,
+ unsigned char *bBoardOptions,
+ unsigned long *iiSerialNumber,
+ unsigned char *bBuildYear,
+ unsigned char *bBuildMonth,
+ unsigned char *bBuildDay,
+ unsigned char *bBuildHour,
+ float *fOscOffset,
+ unsigned short *iTestCodeId)
+{
+ if(rpt->len != 17) return FALSE;
+ *bSearchRange = rpt->buf[1];
+ *bBoardOptions = rpt->buf[2];
+ *iiSerialNumber = bGetLong(&rpt->buf[3]);
+ *bBuildYear = rpt->buf[7];
+ *bBuildMonth = rpt->buf[8];
+ *bBuildDay = rpt->buf[9];
+ *bBuildHour = rpt->buf[10];
+ *fOscOffset = bGetSingle(&rpt->buf[11]);
+ *iTestCodeId = bGetShort(&rpt->buf[15]);
+/* Tsipx8E41Data = *Tsipx8E41; */
+ return TRUE;
+}
+
+short rpt_0x8F42 (TSIPPKT *rpt,
+ unsigned char *bProdOptionsPre,
+ unsigned char *bProdNumberExt,
+ unsigned short *iCaseSerialNumberPre,
+ unsigned long *iiCaseSerialNumber,
+ unsigned long *iiProdNumber,
+ unsigned short *iPremiumOptions,
+ unsigned short *iMachineID,
+ unsigned short *iKey)
+{
+ if(rpt->len != 19) return FALSE;
+ *bProdOptionsPre = rpt->buf[1];
+ *bProdNumberExt = rpt->buf[2];
+ *iCaseSerialNumberPre = bGetShort(&rpt->buf[3]);
+ *iiCaseSerialNumber = bGetLong(&rpt->buf[5]);
+ *iiProdNumber = bGetLong(&rpt->buf[9]);
+ *iPremiumOptions = bGetShort(&rpt->buf[13]);
+ *iMachineID = bGetShort(&rpt->buf[15]);
+ *iKey = bGetShort(&rpt->buf[17]);
+ return TRUE;
+}
+
+short rpt_0x8F45(TSIPPKT *rpt,
+ unsigned char *bSegMask)
+{
+ if(rpt->len != 2) return FALSE;
+ *bSegMask = rpt->buf[1];
+ return TRUE;
+}
+
+short rpt_0x8F4A_16(TSIPPKT *rpt,
+ unsigned char *pps_enabled,
+ unsigned char *pps_timebase,
+ unsigned char *pos_polarity,
+ double *pps_offset,
+ float *bias_unc_threshold)
+/* Stinger PPS definition */
+{
+ unsigned char
+ *buf;
+
+ buf = rpt->buf;
+ if (rpt->len != 16) return TRUE;
+ *pps_enabled = buf[1];
+ *pps_timebase = buf[2];
+ *pos_polarity = buf[3];
+ *pps_offset = bGetDouble(&buf[4]);
+ *bias_unc_threshold = bGetSingle(&buf[12]);
+ return FALSE;
+}
+
+short rpt_0x8F4B(TSIPPKT *rpt,
+ unsigned long *decorr_max)
+{
+ unsigned char
+ *buf;
+
+ buf = rpt->buf;
+ if (rpt->len != 5) return TRUE;
+ *decorr_max = bGetLong(&buf[1]);
+ return FALSE;
+}
+
+short rpt_0x8F4D(TSIPPKT *rpt,
+ unsigned long *event_mask)
+{
+ unsigned char
+ *buf;
+
+ buf = rpt->buf;
+ if (rpt->len != 5) return TRUE;
+ *event_mask = bGetULong (&buf[1]);
+ return FALSE;
+}
+
+short rpt_0x8FA5(TSIPPKT *rpt,
+ unsigned char *spktmask)
+{
+ unsigned char
+ *buf;
+
+ buf = rpt->buf;
+ if (rpt->len != 5) return TRUE;
+ spktmask[0] = buf[1];
+ spktmask[1] = buf[2];
+ spktmask[2] = buf[3];
+ spktmask[3] = buf[4];
+ return FALSE;
+}
+
+short rpt_0x8FAD (TSIPPKT *rpt,
+ unsigned short *COUNT,
+ double *FracSec,
+ unsigned char *Hour,
+ unsigned char *Minute,
+ unsigned char *Second,
+ unsigned char *Day,
+ unsigned char *Month,
+ unsigned short *Year,
+ unsigned char *Status,
+ unsigned char *Flags)
+{
+
+ if (rpt->len != 22) return TRUE;
+
+ *COUNT = bGetUShort(&rpt->buf[1]);
+ *FracSec = bGetDouble(&rpt->buf[3]);
+ *Hour = rpt->buf[11];
+ *Minute = rpt->buf[12];
+ *Second = rpt->buf[13];
+ *Day = rpt->buf[14];
+ *Month = rpt->buf[15];
+ *Year = bGetUShort(&rpt->buf[16]);
+ *Status = rpt->buf[18];
+ *Flags = rpt->buf[19];
+ return FALSE;
+}
+
+
+/*
+ * *************************************************************************
+ *
+ * Trimble Navigation, Ltd.
+ * OEM Products Development Group
+ * P.O. Box 3642
+ * 645 North Mary Avenue
+ * Sunnyvale, California 94088-3642
+ *
+ * Corporate Headquarter:
+ * Telephone: (408) 481-8000
+ * Fax: (408) 481-6005
+ *
+ * Technical Support Center:
+ * Telephone: (800) 767-4822 (U.S. and Canada)
+ * (408) 481-6940 (outside U.S. and Canada)
+ * Fax: (408) 481-6020
+ * BBS: (408) 481-7800
+ * e-mail: trimble_support@trimble.com
+ * ftp://ftp.trimble.com/pub/sct/embedded/bin
+ *
+ * *************************************************************************
+ *
+ * T_REPORT.C consists of a primary function TranslateTSIPReportToText()
+ * called by main().
+ *
+ * This function takes a character buffer that has been received as a report
+ * from a TSIP device and interprets it. The character buffer has been
+ * assembled using tsip_input_proc() in T_PARSER.C.
+ *
+ * A large case statement directs processing to one of many mid-level
+ * functions. The mid-level functions specific to the current report
+ * code passes the report buffer to the appropriate report decoder
+ * rpt_0x?? () in T_PARSER.C, which converts the byte stream in rpt.buf
+ * to data values approporaite for use.
+ *
+ * *************************************************************************
+ *
+ */
+
+
+#define GOOD_PARSE 0
+#define BADID_PARSE 1
+#define BADLEN_PARSE 2
+#define BADDATA_PARSE 3
+
+#define B_TSIP 0x02
+#define B_NMEA 0x04
+
+
+/* pbuf is the pointer to the current location of the text output */
+static char
+ *pbuf;
+
+/* keep track of whether the message has been successfully parsed */
+static short
+ parsed;
+
+
+/* convert time of week into day-hour-minute-second and print */
+char* show_time (float time_of_week)
+{
+ short days, hours, minutes;
+ float seconds;
+ double tow = 0;
+ static char timestring [80];
+
+ if (time_of_week == -1.0)
+ {
+ sprintf(timestring, " <No time yet> ");
+ }
+ else if ((time_of_week >= 604800.0) || (time_of_week < 0.0))
+ {
+ sprintf(timestring, " <Bad time> ");
+ }
+ else
+ {
+ if (time_of_week < 604799.9)
+ tow = time_of_week + .00000001;
+ seconds = (float)fmod(tow, 60.);
+ minutes = (short) fmod(tow/60., 60.);
+ hours = (short)fmod(tow / 3600., 24.);
+ days = (short)(tow / 86400.0);
+ sprintf(timestring, " %s %02d:%02d:%05.2f ",
+ dayname[days], hours, minutes, seconds);
+ }
+ return timestring;
+}
+
+/**/
+/* 0x3D */
+static void rpt_chan_A_config (TSIPPKT *rpt)
+{
+ unsigned char
+ tx_baud_index, rx_baud_index,
+ char_format_index, stop_bits,
+ tx_mode_index, rx_mode_index,
+ databits, parity;
+ int
+ i, nbaud;
+
+ /* unload rptbuf */
+ if (rpt_0x3D (rpt,
+ &tx_baud_index, &rx_baud_index, &char_format_index,
+ &stop_bits, &tx_mode_index, &rx_mode_index)) {
+ parsed = BADLEN_PARSE;
+ return;
+ }
+
+ pbuf += sprintf(pbuf, "\nChannel A Configuration");
+
+ nbaud = sizeof(old_baudnum);
+
+ for (i = 0; i < nbaud; ++i) if (tx_baud_index == old_baudnum[i]) break;
+ pbuf += sprintf(pbuf, "\n Transmit speed: %s at %s",
+ old_output_ch[tx_mode_index], st_baud_text_app[i]);
+
+ for (i = 0; i < nbaud; ++i) if (rx_baud_index == old_baudnum[i]) break;
+ pbuf += sprintf(pbuf, "\n Receive speed: %s at %s",
+ old_input_ch[rx_mode_index], st_baud_text_app[i]);
+
+ databits = (unsigned char)((char_format_index & 0x03) + 5);
+
+ parity = (unsigned char)(char_format_index >> 2);
+ if (parity > 4) parity = 2;
+
+ pbuf += sprintf(pbuf, "\n Character format (bits/char, parity, stop bits): %d-%s-%d",
+ databits, old_parity_text[parity], stop_bits);
+}
+
+/**/
+/* 0x40 */
+static void rpt_almanac_data_page (TSIPPKT *rpt)
+{
+ unsigned char
+ sv_prn;
+ short
+ week_num;
+ float
+ t_zc,
+ eccentricity,
+ t_oa,
+ i_0,
+ OMEGA_dot,
+ sqrt_A,
+ OMEGA_0,
+ omega,
+ M_0;
+
+ /* unload rptbuf */
+ if (rpt_0x40 (rpt,
+ &sv_prn, &week_num, &t_zc, &eccentricity, &t_oa,
+ &i_0, &OMEGA_dot, &sqrt_A, &OMEGA_0, &omega, &M_0)) {
+ parsed = BADLEN_PARSE;
+ return;
+ }
+
+ pbuf += sprintf(pbuf, "\nAlmanac for SV %02d", sv_prn);
+ pbuf += sprintf(pbuf, "\n Captured:%15.0f %s",
+ t_zc, show_time (t_zc));
+ pbuf += sprintf(pbuf, "\n week:%15d", week_num);
+ pbuf += sprintf(pbuf, "\n Eccentricity:%15g", eccentricity);
+ pbuf += sprintf(pbuf, "\n T_oa:%15.0f %s",
+ t_oa, show_time (t_oa));
+ pbuf += sprintf(pbuf, "\n i 0:%15g", i_0);
+ pbuf += sprintf(pbuf, "\n OMEGA dot:%15g", OMEGA_dot);
+ pbuf += sprintf(pbuf, "\n sqrt A:%15g", sqrt_A);
+ pbuf += sprintf(pbuf, "\n OMEGA 0:%15g", OMEGA_0);
+ pbuf += sprintf(pbuf, "\n omega:%15g", omega);
+ pbuf += sprintf(pbuf, "\n M 0:%15g", M_0);
+}
+
+/* 0x41 */
+static void rpt_GPS_time (TSIPPKT *rpt)
+{
+ float
+ time_of_week, UTC_offset;
+ short
+ week_num;
+
+ /* unload rptbuf */
+ if (rpt_0x41 (rpt, &time_of_week, &UTC_offset, &week_num)) {
+ parsed = BADLEN_PARSE;
+ return;
+ }
+
+ pbuf += sprintf(pbuf, "\nGPS time:%s GPS week: %d UTC offset %.1f",
+ show_time(time_of_week), week_num, UTC_offset);
+
+}
+
+/* 0x42 */
+static void rpt_single_ECEF_position (TSIPPKT *rpt)
+{
+ float
+ ECEF_pos[3], time_of_fix;
+
+ /* unload rptbuf */
+ if (rpt_0x42 (rpt, ECEF_pos, &time_of_fix)) {
+ parsed = BADLEN_PARSE;
+ return;
+ }
+
+ pbuf += sprintf(pbuf, "\nSXYZ: %15.0f %15.0f %15.0f %s",
+ ECEF_pos[0], ECEF_pos[1], ECEF_pos[2],
+ show_time(time_of_fix));
+}
+
+/* 0x43 */
+static void rpt_single_ECEF_velocity (TSIPPKT *rpt)
+{
+
+ float
+ ECEF_vel[3], freq_offset, time_of_fix;
+
+ /* unload rptbuf */
+ if (rpt_0x43 (rpt, ECEF_vel, &freq_offset, &time_of_fix)) {
+ parsed = BADLEN_PARSE;
+ return;
+ }
+
+ pbuf += sprintf(pbuf, "\nVelECEF: %11.3f %11.3f %11.3f %12.3f%s",
+ ECEF_vel[0], ECEF_vel[1], ECEF_vel[2], freq_offset,
+ show_time(time_of_fix));
+}
+
+/* 0x45 */
+static void rpt_SW_version (TSIPPKT *rpt) {
+ unsigned char
+ major_nav_version, minor_nav_version,
+ nav_day, nav_month, nav_year,
+ major_dsp_version, minor_dsp_version,
+ dsp_day, dsp_month, dsp_year;
+
+ /* unload rptbuf */
+ if (rpt_0x45 (rpt,
+ &major_nav_version, &minor_nav_version,
+ &nav_day, &nav_month, &nav_year,
+ &major_dsp_version, &minor_dsp_version,
+ &dsp_day, &dsp_month, &dsp_year)) {
+ parsed = BADLEN_PARSE;
+ return;
+ }
+
+ pbuf += sprintf(pbuf,
+"\nFW Versions: Nav Proc %2d.%02d %2d/%2d/%2d Sig Proc %2d.%02d %2d/%2d/%2d",
+ major_nav_version, minor_nav_version, nav_day, nav_month, nav_year,
+ major_dsp_version, minor_dsp_version, dsp_day, dsp_month, dsp_year);
+}
+
+/* 0x46 */
+static void rpt_rcvr_health (TSIPPKT *rpt)
+{
+ unsigned char
+ status1, status2;
+ static char
+ *sc_text[] = {
+ "Doing position fixes",
+ "Don't have GPS time yet",
+ "Waiting for almanac collection",
+ "DOP too high ",
+ "No satellites available",
+ "Only 1 satellite available",
+ "Only 2 satellites available",
+ "Only 3 satellites available",
+ "No satellites usable ",
+ "Only 1 satellite usable",
+ "Only 2 satellites usable",
+ "Only 3 satellites usable",
+ "Chosen satellite unusable"};
+
+
+ /* unload rptbuf */
+ if (rpt_0x46 (rpt, &status1, &status2))
+ {
+ parsed = BADLEN_PARSE;
+ return;
+ }
+
+ pbuf += sprintf(pbuf, "\nRcvr status1: %s (%02Xh); ",
+ sc_text[rpt->buf[0]], status1);
+
+ pbuf += sprintf(pbuf, "status2: %s, %s (%02Xh)",
+ (status2 & 0x01)?"No BBRAM":"BBRAM OK",
+ (status2 & 0x10)?"No Ant":"Ant OK",
+ status2);
+}
+
+/* 0x47 */
+static void rpt_SNR_all_SVs (TSIPPKT *rpt)
+{
+ unsigned char
+ nsvs, sv_prn[12];
+ short
+ isv;
+ float
+ snr[12];
+
+ /* unload rptbuf */
+ if (rpt_0x47 (rpt, &nsvs, sv_prn, snr))
+ {
+ parsed = BADLEN_PARSE;
+ return;
+ }
+
+ pbuf += sprintf(pbuf, "\nSNR for satellites: %d", nsvs);
+ for (isv = 0; isv < nsvs; isv++)
+ {
+ pbuf += sprintf(pbuf, "\n SV %02d %6.2f",
+ sv_prn[isv], snr[isv]);
+ }
+}
+
+/* 0x48 */
+static void rpt_GPS_system_message (TSIPPKT *rpt)
+{
+ unsigned char
+ message[23];
+
+ /* unload rptbuf */
+ if (rpt_0x48 (rpt, message))
+ {
+ parsed = BADLEN_PARSE;
+ return;
+ }
+
+ pbuf += sprintf(pbuf, "\nGPS message: %s", message);
+}
+
+/* 0x49 */
+static void rpt_almanac_health_page (TSIPPKT *rpt)
+{
+ short
+ iprn;
+ unsigned char
+ sv_health [32];
+
+ /* unload rptbuf */
+ if (rpt_0x49 (rpt, sv_health))
+ {
+ parsed = BADLEN_PARSE;
+ return;
+ }
+
+ pbuf += sprintf(pbuf, "\nAlmanac health page:");
+ for (iprn = 0; iprn < 32; iprn++)
+ {
+ if (!(iprn%5)) *pbuf++ = '\n';
+ pbuf += sprintf(pbuf, " SV%02d %2X",
+ (iprn+1) , sv_health[iprn]);
+ }
+}
+
+/* 0x4A */
+static void rpt_single_lla_position (TSIPPKT *rpt) {
+ short
+ lat_deg, lon_deg;
+ float
+ lat, lon,
+ alt, clock_bias, time_of_fix;
+ double lat_min, lon_min;
+ unsigned char
+ north_south, east_west;
+
+ if (rpt_0x4A (rpt,
+ &lat, &lon, &alt, &clock_bias, &time_of_fix))
+ {
+ parsed = BADLEN_PARSE;
+ return;
+ }
+
+ /* convert from radians to degrees */
+ lat *= (float)R2D;
+ north_south = 'N';
+ if (lat < 0.0)
+ {
+ north_south = 'S';
+ lat = -lat;
+ }
+ lat_deg = (short)lat;
+ lat_min = (lat - lat_deg) * 60.0;
+
+ lon *= (float)R2D;
+ east_west = 'E';
+ if (lon < 0.0)
+ {
+ east_west = 'W';
+ lon = -lon;
+ }
+ lon_deg = (short)lon;
+ lon_min = (lon - lon_deg) * 60.0;
+
+ pbuf += sprintf(pbuf, "\nSLLA: %4d: %06.3f %c%5d:%06.3f %c%10.2f %12.2f%s",
+ lat_deg, lat_min, north_south,
+ lon_deg, lon_min, east_west,
+ alt, clock_bias,
+ show_time(time_of_fix));
+}
+
+/* 0x4A */
+static void rpt_ref_alt (TSIPPKT *rpt) {
+
+ float
+ alt, dummy;
+ unsigned char
+ alt_flag;
+
+ if (rpt_0x4A_2 (rpt,
+ &alt, &dummy, &alt_flag))
+ {
+ parsed = BADLEN_PARSE;
+ return;
+ }
+
+ pbuf += sprintf(pbuf, "\nReference Alt: %.1f m; %s",
+ alt, alt_flag?"ON":"OFF");
+}
+
+/* 0x4B */
+static void rpt_rcvr_id_and_status (TSIPPKT *rpt)
+{
+
+ unsigned char
+ machine_id, status3, status4;
+
+ /* unload rptbuf */
+ if (rpt_0x4B (rpt, &machine_id, &status3, &status4))
+ {
+ parsed = BADLEN_PARSE;
+ return;
+ }
+
+ pbuf += sprintf(pbuf, "\nRcvr Machine ID: %d; Status3 = %s, %s (%02Xh)",
+ machine_id,
+ (status3 & 0x02)?"No RTC":"RTC OK",
+ (status3 & 0x08)?"No Alm":"Alm OK",
+ status3);
+}
+
+/* 0x4C */
+static void rpt_operating_parameters (TSIPPKT *rpt)
+{
+ unsigned char
+ dyn_code;
+ float
+ el_mask, snr_mask, dop_mask, dop_switch;
+
+ /* unload rptbuf */
+ if (rpt_0x4C (rpt, &dyn_code, &el_mask,
+ &snr_mask, &dop_mask, &dop_switch))
+ {
+ parsed = BADLEN_PARSE;
+ return;
+ }
+
+ pbuf += sprintf(pbuf, "\nOperating Parameters:");
+ pbuf += sprintf(pbuf, "\n Dynamics code = %d %s",
+ dyn_code, dyn_text[dyn_code]);
+ pbuf += sprintf(pbuf, "\n Elevation mask = %.2fø", el_mask * R2D);
+ pbuf += sprintf(pbuf, "\n SNR mask = %.2f", snr_mask);
+ pbuf += sprintf(pbuf, "\n DOP mask = %.2f", dop_mask);
+ pbuf += sprintf(pbuf, "\n DOP switch = %.2f", dop_switch);
+}
+
+/* 0x4D */
+static void rpt_oscillator_offset (TSIPPKT *rpt)
+{
+ float
+ osc_offset;
+
+ /* unload rptbuf */
+ if (rpt_0x4D (rpt, &osc_offset))
+ {
+ parsed = BADLEN_PARSE;
+ return;
+ }
+
+ pbuf += sprintf(pbuf, "\nOscillator offset: %.2f Hz = %.3f PPM",
+ osc_offset, osc_offset/1575.42);
+}
+
+/* 0x4E */
+static void rpt_GPS_time_set_response (TSIPPKT *rpt)
+{
+
+ unsigned char
+ response;
+
+ /* unload rptbuf */
+ if (rpt_0x4E (rpt, &response))
+ {
+ parsed = BADLEN_PARSE;
+ return;
+ }
+
+ switch (response)
+ {
+ case 'Y':
+ pbuf += sprintf(pbuf, "\nTime set accepted");
+ break;
+
+ case 'N':
+ pbuf += sprintf(pbuf, "\nTime set rejected or not required");
+ break;
+
+ default:
+ parsed = BADDATA_PARSE;
+ }
+}
+
+/* 0x4F */
+static void rpt_UTC_offset (TSIPPKT *rpt)
+{
+ double
+ a0;
+ float
+ a1, time_of_data;
+ short
+ dt_ls, wn_t, wn_lsf, dn, dt_lsf;
+
+ /* unload rptbuf */
+ if (rpt_0x4F (rpt, &a0, &a1, &time_of_data,
+ &dt_ls, &wn_t, &wn_lsf, &dn, &dt_lsf)) {
+ parsed = BADLEN_PARSE;
+ return;
+ }
+
+ pbuf += sprintf(pbuf, "\nUTC Correction Data");
+ pbuf += sprintf(pbuf, "\n A_0 = %g ", a0);
+ pbuf += sprintf(pbuf, "\n A_1 = %g ", a1);
+ pbuf += sprintf(pbuf, "\n delta_t_LS = %d ", dt_ls);
+ pbuf += sprintf(pbuf, "\n t_ot = %.0f ", time_of_data);
+ pbuf += sprintf(pbuf, "\n WN_t = %d ", wn_t );
+ pbuf += sprintf(pbuf, "\n WN_LSF = %d ", wn_lsf );
+ pbuf += sprintf(pbuf, "\n DN = %d ", dn );
+ pbuf += sprintf(pbuf, "\n delta_t_LSF = %d ", dt_lsf );
+}
+
+/**/
+/* 0x54 */
+static void rpt_1SV_bias (TSIPPKT *rpt)
+{
+ float
+ clock_bias, freq_offset, time_of_fix;
+
+ /* unload rptbuf */
+ if (rpt_0x54 (rpt, &clock_bias, &freq_offset, &time_of_fix)) {
+ parsed = BADLEN_PARSE;
+ return;
+ }
+
+ pbuf += sprintf (pbuf, "\nTime Fix Clock Bias: %6.2f m Freq Bias: %6.2f m/s%s",
+ clock_bias, freq_offset, show_time (time_of_fix));
+}
+
+/* 0x55 */
+static void rpt_io_opt (TSIPPKT *rpt)
+{
+ unsigned char
+ pos_code, vel_code, time_code, aux_code;
+
+ /* unload rptbuf */
+ if (rpt_0x55 (rpt,
+ &pos_code, &vel_code, &time_code, &aux_code)) {
+ parsed = BADLEN_PARSE;
+ return;
+ }
+ /* rptbuf unloaded */
+
+ pbuf += sprintf(pbuf, "\nI/O Options: %2X %2X %2X %2X",
+ pos_code, vel_code, time_code, aux_code);
+
+ if (pos_code & 0x01) {
+ pbuf += sprintf(pbuf, "\n ECEF XYZ position output");
+ }
+
+ if (pos_code & 0x02) {
+ pbuf += sprintf(pbuf, "\n LLA position output");
+ }
+
+ pbuf += sprintf(pbuf, (pos_code & 0x04)?
+ "\n MSL altitude output (Geoid height) ":
+ "\n WGS-84 altitude output");
+
+ pbuf += sprintf(pbuf, (pos_code & 0x08)?
+ "\n MSL altitude input":
+ "\n WGS-84 altitude input");
+
+ pbuf += sprintf(pbuf, (pos_code & 0x10)?
+ "\n Double precision":
+ "\n Single precision");
+
+ if (pos_code & 0x20) {
+ pbuf += sprintf(pbuf, "\n All Enabled Superpackets");
+ }
+
+ if (vel_code & 0x01) {
+ pbuf += sprintf(pbuf, "\n ECEF XYZ velocity output");
+ }
+
+ if (vel_code & 0x02) {
+ pbuf += sprintf(pbuf, "\n ENU velocity output");
+ }
+
+ pbuf += sprintf(pbuf, (time_code & 0x01)?
+ "\n Time tags in UTC":
+ "\n Time tags in GPS time");
+
+ if (time_code & 0x02) {
+ pbuf += sprintf(pbuf, "\n Fixes delayed to integer seconds");
+ }
+
+ if (time_code & 0x04) {
+ pbuf += sprintf(pbuf, "\n Fixes sent only on request");
+ }
+
+ if (time_code & 0x08) {
+ pbuf += sprintf(pbuf, "\n Synchronized measurements");
+ }
+
+ if (time_code & 0x10) {
+ pbuf += sprintf(pbuf, "\n Minimize measurement propagation");
+ }
+
+ pbuf += sprintf(pbuf, (time_code & 0x20) ?
+ "\n PPS output at all times" :
+ "\n PPS output during fixes");
+
+ if (aux_code & 0x01) {
+ pbuf += sprintf(pbuf, "\n Raw measurement output");
+ }
+
+ if (aux_code & 0x02) {
+ pbuf += sprintf(pbuf, "\n Code-phase smoothed before output");
+ }
+
+ if (aux_code & 0x04) {
+ pbuf += sprintf(pbuf, "\n Additional fix status");
+ }
+
+ pbuf += sprintf(pbuf, (aux_code & 0x08)?
+ "\n Signal Strength Output as dBHz" :
+ "\n Signal Strength Output as AMU");
+}
+
+/* 0x56 */
+static void rpt_ENU_velocity (TSIPPKT *rpt)
+{
+ float
+ vel_ENU[3], freq_offset, time_of_fix;
+
+ /* unload rptbuf */
+ if (rpt_0x56 (rpt, vel_ENU, &freq_offset, &time_of_fix)) {
+ parsed = BADLEN_PARSE;
+ return;
+ }
+
+ pbuf += sprintf(pbuf, "\nVel ENU: %11.3f %11.3f %11.3f %12.3f%s",
+ vel_ENU[0], vel_ENU[1], vel_ENU[2], freq_offset,
+ show_time (time_of_fix));
+}
+
+/* 0x57 */
+static void rpt_last_fix_info (TSIPPKT *rpt)
+{
+ unsigned char
+ source_code, diag_code;
+ short
+ week_num;
+ float
+ time_of_fix;
+
+ /* unload rptbuf */
+ if (rpt_0x57 (rpt, &source_code, &diag_code, &week_num, &time_of_fix)) {
+ parsed = BADLEN_PARSE;
+ return;
+ }
+
+ pbuf += sprintf(pbuf, "\n source code %d; diag code: %2Xh",
+ source_code, diag_code);
+ pbuf += sprintf(pbuf, "\n Time of last fix:%s", show_time(time_of_fix));
+ pbuf += sprintf(pbuf, "\n Week of last fix: %d", week_num);
+}
+
+/* 0x58 */
+static void rpt_GPS_system_data (TSIPPKT *rpt)
+{
+ unsigned char
+ iprn,
+ op_code, data_type, sv_prn,
+ data_length, data_packet[250];
+ ALM_INFO
+ *almanac;
+ ALH_PARMS
+ *almh;
+ UTC_INFO
+ *utc;
+ ION_INFO
+ *ionosphere;
+ EPHEM_CLOCK
+ *cdata;
+ EPHEM_ORBIT
+ *edata;
+ NAV_INFO
+ *nav_data;
+ unsigned char
+ curr_t_oa;
+ unsigned short
+ curr_wn_oa;
+ static char
+ *datname[] =
+ {"", "", "Almanac Orbit",
+ "Health Page & Ref Time", "Ionosphere", "UTC ",
+ "Ephemeris"};
+
+ /* unload rptbuf */
+ if (rpt_0x58 (rpt, &op_code, &data_type, &sv_prn,
+ &data_length, data_packet))
+ {
+ parsed = BADLEN_PARSE;
+ return;
+ }
+
+ pbuf += sprintf(pbuf, "\nSystem data [%d]: %s SV%02d",
+ data_type, datname[data_type], sv_prn);
+ switch (op_code)
+ {
+ case 1:
+ pbuf += sprintf(pbuf, " Acknowledgment");
+ break;
+ case 2:
+ pbuf += sprintf(pbuf, " length = %d bytes", data_length);
+ switch (data_type) {
+ case 2:
+ /* Almanac */
+ if (sv_prn == 0 || sv_prn > 32) {
+ pbuf += sprintf(pbuf, " Binary PRN invalid");
+ return;
+ }
+ almanac = (ALM_INFO*)data_packet;
+ pbuf += sprintf(pbuf, "\n t_oa_raw = % -12d SV_hlth = % -12d ",
+ almanac->t_oa_raw , almanac->SV_health );
+ pbuf += sprintf(pbuf, "\n e = % -12g t_oa = % -12g ",
+ almanac->e , almanac->t_oa );
+ pbuf += sprintf(pbuf, "\n i_0 = % -12g OMEGADOT = % -12g ",
+ almanac->i_0 , almanac->OMEGADOT );
+ pbuf += sprintf(pbuf, "\n sqrt_A = % -12g OMEGA_0 = % -12g ",
+ almanac->sqrt_A , almanac->OMEGA_0 );
+ pbuf += sprintf(pbuf, "\n omega = % -12g M_0 = % -12g ",
+ almanac->omega , almanac->M_0 );
+ pbuf += sprintf(pbuf, "\n a_f0 = % -12g a_f1 = % -12g ",
+ almanac->a_f0 , almanac->a_f1 );
+ pbuf += sprintf(pbuf, "\n Axis = % -12g n = % -12g ",
+ almanac->Axis , almanac->n );
+ pbuf += sprintf(pbuf, "\n OMEGA_n = % -12g ODOT_n = % -12g ",
+ almanac->OMEGA_n , almanac->ODOT_n );
+ pbuf += sprintf(pbuf, "\n t_zc = % -12g weeknum = % -12d ",
+ almanac->t_zc , almanac->weeknum );
+ pbuf += sprintf(pbuf, "\n wn_oa = % -12d", almanac->wn_oa );
+ break;
+
+ case 3:
+ /* Almanac health page */
+ almh = (ALH_PARMS*)data_packet;
+ pbuf += sprintf(pbuf, "\n t_oa = %d, wn_oa&0xFF = %d ",
+ almh->t_oa, almh->WN_a);
+ pbuf += sprintf(pbuf, "\nAlmanac health page:");
+ for (iprn = 0; iprn < 32; iprn++) {
+ if (!(iprn%5)) *pbuf++ = '\n';
+ pbuf += sprintf(pbuf, " SV%02d %2X",
+ (iprn+1) , almh->SV_health[iprn]);
+ }
+ curr_t_oa = data_packet[34];
+ curr_wn_oa = (unsigned short)((data_packet[35]<<8) + data_packet[36]);
+ pbuf += sprintf(pbuf, "\n current t_oa = %d, wn_oa = %d ",
+ curr_t_oa, curr_wn_oa);
+ break;
+
+ case 4:
+ /* Ionosphere */
+ ionosphere = (ION_INFO*)data_packet;
+ pbuf += sprintf(pbuf, "\n alpha_0 = % -12g alpha_1 = % -12g ",
+ ionosphere->alpha_0, ionosphere->alpha_1);
+ pbuf += sprintf(pbuf, "\n alpha_2 = % -12g alpha_3 = % -12g ",
+ ionosphere->alpha_2, ionosphere->alpha_3);
+ pbuf += sprintf(pbuf, "\n beta_0 = % -12g beta_1 = % -12g ",
+ ionosphere->beta_0, ionosphere->beta_1);
+ pbuf += sprintf(pbuf, "\n beta_2 = % -12g beta_3 = % -12g ",
+ ionosphere->beta_2, ionosphere->beta_3);
+ break;
+
+ case 5:
+ /* UTC */
+ utc = (UTC_INFO*)data_packet;
+ pbuf += sprintf(pbuf, "\n A_0 = %g ", utc->A_0);
+ pbuf += sprintf(pbuf, "\n A_1 = %g ", utc->A_1);
+ pbuf += sprintf(pbuf, "\n delta_t_LS = %d ", utc->delta_t_LS);
+ pbuf += sprintf(pbuf, "\n t_ot = %.0f ", utc->t_ot );
+ pbuf += sprintf(pbuf, "\n WN_t = %d ", utc->WN_t );
+ pbuf += sprintf(pbuf, "\n WN_LSF = %d ", utc->WN_LSF );
+ pbuf += sprintf(pbuf, "\n DN = %d ", utc->DN );
+ pbuf += sprintf(pbuf, "\n delta_t_LSF = %d ", utc->delta_t_LSF );
+ break;
+
+ case 6: /* Ephemeris */
+ if (sv_prn == 0 || sv_prn > 32) {
+ pbuf += sprintf(pbuf, " Binary PRN invalid");
+ return;
+ }
+ nav_data = (NAV_INFO*)data_packet;
+
+ pbuf += sprintf(pbuf, "\n SV_PRN = % -12d . t_ephem = % -12g . ",
+ nav_data->sv_number , nav_data->t_ephem );
+ cdata = &(nav_data->ephclk);
+ pbuf += sprintf(pbuf,
+ "\n weeknum = % -12d . codeL2 = % -12d . L2Pdata = % -12d",
+ cdata->weeknum , cdata->codeL2 , cdata->L2Pdata );
+ pbuf += sprintf(pbuf,
+ "\n SVacc_raw = % -12d .SV_health = % -12d . IODC = % -12d",
+ cdata->SVacc_raw, cdata->SV_health, cdata->IODC );
+ pbuf += sprintf(pbuf,
+ "\n T_GD = % -12g . t_oc = % -12g . a_f2 = % -12g",
+ cdata->T_GD, cdata->t_oc, cdata->a_f2 );
+ pbuf += sprintf(pbuf,
+ "\n a_f1 = % -12g . a_f0 = % -12g . SVacc = % -12g",
+ cdata->a_f1, cdata->a_f0, cdata->SVacc );
+ edata = &(nav_data->ephorb);
+ pbuf += sprintf(pbuf,
+ "\n IODE = % -12d .fit_intvl = % -12d . C_rs = % -12g",
+ edata->IODE, edata->fit_interval, edata->C_rs );
+ pbuf += sprintf(pbuf,
+ "\n delta_n = % -12g . M_0 = % -12g . C_uc = % -12g",
+ edata->delta_n, edata->M_0, edata->C_uc );
+ pbuf += sprintf(pbuf,
+ "\n ecc = % -12g . C_us = % -12g . sqrt_A = % -12g",
+ edata->e, edata->C_us, edata->sqrt_A );
+ pbuf += sprintf(pbuf,
+ "\n t_oe = % -12g . C_ic = % -12g . OMEGA_0 = % -12g",
+ edata->t_oe, edata->C_ic, edata->OMEGA_0 );
+ pbuf += sprintf(pbuf,
+ "\n C_is = % -12g . i_0 = % -12g . C_rc = % -12g",
+ edata->C_is, edata->i_0, edata->C_rc );
+ pbuf += sprintf(pbuf,
+ "\n omega = % -12g . OMEGADOT = % -12g . IDOT = % -12g",
+ edata->omega, edata->OMEGADOT, edata->IDOT );
+ pbuf += sprintf(pbuf,
+ "\n Axis = % -12g . n = % -12g . r1me2 = % -12g",
+ edata->Axis, edata->n, edata->r1me2 );
+ pbuf += sprintf(pbuf,
+ "\n OMEGA_n = % -12g . ODOT_n = % -12g",
+ edata->OMEGA_n, edata->ODOT_n );
+ break;
+ }
+ }
+}
+
+
+/* 0x59: */
+static void rpt_SVs_enabled (TSIPPKT *rpt)
+{
+ unsigned char
+ numsvs,
+ code_type,
+ status_code[32];
+ short
+ iprn;
+
+ /* unload rptbuf */
+ if (rpt_0x59 (rpt, &code_type, status_code))
+ {
+ parsed = BADLEN_PARSE;
+ return;
+ }
+ switch (code_type)
+ {
+ case 3: pbuf += sprintf(pbuf, "\nSVs Disabled:\n"); break;
+ case 6: pbuf += sprintf(pbuf, "\nSVs with Health Ignored:\n"); break;
+ default: return;
+ }
+ numsvs = 0;
+ for (iprn=0; iprn<32; iprn++)
+ {
+ if (status_code[iprn])
+ {
+ pbuf += sprintf(pbuf, " %02d", iprn+1);
+ numsvs++;
+ }
+ }
+ if (numsvs == 0) pbuf += sprintf(pbuf, "None");
+}
+
+
+/* 0x5A */
+static void rpt_raw_msmt (TSIPPKT *rpt)
+{
+ unsigned char
+ sv_prn;
+ float
+ sample_length, signal_level, code_phase, Doppler;
+ double
+ time_of_fix;
+
+ /* unload rptbuf */
+ if (rpt_0x5A (rpt, &sv_prn, &sample_length, &signal_level,
+ &code_phase, &Doppler, &time_of_fix))
+ {
+ parsed = BADLEN_PARSE;
+ return;
+ }
+
+ pbuf += sprintf(pbuf, "\n %02d %5.0f %7.1f %10.2f %10.2f %12.3f %s",
+ sv_prn, sample_length, signal_level, code_phase, Doppler, time_of_fix,
+ show_time ((float)time_of_fix));
+}
+
+/* 0x5B */
+static void rpt_SV_ephemeris_status (TSIPPKT *rpt)
+{
+ unsigned char
+ sv_prn, sv_health, sv_iode, fit_interval_flag;
+ float
+ time_of_collection, time_of_eph, sv_accy;
+
+ /* unload rptbuf */
+ if (rpt_0x5B (rpt, &sv_prn, &sv_health, &sv_iode, &fit_interval_flag,
+ &time_of_collection, &time_of_eph, &sv_accy))
+ {
+ parsed = BADLEN_PARSE;
+ return;
+ }
+
+ pbuf += sprintf(pbuf, "\n SV%02d %s %2Xh %2Xh ",
+ sv_prn, show_time (time_of_collection), sv_health, sv_iode);
+ /* note: cannot use show_time twice in same call */
+ pbuf += sprintf(pbuf, "%s %1d %4.1f",
+ show_time (time_of_eph), fit_interval_flag, sv_accy);
+}
+
+/* 0x5C */
+static void rpt_SV_tracking_status (TSIPPKT *rpt)
+{
+ unsigned char
+ sv_prn, chan, slot, acq_flag, eph_flag,
+ old_msmt_flag, integer_msec_flag, bad_data_flag,
+ data_collect_flag;
+ float
+ signal_level, time_of_last_msmt,
+ elev, azim;
+
+ /* unload rptbuf */
+ if (rpt_0x5C (rpt,
+ &sv_prn, &slot, &chan, &acq_flag, &eph_flag,
+ &signal_level, &time_of_last_msmt, &elev, &azim,
+ &old_msmt_flag, &integer_msec_flag, &bad_data_flag,
+ &data_collect_flag))
+ {
+ parsed = BADLEN_PARSE;
+ return;
+ }
+
+ pbuf += sprintf(pbuf,
+"\n SV%2d %1d %1d %1d %4.1f %s %5.1f %5.1f",
+ sv_prn, chan,
+ acq_flag, eph_flag, signal_level,
+ show_time(time_of_last_msmt),
+ elev*R2D, azim*R2D);
+}
+
+/**/
+/* 0x6D */
+static void rpt_allSV_selection (TSIPPKT *rpt)
+{
+ unsigned char
+ manual_mode, nsvs, sv_prn[8], ndim;
+ short
+ islot;
+ float
+ pdop, hdop, vdop, tdop;
+
+ /* unload rptbuf */
+ if (rpt_0x6D (rpt,
+ &manual_mode, &nsvs, &ndim, sv_prn,
+ &pdop, &hdop, &vdop, &tdop))
+ {
+ parsed = BADLEN_PARSE;
+ return;
+ }
+
+ switch (ndim)
+ {
+ case 0:
+ pbuf += sprintf(pbuf, "\nMode: Searching, %d-SV:", nsvs);
+ break;
+ case 1:
+ pbuf += sprintf(pbuf, "\nMode: One-SV Timing:");
+ break;
+ case 3: case 4:
+ pbuf += sprintf(pbuf, "\nMode: %c-%dD, %d-SV:",
+ manual_mode ? 'M' : 'A', ndim - 1, nsvs);
+ break;
+ case 5:
+ pbuf += sprintf(pbuf, "\nMode: Timing, %d-SV:", nsvs);
+ break;
+ default:
+ pbuf += sprintf(pbuf, "\nMode: Unknown = %d:", ndim);
+ break;
+ }
+
+ for (islot = 0; islot < nsvs; islot++)
+ {
+ if (sv_prn[islot]) pbuf += sprintf(pbuf, " %02d", sv_prn[islot]);
+ }
+ if (ndim == 3 || ndim == 4)
+ {
+ pbuf += sprintf(pbuf, "; DOPs: P %.1f H %.1f V %.1f T %.1f",
+ pdop, hdop, vdop, tdop);
+ }
+}
+
+/**/
+/* 0x82 */
+static void rpt_DGPS_position_mode (TSIPPKT *rpt)
+{
+ unsigned char
+ diff_mode;
+
+ /* unload rptbuf */
+ if (rpt_0x82 (rpt, &diff_mode)) {
+ parsed = BADLEN_PARSE;
+ return;
+ }
+
+ pbuf += sprintf(pbuf, "\nFix is%s DGPS-corrected (%s mode) (%d)",
+ (diff_mode&1) ? "" : " not",
+ (diff_mode&2) ? "auto" : "manual",
+ diff_mode);
+}
+
+/* 0x83 */
+static void rpt_double_ECEF_position (TSIPPKT *rpt)
+{
+
+ double
+ ECEF_pos[3], clock_bias;
+ float
+ time_of_fix;
+
+ /* unload rptbuf */
+ if (rpt_0x83 (rpt, ECEF_pos, &clock_bias, &time_of_fix))
+ {
+ parsed = BADLEN_PARSE;
+ return;
+ }
+
+ pbuf += sprintf(pbuf, "\nDXYZ:%12.2f %13.2f %13.2f %12.2f%s",
+ ECEF_pos[0], ECEF_pos[1], ECEF_pos[2], clock_bias,
+ show_time(time_of_fix));
+}
+
+/* 0x84 */
+static void rpt_double_lla_position (TSIPPKT *rpt)
+{
+ short
+ lat_deg, lon_deg;
+ double
+ lat, lon, lat_min, lon_min,
+ alt, clock_bias;
+ float
+ time_of_fix;
+ unsigned char
+ north_south, east_west;
+
+ /* unload rptbuf */
+ if (rpt_0x84 (rpt,
+ &lat, &lon, &alt, &clock_bias, &time_of_fix))
+ {
+ parsed = BADLEN_PARSE;
+ return;
+ }
+
+ lat *= R2D;
+ lon *= R2D;
+ if (lat < 0.0) {
+ north_south = 'S';
+ lat = -lat;
+ } else {
+ north_south = 'N';
+ }
+ lat_deg = (short)lat;
+ lat_min = (lat - lat_deg) * 60.0;
+
+ if (lon < 0.0) {
+ east_west = 'W';
+ lon = -lon;
+ } else {
+ east_west = 'E';
+ }
+ lon_deg = (short)lon;
+ lon_min = (lon - lon_deg) * 60.0;
+ pbuf += sprintf(pbuf, "\nDLLA: %2d:%08.5f %c; %3d:%08.5f %c; %10.2f %12.2f%s",
+ lat_deg, lat_min, north_south,
+ lon_deg, lon_min, east_west,
+ alt, clock_bias,
+ show_time(time_of_fix));
+}
+
+/* 0xBB */
+static void rpt_complete_rcvr_config (TSIPPKT *rpt)
+{
+ TSIP_RCVR_CFG TsipxBB ;
+ /* unload rptbuf */
+ if (rpt_Paly0xBB (rpt, &TsipxBB))
+ {
+ parsed = BADLEN_PARSE;
+ return;
+ }
+
+ pbuf += sprintf(pbuf, "\n operating mode: %s",
+ NavModeText0xBB[TsipxBB.operating_mode]);
+ pbuf += sprintf(pbuf, "\n dynamics: %s",
+ dyn_text[TsipxBB.dyn_code]);
+ pbuf += sprintf(pbuf, "\n elev angle mask: %g deg",
+ TsipxBB.elev_mask * R2D);
+ pbuf += sprintf(pbuf, "\n SNR mask: %g AMU",
+ TsipxBB.cno_mask);
+ pbuf += sprintf(pbuf, "\n DOP mask: %g",
+ TsipxBB.dop_mask);
+ pbuf += sprintf(pbuf, "\n DOP switch: %g",
+ TsipxBB.dop_switch);
+ return ;
+}
+
+/* 0xBC */
+static void rpt_rcvr_serial_port_config (TSIPPKT *rpt)
+{
+ unsigned char
+ port_num, in_baud, out_baud, data_bits, parity, stop_bits, flow_control,
+ protocols_in, protocols_out, reserved;
+ unsigned char known;
+
+ /* unload rptbuf */
+ if (rpt_0xBC (rpt, &port_num, &in_baud, &out_baud, &data_bits, &parity,
+ &stop_bits, &flow_control, &protocols_in, &protocols_out, &reserved)) {
+ parsed = BADLEN_PARSE;
+ return;
+ }
+ /* rptbuf unloaded */
+
+ pbuf += sprintf(pbuf, "\n RECEIVER serial port %s config:",
+ rcvr_port_text[port_num]);
+
+ pbuf += sprintf(pbuf, "\n I/O Baud %s/%s, %d - %s - %d",
+ st_baud_text_app[in_baud],
+ st_baud_text_app[out_baud],
+ data_bits+5,
+ parity_text[parity],
+ stop_bits=1);
+ pbuf += sprintf(pbuf, "\n Input protocols: ");
+ known = FALSE;
+ if (protocols_in&B_TSIP)
+ {
+ pbuf += sprintf(pbuf, "%s ", protocols_in_text[1]);
+ known = TRUE;
+ }
+ if (known == FALSE) pbuf += sprintf(pbuf, "No known");
+
+ pbuf += sprintf(pbuf, "\n Output protocols: ");
+ known = FALSE;
+ if (protocols_out&B_TSIP)
+ {
+ pbuf += sprintf(pbuf, "%s ", protocols_out_text[1]);
+ known = TRUE;
+ }
+ if (protocols_out&B_NMEA)
+ {
+ pbuf += sprintf(pbuf, "%s ", protocols_out_text[2]);
+ known = TRUE;
+ }
+ if (known == FALSE) pbuf += sprintf(pbuf, "No known");
+ reserved = reserved;
+
+ }
+
+/* 0x8F */
+/* 8F0B */
+static void rpt_8F0B(TSIPPKT *rpt)
+{
+ const char
+ *oprtng_dim[7] = {
+ "horizontal (2-D)",
+ "full position (3-D)",
+ "single satellite (0-D)",
+ "automatic",
+ "N/A",
+ "N/A",
+ "overdetermined clock"};
+ char
+ sv_id[8];
+ unsigned char
+ month,
+ date,
+ dim_mode,
+ north_south,
+ east_west;
+ unsigned short
+ event;
+ short
+ utc_offset,
+ year,
+ local_index;
+ short
+ lat_deg,
+ lon_deg;
+ float
+ bias_unc,
+ dr_unc;
+ double
+ tow,
+ bias,
+ drift,
+ lat,
+ lon,
+ alt,
+ lat_min,
+ lon_min;
+ int
+ numfix,
+ numnotfix;
+
+ if (rpt_0x8F0B(rpt,
+ &event,
+ &tow,
+ &date,
+ &month,
+ &year,
+ &dim_mode,
+ &utc_offset,
+ &bias,
+ &drift,
+ &bias_unc,
+ &dr_unc,
+ &lat,
+ &lon,
+ &alt,
+ sv_id))
+ {
+ parsed = BADLEN_PARSE;
+ return;
+ }
+
+ if (event == 0)
+ {
+ pbuf += sprintf(pbuf, "\nNew partial+full meas");
+ }
+ else
+ {
+ pbuf += sprintf(pbuf, "\nEvent count: %5d", event);
+ }
+
+ pbuf += sprintf(pbuf, "\nGPS time : %s %2d/%2d/%2d (DMY)",
+ show_time(tow), date, month, year);
+ pbuf += sprintf(pbuf, "\nMode : %s", oprtng_dim[dim_mode]);
+ pbuf += sprintf(pbuf, "\nUTC offset: %2d", utc_offset);
+ pbuf += sprintf(pbuf, "\nClock Bias: %6.2f m", bias);
+ pbuf += sprintf(pbuf, "\nFreq bias : %6.2f m/s", drift);
+ pbuf += sprintf(pbuf, "\nBias unc : %6.2f m", bias_unc);
+ pbuf += sprintf(pbuf, "\nFreq unc : %6.2f m/s", dr_unc);
+
+ lat *= R2D; /* convert from radians to degrees */
+ lon *= R2D;
+ if (lat < 0.0)
+ {
+ north_south = 'S';
+ lat = -lat;
+ }
+ else
+ {
+ north_south = 'N';
+ }
+
+ lat_deg = (short)lat;
+ lat_min = (lat - lat_deg) * 60.0;
+ if (lon < 0.0)
+ {
+ east_west = 'W';
+ lon = -lon;
+ }
+ else
+ {
+ east_west = 'E';
+ }
+
+ lon_deg = (short)lon;
+ lon_min = (lon - lon_deg) * 60.0;
+ pbuf += sprintf(pbuf, "\nPosition :");
+ pbuf += sprintf(pbuf, " %4d %6.3f %c", lat_deg, lat_min, north_south);
+ pbuf += sprintf(pbuf, " %5d %6.3f %c", lon_deg, lon_min, east_west);
+ pbuf += sprintf(pbuf, " %10.2f", alt);
+
+ numfix = numnotfix = 0;
+ for (local_index=0; local_index<8; local_index++)
+ {
+ if (sv_id[local_index] < 0) numnotfix++;
+ if (sv_id[local_index] > 0) numfix++;
+ }
+ if (numfix > 0)
+ {
+ pbuf += sprintf(pbuf, "\nSVs used in fix : ");
+ for (local_index=0; local_index<8; local_index++)
+ {
+ if (sv_id[local_index] > 0)
+ {
+ pbuf += sprintf(pbuf, "%2d ", sv_id[local_index]);
+ }
+ }
+ }
+ if (numnotfix > 0)
+ {
+ pbuf += sprintf(pbuf, "\nOther SVs tracked: ");
+ for (local_index=0; local_index<8; local_index++)
+ {
+ if (sv_id[local_index] < 0)
+ {
+ pbuf += sprintf(pbuf, "%2d ", sv_id[local_index]);
+ }
+ }
+ }
+}
+
+/* 0x8F14 */
+static void rpt_8F14 (TSIPPKT *rpt)
+/* Datum parameters */
+{
+ double
+ datum_coeffs[5];
+ short
+ datum_idx;
+
+ /* unload rptbuf */
+ if (rpt_0x8F14 (rpt, &datum_idx, datum_coeffs))
+ {
+ parsed = BADLEN_PARSE;
+ return;
+ }
+
+ if (datum_idx == -1)
+ {
+ pbuf += sprintf(pbuf, "\nUser-Entered Datum:");
+ pbuf += sprintf(pbuf, "\n dx = %6.1f", datum_coeffs[0]);
+ pbuf += sprintf(pbuf, "\n dy = %6.1f", datum_coeffs[1]);
+ pbuf += sprintf(pbuf, "\n dz = %6.1f", datum_coeffs[2]);
+ pbuf += sprintf(pbuf, "\n a-axis = %10.3f", datum_coeffs[3]);
+ pbuf += sprintf(pbuf, "\n e-squared = %16.14f", datum_coeffs[4]);
+ }
+ else if (datum_idx == 0)
+ {
+ pbuf += sprintf(pbuf, "\nWGS-84 datum, Index 0 ");
+ }
+ else
+ {
+ pbuf += sprintf(pbuf, "\nStandard Datum, Index %3d ", datum_idx);
+ }
+}
+
+/* 0x8F15 */
+static void rpt_8F15 (TSIPPKT *rpt)
+/* Datum parameters */
+{
+ double
+ datum_coeffs[5];
+ short
+ datum_idx;
+
+ /* unload rptbuf */
+ if (rpt_0x8F15 (rpt, &datum_idx, datum_coeffs)) {
+ parsed = BADLEN_PARSE;
+ return;
+ }
+
+ if (datum_idx == -1)
+ {
+ pbuf += sprintf(pbuf, "\nUser-Entered Datum:");
+ pbuf += sprintf(pbuf, "\n dx = %6.1f", datum_coeffs[0]);
+ pbuf += sprintf(pbuf, "\n dy = %6.1f", datum_coeffs[1]);
+ pbuf += sprintf(pbuf, "\n dz = %6.1f", datum_coeffs[2]);
+ pbuf += sprintf(pbuf, "\n a-axis = %10.3f", datum_coeffs[3]);
+ pbuf += sprintf(pbuf, "\n e-squared = %16.14f", datum_coeffs[4]);
+ }
+ else if (datum_idx == 0)
+ {
+ pbuf += sprintf(pbuf, "\nWGS-84 datum, Index 0 ");
+ }
+ else
+ {
+ pbuf += sprintf(pbuf, "\nStandard Datum, Index %3d ", datum_idx);
+ }
+}
+
+/* 0x8F20 */
+#define INFO_DGPS 0x02
+#define INFO_2D 0x04
+#define INFO_ALTSET 0x08
+#define INFO_FILTERED 0x10
+static void rpt_8F20 (TSIPPKT *rpt)
+{
+ unsigned char
+ info, nsvs, sv_prn[32];
+ short
+ week_num, datum_index, sv_IODC[32];
+ double
+ lat, lon, alt, time_of_fix;
+ double
+ londeg, latdeg, vel[3];
+ short
+ isv;
+ char
+ datum_string[20];
+
+ /* unload rptbuf */
+ if (rpt_0x8F20 (rpt,
+ &info, &lat, &lon, &alt, vel,
+ &time_of_fix,
+ &week_num, &nsvs, sv_prn, sv_IODC, &datum_index))
+ {
+ parsed = BADLEN_PARSE;
+ return;
+ }
+ pbuf += sprintf(pbuf,
+ "\nFix at: %04d:%3s:%02d:%02d:%06.3f GPS (=UTC+%2ds) FixType: %s%s%s",
+ week_num,
+ dayname[(short)(time_of_fix/86400.0)],
+ (short)fmod(time_of_fix/3600., 24.),
+ (short)fmod(time_of_fix/60., 60.),
+ fmod(time_of_fix, 60.),
+ (char)rpt->buf[29], /* UTC offset */
+ (info & INFO_DGPS)?"Diff":"",
+ (info & INFO_2D)?"2D":"3D",
+ (info & INFO_FILTERED)?"-Filtrd":"");
+
+ if (datum_index > 0)
+ {
+ sprintf(datum_string, "Datum%3d", datum_index);
+ }
+ else if (datum_index)
+ {
+ sprintf(datum_string, "Unknown ");
+ }
+ else
+ {
+ sprintf(datum_string, "WGS-84");
+ }
+
+ /* convert from radians to degrees */
+ latdeg = R2D * fabs(lat);
+ londeg = R2D * fabs(lon);
+ pbuf += sprintf(pbuf,
+ "\n Pos: %4d:%09.6f %c %5d:%09.6f %c %10.2f m HAE (%s)",
+ (short)latdeg, fmod (latdeg, 1.)*60.0,
+ (lat<0.0)?'S':'N',
+ (short)londeg, fmod (londeg, 1.)*60.0,
+ (lon<0.0)?'W':'E',
+ alt,
+ datum_string);
+ pbuf += sprintf(pbuf,
+ "\n Vel: %9.3f E %9.3f N %9.3f U (m/sec)",
+ vel[0], vel[1], vel[2]);
+
+ pbuf += sprintf(pbuf,
+ "\n SVs: ");
+ for (isv = 0; isv < nsvs; isv++) {
+ pbuf += sprintf(pbuf, " %02d", sv_prn[isv]);
+ }
+ pbuf += sprintf(pbuf, " (IODEs:");
+ for (isv = 0; isv < nsvs; isv++) {
+ pbuf += sprintf(pbuf, " %02X", sv_IODC[isv]&0xFF);
+ }
+ pbuf += sprintf(pbuf, ")");
+}
+
+/* 0x8F41 */
+static void rpt_8F41(TSIPPKT *rpt)
+{
+ unsigned char
+ bSearchRange,
+ bBoardOptions,
+ bBuildYear,
+ bBuildMonth,
+ bBuildDay,
+ bBuildHour;
+ float
+ fOscOffset;
+ unsigned short
+ iTestCodeId;
+ unsigned long
+ iiSerialNumber;
+
+ if (!rpt_0x8F41(rpt,
+ &bSearchRange,
+ &bBoardOptions,
+ &iiSerialNumber,
+ &bBuildYear,
+ &bBuildMonth,
+ &bBuildDay,
+ &bBuildHour,
+ &fOscOffset,
+ &iTestCodeId))
+ {
+ parsed = BADLEN_PARSE;
+ return;
+ }
+
+ pbuf += sprintf(pbuf, "\n search range: %d",
+ bSearchRange);
+ pbuf += sprintf(pbuf, "\n board options: %d",
+ bBoardOptions);
+ pbuf += sprintf(pbuf, "\n board serial #: %ld",
+ iiSerialNumber);
+ pbuf += sprintf(pbuf, "\n build date/hour: %02d/%02d/%02d %02d:00",
+ bBuildDay, bBuildMonth, bBuildYear, bBuildHour);
+ pbuf += sprintf(pbuf, "\n osc offset: %.3f PPM (%.0f Hz)",
+ fOscOffset/1575.42, fOscOffset);
+ pbuf += sprintf(pbuf, "\n test code: %d",
+ iTestCodeId);
+}
+
+/* 0x8F42 */
+static void rpt_8F42(TSIPPKT *rpt)
+{
+ unsigned char
+ bProdOptionsPre,
+ bProdNumberExt;
+ unsigned short
+ iCaseSerialNumberPre,
+ iPremiumOptions,
+ iMachineID,
+ iKey;
+ unsigned long
+ iiCaseSerialNumber,
+ iiProdNumber;
+
+ if (!rpt_0x8F42(rpt,
+ &bProdOptionsPre,
+ &bProdNumberExt,
+ &iCaseSerialNumberPre,
+ &iiCaseSerialNumber,
+ &iiProdNumber,
+ &iPremiumOptions,
+ &iMachineID,
+ &iKey))
+ {
+ parsed = BADLEN_PARSE;
+ return;
+ }
+
+ pbuf += sprintf(pbuf, "\nProduct ID 8F42");
+ pbuf += sprintf(pbuf, "\n extension: %d", bProdNumberExt);
+ pbuf += sprintf(pbuf, "\n case serial # prefix: %d", iCaseSerialNumberPre);
+ pbuf += sprintf(pbuf, "\n case serial #: %ld", iiCaseSerialNumber);
+ pbuf += sprintf(pbuf, "\n prod. #: %ld", iiProdNumber);
+ pbuf += sprintf(pbuf, "\n premium options: %Xh", iPremiumOptions);
+ pbuf += sprintf(pbuf, "\n machine ID: %d", iMachineID);
+ pbuf += sprintf(pbuf, "\n key: %Xh", iKey);
+}
+
+/* 0x8F45 */
+static void rpt_8F45(TSIPPKT *rpt)
+{
+ unsigned char bSegMask;
+
+ if (!rpt_0x8F45(rpt,
+ &bSegMask))
+ {
+ parsed = BADLEN_PARSE;
+ return;
+ }
+ pbuf += sprintf(pbuf, "\nCleared Segment Mask: %Xh", bSegMask);
+}
+
+static void rpt_8F4A(TSIPPKT *rpt)
+/* Stinger PPS def */
+{
+ unsigned char
+ pps_enabled,
+ pps_timebase,
+ pps_polarity;
+ float
+ bias_unc_threshold;
+ double
+ pps_offset;
+
+ if (rpt_0x8F4A_16 (rpt,
+ &pps_enabled,
+ &pps_timebase,
+ &pps_polarity,
+ &pps_offset,
+ &bias_unc_threshold))
+ {
+ parsed = BADLEN_PARSE;
+ return;
+ }
+
+ pbuf += sprintf(pbuf, "\nPPS is %s", pps_enabled?"enabled":"disabled");
+ pbuf += sprintf(pbuf, "\n timebase: %s", PPSTimeBaseText[pps_timebase]);
+ pbuf += sprintf(pbuf, "\n polarity: %s", PPSPolarityText[pps_polarity]);
+ pbuf += sprintf(pbuf, "\n offset: %.1f ns, ", pps_offset*1.e9);
+ pbuf += sprintf(pbuf, "\n biasunc: %.1f ns", bias_unc_threshold/GPS_C*1.e9);
+}
+
+static void rpt_8F4B(TSIPPKT *rpt)
+/* fast-SA decorrolation time for self-survey */
+{
+ unsigned long
+ decorr_max;
+
+ if (rpt_0x8F4B(rpt, &decorr_max))
+ {
+ parsed = BADLEN_PARSE;
+ return;
+ }
+
+ pbuf += sprintf(pbuf,
+ "\nMax # of position fixes for self-survey : %ld",
+ decorr_max);
+}
+
+static void rpt_8F4D(TSIPPKT *rpt)
+{
+ static char
+ *linestart;
+ unsigned long
+ OutputMask;
+ static unsigned long
+ MaskBit[] = {
+ 0x00000001, 0x00000002, 0x00000004, 0x00000008, 0x00000010, 0x00000020,
+ 0x00000100L, 0x00000800L, 0x00001000L,
+ 0x40000000L, 0x80000000L};
+ int
+ ichoice,
+ numchoices;
+
+ if (rpt_0x8F4D(rpt, &OutputMask))
+ {
+ parsed = BADLEN_PARSE;
+ return;
+ }
+
+ pbuf += sprintf(pbuf, "\nAuto-Report Mask: %02X %02X %02X %02X",
+ (unsigned char)(OutputMask>>24),
+ (unsigned char)(OutputMask>>16),
+ (unsigned char)(OutputMask>>8),
+ (unsigned char)OutputMask);
+
+ numchoices = sizeof(MaskText)/sizeof(char*);
+ pbuf += sprintf(pbuf, "\nAuto-Reports scheduled for Output:");
+ linestart = pbuf;
+ for (ichoice=0; ichoice<numchoices; ichoice++)
+ {
+ if (OutputMask&MaskBit[ichoice])
+ {
+ pbuf += sprintf(pbuf, "%s %s",
+ (pbuf==linestart)?"\n ":",",
+ MaskText[ichoice]);
+ if (pbuf-linestart > 60) linestart = pbuf;
+ }
+ }
+
+ pbuf += sprintf(pbuf, "\nAuto-Reports NOT scheduled for Output:");
+ linestart = pbuf;
+ for (ichoice=0; ichoice<numchoices; ichoice++)
+ {
+ if (OutputMask&MaskBit[ichoice]) continue;
+ pbuf += sprintf(pbuf, "%s %s",
+ (pbuf==linestart)?"\n ":",",
+ MaskText[ichoice]);
+ if (pbuf-linestart > 60) linestart = pbuf;
+ }
+}
+
+static void rpt_8FA5(TSIPPKT *rpt)
+{
+ unsigned char
+ spktmask[4];
+
+ if (rpt_0x8FA5(rpt, spktmask))
+ {
+ parsed = BADLEN_PARSE;
+ return;
+ }
+
+ pbuf += sprintf(pbuf, "\nSuperpacket auto-output mask: %02X %02X %02X %02X",
+ spktmask[0], spktmask[1], spktmask[2], spktmask[3]);
+
+ if (spktmask[0]&0x01) pbuf+= sprintf (pbuf, "\n PPS 8F-0B");
+ if (spktmask[0]&0x02) pbuf+= sprintf (pbuf, "\n Event 8F-0B");
+ if (spktmask[0]&0x10) pbuf+= sprintf (pbuf, "\n PPS 8F-AD");
+ if (spktmask[0]&0x20) pbuf+= sprintf (pbuf, "\n Event 8F-AD");
+ if (spktmask[2]&0x01) pbuf+= sprintf (pbuf, "\n ppos Fix 8F-20");
+}
+
+static void rpt_8FAD (TSIPPKT *rpt)
+{
+ unsigned short
+ Count,
+ Year;
+ double
+ FracSec;
+ unsigned char
+ Hour,
+ Minute,
+ Second,
+ Day,
+ Month,
+ Status,
+ Flags;
+ static char* Status8FADText[] = {
+ "CODE_DOING_FIXES",
+ "CODE_GOOD_1_SV",
+ "CODE_APPX_1SV",
+ "CODE_NEED_TIME",
+ "CODE_NEED_INITIALIZATION",
+ "CODE_PDOP_HIGH",
+ "CODE_BAD_1SV",
+ "CODE_0SVS",
+ "CODE_1SV",
+ "CODE_2SVS",
+ "CODE_3SVS",
+ "CODE_NO_INTEGRITY",
+ "CODE_DCORR_GEN",
+ "CODE_OVERDET_CLK",
+ "Invalid Status"},
+ *LeapStatusText[] = {
+ " UTC Avail", " ", " ", " ",
+ " Scheduled", " Pending", " Warning", " In Progress"};
+ int i;
+
+ if (rpt_0x8FAD (rpt,
+ &Count,
+ &FracSec,
+ &Hour,
+ &Minute,
+ &Second,
+ &Day,
+ &Month,
+ &Year,
+ &Status,
+ &Flags))
+ {
+ parsed = BADLEN_PARSE;
+ return;
+ }
+
+ pbuf += sprintf(pbuf, "\n8FAD Count: %d Status: %s",
+ Count, Status8FADText[Status]);
+
+ pbuf += sprintf(pbuf, "\n Leap Flags:");
+ if (Flags)
+ {
+ for (i=0; i<8; i++)
+ {
+ if (Flags&(1<<i)) pbuf += sprintf(pbuf, LeapStatusText[i]);
+ }
+ }
+ else
+ {
+ pbuf += sprintf(pbuf, " UTC info not available");
+ }
+
+ pbuf += sprintf(pbuf, "\n %02d/%02d/%04d (DMY) %02d:%02d:%02d.%09ld UTC",
+ Day, Month, Year, Hour, Minute, Second, (long)(FracSec*1.e9));
+}
+
+
+int print_msg_table_header (int rptcode, char *HdrStr, int force)
+{
+ /* force header is to help auto-output function */
+ /* last_rptcode is to determine whether to print a header */
+ /* for the first occurence of a series of reports */
+ static int
+ last_rptcode = 0;
+ int
+ numchars;
+
+ numchars = 0;
+ if (force || rptcode!=last_rptcode)
+ {
+ /* supply a header in console output */
+ switch (rptcode)
+ {
+ case 0x5A:
+ numchars = sprintf(HdrStr, "\nRaw Measurement Data");
+ numchars += sprintf(HdrStr+numchars,
+ "\n SV Sample SNR Code Phase Doppler Seconds Time of Meas");
+ break;
+
+ case 0x5B:
+ numchars = sprintf(HdrStr, "\nEphemeris Status");
+ numchars += sprintf(HdrStr+numchars,
+ "\n SV Time collected Health IODE t oe Fit URA");
+ break;
+
+ case 0x5C:
+ numchars = sprintf(HdrStr, "\nTracking Info");
+ numchars += sprintf(HdrStr+numchars,
+ "\n SV C Acq Eph SNR Time of Meas Elev Azim ");
+ break;
+
+ }
+ }
+ last_rptcode = rptcode;
+ return (short)numchars;
+}
+
+static void unknown_rpt (TSIPPKT *rpt)
+{
+ int i;
+
+ /* app-specific rpt packets */
+ if (parsed == BADLEN_PARSE)
+ {
+ pbuf += sprintf(pbuf, "\nTSIP report packet ID %2Xh, length %d: Bad length",
+ rpt->code, rpt->len);
+ }
+ if (parsed == BADID_PARSE)
+ {
+ pbuf += sprintf(pbuf,
+ "\nTSIP report packet ID %2Xh, length %d: translation not supported",
+ rpt->code, rpt->len);
+ }
+
+ if (parsed == BADDATA_PARSE)
+ {
+ pbuf += sprintf(pbuf,
+ "\nTSIP report packet ID %2Xh, length %d: data content incorrect",
+ rpt->code, rpt->len);
+ }
+
+ for (i = 0; i < rpt->len; i++) {
+ if ((i % 20) == 0) *pbuf++ = '\n';
+ pbuf += sprintf(pbuf, " %02X", rpt->buf[i]);
+ }
+}
+/**/
+/*
+** main subroutine, called from ProcessInputBytesWhileWaitingForKBHit()
+*/
+void TranslateTSIPReportToText (TSIPPKT *rpt, char *TextOutputBuffer)
+{
+
+ /* pbuf is the pointer to the current location of the text output */
+ pbuf = TextOutputBuffer;
+
+ /* keep track of whether the message has been successfully parsed */
+ parsed = GOOD_PARSE;
+
+ /* print a header if this is the first of a series of messages */
+ pbuf += print_msg_table_header (rpt->code, pbuf, FALSE);
+
+ /* process incoming TSIP report according to code */
+ switch (rpt->code)
+ {
+ case 0x3D: rpt_chan_A_config (rpt); break;
+ case 0x40: rpt_almanac_data_page (rpt); break;
+ case 0x41: rpt_GPS_time (rpt); break;
+ case 0x42: rpt_single_ECEF_position (rpt); break;
+ case 0x43: rpt_single_ECEF_velocity (rpt); break;
+ case 0x45: rpt_SW_version (rpt); break;
+ case 0x46: rpt_rcvr_health (rpt); break;
+ case 0x47: rpt_SNR_all_SVs (rpt); break;
+ case 0x48: rpt_GPS_system_message (rpt); break;
+ case 0x49: rpt_almanac_health_page (rpt); break;
+ case 0x4A: switch (rpt->len) {
+ /*
+ ** special case (=slip-up) in the TSIP protocol;
+ ** parsing method depends on length
+ */
+ case 20: rpt_single_lla_position (rpt); break;
+ case 9: rpt_ref_alt (rpt); break;
+ } break;
+ case 0x4B: rpt_rcvr_id_and_status (rpt);break;
+ case 0x4C: rpt_operating_parameters (rpt); break;
+ case 0x4D: rpt_oscillator_offset (rpt); break;
+ case 0x4E: rpt_GPS_time_set_response (rpt); break;
+ case 0x4F: rpt_UTC_offset (rpt); break;
+ case 0x54: rpt_1SV_bias (rpt); break;
+ case 0x55: rpt_io_opt (rpt); break;
+ case 0x56: rpt_ENU_velocity (rpt); break;
+ case 0x57: rpt_last_fix_info (rpt); break;
+ case 0x58: rpt_GPS_system_data (rpt); break;
+ case 0x59: rpt_SVs_enabled (rpt); break;
+ case 0x5A: rpt_raw_msmt (rpt); break;
+ case 0x5B: rpt_SV_ephemeris_status (rpt); break;
+ case 0x5C: rpt_SV_tracking_status (rpt); break;
+ case 0x6D: rpt_allSV_selection (rpt); break;
+ case 0x82: rpt_DGPS_position_mode (rpt); break;
+ case 0x83: rpt_double_ECEF_position (rpt); break;
+ case 0x84: rpt_double_lla_position (rpt); break;
+ case 0xBB: rpt_complete_rcvr_config (rpt); break;
+ case 0xBC: rpt_rcvr_serial_port_config (rpt); break;
+
+ case 0x8F: switch (rpt->buf[0])
+ {
+ /* superpackets; parsed according to subcodes */
+ case 0x0B: rpt_8F0B(rpt); break;
+ case 0x14: rpt_8F14(rpt); break;
+ case 0x15: rpt_8F15(rpt); break;
+ case 0x20: rpt_8F20(rpt); break;
+ case 0x41: rpt_8F41(rpt); break;
+ case 0x42: rpt_8F42(rpt); break;
+ case 0x45: rpt_8F45(rpt); break;
+ case 0x4A: rpt_8F4A(rpt); break;
+ case 0x4B: rpt_8F4B(rpt); break;
+ case 0x4D: rpt_8F4D(rpt); break;
+ case 0xA5: rpt_8FA5(rpt); break;
+ case 0xAD: rpt_8FAD(rpt); break;
+ default: parsed = BADID_PARSE; break;
+ }
+ break;
+
+ default: parsed = BADID_PARSE; break;
+ }
+
+ if (parsed != GOOD_PARSE)
+ {
+ /*
+ **The message has TSIP structure (DLEs, etc.)
+ ** but could not be parsed by above routines
+ */
+ unknown_rpt (rpt);
+ }
+
+ /* close TextOutputBuffer */
+ pbuf = '\0';
+}
+
+#endif /* TRIMBLE_OUTPUT_FUNC */
+
+#else /* defined(REFCLOCK) && defined(CLOCK_RIPENCC) */
+int refclock_ripencc_bs;
+#endif /* defined(REFCLOCK) && defined(CLOCK_RIPENCC) */
+
diff --git a/contrib/ntp/ntpd/refclock_zyfer.c b/contrib/ntp/ntpd/refclock_zyfer.c
index b622931..44f2c4d 100644
--- a/contrib/ntp/ntpd/refclock_zyfer.c
+++ b/contrib/ntp/ntpd/refclock_zyfer.c
@@ -233,7 +233,7 @@ zyfer_receive(
* - wait for more data
* Crack the beast, and if it's OK, process it.
*
- * We use refclock_getlin() because we might use LDISC_CLK.
+ * We use refclock_gtlin() because we might use LDISC_CLK.
*
* Under FreeBSD, we get the ! followed by two 14-byte packets.
*/
OpenPOWER on IntegriCloud