154359Sroberto/*
254359Sroberto * This software was developed by the Software and Component Technologies
354359Sroberto * group of Trimble Navigation, Ltd.
454359Sroberto *
582498Sroberto * Copyright (c) 1997, 1998, 1999, 2000  Trimble Navigation Ltd.
654359Sroberto * All rights reserved.
754359Sroberto *
854359Sroberto * Redistribution and use in source and binary forms, with or without
954359Sroberto * modification, are permitted provided that the following conditions
1054359Sroberto * are met:
1154359Sroberto * 1. Redistributions of source code must retain the above copyright
1254359Sroberto *    notice, this list of conditions and the following disclaimer.
1354359Sroberto * 2. Redistributions in binary form must reproduce the above copyright
1454359Sroberto *    notice, this list of conditions and the following disclaimer in the
1554359Sroberto *    documentation and/or other materials provided with the distribution.
1654359Sroberto * 3. All advertising materials mentioning features or use of this software
1754359Sroberto *    must display the following acknowledgement:
1854359Sroberto *    This product includes software developed by Trimble Navigation, Ltd.
1954359Sroberto * 4. The name of Trimble Navigation Ltd. may not be used to endorse or
2054359Sroberto *    promote products derived from this software without specific prior
2154359Sroberto *    written permission.
2254359Sroberto *
2354359Sroberto * THIS SOFTWARE IS PROVIDED BY TRIMBLE NAVIGATION LTD. ``AS IS'' AND
2454359Sroberto * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2554359Sroberto * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2654359Sroberto * ARE DISCLAIMED.  IN NO EVENT SHALL TRIMBLE NAVIGATION LTD. BE LIABLE
2754359Sroberto * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2854359Sroberto * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2954359Sroberto * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3054359Sroberto * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3154359Sroberto * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3254359Sroberto * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3354359Sroberto * SUCH DAMAGE.
3454359Sroberto */
3554359Sroberto
3654359Sroberto/*
3754359Sroberto * refclock_palisade - clock driver for the Trimble Palisade GPS
3854359Sroberto * timing receiver
3954359Sroberto *
4054359Sroberto * For detailed information on this program, please refer to the html
4154359Sroberto * Refclock 29 page accompanying the NTP distribution.
4254359Sroberto *
4354359Sroberto * for questions / bugs / comments, contact:
4454359Sroberto * sven_dietrich@trimble.com
4554359Sroberto *
4654359Sroberto * Sven-Thorsten Dietrich
4754359Sroberto * 645 North Mary Avenue
4854359Sroberto * Post Office Box 3642
4954359Sroberto * Sunnyvale, CA 94088-3642
5054359Sroberto *
5154359Sroberto * Version 2.45; July 14, 1999
5254359Sroberto *
53290000Sglebius *
54290000Sglebius *
55290000Sglebius * 31/03/06: Added support for Thunderbolt GPS Disciplined Clock.
56290000Sglebius *	     Contact: Fernando Pablo Hauscarriaga
57290000Sglebius * 	     E-mail: fernandoph@iar.unlp.edu.ar
58290000Sglebius * 	     Home page: www.iar.unlp.edu.ar/~fernandoph
59290000Sglebius *		  Instituto Argentino de Radioastronomia
60290000Sglebius *			    www.iar.unlp.edu.ar
61290000Sglebius *
62290000Sglebius * 14/01/07: Conditinal compilation for Thunderbolt support no longer needed
63290000Sglebius *	     now we use mode 2 for decode thunderbolt packets.
64290000Sglebius *	     Fernando P. Hauscarriaga
65290000Sglebius *
66290000Sglebius * 30/08/09: Added support for Trimble Acutime Gold Receiver.
67290000Sglebius *	     Fernando P. Hauscarriaga (fernandoph@iar.unlp.edu.ar)
6854359Sroberto */
6954359Sroberto
7054359Sroberto#ifdef HAVE_CONFIG_H
71290000Sglebius# include "config.h"
7254359Sroberto#endif
7354359Sroberto
74290000Sglebius#if defined(REFCLOCK) && defined(CLOCK_PALISADE)
75200576Sroberto
76200576Sroberto#ifdef SYS_WINNT
77200576Srobertoextern int async_write(int, const void *, unsigned int);
78200576Sroberto#undef write
79200576Sroberto#define write(fd, data, octets)	async_write(fd, data, octets)
80132451Sroberto#endif
81132451Sroberto
8254359Sroberto#include "refclock_palisade.h"
8354359Sroberto/* Table to get from month to day of the year */
8454359Srobertoconst int days_of_year [12] = {
8554359Sroberto	0,  31,  59,  90, 120, 151, 181, 212, 243, 273, 304, 334
8654359Sroberto};
8754359Sroberto
8854359Sroberto#ifdef DEBUG
8954359Srobertoconst char * Tracking_Status[15][15] = {
90290000Sglebius	{ "Doing Fixes\0" }, { "Good 1SV\0" }, { "Approx. 1SV\0" },
91290000Sglebius	{"Need Time\0" }, { "Need INIT\0" }, { "PDOP too High\0" },
92290000Sglebius	{ "Bad 1SV\0" }, { "0SV Usable\0" }, { "1SV Usable\0" },
93290000Sglebius	{ "2SV Usable\0" }, { "3SV Usable\0" }, { "No Integrity\0" },
94290000Sglebius	{ "Diff Corr\0" }, { "Overdet Clock\0" }, { "Invalid\0" } };
9554359Sroberto#endif
9654359Sroberto
9754359Sroberto/*
9854359Sroberto * Transfer vector
9954359Sroberto */
10054359Srobertostruct refclock refclock_palisade = {
10154359Sroberto	palisade_start,		/* start up driver */
10254359Sroberto	palisade_shutdown,	/* shut down driver */
10354359Sroberto	palisade_poll,		/* transmit poll message */
10454359Sroberto	noentry,		/* not used  */
10554359Sroberto	noentry,		/* initialize driver (not used) */
10654359Sroberto	noentry,		/* not used */
10754359Sroberto	NOFLAGS			/* not used */
10854359Sroberto};
10954359Sroberto
110290000Sglebiusint day_of_year (char *dt);
11154359Sroberto
112132451Sroberto/* Extract the clock type from the mode setting */
113132451Sroberto#define CLK_TYPE(x) ((int)(((x)->ttl) & 0x7F))
114132451Sroberto
115132451Sroberto/* Supported clock types */
116132451Sroberto#define CLK_TRIMBLE	0	/* Trimble Palisade */
117132451Sroberto#define CLK_PRAECIS	1	/* Endrun Technologies Praecis */
118290000Sglebius#define CLK_THUNDERBOLT	2	/* Trimble Thunderbolt GPS Receiver */
119290000Sglebius#define CLK_ACUTIME     3	/* Trimble Acutime Gold */
120290000Sglebius#define CLK_ACUTIMEB    4	/* Trimble Actutime Gold Port B */
121132451Sroberto
122132451Srobertoint praecis_msg;
123132451Srobertostatic void praecis_parse(struct recvbuf *rbufp, struct peer *peer);
124132451Sroberto
125290000Sglebius/* These routines are for sending packets to the Thunderbolt receiver
126290000Sglebius * They are taken from Markus Prosch
127290000Sglebius */
128290000Sglebius
129290000Sglebius#ifdef PALISADE_SENDCMD_RESURRECTED
13054359Sroberto/*
131290000Sglebius * sendcmd - Build data packet for sending
132290000Sglebius */
133290000Sglebiusstatic void
134290000Sglebiussendcmd (
135290000Sglebius	struct packettx *buffer,
136290000Sglebius	int c
137290000Sglebius	)
138290000Sglebius{
139290000Sglebius	*buffer->data = DLE;
140290000Sglebius	*(buffer->data + 1) = (unsigned char)c;
141290000Sglebius	buffer->size = 2;
142290000Sglebius}
143290000Sglebius#endif	/* PALISADE_SENDCMD_RESURRECTED */
144290000Sglebius
145290000Sglebius/*
146290000Sglebius * sendsupercmd - Build super data packet for sending
147290000Sglebius */
148290000Sglebiusstatic void
149290000Sglebiussendsupercmd (
150290000Sglebius	struct packettx *buffer,
151290000Sglebius	int c1,
152290000Sglebius	int c2
153290000Sglebius	)
154290000Sglebius{
155290000Sglebius	*buffer->data = DLE;
156290000Sglebius	*(buffer->data + 1) = (unsigned char)c1;
157290000Sglebius	*(buffer->data + 2) = (unsigned char)c2;
158290000Sglebius	buffer->size = 3;
159290000Sglebius}
160290000Sglebius
161290000Sglebius/*
162290000Sglebius * sendbyte -
163290000Sglebius */
164290000Sglebiusstatic void
165290000Sglebiussendbyte (
166290000Sglebius	struct packettx *buffer,
167290000Sglebius	int b
168290000Sglebius	)
169290000Sglebius{
170290000Sglebius	if (b == DLE)
171290000Sglebius		*(buffer->data+buffer->size++) = DLE;
172290000Sglebius	*(buffer->data+buffer->size++) = (unsigned char)b;
173290000Sglebius}
174290000Sglebius
175290000Sglebius/*
176290000Sglebius * sendint -
177290000Sglebius */
178290000Sglebiusstatic void
179290000Sglebiussendint (
180290000Sglebius	struct packettx *buffer,
181290000Sglebius	int a
182290000Sglebius	)
183290000Sglebius{
184290000Sglebius	sendbyte(buffer, (unsigned char)((a>>8) & 0xff));
185290000Sglebius	sendbyte(buffer, (unsigned char)(a & 0xff));
186290000Sglebius}
187290000Sglebius
188290000Sglebius/*
189290000Sglebius * sendetx - Send packet or super packet to the device
190290000Sglebius */
191290000Sglebiusstatic int
192290000Sglebiussendetx (
193290000Sglebius	struct packettx *buffer,
194290000Sglebius	int fd
195290000Sglebius	)
196290000Sglebius{
197290000Sglebius	int result;
198290000Sglebius
199290000Sglebius	*(buffer->data+buffer->size++) = DLE;
200290000Sglebius	*(buffer->data+buffer->size++) = ETX;
201290000Sglebius	result = write(fd, buffer->data, (unsigned long)buffer->size);
202290000Sglebius
203290000Sglebius	if (result != -1)
204290000Sglebius		return (result);
205290000Sglebius	else
206290000Sglebius		return (-1);
207290000Sglebius}
208290000Sglebius
209290000Sglebius/*
210290000Sglebius * init_thunderbolt - Prepares Thunderbolt receiver to be used with
211290000Sglebius *		      NTP (also taken from Markus Prosch).
212290000Sglebius */
213290000Sglebiusstatic void
214290000Sglebiusinit_thunderbolt (
215290000Sglebius	int fd
216290000Sglebius	)
217290000Sglebius{
218290000Sglebius	struct packettx tx;
219290000Sglebius
220290000Sglebius	tx.size = 0;
221290000Sglebius	tx.data = (u_char *) emalloc(100);
222290000Sglebius
223290000Sglebius	/* set UTC time */
224290000Sglebius	sendsupercmd (&tx, 0x8E, 0xA2);
225290000Sglebius	sendbyte     (&tx, 0x3);
226290000Sglebius	sendetx      (&tx, fd);
227290000Sglebius
228290000Sglebius	/* activate packets 0x8F-AB and 0x8F-AC */
229290000Sglebius	sendsupercmd (&tx, 0x8F, 0xA5);
230290000Sglebius	sendint      (&tx, 0x5);
231290000Sglebius	sendetx      (&tx, fd);
232290000Sglebius
233290000Sglebius	free(tx.data);
234290000Sglebius}
235290000Sglebius
236290000Sglebius/*
237290000Sglebius * init_acutime - Prepares Acutime Receiver to be used with NTP
238290000Sglebius */
239290000Sglebiusstatic void
240290000Sglebiusinit_acutime (
241290000Sglebius	int fd
242290000Sglebius	)
243290000Sglebius{
244290000Sglebius	/* Disable all outputs, Enable Event-Polling on PortA so
245290000Sglebius	   we can ask for time packets */
246290000Sglebius	struct packettx tx;
247290000Sglebius
248290000Sglebius	tx.size = 0;
249290000Sglebius	tx.data = (u_char *) emalloc(100);
250290000Sglebius
251290000Sglebius	sendsupercmd(&tx, 0x8E, 0xA5);
252290000Sglebius	sendbyte(&tx, 0x02);
253290000Sglebius	sendbyte(&tx, 0x00);
254290000Sglebius	sendbyte(&tx, 0x00);
255290000Sglebius	sendbyte(&tx, 0x00);
256290000Sglebius	sendetx(&tx, fd);
257290000Sglebius
258290000Sglebius	free(tx.data);
259290000Sglebius}
260290000Sglebius
261290000Sglebius/*
26254359Sroberto * palisade_start - open the devices and initialize data for processing
26354359Sroberto */
26454359Srobertostatic int
26554359Srobertopalisade_start (
26654359Sroberto	int unit,
26754359Sroberto	struct peer *peer
26854359Sroberto	)
26954359Sroberto{
27054359Sroberto	struct palisade_unit *up;
27154359Sroberto	struct refclockproc *pp;
27254359Sroberto	int fd;
27354359Sroberto	char gpsdev[20];
274290000Sglebius	struct termios tio;
27554359Sroberto
276290000Sglebius	snprintf(gpsdev, sizeof(gpsdev), DEVICE, unit);
277290000Sglebius
27854359Sroberto	/*
27954359Sroberto	 * Open serial port.
28054359Sroberto	 */
28154359Sroberto	fd = refclock_open(gpsdev, SPEED232, LDISC_RAW);
28254359Sroberto	if (fd <= 0) {
28354359Sroberto#ifdef DEBUG
28454359Sroberto		printf("Palisade(%d) start: open %s failed\n", unit, gpsdev);
28554359Sroberto#endif
28654359Sroberto		return 0;
28754359Sroberto	}
28854359Sroberto
28954359Sroberto	msyslog(LOG_NOTICE, "Palisade(%d) fd: %d dev: %s", unit, fd,
29054359Sroberto		gpsdev);
29154359Sroberto
292290000Sglebius	if (tcgetattr(fd, &tio) < 0) {
293290000Sglebius		msyslog(LOG_ERR,
29454359Sroberto			"Palisade(%d) tcgetattr(fd, &tio): %m",unit);
29554359Sroberto#ifdef DEBUG
296290000Sglebius		printf("Palisade(%d) tcgetattr(fd, &tio)\n",unit);
29754359Sroberto#endif
298290000Sglebius		close(fd);
299290000Sglebius		return (0);
300290000Sglebius	}
30154359Sroberto
302290000Sglebius	tio.c_cflag |= (PARENB|PARODD);
303290000Sglebius	tio.c_iflag &= ~ICRNL;
30454359Sroberto
30554359Sroberto	/*
30654359Sroberto	 * Allocate and initialize unit structure
30754359Sroberto	 */
308290000Sglebius	up = emalloc_zero(sizeof(*up));
30954359Sroberto
310132451Sroberto	up->type = CLK_TYPE(peer);
311132451Sroberto	switch (up->type) {
312290000Sglebius	    case CLK_TRIMBLE:
313290000Sglebius		/* Normal mode, do nothing */
314290000Sglebius		break;
315290000Sglebius	    case CLK_PRAECIS:
316290000Sglebius		msyslog(LOG_NOTICE, "Palisade(%d) Praecis mode enabled"
317290000Sglebius			,unit);
318290000Sglebius		break;
319290000Sglebius	    case CLK_THUNDERBOLT:
320290000Sglebius		msyslog(LOG_NOTICE, "Palisade(%d) Thunderbolt mode enabled"
321290000Sglebius			,unit);
322290000Sglebius		tio.c_cflag = (CS8|CLOCAL|CREAD);
323290000Sglebius		break;
324290000Sglebius	    case CLK_ACUTIME:
325290000Sglebius		msyslog(LOG_NOTICE, "Palisade(%d) Acutime Gold mode enabled"
326290000Sglebius			,unit);
327290000Sglebius		break;
328290000Sglebius	    default:
329290000Sglebius		msyslog(LOG_NOTICE, "Palisade(%d) mode unknown",unit);
330290000Sglebius		break;
331132451Sroberto	}
332290000Sglebius	if (tcsetattr(fd, TCSANOW, &tio) == -1) {
333290000Sglebius		msyslog(LOG_ERR, "Palisade(%d) tcsetattr(fd, &tio): %m",unit);
334290000Sglebius#ifdef DEBUG
335290000Sglebius		printf("Palisade(%d) tcsetattr(fd, &tio)\n",unit);
336290000Sglebius#endif
337290000Sglebius		close(fd);
338290000Sglebius		free(up);
339290000Sglebius		return 0;
340290000Sglebius	}
341132451Sroberto
34254359Sroberto	pp = peer->procptr;
34354359Sroberto	pp->io.clock_recv = palisade_io;
344290000Sglebius	pp->io.srcclock = peer;
34554359Sroberto	pp->io.datalen = 0;
34654359Sroberto	pp->io.fd = fd;
34754359Sroberto	if (!io_addclock(&pp->io)) {
34854359Sroberto#ifdef DEBUG
349290000Sglebius		printf("Palisade(%d) io_addclock\n",unit);
35054359Sroberto#endif
351290000Sglebius		close(fd);
352290000Sglebius		pp->io.fd = -1;
35354359Sroberto		free(up);
35454359Sroberto		return (0);
35554359Sroberto	}
35654359Sroberto
35754359Sroberto	/*
35854359Sroberto	 * Initialize miscellaneous variables
35954359Sroberto	 */
360290000Sglebius	pp->unitptr = up;
36154359Sroberto	pp->clockdesc = DESCRIPTION;
36254359Sroberto
36354359Sroberto	peer->precision = PRECISION;
36454359Sroberto	peer->sstclktype = CTL_SST_TS_UHF;
36554359Sroberto	peer->minpoll = TRMB_MINPOLL;
36654359Sroberto	peer->maxpoll = TRMB_MAXPOLL;
36754359Sroberto	memcpy((char *)&pp->refid, REFID, 4);
36854359Sroberto
36954359Sroberto	up->leap_status = 0;
37054359Sroberto	up->unit = (short) unit;
37154359Sroberto	up->rpt_status = TSIP_PARSED_EMPTY;
372290000Sglebius	up->rpt_cnt = 0;
37354359Sroberto
374290000Sglebius	if (up->type == CLK_THUNDERBOLT)
375290000Sglebius		init_thunderbolt(fd);
376290000Sglebius	if (up->type == CLK_ACUTIME)
377290000Sglebius		init_acutime(fd);
378290000Sglebius
37954359Sroberto	return 1;
38054359Sroberto}
38154359Sroberto
38254359Sroberto
38354359Sroberto/*
38454359Sroberto * palisade_shutdown - shut down the clock
38554359Sroberto */
38654359Srobertostatic void
38754359Srobertopalisade_shutdown (
38854359Sroberto	int unit,
38954359Sroberto	struct peer *peer
39054359Sroberto	)
39154359Sroberto{
39254359Sroberto	struct palisade_unit *up;
39354359Sroberto	struct refclockproc *pp;
39454359Sroberto	pp = peer->procptr;
395290000Sglebius	up = pp->unitptr;
396290000Sglebius	if (-1 != pp->io.fd)
397290000Sglebius		io_closeclock(&pp->io);
398290000Sglebius	if (NULL != up)
399290000Sglebius		free(up);
40054359Sroberto}
40154359Sroberto
40254359Sroberto
40354359Sroberto
40454359Sroberto/*
40554359Sroberto * unpack_date - get day and year from date
40654359Sroberto */
40754359Srobertoint
40854359Srobertoday_of_year (
40954359Sroberto	char * dt
41054359Sroberto	)
41154359Sroberto{
41254359Sroberto	int day, mon, year;
41354359Sroberto
41454359Sroberto	mon = dt[1];
415290000Sglebius	/* Check month is inside array bounds */
416290000Sglebius	if ((mon < 1) || (mon > 12))
41754359Sroberto		return -1;
41854359Sroberto
41954359Sroberto	day = dt[0] + days_of_year[mon - 1];
42054359Sroberto	year = getint((u_char *) (dt + 2));
42154359Sroberto
42254359Sroberto	if ( !(year % 4) && ((year % 100) ||
423290000Sglebius			     (!(year % 100) && !(year%400)))
424290000Sglebius	     &&(mon > 2))
425290000Sglebius		day ++; /* leap year and March or later */
42654359Sroberto
42754359Sroberto	return day;
42854359Sroberto}
42954359Sroberto
43054359Sroberto
43154359Sroberto/*
43254359Sroberto * TSIP_decode - decode the TSIP data packets
43354359Sroberto */
43454359Srobertoint
43554359SrobertoTSIP_decode (
43654359Sroberto	struct peer *peer
43754359Sroberto	)
43854359Sroberto{
43954359Sroberto	int st;
44054359Sroberto	long   secint;
44154359Sroberto	double secs;
44254359Sroberto	double secfrac;
44354359Sroberto	unsigned short event = 0;
44454359Sroberto
44554359Sroberto	struct palisade_unit *up;
44654359Sroberto	struct refclockproc *pp;
44754359Sroberto
44854359Sroberto	pp = peer->procptr;
449290000Sglebius	up = pp->unitptr;
45054359Sroberto
45154359Sroberto	/*
45254359Sroberto	 * Check the time packet, decode its contents.
45354359Sroberto	 * If the timecode has invalid length or is not in
45454359Sroberto	 * proper format, declare bad format and exit.
45554359Sroberto	 */
45654359Sroberto
457290000Sglebius	if ((up->type != CLK_THUNDERBOLT) & (up->type != CLK_ACUTIME)){
458290000Sglebius		if ((up->rpt_buf[0] == (char) 0x41) ||
459290000Sglebius		    (up->rpt_buf[0] == (char) 0x46) ||
460290000Sglebius		    (up->rpt_buf[0] == (char) 0x54) ||
461290000Sglebius		    (up->rpt_buf[0] == (char) 0x4B) ||
462290000Sglebius		    (up->rpt_buf[0] == (char) 0x6D)) {
46354359Sroberto
464290000Sglebius			/* standard time packet - GPS time and GPS week number */
46554359Sroberto#ifdef DEBUG
46654359Sroberto			printf("Palisade Port B packets detected. Connect to Port A\n");
46754359Sroberto#endif
46854359Sroberto
469290000Sglebius			return 0;
470290000Sglebius		}
47154359Sroberto	}
47254359Sroberto
473132451Sroberto	/*
474132451Sroberto	 * We cast both to u_char to as 0x8f uses the sign bit on a char
475132451Sroberto	 */
476132451Sroberto	if ((u_char) up->rpt_buf[0] == (u_char) 0x8f) {
477290000Sglebius		/*
478290000Sglebius		 * Superpackets
479290000Sglebius		 */
480290000Sglebius		event = (unsigned short) (getint((u_char *) &mb(1)) & 0xffff);
481290000Sglebius		if (!((pp->sloppyclockflag & CLK_FLAG2) || event))
482290000Sglebius			/* Ignore Packet */
48354359Sroberto			return 0;
48454359Sroberto
485290000Sglebius		switch (mb(0) & 0xff) {
486290000Sglebius			int GPS_UTC_Offset;
487290000Sglebius			long tow;
48854359Sroberto
489290000Sglebius		    case PACKET_8F0B:
49054359Sroberto
491290000Sglebius			if (up->polled <= 0)
492290000Sglebius				return 0;
493290000Sglebius
494290000Sglebius			if (up->rpt_cnt != LENCODE_8F0B)  /* check length */
495290000Sglebius				break;
49654359Sroberto
49754359Sroberto#ifdef DEBUG
498290000Sglebius			if (debug > 1) {
499290000Sglebius				int ts;
500290000Sglebius				double lat, lon, alt;
501290000Sglebius				lat = getdbl((u_char *) &mb(42)) * R2D;
502290000Sglebius				lon = getdbl((u_char *) &mb(50)) * R2D;
503290000Sglebius				alt = getdbl((u_char *) &mb(58));
50454359Sroberto
505290000Sglebius				printf("TSIP_decode: unit %d: Latitude: %03.4f Longitude: %03.4f Alt: %05.2f m\n",
506290000Sglebius				       up->unit, lat,lon,alt);
507290000Sglebius				printf("TSIP_decode: unit %d: Sats:",
508290000Sglebius				       up->unit);
509290000Sglebius				for (st = 66, ts = 0; st <= 73; st++)
510290000Sglebius					if (mb(st)) {
511290000Sglebius						if (mb(st) > 0) ts++;
512290000Sglebius						printf(" %02d", mb(st));
513290000Sglebius					}
514290000Sglebius				printf(" : Tracking %d\n", ts);
515290000Sglebius			}
51654359Sroberto#endif
51754359Sroberto
518290000Sglebius			GPS_UTC_Offset = getint((u_char *) &mb(16));
519290000Sglebius			if (GPS_UTC_Offset == 0) { /* Check UTC offset */
52054359Sroberto#ifdef DEBUG
521290000Sglebius				printf("TSIP_decode: UTC Offset Unknown\n");
52254359Sroberto#endif
523290000Sglebius				break;
524290000Sglebius			}
52554359Sroberto
526290000Sglebius			secs = getdbl((u_char *) &mb(3));
527290000Sglebius			secint = (long) secs;
528290000Sglebius			secfrac = secs - secint; /* 0.0 <= secfrac < 1.0 */
52954359Sroberto
530290000Sglebius			pp->nsec = (long) (secfrac * 1000000000);
53154359Sroberto
532290000Sglebius			secint %= 86400;    /* Only care about today */
533290000Sglebius			pp->hour = secint / 3600;
534290000Sglebius			secint %= 3600;
535290000Sglebius			pp->minute = secint / 60;
536290000Sglebius			secint %= 60;
537290000Sglebius			pp->second = secint % 60;
53854359Sroberto
539290000Sglebius			if ((pp->day = day_of_year(&mb(11))) < 0) break;
54054359Sroberto
541290000Sglebius			pp->year = getint((u_char *) &mb(13));
54254359Sroberto
54354359Sroberto#ifdef DEBUG
544290000Sglebius			if (debug > 1)
545290000Sglebius				printf("TSIP_decode: unit %d: %02X #%d %02d:%02d:%02d.%09ld %02d/%02d/%04d UTC %02d\n",
546290000Sglebius				       up->unit, mb(0) & 0xff, event, pp->hour, pp->minute,
547290000Sglebius				       pp->second, pp->nsec, mb(12), mb(11), pp->year, GPS_UTC_Offset);
54854359Sroberto#endif
549290000Sglebius			/* Only use this packet when no
550290000Sglebius			 * 8F-AD's are being received
551290000Sglebius			 */
55254359Sroberto
553290000Sglebius			if (up->leap_status) {
554290000Sglebius				up->leap_status = 0;
555290000Sglebius				return 0;
556290000Sglebius			}
55754359Sroberto
558290000Sglebius			return 2;
559290000Sglebius			break;
56054359Sroberto
561290000Sglebius		    case PACKET_NTP:
562290000Sglebius			/* Palisade-NTP Packet */
56354359Sroberto
564290000Sglebius			if (up->rpt_cnt != LENCODE_NTP) /* check length */
565290000Sglebius				break;
56654359Sroberto
567290000Sglebius			up->leap_status = mb(19);
56854359Sroberto
569290000Sglebius			if (up->polled  <= 0)
570290000Sglebius				return 0;
57154359Sroberto
572290000Sglebius			/* Check Tracking Status */
573290000Sglebius			st = mb(18);
574290000Sglebius			if (st < 0 || st > 14)
575290000Sglebius				st = 14;
576290000Sglebius			if ((st >= 2 && st <= 7) || st == 11 || st == 12) {
57754359Sroberto#ifdef DEBUG
578290000Sglebius				printf("TSIP_decode: Not Tracking Sats : %s\n",
579290000Sglebius				       *Tracking_Status[st]);
58054359Sroberto#endif
581290000Sglebius				refclock_report(peer, CEVNT_BADTIME);
582290000Sglebius				up->polled = -1;
583290000Sglebius				return 0;
584290000Sglebius				break;
585290000Sglebius			}
586290000Sglebius
587290000Sglebius			up->month = mb(15);
588290000Sglebius			if ( (up->leap_status & PALISADE_LEAP_PENDING) &&
589290000Sglebius			/* Avoid early announce: https://bugs.ntp.org/2773 */
590290000Sglebius				(6 == up->month || 12 == up->month) ) {
591290000Sglebius				if (up->leap_status & PALISADE_UTC_TIME)
592290000Sglebius					pp->leap = LEAP_ADDSECOND;
593290000Sglebius				else
594290000Sglebius					pp->leap = LEAP_DELSECOND;
595290000Sglebius			}
596290000Sglebius			else if (up->leap_status)
597290000Sglebius				pp->leap = LEAP_NOWARNING;
598290000Sglebius
599290000Sglebius			else {  /* UTC flag is not set:
600290000Sglebius				 * Receiver may have been reset, and lost
601290000Sglebius				 * its UTC almanac data */
602290000Sglebius				pp->leap = LEAP_NOTINSYNC;
603290000Sglebius#ifdef DEBUG
604290000Sglebius				printf("TSIP_decode: UTC Almanac unavailable: %d\n",
605290000Sglebius				       mb(19));
606290000Sglebius#endif
607290000Sglebius				refclock_report(peer, CEVNT_BADTIME);
608290000Sglebius				up->polled = -1;
609290000Sglebius				return 0;
610290000Sglebius			}
611290000Sglebius
612290000Sglebius			pp->nsec = (long) (getdbl((u_char *) &mb(3))
613290000Sglebius					   * 1000000000);
614290000Sglebius
615290000Sglebius			if ((pp->day = day_of_year(&mb(14))) < 0)
616290000Sglebius				break;
617290000Sglebius			pp->year = getint((u_char *) &mb(16));
618290000Sglebius			pp->hour = mb(11);
619290000Sglebius			pp->minute = mb(12);
620290000Sglebius			pp->second = mb(13);
621290000Sglebius			up->month = mb(14);  /* Save for LEAP check */
622290000Sglebius
623290000Sglebius#ifdef DEBUG
624290000Sglebius			if (debug > 1)
625290000Sglebius				printf("TSIP_decode: unit %d: %02X #%d %02d:%02d:%02d.%09ld %02d/%02d/%04d UTC %02x %s\n",
626290000Sglebius				       up->unit, mb(0) & 0xff, event, pp->hour, pp->minute,
627290000Sglebius				       pp->second, pp->nsec, mb(15), mb(14), pp->year,
628290000Sglebius				       mb(19), *Tracking_Status[st]);
629290000Sglebius#endif
630290000Sglebius			return 1;
631290000Sglebius			break;
632290000Sglebius
633290000Sglebius		    case PACKET_8FAC:
634290000Sglebius			if (up->polled <= 0)
635290000Sglebius				return 0;
636290000Sglebius
637290000Sglebius			if (up->rpt_cnt != LENCODE_8FAC)/* check length */
638290000Sglebius				break;
639290000Sglebius
640290000Sglebius#ifdef DEBUG
641290000Sglebius			if (debug > 1) {
642290000Sglebius				double lat, lon, alt;
643290000Sglebius				lat = getdbl((u_char *) &mb(36)) * R2D;
644290000Sglebius				lon = getdbl((u_char *) &mb(44)) * R2D;
645290000Sglebius				alt = getdbl((u_char *) &mb(52));
646290000Sglebius
647290000Sglebius				printf("TSIP_decode: unit %d: Latitude: %03.4f Longitude: %03.4f Alt: %05.2f m\n",
648290000Sglebius				       up->unit, lat,lon,alt);
649290000Sglebius				printf("TSIP_decode: unit %d\n", up->unit);
650290000Sglebius			}
651290000Sglebius#endif
652290000Sglebius			if ( (getint((u_char *) &mb(10)) & 0x80) &&
653290000Sglebius			/* Avoid early announce: https://bugs.ntp.org/2773 */
654290000Sglebius			    (6 == up->month || 12 == up->month) )
655290000Sglebius				pp->leap = LEAP_ADDSECOND;  /* we ASSUME addsecond */
656290000Sglebius			else
657290000Sglebius				pp->leap = LEAP_NOWARNING;
658290000Sglebius
659290000Sglebius#ifdef DEBUG
660290000Sglebius			if (debug > 1)
661290000Sglebius				printf("TSIP_decode: unit %d: 0x%02x leap %d\n",
662290000Sglebius				       up->unit, mb(0) & 0xff, pp->leap);
663290000Sglebius			if (debug > 1) {
664290000Sglebius				printf("Receiver MODE: 0x%02X\n", (u_char)mb(1));
665290000Sglebius				if (mb(1) == 0x00)
666290000Sglebius					printf("                AUTOMATIC\n");
667290000Sglebius				if (mb(1) == 0x01)
668290000Sglebius					printf("                SINGLE SATELLITE\n");
669290000Sglebius				if (mb(1) == 0x03)
670290000Sglebius					printf("                HORIZONTAL(2D)\n");
671290000Sglebius				if (mb(1) == 0x04)
672290000Sglebius					printf("                FULL POSITION(3D)\n");
673290000Sglebius				if (mb(1) == 0x05)
674290000Sglebius					printf("                DGPR REFERENCE\n");
675290000Sglebius				if (mb(1) == 0x06)
676290000Sglebius					printf("                CLOCK HOLD(2D)\n");
677290000Sglebius				if (mb(1) == 0x07)
678290000Sglebius					printf("                OVERDETERMINED CLOCK\n");
679290000Sglebius
680290000Sglebius				printf("\n** Disciplining MODE 0x%02X:\n", (u_char)mb(2));
681290000Sglebius				if (mb(2) == 0x00)
682290000Sglebius					printf("                NORMAL\n");
683290000Sglebius				if (mb(2) == 0x01)
684290000Sglebius					printf("                POWER-UP\n");
685290000Sglebius				if (mb(2) == 0x02)
686290000Sglebius					printf("                AUTO HOLDOVER\n");
687290000Sglebius				if (mb(2) == 0x03)
688290000Sglebius					printf("                MANUAL HOLDOVER\n");
689290000Sglebius				if (mb(2) == 0x04)
690290000Sglebius					printf("                RECOVERY\n");
691290000Sglebius				if (mb(2) == 0x06)
692290000Sglebius					printf("                DISCIPLINING DISABLED\n");
693290000Sglebius			}
694290000Sglebius#endif
69554359Sroberto			return 0;
69654359Sroberto			break;
69754359Sroberto
698290000Sglebius		    case PACKET_8FAB:
699290000Sglebius			/* Thunderbolt Primary Timing Packet */
700290000Sglebius
701290000Sglebius			if (up->rpt_cnt != LENCODE_8FAB) /* check length */
702290000Sglebius				break;
703290000Sglebius
704290000Sglebius			if (up->polled  <= 0)
705290000Sglebius				return 0;
706290000Sglebius
707290000Sglebius			GPS_UTC_Offset = getint((u_char *) &mb(7));
708290000Sglebius
709290000Sglebius			if (GPS_UTC_Offset == 0){ /* Check UTC Offset */
710290000Sglebius#ifdef DEBUG
711290000Sglebius				printf("TSIP_decode: UTC Offset Unknown\n");
712290000Sglebius#endif
713290000Sglebius				break;
714290000Sglebius			}
715290000Sglebius
716290000Sglebius
717290000Sglebius			if ((mb(9) & 0x1d) == 0x0) {
718290000Sglebius				/* if we know the GPS time and the UTC offset,
719290000Sglebius				   we expect UTC timing information !!! */
720290000Sglebius
721290000Sglebius				pp->leap = LEAP_NOTINSYNC;
722290000Sglebius				refclock_report(peer, CEVNT_BADTIME);
723290000Sglebius				up->polled = -1;
724290000Sglebius				return 0;
725290000Sglebius			}
726290000Sglebius
727290000Sglebius			pp->nsec = 0;
728290000Sglebius#ifdef DEBUG
729290000Sglebius			printf("\nTiming Flags are:\n");
730290000Sglebius			printf("Timing flag value is: 0x%X\n", mb(9));
731290000Sglebius			if ((mb(9) & 0x01) != 0)
732290000Sglebius				printf ("	Getting UTC time\n");
73354359Sroberto			else
734290000Sglebius				printf ("	Getting GPS time\n");
735290000Sglebius			if ((mb(9) & 0x02) != 0)
736290000Sglebius				printf ("	PPS is from UTC\n");
737290000Sglebius			else
738290000Sglebius				printf ("	PPS is from GPS\n");
739290000Sglebius			if ((mb(9) & 0x04) != 0)
740290000Sglebius				printf ("	Time is not Set\n");
741290000Sglebius			else
742290000Sglebius				printf ("	Time is Set\n");
743290000Sglebius			if ((mb(9) & 0x08) != 0)
744290000Sglebius				printf("	I dont have UTC info\n");
745290000Sglebius			else
746290000Sglebius				printf ("	I have UTC info\n");
747290000Sglebius			if ((mb(9) & 0x10) != 0)
748290000Sglebius				printf ("	Time is from USER\n\n");
749290000Sglebius			else
750290000Sglebius				printf ("	Time is from GPS\n\n");
751290000Sglebius#endif
752290000Sglebius
753290000Sglebius			if ((pp->day = day_of_year(&mb(13))) < 0)
754290000Sglebius				break;
755290000Sglebius			tow = getlong((u_char *) &mb(1));
756290000Sglebius#ifdef DEBUG
757290000Sglebius			if (debug > 1) {
758290000Sglebius				printf("pp->day: %d\n", pp->day);
759290000Sglebius				printf("TOW: %ld\n", tow);
760290000Sglebius				printf("DAY: %d\n", mb(13));
761290000Sglebius			}
762290000Sglebius#endif
763290000Sglebius			pp->year = getint((u_char *) &mb(15));
764290000Sglebius			pp->hour = mb(12);
765290000Sglebius			pp->minute = mb(11);
766290000Sglebius			pp->second = mb(10);
767290000Sglebius
768290000Sglebius
76954359Sroberto#ifdef DEBUG
770290000Sglebius			if (debug > 1)
771290000Sglebius				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, mb(14), mb(13), pp->year);
77254359Sroberto#endif
773290000Sglebius			return 1;
774290000Sglebius			break;
775290000Sglebius
776290000Sglebius		    default:
777290000Sglebius			/* Ignore Packet */
778290000Sglebius			return 0;
779290000Sglebius		} /* switch */
780290000Sglebius	} /* if 8F packets */
781290000Sglebius
782290000Sglebius	else if (up->rpt_buf[0] == (u_char)0x42) {
783290000Sglebius		printf("0x42\n");
784290000Sglebius		return 0;
785290000Sglebius	}
786290000Sglebius	else if (up->rpt_buf[0] == (u_char)0x43) {
787290000Sglebius		printf("0x43\n");
788290000Sglebius		return 0;
789290000Sglebius	}
790290000Sglebius	else if ((up->rpt_buf[0] == PACKET_41) & (up->type == CLK_THUNDERBOLT)){
791290000Sglebius		printf("Undocumented 0x41 packet on Thunderbolt\n");
792290000Sglebius		return 0;
793290000Sglebius	}
794290000Sglebius	else if ((up->rpt_buf[0] == PACKET_41A) & (up->type == CLK_ACUTIME)) {
795290000Sglebius#ifdef DEBUG
796290000Sglebius		printf("GPS TOW: %ld\n", (long)getlong((u_char *) &mb(0)));
797290000Sglebius		printf("GPS WN: %d\n", getint((u_char *) &mb(4)));
798290000Sglebius		printf("GPS UTC-GPS Offser: %ld\n", (long)getlong((u_char *) &mb(6)));
799290000Sglebius#endif
800290000Sglebius		return 0;
801290000Sglebius	}
802290000Sglebius
803290000Sglebius	/* Health Status for Acutime Receiver */
804290000Sglebius	else if ((up->rpt_buf[0] == PACKET_46) & (up->type == CLK_ACUTIME)) {
805290000Sglebius#ifdef DEBUG
806290000Sglebius		if (debug > 1)
807290000Sglebius		/* Status Codes */
808290000Sglebius			switch (mb(0)) {
809290000Sglebius			    case 0x00:
810290000Sglebius				printf ("Doing Position Fixes\n");
811290000Sglebius				break;
812290000Sglebius			    case 0x01:
813290000Sglebius				printf ("Do no have GPS time yet\n");
814290000Sglebius				break;
815290000Sglebius			    case 0x03:
816290000Sglebius				printf ("PDOP is too high\n");
817290000Sglebius				break;
818290000Sglebius			    case 0x08:
819290000Sglebius				printf ("No usable satellites\n");
820290000Sglebius				break;
821290000Sglebius			    case 0x09:
822290000Sglebius				printf ("Only 1 usable satellite\n");
823290000Sglebius				break;
824290000Sglebius			    case 0x0A:
825290000Sglebius				printf ("Only 2 usable satellites\n");
826290000Sglebius				break;
827290000Sglebius			    case 0x0B:
828290000Sglebius				printf ("Only 3 usable satellites\n");
829290000Sglebius				break;
830290000Sglebius			    case 0x0C:
831290000Sglebius				printf("The Chosen satellite is unusable\n");
832290000Sglebius				break;
833290000Sglebius			}
834290000Sglebius#endif
835290000Sglebius		/* Error Codes */
836290000Sglebius		if (mb(1) != 0)	{
837290000Sglebius
83854359Sroberto			refclock_report(peer, CEVNT_BADTIME);
83954359Sroberto			up->polled = -1;
840290000Sglebius#ifdef DEBUG
841290000Sglebius			if (debug > 1) {
842290000Sglebius				if (mb(1) & 0x01)
843290000Sglebius					printf ("Signal Processor Error, reset unit.\n");
844290000Sglebius				if (mb(1) & 0x02)
845290000Sglebius					printf ("Alignment error, channel or chip 1, reset unit.\n");
846290000Sglebius				if (mb(1) & 0x03)
847290000Sglebius					printf ("Alignment error, channel or chip 2, reset unit.\n");
848290000Sglebius				if (mb(1) & 0x04)
849290000Sglebius					printf ("Antenna feed line fault (open or short)\n");
850290000Sglebius				if (mb(1) & 0x05)
851290000Sglebius					printf ("Excessive reference frequency error, refer to packet 0x2D and packet 0x4D documentation for further information\n");
852290000Sglebius			}
853290000Sglebius#endif
854290000Sglebius
855290000Sglebius		return 0;
85654359Sroberto		}
857290000Sglebius	}
858290000Sglebius	else if (up->rpt_buf[0] == 0x54)
859290000Sglebius		return 0;
86054359Sroberto
861290000Sglebius	else if (up->rpt_buf[0] == PACKET_6D) {
862290000Sglebius#ifdef DEBUG
863290000Sglebius		int sats;
86454359Sroberto
865290000Sglebius		if ((mb(0) & 0x01) && (mb(0) & 0x02))
866290000Sglebius			printf("2d Fix Dimension\n");
867290000Sglebius		if (mb(0) & 0x04)
868290000Sglebius			printf("3d Fix Dimension\n");
86954359Sroberto
870290000Sglebius		if (mb(0) & 0x08)
871290000Sglebius			printf("Fix Mode is MANUAL\n");
872290000Sglebius		else
873290000Sglebius			printf("Fix Mode is AUTO\n");
874290000Sglebius
875290000Sglebius		sats = mb(0) & 0xF0;
876290000Sglebius		sats = sats >> 4;
877290000Sglebius		printf("Tracking %d Satellites\n", sats);
87854359Sroberto#endif
87954359Sroberto		return 0;
880290000Sglebius	} /* else if not super packet */
88154359Sroberto	refclock_report(peer, CEVNT_BADREPLY);
88254359Sroberto	up->polled = -1;
88354359Sroberto#ifdef DEBUG
88454359Sroberto	printf("TSIP_decode: unit %d: bad packet %02x-%02x event %d len %d\n",
885290000Sglebius	       up->unit, up->rpt_buf[0] & 0xff, mb(0) & 0xff,
886290000Sglebius	       event, up->rpt_cnt);
88754359Sroberto#endif
88854359Sroberto	return 0;
88954359Sroberto}
89054359Sroberto
89154359Sroberto/*
89254359Sroberto * palisade__receive - receive data from the serial interface
89354359Sroberto */
89454359Sroberto
89554359Srobertostatic void
89654359Srobertopalisade_receive (
89754359Sroberto	struct peer * peer
89854359Sroberto	)
89954359Sroberto{
90054359Sroberto	struct palisade_unit *up;
90154359Sroberto	struct refclockproc *pp;
90254359Sroberto
90354359Sroberto	/*
90454359Sroberto	 * Initialize pointers and read the timecode and timestamp.
90554359Sroberto	 */
90654359Sroberto	pp = peer->procptr;
907290000Sglebius	up = pp->unitptr;
90854359Sroberto
90954359Sroberto	if (! TSIP_decode(peer)) return;
91054359Sroberto
91154359Sroberto	if (up->polled <= 0)
912290000Sglebius		return;   /* no poll pending, already received or timeout */
91354359Sroberto
91454359Sroberto	up->polled = 0;  /* Poll reply received */
91554359Sroberto	pp->lencode = 0; /* clear time code */
91654359Sroberto#ifdef DEBUG
91754359Sroberto	if (debug)
91854359Sroberto		printf(
919290000Sglebius			"palisade_receive: unit %d: %4d %03d %02d:%02d:%02d.%09ld\n",
92054359Sroberto			up->unit, pp->year, pp->day, pp->hour, pp->minute,
921132451Sroberto			pp->second, pp->nsec);
92254359Sroberto#endif
92354359Sroberto
92454359Sroberto	/*
92554359Sroberto	 * Process the sample
92654359Sroberto	 * Generate timecode: YYYY DoY HH:MM:SS.microsec
92754359Sroberto	 * report and process
92854359Sroberto	 */
92954359Sroberto
930290000Sglebius	snprintf(pp->a_lastcode, sizeof(pp->a_lastcode),
931290000Sglebius		 "%4d %03d %02d:%02d:%02d.%09ld",
932290000Sglebius		 pp->year, pp->day,
933290000Sglebius		 pp->hour,pp->minute, pp->second, pp->nsec);
93454359Sroberto	pp->lencode = 24;
93554359Sroberto
936290000Sglebius	if (!refclock_process(pp)) {
93754359Sroberto		refclock_report(peer, CEVNT_BADTIME);
93854359Sroberto
93954359Sroberto#ifdef DEBUG
94054359Sroberto		printf("palisade_receive: unit %d: refclock_process failed!\n",
941290000Sglebius		       up->unit);
94254359Sroberto#endif
94354359Sroberto		return;
94454359Sroberto	}
94554359Sroberto
94654359Sroberto	record_clock_stats(&peer->srcadr, pp->a_lastcode);
94754359Sroberto
94854359Sroberto#ifdef DEBUG
94954359Sroberto	if (debug)
950290000Sglebius		printf("palisade_receive: unit %d: %s\n",
951290000Sglebius		       up->unit, prettydate(&pp->lastrec));
95254359Sroberto#endif
953132451Sroberto	pp->lastref = pp->lastrec;
954290000Sglebius	refclock_receive(peer);
95554359Sroberto}
95654359Sroberto
95754359Sroberto
95854359Sroberto/*
95954359Sroberto * palisade_poll - called by the transmit procedure
96054359Sroberto *
96154359Sroberto */
96254359Srobertostatic void
96354359Srobertopalisade_poll (
96454359Sroberto	int unit,
96554359Sroberto	struct peer *peer
96654359Sroberto	)
96754359Sroberto{
96854359Sroberto	struct palisade_unit *up;
96954359Sroberto	struct refclockproc *pp;
97054359Sroberto
97154359Sroberto	pp = peer->procptr;
972290000Sglebius	up = pp->unitptr;
97354359Sroberto
97454359Sroberto	pp->polls++;
97554359Sroberto	if (up->polled > 0) /* last reply never arrived or error */
976290000Sglebius		refclock_report(peer, CEVNT_TIMEOUT);
97754359Sroberto
97854359Sroberto	up->polled = 2; /* synchronous packet + 1 event */
97954359Sroberto
98054359Sroberto#ifdef DEBUG
98154359Sroberto	if (debug)
982290000Sglebius		printf("palisade_poll: unit %d: polling %s\n", unit,
983290000Sglebius		       (pp->sloppyclockflag & CLK_FLAG2) ?
984290000Sglebius		       "synchronous packet" : "event");
98554359Sroberto#endif
98654359Sroberto
98754359Sroberto	if (pp->sloppyclockflag & CLK_FLAG2)
988290000Sglebius		return;  /* using synchronous packet input */
98954359Sroberto
990132451Sroberto	if(up->type == CLK_PRAECIS) {
991132451Sroberto		if(write(peer->procptr->io.fd,"SPSTAT\r\n",8) < 0)
992132451Sroberto			msyslog(LOG_ERR, "Palisade(%d) write: %m:",unit);
993132451Sroberto		else {
994132451Sroberto			praecis_msg = 1;
995132451Sroberto			return;
996132451Sroberto		}
997132451Sroberto	}
998132451Sroberto
99954359Sroberto	if (HW_poll(pp) < 0)
1000290000Sglebius		refclock_report(peer, CEVNT_FAULT);
100154359Sroberto}
100254359Sroberto
1003132451Srobertostatic void
1004290000Sglebiuspraecis_parse (
1005290000Sglebius	struct recvbuf *rbufp,
1006290000Sglebius	struct peer *peer
1007290000Sglebius	)
1008132451Sroberto{
1009132451Sroberto	static char buf[100];
1010132451Sroberto	static int p = 0;
1011132451Sroberto	struct refclockproc *pp;
101254359Sroberto
1013132451Sroberto	pp = peer->procptr;
1014132451Sroberto
1015132451Sroberto	memcpy(buf+p,rbufp->recv_space.X_recv_buffer, rbufp->recv_length);
1016132451Sroberto	p += rbufp->recv_length;
1017132451Sroberto
1018132451Sroberto	if(buf[p-2] == '\r' && buf[p-1] == '\n') {
1019132451Sroberto		buf[p-2] = '\0';
1020132451Sroberto		record_clock_stats(&peer->srcadr, buf);
1021132451Sroberto
1022132451Sroberto		p = 0;
1023132451Sroberto		praecis_msg = 0;
1024132451Sroberto
1025132451Sroberto		if (HW_poll(pp) < 0)
1026132451Sroberto			refclock_report(peer, CEVNT_FAULT);
1027132451Sroberto
1028132451Sroberto	}
1029132451Sroberto}
1030132451Sroberto
103154359Srobertostatic void
103254359Srobertopalisade_io (
103354359Sroberto	struct recvbuf *rbufp
103454359Sroberto	)
103554359Sroberto{
103654359Sroberto	/*
103754359Sroberto	 * Initialize pointers and read the timecode and timestamp.
103854359Sroberto	 */
103954359Sroberto	struct palisade_unit *up;
104054359Sroberto	struct refclockproc *pp;
104154359Sroberto	struct peer *peer;
104254359Sroberto
104354359Sroberto	char * c, * d;
104454359Sroberto
1045290000Sglebius	peer = rbufp->recv_peer;
104654359Sroberto	pp = peer->procptr;
1047290000Sglebius	up = pp->unitptr;
104854359Sroberto
1049132451Sroberto	if(up->type == CLK_PRAECIS) {
1050132451Sroberto		if(praecis_msg) {
1051132451Sroberto			praecis_parse(rbufp,peer);
1052132451Sroberto			return;
1053132451Sroberto		}
1054132451Sroberto	}
1055132451Sroberto
105654359Sroberto	c = (char *) &rbufp->recv_space;
105754359Sroberto	d = c + rbufp->recv_length;
105854359Sroberto
105954359Sroberto	while (c != d) {
106054359Sroberto
106154359Sroberto		/* Build time packet */
106254359Sroberto		switch (up->rpt_status) {
106354359Sroberto
106454359Sroberto		    case TSIP_PARSED_DLE_1:
106554359Sroberto			switch (*c)
106654359Sroberto			{
106754359Sroberto			    case 0:
106854359Sroberto			    case DLE:
106954359Sroberto			    case ETX:
107054359Sroberto				up->rpt_status = TSIP_PARSED_EMPTY;
107154359Sroberto				break;
107254359Sroberto
107354359Sroberto			    default:
107454359Sroberto				up->rpt_status = TSIP_PARSED_DATA;
107554359Sroberto				/* save packet ID */
107654359Sroberto				up->rpt_buf[0] = *c;
107754359Sroberto				break;
107854359Sroberto			}
107954359Sroberto			break;
108054359Sroberto
108154359Sroberto		    case TSIP_PARSED_DATA:
108254359Sroberto			if (*c == DLE)
1083290000Sglebius				up->rpt_status = TSIP_PARSED_DLE_2;
108454359Sroberto			else
1085290000Sglebius				mb(up->rpt_cnt++) = *c;
108654359Sroberto			break;
108754359Sroberto
108854359Sroberto		    case TSIP_PARSED_DLE_2:
108954359Sroberto			if (*c == DLE) {
109054359Sroberto				up->rpt_status = TSIP_PARSED_DATA;
109154359Sroberto				mb(up->rpt_cnt++) =
1092290000Sglebius				    *c;
1093290000Sglebius			}
109454359Sroberto			else if (*c == ETX)
1095290000Sglebius				up->rpt_status = TSIP_PARSED_FULL;
109654359Sroberto			else 	{
1097290000Sglebius				/* error: start new report packet */
109854359Sroberto				up->rpt_status = TSIP_PARSED_DLE_1;
109954359Sroberto				up->rpt_buf[0] = *c;
110054359Sroberto			}
110154359Sroberto			break;
110254359Sroberto
110354359Sroberto		    case TSIP_PARSED_FULL:
110454359Sroberto		    case TSIP_PARSED_EMPTY:
110554359Sroberto		    default:
1106290000Sglebius			if ( *c != DLE)
1107290000Sglebius				up->rpt_status = TSIP_PARSED_EMPTY;
1108290000Sglebius			else
1109290000Sglebius				up->rpt_status = TSIP_PARSED_DLE_1;
1110290000Sglebius			break;
111154359Sroberto		}
111254359Sroberto
111354359Sroberto		c++;
111454359Sroberto
111554359Sroberto		if (up->rpt_status == TSIP_PARSED_DLE_1) {
1116290000Sglebius			up->rpt_cnt = 0;
111754359Sroberto			if (pp->sloppyclockflag & CLK_FLAG2)
1118290000Sglebius				/* stamp it */
1119290000Sglebius				get_systime(&pp->lastrec);
112054359Sroberto		}
112154359Sroberto		else if (up->rpt_status == TSIP_PARSED_EMPTY)
1122290000Sglebius			up->rpt_cnt = 0;
112354359Sroberto
112454359Sroberto		else if (up->rpt_cnt > BMAX)
112554359Sroberto			up->rpt_status =TSIP_PARSED_EMPTY;
112654359Sroberto
112754359Sroberto		if (up->rpt_status == TSIP_PARSED_FULL)
112854359Sroberto			palisade_receive(peer);
112954359Sroberto
113054359Sroberto	} /* while chars in buffer */
113154359Sroberto}
113254359Sroberto
113354359Sroberto
113454359Sroberto/*
113554359Sroberto * Trigger the Palisade's event input, which is driven off the RTS
113654359Sroberto *
113754359Sroberto * Take a system time stamp to match the GPS time stamp.
113854359Sroberto *
113954359Sroberto */
114054359Srobertolong
114154359SrobertoHW_poll (
114254359Sroberto	struct refclockproc * pp 	/* pointer to unit structure */
114354359Sroberto	)
114454359Sroberto{
114554359Sroberto	int x;	/* state before & after RTS set */
114654359Sroberto	struct palisade_unit *up;
114754359Sroberto
1148290000Sglebius	up = pp->unitptr;
114954359Sroberto
115054359Sroberto	/* read the current status, so we put things back right */
115154359Sroberto	if (ioctl(pp->io.fd, TIOCMGET, &x) < 0) {
1152290000Sglebius		DPRINTF(1, ("Palisade HW_poll: unit %d: GET %m\n",
1153290000Sglebius			up->unit));
115454359Sroberto		msyslog(LOG_ERR, "Palisade(%d) HW_poll: ioctl(fd,GET): %m",
115554359Sroberto			up->unit);
115654359Sroberto		return -1;
115754359Sroberto	}
115854359Sroberto
115954359Sroberto	x |= TIOCM_RTS;        /* turn on RTS  */
116054359Sroberto
116154359Sroberto	/* Edge trigger */
1162290000Sglebius	if (up->type == CLK_ACUTIME)
1163290000Sglebius		write (pp->io.fd, "", 1);
1164290000Sglebius
116554359Sroberto	if (ioctl(pp->io.fd, TIOCMSET, &x) < 0) {
116654359Sroberto#ifdef DEBUG
1167290000Sglebius		if (debug)
1168290000Sglebius			printf("Palisade HW_poll: unit %d: SET \n", up->unit);
116954359Sroberto#endif
117054359Sroberto		msyslog(LOG_ERR,
117154359Sroberto			"Palisade(%d) HW_poll: ioctl(fd, SET, RTS_on): %m",
117254359Sroberto			up->unit);
117354359Sroberto		return -1;
117454359Sroberto	}
117554359Sroberto
117654359Sroberto	x &= ~TIOCM_RTS;        /* turn off RTS  */
117754359Sroberto
117854359Sroberto	/* poll timestamp */
117954359Sroberto	get_systime(&pp->lastrec);
118054359Sroberto
118154359Sroberto	if (ioctl(pp->io.fd, TIOCMSET, &x) == -1) {
118254359Sroberto#ifdef DEBUG
1183290000Sglebius		if (debug)
1184290000Sglebius			printf("Palisade HW_poll: unit %d: UNSET \n", up->unit);
118554359Sroberto#endif
118654359Sroberto		msyslog(LOG_ERR,
118754359Sroberto			"Palisade(%d) HW_poll: ioctl(fd, UNSET, RTS_off): %m",
118854359Sroberto			up->unit);
118954359Sroberto		return -1;
119054359Sroberto	}
119154359Sroberto
119254359Sroberto	return 0;
119354359Sroberto}
119454359Sroberto
119554359Sroberto/*
1196290000Sglebius * copy/swap a big-endian palisade double into a host double
119754359Sroberto */
1198290000Sglebiusstatic double
1199290000Sglebiusgetdbl (
120054359Sroberto	u_char *bp
120154359Sroberto	)
120254359Sroberto{
1203290000Sglebius#ifdef WORDS_BIGENDIAN
1204290000Sglebius	double out;
1205290000Sglebius
1206290000Sglebius	memcpy(&out, bp, sizeof(out));
1207290000Sglebius	return out;
120854359Sroberto#else
1209290000Sglebius	union {
1210290000Sglebius		u_char ch[8];
1211290000Sglebius		u_int32 u32[2];
1212290000Sglebius	} ui;
1213290000Sglebius
1214290000Sglebius	union {
1215290000Sglebius		double out;
1216290000Sglebius		u_int32 u32[2];
1217290000Sglebius	} uo;
1218290000Sglebius
1219290000Sglebius	memcpy(ui.ch, bp, sizeof(ui.ch));
1220290000Sglebius	/* least-significant 32 bits of double from swapped bp[4] to bp[7] */
1221290000Sglebius	uo.u32[0] = ntohl(ui.u32[1]);
1222290000Sglebius	/* most-significant 32 bits from swapped bp[0] to bp[3] */
1223290000Sglebius	uo.u32[1] = ntohl(ui.u32[0]);
1224290000Sglebius
1225290000Sglebius	return uo.out;
1226290000Sglebius#endif
122754359Sroberto}
122854359Sroberto
122954359Sroberto/*
1230290000Sglebius * copy/swap a big-endian palisade short into a host short
123154359Sroberto */
1232290000Sglebiusstatic short
1233290000Sglebiusgetint (
123454359Sroberto	u_char *bp
123554359Sroberto	)
123654359Sroberto{
1237290000Sglebius	u_short us;
1238290000Sglebius
1239290000Sglebius	memcpy(&us, bp, sizeof(us));
1240290000Sglebius	return (short)ntohs(us);
124154359Sroberto}
124254359Sroberto
124354359Sroberto/*
1244290000Sglebius * copy/swap a big-endian palisade 32-bit int into a host 32-bit int
124554359Sroberto */
1246290000Sglebiusstatic int32
1247290000Sglebiusgetlong(
124854359Sroberto	u_char *bp
124954359Sroberto	)
125054359Sroberto{
1251290000Sglebius	u_int32 u32;
1252290000Sglebius
1253290000Sglebius	memcpy(&u32, bp, sizeof(u32));
1254290000Sglebius	return (int32)(u_int32)ntohl(u32);
125554359Sroberto}
125654359Sroberto
1257290000Sglebius#else	/* REFCLOCK && CLOCK_PALISADE*/
1258290000Sglebiusint refclock_palisade_c_notempty;
1259290000Sglebius#endif
1260