aboutsummaryrefslogtreecommitdiff
path: root/contrib/ntp/ntpd/refclock_palisade.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/ntp/ntpd/refclock_palisade.c')
-rw-r--r--contrib/ntp/ntpd/refclock_palisade.c1571
1 files changed, 1571 insertions, 0 deletions
diff --git a/contrib/ntp/ntpd/refclock_palisade.c b/contrib/ntp/ntpd/refclock_palisade.c
new file mode 100644
index 000000000000..3a61d6012213
--- /dev/null
+++ b/contrib/ntp/ntpd/refclock_palisade.c
@@ -0,0 +1,1571 @@
+/*
+ * This software was developed by the Software and Component Technologies
+ * group of Trimble Navigation, Ltd.
+ *
+ * Copyright (c) 1997, 1998, 1999, 2000 Trimble Navigation Ltd.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Trimble Navigation, Ltd.
+ * 4. The name of Trimble Navigation Ltd. may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY TRIMBLE NAVIGATION LTD. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL TRIMBLE NAVIGATION LTD. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * refclock_palisade - clock driver for the Trimble Palisade GPS
+ * timing receiver
+ *
+ * For detailed information on this program, please refer to the html
+ * Refclock 29 page accompanying the NTP distribution.
+ *
+ * for questions / bugs / comments, contact:
+ * sven_dietrich@trimble.com
+ *
+ * Sven-Thorsten Dietrich
+ * 645 North Mary Avenue
+ * Post Office Box 3642
+ * Sunnyvale, CA 94088-3642
+ *
+ * Version 2.45; July 14, 1999
+ *
+ *
+ *
+ * 31/03/06: Added support for Thunderbolt GPS Disciplined Clock.
+ * Contact: Fernando Pablo Hauscarriaga
+ * E-mail: fernandoph@iar.unlp.edu.ar
+ * Home page: www.iar.unlp.edu.ar/~fernandoph
+ * Instituto Argentino de Radioastronomia
+ * www.iar.unlp.edu.ar
+ *
+ * 14/01/07: Conditinal compilation for Thunderbolt support no longer needed
+ * now we use mode 2 for decode thunderbolt packets.
+ * Fernando P. Hauscarriaga
+ *
+ * 30/08/09: Added support for Trimble Acutime Gold Receiver.
+ * Fernando P. Hauscarriaga (fernandoph@iar.unlp.edu.ar)
+ *
+ * 21/04/18: Added support for Resolution devices.
+ *
+ * 03/09/19: Added support for ACE III & Copernicus II.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#if defined(REFCLOCK) && defined(CLOCK_PALISADE)
+
+#ifdef SYS_WINNT
+extern int async_write(int, const void *, unsigned int);
+#undef write
+#define write(fd, data, octets) async_write(fd, data, octets)
+#endif
+
+#include "refclock_palisade.h"
+
+#ifdef DEBUG
+const char * Tracking_Status[15][15] = {
+ { "Doing Fixes\0" }, { "Good 1SV\0" }, { "Approx. 1SV\0" },
+ {"Need Time\0" }, { "Need INIT\0" }, { "PDOP too High\0" },
+ { "Bad 1SV\0" }, { "0SV Usable\0" }, { "1SV Usable\0" },
+ { "2SV Usable\0" }, { "3SV Usable\0" }, { "No Integrity\0" },
+ { "Diff Corr\0" }, { "Overdet Clock\0" }, { "Invalid\0" } };
+#endif
+
+/*
+ * Transfer vector
+ */
+struct refclock refclock_palisade = {
+ palisade_start, /* start up driver */
+ palisade_shutdown, /* shut down driver */
+ palisade_poll, /* transmit poll message */
+ noentry, /* not used */
+ noentry, /* initialize driver (not used) */
+ noentry, /* not used */
+ NOFLAGS /* not used */
+};
+
+static int decode_date(struct refclockproc *pp, const char *cp);
+
+/* Extract the clock type from the mode setting */
+#define CLK_TYPE(x) ((int)(((x)->ttl) & 0x7F))
+
+/* Supported clock types */
+#define CLK_TRIMBLE 0 /* Trimble Palisade */
+#define CLK_PRAECIS 1 /* Endrun Technologies Praecis */
+#define CLK_THUNDERBOLT 2 /* Trimble Thunderbolt GPS Receiver */
+#define CLK_ACUTIME 3 /* Trimble Acutime Gold */
+#define CLK_ACUTIMEB 4 /* Trimble Actutime Gold Port B */
+#define CLK_RESOLUTION 5 /* Trimble Resolution Receivers */
+#define CLK_ACE 6 /* Trimble ACE III */
+#define CLK_COPERNICUS 7 /* Trimble Copernicus II */
+
+int praecis_msg;
+static void praecis_parse(struct recvbuf *rbufp, struct peer *peer);
+
+/* These routines are for sending packets to the Thunderbolt receiver
+ * They are taken from Markus Prosch
+ */
+
+/*
+ * sendcmd - Build data packet for sending
+ */
+static void
+sendcmd (
+ struct packettx *buffer,
+ int c
+ )
+{
+ *buffer->data = DLE;
+ *(buffer->data + 1) = (unsigned char)c;
+ buffer->size = 2;
+}
+
+/*
+ * sendsupercmd - Build super data packet for sending
+ */
+static void
+sendsupercmd (
+ struct packettx *buffer,
+ int c1,
+ int c2
+ )
+{
+ *buffer->data = DLE;
+ *(buffer->data + 1) = (unsigned char)c1;
+ *(buffer->data + 2) = (unsigned char)c2;
+ buffer->size = 3;
+}
+
+/*
+ * sendbyte -
+ */
+static void
+sendbyte (
+ struct packettx *buffer,
+ int b
+ )
+{
+ if (b == DLE)
+ *(buffer->data+buffer->size++) = DLE;
+ *(buffer->data+buffer->size++) = (unsigned char)b;
+}
+
+/*
+ * sendint -
+ */
+static void
+sendint (
+ struct packettx *buffer,
+ int a
+ )
+{
+ sendbyte(buffer, (unsigned char)((a>>8) & 0xff));
+ sendbyte(buffer, (unsigned char)(a & 0xff));
+}
+
+/*
+ * sendetx - Send packet or super packet to the device
+ */
+static int
+sendetx (
+ struct packettx *buffer,
+ int fd
+ )
+{
+ int result;
+
+ *(buffer->data+buffer->size++) = DLE;
+ *(buffer->data+buffer->size++) = ETX;
+ result = write(fd, buffer->data, (unsigned long)buffer->size);
+
+ if (result != -1)
+ return (result);
+ else
+ return (-1);
+}
+
+/*
+ * init_thunderbolt - Prepares Thunderbolt receiver to be used with
+ * NTP (also taken from Markus Prosch).
+ */
+static void
+init_thunderbolt (
+ int fd
+ )
+{
+ struct packettx tx;
+
+ tx.size = 0;
+ tx.data = (u_char *) emalloc(100);
+
+ /* set UTC time */
+ sendsupercmd (&tx, 0x8E, 0xA2);
+ sendbyte (&tx, 0x3);
+ sendetx (&tx, fd);
+
+ /* activate packets 0x8F-AB and 0x8F-AC */
+ sendsupercmd (&tx, 0x8E, 0xA5);
+ sendint (&tx, 0x5);
+ sendetx (&tx, fd);
+
+ free(tx.data);
+}
+
+/*
+ * init_acutime - Prepares Acutime Receiver to be used with NTP
+ */
+static void
+init_acutime (
+ int fd
+ )
+{
+ /* Disable all outputs, Enable Event-Polling on PortA so
+ we can ask for time packets */
+ struct packettx tx;
+
+ tx.size = 0;
+ tx.data = (u_char *) emalloc(100);
+
+ sendsupercmd(&tx, 0x8E, 0xA5);
+ sendbyte(&tx, 0x02);
+ sendbyte(&tx, 0x00);
+ sendbyte(&tx, 0x00);
+ sendbyte(&tx, 0x00);
+ sendetx(&tx, fd);
+
+ free(tx.data);
+}
+
+/*
+ * init_resolution - Prepares Resolution receiver to be used with NTP
+ */
+static void
+init_resolution (
+ int fd
+ )
+{
+ struct packettx tx;
+
+ tx.size = 0;
+ tx.data = (u_char *) emalloc(100);
+
+ /* set UTC time */
+ sendsupercmd (&tx, 0x8E, 0xA2);
+ sendbyte (&tx, 0x3);
+ sendetx (&tx, fd);
+
+ /* squelch PPS output unless locked to at least one satellite */
+ sendsupercmd (&tx, 0x8E, 0x4E);
+ sendbyte (&tx, 0x3);
+ sendetx (&tx, fd);
+
+ /* activate packets 0x8F-AB and 0x8F-AC */
+ sendsupercmd (&tx, 0x8E, 0xA5);
+ sendint (&tx, 0x5);
+ sendetx (&tx, fd);
+
+ free(tx.data);
+}
+
+/*
+ * palisade_start - open the devices and initialize data for processing
+ */
+static int
+palisade_start (
+ int unit,
+ struct peer *peer
+ )
+{
+ struct palisade_unit *up;
+ struct refclockproc *pp;
+ int fd;
+ char gpsdev[20];
+ struct termios tio;
+ u_int speed;
+
+ snprintf(gpsdev, sizeof(gpsdev), DEVICE, unit);
+
+ /*
+ * Open serial port.
+ */
+ speed = (CLK_TYPE(peer) == CLK_COPERNICUS) ? SPEED232COP : SPEED232;
+ fd = refclock_open(&peer->srcadr, gpsdev, speed, LDISC_RAW);
+ if (fd <= 0) {
+#ifdef DEBUG
+ printf("Palisade(%d) start: open %s failed\n", unit, gpsdev);
+#endif
+ return 0;
+ }
+
+ msyslog(LOG_NOTICE, "Palisade(%d) fd: %d dev: %s", unit, fd,
+ gpsdev);
+
+ if (tcgetattr(fd, &tio) < 0) {
+ msyslog(LOG_ERR,
+ "Palisade(%d) tcgetattr(fd, &tio): %m",unit);
+#ifdef DEBUG
+ printf("Palisade(%d) tcgetattr(fd, &tio)\n",unit);
+#endif
+ close(fd);
+ return (0);
+ }
+
+ tio.c_cflag |= (PARENB|PARODD);
+ tio.c_iflag &= ~ICRNL;
+
+ /*
+ * Allocate and initialize unit structure
+ */
+ up = emalloc_zero(sizeof(*up));
+
+ up->type = CLK_TYPE(peer);
+ switch (up->type) {
+ case CLK_TRIMBLE:
+ /* Normal mode, do nothing */
+ break;
+ case CLK_PRAECIS:
+ msyslog(LOG_NOTICE, "Palisade(%d) Praecis mode enabled"
+ ,unit);
+ break;
+ case CLK_THUNDERBOLT:
+ msyslog(LOG_NOTICE, "Palisade(%d) Thunderbolt mode enabled"
+ ,unit);
+ tio.c_cflag = (CS8|CLOCAL|CREAD);
+ break;
+ case CLK_ACUTIME:
+ msyslog(LOG_NOTICE, "Palisade(%d) Acutime Gold mode enabled"
+ ,unit);
+ break;
+ case CLK_RESOLUTION:
+ msyslog(LOG_NOTICE, "Palisade(%d) Resolution mode enabled"
+ ,unit);
+ tio.c_cflag = (CS8|CLOCAL|CREAD|PARENB|PARODD);
+ break;
+ case CLK_ACE:
+ msyslog(LOG_NOTICE, "Palisade(%d) ACE III mode enabled"
+ ,unit);
+ tio.c_cflag = (CS8|CLOCAL|CREAD|PARENB|PARODD);
+ break;
+ case CLK_COPERNICUS:
+ msyslog(LOG_NOTICE, "Palisade(%d) Copernicus II mode enabled"
+ ,unit);
+ /* Must use ORing/ANDing to set/clear c_cflag bits otherwise
+ CBAUD gets set back to 0. This ought to be an issue for
+ the other modes above but it seems that the baud rate
+ defaults to 9600 if CBAUD gets set to 0. */
+ tio.c_cflag &= ~(PARENB|PARODD);
+ break;
+ default:
+ msyslog(LOG_NOTICE, "Palisade(%d) mode unknown",unit);
+ break;
+ }
+ if (tcsetattr(fd, TCSANOW, &tio) == -1) {
+ msyslog(LOG_ERR, "Palisade(%d) tcsetattr(fd, &tio): %m",unit);
+#ifdef DEBUG
+ printf("Palisade(%d) tcsetattr(fd, &tio)\n",unit);
+#endif
+ close(fd);
+ free(up);
+ return 0;
+ }
+
+ pp = peer->procptr;
+ pp->io.clock_recv = palisade_io;
+ pp->io.srcclock = peer;
+ pp->io.datalen = 0;
+ pp->io.fd = fd;
+ if (!io_addclock(&pp->io)) {
+#ifdef DEBUG
+ printf("Palisade(%d) io_addclock\n",unit);
+#endif
+ close(fd);
+ pp->io.fd = -1;
+ free(up);
+ return (0);
+ }
+
+ /*
+ * Initialize miscellaneous variables
+ */
+ pp->unitptr = up;
+ pp->clockdesc = DESCRIPTION;
+
+ peer->precision = PRECISION;
+ peer->sstclktype = CTL_SST_TS_UHF;
+ peer->minpoll = TRMB_MINPOLL;
+ peer->maxpoll = TRMB_MAXPOLL;
+ memcpy((char *)&pp->refid, REFID, 4);
+
+ up->leap_status = 0;
+ up->unit = (short) unit;
+ up->rpt_status = TSIP_PARSED_EMPTY;
+ up->rpt_cnt = 0;
+
+ if (up->type == CLK_THUNDERBOLT)
+ init_thunderbolt(fd);
+ if (up->type == CLK_ACUTIME)
+ init_acutime(fd);
+ if (up->type == CLK_RESOLUTION)
+ init_resolution(fd);
+
+ return 1;
+}
+
+
+/*
+ * palisade_shutdown - shut down the clock
+ */
+static void
+palisade_shutdown (
+ int unit,
+ struct peer *peer
+ )
+{
+ struct palisade_unit *up;
+ struct refclockproc *pp;
+ pp = peer->procptr;
+ up = pp->unitptr;
+ if (-1 != pp->io.fd)
+ io_closeclock(&pp->io);
+ if (NULL != up)
+ free(up);
+}
+
+
+/*
+ * unpack helpers
+ */
+
+static inline uint8_t
+get_u8(
+ const char *cp)
+{
+ return ((const u_char*)cp)[0];
+}
+
+static inline uint16_t
+get_u16(
+ const char *cp)
+{
+ return ((uint16_t)get_u8(cp) << 8) | get_u8(cp + 1);
+}
+
+/*
+ * unpack & fix date (the receiver provides a valid time for 1024 weeks
+ * after 1997-12-14 and therefore folds back in 2017, 2037,...)
+ *
+ * Returns -1 on error, day-of-month + (month * 32) othertwise.
+ */
+int
+decode_date(
+ struct refclockproc *pp,
+ const char *cp)
+{
+ static int32_t s_baseday = 0;
+
+ struct calendar jd;
+ int32_t rd;
+
+ if (0 == s_baseday) {
+ if (!ntpcal_get_build_date(&jd)) {
+ jd.year = 2015;
+ jd.month = 1;
+ jd.monthday = 1;
+ }
+ s_baseday = ntpcal_date_to_rd(&jd);
+ }
+
+ /* get date fields and convert to RDN */
+ jd.monthday = get_u8 ( cp );
+ jd.month = get_u8 (cp + 1);
+ jd.year = get_u16(cp + 2);
+ rd = ntpcal_date_to_rd(&jd);
+
+ /* for the paranoid: do reverse calculation and cross-check */
+ ntpcal_rd_to_date(&jd, rd);
+ if ((jd.monthday != get_u8 ( cp )) ||
+ (jd.month != get_u8 (cp + 1)) ||
+ (jd.year != get_u16(cp + 2)) )
+ return - 1;
+
+ /* calculate cycle shift to base day and calculate re-folded
+ * date
+ *
+ * One could do a proper modulo calculation here, but a counting
+ * loop is probably faster for the next few rollovers...
+ */
+ while (rd < s_baseday)
+ rd += 7*1024;
+ ntpcal_rd_to_date(&jd, rd);
+
+ /* fill refclock structure & indicate success */
+ pp->day = jd.yearday;
+ pp->year = jd.year;
+ return ((int)jd.month << 5) | jd.monthday;
+}
+
+
+/*
+ * TSIP_decode - decode the TSIP data packets
+ */
+int
+TSIP_decode (
+ struct peer *peer
+ )
+{
+ int st;
+ long secint;
+ double secs;
+ double secfrac;
+ unsigned short event = 0;
+ int mmday;
+ long tow;
+ uint16_t wn;
+ int GPS_UTC_Offset;
+
+ struct palisade_unit *up;
+ struct refclockproc *pp;
+
+ pp = peer->procptr;
+ up = pp->unitptr;
+
+ /*
+ * Check the time packet, decode its contents.
+ * If the timecode has invalid length or is not in
+ * proper format, declare bad format and exit.
+ */
+
+ if ((up->type != CLK_THUNDERBOLT) &&
+ (up->type != CLK_ACUTIME ) &&
+ (up->type != CLK_RESOLUTION ) &&
+ (up->type != CLK_ACE ) &&
+ (up->type != CLK_COPERNICUS ) )
+ {
+ if ((up->rpt_buf[0] == (char) 0x41) ||
+ (up->rpt_buf[0] == (char) 0x46) ||
+ (up->rpt_buf[0] == (char) 0x54) ||
+ (up->rpt_buf[0] == (char) 0x4B) ||
+ (up->rpt_buf[0] == (char) 0x6D)) {
+
+ /* standard time packet - GPS time and GPS week number */
+#ifdef DEBUG
+ printf("Palisade Port B packets detected. Connect to Port A\n");
+#endif
+
+ return 0;
+ }
+ }
+
+ /*
+ * We cast both to u_char as 0x8f uses the sign bit on a char
+ */
+ if ((u_char) up->rpt_buf[0] == (u_char) 0x8f) {
+ /*
+ * Superpackets
+ */
+ event = (unsigned short) (getint((u_char *) &mb(1)) & 0xffff);
+ if (!((pp->sloppyclockflag & CLK_FLAG2) || event))
+ /* Ignore Packet */
+ return 0;
+
+ switch (mb(0) & 0xff) {
+
+ case PACKET_8F0B:
+
+ if (up->polled <= 0)
+ return 0;
+
+ if (up->rpt_cnt != LENCODE_8F0B) /* check length */
+ break;
+
+#ifdef DEBUG
+ if (debug > 1) {
+ int ts;
+ double lat, lon, alt;
+ lat = getdbl((u_char *) &mb(42)) * R2D;
+ lon = getdbl((u_char *) &mb(50)) * R2D;
+ alt = getdbl((u_char *) &mb(58));
+
+ printf("TSIP_decode: unit %d: Latitude: %03.4f Longitude: %03.4f Alt: %05.2f m\n",
+ up->unit, lat,lon,alt);
+ printf("TSIP_decode: unit %d: Sats:",
+ up->unit);
+ for (st = 66, ts = 0; st <= 73; st++)
+ if (mb(st)) {
+ if (mb(st) > 0) ts++;
+ printf(" %02d", mb(st));
+ }
+ printf(" : Tracking %d\n", ts);
+ }
+#endif
+
+ GPS_UTC_Offset = getint((u_char *) &mb(16));
+ if (GPS_UTC_Offset == 0) { /* Check UTC offset */
+#ifdef DEBUG
+ printf("TSIP_decode: UTC Offset Unknown\n");
+#endif
+ break;
+ }
+
+ secs = getdbl((u_char *) &mb(3));
+ secint = (long) secs;
+ secfrac = secs - secint; /* 0.0 <= secfrac < 1.0 */
+
+ pp->nsec = (long) (secfrac * 1000000000);
+
+ secint %= 86400; /* Only care about today */
+ pp->hour = secint / 3600;
+ secint %= 3600;
+ pp->minute = secint / 60;
+ secint %= 60;
+ pp->second = secint % 60;
+
+ mmday = decode_date(pp, &mb(11));
+ if (mmday < 0)
+ break;
+
+#ifdef DEBUG
+ if (debug > 1)
+ printf("TSIP_decode: unit %d: %02X #%d %02d:%02d:%02d.%09ld %02d/%02d/%04d UTC %02d\n",
+ up->unit, mb(0) & 0xff, event, pp->hour, pp->minute,
+ pp->second, pp->nsec, (mmday >> 5), (mmday & 31), pp->year, GPS_UTC_Offset);
+#endif
+ /* Only use this packet when no
+ * 8F-AD's are being received
+ */
+
+ if (up->leap_status) {
+ up->leap_status = 0;
+ return 0;
+ }
+
+ return 2;
+ break;
+
+ case PACKET_NTP:
+ /* Palisade-NTP Packet */
+
+ if (up->rpt_cnt != LENCODE_NTP) /* check length */
+ break;
+
+ up->leap_status = mb(19);
+
+ if (up->polled <= 0)
+ return 0;
+
+ /* Check Tracking Status */
+ st = mb(18);
+ if (st < 0 || st > 14)
+ st = 14;
+ if ((st >= 2 && st <= 7) || st == 11 || st == 12) {
+#ifdef DEBUG
+ printf("TSIP_decode: Not Tracking Sats : %s\n",
+ *Tracking_Status[st]);
+#endif
+ refclock_report(peer, CEVNT_BADTIME);
+ up->polled = -1;
+ return 0;
+ break;
+ }
+
+ mmday = decode_date(pp, &mb(14));
+ if (mmday < 0)
+ break;
+ up->month = (mmday >> 5); /* Save for LEAP check */
+
+ if ( (up->leap_status & PALISADE_LEAP_PENDING) &&
+ /* Avoid early announce: https://bugs.ntp.org/2773 */
+ (6 == up->month || 12 == up->month) ) {
+ if (up->leap_status & PALISADE_UTC_TIME)
+ pp->leap = LEAP_ADDSECOND;
+ else
+ pp->leap = LEAP_DELSECOND;
+ }
+ else if (up->leap_status)
+ pp->leap = LEAP_NOWARNING;
+
+ else { /* UTC flag is not set:
+ * Receiver may have been reset, and lost
+ * its UTC almanac data */
+ pp->leap = LEAP_NOTINSYNC;
+#ifdef DEBUG
+ printf("TSIP_decode: UTC Almanac unavailable: %d\n",
+ mb(19));
+#endif
+ refclock_report(peer, CEVNT_BADTIME);
+ up->polled = -1;
+ return 0;
+ }
+
+ pp->nsec = (long) (getdbl((u_char *) &mb(3))
+ * 1000000000);
+
+ pp->hour = mb(11);
+ pp->minute = mb(12);
+ pp->second = mb(13);
+
+#ifdef DEBUG
+ if (debug > 1)
+ printf("TSIP_decode: unit %d: %02X #%d %02d:%02d:%02d.%09ld %02d/%02d/%04d UTC %02x %s\n",
+ up->unit, mb(0) & 0xff, event, pp->hour, pp->minute,
+ pp->second, pp->nsec, (mmday >> 5), (mmday & 31), pp->year,
+ mb(19), *Tracking_Status[st]);
+#endif
+ return 1;
+ break;
+
+ case PACKET_8FAC:
+ if (up->polled <= 0)
+ return 0;
+
+ if (up->rpt_cnt != LENCODE_8FAC)/* check length */
+ break;
+
+#ifdef DEBUG
+ if (debug > 1) {
+ double lat, lon, alt;
+ lat = getdbl((u_char *) &mb(36)) * R2D;
+ lon = getdbl((u_char *) &mb(44)) * R2D;
+ alt = getdbl((u_char *) &mb(52));
+
+ printf("TSIP_decode: unit %d: Latitude: %03.4f Longitude: %03.4f Alt: %05.2f m\n",
+ up->unit, lat,lon,alt);
+ printf("TSIP_decode: unit %d\n", up->unit);
+ }
+#endif
+ if ( (getint((u_char *) &mb(10)) & 0x80) &&
+ /* Avoid early announce: https://bugs.ntp.org/2773 */
+ (6 == up->month || 12 == up->month) )
+ pp->leap = LEAP_ADDSECOND; /* we ASSUME addsecond */
+ else
+ pp->leap = LEAP_NOWARNING;
+
+#ifdef DEBUG
+ if (debug > 1)
+ printf("TSIP_decode: unit %d: 0x%02x leap %d\n",
+ up->unit, mb(0) & 0xff, pp->leap);
+ if (debug > 1) {
+ printf("Receiver MODE: 0x%02X\n", (u_char)mb(1));
+ if (mb(1) == 0x00)
+ printf(" AUTOMATIC\n");
+ if (mb(1) == 0x01)
+ printf(" SINGLE SATELLITE\n");
+ if (mb(1) == 0x03)
+ printf(" HORIZONTAL(2D)\n");
+ if (mb(1) == 0x04)
+ printf(" FULL POSITION(3D)\n");
+ if (mb(1) == 0x05)
+ printf(" DGPR REFERENCE\n");
+ if (mb(1) == 0x06)
+ printf(" CLOCK HOLD(2D)\n");
+ if (mb(1) == 0x07)
+ printf(" OVERDETERMINED CLOCK\n");
+
+ printf("\n** Disciplining MODE 0x%02X:\n", (u_char)mb(2));
+ if (mb(2) == 0x00)
+ printf(" NORMAL\n");
+ if (mb(2) == 0x01)
+ printf(" POWER-UP\n");
+ if (mb(2) == 0x02)
+ printf(" AUTO HOLDOVER\n");
+ if (mb(2) == 0x03)
+ printf(" MANUAL HOLDOVER\n");
+ if (mb(2) == 0x04)
+ printf(" RECOVERY\n");
+ if (mb(2) == 0x06)
+ printf(" DISCIPLINING DISABLED\n");
+ }
+#endif
+ return 0;
+ break;
+
+ case PACKET_8FAB:
+ /* Thunderbolt Primary Timing Packet */
+
+ if (up->rpt_cnt != LENCODE_8FAB) /* check length */
+ break;
+
+ if (up->polled <= 0)
+ return 0;
+
+ GPS_UTC_Offset = getint((u_char *) &mb(7));
+
+ if (GPS_UTC_Offset == 0){ /* Check UTC Offset */
+#ifdef DEBUG
+ printf("TSIP_decode: UTC Offset Unknown\n");
+#endif
+ break;
+ }
+
+
+ if ((mb(9) & 0x1d) == 0x0) {
+ /* if we know the GPS time and the UTC offset,
+ we expect UTC timing information !!! */
+
+ pp->leap = LEAP_NOTINSYNC;
+ refclock_report(peer, CEVNT_BADTIME);
+ up->polled = -1;
+ return 0;
+ }
+
+ pp->nsec = 0;
+#ifdef DEBUG
+ printf("\nTiming Flags are:\n");
+ printf("Timing flag value is: 0x%X\n", mb(9));
+ if ((mb(9) & 0x01) != 0)
+ printf (" Getting UTC time\n");
+ else
+ printf (" Getting GPS time\n");
+ if ((mb(9) & 0x02) != 0)
+ printf (" PPS is from UTC\n");
+ else
+ printf (" PPS is from GPS\n");
+ if ((mb(9) & 0x04) != 0)
+ printf (" Time is not Set\n");
+ else
+ printf (" Time is Set\n");
+ if ((mb(9) & 0x08) != 0)
+ printf(" I dont have UTC info\n");
+ else
+ printf (" I have UTC info\n");
+ if ((mb(9) & 0x10) != 0)
+ printf (" Time is from USER\n\n");
+ else
+ printf (" Time is from GPS\n\n");
+#endif
+
+ mmday = decode_date(pp, &mb(13));
+ if (mmday < 0)
+ break;
+ tow = getlong((u_char *) &mb(1));
+#ifdef DEBUG
+ if (debug > 1) {
+ printf("pp->day: %d\n", pp->day);
+ printf("TOW: %ld\n", tow);
+ printf("DAY: %d\n", (mmday & 31));
+ }
+#endif
+ pp->hour = mb(12);
+ pp->minute = mb(11);
+ pp->second = mb(10);
+
+
+#ifdef DEBUG
+ if (debug > 1)
+ printf("TSIP_decode: unit %d: %02X #%d %02d:%02d:%02d.%09ld %02d/%02d/%04d ",
+ up->unit, mb(0) & 0xff, event, pp->hour, pp->minute, pp->second,
+ pp->nsec, (mmday >> 5), (mmday & 31), pp->year);
+#endif
+ return 1;
+ break;
+
+ default:
+ /* Ignore Packet */
+ return 0;
+ } /* switch */
+ } /* if 8F packets */
+
+ else if (up->rpt_buf[0] == (u_char)0x42) {
+ printf("0x42\n");
+ return 0;
+ }
+ else if (up->rpt_buf[0] == (u_char)0x43) {
+ printf("0x43\n");
+ return 0;
+ }
+ else if ((up->rpt_buf[0] == PACKET_41) & (up->type == CLK_THUNDERBOLT)){
+ printf("Undocumented 0x41 packet on Thunderbolt\n");
+ return 0;
+ }
+ else if ((up->rpt_buf[0] == PACKET_41A) & (up->type == CLK_ACUTIME)) {
+#ifdef DEBUG
+ printf("GPS TOW: %ld\n", (long)getlong((u_char *) &mb(0)));
+ printf("GPS WN: %d\n", getint((u_char *) &mb(4)));
+ printf("GPS UTC-GPS Offset: %ld\n", (long)getlong((u_char *) &mb(6)));
+#endif
+ return 0;
+ }
+
+ /* GPS time packet for ACE III or Copernicus II receiver */
+ else if ((up->rpt_buf[0] == PACKET_41) &&
+ ((up->type == CLK_ACE) || (up->type == CLK_COPERNICUS))) {
+#ifdef DEBUG
+ if ((debug > 1) && (up->type == CLK_ACE))
+ printf("TSIP_decode: Packet 0x41 seen in ACE III mode\n");
+ if ((debug > 1) && (up->type == CLK_COPERNICUS))
+ printf("TSIP_decode: Packet 0x41 seen in Copernicus II mode\n");
+#endif
+ if (up->rpt_cnt != LENCODE_41) { /* check length */
+ refclock_report(peer, CEVNT_BADREPLY);
+ up->polled = -1;
+#ifdef DEBUG
+ printf("TSIP_decode: unit %d: bad packet %02x len %d\n",
+ up->unit, up->rpt_buf[0] & 0xff, up->rpt_cnt);
+#endif
+ return 0;
+ }
+ if (up->polled <= 0)
+ return 0;
+ tow = (long)getsingle((u_char *) &mb(0));
+ wn = (uint16_t)getint((u_char *) &mb(4));
+ GPS_UTC_Offset = (int)getsingle((u_char *) &mb(6));
+ if (GPS_UTC_Offset == 0){ /* Check UTC Offset */
+#ifdef DEBUG
+ printf("TSIP_decode: UTC Offset Unknown\n");
+#endif
+ refclock_report(peer, CEVNT_BADREPLY);
+ up->polled = -1;
+ return 0;
+ }
+ /* Get date & time from WN & ToW minus offset */
+ {
+ TCivilDate cd;
+ TGpsDatum wd;
+ l_fp ugo; /* UTC-GPS offset, negative number */
+ ugo.Ul_i.Xl_i = (int32_t)-GPS_UTC_Offset;
+ ugo.l_uf = 0;
+ wd = gpscal_from_gpsweek((wn % 1024), (int32_t)tow, ugo);
+ gpscal_to_calendar(&cd, &wd);
+ pp->year = cd.year;
+ pp->day = cd.yearday;
+ pp->hour = cd.hour;
+ pp->minute = cd.minute;
+ pp->second = cd.second;
+ pp->nsec = 0;
+ pp->leap = LEAP_NOWARNING;
+#ifdef DEBUG
+ if (debug > 1) {
+ printf("GPS TOW: %ld\n", tow);
+ printf("GPS WN: %d\n", wn);
+ printf("GPS UTC-GPS Offset: %d\n", GPS_UTC_Offset);
+ printf("TSIP_decode: unit %d: %02X #%d %02d:%02d:%02d.%09ld %02d/%02d/%04d ",
+ up->unit, mb(0) & 0xff, event, pp->hour, pp->minute, pp->second,
+ pp->nsec, cd.month, cd.monthday, pp->year);
+ }
+#endif
+ }
+ return 1;
+ }
+
+ /* Health Status for Acutime Receiver */
+ else if ((up->rpt_buf[0] == PACKET_46) & (up->type == CLK_ACUTIME)) {
+#ifdef DEBUG
+ if (debug > 1)
+ /* Status Codes */
+ switch (mb(0)) {
+ case 0x00:
+ printf ("Doing Position Fixes\n");
+ break;
+ case 0x01:
+ printf ("Do not have GPS time yet\n");
+ break;
+ case 0x03:
+ printf ("PDOP is too high\n");
+ break;
+ case 0x08:
+ printf ("No usable satellites\n");
+ break;
+ case 0x09:
+ printf ("Only 1 usable satellite\n");
+ break;
+ case 0x0A:
+ printf ("Only 2 usable satellites\n");
+ break;
+ case 0x0B:
+ printf ("Only 3 usable satellites\n");
+ break;
+ case 0x0C:
+ printf("The Chosen satellite is unusable\n");
+ break;
+ }
+#endif
+ /* Error Codes */
+ if (mb(1) != 0) {
+
+ refclock_report(peer, CEVNT_BADTIME);
+ up->polled = -1;
+#ifdef DEBUG
+ if (debug > 1) {
+ if (mb(1) & 0x01)
+ printf ("Signal Processor Error, reset unit.\n");
+ if (mb(1) & 0x02)
+ printf ("Alignment error, channel or chip 1, reset unit.\n");
+ if (mb(1) & 0x03)
+ printf ("Alignment error, channel or chip 2, reset unit.\n");
+ if (mb(1) & 0x04)
+ printf ("Antenna feed line fault (open or short)\n");
+ if (mb(1) & 0x05)
+ printf ("Excessive reference frequency error, refer to packet 0x2D and packet 0x4D documentation for further information\n");
+ }
+#endif
+
+ return 0;
+ }
+ }
+
+ /* Health Status for Copernicus II Receiver */
+ else if ((up->rpt_buf[0] == PACKET_46) && (up->type == CLK_COPERNICUS)) {
+#ifdef DEBUG
+ if (debug > 1)
+ /* Status Codes */
+ switch (mb(0)) {
+ case 0x00:
+ printf ("Doing Position Fixes\n");
+ break;
+ case 0x01:
+ printf ("Do not have GPS time yet\n");
+ break;
+ case 0x03:
+ printf ("PDOP is too high\n");
+ break;
+ case 0x04:
+ printf("The Chosen satellite is unusable\n");
+ break;
+ case 0x08:
+ printf ("No usable satellites\n");
+ break;
+ case 0x09:
+ printf ("Only 1 usable satellite\n");
+ break;
+ case 0x0A:
+ printf ("Only 2 usable satellites\n");
+ break;
+ case 0x0B:
+ printf ("Only 3 usable satellites\n");
+ break;
+ }
+#endif
+ /* Error Codes */
+ if ((mb(1) & 0x3E) != 0) { /* Don't regard bits 0 and 6 as errors */
+ refclock_report(peer, CEVNT_BADTIME);
+ up->polled = -1;
+#ifdef DEBUG
+ if (debug > 1) {
+ if ((mb(1) & 0x18) == 0x08)
+ printf ("Antenna feed line fault (open)\n");
+ if ((mb(1) & 0x18) == 0x18)
+ printf ("Antenna feed line fault (short)\n");
+ }
+#endif
+ }
+ return 0;
+ }
+
+ /* Other packets output by ACE III & Copernicus II Receivers, dropped silently */
+ else if (((up->rpt_buf[0] == (char) 0x4A) ||
+ (up->rpt_buf[0] == (char) 0x4B) ||
+ (up->rpt_buf[0] == (char) 0x56) ||
+ (up->rpt_buf[0] == (char) 0x5F) ||
+ (up->rpt_buf[0] == (char) 0x6D) ||
+ (up->rpt_buf[0] == (char) 0x82) ||
+ (up->rpt_buf[0] == (char) 0x84)) &&
+ ((up->type == CLK_ACE) || (up->type == CLK_COPERNICUS))) {
+#ifdef DEBUG
+ if ((debug > 1) && (up->type == CLK_ACE))
+ printf("TSIP_decode: Packet 0x%2x seen in ACE III mode\n", (up->rpt_buf[0] & 0XFF));
+ if ((debug > 1) && (up->type == CLK_COPERNICUS))
+ printf("TSIP_decode: Packet 0x%2x seen in Copernicus II mode\n", (up->rpt_buf[0] & 0XFF));
+#endif
+ return 0;
+ }
+
+ else if (up->rpt_buf[0] == 0x54)
+ return 0;
+
+ else if (up->rpt_buf[0] == PACKET_6D) {
+#ifdef DEBUG
+ int sats;
+
+ if ((mb(0) & 0x01) && (mb(0) & 0x02))
+ printf("2d Fix Dimension\n");
+ if (mb(0) & 0x04)
+ printf("3d Fix Dimension\n");
+
+ if (mb(0) & 0x08)
+ printf("Fix Mode is MANUAL\n");
+ else
+ printf("Fix Mode is AUTO\n");
+
+ sats = mb(0) & 0xF0;
+ sats = sats >> 4;
+ printf("Tracking %d Satellites\n", sats);
+#endif
+ return 0;
+ } /* else if not super packet */
+ refclock_report(peer, CEVNT_BADREPLY);
+ up->polled = -1;
+#ifdef DEBUG
+ printf("TSIP_decode: unit %d: bad packet %02x-%02x event %d len %d\n",
+ up->unit, up->rpt_buf[0] & 0xff, mb(0) & 0xff,
+ event, up->rpt_cnt);
+#endif
+ return 0;
+}
+
+/*
+ * palisade__receive - receive data from the serial interface
+ */
+
+static void
+palisade_receive (
+ struct peer * peer
+ )
+{
+ struct palisade_unit *up;
+ struct refclockproc *pp;
+
+ /*
+ * Initialize pointers and read the timecode and timestamp.
+ */
+ pp = peer->procptr;
+ up = pp->unitptr;
+
+ if (! TSIP_decode(peer)) return;
+
+ if (up->polled <= 0)
+ return; /* no poll pending, already received or timeout */
+
+ up->polled = 0; /* Poll reply received */
+ pp->lencode = 0; /* clear time code */
+#ifdef DEBUG
+ if (debug)
+ printf(
+ "palisade_receive: unit %d: %4d %03d %02d:%02d:%02d.%09ld\n",
+ up->unit, pp->year, pp->day, pp->hour, pp->minute,
+ pp->second, pp->nsec);
+#endif
+
+ /*
+ * Process the sample
+ * Generate timecode: YYYY DoY HH:MM:SS.microsec
+ * report and process
+ */
+
+ snprintf(pp->a_lastcode, sizeof(pp->a_lastcode),
+ "%4d %03d %02d:%02d:%02d.%09ld",
+ pp->year, pp->day,
+ pp->hour,pp->minute, pp->second, pp->nsec);
+ pp->lencode = 24;
+
+ if (!refclock_process(pp)) {
+ refclock_report(peer, CEVNT_BADTIME);
+
+#ifdef DEBUG
+ printf("palisade_receive: unit %d: refclock_process failed!\n",
+ up->unit);
+#endif
+ return;
+ }
+
+ record_clock_stats(&peer->srcadr, pp->a_lastcode);
+
+#ifdef DEBUG
+ if (debug)
+ printf("palisade_receive: unit %d: %s\n",
+ up->unit, prettydate(&pp->lastrec));
+#endif
+ pp->lastref = pp->lastrec;
+ refclock_receive(peer);
+}
+
+
+/*
+ * palisade_poll - called by the transmit procedure
+ *
+ */
+static void
+palisade_poll (
+ int unit,
+ struct peer *peer
+ )
+{
+ struct palisade_unit *up;
+ struct refclockproc *pp;
+
+ pp = peer->procptr;
+ up = pp->unitptr;
+
+ pp->polls++;
+ if (up->polled > 0) /* last reply never arrived or error */
+ refclock_report(peer, CEVNT_TIMEOUT);
+
+ up->polled = 2; /* synchronous packet + 1 event */
+
+#ifdef DEBUG
+ if (debug)
+ printf("palisade_poll: unit %d: polling %s\n", unit,
+ (pp->sloppyclockflag & CLK_FLAG2) ?
+ "synchronous packet" : "event");
+#endif
+
+ if (pp->sloppyclockflag & CLK_FLAG2)
+ return; /* using synchronous packet input */
+
+ if(up->type == CLK_PRAECIS) {
+ if (write(peer->procptr->io.fd,"SPSTAT\r\n",8) < 0) {
+ msyslog(LOG_ERR, "Palisade(%d) write: %m:",unit);
+ } else {
+ praecis_msg = 1;
+ return;
+ }
+ }
+
+ if (HW_poll(pp) < 0)
+ refclock_report(peer, CEVNT_FAULT);
+}
+
+static void
+praecis_parse (
+ struct recvbuf *rbufp,
+ struct peer *peer
+ )
+{
+ static char buf[100];
+ static int p = 0;
+ struct refclockproc *pp;
+
+ pp = peer->procptr;
+
+ if (p + rbufp->recv_length >= sizeof buf) {
+ struct palisade_unit *up;
+ up = pp->unitptr;
+
+ /*
+ * We COULD see if there is a \r\n in the incoming
+ * buffer before it overflows, and then process the
+ * current line.
+ *
+ * Similarly, if we already have a hunk of data that
+ * we're now flushing, that will cause the line of
+ * data we're in the process of collecting to be garbage.
+ *
+ * Since we now check for this overflow and log when it
+ * happens, we're now in a better place to easily see
+ * what's going on and perhaps better choices can be made.
+ */
+
+ /* Do we need to log the size of the overflow? */
+ msyslog(LOG_ERR, "Palisade(%d) praecis_parse(): input buffer overflow",
+ up->unit);
+
+ p = 0;
+ praecis_msg = 0;
+
+ refclock_report(peer, CEVNT_BADREPLY);
+
+ return;
+ }
+
+ memcpy(buf+p, rbufp->recv_buffer, rbufp->recv_length);
+ p += rbufp->recv_length;
+
+ if ( p >= 2
+ && buf[p-2] == '\r'
+ && buf[p-1] == '\n') {
+ buf[p-2] = '\0';
+ record_clock_stats(&peer->srcadr, buf);
+
+ p = 0;
+ praecis_msg = 0;
+
+ if (HW_poll(pp) < 0) {
+ refclock_report(peer, CEVNT_FAULT);
+ }
+ }
+ return;
+}
+
+static void
+palisade_io (
+ struct recvbuf *rbufp
+ )
+{
+ /*
+ * Initialize pointers and read the timecode and timestamp.
+ */
+ struct palisade_unit *up;
+ struct refclockproc *pp;
+ struct peer *peer;
+
+ char * c, * d;
+
+ peer = rbufp->recv_peer;
+ pp = peer->procptr;
+ up = pp->unitptr;
+
+ if(up->type == CLK_PRAECIS) {
+ if(praecis_msg) {
+ praecis_parse(rbufp,peer);
+ return;
+ }
+ }
+
+ c = (char *) &rbufp->recv_space;
+ d = c + rbufp->recv_length;
+
+ while (c != d) {
+
+ /* Build time packet */
+ switch (up->rpt_status) {
+
+ case TSIP_PARSED_DLE_1:
+ switch (*c)
+ {
+ case 0:
+ case DLE:
+ case ETX:
+ up->rpt_status = TSIP_PARSED_EMPTY;
+ break;
+
+ default:
+ up->rpt_status = TSIP_PARSED_DATA;
+ /* save packet ID */
+ up->rpt_buf[0] = *c;
+ break;
+ }
+ break;
+
+ case TSIP_PARSED_DATA:
+ if (*c == DLE)
+ up->rpt_status = TSIP_PARSED_DLE_2;
+ else
+ mb(up->rpt_cnt++) = *c;
+ break;
+
+ case TSIP_PARSED_DLE_2:
+ if (*c == DLE) {
+ up->rpt_status = TSIP_PARSED_DATA;
+ mb(up->rpt_cnt++) =
+ *c;
+ }
+ else if (*c == ETX)
+ up->rpt_status = TSIP_PARSED_FULL;
+ else {
+ /* error: start new report packet */
+ up->rpt_status = TSIP_PARSED_DLE_1;
+ up->rpt_buf[0] = *c;
+ }
+ break;
+
+ case TSIP_PARSED_FULL:
+ case TSIP_PARSED_EMPTY:
+ default:
+ if ( *c != DLE)
+ up->rpt_status = TSIP_PARSED_EMPTY;
+ else
+ up->rpt_status = TSIP_PARSED_DLE_1;
+ break;
+ }
+
+ c++;
+
+ if (up->rpt_status == TSIP_PARSED_DLE_1) {
+ up->rpt_cnt = 0;
+ if (pp->sloppyclockflag & CLK_FLAG2)
+ /* stamp it */
+ get_systime(&pp->lastrec);
+ }
+ else if (up->rpt_status == TSIP_PARSED_EMPTY)
+ up->rpt_cnt = 0;
+
+ else if (up->rpt_cnt > BMAX)
+ up->rpt_status =TSIP_PARSED_EMPTY;
+
+ if (up->rpt_status == TSIP_PARSED_FULL)
+ palisade_receive(peer);
+
+ } /* while chars in buffer */
+}
+
+
+/*
+ * Trigger the Palisade's event input, which is driven off the RTS
+ *
+ * Take a system time stamp to match the GPS time stamp.
+ *
+ */
+long
+HW_poll (
+ struct refclockproc * pp /* pointer to unit structure */
+ )
+{
+ int x; /* state before & after RTS set */
+ struct palisade_unit *up;
+ struct packettx tx;
+
+ up = pp->unitptr;
+
+ if (up->type == CLK_ACE) {
+ /* Poll by sending a 0x21 command */
+ tx.size = 0;
+ tx.data = (u_char *) emalloc(100);
+ sendcmd (&tx, 0x21);
+ sendetx (&tx, pp->io.fd);
+ free(tx.data);
+ } else {
+
+ /* read the current status, so we put things back right */
+ if (ioctl(pp->io.fd, TIOCMGET, &x) < 0) {
+ DPRINTF(1, ("Palisade HW_poll: unit %d: GET %m\n",
+ up->unit));
+ msyslog(LOG_ERR, "Palisade(%d) HW_poll: ioctl(fd,GET): %m",
+ up->unit);
+ return -1;
+ }
+
+ x |= TIOCM_RTS; /* turn on RTS */
+
+ /* Edge trigger */
+ if (up->type == CLK_ACUTIME)
+ if (write (pp->io.fd, "", 1) != 1)
+ msyslog(LOG_WARNING,
+ "Palisade(%d) HW_poll: failed to send trigger: %m",
+ up->unit);
+
+ if (ioctl(pp->io.fd, TIOCMSET, &x) < 0) {
+#ifdef DEBUG
+ if (debug)
+ printf("Palisade HW_poll: unit %d: SET \n", up->unit);
+#endif
+ msyslog(LOG_ERR,
+ "Palisade(%d) HW_poll: ioctl(fd, SET, RTS_on): %m",
+ up->unit);
+ return -1;
+ }
+
+ x &= ~TIOCM_RTS; /* turn off RTS */
+
+ } /* (up->type != CLK_ACE) */
+
+ /* poll timestamp */
+ get_systime(&pp->lastrec);
+
+ if (up->type != CLK_ACE) {
+ if (ioctl(pp->io.fd, TIOCMSET, &x) == -1) {
+#ifdef DEBUG
+ if (debug)
+ printf("Palisade HW_poll: unit %d: UNSET \n", up->unit);
+#endif
+ msyslog(LOG_ERR,
+ "Palisade(%d) HW_poll: ioctl(fd, UNSET, RTS_off): %m",
+ up->unit);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * copy/swap a big-endian palisade double into a host double
+ */
+static double
+getdbl (
+ u_char *bp
+ )
+{
+#ifdef WORDS_BIGENDIAN
+ double out;
+
+ memcpy(&out, bp, sizeof(out));
+ return out;
+#else
+ union {
+ u_char ch[8];
+ u_int32 u32[2];
+ } ui;
+
+ union {
+ double out;
+ u_int32 u32[2];
+ } uo;
+
+ memcpy(ui.ch, bp, sizeof(ui.ch));
+ /* least-significant 32 bits of double from swapped bp[4] to bp[7] */
+ uo.u32[0] = ntohl(ui.u32[1]);
+ /* most-significant 32 bits from swapped bp[0] to bp[3] */
+ uo.u32[1] = ntohl(ui.u32[0]);
+
+ return uo.out;
+#endif
+}
+
+/*
+ * copy/swap a big-endian palisade short into a host short
+ */
+static short
+getint (
+ u_char *bp
+ )
+{
+ u_short us;
+
+ memcpy(&us, bp, sizeof(us));
+ return (short)ntohs(us);
+}
+
+/*
+ * copy/swap a big-endian palisade 32-bit int into a host 32-bit int
+ */
+static int32
+getlong(
+ u_char *bp
+ )
+{
+ u_int32 u32;
+
+ memcpy(&u32, bp, sizeof(u32));
+ return (int32)(u_int32)ntohl(u32);
+}
+
+/*
+ * copy/swap a big-endian 32-bit single-precision floating point into a host 32-bit int
+ */
+static int32
+getsingle(
+ u_char *bp
+ )
+{
+ u_int32 mantissa;
+ int8_t exponent;
+ uint8_t sign, exp_field;
+ int32 res;
+
+ memcpy(&mantissa, bp, sizeof(mantissa));
+ mantissa = ((u_int32)ntohl(mantissa) & 0x7FFFFF) | 0x800000;
+ exp_field = ((uint8_t)bp[0] << 1) + ((uint8_t)bp[1] >> 7);
+ exponent = (int8_t)exp_field - 127;
+ sign = ((uint8_t)bp[0] >> 7);
+ if (exponent > 23)
+ res = (int32)(mantissa << (exponent - 23));
+ else
+ res = (int32)(mantissa >> (23 - exponent));
+ return sign ? -res : res;
+}
+
+#else /* REFCLOCK && CLOCK_PALISADE*/
+NONEMPTY_TRANSLATION_UNIT
+#endif