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