Patrick Welche <prlw1@cam.ac.uk>
[netbsd-mini2440.git] / external / bsd / ntp / dist / ntpd / refclock_palisade.c
blob835a598c01d5f77e4b7a90d7abb91bfb686c0519
1 /* $NetBSD$ */
3 /*
4 * This software was developed by the Software and Component Technologies
5 * group of Trimble Navigation, Ltd.
7 * Copyright (c) 1997, 1998, 1999, 2000 Trimble Navigation Ltd.
8 * All rights reserved.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by Trimble Navigation, Ltd.
21 * 4. The name of Trimble Navigation Ltd. may not be used to endorse or
22 * promote products derived from this software without specific prior
23 * written permission.
25 * THIS SOFTWARE IS PROVIDED BY TRIMBLE NAVIGATION LTD. ``AS IS'' AND
26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 * ARE DISCLAIMED. IN NO EVENT SHALL TRIMBLE NAVIGATION LTD. BE LIABLE
29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 * SUCH DAMAGE.
39 * refclock_palisade - clock driver for the Trimble Palisade GPS
40 * timing receiver
42 * For detailed information on this program, please refer to the html
43 * Refclock 29 page accompanying the NTP distribution.
45 * for questions / bugs / comments, contact:
46 * sven_dietrich@trimble.com
48 * Sven-Thorsten Dietrich
49 * 645 North Mary Avenue
50 * Post Office Box 3642
51 * Sunnyvale, CA 94088-3642
53 * Version 2.45; July 14, 1999
57 * 31/03/06: Added support for Thunderbolt GPS Disciplined Clock.
58 * Contact: Fernando Pablo Hauscarriaga
59 * E-mail: fernandoph@iar.unlp.edu.ar
60 * Home page: www.iar.unlp.edu.ar/~fernandoph
61 * Instituto Argentino de Radioastronomia
62 * www.iar.unlp.edu.ar
64 * 14/01/07: Conditinal compilation for Thunderbolt support no longer needed
65 * now we use mode 2 for decode thunderbolt packets.
66 * Fernando P. Hauscarriaga
68 * 30/08/09: Added support for Trimble Acutime Gold Receiver.
69 * Fernando P. Hauscarriaga (fernandoph@iar.unlp.edu.ar)
72 #ifdef HAVE_CONFIG_H
73 # include "config.h"
74 #endif
76 #if defined(REFCLOCK) && (defined(PALISADE) || defined(CLOCK_PALISADE))
78 #ifdef SYS_WINNT
79 extern int async_write(int, const void *, unsigned int);
80 #undef write
81 #define write(fd, data, octets) async_write(fd, data, octets)
82 #endif
84 #include "refclock_palisade.h"
85 /* Table to get from month to day of the year */
86 const int days_of_year [12] = {
87 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334
90 #ifdef DEBUG
91 const char * Tracking_Status[15][15] = {
92 { "Doing Fixes\0" }, { "Good 1SV\0" }, { "Approx. 1SV\0" },
93 {"Need Time\0" }, { "Need INIT\0" }, { "PDOP too High\0" },
94 { "Bad 1SV\0" }, { "0SV Usable\0" }, { "1SV Usable\0" },
95 { "2SV Usable\0" }, { "3SV Usable\0" }, { "No Integrity\0" },
96 { "Diff Corr\0" }, { "Overdet Clock\0" }, { "Invalid\0" } };
97 #endif
100 * Transfer vector
102 struct refclock refclock_palisade = {
103 palisade_start, /* start up driver */
104 palisade_shutdown, /* shut down driver */
105 palisade_poll, /* transmit poll message */
106 noentry, /* not used */
107 noentry, /* initialize driver (not used) */
108 noentry, /* not used */
109 NOFLAGS /* not used */
112 int day_of_year (char *dt);
114 /* Extract the clock type from the mode setting */
115 #define CLK_TYPE(x) ((int)(((x)->ttl) & 0x7F))
117 /* Supported clock types */
118 #define CLK_TRIMBLE 0 /* Trimble Palisade */
119 #define CLK_PRAECIS 1 /* Endrun Technologies Praecis */
120 #define CLK_THUNDERBOLT 2 /* Trimble Thunderbolt GPS Receiver */
121 #define CLK_ACUTIME 3 /* Trimble Acutime Gold */
122 #define CLK_ACUTIMEB 4 /* Trimble Actutime Gold Port B */
124 int praecis_msg;
125 static void praecis_parse(struct recvbuf *rbufp, struct peer *peer);
127 /* These routines are for sending packets to the Thunderbolt receiver
128 * They are taken from Markus Prosch
131 #ifdef PALISADE_SENDCMD_RESURRECTED
133 * sendcmd - Build data packet for sending
135 static void
136 sendcmd (
137 struct packettx *buffer,
138 int c
141 *buffer->data = DLE;
142 *(buffer->data + 1) = (unsigned char)c;
143 buffer->size = 2;
145 #endif /* PALISADE_SENDCMD_RESURRECTED */
148 * sendsupercmd - Build super data packet for sending
150 static void
151 sendsupercmd (
152 struct packettx *buffer,
153 int c1,
154 int c2
157 *buffer->data = DLE;
158 *(buffer->data + 1) = (unsigned char)c1;
159 *(buffer->data + 2) = (unsigned char)c2;
160 buffer->size = 3;
164 * sendbyte -
166 static void
167 sendbyte (
168 struct packettx *buffer,
169 int b
172 if (b == DLE)
173 *(buffer->data+buffer->size++) = DLE;
174 *(buffer->data+buffer->size++) = (unsigned char)b;
178 * sendint -
180 static void
181 sendint (
182 struct packettx *buffer,
183 int a
186 sendbyte(buffer, (unsigned char)((a>>8) & 0xff));
187 sendbyte(buffer, (unsigned char)(a & 0xff));
191 * sendetx - Send packet or super packet to the device
193 static int
194 sendetx (
195 struct packettx *buffer,
196 int fd
199 int result;
201 *(buffer->data+buffer->size++) = DLE;
202 *(buffer->data+buffer->size++) = ETX;
203 result = write(fd, buffer->data, (unsigned long)buffer->size);
205 if (result != -1)
206 return (result);
207 else
208 return (-1);
212 * init_thunderbolt - Prepares Thunderbolt receiver to be used with
213 * NTP (also taken from Markus Prosch).
215 static void
216 init_thunderbolt (
217 int fd
220 struct packettx tx;
222 tx.size = 0;
223 tx.data = (u_char *) malloc(100);
225 /* set UTC time */
226 sendsupercmd (&tx, 0x8E, 0xA2);
227 sendbyte (&tx, 0x3);
228 sendetx (&tx, fd);
230 /* activate packets 0x8F-AB and 0x8F-AC */
231 sendsupercmd (&tx, 0x8F, 0xA5);
232 sendint (&tx, 0x5);
233 sendetx (&tx, fd);
235 free(tx.data);
239 * init_acutime - Prepares Acutime Receiver to be used with NTP
241 static void
242 init_acutime (
243 int fd
246 /* Disable all outputs, Enable Event-Polling on PortA so
247 we can ask for time packets */
248 struct packettx tx;
250 tx.size = 0;
251 tx.data = (u_char *) malloc(100);
253 sendsupercmd(&tx, 0x8E, 0xA5);
254 sendbyte(&tx, 0x02);
255 sendbyte(&tx, 0x00);
256 sendbyte(&tx, 0x00);
257 sendbyte(&tx, 0x00);
258 sendetx(&tx, fd);
260 free(tx.data);
264 * palisade_start - open the devices and initialize data for processing
266 static int
267 palisade_start (
268 int unit,
269 struct peer *peer
272 struct palisade_unit *up;
273 struct refclockproc *pp;
274 int fd;
275 char gpsdev[20];
276 struct termios tio;
278 (void) sprintf(gpsdev, DEVICE, unit);
281 * Open serial port.
283 fd = refclock_open(gpsdev, SPEED232, LDISC_RAW);
284 if (fd <= 0) {
285 #ifdef DEBUG
286 printf("Palisade(%d) start: open %s failed\n", unit, gpsdev);
287 #endif
288 return 0;
291 msyslog(LOG_NOTICE, "Palisade(%d) fd: %d dev: %s", unit, fd,
292 gpsdev);
294 if (tcgetattr(fd, &tio) < 0) {
295 msyslog(LOG_ERR,
296 "Palisade(%d) tcgetattr(fd, &tio): %m",unit);
297 #ifdef DEBUG
298 printf("Palisade(%d) tcgetattr(fd, &tio)\n",unit);
299 #endif
300 close(fd);
301 return (0);
304 tio.c_cflag |= (PARENB|PARODD);
305 tio.c_iflag &= ~ICRNL;
308 * Allocate and initialize unit structure
310 up = (struct palisade_unit *) emalloc(sizeof(struct palisade_unit));
312 memset((char *)up, 0, sizeof(struct palisade_unit));
314 up->type = CLK_TYPE(peer);
315 switch (up->type) {
316 case CLK_TRIMBLE:
317 /* Normal mode, do nothing */
318 break;
319 case CLK_PRAECIS:
320 msyslog(LOG_NOTICE, "Palisade(%d) Praecis mode enabled\n"
321 ,unit);
322 break;
323 case CLK_THUNDERBOLT:
324 msyslog(LOG_NOTICE, "Palisade(%d) Thunderbolt mode enabled\n"
325 ,unit);
326 tio.c_cflag = (CS8|CLOCAL|CREAD);
327 break;
328 case CLK_ACUTIME:
329 msyslog(LOG_NOTICE, "Palisade(%d) Acutime Gold mode enabled\n"
330 ,unit);
331 break;
332 default:
333 msyslog(LOG_NOTICE, "Palisade(%d) mode unknown\n",unit);
334 break;
336 if (tcsetattr(fd, TCSANOW, &tio) == -1) {
337 msyslog(LOG_ERR, "Palisade(%d) tcsetattr(fd, &tio): %m",unit);
338 #ifdef DEBUG
339 printf("Palisade(%d) tcsetattr(fd, &tio)\n",unit);
340 #endif
341 close(fd);
342 free(up);
343 return 0;
346 pp = peer->procptr;
347 pp->io.clock_recv = palisade_io;
348 pp->io.srcclock = (caddr_t)peer;
349 pp->io.datalen = 0;
350 pp->io.fd = fd;
351 if (!io_addclock(&pp->io)) {
352 #ifdef DEBUG
353 printf("Palisade(%d) io_addclock\n",unit);
354 #endif
355 (void) close(fd);
356 free(up);
357 return (0);
361 * Initialize miscellaneous variables
363 pp->unitptr = (caddr_t)up;
364 pp->clockdesc = DESCRIPTION;
366 peer->precision = PRECISION;
367 peer->sstclktype = CTL_SST_TS_UHF;
368 peer->minpoll = TRMB_MINPOLL;
369 peer->maxpoll = TRMB_MAXPOLL;
370 memcpy((char *)&pp->refid, REFID, 4);
372 up->leap_status = 0;
373 up->unit = (short) unit;
374 up->rpt_status = TSIP_PARSED_EMPTY;
375 up->rpt_cnt = 0;
377 if (up->type == CLK_THUNDERBOLT)
378 init_thunderbolt(fd);
379 if (up->type == CLK_ACUTIME)
380 init_acutime(fd);
382 return 1;
387 * palisade_shutdown - shut down the clock
389 static void
390 palisade_shutdown (
391 int unit,
392 struct peer *peer
395 struct palisade_unit *up;
396 struct refclockproc *pp;
397 pp = peer->procptr;
398 up = (struct palisade_unit *)pp->unitptr;
399 io_closeclock(&pp->io);
400 free(up);
406 * unpack_date - get day and year from date
409 day_of_year (
410 char * dt
413 int day, mon, year;
415 mon = dt[1];
416 /* Check month is inside array bounds */
417 if ((mon < 1) || (mon > 12))
418 return -1;
420 day = dt[0] + days_of_year[mon - 1];
421 year = getint((u_char *) (dt + 2));
423 if ( !(year % 4) && ((year % 100) ||
424 (!(year % 100) && !(year%400)))
425 &&(mon > 2))
426 day ++; /* leap year and March or later */
428 return day;
433 * TSIP_decode - decode the TSIP data packets
436 TSIP_decode (
437 struct peer *peer
440 int st;
441 long secint;
442 double secs;
443 double secfrac;
444 unsigned short event = 0;
446 struct palisade_unit *up;
447 struct refclockproc *pp;
449 pp = peer->procptr;
450 up = (struct palisade_unit *)pp->unitptr;
453 * Check the time packet, decode its contents.
454 * If the timecode has invalid length or is not in
455 * proper format, declare bad format and exit.
458 if ((up->type != CLK_THUNDERBOLT) & (up->type != CLK_ACUTIME)){
459 if ((up->rpt_buf[0] == (char) 0x41) ||
460 (up->rpt_buf[0] == (char) 0x46) ||
461 (up->rpt_buf[0] == (char) 0x54) ||
462 (up->rpt_buf[0] == (char) 0x4B) ||
463 (up->rpt_buf[0] == (char) 0x6D)) {
465 /* standard time packet - GPS time and GPS week number */
466 #ifdef DEBUG
467 printf("Palisade Port B packets detected. Connect to Port A\n");
468 #endif
470 return 0;
475 * We cast both to u_char to as 0x8f uses the sign bit on a char
477 if ((u_char) up->rpt_buf[0] == (u_char) 0x8f) {
479 * Superpackets
481 event = (unsigned short) (getint((u_char *) &mb(1)) & 0xffff);
482 if (!((pp->sloppyclockflag & CLK_FLAG2) || event))
483 /* Ignore Packet */
484 return 0;
486 switch (mb(0) & 0xff) {
487 int GPS_UTC_Offset;
488 long tow;
490 case PACKET_8F0B:
492 if (up->polled <= 0)
493 return 0;
495 if (up->rpt_cnt != LENCODE_8F0B) /* check length */
496 break;
498 #ifdef DEBUG
499 if (debug > 1) {
500 int ts;
501 double lat, lon, alt;
502 lat = getdbl((u_char *) &mb(42)) * R2D;
503 lon = getdbl((u_char *) &mb(50)) * R2D;
504 alt = getdbl((u_char *) &mb(58));
506 printf("TSIP_decode: unit %d: Latitude: %03.4f Longitude: %03.4f Alt: %05.2f m\n",
507 up->unit, lat,lon,alt);
508 printf("TSIP_decode: unit %d: Sats:",
509 up->unit);
510 for (st = 66, ts = 0; st <= 73; st++)
511 if (mb(st)) {
512 if (mb(st) > 0) ts++;
513 printf(" %02d", mb(st));
515 printf(" : Tracking %d\n", ts);
517 #endif
519 GPS_UTC_Offset = getint((u_char *) &mb(16));
520 if (GPS_UTC_Offset == 0) { /* Check UTC offset */
521 #ifdef DEBUG
522 printf("TSIP_decode: UTC Offset Unknown\n");
523 #endif
524 break;
527 secs = getdbl((u_char *) &mb(3));
528 secint = (long) secs;
529 secfrac = secs - secint; /* 0.0 <= secfrac < 1.0 */
531 pp->nsec = (long) (secfrac * 1000000000);
533 secint %= 86400; /* Only care about today */
534 pp->hour = secint / 3600;
535 secint %= 3600;
536 pp->minute = secint / 60;
537 secint %= 60;
538 pp->second = secint % 60;
540 if ((pp->day = day_of_year(&mb(11))) < 0) break;
542 pp->year = getint((u_char *) &mb(13));
544 #ifdef DEBUG
545 if (debug > 1)
546 printf("TSIP_decode: unit %d: %02X #%d %02d:%02d:%02d.%06ld %02d/%02d/%04d UTC %02d\n",
547 up->unit, mb(0) & 0xff, event, pp->hour, pp->minute,
548 pp->second, pp->nsec, mb(12), mb(11), pp->year, GPS_UTC_Offset);
549 #endif
550 /* Only use this packet when no
551 * 8F-AD's are being received
554 if (up->leap_status) {
555 up->leap_status = 0;
556 return 0;
559 return 2;
560 break;
562 case PACKET_NTP:
563 /* Palisade-NTP Packet */
565 if (up->rpt_cnt != LENCODE_NTP) /* check length */
566 break;
568 up->leap_status = mb(19);
570 if (up->polled <= 0)
571 return 0;
573 /* Check Tracking Status */
574 st = mb(18);
575 if (st < 0 || st > 14)
576 st = 14;
577 if ((st >= 2 && st <= 7) || st == 11 || st == 12) {
578 #ifdef DEBUG
579 printf("TSIP_decode: Not Tracking Sats : %s\n",
580 *Tracking_Status[st]);
581 #endif
582 refclock_report(peer, CEVNT_BADTIME);
583 up->polled = -1;
584 return 0;
585 break;
588 if (up->leap_status & PALISADE_LEAP_PENDING) {
589 if (up->leap_status & PALISADE_UTC_TIME)
590 pp->leap = LEAP_ADDSECOND;
591 else
592 pp->leap = LEAP_DELSECOND;
594 else if (up->leap_status)
595 pp->leap = LEAP_NOWARNING;
597 else { /* UTC flag is not set:
598 * Receiver may have been reset, and lost
599 * its UTC almanac data */
600 pp->leap = LEAP_NOTINSYNC;
601 #ifdef DEBUG
602 printf("TSIP_decode: UTC Almanac unavailable: %d\n",
603 mb(19));
604 #endif
605 refclock_report(peer, CEVNT_BADTIME);
606 up->polled = -1;
607 return 0;
610 pp->nsec = (long) (getdbl((u_char *) &mb(3))
611 * 1000000000);
613 if ((pp->day = day_of_year(&mb(14))) < 0)
614 break;
615 pp->year = getint((u_char *) &mb(16));
616 pp->hour = mb(11);
617 pp->minute = mb(12);
618 pp->second = mb(13);
620 #ifdef DEBUG
621 if (debug > 1)
622 printf("TSIP_decode: unit %d: %02X #%d %02d:%02d:%02d.%06ld %02d/%02d/%04d UTC %02x %s\n",
623 up->unit, mb(0) & 0xff, event, pp->hour, pp->minute,
624 pp->second, pp->nsec, mb(15), mb(14), pp->year,
625 mb(19), *Tracking_Status[st]);
626 #endif
627 return 1;
628 break;
630 case PACKET_8FAC:
631 if (up->polled <= 0)
632 return 0;
634 if (up->rpt_cnt != LENCODE_8FAC)/* check length */
635 break;
637 #ifdef DEBUG
638 if (debug > 1) {
639 double lat, lon, alt;
640 lat = getdbl((u_char *) &mb(36)) * R2D;
641 lon = getdbl((u_char *) &mb(44)) * R2D;
642 alt = getdbl((u_char *) &mb(52));
644 printf("TSIP_decode: unit %d: Latitude: %03.4f Longitude: %03.4f Alt: %05.2f m\n",
645 up->unit, lat,lon,alt);
646 printf("TSIP_decode: unit %d\n", up->unit);
648 #endif
649 if (getint((u_char *) &mb(10)) & 0x80)
650 pp->leap = LEAP_ADDSECOND; /* we ASSUME addsecond */
651 else
652 pp->leap = LEAP_NOWARNING;
654 #ifdef DEBUG
655 if (debug > 1)
656 printf("TSIP_decode: unit %d: 0x%02x leap %d\n",
657 up->unit, mb(0) & 0xff, pp->leap);
658 if (debug > 1) {
659 printf("Receiver MODE: 0x%02X\n", (u_char)mb(1));
660 if (mb(1) == 0x00)
661 printf(" AUTOMATIC\n");
662 if (mb(1) == 0x01)
663 printf(" SINGLE SATELLITE\n");
664 if (mb(1) == 0x03)
665 printf(" HORIZONTAL(2D)\n");
666 if (mb(1) == 0x04)
667 printf(" FULL POSITION(3D)\n");
668 if (mb(1) == 0x05)
669 printf(" DGPR REFERENCE\n");
670 if (mb(1) == 0x06)
671 printf(" CLOCK HOLD(2D)\n");
672 if (mb(1) == 0x07)
673 printf(" OVERDETERMINED CLOCK\n");
675 printf("\n** Disciplining MODE 0x%02X:\n", (u_char)mb(2));
676 if (mb(2) == 0x00)
677 printf(" NORMAL\n");
678 if (mb(2) == 0x01)
679 printf(" POWER-UP\n");
680 if (mb(2) == 0x02)
681 printf(" AUTO HOLDOVER\n");
682 if (mb(2) == 0x03)
683 printf(" MANUAL HOLDOVER\n");
684 if (mb(2) == 0x04)
685 printf(" RECOVERY\n");
686 if (mb(2) == 0x06)
687 printf(" DISCIPLINING DISABLED\n");
689 #endif
690 return 0;
691 break;
693 case PACKET_8FAB:
694 /* Thunderbolt Primary Timing Packet */
696 if (up->rpt_cnt != LENCODE_8FAB) /* check length */
697 break;
699 if (up->polled <= 0)
700 return 0;
702 GPS_UTC_Offset = getint((u_char *) &mb(7));
704 if (GPS_UTC_Offset == 0){ /* Check UTC Offset */
705 #ifdef DEBUG
706 printf("TSIP_decode: UTC Offset Unknown\n");
707 #endif
708 break;
712 if ((mb(9) & 0x1d) == 0x0) {
713 /* if we know the GPS time and the UTC offset,
714 we expect UTC timing information !!! */
716 pp->leap = LEAP_NOTINSYNC;
717 refclock_report(peer, CEVNT_BADTIME);
718 up->polled = -1;
719 return 0;
722 pp->nsec = 0;
723 #ifdef DEBUG
724 printf("\nTiming Flags are:\n");
725 printf("Timing flag value is: 0x%X\n", mb(9));
726 if ((mb(9) & 0x01) != 0)
727 printf (" Getting UTC time\n");
728 else
729 printf (" Getting GPS time\n");
730 if ((mb(9) & 0x02) != 0)
731 printf (" PPS is from UTC\n");
732 else
733 printf (" PPS is from GPS\n");
734 if ((mb(9) & 0x04) != 0)
735 printf (" Time is not Set\n");
736 else
737 printf (" Time is Set\n");
738 if ((mb(9) & 0x08) != 0)
739 printf(" I dont have UTC info\n");
740 else
741 printf (" I have UTC info\n");
742 if ((mb(9) & 0x10) != 0)
743 printf (" Time is from USER\n\n");
744 else
745 printf (" Time is from GPS\n\n");
746 #endif
748 if ((pp->day = day_of_year(&mb(13))) < 0)
749 break;
750 tow = getlong((u_char *) &mb(1));
751 #ifdef DEBUG
752 if (debug > 1) {
753 printf("pp->day: %d\n", pp->day);
754 printf("TOW: %ld\n", tow);
755 printf("DAY: %d\n", mb(13));
757 #endif
758 pp->year = getint((u_char *) &mb(15));
759 pp->hour = mb(12);
760 pp->minute = mb(11);
761 pp->second = mb(10);
764 #ifdef DEBUG
765 if (debug > 1)
766 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);
767 #endif
768 return 1;
769 break;
771 default:
772 /* Ignore Packet */
773 return 0;
774 } /* switch */
775 } /* if 8F packets */
777 else if (up->rpt_buf[0] == (u_char)0x42) {
778 printf("0x42\n");
779 return 0;
781 else if (up->rpt_buf[0] == (u_char)0x43) {
782 printf("0x43\n");
783 return 0;
785 else if ((up->rpt_buf[0] == PACKET_41) & (up->type == CLK_THUNDERBOLT)){
786 printf("Undocumented 0x41 packet on Thunderbolt\n");
787 return 0;
789 else if ((up->rpt_buf[0] == PACKET_41A) & (up->type == CLK_ACUTIME)) {
790 #ifdef DEBUG
791 printf("GPS TOW: %ld\n", getlong((u_char *) &mb(0)));
792 printf("GPS WN: %d\n", getint((u_char *) &mb(4)));
793 printf("GPS UTC-GPS Offser: %ld\n", getlong((u_char *) &mb(6)));
794 #endif
795 return 0;
798 /* Health Status for Acutime Receiver */
799 else if ((up->rpt_buf[0] == PACKET_46) & (up->type == CLK_ACUTIME)) {
800 #ifdef DEBUG
801 if (debug > 1)
802 /* Status Codes */
803 switch (mb(0)) {
804 case 0x00:
805 printf ("Doing Position Fixes\n");
806 break;
807 case 0x01:
808 printf ("Do no have GPS time yet\n");
809 break;
810 case 0x03:
811 printf ("PDOP is too high\n");
812 break;
813 case 0x08:
814 printf ("No usable satellites\n");
815 break;
816 case 0x09:
817 printf ("Only 1 usable satellite\n");
818 break;
819 case 0x0A:
820 printf ("Only 2 usable satellites\n");
821 break;
822 case 0x0B:
823 printf ("Only 3 usable satellites\n");
824 break;
825 case 0x0C:
826 printf("The Chosen satellite is unusable\n");
827 break;
829 #endif
830 /* Error Codes */
831 if (mb(1) != 0) {
833 refclock_report(peer, CEVNT_BADTIME);
834 up->polled = -1;
835 #ifdef DEBUG
836 if (debug > 1) {
837 if (mb(1) && 0x01)
838 printf ("Signal Processor Error, reset unit.\n");
839 if (mb(1) && 0x02)
840 printf ("Alignment error, channel or chip 1, reset unit.\n");
841 if (mb(1) && 0x03)
842 printf ("Alignment error, channel or chip 2, reset unit.\n");
843 if (mb(1) && 0x04)
844 printf ("Antenna feed line fault (open or short)\n");
845 if (mb(1) && 0x05)
846 printf ("Excessive reference frequency error, refer to packet 0x2D and packet 0x4D documentation for further information\n");
848 #endif
850 return 0;
853 else if (up->rpt_buf[0] == 0x54)
854 return 0;
856 else if (up->rpt_buf[0] == PACKET_6D) {
857 #ifdef DEBUG
858 int sats;
860 if ((mb(0) & 0x01) && (mb(0) & 0x02))
861 printf("2d Fix Dimension\n");
862 if (mb(0) & 0x04)
863 printf("3d Fix Dimension\n");
865 if (mb(0) & 0x08)
866 printf("Fix Mode is MANUAL\n");
867 else
868 printf("Fix Mode is AUTO\n");
870 sats = mb(0) & 0xF0;
871 sats = sats >> 4;
872 printf("Tracking %d Satellites\n", sats);
873 #endif
874 return 0;
875 } /* else if not super packet */
876 refclock_report(peer, CEVNT_BADREPLY);
877 up->polled = -1;
878 #ifdef DEBUG
879 printf("TSIP_decode: unit %d: bad packet %02x-%02x event %d len %d\n",
880 up->unit, up->rpt_buf[0] & 0xff, mb(0) & 0xff,
881 event, up->rpt_cnt);
882 #endif
883 return 0;
887 * palisade__receive - receive data from the serial interface
890 static void
891 palisade_receive (
892 struct peer * peer
895 struct palisade_unit *up;
896 struct refclockproc *pp;
899 * Initialize pointers and read the timecode and timestamp.
901 pp = peer->procptr;
902 up = (struct palisade_unit *)pp->unitptr;
904 if (! TSIP_decode(peer)) return;
906 if (up->polled <= 0)
907 return; /* no poll pending, already received or timeout */
909 up->polled = 0; /* Poll reply received */
910 pp->lencode = 0; /* clear time code */
911 #ifdef DEBUG
912 if (debug)
913 printf(
914 "palisade_receive: unit %d: %4d %03d %02d:%02d:%02d.%06ld\n",
915 up->unit, pp->year, pp->day, pp->hour, pp->minute,
916 pp->second, pp->nsec);
917 #endif
920 * Process the sample
921 * Generate timecode: YYYY DoY HH:MM:SS.microsec
922 * report and process
925 (void) sprintf(pp->a_lastcode,"%4d %03d %02d:%02d:%02d.%06ld",
926 pp->year,pp->day,pp->hour,pp->minute, pp->second,pp->nsec);
927 pp->lencode = 24;
929 if (!refclock_process(pp)) {
930 refclock_report(peer, CEVNT_BADTIME);
932 #ifdef DEBUG
933 printf("palisade_receive: unit %d: refclock_process failed!\n",
934 up->unit);
935 #endif
936 return;
939 record_clock_stats(&peer->srcadr, pp->a_lastcode);
941 #ifdef DEBUG
942 if (debug)
943 printf("palisade_receive: unit %d: %s\n",
944 up->unit, prettydate(&pp->lastrec));
945 #endif
946 pp->lastref = pp->lastrec;
947 refclock_receive(peer);
952 * palisade_poll - called by the transmit procedure
955 static void
956 palisade_poll (
957 int unit,
958 struct peer *peer
961 struct palisade_unit *up;
962 struct refclockproc *pp;
964 pp = peer->procptr;
965 up = (struct palisade_unit *)pp->unitptr;
967 pp->polls++;
968 if (up->polled > 0) /* last reply never arrived or error */
969 refclock_report(peer, CEVNT_TIMEOUT);
971 up->polled = 2; /* synchronous packet + 1 event */
973 #ifdef DEBUG
974 if (debug)
975 printf("palisade_poll: unit %d: polling %s\n", unit,
976 (pp->sloppyclockflag & CLK_FLAG2) ?
977 "synchronous packet" : "event");
978 #endif
980 if (pp->sloppyclockflag & CLK_FLAG2)
981 return; /* using synchronous packet input */
983 if(up->type == CLK_PRAECIS) {
984 if(write(peer->procptr->io.fd,"SPSTAT\r\n",8) < 0)
985 msyslog(LOG_ERR, "Palisade(%d) write: %m:",unit);
986 else {
987 praecis_msg = 1;
988 return;
992 if (HW_poll(pp) < 0)
993 refclock_report(peer, CEVNT_FAULT);
996 static void
997 praecis_parse (
998 struct recvbuf *rbufp,
999 struct peer *peer
1002 static char buf[100];
1003 static int p = 0;
1004 struct refclockproc *pp;
1006 pp = peer->procptr;
1008 memcpy(buf+p,rbufp->recv_space.X_recv_buffer, rbufp->recv_length);
1009 p += rbufp->recv_length;
1011 if(buf[p-2] == '\r' && buf[p-1] == '\n') {
1012 buf[p-2] = '\0';
1013 record_clock_stats(&peer->srcadr, buf);
1015 p = 0;
1016 praecis_msg = 0;
1018 if (HW_poll(pp) < 0)
1019 refclock_report(peer, CEVNT_FAULT);
1024 static void
1025 palisade_io (
1026 struct recvbuf *rbufp
1030 * Initialize pointers and read the timecode and timestamp.
1032 struct palisade_unit *up;
1033 struct refclockproc *pp;
1034 struct peer *peer;
1036 char * c, * d;
1038 peer = (struct peer *)rbufp->recv_srcclock;
1039 pp = peer->procptr;
1040 up = (struct palisade_unit *)pp->unitptr;
1042 if(up->type == CLK_PRAECIS) {
1043 if(praecis_msg) {
1044 praecis_parse(rbufp,peer);
1045 return;
1049 c = (char *) &rbufp->recv_space;
1050 d = c + rbufp->recv_length;
1052 while (c != d) {
1054 /* Build time packet */
1055 switch (up->rpt_status) {
1057 case TSIP_PARSED_DLE_1:
1058 switch (*c)
1060 case 0:
1061 case DLE:
1062 case ETX:
1063 up->rpt_status = TSIP_PARSED_EMPTY;
1064 break;
1066 default:
1067 up->rpt_status = TSIP_PARSED_DATA;
1068 /* save packet ID */
1069 up->rpt_buf[0] = *c;
1070 break;
1072 break;
1074 case TSIP_PARSED_DATA:
1075 if (*c == DLE)
1076 up->rpt_status = TSIP_PARSED_DLE_2;
1077 else
1078 mb(up->rpt_cnt++) = *c;
1079 break;
1081 case TSIP_PARSED_DLE_2:
1082 if (*c == DLE) {
1083 up->rpt_status = TSIP_PARSED_DATA;
1084 mb(up->rpt_cnt++) =
1087 else if (*c == ETX)
1088 up->rpt_status = TSIP_PARSED_FULL;
1089 else {
1090 /* error: start new report packet */
1091 up->rpt_status = TSIP_PARSED_DLE_1;
1092 up->rpt_buf[0] = *c;
1094 break;
1096 case TSIP_PARSED_FULL:
1097 case TSIP_PARSED_EMPTY:
1098 default:
1099 if ( *c != DLE)
1100 up->rpt_status = TSIP_PARSED_EMPTY;
1101 else
1102 up->rpt_status = TSIP_PARSED_DLE_1;
1103 break;
1106 c++;
1108 if (up->rpt_status == TSIP_PARSED_DLE_1) {
1109 up->rpt_cnt = 0;
1110 if (pp->sloppyclockflag & CLK_FLAG2)
1111 /* stamp it */
1112 get_systime(&pp->lastrec);
1114 else if (up->rpt_status == TSIP_PARSED_EMPTY)
1115 up->rpt_cnt = 0;
1117 else if (up->rpt_cnt > BMAX)
1118 up->rpt_status =TSIP_PARSED_EMPTY;
1120 if (up->rpt_status == TSIP_PARSED_FULL)
1121 palisade_receive(peer);
1123 } /* while chars in buffer */
1128 * Trigger the Palisade's event input, which is driven off the RTS
1130 * Take a system time stamp to match the GPS time stamp.
1133 long
1134 HW_poll (
1135 struct refclockproc * pp /* pointer to unit structure */
1138 int x; /* state before & after RTS set */
1139 struct palisade_unit *up;
1141 up = (struct palisade_unit *) pp->unitptr;
1143 /* read the current status, so we put things back right */
1144 if (ioctl(pp->io.fd, TIOCMGET, &x) < 0) {
1145 #ifdef DEBUG
1146 if (debug)
1147 printf("Palisade HW_poll: unit %d: GET %s\n", up->unit, strerror(errno));
1148 #endif
1149 msyslog(LOG_ERR, "Palisade(%d) HW_poll: ioctl(fd,GET): %m",
1150 up->unit);
1151 return -1;
1154 x |= TIOCM_RTS; /* turn on RTS */
1156 /* Edge trigger */
1157 if (up->type == CLK_ACUTIME)
1158 write (pp->io.fd, "", 1);
1160 if (ioctl(pp->io.fd, TIOCMSET, &x) < 0) {
1161 #ifdef DEBUG
1162 if (debug)
1163 printf("Palisade HW_poll: unit %d: SET \n", up->unit);
1164 #endif
1165 msyslog(LOG_ERR,
1166 "Palisade(%d) HW_poll: ioctl(fd, SET, RTS_on): %m",
1167 up->unit);
1168 return -1;
1171 x &= ~TIOCM_RTS; /* turn off RTS */
1173 /* poll timestamp */
1174 get_systime(&pp->lastrec);
1176 if (ioctl(pp->io.fd, TIOCMSET, &x) == -1) {
1177 #ifdef DEBUG
1178 if (debug)
1179 printf("Palisade HW_poll: unit %d: UNSET \n", up->unit);
1180 #endif
1181 msyslog(LOG_ERR,
1182 "Palisade(%d) HW_poll: ioctl(fd, UNSET, RTS_off): %m",
1183 up->unit);
1184 return -1;
1187 return 0;
1190 #if 0 /* unused */
1192 * this 'casts' a character array into a float
1194 float
1195 getfloat (
1196 u_char *bp
1199 float sval;
1200 #ifdef WORDS_BIGENDIAN
1201 ((char *) &sval)[0] = *bp++;
1202 ((char *) &sval)[1] = *bp++;
1203 ((char *) &sval)[2] = *bp++;
1204 ((char *) &sval)[3] = *bp++;
1205 #else
1206 ((char *) &sval)[3] = *bp++;
1207 ((char *) &sval)[2] = *bp++;
1208 ((char *) &sval)[1] = *bp++;
1209 ((char *) &sval)[0] = *bp;
1210 #endif /* ! XNTP_BIG_ENDIAN */
1211 return sval;
1213 #endif
1216 * this 'casts' a character array into a double
1218 double
1219 getdbl (
1220 u_char *bp
1223 double dval;
1224 #ifdef WORDS_BIGENDIAN
1225 ((char *) &dval)[0] = *bp++;
1226 ((char *) &dval)[1] = *bp++;
1227 ((char *) &dval)[2] = *bp++;
1228 ((char *) &dval)[3] = *bp++;
1229 ((char *) &dval)[4] = *bp++;
1230 ((char *) &dval)[5] = *bp++;
1231 ((char *) &dval)[6] = *bp++;
1232 ((char *) &dval)[7] = *bp;
1233 #else
1234 ((char *) &dval)[7] = *bp++;
1235 ((char *) &dval)[6] = *bp++;
1236 ((char *) &dval)[5] = *bp++;
1237 ((char *) &dval)[4] = *bp++;
1238 ((char *) &dval)[3] = *bp++;
1239 ((char *) &dval)[2] = *bp++;
1240 ((char *) &dval)[1] = *bp++;
1241 ((char *) &dval)[0] = *bp;
1242 #endif /* ! XNTP_BIG_ENDIAN */
1243 return dval;
1247 * cast a 16 bit character array into a short (16 bit) int
1249 short
1250 getint (
1251 u_char *bp
1254 return (short) (bp[1] + (bp[0] << 8));
1258 * cast a 32 bit character array into a long (32 bit) int
1260 long
1261 getlong(
1262 u_char *bp
1265 return (long) (bp[0] << 24) |
1266 (bp[1] << 16) |
1267 (bp[2] << 8) |
1268 bp[3];
1271 int refclock_palisade_bs;
1272 #endif /* REFCLOCK */