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