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