refclock_palisade.c revision 200576
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#ifdef HAVE_CONFIG_H
56#include "config.h"
57#endif
58
59#if defined(REFCLOCK) && (defined(PALISADE) || defined(CLOCK_PALISADE))
60
61#ifdef SYS_WINNT
62extern int async_write(int, const void *, unsigned int);
63#undef write
64#define write(fd, data, octets)	async_write(fd, data, octets)
65#endif
66
67#include "refclock_palisade.h"
68/* Table to get from month to day of the year */
69const int days_of_year [12] = {
70	0,  31,  59,  90, 120, 151, 181, 212, 243, 273, 304, 334
71};
72
73#ifdef DEBUG
74const char * Tracking_Status[15][15] = {
75        	{ "Doing Fixes\0" }, { "Good 1SV\0" }, { "Approx. 1SV\0" },
76        	{"Need Time\0" }, { "Need INIT\0" }, { "PDOP too High\0" },
77        	{ "Bad 1SV\0" }, { "0SV Usable\0" }, { "1SV Usable\0" },
78        	{ "2SV Usable\0" }, { "3SV Usable\0" }, { "No Integrity\0" },
79        	{ "Diff Corr\0" }, { "Overdet Clock\0" }, { "Invalid\0" } };
80#endif
81
82/*
83 * Transfer vector
84 */
85struct refclock refclock_palisade = {
86	palisade_start,		/* start up driver */
87	palisade_shutdown,	/* shut down driver */
88	palisade_poll,		/* transmit poll message */
89	noentry,		/* not used  */
90	noentry,		/* initialize driver (not used) */
91	noentry,		/* not used */
92	NOFLAGS			/* not used */
93};
94
95int day_of_year P((char *dt));
96
97/* Extract the clock type from the mode setting */
98#define CLK_TYPE(x) ((int)(((x)->ttl) & 0x7F))
99
100/* Supported clock types */
101#define CLK_TRIMBLE	0	/* Trimble Palisade */
102#define CLK_PRAECIS	1	/* Endrun Technologies Praecis */
103
104int praecis_msg;
105static void praecis_parse(struct recvbuf *rbufp, struct peer *peer);
106
107/*
108 * palisade_start - open the devices and initialize data for processing
109 */
110static int
111palisade_start (
112#ifdef PALISADE
113	unit, peer
114	)
115	int unit;
116	struct peer *peer;
117#else /* ANSI */
118	int unit,
119	struct peer *peer
120	)
121#endif
122{
123	struct palisade_unit *up;
124	struct refclockproc *pp;
125	int fd;
126	char gpsdev[20];
127
128	struct termios tio;
129#ifdef SYS_WINNT
130	(void) sprintf(gpsdev, "COM%d:", unit);
131#else
132	(void) sprintf(gpsdev, DEVICE, unit);
133#endif
134	/*
135	 * Open serial port.
136	 */
137#if defined PALISADE
138	 fd = open(gpsdev, O_RDWR
139#ifdef O_NONBLOCK
140                  | O_NONBLOCK
141#endif
142                  );
143#else /* NTP 4.x */
144	fd = refclock_open(gpsdev, SPEED232, LDISC_RAW);
145#endif
146	if (fd <= 0) {
147#ifdef DEBUG
148		printf("Palisade(%d) start: open %s failed\n", unit, gpsdev);
149#endif
150		return 0;
151	}
152
153	msyslog(LOG_NOTICE, "Palisade(%d) fd: %d dev: %s", unit, fd,
154		gpsdev);
155
156#if defined PALISADE
157        tio.c_cflag = (CS8|CLOCAL|CREAD|PARENB|PARODD);
158        tio.c_iflag = (IGNBRK);
159        tio.c_oflag = (0);
160        tio.c_lflag = (0);
161
162        if (cfsetispeed(&tio, SPEED232) == -1) {
163                msyslog(LOG_ERR,"Palisade(%d) cfsetispeed(fd, &tio): %m",unit);
164#ifdef DEBUG
165                printf("Palisade(%d) cfsetispeed(fd, &tio)\n",unit);
166#endif
167                return 0;
168        }
169        if (cfsetospeed(&tio, SPEED232) == -1) {
170#ifdef DEBUG
171                printf("Palisade(%d) cfsetospeed(fd, &tio)\n",unit);
172#endif
173                msyslog(LOG_ERR,"Palisade(%d) cfsetospeed(fd, &tio): %m",unit);
174                return 0;
175        }
176#else /* NTP 4.x */
177        if (tcgetattr(fd, &tio) < 0) {
178                msyslog(LOG_ERR,
179			"Palisade(%d) tcgetattr(fd, &tio): %m",unit);
180#ifdef DEBUG
181                printf("Palisade(%d) tcgetattr(fd, &tio)\n",unit);
182#endif
183                return (0);
184        }
185
186        tio.c_cflag |= (PARENB|PARODD);
187        tio.c_iflag &= ~ICRNL;
188#endif /*  NTP 4.x */
189
190	if (tcsetattr(fd, TCSANOW, &tio) == -1) {
191                msyslog(LOG_ERR, "Palisade(%d) tcsetattr(fd, &tio): %m",unit);
192#ifdef DEBUG
193                printf("Palisade(%d) tcsetattr(fd, &tio)\n",unit);
194#endif
195                return 0;
196        }
197
198	/*
199	 * Allocate and initialize unit structure
200	 */
201	up = (struct palisade_unit *) emalloc(sizeof(struct palisade_unit));
202
203	if (!(up)) {
204                msyslog(LOG_ERR, "Palisade(%d) emalloc: %m",unit);
205#ifdef DEBUG
206                printf("Palisade(%d) emalloc\n",unit);
207#endif
208		(void) close(fd);
209		return (0);
210	}
211
212	memset((char *)up, 0, sizeof(struct palisade_unit));
213
214	up->type = CLK_TYPE(peer);
215	switch (up->type) {
216		case CLK_TRIMBLE:
217			/* Normal mode, do nothing */
218			break;
219		case CLK_PRAECIS:
220			msyslog(LOG_NOTICE, "Palisade(%d) Praecis mode enabled\n",unit);
221			break;
222		default:
223			msyslog(LOG_NOTICE, "Palisade(%d) mode unknown\n",unit);
224			break;
225	}
226
227	pp = peer->procptr;
228	pp->io.clock_recv = palisade_io;
229	pp->io.srcclock = (caddr_t)peer;
230	pp->io.datalen = 0;
231	pp->io.fd = fd;
232	if (!io_addclock(&pp->io)) {
233#ifdef DEBUG
234                printf("Palisade(%d) io_addclock\n",unit);
235#endif
236		(void) close(fd);
237		free(up);
238		return (0);
239	}
240
241	/*
242	 * Initialize miscellaneous variables
243	 */
244	pp->unitptr = (caddr_t)up;
245	pp->clockdesc = DESCRIPTION;
246
247	peer->precision = PRECISION;
248	peer->sstclktype = CTL_SST_TS_UHF;
249	peer->minpoll = TRMB_MINPOLL;
250	peer->maxpoll = TRMB_MAXPOLL;
251	memcpy((char *)&pp->refid, REFID, 4);
252
253	up->leap_status = 0;
254	up->unit = (short) unit;
255	up->rpt_status = TSIP_PARSED_EMPTY;
256    	up->rpt_cnt = 0;
257
258	return 1;
259}
260
261
262/*
263 * palisade_shutdown - shut down the clock
264 */
265static void
266palisade_shutdown (
267#ifdef PALISADE
268	unit, peer
269	)
270	int unit;
271	struct peer *peer;
272#else /* ANSI */
273	int unit,
274	struct peer *peer
275	)
276#endif
277{
278	struct palisade_unit *up;
279	struct refclockproc *pp;
280	pp = peer->procptr;
281	up = (struct palisade_unit *)pp->unitptr;
282	io_closeclock(&pp->io);
283	free(up);
284}
285
286
287
288/*
289 * unpack_date - get day and year from date
290 */
291int
292day_of_year (
293#ifdef PALISADE
294	dt
295	)
296	char * dt;
297#else
298	char * dt
299	)
300#endif
301{
302	int day, mon, year;
303
304	mon = dt[1];
305       /* Check month is inside array bounds */
306       if ((mon < 1) || (mon > 12))
307		return -1;
308
309	day = dt[0] + days_of_year[mon - 1];
310	year = getint((u_char *) (dt + 2));
311
312	if ( !(year % 4) && ((year % 100) ||
313		(!(year % 100) && !(year%400)))
314			&&(mon > 2))
315			day ++; /* leap year and March or later */
316
317	return day;
318}
319
320
321/*
322 * TSIP_decode - decode the TSIP data packets
323 */
324int
325TSIP_decode (
326#ifdef PALISADE
327	peer
328	)
329	struct peer *peer;
330#else
331	struct peer *peer
332	)
333#endif
334{
335	int st;
336	long   secint;
337	double secs;
338	double secfrac;
339	unsigned short event = 0;
340
341	struct palisade_unit *up;
342	struct refclockproc *pp;
343
344	pp = peer->procptr;
345	up = (struct palisade_unit *)pp->unitptr;
346
347	/*
348	 * Check the time packet, decode its contents.
349	 * If the timecode has invalid length or is not in
350	 * proper format, declare bad format and exit.
351	 */
352
353	if ((up->rpt_buf[0] == (char) 0x41) ||
354		(up->rpt_buf[0] == (char) 0x46) ||
355		(up->rpt_buf[0] == (char) 0x54) ||
356		(up->rpt_buf[0] == (char) 0x4B) ||
357		(up->rpt_buf[0] == (char) 0x6D)) {
358
359	/* standard time packet - GPS time and GPS week number */
360#ifdef DEBUG
361			printf("Palisade Port B packets detected. Connect to Port A\n");
362#endif
363
364		return 0;
365	}
366
367	/*
368	 * We cast both to u_char to as 0x8f uses the sign bit on a char
369	 */
370	if ((u_char) up->rpt_buf[0] == (u_char) 0x8f) {
371	/*
372	 * Superpackets
373	 */
374	   event = (unsigned short) (getint((u_char *) &mb(1)) & 0xffff);
375	   if (!((pp->sloppyclockflag & CLK_FLAG2) || event))
376		/* Ignore Packet */
377			return 0;
378
379	   switch (mb(0) & 0xff) {
380	     int GPS_UTC_Offset;
381	     case PACKET_8F0B:
382
383		if (up->polled <= 0)
384			return 0;
385
386		if (up->rpt_cnt != LENCODE_8F0B)  /* check length */
387			break;
388
389#ifdef DEBUG
390if (debug > 1) {
391		int ts;
392		double lat, lon, alt;
393		lat = getdbl((u_char *) &mb(42)) * R2D;
394		lon = getdbl((u_char *) &mb(50)) * R2D;
395		alt = getdbl((u_char *) &mb(58));
396
397  		printf("TSIP_decode: unit %d: Latitude: %03.4f Longitude: %03.4f Alt: %05.2f m\n",
398				up->unit, lat,lon,alt);
399  		printf("TSIP_decode: unit %d: Sats:", up->unit);
400		for (st = 66, ts = 0; st <= 73; st++) if (mb(st)) {
401			if (mb(st) > 0) ts++;
402			printf(" %02d", mb(st));
403		}
404		printf(" : Tracking %d\n", ts);
405	}
406#endif
407
408		GPS_UTC_Offset = getint((u_char *) &mb(16));
409		if (GPS_UTC_Offset == 0) { /* Check UTC offset */
410#ifdef DEBUG
411			 printf("TSIP_decode: UTC Offset Unknown\n");
412#endif
413			break;
414		}
415
416		secs = getdbl((u_char *) &mb(3));
417		secint = (long) secs;
418		secfrac = secs - secint; /* 0.0 <= secfrac < 1.0 */
419
420		pp->nsec = (long) (secfrac * 1000000000);
421
422		secint %= 86400;    /* Only care about today */
423		pp->hour = secint / 3600;
424		secint %= 3600;
425		pp->minute = secint / 60;
426		secint %= 60;
427		pp->second = secint % 60;
428
429		if ((pp->day = day_of_year(&mb(11))) < 0) break;
430
431		pp->year = getint((u_char *) &mb(13));
432
433#ifdef DEBUG
434	if (debug > 1)
435		printf("TSIP_decode: unit %d: %02X #%d %02d:%02d:%02d.%06ld %02d/%02d/%04d UTC %02d\n",
436 			up->unit, mb(0) & 0xff, event, pp->hour, pp->minute,
437			pp->second, pp->nsec, mb(12), mb(11), pp->year, GPS_UTC_Offset);
438#endif
439		/* Only use this packet when no
440		 * 8F-AD's are being received
441		 */
442
443		if (up->leap_status) {
444			up->leap_status = 0;
445			return 0;
446		}
447
448		return 2;
449		break;
450
451	  case PACKET_NTP:
452		/* Palisade-NTP Packet */
453
454		if (up->rpt_cnt != LENCODE_NTP) /* check length */
455			break;
456
457		up->leap_status = mb(19);
458
459		if (up->polled  <= 0)
460			return 0;
461
462		/* Check Tracking Status */
463		st = mb(18);
464		if (st < 0 || st > 14) st = 14;
465		if ((st >= 2 && st <= 7) || st == 11 || st == 12) {
466#ifdef DEBUG
467		 printf("TSIP_decode: Not Tracking Sats : %s\n",
468				*Tracking_Status[st]);
469#endif
470			refclock_report(peer, CEVNT_BADTIME);
471			up->polled = -1;
472			return 0;
473			break;
474		}
475
476		if (up->leap_status & PALISADE_LEAP_PENDING) {
477			if (up->leap_status & PALISADE_UTC_TIME)
478				pp->leap = LEAP_ADDSECOND;
479			else
480				pp->leap = LEAP_DELSECOND;
481		}
482		else if (up->leap_status)
483			pp->leap = LEAP_NOWARNING;
484
485		else {  /* UTC flag is not set:
486			 * Receiver may have been reset, and lost
487			 * its UTC almanac data */
488			pp->leap = LEAP_NOTINSYNC;
489#ifdef DEBUG
490			 printf("TSIP_decode: UTC Almanac unavailable: %d\n",
491				mb(19));
492#endif
493			refclock_report(peer, CEVNT_BADTIME);
494			up->polled = -1;
495			return 0;
496		}
497
498		pp->nsec = (long) (getdbl((u_char *) &mb(3)) * 1000000000);
499
500		if ((pp->day = day_of_year(&mb(14))) < 0)
501			break;
502		pp->year = getint((u_char *) &mb(16));
503		pp->hour = mb(11);
504		pp->minute = mb(12);
505		pp->second = mb(13);
506
507#ifdef DEBUG
508	if (debug > 1)
509printf("TSIP_decode: unit %d: %02X #%d %02d:%02d:%02d.%06ld %02d/%02d/%04d UTC %02x %s\n",
510 			up->unit, mb(0) & 0xff, event, pp->hour, pp->minute,
511			pp->second, pp->nsec, mb(15), mb(14), pp->year,
512			mb(19), *Tracking_Status[st]);
513#endif
514		return 1;
515		break;
516
517	  default:
518		/* Ignore Packet */
519		return 0;
520	  } /* switch */
521	}/* if 8F packets */
522
523	refclock_report(peer, CEVNT_BADREPLY);
524	up->polled = -1;
525#ifdef DEBUG
526	printf("TSIP_decode: unit %d: bad packet %02x-%02x event %d len %d\n",
527		   up->unit, up->rpt_buf[0] & 0xff, mb(0) & 0xff,
528			event, up->rpt_cnt);
529#endif
530	return 0;
531}
532
533/*
534 * palisade__receive - receive data from the serial interface
535 */
536
537static void
538palisade_receive (
539#ifdef PALISADE
540	peer
541	)
542	struct peer * peer;
543#else /* ANSI */
544	struct peer * peer
545	)
546#endif
547{
548	struct palisade_unit *up;
549	struct refclockproc *pp;
550
551	/*
552	 * Initialize pointers and read the timecode and timestamp.
553	 */
554	pp = peer->procptr;
555	up = (struct palisade_unit *)pp->unitptr;
556
557	if (! TSIP_decode(peer)) return;
558
559	if (up->polled <= 0)
560	    return;   /* no poll pending, already received or timeout */
561
562	up->polled = 0;  /* Poll reply received */
563	pp->lencode = 0; /* clear time code */
564#ifdef DEBUG
565	if (debug)
566		printf(
567	"palisade_receive: unit %d: %4d %03d %02d:%02d:%02d.%06ld\n",
568			up->unit, pp->year, pp->day, pp->hour, pp->minute,
569			pp->second, pp->nsec);
570#endif
571
572	/*
573	 * Process the sample
574	 * Generate timecode: YYYY DoY HH:MM:SS.microsec
575	 * report and process
576	 */
577
578	(void) sprintf(pp->a_lastcode,"%4d %03d %02d:%02d:%02d.%06ld",
579		   pp->year,pp->day,pp->hour,pp->minute, pp->second,pp->nsec);
580	pp->lencode = 24;
581
582#ifdef PALISADE
583    	pp->lasttime = current_time;
584#endif
585	if (!refclock_process(pp
586#ifdef PALISADE
587		, PALISADE_SAMPLES, PALISADE_SAMPLES * 3 / 5
588#endif
589		)) {
590		refclock_report(peer, CEVNT_BADTIME);
591
592#ifdef DEBUG
593		printf("palisade_receive: unit %d: refclock_process failed!\n",
594			up->unit);
595#endif
596		return;
597	}
598
599	record_clock_stats(&peer->srcadr, pp->a_lastcode);
600
601#ifdef DEBUG
602	if (debug)
603	    printf("palisade_receive: unit %d: %s\n",
604		   up->unit, prettydate(&pp->lastrec));
605#endif
606	pp->lastref = pp->lastrec;
607	refclock_receive(peer
608#ifdef PALISADE
609		, &pp->offset, 0, pp->dispersion,
610              &pp->lastrec, &pp->lastrec, pp->leap
611#endif
612		);
613}
614
615
616/*
617 * palisade_poll - called by the transmit procedure
618 *
619 */
620static void
621palisade_poll (
622#ifdef PALISADE
623	unit, peer
624	)
625	int unit;
626	struct peer *peer;
627#else
628	int unit,
629	struct peer *peer
630	)
631#endif
632{
633	struct palisade_unit *up;
634	struct refclockproc *pp;
635
636	pp = peer->procptr;
637	up = (struct palisade_unit *)pp->unitptr;
638
639	pp->polls++;
640	if (up->polled > 0) /* last reply never arrived or error */
641	    refclock_report(peer, CEVNT_TIMEOUT);
642
643	up->polled = 2; /* synchronous packet + 1 event */
644
645#ifdef DEBUG
646	if (debug)
647	    printf("palisade_poll: unit %d: polling %s\n", unit,
648		   (pp->sloppyclockflag & CLK_FLAG2) ?
649			"synchronous packet" : "event");
650#endif
651
652	if (pp->sloppyclockflag & CLK_FLAG2)
653	    return;  /* using synchronous packet input */
654
655	if(up->type == CLK_PRAECIS) {
656		if(write(peer->procptr->io.fd,"SPSTAT\r\n",8) < 0)
657			msyslog(LOG_ERR, "Palisade(%d) write: %m:",unit);
658		else {
659			praecis_msg = 1;
660			return;
661		}
662	}
663
664	if (HW_poll(pp) < 0)
665	    refclock_report(peer, CEVNT_FAULT);
666}
667
668static void
669praecis_parse(struct recvbuf *rbufp, struct peer *peer)
670{
671	static char buf[100];
672	static int p = 0;
673	struct refclockproc *pp;
674
675	pp = peer->procptr;
676
677	memcpy(buf+p,rbufp->recv_space.X_recv_buffer, rbufp->recv_length);
678	p += rbufp->recv_length;
679
680	if(buf[p-2] == '\r' && buf[p-1] == '\n') {
681		buf[p-2] = '\0';
682		record_clock_stats(&peer->srcadr, buf);
683
684		p = 0;
685		praecis_msg = 0;
686
687		if (HW_poll(pp) < 0)
688			refclock_report(peer, CEVNT_FAULT);
689
690	}
691}
692
693static void
694palisade_io (
695#ifdef PALISADE
696	rbufp
697	)
698	struct recvbuf *rbufp;
699#else /* ANSI */
700	struct recvbuf *rbufp
701	)
702#endif
703{
704	/*
705	 * Initialize pointers and read the timecode and timestamp.
706	 */
707	struct palisade_unit *up;
708	struct refclockproc *pp;
709	struct peer *peer;
710
711	char * c, * d;
712
713	peer = (struct peer *)rbufp->recv_srcclock;
714	pp = peer->procptr;
715	up = (struct palisade_unit *)pp->unitptr;
716
717	if(up->type == CLK_PRAECIS) {
718		if(praecis_msg) {
719			praecis_parse(rbufp,peer);
720			return;
721		}
722	}
723
724	c = (char *) &rbufp->recv_space;
725	d = c + rbufp->recv_length;
726
727	while (c != d) {
728
729		/* Build time packet */
730		switch (up->rpt_status) {
731
732		    case TSIP_PARSED_DLE_1:
733			switch (*c)
734			{
735			    case 0:
736			    case DLE:
737			    case ETX:
738				up->rpt_status = TSIP_PARSED_EMPTY;
739				break;
740
741			    default:
742				up->rpt_status = TSIP_PARSED_DATA;
743				/* save packet ID */
744				up->rpt_buf[0] = *c;
745				break;
746			}
747			break;
748
749		    case TSIP_PARSED_DATA:
750			if (*c == DLE)
751			    up->rpt_status = TSIP_PARSED_DLE_2;
752			else
753			    mb(up->rpt_cnt++) = *c;
754			break;
755
756		    case TSIP_PARSED_DLE_2:
757			if (*c == DLE) {
758				up->rpt_status = TSIP_PARSED_DATA;
759				mb(up->rpt_cnt++) =
760						*c;
761			}
762			else if (*c == ETX)
763				    up->rpt_status = TSIP_PARSED_FULL;
764			else 	{
765                        	/* error: start new report packet */
766				up->rpt_status = TSIP_PARSED_DLE_1;
767				up->rpt_buf[0] = *c;
768			}
769			break;
770
771		    case TSIP_PARSED_FULL:
772		    case TSIP_PARSED_EMPTY:
773		    default:
774		        if ( *c != DLE)
775                          up->rpt_status = TSIP_PARSED_EMPTY;
776                else
777                          up->rpt_status = TSIP_PARSED_DLE_1;
778                        break;
779		}
780
781		c++;
782
783		if (up->rpt_status == TSIP_PARSED_DLE_1) {
784		    up->rpt_cnt = 0;
785			if (pp->sloppyclockflag & CLK_FLAG2)
786                		/* stamp it */
787                       	get_systime(&pp->lastrec);
788		}
789		else if (up->rpt_status == TSIP_PARSED_EMPTY)
790		    	up->rpt_cnt = 0;
791
792		else if (up->rpt_cnt > BMAX)
793			up->rpt_status =TSIP_PARSED_EMPTY;
794
795		if (up->rpt_status == TSIP_PARSED_FULL)
796			palisade_receive(peer);
797
798	} /* while chars in buffer */
799}
800
801
802/*
803 * Trigger the Palisade's event input, which is driven off the RTS
804 *
805 * Take a system time stamp to match the GPS time stamp.
806 *
807 */
808long
809HW_poll (
810#ifdef PALISADE
811	pp 	/* pointer to unit structure */
812	)
813	struct refclockproc * pp;	/* pointer to unit structure */
814#else
815	struct refclockproc * pp 	/* pointer to unit structure */
816	)
817#endif
818{
819	int x;	/* state before & after RTS set */
820	struct palisade_unit *up;
821
822	up = (struct palisade_unit *) pp->unitptr;
823
824	/* read the current status, so we put things back right */
825	if (ioctl(pp->io.fd, TIOCMGET, &x) < 0) {
826#ifdef DEBUG
827	if (debug)
828	    printf("Palisade HW_poll: unit %d: GET %s\n", up->unit, strerror(errno));
829#endif
830		msyslog(LOG_ERR, "Palisade(%d) HW_poll: ioctl(fd,GET): %m",
831			up->unit);
832		return -1;
833	}
834
835	x |= TIOCM_RTS;        /* turn on RTS  */
836
837	/* Edge trigger */
838	if (ioctl(pp->io.fd, TIOCMSET, &x) < 0) {
839#ifdef DEBUG
840	if (debug)
841	    printf("Palisade HW_poll: unit %d: SET \n", up->unit);
842#endif
843		msyslog(LOG_ERR,
844			"Palisade(%d) HW_poll: ioctl(fd, SET, RTS_on): %m",
845			up->unit);
846		return -1;
847	}
848
849	x &= ~TIOCM_RTS;        /* turn off RTS  */
850
851	/* poll timestamp */
852	get_systime(&pp->lastrec);
853
854	if (ioctl(pp->io.fd, TIOCMSET, &x) == -1) {
855#ifdef DEBUG
856	if (debug)
857	    printf("Palisade HW_poll: unit %d: UNSET \n", up->unit);
858#endif
859		msyslog(LOG_ERR,
860			"Palisade(%d) HW_poll: ioctl(fd, UNSET, RTS_off): %m",
861			up->unit);
862		return -1;
863	}
864
865	return 0;
866}
867
868#if 0 /* unused */
869/*
870 * this 'casts' a character array into a float
871 */
872float
873getfloat (
874#ifdef PALISADE
875	bp
876	)
877	u_char *bp;
878#else
879	u_char *bp
880	)
881#endif
882{
883	float sval;
884#ifdef WORDS_BIGENDIAN
885	((char *) &sval)[0] = *bp++;
886	((char *) &sval)[1] = *bp++;
887	((char *) &sval)[2] = *bp++;
888	((char *) &sval)[3] = *bp++;
889#else
890	((char *) &sval)[3] = *bp++;
891	((char *) &sval)[2] = *bp++;
892	((char *) &sval)[1] = *bp++;
893	((char *) &sval)[0] = *bp;
894#endif  /* ! XNTP_BIG_ENDIAN */
895	return sval;
896}
897#endif
898
899/*
900 * this 'casts' a character array into a double
901 */
902double
903getdbl (
904#ifdef PALISADE
905	bp
906	)
907	u_char *bp;
908#else
909	u_char *bp
910	)
911#endif
912{
913	double dval;
914#ifdef WORDS_BIGENDIAN
915	((char *) &dval)[0] = *bp++;
916	((char *) &dval)[1] = *bp++;
917	((char *) &dval)[2] = *bp++;
918	((char *) &dval)[3] = *bp++;
919	((char *) &dval)[4] = *bp++;
920	((char *) &dval)[5] = *bp++;
921	((char *) &dval)[6] = *bp++;
922	((char *) &dval)[7] = *bp;
923#else
924	((char *) &dval)[7] = *bp++;
925	((char *) &dval)[6] = *bp++;
926	((char *) &dval)[5] = *bp++;
927	((char *) &dval)[4] = *bp++;
928	((char *) &dval)[3] = *bp++;
929	((char *) &dval)[2] = *bp++;
930	((char *) &dval)[1] = *bp++;
931	((char *) &dval)[0] = *bp;
932#endif  /* ! XNTP_BIG_ENDIAN */
933	return dval;
934}
935
936/*
937 * cast a 16 bit character array into a short (16 bit) int
938 */
939short
940getint (
941#ifdef PALISADE
942	bp
943	)
944	u_char *bp;
945#else
946	u_char *bp
947	)
948#endif
949{
950return (short) (bp[1] + (bp[0] << 8));
951}
952
953#else
954int refclock_palisade_bs;
955#endif /* REFCLOCK */
956