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