refclock_palisade.c revision 330106
1/*
2 * This software was developed by the Software and Component Technologies
3 * group of Trimble Navigation, Ltd.
4 *
5 * Copyright (c) 1997, 1998, 1999, 2000  Trimble Navigation Ltd.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 *    must display the following acknowledgement:
18 *    This product includes software developed by Trimble Navigation, Ltd.
19 * 4. The name of Trimble Navigation Ltd. may not be used to endorse or
20 *    promote products derived from this software without specific prior
21 *    written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY TRIMBLE NAVIGATION LTD. ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED.  IN NO EVENT SHALL TRIMBLE NAVIGATION LTD. BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 */
35
36/*
37 * refclock_palisade - clock driver for the Trimble Palisade GPS
38 * timing receiver
39 *
40 * For detailed information on this program, please refer to the html
41 * Refclock 29 page accompanying the NTP distribution.
42 *
43 * for questions / bugs / comments, contact:
44 * sven_dietrich@trimble.com
45 *
46 * Sven-Thorsten Dietrich
47 * 645 North Mary Avenue
48 * Post Office Box 3642
49 * Sunnyvale, CA 94088-3642
50 *
51 * Version 2.45; July 14, 1999
52 *
53 *
54 *
55 * 31/03/06: Added support for Thunderbolt GPS Disciplined Clock.
56 *	     Contact: Fernando Pablo Hauscarriaga
57 * 	     E-mail: fernandoph@iar.unlp.edu.ar
58 * 	     Home page: www.iar.unlp.edu.ar/~fernandoph
59 *		  Instituto Argentino de Radioastronomia
60 *			    www.iar.unlp.edu.ar
61 *
62 * 14/01/07: Conditinal compilation for Thunderbolt support no longer needed
63 *	     now we use mode 2 for decode thunderbolt packets.
64 *	     Fernando P. Hauscarriaga
65 *
66 * 30/08/09: Added support for Trimble Acutime Gold Receiver.
67 *	     Fernando P. Hauscarriaga (fernandoph@iar.unlp.edu.ar)
68 */
69
70#ifdef HAVE_CONFIG_H
71# include "config.h"
72#endif
73
74#if defined(REFCLOCK) && defined(CLOCK_PALISADE)
75
76#ifdef SYS_WINNT
77extern int async_write(int, const void *, unsigned int);
78#undef write
79#define write(fd, data, octets)	async_write(fd, data, octets)
80#endif
81
82#include "refclock_palisade.h"
83
84#ifdef DEBUG
85const char * Tracking_Status[15][15] = {
86	{ "Doing Fixes\0" }, { "Good 1SV\0" }, { "Approx. 1SV\0" },
87	{"Need Time\0" }, { "Need INIT\0" }, { "PDOP too High\0" },
88	{ "Bad 1SV\0" }, { "0SV Usable\0" }, { "1SV Usable\0" },
89	{ "2SV Usable\0" }, { "3SV Usable\0" }, { "No Integrity\0" },
90	{ "Diff Corr\0" }, { "Overdet Clock\0" }, { "Invalid\0" } };
91#endif
92
93/*
94 * Transfer vector
95 */
96struct refclock refclock_palisade = {
97	palisade_start,		/* start up driver */
98	palisade_shutdown,	/* shut down driver */
99	palisade_poll,		/* transmit poll message */
100	noentry,		/* not used  */
101	noentry,		/* initialize driver (not used) */
102	noentry,		/* not used */
103	NOFLAGS			/* not used */
104};
105
106static int decode_date(struct refclockproc *pp, const char *cp);
107
108/* Extract the clock type from the mode setting */
109#define CLK_TYPE(x) ((int)(((x)->ttl) & 0x7F))
110
111/* Supported clock types */
112#define CLK_TRIMBLE	0	/* Trimble Palisade */
113#define CLK_PRAECIS	1	/* Endrun Technologies Praecis */
114#define CLK_THUNDERBOLT	2	/* Trimble Thunderbolt GPS Receiver */
115#define CLK_ACUTIME     3	/* Trimble Acutime Gold */
116#define CLK_ACUTIMEB    4	/* Trimble Actutime Gold Port B */
117
118int praecis_msg;
119static void praecis_parse(struct recvbuf *rbufp, struct peer *peer);
120
121/* These routines are for sending packets to the Thunderbolt receiver
122 * They are taken from Markus Prosch
123 */
124
125#ifdef PALISADE_SENDCMD_RESURRECTED
126/*
127 * sendcmd - Build data packet for sending
128 */
129static void
130sendcmd (
131	struct packettx *buffer,
132	int c
133	)
134{
135	*buffer->data = DLE;
136	*(buffer->data + 1) = (unsigned char)c;
137	buffer->size = 2;
138}
139#endif	/* PALISADE_SENDCMD_RESURRECTED */
140
141/*
142 * sendsupercmd - Build super data packet for sending
143 */
144static void
145sendsupercmd (
146	struct packettx *buffer,
147	int c1,
148	int c2
149	)
150{
151	*buffer->data = DLE;
152	*(buffer->data + 1) = (unsigned char)c1;
153	*(buffer->data + 2) = (unsigned char)c2;
154	buffer->size = 3;
155}
156
157/*
158 * sendbyte -
159 */
160static void
161sendbyte (
162	struct packettx *buffer,
163	int b
164	)
165{
166	if (b == DLE)
167		*(buffer->data+buffer->size++) = DLE;
168	*(buffer->data+buffer->size++) = (unsigned char)b;
169}
170
171/*
172 * sendint -
173 */
174static void
175sendint (
176	struct packettx *buffer,
177	int a
178	)
179{
180	sendbyte(buffer, (unsigned char)((a>>8) & 0xff));
181	sendbyte(buffer, (unsigned char)(a & 0xff));
182}
183
184/*
185 * sendetx - Send packet or super packet to the device
186 */
187static int
188sendetx (
189	struct packettx *buffer,
190	int fd
191	)
192{
193	int result;
194
195	*(buffer->data+buffer->size++) = DLE;
196	*(buffer->data+buffer->size++) = ETX;
197	result = write(fd, buffer->data, (unsigned long)buffer->size);
198
199	if (result != -1)
200		return (result);
201	else
202		return (-1);
203}
204
205/*
206 * init_thunderbolt - Prepares Thunderbolt receiver to be used with
207 *		      NTP (also taken from Markus Prosch).
208 */
209static void
210init_thunderbolt (
211	int fd
212	)
213{
214	struct packettx tx;
215
216	tx.size = 0;
217	tx.data = (u_char *) emalloc(100);
218
219	/* set UTC time */
220	sendsupercmd (&tx, 0x8E, 0xA2);
221	sendbyte     (&tx, 0x3);
222	sendetx      (&tx, fd);
223
224	/* activate packets 0x8F-AB and 0x8F-AC */
225	sendsupercmd (&tx, 0x8E, 0xA5);
226	sendint      (&tx, 0x5);
227	sendetx      (&tx, fd);
228
229	free(tx.data);
230}
231
232/*
233 * init_acutime - Prepares Acutime Receiver to be used with NTP
234 */
235static void
236init_acutime (
237	int fd
238	)
239{
240	/* Disable all outputs, Enable Event-Polling on PortA so
241	   we can ask for time packets */
242	struct packettx tx;
243
244	tx.size = 0;
245	tx.data = (u_char *) emalloc(100);
246
247	sendsupercmd(&tx, 0x8E, 0xA5);
248	sendbyte(&tx, 0x02);
249	sendbyte(&tx, 0x00);
250	sendbyte(&tx, 0x00);
251	sendbyte(&tx, 0x00);
252	sendetx(&tx, fd);
253
254	free(tx.data);
255}
256
257/*
258 * palisade_start - open the devices and initialize data for processing
259 */
260static int
261palisade_start (
262	int unit,
263	struct peer *peer
264	)
265{
266	struct palisade_unit *up;
267	struct refclockproc *pp;
268	int fd;
269	char gpsdev[20];
270	struct termios tio;
271
272	snprintf(gpsdev, sizeof(gpsdev), DEVICE, unit);
273
274	/*
275	 * Open serial port.
276	 */
277	fd = refclock_open(gpsdev, SPEED232, LDISC_RAW);
278	if (fd <= 0) {
279#ifdef DEBUG
280		printf("Palisade(%d) start: open %s failed\n", unit, gpsdev);
281#endif
282		return 0;
283	}
284
285	msyslog(LOG_NOTICE, "Palisade(%d) fd: %d dev: %s", unit, fd,
286		gpsdev);
287
288	if (tcgetattr(fd, &tio) < 0) {
289		msyslog(LOG_ERR,
290			"Palisade(%d) tcgetattr(fd, &tio): %m",unit);
291#ifdef DEBUG
292		printf("Palisade(%d) tcgetattr(fd, &tio)\n",unit);
293#endif
294		close(fd);
295		return (0);
296	}
297
298	tio.c_cflag |= (PARENB|PARODD);
299	tio.c_iflag &= ~ICRNL;
300
301	/*
302	 * Allocate and initialize unit structure
303	 */
304	up = emalloc_zero(sizeof(*up));
305
306	up->type = CLK_TYPE(peer);
307	switch (up->type) {
308	    case CLK_TRIMBLE:
309		/* Normal mode, do nothing */
310		break;
311	    case CLK_PRAECIS:
312		msyslog(LOG_NOTICE, "Palisade(%d) Praecis mode enabled"
313			,unit);
314		break;
315	    case CLK_THUNDERBOLT:
316		msyslog(LOG_NOTICE, "Palisade(%d) Thunderbolt mode enabled"
317			,unit);
318		tio.c_cflag = (CS8|CLOCAL|CREAD);
319		break;
320	    case CLK_ACUTIME:
321		msyslog(LOG_NOTICE, "Palisade(%d) Acutime Gold mode enabled"
322			,unit);
323		break;
324	    default:
325		msyslog(LOG_NOTICE, "Palisade(%d) mode unknown",unit);
326		break;
327	}
328	if (tcsetattr(fd, TCSANOW, &tio) == -1) {
329		msyslog(LOG_ERR, "Palisade(%d) tcsetattr(fd, &tio): %m",unit);
330#ifdef DEBUG
331		printf("Palisade(%d) tcsetattr(fd, &tio)\n",unit);
332#endif
333		close(fd);
334		free(up);
335		return 0;
336	}
337
338	pp = peer->procptr;
339	pp->io.clock_recv = palisade_io;
340	pp->io.srcclock = peer;
341	pp->io.datalen = 0;
342	pp->io.fd = fd;
343	if (!io_addclock(&pp->io)) {
344#ifdef DEBUG
345		printf("Palisade(%d) io_addclock\n",unit);
346#endif
347		close(fd);
348		pp->io.fd = -1;
349		free(up);
350		return (0);
351	}
352
353	/*
354	 * Initialize miscellaneous variables
355	 */
356	pp->unitptr = up;
357	pp->clockdesc = DESCRIPTION;
358
359	peer->precision = PRECISION;
360	peer->sstclktype = CTL_SST_TS_UHF;
361	peer->minpoll = TRMB_MINPOLL;
362	peer->maxpoll = TRMB_MAXPOLL;
363	memcpy((char *)&pp->refid, REFID, 4);
364
365	up->leap_status = 0;
366	up->unit = (short) unit;
367	up->rpt_status = TSIP_PARSED_EMPTY;
368	up->rpt_cnt = 0;
369
370	if (up->type == CLK_THUNDERBOLT)
371		init_thunderbolt(fd);
372	if (up->type == CLK_ACUTIME)
373		init_acutime(fd);
374
375	return 1;
376}
377
378
379/*
380 * palisade_shutdown - shut down the clock
381 */
382static void
383palisade_shutdown (
384	int unit,
385	struct peer *peer
386	)
387{
388	struct palisade_unit *up;
389	struct refclockproc *pp;
390	pp = peer->procptr;
391	up = pp->unitptr;
392	if (-1 != pp->io.fd)
393		io_closeclock(&pp->io);
394	if (NULL != up)
395		free(up);
396}
397
398
399/*
400 * unpack helpers
401 */
402
403static inline uint8_t
404get_u8(
405	const char *cp)
406{
407	return ((const u_char*)cp)[0];
408}
409
410static inline uint16_t
411get_u16(
412	const char *cp)
413{
414	return ((uint16_t)get_u8(cp) << 8) | get_u8(cp + 1);
415}
416
417/*
418 * unpack & fix date (the receiver provides a valid time for 1024 weeks
419 * after 1997-12-14 and therefore folds back in 2017, 2037,...)
420 *
421 * Returns -1 on error, day-of-month + (month * 32) othertwise.
422 */
423int
424decode_date(
425	struct refclockproc *pp,
426	const char          *cp)
427{
428	static int32_t  s_baseday = 0;
429
430	struct calendar jd;
431	int32_t         rd;
432
433	if (0 == s_baseday) {
434		if (!ntpcal_get_build_date(&jd)) {
435			jd.year     = 2015;
436			jd.month    = 1;
437			jd.monthday = 1;
438		}
439		s_baseday = ntpcal_date_to_rd(&jd);
440	}
441
442	/* get date fields and convert to RDN */
443	jd.monthday = get_u8 (  cp  );
444	jd.month    = get_u8 (cp + 1);
445	jd.year     = get_u16(cp + 2);
446	rd = ntpcal_date_to_rd(&jd);
447
448	/* for the paranoid: do reverse calculation and cross-check */
449	ntpcal_rd_to_date(&jd, rd);
450	if ((jd.monthday != get_u8 (  cp  )) ||
451	    (jd.month    != get_u8 (cp + 1)) ||
452	    (jd.year     != get_u16(cp + 2))  )
453		return - 1;
454
455	/* calculate cycle shift to base day and calculate re-folded
456	 * date
457	 *
458	 * One could do a proper modulo calculation here, but a counting
459	 * loop is probably faster for the next few rollovers...
460	 */
461	while (rd < s_baseday)
462		rd += 7*1024;
463	ntpcal_rd_to_date(&jd, rd);
464
465	/* fill refclock structure & indicate success */
466	pp->day  = jd.yearday;
467	pp->year = jd.year;
468	return ((int)jd.month << 5) | jd.monthday;
469}
470
471
472/*
473 * TSIP_decode - decode the TSIP data packets
474 */
475int
476TSIP_decode (
477	struct peer *peer
478	)
479{
480	int st;
481	long   secint;
482	double secs;
483	double secfrac;
484	unsigned short event = 0;
485	int mmday;
486
487	struct palisade_unit *up;
488	struct refclockproc *pp;
489
490	pp = peer->procptr;
491	up = pp->unitptr;
492
493	/*
494	 * Check the time packet, decode its contents.
495	 * If the timecode has invalid length or is not in
496	 * proper format, declare bad format and exit.
497	 */
498
499	if ((up->type != CLK_THUNDERBOLT) & (up->type != CLK_ACUTIME)){
500		if ((up->rpt_buf[0] == (char) 0x41) ||
501		    (up->rpt_buf[0] == (char) 0x46) ||
502		    (up->rpt_buf[0] == (char) 0x54) ||
503		    (up->rpt_buf[0] == (char) 0x4B) ||
504		    (up->rpt_buf[0] == (char) 0x6D)) {
505
506			/* standard time packet - GPS time and GPS week number */
507#ifdef DEBUG
508			printf("Palisade Port B packets detected. Connect to Port A\n");
509#endif
510
511			return 0;
512		}
513	}
514
515	/*
516	 * We cast both to u_char to as 0x8f uses the sign bit on a char
517	 */
518	if ((u_char) up->rpt_buf[0] == (u_char) 0x8f) {
519		/*
520		 * Superpackets
521		 */
522		event = (unsigned short) (getint((u_char *) &mb(1)) & 0xffff);
523		if (!((pp->sloppyclockflag & CLK_FLAG2) || event))
524			/* Ignore Packet */
525			return 0;
526
527		switch (mb(0) & 0xff) {
528			int GPS_UTC_Offset;
529			long tow;
530
531		    case PACKET_8F0B:
532
533			if (up->polled <= 0)
534				return 0;
535
536			if (up->rpt_cnt != LENCODE_8F0B)  /* check length */
537				break;
538
539#ifdef DEBUG
540			if (debug > 1) {
541				int ts;
542				double lat, lon, alt;
543				lat = getdbl((u_char *) &mb(42)) * R2D;
544				lon = getdbl((u_char *) &mb(50)) * R2D;
545				alt = getdbl((u_char *) &mb(58));
546
547				printf("TSIP_decode: unit %d: Latitude: %03.4f Longitude: %03.4f Alt: %05.2f m\n",
548				       up->unit, lat,lon,alt);
549				printf("TSIP_decode: unit %d: Sats:",
550				       up->unit);
551				for (st = 66, ts = 0; st <= 73; st++)
552					if (mb(st)) {
553						if (mb(st) > 0) ts++;
554						printf(" %02d", mb(st));
555					}
556				printf(" : Tracking %d\n", ts);
557			}
558#endif
559
560			GPS_UTC_Offset = getint((u_char *) &mb(16));
561			if (GPS_UTC_Offset == 0) { /* Check UTC offset */
562#ifdef DEBUG
563				printf("TSIP_decode: UTC Offset Unknown\n");
564#endif
565				break;
566			}
567
568			secs = getdbl((u_char *) &mb(3));
569			secint = (long) secs;
570			secfrac = secs - secint; /* 0.0 <= secfrac < 1.0 */
571
572			pp->nsec = (long) (secfrac * 1000000000);
573
574			secint %= 86400;    /* Only care about today */
575			pp->hour = secint / 3600;
576			secint %= 3600;
577			pp->minute = secint / 60;
578			secint %= 60;
579			pp->second = secint % 60;
580
581			mmday = decode_date(pp, &mb(11));
582			if (mmday < 0)
583				break;
584
585#ifdef DEBUG
586			if (debug > 1)
587				printf("TSIP_decode: unit %d: %02X #%d %02d:%02d:%02d.%09ld %02d/%02d/%04d UTC %02d\n",
588				       up->unit, mb(0) & 0xff, event, pp->hour, pp->minute,
589				       pp->second, pp->nsec, (mmday >> 5), (mmday & 31), pp->year, GPS_UTC_Offset);
590#endif
591			/* Only use this packet when no
592			 * 8F-AD's are being received
593			 */
594
595			if (up->leap_status) {
596				up->leap_status = 0;
597				return 0;
598			}
599
600			return 2;
601			break;
602
603		    case PACKET_NTP:
604			/* Palisade-NTP Packet */
605
606			if (up->rpt_cnt != LENCODE_NTP) /* check length */
607				break;
608
609			up->leap_status = mb(19);
610
611			if (up->polled  <= 0)
612				return 0;
613
614			/* Check Tracking Status */
615			st = mb(18);
616			if (st < 0 || st > 14)
617				st = 14;
618			if ((st >= 2 && st <= 7) || st == 11 || st == 12) {
619#ifdef DEBUG
620				printf("TSIP_decode: Not Tracking Sats : %s\n",
621				       *Tracking_Status[st]);
622#endif
623				refclock_report(peer, CEVNT_BADTIME);
624				up->polled = -1;
625				return 0;
626				break;
627			}
628
629			mmday = decode_date(pp, &mb(14));
630			if (mmday < 0)
631				break;
632			up->month  = (mmday >> 5);  /* Save for LEAP check */
633
634			if ( (up->leap_status & PALISADE_LEAP_PENDING) &&
635			/* Avoid early announce: https://bugs.ntp.org/2773 */
636				(6 == up->month || 12 == up->month) ) {
637				if (up->leap_status & PALISADE_UTC_TIME)
638					pp->leap = LEAP_ADDSECOND;
639				else
640					pp->leap = LEAP_DELSECOND;
641			}
642			else if (up->leap_status)
643				pp->leap = LEAP_NOWARNING;
644
645			else {  /* UTC flag is not set:
646				 * Receiver may have been reset, and lost
647				 * its UTC almanac data */
648				pp->leap = LEAP_NOTINSYNC;
649#ifdef DEBUG
650				printf("TSIP_decode: UTC Almanac unavailable: %d\n",
651				       mb(19));
652#endif
653				refclock_report(peer, CEVNT_BADTIME);
654				up->polled = -1;
655				return 0;
656			}
657
658			pp->nsec = (long) (getdbl((u_char *) &mb(3))
659					   * 1000000000);
660
661			pp->hour = mb(11);
662			pp->minute = mb(12);
663			pp->second = mb(13);
664
665#ifdef DEBUG
666			if (debug > 1)
667				printf("TSIP_decode: unit %d: %02X #%d %02d:%02d:%02d.%09ld %02d/%02d/%04d UTC %02x %s\n",
668				       up->unit, mb(0) & 0xff, event, pp->hour, pp->minute,
669				       pp->second, pp->nsec, (mmday >> 5), (mmday & 31), pp->year,
670				       mb(19), *Tracking_Status[st]);
671#endif
672			return 1;
673			break;
674
675		    case PACKET_8FAC:
676			if (up->polled <= 0)
677				return 0;
678
679			if (up->rpt_cnt != LENCODE_8FAC)/* check length */
680				break;
681
682#ifdef DEBUG
683			if (debug > 1) {
684				double lat, lon, alt;
685				lat = getdbl((u_char *) &mb(36)) * R2D;
686				lon = getdbl((u_char *) &mb(44)) * R2D;
687				alt = getdbl((u_char *) &mb(52));
688
689				printf("TSIP_decode: unit %d: Latitude: %03.4f Longitude: %03.4f Alt: %05.2f m\n",
690				       up->unit, lat,lon,alt);
691				printf("TSIP_decode: unit %d\n", up->unit);
692			}
693#endif
694			if ( (getint((u_char *) &mb(10)) & 0x80) &&
695			/* Avoid early announce: https://bugs.ntp.org/2773 */
696			    (6 == up->month || 12 == up->month) )
697				pp->leap = LEAP_ADDSECOND;  /* we ASSUME addsecond */
698			else
699				pp->leap = LEAP_NOWARNING;
700
701#ifdef DEBUG
702			if (debug > 1)
703				printf("TSIP_decode: unit %d: 0x%02x leap %d\n",
704				       up->unit, mb(0) & 0xff, pp->leap);
705			if (debug > 1) {
706				printf("Receiver MODE: 0x%02X\n", (u_char)mb(1));
707				if (mb(1) == 0x00)
708					printf("                AUTOMATIC\n");
709				if (mb(1) == 0x01)
710					printf("                SINGLE SATELLITE\n");
711				if (mb(1) == 0x03)
712					printf("                HORIZONTAL(2D)\n");
713				if (mb(1) == 0x04)
714					printf("                FULL POSITION(3D)\n");
715				if (mb(1) == 0x05)
716					printf("                DGPR REFERENCE\n");
717				if (mb(1) == 0x06)
718					printf("                CLOCK HOLD(2D)\n");
719				if (mb(1) == 0x07)
720					printf("                OVERDETERMINED CLOCK\n");
721
722				printf("\n** Disciplining MODE 0x%02X:\n", (u_char)mb(2));
723				if (mb(2) == 0x00)
724					printf("                NORMAL\n");
725				if (mb(2) == 0x01)
726					printf("                POWER-UP\n");
727				if (mb(2) == 0x02)
728					printf("                AUTO HOLDOVER\n");
729				if (mb(2) == 0x03)
730					printf("                MANUAL HOLDOVER\n");
731				if (mb(2) == 0x04)
732					printf("                RECOVERY\n");
733				if (mb(2) == 0x06)
734					printf("                DISCIPLINING DISABLED\n");
735			}
736#endif
737			return 0;
738			break;
739
740		    case PACKET_8FAB:
741			/* Thunderbolt Primary Timing Packet */
742
743			if (up->rpt_cnt != LENCODE_8FAB) /* check length */
744				break;
745
746			if (up->polled  <= 0)
747				return 0;
748
749			GPS_UTC_Offset = getint((u_char *) &mb(7));
750
751			if (GPS_UTC_Offset == 0){ /* Check UTC Offset */
752#ifdef DEBUG
753				printf("TSIP_decode: UTC Offset Unknown\n");
754#endif
755				break;
756			}
757
758
759			if ((mb(9) & 0x1d) == 0x0) {
760				/* if we know the GPS time and the UTC offset,
761				   we expect UTC timing information !!! */
762
763				pp->leap = LEAP_NOTINSYNC;
764				refclock_report(peer, CEVNT_BADTIME);
765				up->polled = -1;
766				return 0;
767			}
768
769			pp->nsec = 0;
770#ifdef DEBUG
771			printf("\nTiming Flags are:\n");
772			printf("Timing flag value is: 0x%X\n", mb(9));
773			if ((mb(9) & 0x01) != 0)
774				printf ("	Getting UTC time\n");
775			else
776				printf ("	Getting GPS time\n");
777			if ((mb(9) & 0x02) != 0)
778				printf ("	PPS is from UTC\n");
779			else
780				printf ("	PPS is from GPS\n");
781			if ((mb(9) & 0x04) != 0)
782				printf ("	Time is not Set\n");
783			else
784				printf ("	Time is Set\n");
785			if ((mb(9) & 0x08) != 0)
786				printf("	I dont have UTC info\n");
787			else
788				printf ("	I have UTC info\n");
789			if ((mb(9) & 0x10) != 0)
790				printf ("	Time is from USER\n\n");
791			else
792				printf ("	Time is from GPS\n\n");
793#endif
794
795			mmday = decode_date(pp, &mb(13));
796			if (mmday < 0)
797				break;
798			tow = getlong((u_char *) &mb(1));
799#ifdef DEBUG
800			if (debug > 1) {
801				printf("pp->day: %d\n", pp->day);
802				printf("TOW: %ld\n", tow);
803				printf("DAY: %d\n", (mmday & 31));
804			}
805#endif
806			pp->hour = mb(12);
807			pp->minute = mb(11);
808			pp->second = mb(10);
809
810
811#ifdef DEBUG
812			if (debug > 1)
813				printf("TSIP_decode: unit %d: %02X #%d %02d:%02d:%02d.%09ld %02d/%02d/%04d ",
814				       up->unit, mb(0) & 0xff, event, pp->hour, pp->minute, pp->second,
815				       pp->nsec, (mmday >> 5), (mmday & 31), pp->year);
816#endif
817			return 1;
818			break;
819
820		    default:
821			/* Ignore Packet */
822			return 0;
823		} /* switch */
824	} /* if 8F packets */
825
826	else if (up->rpt_buf[0] == (u_char)0x42) {
827		printf("0x42\n");
828		return 0;
829	}
830	else if (up->rpt_buf[0] == (u_char)0x43) {
831		printf("0x43\n");
832		return 0;
833	}
834	else if ((up->rpt_buf[0] == PACKET_41) & (up->type == CLK_THUNDERBOLT)){
835		printf("Undocumented 0x41 packet on Thunderbolt\n");
836		return 0;
837	}
838	else if ((up->rpt_buf[0] == PACKET_41A) & (up->type == CLK_ACUTIME)) {
839#ifdef DEBUG
840		printf("GPS TOW: %ld\n", (long)getlong((u_char *) &mb(0)));
841		printf("GPS WN: %d\n", getint((u_char *) &mb(4)));
842		printf("GPS UTC-GPS Offser: %ld\n", (long)getlong((u_char *) &mb(6)));
843#endif
844		return 0;
845	}
846
847	/* Health Status for Acutime Receiver */
848	else if ((up->rpt_buf[0] == PACKET_46) & (up->type == CLK_ACUTIME)) {
849#ifdef DEBUG
850		if (debug > 1)
851		/* Status Codes */
852			switch (mb(0)) {
853			    case 0x00:
854				printf ("Doing Position Fixes\n");
855				break;
856			    case 0x01:
857				printf ("Do no have GPS time yet\n");
858				break;
859			    case 0x03:
860				printf ("PDOP is too high\n");
861				break;
862			    case 0x08:
863				printf ("No usable satellites\n");
864				break;
865			    case 0x09:
866				printf ("Only 1 usable satellite\n");
867				break;
868			    case 0x0A:
869				printf ("Only 2 usable satellites\n");
870				break;
871			    case 0x0B:
872				printf ("Only 3 usable satellites\n");
873				break;
874			    case 0x0C:
875				printf("The Chosen satellite is unusable\n");
876				break;
877			}
878#endif
879		/* Error Codes */
880		if (mb(1) != 0)	{
881
882			refclock_report(peer, CEVNT_BADTIME);
883			up->polled = -1;
884#ifdef DEBUG
885			if (debug > 1) {
886				if (mb(1) & 0x01)
887					printf ("Signal Processor Error, reset unit.\n");
888				if (mb(1) & 0x02)
889					printf ("Alignment error, channel or chip 1, reset unit.\n");
890				if (mb(1) & 0x03)
891					printf ("Alignment error, channel or chip 2, reset unit.\n");
892				if (mb(1) & 0x04)
893					printf ("Antenna feed line fault (open or short)\n");
894				if (mb(1) & 0x05)
895					printf ("Excessive reference frequency error, refer to packet 0x2D and packet 0x4D documentation for further information\n");
896			}
897#endif
898
899		return 0;
900		}
901	}
902	else if (up->rpt_buf[0] == 0x54)
903		return 0;
904
905	else if (up->rpt_buf[0] == PACKET_6D) {
906#ifdef DEBUG
907		int sats;
908
909		if ((mb(0) & 0x01) && (mb(0) & 0x02))
910			printf("2d Fix Dimension\n");
911		if (mb(0) & 0x04)
912			printf("3d Fix Dimension\n");
913
914		if (mb(0) & 0x08)
915			printf("Fix Mode is MANUAL\n");
916		else
917			printf("Fix Mode is AUTO\n");
918
919		sats = mb(0) & 0xF0;
920		sats = sats >> 4;
921		printf("Tracking %d Satellites\n", sats);
922#endif
923		return 0;
924	} /* else if not super packet */
925	refclock_report(peer, CEVNT_BADREPLY);
926	up->polled = -1;
927#ifdef DEBUG
928	printf("TSIP_decode: unit %d: bad packet %02x-%02x event %d len %d\n",
929	       up->unit, up->rpt_buf[0] & 0xff, mb(0) & 0xff,
930	       event, up->rpt_cnt);
931#endif
932	return 0;
933}
934
935/*
936 * palisade__receive - receive data from the serial interface
937 */
938
939static void
940palisade_receive (
941	struct peer * peer
942	)
943{
944	struct palisade_unit *up;
945	struct refclockproc *pp;
946
947	/*
948	 * Initialize pointers and read the timecode and timestamp.
949	 */
950	pp = peer->procptr;
951	up = pp->unitptr;
952
953	if (! TSIP_decode(peer)) return;
954
955	if (up->polled <= 0)
956		return;   /* no poll pending, already received or timeout */
957
958	up->polled = 0;  /* Poll reply received */
959	pp->lencode = 0; /* clear time code */
960#ifdef DEBUG
961	if (debug)
962		printf(
963			"palisade_receive: unit %d: %4d %03d %02d:%02d:%02d.%09ld\n",
964			up->unit, pp->year, pp->day, pp->hour, pp->minute,
965			pp->second, pp->nsec);
966#endif
967
968	/*
969	 * Process the sample
970	 * Generate timecode: YYYY DoY HH:MM:SS.microsec
971	 * report and process
972	 */
973
974	snprintf(pp->a_lastcode, sizeof(pp->a_lastcode),
975		 "%4d %03d %02d:%02d:%02d.%09ld",
976		 pp->year, pp->day,
977		 pp->hour,pp->minute, pp->second, pp->nsec);
978	pp->lencode = 24;
979
980	if (!refclock_process(pp)) {
981		refclock_report(peer, CEVNT_BADTIME);
982
983#ifdef DEBUG
984		printf("palisade_receive: unit %d: refclock_process failed!\n",
985		       up->unit);
986#endif
987		return;
988	}
989
990	record_clock_stats(&peer->srcadr, pp->a_lastcode);
991
992#ifdef DEBUG
993	if (debug)
994		printf("palisade_receive: unit %d: %s\n",
995		       up->unit, prettydate(&pp->lastrec));
996#endif
997	pp->lastref = pp->lastrec;
998	refclock_receive(peer);
999}
1000
1001
1002/*
1003 * palisade_poll - called by the transmit procedure
1004 *
1005 */
1006static void
1007palisade_poll (
1008	int unit,
1009	struct peer *peer
1010	)
1011{
1012	struct palisade_unit *up;
1013	struct refclockproc *pp;
1014
1015	pp = peer->procptr;
1016	up = pp->unitptr;
1017
1018	pp->polls++;
1019	if (up->polled > 0) /* last reply never arrived or error */
1020		refclock_report(peer, CEVNT_TIMEOUT);
1021
1022	up->polled = 2; /* synchronous packet + 1 event */
1023
1024#ifdef DEBUG
1025	if (debug)
1026		printf("palisade_poll: unit %d: polling %s\n", unit,
1027		       (pp->sloppyclockflag & CLK_FLAG2) ?
1028		       "synchronous packet" : "event");
1029#endif
1030
1031	if (pp->sloppyclockflag & CLK_FLAG2)
1032		return;  /* using synchronous packet input */
1033
1034	if(up->type == CLK_PRAECIS) {
1035		if(write(peer->procptr->io.fd,"SPSTAT\r\n",8) < 0)
1036			msyslog(LOG_ERR, "Palisade(%d) write: %m:",unit);
1037		else {
1038			praecis_msg = 1;
1039			return;
1040		}
1041	}
1042
1043	if (HW_poll(pp) < 0)
1044		refclock_report(peer, CEVNT_FAULT);
1045}
1046
1047static void
1048praecis_parse (
1049	struct recvbuf *rbufp,
1050	struct peer *peer
1051	)
1052{
1053	static char buf[100];
1054	static int p = 0;
1055	struct refclockproc *pp;
1056
1057	pp = peer->procptr;
1058
1059	memcpy(buf+p,rbufp->recv_space.X_recv_buffer, rbufp->recv_length);
1060	p += rbufp->recv_length;
1061
1062	if(buf[p-2] == '\r' && buf[p-1] == '\n') {
1063		buf[p-2] = '\0';
1064		record_clock_stats(&peer->srcadr, buf);
1065
1066		p = 0;
1067		praecis_msg = 0;
1068
1069		if (HW_poll(pp) < 0)
1070			refclock_report(peer, CEVNT_FAULT);
1071
1072	}
1073}
1074
1075static void
1076palisade_io (
1077	struct recvbuf *rbufp
1078	)
1079{
1080	/*
1081	 * Initialize pointers and read the timecode and timestamp.
1082	 */
1083	struct palisade_unit *up;
1084	struct refclockproc *pp;
1085	struct peer *peer;
1086
1087	char * c, * d;
1088
1089	peer = rbufp->recv_peer;
1090	pp = peer->procptr;
1091	up = pp->unitptr;
1092
1093	if(up->type == CLK_PRAECIS) {
1094		if(praecis_msg) {
1095			praecis_parse(rbufp,peer);
1096			return;
1097		}
1098	}
1099
1100	c = (char *) &rbufp->recv_space;
1101	d = c + rbufp->recv_length;
1102
1103	while (c != d) {
1104
1105		/* Build time packet */
1106		switch (up->rpt_status) {
1107
1108		    case TSIP_PARSED_DLE_1:
1109			switch (*c)
1110			{
1111			    case 0:
1112			    case DLE:
1113			    case ETX:
1114				up->rpt_status = TSIP_PARSED_EMPTY;
1115				break;
1116
1117			    default:
1118				up->rpt_status = TSIP_PARSED_DATA;
1119				/* save packet ID */
1120				up->rpt_buf[0] = *c;
1121				break;
1122			}
1123			break;
1124
1125		    case TSIP_PARSED_DATA:
1126			if (*c == DLE)
1127				up->rpt_status = TSIP_PARSED_DLE_2;
1128			else
1129				mb(up->rpt_cnt++) = *c;
1130			break;
1131
1132		    case TSIP_PARSED_DLE_2:
1133			if (*c == DLE) {
1134				up->rpt_status = TSIP_PARSED_DATA;
1135				mb(up->rpt_cnt++) =
1136				    *c;
1137			}
1138			else if (*c == ETX)
1139				up->rpt_status = TSIP_PARSED_FULL;
1140			else 	{
1141				/* error: start new report packet */
1142				up->rpt_status = TSIP_PARSED_DLE_1;
1143				up->rpt_buf[0] = *c;
1144			}
1145			break;
1146
1147		    case TSIP_PARSED_FULL:
1148		    case TSIP_PARSED_EMPTY:
1149		    default:
1150			if ( *c != DLE)
1151				up->rpt_status = TSIP_PARSED_EMPTY;
1152			else
1153				up->rpt_status = TSIP_PARSED_DLE_1;
1154			break;
1155		}
1156
1157		c++;
1158
1159		if (up->rpt_status == TSIP_PARSED_DLE_1) {
1160			up->rpt_cnt = 0;
1161			if (pp->sloppyclockflag & CLK_FLAG2)
1162				/* stamp it */
1163				get_systime(&pp->lastrec);
1164		}
1165		else if (up->rpt_status == TSIP_PARSED_EMPTY)
1166			up->rpt_cnt = 0;
1167
1168		else if (up->rpt_cnt > BMAX)
1169			up->rpt_status =TSIP_PARSED_EMPTY;
1170
1171		if (up->rpt_status == TSIP_PARSED_FULL)
1172			palisade_receive(peer);
1173
1174	} /* while chars in buffer */
1175}
1176
1177
1178/*
1179 * Trigger the Palisade's event input, which is driven off the RTS
1180 *
1181 * Take a system time stamp to match the GPS time stamp.
1182 *
1183 */
1184long
1185HW_poll (
1186	struct refclockproc * pp 	/* pointer to unit structure */
1187	)
1188{
1189	int x;	/* state before & after RTS set */
1190	struct palisade_unit *up;
1191
1192	up = pp->unitptr;
1193
1194	/* read the current status, so we put things back right */
1195	if (ioctl(pp->io.fd, TIOCMGET, &x) < 0) {
1196		DPRINTF(1, ("Palisade HW_poll: unit %d: GET %m\n",
1197			up->unit));
1198		msyslog(LOG_ERR, "Palisade(%d) HW_poll: ioctl(fd,GET): %m",
1199			up->unit);
1200		return -1;
1201	}
1202
1203	x |= TIOCM_RTS;        /* turn on RTS  */
1204
1205	/* Edge trigger */
1206	if (up->type == CLK_ACUTIME)
1207		write (pp->io.fd, "", 1);
1208
1209	if (ioctl(pp->io.fd, TIOCMSET, &x) < 0) {
1210#ifdef DEBUG
1211		if (debug)
1212			printf("Palisade HW_poll: unit %d: SET \n", up->unit);
1213#endif
1214		msyslog(LOG_ERR,
1215			"Palisade(%d) HW_poll: ioctl(fd, SET, RTS_on): %m",
1216			up->unit);
1217		return -1;
1218	}
1219
1220	x &= ~TIOCM_RTS;        /* turn off RTS  */
1221
1222	/* poll timestamp */
1223	get_systime(&pp->lastrec);
1224
1225	if (ioctl(pp->io.fd, TIOCMSET, &x) == -1) {
1226#ifdef DEBUG
1227		if (debug)
1228			printf("Palisade HW_poll: unit %d: UNSET \n", up->unit);
1229#endif
1230		msyslog(LOG_ERR,
1231			"Palisade(%d) HW_poll: ioctl(fd, UNSET, RTS_off): %m",
1232			up->unit);
1233		return -1;
1234	}
1235
1236	return 0;
1237}
1238
1239/*
1240 * copy/swap a big-endian palisade double into a host double
1241 */
1242static double
1243getdbl (
1244	u_char *bp
1245	)
1246{
1247#ifdef WORDS_BIGENDIAN
1248	double out;
1249
1250	memcpy(&out, bp, sizeof(out));
1251	return out;
1252#else
1253	union {
1254		u_char ch[8];
1255		u_int32 u32[2];
1256	} ui;
1257
1258	union {
1259		double out;
1260		u_int32 u32[2];
1261	} uo;
1262
1263	memcpy(ui.ch, bp, sizeof(ui.ch));
1264	/* least-significant 32 bits of double from swapped bp[4] to bp[7] */
1265	uo.u32[0] = ntohl(ui.u32[1]);
1266	/* most-significant 32 bits from swapped bp[0] to bp[3] */
1267	uo.u32[1] = ntohl(ui.u32[0]);
1268
1269	return uo.out;
1270#endif
1271}
1272
1273/*
1274 * copy/swap a big-endian palisade short into a host short
1275 */
1276static short
1277getint (
1278	u_char *bp
1279	)
1280{
1281	u_short us;
1282
1283	memcpy(&us, bp, sizeof(us));
1284	return (short)ntohs(us);
1285}
1286
1287/*
1288 * copy/swap a big-endian palisade 32-bit int into a host 32-bit int
1289 */
1290static int32
1291getlong(
1292	u_char *bp
1293	)
1294{
1295	u_int32 u32;
1296
1297	memcpy(&u32, bp, sizeof(u32));
1298	return (int32)(u_int32)ntohl(u32);
1299}
1300
1301#else	/* REFCLOCK && CLOCK_PALISADE*/
1302int refclock_palisade_c_notempty;
1303#endif
1304