xref: /netbsd-src/external/bsd/ntp/dist/ntpd/refclock_palisade.c (revision a5847cc334d9a7029f6352b847e9e8d71a0f9e0c)
1 /*	$NetBSD: refclock_palisade.c,v 1.1.1.1 2009/12/13 16:55:56 kardel 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(PALISADE) || 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 *) malloc(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 *) malloc(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 	(void) sprintf(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 = (struct palisade_unit *) emalloc(sizeof(struct palisade_unit));
311 
312 	memset((char *)up, 0, sizeof(struct palisade_unit));
313 
314 	up->type = CLK_TYPE(peer);
315 	switch (up->type) {
316 	    case CLK_TRIMBLE:
317 		/* Normal mode, do nothing */
318 		break;
319 	    case CLK_PRAECIS:
320 		msyslog(LOG_NOTICE, "Palisade(%d) Praecis mode enabled\n"
321 			,unit);
322 		break;
323 	    case CLK_THUNDERBOLT:
324 		msyslog(LOG_NOTICE, "Palisade(%d) Thunderbolt mode enabled\n"
325 			,unit);
326 		tio.c_cflag = (CS8|CLOCAL|CREAD);
327 		break;
328 	    case CLK_ACUTIME:
329 		msyslog(LOG_NOTICE, "Palisade(%d) Acutime Gold mode enabled\n"
330 			,unit);
331 		break;
332 	    default:
333 		msyslog(LOG_NOTICE, "Palisade(%d) mode unknown\n",unit);
334 		break;
335 	}
336 	if (tcsetattr(fd, TCSANOW, &tio) == -1) {
337 		msyslog(LOG_ERR, "Palisade(%d) tcsetattr(fd, &tio): %m",unit);
338 #ifdef DEBUG
339 		printf("Palisade(%d) tcsetattr(fd, &tio)\n",unit);
340 #endif
341 		close(fd);
342 		free(up);
343 		return 0;
344 	}
345 
346 	pp = peer->procptr;
347 	pp->io.clock_recv = palisade_io;
348 	pp->io.srcclock = (caddr_t)peer;
349 	pp->io.datalen = 0;
350 	pp->io.fd = fd;
351 	if (!io_addclock(&pp->io)) {
352 #ifdef DEBUG
353 		printf("Palisade(%d) io_addclock\n",unit);
354 #endif
355 		(void) close(fd);
356 		free(up);
357 		return (0);
358 	}
359 
360 	/*
361 	 * Initialize miscellaneous variables
362 	 */
363 	pp->unitptr = (caddr_t)up;
364 	pp->clockdesc = DESCRIPTION;
365 
366 	peer->precision = PRECISION;
367 	peer->sstclktype = CTL_SST_TS_UHF;
368 	peer->minpoll = TRMB_MINPOLL;
369 	peer->maxpoll = TRMB_MAXPOLL;
370 	memcpy((char *)&pp->refid, REFID, 4);
371 
372 	up->leap_status = 0;
373 	up->unit = (short) unit;
374 	up->rpt_status = TSIP_PARSED_EMPTY;
375 	up->rpt_cnt = 0;
376 
377 	if (up->type == CLK_THUNDERBOLT)
378 		init_thunderbolt(fd);
379 	if (up->type == CLK_ACUTIME)
380 		init_acutime(fd);
381 
382 	return 1;
383 }
384 
385 
386 /*
387  * palisade_shutdown - shut down the clock
388  */
389 static void
390 palisade_shutdown (
391 	int unit,
392 	struct peer *peer
393 	)
394 {
395 	struct palisade_unit *up;
396 	struct refclockproc *pp;
397 	pp = peer->procptr;
398 	up = (struct palisade_unit *)pp->unitptr;
399 	io_closeclock(&pp->io);
400 	free(up);
401 }
402 
403 
404 
405 /*
406  * unpack_date - get day and year from date
407  */
408 int
409 day_of_year (
410 	char * dt
411 	)
412 {
413 	int day, mon, year;
414 
415 	mon = dt[1];
416 	/* Check month is inside array bounds */
417 	if ((mon < 1) || (mon > 12))
418 		return -1;
419 
420 	day = dt[0] + days_of_year[mon - 1];
421 	year = getint((u_char *) (dt + 2));
422 
423 	if ( !(year % 4) && ((year % 100) ||
424 			     (!(year % 100) && !(year%400)))
425 	     &&(mon > 2))
426 		day ++; /* leap year and March or later */
427 
428 	return day;
429 }
430 
431 
432 /*
433  * TSIP_decode - decode the TSIP data packets
434  */
435 int
436 TSIP_decode (
437 	struct peer *peer
438 	)
439 {
440 	int st;
441 	long   secint;
442 	double secs;
443 	double secfrac;
444 	unsigned short event = 0;
445 
446 	struct palisade_unit *up;
447 	struct refclockproc *pp;
448 
449 	pp = peer->procptr;
450 	up = (struct palisade_unit *)pp->unitptr;
451 
452 	/*
453 	 * Check the time packet, decode its contents.
454 	 * If the timecode has invalid length or is not in
455 	 * proper format, declare bad format and exit.
456 	 */
457 
458 	if ((up->type != CLK_THUNDERBOLT) & (up->type != CLK_ACUTIME)){
459 		if ((up->rpt_buf[0] == (char) 0x41) ||
460 		    (up->rpt_buf[0] == (char) 0x46) ||
461 		    (up->rpt_buf[0] == (char) 0x54) ||
462 		    (up->rpt_buf[0] == (char) 0x4B) ||
463 		    (up->rpt_buf[0] == (char) 0x6D)) {
464 
465 			/* standard time packet - GPS time and GPS week number */
466 #ifdef DEBUG
467 			printf("Palisade Port B packets detected. Connect to Port A\n");
468 #endif
469 
470 			return 0;
471 		}
472 	}
473 
474 	/*
475 	 * We cast both to u_char to as 0x8f uses the sign bit on a char
476 	 */
477 	if ((u_char) up->rpt_buf[0] == (u_char) 0x8f) {
478 		/*
479 		 * Superpackets
480 		 */
481 		event = (unsigned short) (getint((u_char *) &mb(1)) & 0xffff);
482 		if (!((pp->sloppyclockflag & CLK_FLAG2) || event))
483 			/* Ignore Packet */
484 			return 0;
485 
486 		switch (mb(0) & 0xff) {
487 			int GPS_UTC_Offset;
488 			long tow;
489 
490 		    case PACKET_8F0B:
491 
492 			if (up->polled <= 0)
493 				return 0;
494 
495 			if (up->rpt_cnt != LENCODE_8F0B)  /* check length */
496 				break;
497 
498 #ifdef DEBUG
499 			if (debug > 1) {
500 				int ts;
501 				double lat, lon, alt;
502 				lat = getdbl((u_char *) &mb(42)) * R2D;
503 				lon = getdbl((u_char *) &mb(50)) * R2D;
504 				alt = getdbl((u_char *) &mb(58));
505 
506 				printf("TSIP_decode: unit %d: Latitude: %03.4f Longitude: %03.4f Alt: %05.2f m\n",
507 				       up->unit, lat,lon,alt);
508 				printf("TSIP_decode: unit %d: Sats:",
509 				       up->unit);
510 				for (st = 66, ts = 0; st <= 73; st++)
511 					if (mb(st)) {
512 						if (mb(st) > 0) ts++;
513 						printf(" %02d", mb(st));
514 					}
515 				printf(" : Tracking %d\n", ts);
516 			}
517 #endif
518 
519 			GPS_UTC_Offset = getint((u_char *) &mb(16));
520 			if (GPS_UTC_Offset == 0) { /* Check UTC offset */
521 #ifdef DEBUG
522 				printf("TSIP_decode: UTC Offset Unknown\n");
523 #endif
524 				break;
525 			}
526 
527 			secs = getdbl((u_char *) &mb(3));
528 			secint = (long) secs;
529 			secfrac = secs - secint; /* 0.0 <= secfrac < 1.0 */
530 
531 			pp->nsec = (long) (secfrac * 1000000000);
532 
533 			secint %= 86400;    /* Only care about today */
534 			pp->hour = secint / 3600;
535 			secint %= 3600;
536 			pp->minute = secint / 60;
537 			secint %= 60;
538 			pp->second = secint % 60;
539 
540 			if ((pp->day = day_of_year(&mb(11))) < 0) break;
541 
542 			pp->year = getint((u_char *) &mb(13));
543 
544 #ifdef DEBUG
545 			if (debug > 1)
546 				printf("TSIP_decode: unit %d: %02X #%d %02d:%02d:%02d.%06ld %02d/%02d/%04d UTC %02d\n",
547 				       up->unit, mb(0) & 0xff, event, pp->hour, pp->minute,
548 				       pp->second, pp->nsec, mb(12), mb(11), pp->year, GPS_UTC_Offset);
549 #endif
550 			/* Only use this packet when no
551 			 * 8F-AD's are being received
552 			 */
553 
554 			if (up->leap_status) {
555 				up->leap_status = 0;
556 				return 0;
557 			}
558 
559 			return 2;
560 			break;
561 
562 		    case PACKET_NTP:
563 			/* Palisade-NTP Packet */
564 
565 			if (up->rpt_cnt != LENCODE_NTP) /* check length */
566 				break;
567 
568 			up->leap_status = mb(19);
569 
570 			if (up->polled  <= 0)
571 				return 0;
572 
573 			/* Check Tracking Status */
574 			st = mb(18);
575 			if (st < 0 || st > 14)
576 				st = 14;
577 			if ((st >= 2 && st <= 7) || st == 11 || st == 12) {
578 #ifdef DEBUG
579 				printf("TSIP_decode: Not Tracking Sats : %s\n",
580 				       *Tracking_Status[st]);
581 #endif
582 				refclock_report(peer, CEVNT_BADTIME);
583 				up->polled = -1;
584 				return 0;
585 				break;
586 			}
587 
588 			if (up->leap_status & PALISADE_LEAP_PENDING) {
589 				if (up->leap_status & PALISADE_UTC_TIME)
590 					pp->leap = LEAP_ADDSECOND;
591 				else
592 					pp->leap = LEAP_DELSECOND;
593 			}
594 			else if (up->leap_status)
595 				pp->leap = LEAP_NOWARNING;
596 
597 			else {  /* UTC flag is not set:
598 				 * Receiver may have been reset, and lost
599 				 * its UTC almanac data */
600 				pp->leap = LEAP_NOTINSYNC;
601 #ifdef DEBUG
602 				printf("TSIP_decode: UTC Almanac unavailable: %d\n",
603 				       mb(19));
604 #endif
605 				refclock_report(peer, CEVNT_BADTIME);
606 				up->polled = -1;
607 				return 0;
608 			}
609 
610 			pp->nsec = (long) (getdbl((u_char *) &mb(3))
611 					   * 1000000000);
612 
613 			if ((pp->day = day_of_year(&mb(14))) < 0)
614 				break;
615 			pp->year = getint((u_char *) &mb(16));
616 			pp->hour = mb(11);
617 			pp->minute = mb(12);
618 			pp->second = mb(13);
619 
620 #ifdef DEBUG
621 			if (debug > 1)
622 				printf("TSIP_decode: unit %d: %02X #%d %02d:%02d:%02d.%06ld %02d/%02d/%04d UTC %02x %s\n",
623 				       up->unit, mb(0) & 0xff, event, pp->hour, pp->minute,
624 				       pp->second, pp->nsec, mb(15), mb(14), pp->year,
625 				       mb(19), *Tracking_Status[st]);
626 #endif
627 			return 1;
628 			break;
629 
630 		    case PACKET_8FAC:
631 			if (up->polled <= 0)
632 				return 0;
633 
634 			if (up->rpt_cnt != LENCODE_8FAC)/* check length */
635 				break;
636 
637 #ifdef DEBUG
638 			if (debug > 1) {
639 				double lat, lon, alt;
640 				lat = getdbl((u_char *) &mb(36)) * R2D;
641 				lon = getdbl((u_char *) &mb(44)) * R2D;
642 				alt = getdbl((u_char *) &mb(52));
643 
644 				printf("TSIP_decode: unit %d: Latitude: %03.4f Longitude: %03.4f Alt: %05.2f m\n",
645 				       up->unit, lat,lon,alt);
646 				printf("TSIP_decode: unit %d\n", up->unit);
647 			}
648 #endif
649 			if (getint((u_char *) &mb(10)) & 0x80)
650 				pp->leap = LEAP_ADDSECOND;  /* we ASSUME addsecond */
651 			else
652 				pp->leap = LEAP_NOWARNING;
653 
654 #ifdef DEBUG
655 			if (debug > 1)
656 				printf("TSIP_decode: unit %d: 0x%02x leap %d\n",
657 				       up->unit, mb(0) & 0xff, pp->leap);
658 			if (debug > 1) {
659 				printf("Receiver MODE: 0x%02X\n", (u_char)mb(1));
660 				if (mb(1) == 0x00)
661 					printf("                AUTOMATIC\n");
662 				if (mb(1) == 0x01)
663 					printf("                SINGLE SATELLITE\n");
664 				if (mb(1) == 0x03)
665 					printf("                HORIZONTAL(2D)\n");
666 				if (mb(1) == 0x04)
667 					printf("                FULL POSITION(3D)\n");
668 				if (mb(1) == 0x05)
669 					printf("                DGPR REFERENCE\n");
670 				if (mb(1) == 0x06)
671 					printf("                CLOCK HOLD(2D)\n");
672 				if (mb(1) == 0x07)
673 					printf("                OVERDETERMINED CLOCK\n");
674 
675 				printf("\n** Disciplining MODE 0x%02X:\n", (u_char)mb(2));
676 				if (mb(2) == 0x00)
677 					printf("                NORMAL\n");
678 				if (mb(2) == 0x01)
679 					printf("                POWER-UP\n");
680 				if (mb(2) == 0x02)
681 					printf("                AUTO HOLDOVER\n");
682 				if (mb(2) == 0x03)
683 					printf("                MANUAL HOLDOVER\n");
684 				if (mb(2) == 0x04)
685 					printf("                RECOVERY\n");
686 				if (mb(2) == 0x06)
687 					printf("                DISCIPLINING DISABLED\n");
688 			}
689 #endif
690 			return 0;
691 			break;
692 
693 		    case PACKET_8FAB:
694 			/* Thunderbolt Primary Timing Packet */
695 
696 			if (up->rpt_cnt != LENCODE_8FAB) /* check length */
697 				break;
698 
699 			if (up->polled  <= 0)
700 				return 0;
701 
702 			GPS_UTC_Offset = getint((u_char *) &mb(7));
703 
704 			if (GPS_UTC_Offset == 0){ /* Check UTC Offset */
705 #ifdef DEBUG
706 				printf("TSIP_decode: UTC Offset Unknown\n");
707 #endif
708 				break;
709 			}
710 
711 
712 			if ((mb(9) & 0x1d) == 0x0) {
713 				/* if we know the GPS time and the UTC offset,
714 				   we expect UTC timing information !!! */
715 
716 				pp->leap = LEAP_NOTINSYNC;
717 				refclock_report(peer, CEVNT_BADTIME);
718 				up->polled = -1;
719 				return 0;
720 			}
721 
722 			pp->nsec = 0;
723 #ifdef DEBUG
724 			printf("\nTiming Flags are:\n");
725 			printf("Timing flag value is: 0x%X\n", mb(9));
726 			if ((mb(9) & 0x01) != 0)
727 				printf ("	Getting UTC time\n");
728 			else
729 				printf ("	Getting GPS time\n");
730 			if ((mb(9) & 0x02) != 0)
731 				printf ("	PPS is from UTC\n");
732 			else
733 				printf ("	PPS is from GPS\n");
734 			if ((mb(9) & 0x04) != 0)
735 				printf ("	Time is not Set\n");
736 			else
737 				printf ("	Time is Set\n");
738 			if ((mb(9) & 0x08) != 0)
739 				printf("	I dont have UTC info\n");
740 			else
741 				printf ("	I have UTC info\n");
742 			if ((mb(9) & 0x10) != 0)
743 				printf ("	Time is from USER\n\n");
744 			else
745 				printf ("	Time is from GPS\n\n");
746 #endif
747 
748 			if ((pp->day = day_of_year(&mb(13))) < 0)
749 				break;
750 			tow = getlong((u_char *) &mb(1));
751 #ifdef DEBUG
752 			if (debug > 1) {
753 				printf("pp->day: %d\n", pp->day);
754 				printf("TOW: %ld\n", tow);
755 				printf("DAY: %d\n", mb(13));
756 			}
757 #endif
758 			pp->year = getint((u_char *) &mb(15));
759 			pp->hour = mb(12);
760 			pp->minute = mb(11);
761 			pp->second = mb(10);
762 
763 
764 #ifdef DEBUG
765 			if (debug > 1)
766 				printf("TSIP_decode: unit %d: %02X #%d %02d:%02d:%02d.%06ld %02d/%02d/%04d ",up->unit, mb(0) & 0xff, event, pp->hour, pp->minute, pp->second, pp->nsec, mb(14), mb(13), pp->year);
767 #endif
768 			return 1;
769 			break;
770 
771 		    default:
772 			/* Ignore Packet */
773 			return 0;
774 		} /* switch */
775 	} /* if 8F packets */
776 
777 	else if (up->rpt_buf[0] == (u_char)0x42) {
778 		printf("0x42\n");
779 		return 0;
780 	}
781 	else if (up->rpt_buf[0] == (u_char)0x43) {
782 		printf("0x43\n");
783 		return 0;
784 	}
785 	else if ((up->rpt_buf[0] == PACKET_41) & (up->type == CLK_THUNDERBOLT)){
786 		printf("Undocumented 0x41 packet on Thunderbolt\n");
787 		return 0;
788 	}
789 	else if ((up->rpt_buf[0] == PACKET_41A) & (up->type == CLK_ACUTIME)) {
790 #ifdef DEBUG
791 		printf("GPS TOW: %ld\n", getlong((u_char *) &mb(0)));
792 		printf("GPS WN: %d\n", getint((u_char *) &mb(4)));
793 		printf("GPS UTC-GPS Offser: %ld\n", getlong((u_char *) &mb(6)));
794 #endif
795 		return 0;
796 	}
797 
798 	/* Health Status for Acutime Receiver */
799 	else if ((up->rpt_buf[0] == PACKET_46) & (up->type == CLK_ACUTIME)) {
800 #ifdef DEBUG
801 		if (debug > 1)
802 		/* Status Codes */
803 			switch (mb(0)) {
804 			    case 0x00:
805 				printf ("Doing Position Fixes\n");
806 				break;
807 			    case 0x01:
808 				printf ("Do no have GPS time yet\n");
809 				break;
810 			    case 0x03:
811 				printf ("PDOP is too high\n");
812 				break;
813 			    case 0x08:
814 				printf ("No usable satellites\n");
815 				break;
816 			    case 0x09:
817 				printf ("Only 1 usable satellite\n");
818 				break;
819 			    case 0x0A:
820 				printf ("Only 2 usable satellites\n");
821 				break;
822 			    case 0x0B:
823 				printf ("Only 3 usable satellites\n");
824 				break;
825 			    case 0x0C:
826 				printf("The Chosen satellite is unusable\n");
827 				break;
828 			}
829 #endif
830 		/* Error Codes */
831 		if (mb(1) != 0)	{
832 
833 			refclock_report(peer, CEVNT_BADTIME);
834 			up->polled = -1;
835 #ifdef DEBUG
836 			if (debug > 1) {
837 				if (mb(1) && 0x01)
838 					printf ("Signal Processor Error, reset unit.\n");
839 				if (mb(1) && 0x02)
840 					printf ("Alignment error, channel or chip 1, reset unit.\n");
841 				if (mb(1) && 0x03)
842 					printf ("Alignment error, channel or chip 2, reset unit.\n");
843 				if (mb(1) && 0x04)
844 					printf ("Antenna feed line fault (open or short)\n");
845 				if (mb(1) && 0x05)
846 					printf ("Excessive reference frequency error, refer to packet 0x2D and packet 0x4D documentation for further information\n");
847 			}
848 #endif
849 
850 		return 0;
851 		}
852 	}
853 	else if (up->rpt_buf[0] == 0x54)
854 		return 0;
855 
856 	else if (up->rpt_buf[0] == PACKET_6D) {
857 #ifdef DEBUG
858 		int sats;
859 
860 		if ((mb(0) & 0x01) && (mb(0) & 0x02))
861 			printf("2d Fix Dimension\n");
862 		if (mb(0) & 0x04)
863 			printf("3d Fix Dimension\n");
864 
865 		if (mb(0) & 0x08)
866 			printf("Fix Mode is MANUAL\n");
867 		else
868 			printf("Fix Mode is AUTO\n");
869 
870 		sats = mb(0) & 0xF0;
871 		sats = sats >> 4;
872 		printf("Tracking %d Satellites\n", sats);
873 #endif
874 		return 0;
875 	} /* else if not super packet */
876 	refclock_report(peer, CEVNT_BADREPLY);
877 	up->polled = -1;
878 #ifdef DEBUG
879 	printf("TSIP_decode: unit %d: bad packet %02x-%02x event %d len %d\n",
880 	       up->unit, up->rpt_buf[0] & 0xff, mb(0) & 0xff,
881 	       event, up->rpt_cnt);
882 #endif
883 	return 0;
884 }
885 
886 /*
887  * palisade__receive - receive data from the serial interface
888  */
889 
890 static void
891 palisade_receive (
892 	struct peer * peer
893 	)
894 {
895 	struct palisade_unit *up;
896 	struct refclockproc *pp;
897 
898 	/*
899 	 * Initialize pointers and read the timecode and timestamp.
900 	 */
901 	pp = peer->procptr;
902 	up = (struct palisade_unit *)pp->unitptr;
903 
904 	if (! TSIP_decode(peer)) return;
905 
906 	if (up->polled <= 0)
907 		return;   /* no poll pending, already received or timeout */
908 
909 	up->polled = 0;  /* Poll reply received */
910 	pp->lencode = 0; /* clear time code */
911 #ifdef DEBUG
912 	if (debug)
913 		printf(
914 			"palisade_receive: unit %d: %4d %03d %02d:%02d:%02d.%06ld\n",
915 			up->unit, pp->year, pp->day, pp->hour, pp->minute,
916 			pp->second, pp->nsec);
917 #endif
918 
919 	/*
920 	 * Process the sample
921 	 * Generate timecode: YYYY DoY HH:MM:SS.microsec
922 	 * report and process
923 	 */
924 
925 	(void) sprintf(pp->a_lastcode,"%4d %03d %02d:%02d:%02d.%06ld",
926 		       pp->year,pp->day,pp->hour,pp->minute, pp->second,pp->nsec);
927 	pp->lencode = 24;
928 
929 	if (!refclock_process(pp)) {
930 		refclock_report(peer, CEVNT_BADTIME);
931 
932 #ifdef DEBUG
933 		printf("palisade_receive: unit %d: refclock_process failed!\n",
934 		       up->unit);
935 #endif
936 		return;
937 	}
938 
939 	record_clock_stats(&peer->srcadr, pp->a_lastcode);
940 
941 #ifdef DEBUG
942 	if (debug)
943 		printf("palisade_receive: unit %d: %s\n",
944 		       up->unit, prettydate(&pp->lastrec));
945 #endif
946 	pp->lastref = pp->lastrec;
947 	refclock_receive(peer);
948 }
949 
950 
951 /*
952  * palisade_poll - called by the transmit procedure
953  *
954  */
955 static void
956 palisade_poll (
957 	int unit,
958 	struct peer *peer
959 	)
960 {
961 	struct palisade_unit *up;
962 	struct refclockproc *pp;
963 
964 	pp = peer->procptr;
965 	up = (struct palisade_unit *)pp->unitptr;
966 
967 	pp->polls++;
968 	if (up->polled > 0) /* last reply never arrived or error */
969 		refclock_report(peer, CEVNT_TIMEOUT);
970 
971 	up->polled = 2; /* synchronous packet + 1 event */
972 
973 #ifdef DEBUG
974 	if (debug)
975 		printf("palisade_poll: unit %d: polling %s\n", unit,
976 		       (pp->sloppyclockflag & CLK_FLAG2) ?
977 		       "synchronous packet" : "event");
978 #endif
979 
980 	if (pp->sloppyclockflag & CLK_FLAG2)
981 		return;  /* using synchronous packet input */
982 
983 	if(up->type == CLK_PRAECIS) {
984 		if(write(peer->procptr->io.fd,"SPSTAT\r\n",8) < 0)
985 			msyslog(LOG_ERR, "Palisade(%d) write: %m:",unit);
986 		else {
987 			praecis_msg = 1;
988 			return;
989 		}
990 	}
991 
992 	if (HW_poll(pp) < 0)
993 		refclock_report(peer, CEVNT_FAULT);
994 }
995 
996 static void
997 praecis_parse (
998 	struct recvbuf *rbufp,
999 	struct peer *peer
1000 	)
1001 {
1002 	static char buf[100];
1003 	static int p = 0;
1004 	struct refclockproc *pp;
1005 
1006 	pp = peer->procptr;
1007 
1008 	memcpy(buf+p,rbufp->recv_space.X_recv_buffer, rbufp->recv_length);
1009 	p += rbufp->recv_length;
1010 
1011 	if(buf[p-2] == '\r' && buf[p-1] == '\n') {
1012 		buf[p-2] = '\0';
1013 		record_clock_stats(&peer->srcadr, buf);
1014 
1015 		p = 0;
1016 		praecis_msg = 0;
1017 
1018 		if (HW_poll(pp) < 0)
1019 			refclock_report(peer, CEVNT_FAULT);
1020 
1021 	}
1022 }
1023 
1024 static void
1025 palisade_io (
1026 	struct recvbuf *rbufp
1027 	)
1028 {
1029 	/*
1030 	 * Initialize pointers and read the timecode and timestamp.
1031 	 */
1032 	struct palisade_unit *up;
1033 	struct refclockproc *pp;
1034 	struct peer *peer;
1035 
1036 	char * c, * d;
1037 
1038 	peer = (struct peer *)rbufp->recv_srcclock;
1039 	pp = peer->procptr;
1040 	up = (struct palisade_unit *)pp->unitptr;
1041 
1042 	if(up->type == CLK_PRAECIS) {
1043 		if(praecis_msg) {
1044 			praecis_parse(rbufp,peer);
1045 			return;
1046 		}
1047 	}
1048 
1049 	c = (char *) &rbufp->recv_space;
1050 	d = c + rbufp->recv_length;
1051 
1052 	while (c != d) {
1053 
1054 		/* Build time packet */
1055 		switch (up->rpt_status) {
1056 
1057 		    case TSIP_PARSED_DLE_1:
1058 			switch (*c)
1059 			{
1060 			    case 0:
1061 			    case DLE:
1062 			    case ETX:
1063 				up->rpt_status = TSIP_PARSED_EMPTY;
1064 				break;
1065 
1066 			    default:
1067 				up->rpt_status = TSIP_PARSED_DATA;
1068 				/* save packet ID */
1069 				up->rpt_buf[0] = *c;
1070 				break;
1071 			}
1072 			break;
1073 
1074 		    case TSIP_PARSED_DATA:
1075 			if (*c == DLE)
1076 				up->rpt_status = TSIP_PARSED_DLE_2;
1077 			else
1078 				mb(up->rpt_cnt++) = *c;
1079 			break;
1080 
1081 		    case TSIP_PARSED_DLE_2:
1082 			if (*c == DLE) {
1083 				up->rpt_status = TSIP_PARSED_DATA;
1084 				mb(up->rpt_cnt++) =
1085 				    *c;
1086 			}
1087 			else if (*c == ETX)
1088 				up->rpt_status = TSIP_PARSED_FULL;
1089 			else 	{
1090 				/* error: start new report packet */
1091 				up->rpt_status = TSIP_PARSED_DLE_1;
1092 				up->rpt_buf[0] = *c;
1093 			}
1094 			break;
1095 
1096 		    case TSIP_PARSED_FULL:
1097 		    case TSIP_PARSED_EMPTY:
1098 		    default:
1099 			if ( *c != DLE)
1100 				up->rpt_status = TSIP_PARSED_EMPTY;
1101 			else
1102 				up->rpt_status = TSIP_PARSED_DLE_1;
1103 			break;
1104 		}
1105 
1106 		c++;
1107 
1108 		if (up->rpt_status == TSIP_PARSED_DLE_1) {
1109 			up->rpt_cnt = 0;
1110 			if (pp->sloppyclockflag & CLK_FLAG2)
1111 				/* stamp it */
1112 				get_systime(&pp->lastrec);
1113 		}
1114 		else if (up->rpt_status == TSIP_PARSED_EMPTY)
1115 			up->rpt_cnt = 0;
1116 
1117 		else if (up->rpt_cnt > BMAX)
1118 			up->rpt_status =TSIP_PARSED_EMPTY;
1119 
1120 		if (up->rpt_status == TSIP_PARSED_FULL)
1121 			palisade_receive(peer);
1122 
1123 	} /* while chars in buffer */
1124 }
1125 
1126 
1127 /*
1128  * Trigger the Palisade's event input, which is driven off the RTS
1129  *
1130  * Take a system time stamp to match the GPS time stamp.
1131  *
1132  */
1133 long
1134 HW_poll (
1135 	struct refclockproc * pp 	/* pointer to unit structure */
1136 	)
1137 {
1138 	int x;	/* state before & after RTS set */
1139 	struct palisade_unit *up;
1140 
1141 	up = (struct palisade_unit *) pp->unitptr;
1142 
1143 	/* read the current status, so we put things back right */
1144 	if (ioctl(pp->io.fd, TIOCMGET, &x) < 0) {
1145 #ifdef DEBUG
1146 		if (debug)
1147 			printf("Palisade HW_poll: unit %d: GET %s\n", up->unit, strerror(errno));
1148 #endif
1149 		msyslog(LOG_ERR, "Palisade(%d) HW_poll: ioctl(fd,GET): %m",
1150 			up->unit);
1151 		return -1;
1152 	}
1153 
1154 	x |= TIOCM_RTS;        /* turn on RTS  */
1155 
1156 	/* Edge trigger */
1157 	if (up->type == CLK_ACUTIME)
1158 		write (pp->io.fd, "", 1);
1159 
1160 	if (ioctl(pp->io.fd, TIOCMSET, &x) < 0) {
1161 #ifdef DEBUG
1162 		if (debug)
1163 			printf("Palisade HW_poll: unit %d: SET \n", up->unit);
1164 #endif
1165 		msyslog(LOG_ERR,
1166 			"Palisade(%d) HW_poll: ioctl(fd, SET, RTS_on): %m",
1167 			up->unit);
1168 		return -1;
1169 	}
1170 
1171 	x &= ~TIOCM_RTS;        /* turn off RTS  */
1172 
1173 	/* poll timestamp */
1174 	get_systime(&pp->lastrec);
1175 
1176 	if (ioctl(pp->io.fd, TIOCMSET, &x) == -1) {
1177 #ifdef DEBUG
1178 		if (debug)
1179 			printf("Palisade HW_poll: unit %d: UNSET \n", up->unit);
1180 #endif
1181 		msyslog(LOG_ERR,
1182 			"Palisade(%d) HW_poll: ioctl(fd, UNSET, RTS_off): %m",
1183 			up->unit);
1184 		return -1;
1185 	}
1186 
1187 	return 0;
1188 }
1189 
1190 #if 0 /* unused */
1191 /*
1192  * this 'casts' a character array into a float
1193  */
1194 float
1195 getfloat (
1196 	u_char *bp
1197 	)
1198 {
1199 	float sval;
1200 #ifdef WORDS_BIGENDIAN
1201 	((char *) &sval)[0] = *bp++;
1202 	((char *) &sval)[1] = *bp++;
1203 	((char *) &sval)[2] = *bp++;
1204 	((char *) &sval)[3] = *bp++;
1205 #else
1206 	((char *) &sval)[3] = *bp++;
1207 	((char *) &sval)[2] = *bp++;
1208 	((char *) &sval)[1] = *bp++;
1209 	((char *) &sval)[0] = *bp;
1210 #endif  /* ! XNTP_BIG_ENDIAN */
1211 	return sval;
1212 }
1213 #endif
1214 
1215 /*
1216  * this 'casts' a character array into a double
1217  */
1218 double
1219 getdbl (
1220 	u_char *bp
1221 	)
1222 {
1223 	double dval;
1224 #ifdef WORDS_BIGENDIAN
1225 	((char *) &dval)[0] = *bp++;
1226 	((char *) &dval)[1] = *bp++;
1227 	((char *) &dval)[2] = *bp++;
1228 	((char *) &dval)[3] = *bp++;
1229 	((char *) &dval)[4] = *bp++;
1230 	((char *) &dval)[5] = *bp++;
1231 	((char *) &dval)[6] = *bp++;
1232 	((char *) &dval)[7] = *bp;
1233 #else
1234 	((char *) &dval)[7] = *bp++;
1235 	((char *) &dval)[6] = *bp++;
1236 	((char *) &dval)[5] = *bp++;
1237 	((char *) &dval)[4] = *bp++;
1238 	((char *) &dval)[3] = *bp++;
1239 	((char *) &dval)[2] = *bp++;
1240 	((char *) &dval)[1] = *bp++;
1241 	((char *) &dval)[0] = *bp;
1242 #endif  /* ! XNTP_BIG_ENDIAN */
1243 	return dval;
1244 }
1245 
1246 /*
1247  * cast a 16 bit character array into a short (16 bit) int
1248  */
1249 short
1250 getint (
1251 	u_char *bp
1252 	)
1253 {
1254 	return (short) (bp[1] + (bp[0] << 8));
1255 }
1256 
1257 /*
1258  * cast a 32 bit character array into a long (32 bit) int
1259  */
1260 long
1261 getlong(
1262 	u_char *bp
1263 	)
1264 {
1265 	return (long) (bp[0] << 24) |
1266 	    (bp[1] << 16) |
1267 	    (bp[2] << 8) |
1268 	    bp[3];
1269 }
1270 
1271 int refclock_palisade_bs;
1272 #endif /* REFCLOCK */
1273