xref: /freebsd/contrib/ntp/ntpd/refclock_palisade.c (revision 884a2a699669ec61e2366e3e358342dbc94be24a)
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
62 extern 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 */
69 const int days_of_year [12] = {
70 	0,  31,  59,  90, 120, 151, 181, 212, 243, 273, 304, 334
71 };
72 
73 #ifdef DEBUG
74 const 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  */
85 struct 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 
95 int 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 
104 int praecis_msg;
105 static void praecis_parse(struct recvbuf *rbufp, struct peer *peer);
106 
107 /*
108  * palisade_start - open the devices and initialize data for processing
109  */
110 static int
111 palisade_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  */
265 static void
266 palisade_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  */
291 int
292 day_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  */
324 int
325 TSIP_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
390 if (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)
509 printf("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 
537 static void
538 palisade_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  */
620 static void
621 palisade_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 
668 static void
669 praecis_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 
693 static void
694 palisade_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  */
808 long
809 HW_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  */
872 float
873 getfloat (
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  */
902 double
903 getdbl (
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  */
939 short
940 getint (
941 #ifdef PALISADE
942 	bp
943 	)
944 	u_char *bp;
945 #else
946 	u_char *bp
947 	)
948 #endif
949 {
950 return (short) (bp[1] + (bp[0] << 8));
951 }
952 
953 #else
954 int refclock_palisade_bs;
955 #endif /* REFCLOCK */
956