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 *
53285612Sdelphij *
54285612Sdelphij *
55285612Sdelphij * 31/03/06: Added support for Thunderbolt GPS Disciplined Clock.
56285612Sdelphij *	     Contact: Fernando Pablo Hauscarriaga
57285612Sdelphij * 	     E-mail: fernandoph@iar.unlp.edu.ar
58285612Sdelphij * 	     Home page: www.iar.unlp.edu.ar/~fernandoph
59285612Sdelphij *		  Instituto Argentino de Radioastronomia
60285612Sdelphij *			    www.iar.unlp.edu.ar
61285612Sdelphij *
62285612Sdelphij * 14/01/07: Conditinal compilation for Thunderbolt support no longer needed
63285612Sdelphij *	     now we use mode 2 for decode thunderbolt packets.
64285612Sdelphij *	     Fernando P. Hauscarriaga
65285612Sdelphij *
66285612Sdelphij * 30/08/09: Added support for Trimble Acutime Gold Receiver.
67285612Sdelphij *	     Fernando P. Hauscarriaga (fernandoph@iar.unlp.edu.ar)
6854359Sroberto */
6954359Sroberto
7054359Sroberto#ifdef HAVE_CONFIG_H
71285612Sdelphij# include "config.h"
7254359Sroberto#endif
7354359Sroberto
74285612Sdelphij#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
8454359Sroberto#ifdef DEBUG
8554359Srobertoconst char * Tracking_Status[15][15] = {
86285612Sdelphij	{ "Doing Fixes\0" }, { "Good 1SV\0" }, { "Approx. 1SV\0" },
87285612Sdelphij	{"Need Time\0" }, { "Need INIT\0" }, { "PDOP too High\0" },
88285612Sdelphij	{ "Bad 1SV\0" }, { "0SV Usable\0" }, { "1SV Usable\0" },
89285612Sdelphij	{ "2SV Usable\0" }, { "3SV Usable\0" }, { "No Integrity\0" },
90285612Sdelphij	{ "Diff Corr\0" }, { "Overdet Clock\0" }, { "Invalid\0" } };
9154359Sroberto#endif
9254359Sroberto
9354359Sroberto/*
9454359Sroberto * Transfer vector
9554359Sroberto */
9654359Srobertostruct refclock refclock_palisade = {
9754359Sroberto	palisade_start,		/* start up driver */
9854359Sroberto	palisade_shutdown,	/* shut down driver */
9954359Sroberto	palisade_poll,		/* transmit poll message */
10054359Sroberto	noentry,		/* not used  */
10154359Sroberto	noentry,		/* initialize driver (not used) */
10254359Sroberto	noentry,		/* not used */
10354359Sroberto	NOFLAGS			/* not used */
10454359Sroberto};
10554359Sroberto
106330141Sdelphijstatic int decode_date(struct refclockproc *pp, const char *cp);
10754359Sroberto
108132451Sroberto/* Extract the clock type from the mode setting */
109132451Sroberto#define CLK_TYPE(x) ((int)(((x)->ttl) & 0x7F))
110132451Sroberto
111132451Sroberto/* Supported clock types */
112132451Sroberto#define CLK_TRIMBLE	0	/* Trimble Palisade */
113132451Sroberto#define CLK_PRAECIS	1	/* Endrun Technologies Praecis */
114285612Sdelphij#define CLK_THUNDERBOLT	2	/* Trimble Thunderbolt GPS Receiver */
115285612Sdelphij#define CLK_ACUTIME     3	/* Trimble Acutime Gold */
116285612Sdelphij#define CLK_ACUTIMEB    4	/* Trimble Actutime Gold Port B */
117132451Sroberto
118132451Srobertoint praecis_msg;
119132451Srobertostatic void praecis_parse(struct recvbuf *rbufp, struct peer *peer);
120132451Sroberto
121285612Sdelphij/* These routines are for sending packets to the Thunderbolt receiver
122285612Sdelphij * They are taken from Markus Prosch
123285612Sdelphij */
124285612Sdelphij
125285612Sdelphij#ifdef PALISADE_SENDCMD_RESURRECTED
12654359Sroberto/*
127285612Sdelphij * sendcmd - Build data packet for sending
128285612Sdelphij */
129285612Sdelphijstatic void
130285612Sdelphijsendcmd (
131285612Sdelphij	struct packettx *buffer,
132285612Sdelphij	int c
133285612Sdelphij	)
134285612Sdelphij{
135285612Sdelphij	*buffer->data = DLE;
136285612Sdelphij	*(buffer->data + 1) = (unsigned char)c;
137285612Sdelphij	buffer->size = 2;
138285612Sdelphij}
139285612Sdelphij#endif	/* PALISADE_SENDCMD_RESURRECTED */
140285612Sdelphij
141285612Sdelphij/*
142285612Sdelphij * sendsupercmd - Build super data packet for sending
143285612Sdelphij */
144285612Sdelphijstatic void
145285612Sdelphijsendsupercmd (
146285612Sdelphij	struct packettx *buffer,
147285612Sdelphij	int c1,
148285612Sdelphij	int c2
149285612Sdelphij	)
150285612Sdelphij{
151285612Sdelphij	*buffer->data = DLE;
152285612Sdelphij	*(buffer->data + 1) = (unsigned char)c1;
153285612Sdelphij	*(buffer->data + 2) = (unsigned char)c2;
154285612Sdelphij	buffer->size = 3;
155285612Sdelphij}
156285612Sdelphij
157285612Sdelphij/*
158285612Sdelphij * sendbyte -
159285612Sdelphij */
160285612Sdelphijstatic void
161285612Sdelphijsendbyte (
162285612Sdelphij	struct packettx *buffer,
163285612Sdelphij	int b
164285612Sdelphij	)
165285612Sdelphij{
166285612Sdelphij	if (b == DLE)
167285612Sdelphij		*(buffer->data+buffer->size++) = DLE;
168285612Sdelphij	*(buffer->data+buffer->size++) = (unsigned char)b;
169285612Sdelphij}
170285612Sdelphij
171285612Sdelphij/*
172285612Sdelphij * sendint -
173285612Sdelphij */
174285612Sdelphijstatic void
175285612Sdelphijsendint (
176285612Sdelphij	struct packettx *buffer,
177285612Sdelphij	int a
178285612Sdelphij	)
179285612Sdelphij{
180285612Sdelphij	sendbyte(buffer, (unsigned char)((a>>8) & 0xff));
181285612Sdelphij	sendbyte(buffer, (unsigned char)(a & 0xff));
182285612Sdelphij}
183285612Sdelphij
184285612Sdelphij/*
185285612Sdelphij * sendetx - Send packet or super packet to the device
186285612Sdelphij */
187285612Sdelphijstatic int
188285612Sdelphijsendetx (
189285612Sdelphij	struct packettx *buffer,
190285612Sdelphij	int fd
191285612Sdelphij	)
192285612Sdelphij{
193285612Sdelphij	int result;
194285612Sdelphij
195285612Sdelphij	*(buffer->data+buffer->size++) = DLE;
196285612Sdelphij	*(buffer->data+buffer->size++) = ETX;
197285612Sdelphij	result = write(fd, buffer->data, (unsigned long)buffer->size);
198285612Sdelphij
199285612Sdelphij	if (result != -1)
200285612Sdelphij		return (result);
201285612Sdelphij	else
202285612Sdelphij		return (-1);
203285612Sdelphij}
204285612Sdelphij
205285612Sdelphij/*
206285612Sdelphij * init_thunderbolt - Prepares Thunderbolt receiver to be used with
207285612Sdelphij *		      NTP (also taken from Markus Prosch).
208285612Sdelphij */
209285612Sdelphijstatic void
210285612Sdelphijinit_thunderbolt (
211285612Sdelphij	int fd
212285612Sdelphij	)
213285612Sdelphij{
214285612Sdelphij	struct packettx tx;
215285612Sdelphij
216285612Sdelphij	tx.size = 0;
217289997Sglebius	tx.data = (u_char *) emalloc(100);
218285612Sdelphij
219285612Sdelphij	/* set UTC time */
220285612Sdelphij	sendsupercmd (&tx, 0x8E, 0xA2);
221285612Sdelphij	sendbyte     (&tx, 0x3);
222285612Sdelphij	sendetx      (&tx, fd);
223285612Sdelphij
224285612Sdelphij	/* activate packets 0x8F-AB and 0x8F-AC */
225330141Sdelphij	sendsupercmd (&tx, 0x8E, 0xA5);
226285612Sdelphij	sendint      (&tx, 0x5);
227285612Sdelphij	sendetx      (&tx, fd);
228285612Sdelphij
229285612Sdelphij	free(tx.data);
230285612Sdelphij}
231285612Sdelphij
232285612Sdelphij/*
233285612Sdelphij * init_acutime - Prepares Acutime Receiver to be used with NTP
234285612Sdelphij */
235285612Sdelphijstatic void
236285612Sdelphijinit_acutime (
237285612Sdelphij	int fd
238285612Sdelphij	)
239285612Sdelphij{
240285612Sdelphij	/* Disable all outputs, Enable Event-Polling on PortA so
241285612Sdelphij	   we can ask for time packets */
242285612Sdelphij	struct packettx tx;
243285612Sdelphij
244285612Sdelphij	tx.size = 0;
245289997Sglebius	tx.data = (u_char *) emalloc(100);
246285612Sdelphij
247285612Sdelphij	sendsupercmd(&tx, 0x8E, 0xA5);
248285612Sdelphij	sendbyte(&tx, 0x02);
249285612Sdelphij	sendbyte(&tx, 0x00);
250285612Sdelphij	sendbyte(&tx, 0x00);
251285612Sdelphij	sendbyte(&tx, 0x00);
252285612Sdelphij	sendetx(&tx, fd);
253285612Sdelphij
254285612Sdelphij	free(tx.data);
255285612Sdelphij}
256285612Sdelphij
257285612Sdelphij/*
25854359Sroberto * palisade_start - open the devices and initialize data for processing
25954359Sroberto */
26054359Srobertostatic int
26154359Srobertopalisade_start (
26254359Sroberto	int unit,
26354359Sroberto	struct peer *peer
26454359Sroberto	)
26554359Sroberto{
26654359Sroberto	struct palisade_unit *up;
26754359Sroberto	struct refclockproc *pp;
26854359Sroberto	int fd;
26954359Sroberto	char gpsdev[20];
270285612Sdelphij	struct termios tio;
27154359Sroberto
272285612Sdelphij	snprintf(gpsdev, sizeof(gpsdev), DEVICE, unit);
273285612Sdelphij
27454359Sroberto	/*
27554359Sroberto	 * Open serial port.
27654359Sroberto	 */
27754359Sroberto	fd = refclock_open(gpsdev, SPEED232, LDISC_RAW);
27854359Sroberto	if (fd <= 0) {
27954359Sroberto#ifdef DEBUG
28054359Sroberto		printf("Palisade(%d) start: open %s failed\n", unit, gpsdev);
28154359Sroberto#endif
28254359Sroberto		return 0;
28354359Sroberto	}
28454359Sroberto
28554359Sroberto	msyslog(LOG_NOTICE, "Palisade(%d) fd: %d dev: %s", unit, fd,
28654359Sroberto		gpsdev);
28754359Sroberto
288285612Sdelphij	if (tcgetattr(fd, &tio) < 0) {
289285612Sdelphij		msyslog(LOG_ERR,
29054359Sroberto			"Palisade(%d) tcgetattr(fd, &tio): %m",unit);
29154359Sroberto#ifdef DEBUG
292285612Sdelphij		printf("Palisade(%d) tcgetattr(fd, &tio)\n",unit);
29354359Sroberto#endif
294285612Sdelphij		close(fd);
295285612Sdelphij		return (0);
296285612Sdelphij	}
29754359Sroberto
298285612Sdelphij	tio.c_cflag |= (PARENB|PARODD);
299285612Sdelphij	tio.c_iflag &= ~ICRNL;
30054359Sroberto
30154359Sroberto	/*
30254359Sroberto	 * Allocate and initialize unit structure
30354359Sroberto	 */
304285612Sdelphij	up = emalloc_zero(sizeof(*up));
30554359Sroberto
306132451Sroberto	up->type = CLK_TYPE(peer);
307132451Sroberto	switch (up->type) {
308285612Sdelphij	    case CLK_TRIMBLE:
309285612Sdelphij		/* Normal mode, do nothing */
310285612Sdelphij		break;
311285612Sdelphij	    case CLK_PRAECIS:
312285612Sdelphij		msyslog(LOG_NOTICE, "Palisade(%d) Praecis mode enabled"
313285612Sdelphij			,unit);
314285612Sdelphij		break;
315285612Sdelphij	    case CLK_THUNDERBOLT:
316285612Sdelphij		msyslog(LOG_NOTICE, "Palisade(%d) Thunderbolt mode enabled"
317285612Sdelphij			,unit);
318285612Sdelphij		tio.c_cflag = (CS8|CLOCAL|CREAD);
319285612Sdelphij		break;
320285612Sdelphij	    case CLK_ACUTIME:
321285612Sdelphij		msyslog(LOG_NOTICE, "Palisade(%d) Acutime Gold mode enabled"
322285612Sdelphij			,unit);
323285612Sdelphij		break;
324285612Sdelphij	    default:
325285612Sdelphij		msyslog(LOG_NOTICE, "Palisade(%d) mode unknown",unit);
326285612Sdelphij		break;
327132451Sroberto	}
328285612Sdelphij	if (tcsetattr(fd, TCSANOW, &tio) == -1) {
329285612Sdelphij		msyslog(LOG_ERR, "Palisade(%d) tcsetattr(fd, &tio): %m",unit);
330285612Sdelphij#ifdef DEBUG
331285612Sdelphij		printf("Palisade(%d) tcsetattr(fd, &tio)\n",unit);
332285612Sdelphij#endif
333285612Sdelphij		close(fd);
334285612Sdelphij		free(up);
335285612Sdelphij		return 0;
336285612Sdelphij	}
337132451Sroberto
33854359Sroberto	pp = peer->procptr;
33954359Sroberto	pp->io.clock_recv = palisade_io;
340285612Sdelphij	pp->io.srcclock = peer;
34154359Sroberto	pp->io.datalen = 0;
34254359Sroberto	pp->io.fd = fd;
34354359Sroberto	if (!io_addclock(&pp->io)) {
34454359Sroberto#ifdef DEBUG
345285612Sdelphij		printf("Palisade(%d) io_addclock\n",unit);
34654359Sroberto#endif
347285612Sdelphij		close(fd);
348285612Sdelphij		pp->io.fd = -1;
34954359Sroberto		free(up);
35054359Sroberto		return (0);
35154359Sroberto	}
35254359Sroberto
35354359Sroberto	/*
35454359Sroberto	 * Initialize miscellaneous variables
35554359Sroberto	 */
356285612Sdelphij	pp->unitptr = up;
35754359Sroberto	pp->clockdesc = DESCRIPTION;
35854359Sroberto
35954359Sroberto	peer->precision = PRECISION;
36054359Sroberto	peer->sstclktype = CTL_SST_TS_UHF;
36154359Sroberto	peer->minpoll = TRMB_MINPOLL;
36254359Sroberto	peer->maxpoll = TRMB_MAXPOLL;
36354359Sroberto	memcpy((char *)&pp->refid, REFID, 4);
36454359Sroberto
36554359Sroberto	up->leap_status = 0;
36654359Sroberto	up->unit = (short) unit;
36754359Sroberto	up->rpt_status = TSIP_PARSED_EMPTY;
368285612Sdelphij	up->rpt_cnt = 0;
36954359Sroberto
370285612Sdelphij	if (up->type == CLK_THUNDERBOLT)
371285612Sdelphij		init_thunderbolt(fd);
372285612Sdelphij	if (up->type == CLK_ACUTIME)
373285612Sdelphij		init_acutime(fd);
374285612Sdelphij
37554359Sroberto	return 1;
37654359Sroberto}
37754359Sroberto
37854359Sroberto
37954359Sroberto/*
38054359Sroberto * palisade_shutdown - shut down the clock
38154359Sroberto */
38254359Srobertostatic void
38354359Srobertopalisade_shutdown (
38454359Sroberto	int unit,
38554359Sroberto	struct peer *peer
38654359Sroberto	)
38754359Sroberto{
38854359Sroberto	struct palisade_unit *up;
38954359Sroberto	struct refclockproc *pp;
39054359Sroberto	pp = peer->procptr;
391285612Sdelphij	up = pp->unitptr;
392285612Sdelphij	if (-1 != pp->io.fd)
393285612Sdelphij		io_closeclock(&pp->io);
394285612Sdelphij	if (NULL != up)
395285612Sdelphij		free(up);
39654359Sroberto}
39754359Sroberto
39854359Sroberto
39954359Sroberto/*
400330141Sdelphij * unpack helpers
40154359Sroberto */
402330141Sdelphij
403330141Sdelphijstatic inline uint8_t
404330141Sdelphijget_u8(
405330141Sdelphij	const char *cp)
406330141Sdelphij{
407330141Sdelphij	return ((const u_char*)cp)[0];
408330141Sdelphij}
409330141Sdelphij
410330141Sdelphijstatic inline uint16_t
411330141Sdelphijget_u16(
412330141Sdelphij	const char *cp)
413330141Sdelphij{
414330141Sdelphij	return ((uint16_t)get_u8(cp) << 8) | get_u8(cp + 1);
415330141Sdelphij}
416330141Sdelphij
417330141Sdelphij/*
418330141Sdelphij * unpack & fix date (the receiver provides a valid time for 1024 weeks
419330141Sdelphij * after 1997-12-14 and therefore folds back in 2017, 2037,...)
420330141Sdelphij *
421330141Sdelphij * Returns -1 on error, day-of-month + (month * 32) othertwise.
422330141Sdelphij */
42354359Srobertoint
424330141Sdelphijdecode_date(
425330141Sdelphij	struct refclockproc *pp,
426330141Sdelphij	const char          *cp)
42754359Sroberto{
428330141Sdelphij	static int32_t  s_baseday = 0;
429330141Sdelphij
430330141Sdelphij	struct calendar jd;
431330141Sdelphij	int32_t         rd;
43254359Sroberto
433330141Sdelphij	if (0 == s_baseday) {
434330141Sdelphij		if (!ntpcal_get_build_date(&jd)) {
435330141Sdelphij			jd.year     = 2015;
436330141Sdelphij			jd.month    = 1;
437330141Sdelphij			jd.monthday = 1;
438330141Sdelphij		}
439330141Sdelphij		s_baseday = ntpcal_date_to_rd(&jd);
440330141Sdelphij	}
44154359Sroberto
442330141Sdelphij	/* get date fields and convert to RDN */
443330141Sdelphij	jd.monthday = get_u8 (  cp  );
444330141Sdelphij	jd.month    = get_u8 (cp + 1);
445330141Sdelphij	jd.year     = get_u16(cp + 2);
446330141Sdelphij	rd = ntpcal_date_to_rd(&jd);
44754359Sroberto
448330141Sdelphij	/* for the paranoid: do reverse calculation and cross-check */
449330141Sdelphij	ntpcal_rd_to_date(&jd, rd);
450330141Sdelphij	if ((jd.monthday != get_u8 (  cp  )) ||
451330141Sdelphij	    (jd.month    != get_u8 (cp + 1)) ||
452330141Sdelphij	    (jd.year     != get_u16(cp + 2))  )
453330141Sdelphij		return - 1;
454330141Sdelphij
455330141Sdelphij	/* calculate cycle shift to base day and calculate re-folded
456330141Sdelphij	 * date
457330141Sdelphij	 *
458330141Sdelphij	 * One could do a proper modulo calculation here, but a counting
459330141Sdelphij	 * loop is probably faster for the next few rollovers...
460330141Sdelphij	 */
461330141Sdelphij	while (rd < s_baseday)
462330141Sdelphij		rd += 7*1024;
463330141Sdelphij	ntpcal_rd_to_date(&jd, rd);
46454359Sroberto
465330141Sdelphij	/* fill refclock structure & indicate success */
466330141Sdelphij	pp->day  = jd.yearday;
467330141Sdelphij	pp->year = jd.year;
468330141Sdelphij	return ((int)jd.month << 5) | jd.monthday;
46954359Sroberto}
470330141Sdelphij
47154359Sroberto
47254359Sroberto/*
47354359Sroberto * TSIP_decode - decode the TSIP data packets
47454359Sroberto */
47554359Srobertoint
47654359SrobertoTSIP_decode (
47754359Sroberto	struct peer *peer
47854359Sroberto	)
47954359Sroberto{
48054359Sroberto	int st;
48154359Sroberto	long   secint;
48254359Sroberto	double secs;
48354359Sroberto	double secfrac;
48454359Sroberto	unsigned short event = 0;
485330141Sdelphij	int mmday;
486330141Sdelphij
48754359Sroberto	struct palisade_unit *up;
48854359Sroberto	struct refclockproc *pp;
48954359Sroberto
49054359Sroberto	pp = peer->procptr;
491285612Sdelphij	up = pp->unitptr;
49254359Sroberto
49354359Sroberto	/*
49454359Sroberto	 * Check the time packet, decode its contents.
49554359Sroberto	 * If the timecode has invalid length or is not in
49654359Sroberto	 * proper format, declare bad format and exit.
49754359Sroberto	 */
49854359Sroberto
499285612Sdelphij	if ((up->type != CLK_THUNDERBOLT) & (up->type != CLK_ACUTIME)){
500285612Sdelphij		if ((up->rpt_buf[0] == (char) 0x41) ||
501285612Sdelphij		    (up->rpt_buf[0] == (char) 0x46) ||
502285612Sdelphij		    (up->rpt_buf[0] == (char) 0x54) ||
503285612Sdelphij		    (up->rpt_buf[0] == (char) 0x4B) ||
504285612Sdelphij		    (up->rpt_buf[0] == (char) 0x6D)) {
50554359Sroberto
506285612Sdelphij			/* standard time packet - GPS time and GPS week number */
50754359Sroberto#ifdef DEBUG
50854359Sroberto			printf("Palisade Port B packets detected. Connect to Port A\n");
50954359Sroberto#endif
51054359Sroberto
511285612Sdelphij			return 0;
512285612Sdelphij		}
51354359Sroberto	}
51454359Sroberto
515132451Sroberto	/*
516132451Sroberto	 * We cast both to u_char to as 0x8f uses the sign bit on a char
517132451Sroberto	 */
518132451Sroberto	if ((u_char) up->rpt_buf[0] == (u_char) 0x8f) {
519285612Sdelphij		/*
520285612Sdelphij		 * Superpackets
521285612Sdelphij		 */
522285612Sdelphij		event = (unsigned short) (getint((u_char *) &mb(1)) & 0xffff);
523285612Sdelphij		if (!((pp->sloppyclockflag & CLK_FLAG2) || event))
524285612Sdelphij			/* Ignore Packet */
52554359Sroberto			return 0;
52654359Sroberto
527285612Sdelphij		switch (mb(0) & 0xff) {
528285612Sdelphij			int GPS_UTC_Offset;
529285612Sdelphij			long tow;
53054359Sroberto
531285612Sdelphij		    case PACKET_8F0B:
53254359Sroberto
533285612Sdelphij			if (up->polled <= 0)
534285612Sdelphij				return 0;
535285612Sdelphij
536285612Sdelphij			if (up->rpt_cnt != LENCODE_8F0B)  /* check length */
537285612Sdelphij				break;
53854359Sroberto
53954359Sroberto#ifdef DEBUG
540285612Sdelphij			if (debug > 1) {
541285612Sdelphij				int ts;
542285612Sdelphij				double lat, lon, alt;
543285612Sdelphij				lat = getdbl((u_char *) &mb(42)) * R2D;
544285612Sdelphij				lon = getdbl((u_char *) &mb(50)) * R2D;
545285612Sdelphij				alt = getdbl((u_char *) &mb(58));
54654359Sroberto
547285612Sdelphij				printf("TSIP_decode: unit %d: Latitude: %03.4f Longitude: %03.4f Alt: %05.2f m\n",
548285612Sdelphij				       up->unit, lat,lon,alt);
549285612Sdelphij				printf("TSIP_decode: unit %d: Sats:",
550285612Sdelphij				       up->unit);
551285612Sdelphij				for (st = 66, ts = 0; st <= 73; st++)
552285612Sdelphij					if (mb(st)) {
553285612Sdelphij						if (mb(st) > 0) ts++;
554285612Sdelphij						printf(" %02d", mb(st));
555285612Sdelphij					}
556285612Sdelphij				printf(" : Tracking %d\n", ts);
557285612Sdelphij			}
55854359Sroberto#endif
55954359Sroberto
560285612Sdelphij			GPS_UTC_Offset = getint((u_char *) &mb(16));
561285612Sdelphij			if (GPS_UTC_Offset == 0) { /* Check UTC offset */
56254359Sroberto#ifdef DEBUG
563285612Sdelphij				printf("TSIP_decode: UTC Offset Unknown\n");
56454359Sroberto#endif
565285612Sdelphij				break;
566285612Sdelphij			}
56754359Sroberto
568285612Sdelphij			secs = getdbl((u_char *) &mb(3));
569285612Sdelphij			secint = (long) secs;
570285612Sdelphij			secfrac = secs - secint; /* 0.0 <= secfrac < 1.0 */
57154359Sroberto
572285612Sdelphij			pp->nsec = (long) (secfrac * 1000000000);
57354359Sroberto
574285612Sdelphij			secint %= 86400;    /* Only care about today */
575285612Sdelphij			pp->hour = secint / 3600;
576285612Sdelphij			secint %= 3600;
577285612Sdelphij			pp->minute = secint / 60;
578285612Sdelphij			secint %= 60;
579285612Sdelphij			pp->second = secint % 60;
58054359Sroberto
581330141Sdelphij			mmday = decode_date(pp, &mb(11));
582330141Sdelphij			if (mmday < 0)
583330141Sdelphij				break;
58454359Sroberto
58554359Sroberto#ifdef DEBUG
586285612Sdelphij			if (debug > 1)
587285612Sdelphij				printf("TSIP_decode: unit %d: %02X #%d %02d:%02d:%02d.%09ld %02d/%02d/%04d UTC %02d\n",
588285612Sdelphij				       up->unit, mb(0) & 0xff, event, pp->hour, pp->minute,
589330141Sdelphij				       pp->second, pp->nsec, (mmday >> 5), (mmday & 31), pp->year, GPS_UTC_Offset);
59054359Sroberto#endif
591285612Sdelphij			/* Only use this packet when no
592285612Sdelphij			 * 8F-AD's are being received
593285612Sdelphij			 */
59454359Sroberto
595285612Sdelphij			if (up->leap_status) {
596285612Sdelphij				up->leap_status = 0;
597285612Sdelphij				return 0;
598285612Sdelphij			}
59954359Sroberto
600285612Sdelphij			return 2;
601285612Sdelphij			break;
60254359Sroberto
603285612Sdelphij		    case PACKET_NTP:
604285612Sdelphij			/* Palisade-NTP Packet */
60554359Sroberto
606285612Sdelphij			if (up->rpt_cnt != LENCODE_NTP) /* check length */
607285612Sdelphij				break;
60854359Sroberto
609285612Sdelphij			up->leap_status = mb(19);
61054359Sroberto
611285612Sdelphij			if (up->polled  <= 0)
612285612Sdelphij				return 0;
61354359Sroberto
614285612Sdelphij			/* Check Tracking Status */
615285612Sdelphij			st = mb(18);
616285612Sdelphij			if (st < 0 || st > 14)
617285612Sdelphij				st = 14;
618285612Sdelphij			if ((st >= 2 && st <= 7) || st == 11 || st == 12) {
61954359Sroberto#ifdef DEBUG
620285612Sdelphij				printf("TSIP_decode: Not Tracking Sats : %s\n",
621285612Sdelphij				       *Tracking_Status[st]);
62254359Sroberto#endif
623285612Sdelphij				refclock_report(peer, CEVNT_BADTIME);
624285612Sdelphij				up->polled = -1;
625285612Sdelphij				return 0;
626285612Sdelphij				break;
627285612Sdelphij			}
628285612Sdelphij
629330141Sdelphij			mmday = decode_date(pp, &mb(14));
630330141Sdelphij			if (mmday < 0)
631330141Sdelphij				break;
632330141Sdelphij			up->month  = (mmday >> 5);  /* Save for LEAP check */
633330141Sdelphij
634285612Sdelphij			if ( (up->leap_status & PALISADE_LEAP_PENDING) &&
635285612Sdelphij			/* Avoid early announce: https://bugs.ntp.org/2773 */
636285612Sdelphij				(6 == up->month || 12 == up->month) ) {
637285612Sdelphij				if (up->leap_status & PALISADE_UTC_TIME)
638285612Sdelphij					pp->leap = LEAP_ADDSECOND;
639285612Sdelphij				else
640285612Sdelphij					pp->leap = LEAP_DELSECOND;
641285612Sdelphij			}
642285612Sdelphij			else if (up->leap_status)
643285612Sdelphij				pp->leap = LEAP_NOWARNING;
644285612Sdelphij
645285612Sdelphij			else {  /* UTC flag is not set:
646285612Sdelphij				 * Receiver may have been reset, and lost
647285612Sdelphij				 * its UTC almanac data */
648285612Sdelphij				pp->leap = LEAP_NOTINSYNC;
649285612Sdelphij#ifdef DEBUG
650285612Sdelphij				printf("TSIP_decode: UTC Almanac unavailable: %d\n",
651285612Sdelphij				       mb(19));
652285612Sdelphij#endif
653285612Sdelphij				refclock_report(peer, CEVNT_BADTIME);
654285612Sdelphij				up->polled = -1;
655285612Sdelphij				return 0;
656285612Sdelphij			}
657285612Sdelphij
658285612Sdelphij			pp->nsec = (long) (getdbl((u_char *) &mb(3))
659285612Sdelphij					   * 1000000000);
660285612Sdelphij
661285612Sdelphij			pp->hour = mb(11);
662285612Sdelphij			pp->minute = mb(12);
663285612Sdelphij			pp->second = mb(13);
664285612Sdelphij
665285612Sdelphij#ifdef DEBUG
666285612Sdelphij			if (debug > 1)
667285612Sdelphij				printf("TSIP_decode: unit %d: %02X #%d %02d:%02d:%02d.%09ld %02d/%02d/%04d UTC %02x %s\n",
668285612Sdelphij				       up->unit, mb(0) & 0xff, event, pp->hour, pp->minute,
669330141Sdelphij				       pp->second, pp->nsec, (mmday >> 5), (mmday & 31), pp->year,
670285612Sdelphij				       mb(19), *Tracking_Status[st]);
671285612Sdelphij#endif
672285612Sdelphij			return 1;
673285612Sdelphij			break;
674285612Sdelphij
675285612Sdelphij		    case PACKET_8FAC:
676285612Sdelphij			if (up->polled <= 0)
677285612Sdelphij				return 0;
678285612Sdelphij
679285612Sdelphij			if (up->rpt_cnt != LENCODE_8FAC)/* check length */
680285612Sdelphij				break;
681285612Sdelphij
682285612Sdelphij#ifdef DEBUG
683285612Sdelphij			if (debug > 1) {
684285612Sdelphij				double lat, lon, alt;
685285612Sdelphij				lat = getdbl((u_char *) &mb(36)) * R2D;
686285612Sdelphij				lon = getdbl((u_char *) &mb(44)) * R2D;
687285612Sdelphij				alt = getdbl((u_char *) &mb(52));
688285612Sdelphij
689285612Sdelphij				printf("TSIP_decode: unit %d: Latitude: %03.4f Longitude: %03.4f Alt: %05.2f m\n",
690285612Sdelphij				       up->unit, lat,lon,alt);
691285612Sdelphij				printf("TSIP_decode: unit %d\n", up->unit);
692285612Sdelphij			}
693285612Sdelphij#endif
694285612Sdelphij			if ( (getint((u_char *) &mb(10)) & 0x80) &&
695285612Sdelphij			/* Avoid early announce: https://bugs.ntp.org/2773 */
696285612Sdelphij			    (6 == up->month || 12 == up->month) )
697285612Sdelphij				pp->leap = LEAP_ADDSECOND;  /* we ASSUME addsecond */
698285612Sdelphij			else
699285612Sdelphij				pp->leap = LEAP_NOWARNING;
700285612Sdelphij
701285612Sdelphij#ifdef DEBUG
702285612Sdelphij			if (debug > 1)
703285612Sdelphij				printf("TSIP_decode: unit %d: 0x%02x leap %d\n",
704285612Sdelphij				       up->unit, mb(0) & 0xff, pp->leap);
705285612Sdelphij			if (debug > 1) {
706285612Sdelphij				printf("Receiver MODE: 0x%02X\n", (u_char)mb(1));
707285612Sdelphij				if (mb(1) == 0x00)
708285612Sdelphij					printf("                AUTOMATIC\n");
709285612Sdelphij				if (mb(1) == 0x01)
710285612Sdelphij					printf("                SINGLE SATELLITE\n");
711285612Sdelphij				if (mb(1) == 0x03)
712285612Sdelphij					printf("                HORIZONTAL(2D)\n");
713285612Sdelphij				if (mb(1) == 0x04)
714285612Sdelphij					printf("                FULL POSITION(3D)\n");
715285612Sdelphij				if (mb(1) == 0x05)
716285612Sdelphij					printf("                DGPR REFERENCE\n");
717285612Sdelphij				if (mb(1) == 0x06)
718285612Sdelphij					printf("                CLOCK HOLD(2D)\n");
719285612Sdelphij				if (mb(1) == 0x07)
720285612Sdelphij					printf("                OVERDETERMINED CLOCK\n");
721285612Sdelphij
722285612Sdelphij				printf("\n** Disciplining MODE 0x%02X:\n", (u_char)mb(2));
723285612Sdelphij				if (mb(2) == 0x00)
724285612Sdelphij					printf("                NORMAL\n");
725285612Sdelphij				if (mb(2) == 0x01)
726285612Sdelphij					printf("                POWER-UP\n");
727285612Sdelphij				if (mb(2) == 0x02)
728285612Sdelphij					printf("                AUTO HOLDOVER\n");
729285612Sdelphij				if (mb(2) == 0x03)
730285612Sdelphij					printf("                MANUAL HOLDOVER\n");
731285612Sdelphij				if (mb(2) == 0x04)
732285612Sdelphij					printf("                RECOVERY\n");
733285612Sdelphij				if (mb(2) == 0x06)
734285612Sdelphij					printf("                DISCIPLINING DISABLED\n");
735285612Sdelphij			}
736285612Sdelphij#endif
73754359Sroberto			return 0;
73854359Sroberto			break;
73954359Sroberto
740285612Sdelphij		    case PACKET_8FAB:
741285612Sdelphij			/* Thunderbolt Primary Timing Packet */
742285612Sdelphij
743285612Sdelphij			if (up->rpt_cnt != LENCODE_8FAB) /* check length */
744285612Sdelphij				break;
745285612Sdelphij
746285612Sdelphij			if (up->polled  <= 0)
747285612Sdelphij				return 0;
748285612Sdelphij
749285612Sdelphij			GPS_UTC_Offset = getint((u_char *) &mb(7));
750285612Sdelphij
751285612Sdelphij			if (GPS_UTC_Offset == 0){ /* Check UTC Offset */
752285612Sdelphij#ifdef DEBUG
753285612Sdelphij				printf("TSIP_decode: UTC Offset Unknown\n");
754285612Sdelphij#endif
755285612Sdelphij				break;
756285612Sdelphij			}
757285612Sdelphij
758285612Sdelphij
759285612Sdelphij			if ((mb(9) & 0x1d) == 0x0) {
760285612Sdelphij				/* if we know the GPS time and the UTC offset,
761285612Sdelphij				   we expect UTC timing information !!! */
762285612Sdelphij
763285612Sdelphij				pp->leap = LEAP_NOTINSYNC;
764285612Sdelphij				refclock_report(peer, CEVNT_BADTIME);
765285612Sdelphij				up->polled = -1;
766285612Sdelphij				return 0;
767285612Sdelphij			}
768285612Sdelphij
769285612Sdelphij			pp->nsec = 0;
770285612Sdelphij#ifdef DEBUG
771285612Sdelphij			printf("\nTiming Flags are:\n");
772285612Sdelphij			printf("Timing flag value is: 0x%X\n", mb(9));
773285612Sdelphij			if ((mb(9) & 0x01) != 0)
774285612Sdelphij				printf ("	Getting UTC time\n");
77554359Sroberto			else
776285612Sdelphij				printf ("	Getting GPS time\n");
777285612Sdelphij			if ((mb(9) & 0x02) != 0)
778285612Sdelphij				printf ("	PPS is from UTC\n");
779285612Sdelphij			else
780285612Sdelphij				printf ("	PPS is from GPS\n");
781285612Sdelphij			if ((mb(9) & 0x04) != 0)
782285612Sdelphij				printf ("	Time is not Set\n");
783285612Sdelphij			else
784285612Sdelphij				printf ("	Time is Set\n");
785285612Sdelphij			if ((mb(9) & 0x08) != 0)
786285612Sdelphij				printf("	I dont have UTC info\n");
787285612Sdelphij			else
788285612Sdelphij				printf ("	I have UTC info\n");
789285612Sdelphij			if ((mb(9) & 0x10) != 0)
790285612Sdelphij				printf ("	Time is from USER\n\n");
791285612Sdelphij			else
792285612Sdelphij				printf ("	Time is from GPS\n\n");
793285612Sdelphij#endif
794285612Sdelphij
795330141Sdelphij			mmday = decode_date(pp, &mb(13));
796330141Sdelphij			if (mmday < 0)
797285612Sdelphij				break;
798285612Sdelphij			tow = getlong((u_char *) &mb(1));
799285612Sdelphij#ifdef DEBUG
800285612Sdelphij			if (debug > 1) {
801285612Sdelphij				printf("pp->day: %d\n", pp->day);
802285612Sdelphij				printf("TOW: %ld\n", tow);
803330141Sdelphij				printf("DAY: %d\n", (mmday & 31));
804285612Sdelphij			}
805285612Sdelphij#endif
806285612Sdelphij			pp->hour = mb(12);
807285612Sdelphij			pp->minute = mb(11);
808285612Sdelphij			pp->second = mb(10);
809285612Sdelphij
810285612Sdelphij
81154359Sroberto#ifdef DEBUG
812285612Sdelphij			if (debug > 1)
813330141Sdelphij				printf("TSIP_decode: unit %d: %02X #%d %02d:%02d:%02d.%09ld %02d/%02d/%04d ",
814330141Sdelphij				       up->unit, mb(0) & 0xff, event, pp->hour, pp->minute, pp->second,
815330141Sdelphij				       pp->nsec, (mmday >> 5), (mmday & 31), pp->year);
81654359Sroberto#endif
817285612Sdelphij			return 1;
818285612Sdelphij			break;
819285612Sdelphij
820285612Sdelphij		    default:
821285612Sdelphij			/* Ignore Packet */
822285612Sdelphij			return 0;
823285612Sdelphij		} /* switch */
824285612Sdelphij	} /* if 8F packets */
825285612Sdelphij
826285612Sdelphij	else if (up->rpt_buf[0] == (u_char)0x42) {
827285612Sdelphij		printf("0x42\n");
828285612Sdelphij		return 0;
829285612Sdelphij	}
830285612Sdelphij	else if (up->rpt_buf[0] == (u_char)0x43) {
831285612Sdelphij		printf("0x43\n");
832285612Sdelphij		return 0;
833285612Sdelphij	}
834285612Sdelphij	else if ((up->rpt_buf[0] == PACKET_41) & (up->type == CLK_THUNDERBOLT)){
835285612Sdelphij		printf("Undocumented 0x41 packet on Thunderbolt\n");
836285612Sdelphij		return 0;
837285612Sdelphij	}
838285612Sdelphij	else if ((up->rpt_buf[0] == PACKET_41A) & (up->type == CLK_ACUTIME)) {
839285612Sdelphij#ifdef DEBUG
840285612Sdelphij		printf("GPS TOW: %ld\n", (long)getlong((u_char *) &mb(0)));
841285612Sdelphij		printf("GPS WN: %d\n", getint((u_char *) &mb(4)));
842285612Sdelphij		printf("GPS UTC-GPS Offser: %ld\n", (long)getlong((u_char *) &mb(6)));
843285612Sdelphij#endif
844285612Sdelphij		return 0;
845285612Sdelphij	}
846285612Sdelphij
847285612Sdelphij	/* Health Status for Acutime Receiver */
848285612Sdelphij	else if ((up->rpt_buf[0] == PACKET_46) & (up->type == CLK_ACUTIME)) {
849285612Sdelphij#ifdef DEBUG
850285612Sdelphij		if (debug > 1)
851285612Sdelphij		/* Status Codes */
852285612Sdelphij			switch (mb(0)) {
853285612Sdelphij			    case 0x00:
854285612Sdelphij				printf ("Doing Position Fixes\n");
855285612Sdelphij				break;
856285612Sdelphij			    case 0x01:
857285612Sdelphij				printf ("Do no have GPS time yet\n");
858285612Sdelphij				break;
859285612Sdelphij			    case 0x03:
860285612Sdelphij				printf ("PDOP is too high\n");
861285612Sdelphij				break;
862285612Sdelphij			    case 0x08:
863285612Sdelphij				printf ("No usable satellites\n");
864285612Sdelphij				break;
865285612Sdelphij			    case 0x09:
866285612Sdelphij				printf ("Only 1 usable satellite\n");
867285612Sdelphij				break;
868285612Sdelphij			    case 0x0A:
869285612Sdelphij				printf ("Only 2 usable satellites\n");
870285612Sdelphij				break;
871285612Sdelphij			    case 0x0B:
872285612Sdelphij				printf ("Only 3 usable satellites\n");
873285612Sdelphij				break;
874285612Sdelphij			    case 0x0C:
875285612Sdelphij				printf("The Chosen satellite is unusable\n");
876285612Sdelphij				break;
877285612Sdelphij			}
878285612Sdelphij#endif
879285612Sdelphij		/* Error Codes */
880285612Sdelphij		if (mb(1) != 0)	{
881285612Sdelphij
88254359Sroberto			refclock_report(peer, CEVNT_BADTIME);
88354359Sroberto			up->polled = -1;
884285612Sdelphij#ifdef DEBUG
885285612Sdelphij			if (debug > 1) {
886285612Sdelphij				if (mb(1) & 0x01)
887285612Sdelphij					printf ("Signal Processor Error, reset unit.\n");
888285612Sdelphij				if (mb(1) & 0x02)
889285612Sdelphij					printf ("Alignment error, channel or chip 1, reset unit.\n");
890285612Sdelphij				if (mb(1) & 0x03)
891285612Sdelphij					printf ("Alignment error, channel or chip 2, reset unit.\n");
892285612Sdelphij				if (mb(1) & 0x04)
893285612Sdelphij					printf ("Antenna feed line fault (open or short)\n");
894285612Sdelphij				if (mb(1) & 0x05)
895285612Sdelphij					printf ("Excessive reference frequency error, refer to packet 0x2D and packet 0x4D documentation for further information\n");
896285612Sdelphij			}
897285612Sdelphij#endif
898285612Sdelphij
899285612Sdelphij		return 0;
90054359Sroberto		}
901285612Sdelphij	}
902285612Sdelphij	else if (up->rpt_buf[0] == 0x54)
903285612Sdelphij		return 0;
90454359Sroberto
905285612Sdelphij	else if (up->rpt_buf[0] == PACKET_6D) {
906285612Sdelphij#ifdef DEBUG
907285612Sdelphij		int sats;
90854359Sroberto
909285612Sdelphij		if ((mb(0) & 0x01) && (mb(0) & 0x02))
910285612Sdelphij			printf("2d Fix Dimension\n");
911285612Sdelphij		if (mb(0) & 0x04)
912285612Sdelphij			printf("3d Fix Dimension\n");
91354359Sroberto
914285612Sdelphij		if (mb(0) & 0x08)
915285612Sdelphij			printf("Fix Mode is MANUAL\n");
916285612Sdelphij		else
917285612Sdelphij			printf("Fix Mode is AUTO\n");
918285612Sdelphij
919285612Sdelphij		sats = mb(0) & 0xF0;
920285612Sdelphij		sats = sats >> 4;
921285612Sdelphij		printf("Tracking %d Satellites\n", sats);
92254359Sroberto#endif
92354359Sroberto		return 0;
924285612Sdelphij	} /* else if not super packet */
92554359Sroberto	refclock_report(peer, CEVNT_BADREPLY);
92654359Sroberto	up->polled = -1;
92754359Sroberto#ifdef DEBUG
92854359Sroberto	printf("TSIP_decode: unit %d: bad packet %02x-%02x event %d len %d\n",
929285612Sdelphij	       up->unit, up->rpt_buf[0] & 0xff, mb(0) & 0xff,
930285612Sdelphij	       event, up->rpt_cnt);
93154359Sroberto#endif
93254359Sroberto	return 0;
93354359Sroberto}
93454359Sroberto
93554359Sroberto/*
93654359Sroberto * palisade__receive - receive data from the serial interface
93754359Sroberto */
93854359Sroberto
93954359Srobertostatic void
94054359Srobertopalisade_receive (
94154359Sroberto	struct peer * peer
94254359Sroberto	)
94354359Sroberto{
94454359Sroberto	struct palisade_unit *up;
94554359Sroberto	struct refclockproc *pp;
94654359Sroberto
94754359Sroberto	/*
94854359Sroberto	 * Initialize pointers and read the timecode and timestamp.
94954359Sroberto	 */
95054359Sroberto	pp = peer->procptr;
951285612Sdelphij	up = pp->unitptr;
95254359Sroberto
95354359Sroberto	if (! TSIP_decode(peer)) return;
95454359Sroberto
95554359Sroberto	if (up->polled <= 0)
956285612Sdelphij		return;   /* no poll pending, already received or timeout */
95754359Sroberto
95854359Sroberto	up->polled = 0;  /* Poll reply received */
95954359Sroberto	pp->lencode = 0; /* clear time code */
96054359Sroberto#ifdef DEBUG
96154359Sroberto	if (debug)
96254359Sroberto		printf(
963285612Sdelphij			"palisade_receive: unit %d: %4d %03d %02d:%02d:%02d.%09ld\n",
96454359Sroberto			up->unit, pp->year, pp->day, pp->hour, pp->minute,
965132451Sroberto			pp->second, pp->nsec);
96654359Sroberto#endif
96754359Sroberto
96854359Sroberto	/*
96954359Sroberto	 * Process the sample
97054359Sroberto	 * Generate timecode: YYYY DoY HH:MM:SS.microsec
97154359Sroberto	 * report and process
97254359Sroberto	 */
97354359Sroberto
974285612Sdelphij	snprintf(pp->a_lastcode, sizeof(pp->a_lastcode),
975285612Sdelphij		 "%4d %03d %02d:%02d:%02d.%09ld",
976285612Sdelphij		 pp->year, pp->day,
977285612Sdelphij		 pp->hour,pp->minute, pp->second, pp->nsec);
97854359Sroberto	pp->lencode = 24;
97954359Sroberto
980285612Sdelphij	if (!refclock_process(pp)) {
98154359Sroberto		refclock_report(peer, CEVNT_BADTIME);
98254359Sroberto
98354359Sroberto#ifdef DEBUG
98454359Sroberto		printf("palisade_receive: unit %d: refclock_process failed!\n",
985285612Sdelphij		       up->unit);
98654359Sroberto#endif
98754359Sroberto		return;
98854359Sroberto	}
98954359Sroberto
99054359Sroberto	record_clock_stats(&peer->srcadr, pp->a_lastcode);
99154359Sroberto
99254359Sroberto#ifdef DEBUG
99354359Sroberto	if (debug)
994285612Sdelphij		printf("palisade_receive: unit %d: %s\n",
995285612Sdelphij		       up->unit, prettydate(&pp->lastrec));
99654359Sroberto#endif
997132451Sroberto	pp->lastref = pp->lastrec;
998285612Sdelphij	refclock_receive(peer);
99954359Sroberto}
100054359Sroberto
100154359Sroberto
100254359Sroberto/*
100354359Sroberto * palisade_poll - called by the transmit procedure
100454359Sroberto *
100554359Sroberto */
100654359Srobertostatic void
100754359Srobertopalisade_poll (
100854359Sroberto	int unit,
100954359Sroberto	struct peer *peer
101054359Sroberto	)
101154359Sroberto{
101254359Sroberto	struct palisade_unit *up;
101354359Sroberto	struct refclockproc *pp;
101454359Sroberto
101554359Sroberto	pp = peer->procptr;
1016285612Sdelphij	up = pp->unitptr;
101754359Sroberto
101854359Sroberto	pp->polls++;
101954359Sroberto	if (up->polled > 0) /* last reply never arrived or error */
1020285612Sdelphij		refclock_report(peer, CEVNT_TIMEOUT);
102154359Sroberto
102254359Sroberto	up->polled = 2; /* synchronous packet + 1 event */
102354359Sroberto
102454359Sroberto#ifdef DEBUG
102554359Sroberto	if (debug)
1026285612Sdelphij		printf("palisade_poll: unit %d: polling %s\n", unit,
1027285612Sdelphij		       (pp->sloppyclockflag & CLK_FLAG2) ?
1028285612Sdelphij		       "synchronous packet" : "event");
102954359Sroberto#endif
103054359Sroberto
103154359Sroberto	if (pp->sloppyclockflag & CLK_FLAG2)
1032285612Sdelphij		return;  /* using synchronous packet input */
103354359Sroberto
1034132451Sroberto	if(up->type == CLK_PRAECIS) {
1035132451Sroberto		if(write(peer->procptr->io.fd,"SPSTAT\r\n",8) < 0)
1036132451Sroberto			msyslog(LOG_ERR, "Palisade(%d) write: %m:",unit);
1037132451Sroberto		else {
1038132451Sroberto			praecis_msg = 1;
1039132451Sroberto			return;
1040132451Sroberto		}
1041132451Sroberto	}
1042132451Sroberto
104354359Sroberto	if (HW_poll(pp) < 0)
1044285612Sdelphij		refclock_report(peer, CEVNT_FAULT);
104554359Sroberto}
104654359Sroberto
1047132451Srobertostatic void
1048285612Sdelphijpraecis_parse (
1049285612Sdelphij	struct recvbuf *rbufp,
1050285612Sdelphij	struct peer *peer
1051285612Sdelphij	)
1052132451Sroberto{
1053132451Sroberto	static char buf[100];
1054132451Sroberto	static int p = 0;
1055132451Sroberto	struct refclockproc *pp;
105654359Sroberto
1057132451Sroberto	pp = peer->procptr;
1058132451Sroberto
1059132451Sroberto	memcpy(buf+p,rbufp->recv_space.X_recv_buffer, rbufp->recv_length);
1060132451Sroberto	p += rbufp->recv_length;
1061132451Sroberto
1062132451Sroberto	if(buf[p-2] == '\r' && buf[p-1] == '\n') {
1063132451Sroberto		buf[p-2] = '\0';
1064132451Sroberto		record_clock_stats(&peer->srcadr, buf);
1065132451Sroberto
1066132451Sroberto		p = 0;
1067132451Sroberto		praecis_msg = 0;
1068132451Sroberto
1069132451Sroberto		if (HW_poll(pp) < 0)
1070132451Sroberto			refclock_report(peer, CEVNT_FAULT);
1071132451Sroberto
1072132451Sroberto	}
1073132451Sroberto}
1074132451Sroberto
107554359Srobertostatic void
107654359Srobertopalisade_io (
107754359Sroberto	struct recvbuf *rbufp
107854359Sroberto	)
107954359Sroberto{
108054359Sroberto	/*
108154359Sroberto	 * Initialize pointers and read the timecode and timestamp.
108254359Sroberto	 */
108354359Sroberto	struct palisade_unit *up;
108454359Sroberto	struct refclockproc *pp;
108554359Sroberto	struct peer *peer;
108654359Sroberto
108754359Sroberto	char * c, * d;
108854359Sroberto
1089285612Sdelphij	peer = rbufp->recv_peer;
109054359Sroberto	pp = peer->procptr;
1091285612Sdelphij	up = pp->unitptr;
109254359Sroberto
1093132451Sroberto	if(up->type == CLK_PRAECIS) {
1094132451Sroberto		if(praecis_msg) {
1095132451Sroberto			praecis_parse(rbufp,peer);
1096132451Sroberto			return;
1097132451Sroberto		}
1098132451Sroberto	}
1099132451Sroberto
110054359Sroberto	c = (char *) &rbufp->recv_space;
110154359Sroberto	d = c + rbufp->recv_length;
110254359Sroberto
110354359Sroberto	while (c != d) {
110454359Sroberto
110554359Sroberto		/* Build time packet */
110654359Sroberto		switch (up->rpt_status) {
110754359Sroberto
110854359Sroberto		    case TSIP_PARSED_DLE_1:
110954359Sroberto			switch (*c)
111054359Sroberto			{
111154359Sroberto			    case 0:
111254359Sroberto			    case DLE:
111354359Sroberto			    case ETX:
111454359Sroberto				up->rpt_status = TSIP_PARSED_EMPTY;
111554359Sroberto				break;
111654359Sroberto
111754359Sroberto			    default:
111854359Sroberto				up->rpt_status = TSIP_PARSED_DATA;
111954359Sroberto				/* save packet ID */
112054359Sroberto				up->rpt_buf[0] = *c;
112154359Sroberto				break;
112254359Sroberto			}
112354359Sroberto			break;
112454359Sroberto
112554359Sroberto		    case TSIP_PARSED_DATA:
112654359Sroberto			if (*c == DLE)
1127285612Sdelphij				up->rpt_status = TSIP_PARSED_DLE_2;
112854359Sroberto			else
1129285612Sdelphij				mb(up->rpt_cnt++) = *c;
113054359Sroberto			break;
113154359Sroberto
113254359Sroberto		    case TSIP_PARSED_DLE_2:
113354359Sroberto			if (*c == DLE) {
113454359Sroberto				up->rpt_status = TSIP_PARSED_DATA;
113554359Sroberto				mb(up->rpt_cnt++) =
1136285612Sdelphij				    *c;
1137285612Sdelphij			}
113854359Sroberto			else if (*c == ETX)
1139285612Sdelphij				up->rpt_status = TSIP_PARSED_FULL;
114054359Sroberto			else 	{
1141285612Sdelphij				/* error: start new report packet */
114254359Sroberto				up->rpt_status = TSIP_PARSED_DLE_1;
114354359Sroberto				up->rpt_buf[0] = *c;
114454359Sroberto			}
114554359Sroberto			break;
114654359Sroberto
114754359Sroberto		    case TSIP_PARSED_FULL:
114854359Sroberto		    case TSIP_PARSED_EMPTY:
114954359Sroberto		    default:
1150285612Sdelphij			if ( *c != DLE)
1151285612Sdelphij				up->rpt_status = TSIP_PARSED_EMPTY;
1152285612Sdelphij			else
1153285612Sdelphij				up->rpt_status = TSIP_PARSED_DLE_1;
1154285612Sdelphij			break;
115554359Sroberto		}
115654359Sroberto
115754359Sroberto		c++;
115854359Sroberto
115954359Sroberto		if (up->rpt_status == TSIP_PARSED_DLE_1) {
1160285612Sdelphij			up->rpt_cnt = 0;
116154359Sroberto			if (pp->sloppyclockflag & CLK_FLAG2)
1162285612Sdelphij				/* stamp it */
1163285612Sdelphij				get_systime(&pp->lastrec);
116454359Sroberto		}
116554359Sroberto		else if (up->rpt_status == TSIP_PARSED_EMPTY)
1166285612Sdelphij			up->rpt_cnt = 0;
116754359Sroberto
116854359Sroberto		else if (up->rpt_cnt > BMAX)
116954359Sroberto			up->rpt_status =TSIP_PARSED_EMPTY;
117054359Sroberto
117154359Sroberto		if (up->rpt_status == TSIP_PARSED_FULL)
117254359Sroberto			palisade_receive(peer);
117354359Sroberto
117454359Sroberto	} /* while chars in buffer */
117554359Sroberto}
117654359Sroberto
117754359Sroberto
117854359Sroberto/*
117954359Sroberto * Trigger the Palisade's event input, which is driven off the RTS
118054359Sroberto *
118154359Sroberto * Take a system time stamp to match the GPS time stamp.
118254359Sroberto *
118354359Sroberto */
118454359Srobertolong
118554359SrobertoHW_poll (
118654359Sroberto	struct refclockproc * pp 	/* pointer to unit structure */
118754359Sroberto	)
118854359Sroberto{
118954359Sroberto	int x;	/* state before & after RTS set */
119054359Sroberto	struct palisade_unit *up;
119154359Sroberto
1192285612Sdelphij	up = pp->unitptr;
119354359Sroberto
119454359Sroberto	/* read the current status, so we put things back right */
119554359Sroberto	if (ioctl(pp->io.fd, TIOCMGET, &x) < 0) {
1196285612Sdelphij		DPRINTF(1, ("Palisade HW_poll: unit %d: GET %m\n",
1197285612Sdelphij			up->unit));
119854359Sroberto		msyslog(LOG_ERR, "Palisade(%d) HW_poll: ioctl(fd,GET): %m",
119954359Sroberto			up->unit);
120054359Sroberto		return -1;
120154359Sroberto	}
120254359Sroberto
120354359Sroberto	x |= TIOCM_RTS;        /* turn on RTS  */
120454359Sroberto
120554359Sroberto	/* Edge trigger */
1206285612Sdelphij	if (up->type == CLK_ACUTIME)
1207285612Sdelphij		write (pp->io.fd, "", 1);
1208285612Sdelphij
120954359Sroberto	if (ioctl(pp->io.fd, TIOCMSET, &x) < 0) {
121054359Sroberto#ifdef DEBUG
1211285612Sdelphij		if (debug)
1212285612Sdelphij			printf("Palisade HW_poll: unit %d: SET \n", up->unit);
121354359Sroberto#endif
121454359Sroberto		msyslog(LOG_ERR,
121554359Sroberto			"Palisade(%d) HW_poll: ioctl(fd, SET, RTS_on): %m",
121654359Sroberto			up->unit);
121754359Sroberto		return -1;
121854359Sroberto	}
121954359Sroberto
122054359Sroberto	x &= ~TIOCM_RTS;        /* turn off RTS  */
122154359Sroberto
122254359Sroberto	/* poll timestamp */
122354359Sroberto	get_systime(&pp->lastrec);
122454359Sroberto
122554359Sroberto	if (ioctl(pp->io.fd, TIOCMSET, &x) == -1) {
122654359Sroberto#ifdef DEBUG
1227285612Sdelphij		if (debug)
1228285612Sdelphij			printf("Palisade HW_poll: unit %d: UNSET \n", up->unit);
122954359Sroberto#endif
123054359Sroberto		msyslog(LOG_ERR,
123154359Sroberto			"Palisade(%d) HW_poll: ioctl(fd, UNSET, RTS_off): %m",
123254359Sroberto			up->unit);
123354359Sroberto		return -1;
123454359Sroberto	}
123554359Sroberto
123654359Sroberto	return 0;
123754359Sroberto}
123854359Sroberto
123954359Sroberto/*
1240285612Sdelphij * copy/swap a big-endian palisade double into a host double
124154359Sroberto */
1242285612Sdelphijstatic double
1243285612Sdelphijgetdbl (
124454359Sroberto	u_char *bp
124554359Sroberto	)
124654359Sroberto{
1247285612Sdelphij#ifdef WORDS_BIGENDIAN
1248285612Sdelphij	double out;
1249285612Sdelphij
1250285612Sdelphij	memcpy(&out, bp, sizeof(out));
1251285612Sdelphij	return out;
125254359Sroberto#else
1253285612Sdelphij	union {
1254285612Sdelphij		u_char ch[8];
1255285612Sdelphij		u_int32 u32[2];
1256285612Sdelphij	} ui;
1257285612Sdelphij
1258285612Sdelphij	union {
1259285612Sdelphij		double out;
1260285612Sdelphij		u_int32 u32[2];
1261285612Sdelphij	} uo;
1262285612Sdelphij
1263285612Sdelphij	memcpy(ui.ch, bp, sizeof(ui.ch));
1264285612Sdelphij	/* least-significant 32 bits of double from swapped bp[4] to bp[7] */
1265285612Sdelphij	uo.u32[0] = ntohl(ui.u32[1]);
1266285612Sdelphij	/* most-significant 32 bits from swapped bp[0] to bp[3] */
1267285612Sdelphij	uo.u32[1] = ntohl(ui.u32[0]);
1268285612Sdelphij
1269285612Sdelphij	return uo.out;
1270285612Sdelphij#endif
127154359Sroberto}
127254359Sroberto
127354359Sroberto/*
1274285612Sdelphij * copy/swap a big-endian palisade short into a host short
127554359Sroberto */
1276285612Sdelphijstatic short
1277285612Sdelphijgetint (
127854359Sroberto	u_char *bp
127954359Sroberto	)
128054359Sroberto{
1281285612Sdelphij	u_short us;
1282285612Sdelphij
1283285612Sdelphij	memcpy(&us, bp, sizeof(us));
1284285612Sdelphij	return (short)ntohs(us);
128554359Sroberto}
128654359Sroberto
128754359Sroberto/*
1288285612Sdelphij * copy/swap a big-endian palisade 32-bit int into a host 32-bit int
128954359Sroberto */
1290285612Sdelphijstatic int32
1291285612Sdelphijgetlong(
129254359Sroberto	u_char *bp
129354359Sroberto	)
129454359Sroberto{
1295285612Sdelphij	u_int32 u32;
1296285612Sdelphij
1297285612Sdelphij	memcpy(&u32, bp, sizeof(u32));
1298285612Sdelphij	return (int32)(u_int32)ntohl(u32);
129954359Sroberto}
130054359Sroberto
1301285612Sdelphij#else	/* REFCLOCK && CLOCK_PALISADE*/
1302285612Sdelphijint refclock_palisade_c_notempty;
1303285612Sdelphij#endif
1304