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