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