xref: /freebsd/contrib/ntp/ntpd/refclock_palisade.c (revision 788ca347b816afd83b2885e0c79aeeb88649b2ab)
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 *) malloc(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 *) malloc(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 			if (up->leap_status & PALISADE_LEAP_PENDING) {
588 				if (up->leap_status & PALISADE_UTC_TIME)
589 					pp->leap = LEAP_ADDSECOND;
590 				else
591 					pp->leap = LEAP_DELSECOND;
592 			}
593 			else if (up->leap_status)
594 				pp->leap = LEAP_NOWARNING;
595 
596 			else {  /* UTC flag is not set:
597 				 * Receiver may have been reset, and lost
598 				 * its UTC almanac data */
599 				pp->leap = LEAP_NOTINSYNC;
600 #ifdef DEBUG
601 				printf("TSIP_decode: UTC Almanac unavailable: %d\n",
602 				       mb(19));
603 #endif
604 				refclock_report(peer, CEVNT_BADTIME);
605 				up->polled = -1;
606 				return 0;
607 			}
608 
609 			pp->nsec = (long) (getdbl((u_char *) &mb(3))
610 					   * 1000000000);
611 
612 			if ((pp->day = day_of_year(&mb(14))) < 0)
613 				break;
614 			pp->year = getint((u_char *) &mb(16));
615 			pp->hour = mb(11);
616 			pp->minute = mb(12);
617 			pp->second = mb(13);
618 
619 #ifdef DEBUG
620 			if (debug > 1)
621 				printf("TSIP_decode: unit %d: %02X #%d %02d:%02d:%02d.%09ld %02d/%02d/%04d UTC %02x %s\n",
622 				       up->unit, mb(0) & 0xff, event, pp->hour, pp->minute,
623 				       pp->second, pp->nsec, mb(15), mb(14), pp->year,
624 				       mb(19), *Tracking_Status[st]);
625 #endif
626 			return 1;
627 			break;
628 
629 		    case PACKET_8FAC:
630 			if (up->polled <= 0)
631 				return 0;
632 
633 			if (up->rpt_cnt != LENCODE_8FAC)/* check length */
634 				break;
635 
636 #ifdef DEBUG
637 			if (debug > 1) {
638 				double lat, lon, alt;
639 				lat = getdbl((u_char *) &mb(36)) * R2D;
640 				lon = getdbl((u_char *) &mb(44)) * R2D;
641 				alt = getdbl((u_char *) &mb(52));
642 
643 				printf("TSIP_decode: unit %d: Latitude: %03.4f Longitude: %03.4f Alt: %05.2f m\n",
644 				       up->unit, lat,lon,alt);
645 				printf("TSIP_decode: unit %d\n", up->unit);
646 			}
647 #endif
648 			if (getint((u_char *) &mb(10)) & 0x80)
649 				pp->leap = LEAP_ADDSECOND;  /* we ASSUME addsecond */
650 			else
651 				pp->leap = LEAP_NOWARNING;
652 
653 #ifdef DEBUG
654 			if (debug > 1)
655 				printf("TSIP_decode: unit %d: 0x%02x leap %d\n",
656 				       up->unit, mb(0) & 0xff, pp->leap);
657 			if (debug > 1) {
658 				printf("Receiver MODE: 0x%02X\n", (u_char)mb(1));
659 				if (mb(1) == 0x00)
660 					printf("                AUTOMATIC\n");
661 				if (mb(1) == 0x01)
662 					printf("                SINGLE SATELLITE\n");
663 				if (mb(1) == 0x03)
664 					printf("                HORIZONTAL(2D)\n");
665 				if (mb(1) == 0x04)
666 					printf("                FULL POSITION(3D)\n");
667 				if (mb(1) == 0x05)
668 					printf("                DGPR REFERENCE\n");
669 				if (mb(1) == 0x06)
670 					printf("                CLOCK HOLD(2D)\n");
671 				if (mb(1) == 0x07)
672 					printf("                OVERDETERMINED CLOCK\n");
673 
674 				printf("\n** Disciplining MODE 0x%02X:\n", (u_char)mb(2));
675 				if (mb(2) == 0x00)
676 					printf("                NORMAL\n");
677 				if (mb(2) == 0x01)
678 					printf("                POWER-UP\n");
679 				if (mb(2) == 0x02)
680 					printf("                AUTO HOLDOVER\n");
681 				if (mb(2) == 0x03)
682 					printf("                MANUAL HOLDOVER\n");
683 				if (mb(2) == 0x04)
684 					printf("                RECOVERY\n");
685 				if (mb(2) == 0x06)
686 					printf("                DISCIPLINING DISABLED\n");
687 			}
688 #endif
689 			return 0;
690 			break;
691 
692 		    case PACKET_8FAB:
693 			/* Thunderbolt Primary Timing Packet */
694 
695 			if (up->rpt_cnt != LENCODE_8FAB) /* check length */
696 				break;
697 
698 			if (up->polled  <= 0)
699 				return 0;
700 
701 			GPS_UTC_Offset = getint((u_char *) &mb(7));
702 
703 			if (GPS_UTC_Offset == 0){ /* Check UTC Offset */
704 #ifdef DEBUG
705 				printf("TSIP_decode: UTC Offset Unknown\n");
706 #endif
707 				break;
708 			}
709 
710 
711 			if ((mb(9) & 0x1d) == 0x0) {
712 				/* if we know the GPS time and the UTC offset,
713 				   we expect UTC timing information !!! */
714 
715 				pp->leap = LEAP_NOTINSYNC;
716 				refclock_report(peer, CEVNT_BADTIME);
717 				up->polled = -1;
718 				return 0;
719 			}
720 
721 			pp->nsec = 0;
722 #ifdef DEBUG
723 			printf("\nTiming Flags are:\n");
724 			printf("Timing flag value is: 0x%X\n", mb(9));
725 			if ((mb(9) & 0x01) != 0)
726 				printf ("	Getting UTC time\n");
727 			else
728 				printf ("	Getting GPS time\n");
729 			if ((mb(9) & 0x02) != 0)
730 				printf ("	PPS is from UTC\n");
731 			else
732 				printf ("	PPS is from GPS\n");
733 			if ((mb(9) & 0x04) != 0)
734 				printf ("	Time is not Set\n");
735 			else
736 				printf ("	Time is Set\n");
737 			if ((mb(9) & 0x08) != 0)
738 				printf("	I dont have UTC info\n");
739 			else
740 				printf ("	I have UTC info\n");
741 			if ((mb(9) & 0x10) != 0)
742 				printf ("	Time is from USER\n\n");
743 			else
744 				printf ("	Time is from GPS\n\n");
745 #endif
746 
747 			if ((pp->day = day_of_year(&mb(13))) < 0)
748 				break;
749 			tow = getlong((u_char *) &mb(1));
750 #ifdef DEBUG
751 			if (debug > 1) {
752 				printf("pp->day: %d\n", pp->day);
753 				printf("TOW: %ld\n", tow);
754 				printf("DAY: %d\n", mb(13));
755 			}
756 #endif
757 			pp->year = getint((u_char *) &mb(15));
758 			pp->hour = mb(12);
759 			pp->minute = mb(11);
760 			pp->second = mb(10);
761 
762 
763 #ifdef DEBUG
764 			if (debug > 1)
765 				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);
766 #endif
767 			return 1;
768 			break;
769 
770 		    default:
771 			/* Ignore Packet */
772 			return 0;
773 		} /* switch */
774 	} /* if 8F packets */
775 
776 	else if (up->rpt_buf[0] == (u_char)0x42) {
777 		printf("0x42\n");
778 		return 0;
779 	}
780 	else if (up->rpt_buf[0] == (u_char)0x43) {
781 		printf("0x43\n");
782 		return 0;
783 	}
784 	else if ((up->rpt_buf[0] == PACKET_41) & (up->type == CLK_THUNDERBOLT)){
785 		printf("Undocumented 0x41 packet on Thunderbolt\n");
786 		return 0;
787 	}
788 	else if ((up->rpt_buf[0] == PACKET_41A) & (up->type == CLK_ACUTIME)) {
789 #ifdef DEBUG
790 		printf("GPS TOW: %ld\n", (long)getlong((u_char *) &mb(0)));
791 		printf("GPS WN: %d\n", getint((u_char *) &mb(4)));
792 		printf("GPS UTC-GPS Offser: %ld\n", (long)getlong((u_char *) &mb(6)));
793 #endif
794 		return 0;
795 	}
796 
797 	/* Health Status for Acutime Receiver */
798 	else if ((up->rpt_buf[0] == PACKET_46) & (up->type == CLK_ACUTIME)) {
799 #ifdef DEBUG
800 		if (debug > 1)
801 		/* Status Codes */
802 			switch (mb(0)) {
803 			    case 0x00:
804 				printf ("Doing Position Fixes\n");
805 				break;
806 			    case 0x01:
807 				printf ("Do no have GPS time yet\n");
808 				break;
809 			    case 0x03:
810 				printf ("PDOP is too high\n");
811 				break;
812 			    case 0x08:
813 				printf ("No usable satellites\n");
814 				break;
815 			    case 0x09:
816 				printf ("Only 1 usable satellite\n");
817 				break;
818 			    case 0x0A:
819 				printf ("Only 2 usable satellites\n");
820 				break;
821 			    case 0x0B:
822 				printf ("Only 3 usable satellites\n");
823 				break;
824 			    case 0x0C:
825 				printf("The Chosen satellite is unusable\n");
826 				break;
827 			}
828 #endif
829 		/* Error Codes */
830 		if (mb(1) != 0)	{
831 
832 			refclock_report(peer, CEVNT_BADTIME);
833 			up->polled = -1;
834 #ifdef DEBUG
835 			if (debug > 1) {
836 				if (mb(1) & 0x01)
837 					printf ("Signal Processor Error, reset unit.\n");
838 				if (mb(1) & 0x02)
839 					printf ("Alignment error, channel or chip 1, reset unit.\n");
840 				if (mb(1) & 0x03)
841 					printf ("Alignment error, channel or chip 2, reset unit.\n");
842 				if (mb(1) & 0x04)
843 					printf ("Antenna feed line fault (open or short)\n");
844 				if (mb(1) & 0x05)
845 					printf ("Excessive reference frequency error, refer to packet 0x2D and packet 0x4D documentation for further information\n");
846 			}
847 #endif
848 
849 		return 0;
850 		}
851 	}
852 	else if (up->rpt_buf[0] == 0x54)
853 		return 0;
854 
855 	else if (up->rpt_buf[0] == PACKET_6D) {
856 #ifdef DEBUG
857 		int sats;
858 
859 		if ((mb(0) & 0x01) && (mb(0) & 0x02))
860 			printf("2d Fix Dimension\n");
861 		if (mb(0) & 0x04)
862 			printf("3d Fix Dimension\n");
863 
864 		if (mb(0) & 0x08)
865 			printf("Fix Mode is MANUAL\n");
866 		else
867 			printf("Fix Mode is AUTO\n");
868 
869 		sats = mb(0) & 0xF0;
870 		sats = sats >> 4;
871 		printf("Tracking %d Satellites\n", sats);
872 #endif
873 		return 0;
874 	} /* else if not super packet */
875 	refclock_report(peer, CEVNT_BADREPLY);
876 	up->polled = -1;
877 #ifdef DEBUG
878 	printf("TSIP_decode: unit %d: bad packet %02x-%02x event %d len %d\n",
879 	       up->unit, up->rpt_buf[0] & 0xff, mb(0) & 0xff,
880 	       event, up->rpt_cnt);
881 #endif
882 	return 0;
883 }
884 
885 /*
886  * palisade__receive - receive data from the serial interface
887  */
888 
889 static void
890 palisade_receive (
891 	struct peer * peer
892 	)
893 {
894 	struct palisade_unit *up;
895 	struct refclockproc *pp;
896 
897 	/*
898 	 * Initialize pointers and read the timecode and timestamp.
899 	 */
900 	pp = peer->procptr;
901 	up = pp->unitptr;
902 
903 	if (! TSIP_decode(peer)) return;
904 
905 	if (up->polled <= 0)
906 		return;   /* no poll pending, already received or timeout */
907 
908 	up->polled = 0;  /* Poll reply received */
909 	pp->lencode = 0; /* clear time code */
910 #ifdef DEBUG
911 	if (debug)
912 		printf(
913 			"palisade_receive: unit %d: %4d %03d %02d:%02d:%02d.%09ld\n",
914 			up->unit, pp->year, pp->day, pp->hour, pp->minute,
915 			pp->second, pp->nsec);
916 #endif
917 
918 	/*
919 	 * Process the sample
920 	 * Generate timecode: YYYY DoY HH:MM:SS.microsec
921 	 * report and process
922 	 */
923 
924 	snprintf(pp->a_lastcode, sizeof(pp->a_lastcode),
925 		 "%4d %03d %02d:%02d:%02d.%09ld",
926 		 pp->year, pp->day,
927 		 pp->hour,pp->minute, pp->second, pp->nsec);
928 	pp->lencode = 24;
929 
930 	if (!refclock_process(pp)) {
931 		refclock_report(peer, CEVNT_BADTIME);
932 
933 #ifdef DEBUG
934 		printf("palisade_receive: unit %d: refclock_process failed!\n",
935 		       up->unit);
936 #endif
937 		return;
938 	}
939 
940 	record_clock_stats(&peer->srcadr, pp->a_lastcode);
941 
942 #ifdef DEBUG
943 	if (debug)
944 		printf("palisade_receive: unit %d: %s\n",
945 		       up->unit, prettydate(&pp->lastrec));
946 #endif
947 	pp->lastref = pp->lastrec;
948 	refclock_receive(peer);
949 }
950 
951 
952 /*
953  * palisade_poll - called by the transmit procedure
954  *
955  */
956 static void
957 palisade_poll (
958 	int unit,
959 	struct peer *peer
960 	)
961 {
962 	struct palisade_unit *up;
963 	struct refclockproc *pp;
964 
965 	pp = peer->procptr;
966 	up = pp->unitptr;
967 
968 	pp->polls++;
969 	if (up->polled > 0) /* last reply never arrived or error */
970 		refclock_report(peer, CEVNT_TIMEOUT);
971 
972 	up->polled = 2; /* synchronous packet + 1 event */
973 
974 #ifdef DEBUG
975 	if (debug)
976 		printf("palisade_poll: unit %d: polling %s\n", unit,
977 		       (pp->sloppyclockflag & CLK_FLAG2) ?
978 		       "synchronous packet" : "event");
979 #endif
980 
981 	if (pp->sloppyclockflag & CLK_FLAG2)
982 		return;  /* using synchronous packet input */
983 
984 	if(up->type == CLK_PRAECIS) {
985 		if(write(peer->procptr->io.fd,"SPSTAT\r\n",8) < 0)
986 			msyslog(LOG_ERR, "Palisade(%d) write: %m:",unit);
987 		else {
988 			praecis_msg = 1;
989 			return;
990 		}
991 	}
992 
993 	if (HW_poll(pp) < 0)
994 		refclock_report(peer, CEVNT_FAULT);
995 }
996 
997 static void
998 praecis_parse (
999 	struct recvbuf *rbufp,
1000 	struct peer *peer
1001 	)
1002 {
1003 	static char buf[100];
1004 	static int p = 0;
1005 	struct refclockproc *pp;
1006 
1007 	pp = peer->procptr;
1008 
1009 	memcpy(buf+p,rbufp->recv_space.X_recv_buffer, rbufp->recv_length);
1010 	p += rbufp->recv_length;
1011 
1012 	if(buf[p-2] == '\r' && buf[p-1] == '\n') {
1013 		buf[p-2] = '\0';
1014 		record_clock_stats(&peer->srcadr, buf);
1015 
1016 		p = 0;
1017 		praecis_msg = 0;
1018 
1019 		if (HW_poll(pp) < 0)
1020 			refclock_report(peer, CEVNT_FAULT);
1021 
1022 	}
1023 }
1024 
1025 static void
1026 palisade_io (
1027 	struct recvbuf *rbufp
1028 	)
1029 {
1030 	/*
1031 	 * Initialize pointers and read the timecode and timestamp.
1032 	 */
1033 	struct palisade_unit *up;
1034 	struct refclockproc *pp;
1035 	struct peer *peer;
1036 
1037 	char * c, * d;
1038 
1039 	peer = rbufp->recv_peer;
1040 	pp = peer->procptr;
1041 	up = pp->unitptr;
1042 
1043 	if(up->type == CLK_PRAECIS) {
1044 		if(praecis_msg) {
1045 			praecis_parse(rbufp,peer);
1046 			return;
1047 		}
1048 	}
1049 
1050 	c = (char *) &rbufp->recv_space;
1051 	d = c + rbufp->recv_length;
1052 
1053 	while (c != d) {
1054 
1055 		/* Build time packet */
1056 		switch (up->rpt_status) {
1057 
1058 		    case TSIP_PARSED_DLE_1:
1059 			switch (*c)
1060 			{
1061 			    case 0:
1062 			    case DLE:
1063 			    case ETX:
1064 				up->rpt_status = TSIP_PARSED_EMPTY;
1065 				break;
1066 
1067 			    default:
1068 				up->rpt_status = TSIP_PARSED_DATA;
1069 				/* save packet ID */
1070 				up->rpt_buf[0] = *c;
1071 				break;
1072 			}
1073 			break;
1074 
1075 		    case TSIP_PARSED_DATA:
1076 			if (*c == DLE)
1077 				up->rpt_status = TSIP_PARSED_DLE_2;
1078 			else
1079 				mb(up->rpt_cnt++) = *c;
1080 			break;
1081 
1082 		    case TSIP_PARSED_DLE_2:
1083 			if (*c == DLE) {
1084 				up->rpt_status = TSIP_PARSED_DATA;
1085 				mb(up->rpt_cnt++) =
1086 				    *c;
1087 			}
1088 			else if (*c == ETX)
1089 				up->rpt_status = TSIP_PARSED_FULL;
1090 			else 	{
1091 				/* error: start new report packet */
1092 				up->rpt_status = TSIP_PARSED_DLE_1;
1093 				up->rpt_buf[0] = *c;
1094 			}
1095 			break;
1096 
1097 		    case TSIP_PARSED_FULL:
1098 		    case TSIP_PARSED_EMPTY:
1099 		    default:
1100 			if ( *c != DLE)
1101 				up->rpt_status = TSIP_PARSED_EMPTY;
1102 			else
1103 				up->rpt_status = TSIP_PARSED_DLE_1;
1104 			break;
1105 		}
1106 
1107 		c++;
1108 
1109 		if (up->rpt_status == TSIP_PARSED_DLE_1) {
1110 			up->rpt_cnt = 0;
1111 			if (pp->sloppyclockflag & CLK_FLAG2)
1112 				/* stamp it */
1113 				get_systime(&pp->lastrec);
1114 		}
1115 		else if (up->rpt_status == TSIP_PARSED_EMPTY)
1116 			up->rpt_cnt = 0;
1117 
1118 		else if (up->rpt_cnt > BMAX)
1119 			up->rpt_status =TSIP_PARSED_EMPTY;
1120 
1121 		if (up->rpt_status == TSIP_PARSED_FULL)
1122 			palisade_receive(peer);
1123 
1124 	} /* while chars in buffer */
1125 }
1126 
1127 
1128 /*
1129  * Trigger the Palisade's event input, which is driven off the RTS
1130  *
1131  * Take a system time stamp to match the GPS time stamp.
1132  *
1133  */
1134 long
1135 HW_poll (
1136 	struct refclockproc * pp 	/* pointer to unit structure */
1137 	)
1138 {
1139 	int x;	/* state before & after RTS set */
1140 	struct palisade_unit *up;
1141 
1142 	up = pp->unitptr;
1143 
1144 	/* read the current status, so we put things back right */
1145 	if (ioctl(pp->io.fd, TIOCMGET, &x) < 0) {
1146 		DPRINTF(1, ("Palisade HW_poll: unit %d: GET %m\n",
1147 			up->unit));
1148 		msyslog(LOG_ERR, "Palisade(%d) HW_poll: ioctl(fd,GET): %m",
1149 			up->unit);
1150 		return -1;
1151 	}
1152 
1153 	x |= TIOCM_RTS;        /* turn on RTS  */
1154 
1155 	/* Edge trigger */
1156 	if (up->type == CLK_ACUTIME)
1157 		write (pp->io.fd, "", 1);
1158 
1159 	if (ioctl(pp->io.fd, TIOCMSET, &x) < 0) {
1160 #ifdef DEBUG
1161 		if (debug)
1162 			printf("Palisade HW_poll: unit %d: SET \n", up->unit);
1163 #endif
1164 		msyslog(LOG_ERR,
1165 			"Palisade(%d) HW_poll: ioctl(fd, SET, RTS_on): %m",
1166 			up->unit);
1167 		return -1;
1168 	}
1169 
1170 	x &= ~TIOCM_RTS;        /* turn off RTS  */
1171 
1172 	/* poll timestamp */
1173 	get_systime(&pp->lastrec);
1174 
1175 	if (ioctl(pp->io.fd, TIOCMSET, &x) == -1) {
1176 #ifdef DEBUG
1177 		if (debug)
1178 			printf("Palisade HW_poll: unit %d: UNSET \n", up->unit);
1179 #endif
1180 		msyslog(LOG_ERR,
1181 			"Palisade(%d) HW_poll: ioctl(fd, UNSET, RTS_off): %m",
1182 			up->unit);
1183 		return -1;
1184 	}
1185 
1186 	return 0;
1187 }
1188 
1189 /*
1190  * copy/swap a big-endian palisade double into a host double
1191  */
1192 static double
1193 getdbl (
1194 	u_char *bp
1195 	)
1196 {
1197 #ifdef WORDS_BIGENDIAN
1198 	double out;
1199 
1200 	memcpy(&out, bp, sizeof(out));
1201 	return out;
1202 #else
1203 	union {
1204 		u_char ch[8];
1205 		u_int32 u32[2];
1206 	} ui;
1207 
1208 	union {
1209 		double out;
1210 		u_int32 u32[2];
1211 	} uo;
1212 
1213 	memcpy(ui.ch, bp, sizeof(ui.ch));
1214 	/* least-significant 32 bits of double from swapped bp[4] to bp[7] */
1215 	uo.u32[0] = ntohl(ui.u32[1]);
1216 	/* most-significant 32 bits from swapped bp[0] to bp[3] */
1217 	uo.u32[1] = ntohl(ui.u32[0]);
1218 
1219 	return uo.out;
1220 #endif
1221 }
1222 
1223 /*
1224  * copy/swap a big-endian palisade short into a host short
1225  */
1226 static short
1227 getint (
1228 	u_char *bp
1229 	)
1230 {
1231 	u_short us;
1232 
1233 	memcpy(&us, bp, sizeof(us));
1234 	return (short)ntohs(us);
1235 }
1236 
1237 /*
1238  * copy/swap a big-endian palisade 32-bit int into a host 32-bit int
1239  */
1240 static int32
1241 getlong(
1242 	u_char *bp
1243 	)
1244 {
1245 	u_int32 u32;
1246 
1247 	memcpy(&u32, bp, sizeof(u32));
1248 	return (int32)(u_int32)ntohl(u32);
1249 }
1250 
1251 #else	/* REFCLOCK && CLOCK_PALISADE*/
1252 int refclock_palisade_c_notempty;
1253 #endif
1254