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