2 * This software was developed by the Software and Component Technologies
3 * group of Trimble Navigation, Ltd.
5 * Copyright (c) 1997, 1998, 1999, 2000 Trimble Navigation Ltd.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
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
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
37 * refclock_palisade - clock driver for the Trimble Palisade GPS
40 * For detailed information on this program, please refer to the html
41 * Refclock 29 page accompanying the NTP distribution.
43 * for questions / bugs / comments, contact:
44 * sven_dietrich@trimble.com
46 * Sven-Thorsten Dietrich
47 * 645 North Mary Avenue
48 * Post Office Box 3642
49 * Sunnyvale, CA 94088-3642
51 * Version 2.45; July 14, 1999
55 * 31/03/06: Added support for Thunderbolt GPS Disciplined Clock.
56 * Contact: Fernando Pablo Hauscarriaga
57 * E-mail: fernandoph@iar.unlp.edu.ar
58 * Home page: www.iar.unlp.edu.ar/~fernandoph
59 * Instituto Argentino de Radioastronomia
62 * 14/01/07: Conditinal compilation for Thunderbolt support no longer needed
63 * now we use mode 2 for decode thunderbolt packets.
64 * Fernando P. Hauscarriaga
66 * 30/08/09: Added support for Trimble Acutime Gold Receiver.
67 * Fernando P. Hauscarriaga (fernandoph@iar.unlp.edu.ar)
69 * 21/04/18: Added support for Resolution devices.
71 * 03/09/19: Added support for ACE III & Copernicus II.
78 #if defined(REFCLOCK) && defined(CLOCK_PALISADE)
81 extern int async_write(int, const void *, unsigned int);
83 #define write(fd, data, octets) async_write(fd, data, octets)
86 #include "refclock_palisade.h"
89 const char * Tracking_Status[15][15] = {
90 { "Doing Fixes\0" }, { "Good 1SV\0" }, { "Approx. 1SV\0" },
91 {"Need Time\0" }, { "Need INIT\0" }, { "PDOP too High\0" },
92 { "Bad 1SV\0" }, { "0SV Usable\0" }, { "1SV Usable\0" },
93 { "2SV Usable\0" }, { "3SV Usable\0" }, { "No Integrity\0" },
94 { "Diff Corr\0" }, { "Overdet Clock\0" }, { "Invalid\0" } };
100 struct refclock refclock_palisade = {
101 palisade_start, /* start up driver */
102 palisade_shutdown, /* shut down driver */
103 palisade_poll, /* transmit poll message */
104 noentry, /* not used */
105 noentry, /* initialize driver (not used) */
106 noentry, /* not used */
107 NOFLAGS /* not used */
110 static int decode_date(struct refclockproc *pp, const char *cp);
112 /* Extract the clock type from the mode setting */
113 #define CLK_TYPE(x) ((int)(((x)->ttl) & 0x7F))
115 /* Supported clock types */
116 #define CLK_TRIMBLE 0 /* Trimble Palisade */
117 #define CLK_PRAECIS 1 /* Endrun Technologies Praecis */
118 #define CLK_THUNDERBOLT 2 /* Trimble Thunderbolt GPS Receiver */
119 #define CLK_ACUTIME 3 /* Trimble Acutime Gold */
120 #define CLK_ACUTIMEB 4 /* Trimble Actutime Gold Port B */
121 #define CLK_RESOLUTION 5 /* Trimble Resolution Receivers */
122 #define CLK_ACE 6 /* Trimble ACE III */
123 #define CLK_COPERNICUS 7 /* Trimble Copernicus II */
126 static void praecis_parse(struct recvbuf *rbufp, struct peer *peer);
128 /* These routines are for sending packets to the Thunderbolt receiver
129 * They are taken from Markus Prosch
133 * sendcmd - Build data packet for sending
137 struct packettx *buffer,
142 *(buffer->data + 1) = (unsigned char)c;
147 * sendsupercmd - Build super data packet for sending
151 struct packettx *buffer,
157 *(buffer->data + 1) = (unsigned char)c1;
158 *(buffer->data + 2) = (unsigned char)c2;
167 struct packettx *buffer,
172 *(buffer->data+buffer->size++) = DLE;
173 *(buffer->data+buffer->size++) = (unsigned char)b;
181 struct packettx *buffer,
185 sendbyte(buffer, (unsigned char)((a>>8) & 0xff));
186 sendbyte(buffer, (unsigned char)(a & 0xff));
190 * sendetx - Send packet or super packet to the device
194 struct packettx *buffer,
200 *(buffer->data+buffer->size++) = DLE;
201 *(buffer->data+buffer->size++) = ETX;
202 result = write(fd, buffer->data, (unsigned long)buffer->size);
211 * init_thunderbolt - Prepares Thunderbolt receiver to be used with
212 * NTP (also taken from Markus Prosch).
222 tx.data = (u_char *) emalloc(100);
225 sendsupercmd (&tx, 0x8E, 0xA2);
229 /* activate packets 0x8F-AB and 0x8F-AC */
230 sendsupercmd (&tx, 0x8E, 0xA5);
238 * init_acutime - Prepares Acutime Receiver to be used with NTP
245 /* Disable all outputs, Enable Event-Polling on PortA so
246 we can ask for time packets */
250 tx.data = (u_char *) emalloc(100);
252 sendsupercmd(&tx, 0x8E, 0xA5);
263 * init_resolution - Prepares Resolution receiver to be used with NTP
273 tx.data = (u_char *) emalloc(100);
276 sendsupercmd (&tx, 0x8E, 0xA2);
280 /* squelch PPS output unless locked to at least one satellite */
281 sendsupercmd (&tx, 0x8E, 0x4E);
285 /* activate packets 0x8F-AB and 0x8F-AC */
286 sendsupercmd (&tx, 0x8E, 0xA5);
294 * palisade_start - open the devices and initialize data for processing
302 struct palisade_unit *up;
303 struct refclockproc *pp;
308 snprintf(gpsdev, sizeof(gpsdev), DEVICE, unit);
314 speed = (CLK_TYPE(peer) == CLK_COPERNICUS) ? SPEED232COP : SPEED232;
315 fd = refclock_open(gpsdev, speed, LDISC_RAW);
318 printf("Palisade(%d) start: open %s failed\n", unit, gpsdev);
323 msyslog(LOG_NOTICE, "Palisade(%d) fd: %d dev: %s", unit, fd,
326 if (tcgetattr(fd, &tio) < 0) {
328 "Palisade(%d) tcgetattr(fd, &tio): %m",unit);
330 printf("Palisade(%d) tcgetattr(fd, &tio)\n",unit);
336 tio.c_cflag |= (PARENB|PARODD);
337 tio.c_iflag &= ~ICRNL;
340 * Allocate and initialize unit structure
342 up = emalloc_zero(sizeof(*up));
344 up->type = CLK_TYPE(peer);
347 /* Normal mode, do nothing */
350 msyslog(LOG_NOTICE, "Palisade(%d) Praecis mode enabled"
353 case CLK_THUNDERBOLT:
354 msyslog(LOG_NOTICE, "Palisade(%d) Thunderbolt mode enabled"
356 tio.c_cflag = (CS8|CLOCAL|CREAD);
359 msyslog(LOG_NOTICE, "Palisade(%d) Acutime Gold mode enabled"
363 msyslog(LOG_NOTICE, "Palisade(%d) Resolution mode enabled"
365 tio.c_cflag = (CS8|CLOCAL|CREAD|PARENB|PARODD);
368 msyslog(LOG_NOTICE, "Palisade(%d) ACE III mode enabled"
370 tio.c_cflag = (CS8|CLOCAL|CREAD|PARENB|PARODD);
373 msyslog(LOG_NOTICE, "Palisade(%d) Copernicus II mode enabled"
375 /* Must use ORing/ANDing to set/clear c_cflag bits otherwise
376 CBAUD gets set back to 0. This ought to be an issue for
377 the other modes above but it seems that the baud rate
378 defaults to 9600 if CBAUD gets set to 0. */
379 tio.c_cflag &= ~(PARENB|PARODD);
382 msyslog(LOG_NOTICE, "Palisade(%d) mode unknown",unit);
385 if (tcsetattr(fd, TCSANOW, &tio) == -1) {
386 msyslog(LOG_ERR, "Palisade(%d) tcsetattr(fd, &tio): %m",unit);
388 printf("Palisade(%d) tcsetattr(fd, &tio)\n",unit);
396 pp->io.clock_recv = palisade_io;
397 pp->io.srcclock = peer;
400 if (!io_addclock(&pp->io)) {
402 printf("Palisade(%d) io_addclock\n",unit);
411 * Initialize miscellaneous variables
414 pp->clockdesc = DESCRIPTION;
416 peer->precision = PRECISION;
417 peer->sstclktype = CTL_SST_TS_UHF;
418 peer->minpoll = TRMB_MINPOLL;
419 peer->maxpoll = TRMB_MAXPOLL;
420 memcpy((char *)&pp->refid, REFID, 4);
423 up->unit = (short) unit;
424 up->rpt_status = TSIP_PARSED_EMPTY;
427 if (up->type == CLK_THUNDERBOLT)
428 init_thunderbolt(fd);
429 if (up->type == CLK_ACUTIME)
431 if (up->type == CLK_RESOLUTION)
439 * palisade_shutdown - shut down the clock
447 struct palisade_unit *up;
448 struct refclockproc *pp;
452 io_closeclock(&pp->io);
462 static inline uint8_t
466 return ((const u_char*)cp)[0];
469 static inline uint16_t
473 return ((uint16_t)get_u8(cp) << 8) | get_u8(cp + 1);
477 * unpack & fix date (the receiver provides a valid time for 1024 weeks
478 * after 1997-12-14 and therefore folds back in 2017, 2037,...)
480 * Returns -1 on error, day-of-month + (month * 32) othertwise.
484 struct refclockproc *pp,
487 static int32_t s_baseday = 0;
492 if (0 == s_baseday) {
493 if (!ntpcal_get_build_date(&jd)) {
498 s_baseday = ntpcal_date_to_rd(&jd);
501 /* get date fields and convert to RDN */
502 jd.monthday = get_u8 ( cp );
503 jd.month = get_u8 (cp + 1);
504 jd.year = get_u16(cp + 2);
505 rd = ntpcal_date_to_rd(&jd);
507 /* for the paranoid: do reverse calculation and cross-check */
508 ntpcal_rd_to_date(&jd, rd);
509 if ((jd.monthday != get_u8 ( cp )) ||
510 (jd.month != get_u8 (cp + 1)) ||
511 (jd.year != get_u16(cp + 2)) )
514 /* calculate cycle shift to base day and calculate re-folded
517 * One could do a proper modulo calculation here, but a counting
518 * loop is probably faster for the next few rollovers...
520 while (rd < s_baseday)
522 ntpcal_rd_to_date(&jd, rd);
524 /* fill refclock structure & indicate success */
525 pp->day = jd.yearday;
527 return ((int)jd.month << 5) | jd.monthday;
532 * TSIP_decode - decode the TSIP data packets
543 unsigned short event = 0;
549 struct palisade_unit *up;
550 struct refclockproc *pp;
556 * Check the time packet, decode its contents.
557 * If the timecode has invalid length or is not in
558 * proper format, declare bad format and exit.
561 if ((up->type != CLK_THUNDERBOLT) &&
562 (up->type != CLK_ACUTIME ) &&
563 (up->type != CLK_RESOLUTION ) &&
564 (up->type != CLK_ACE ) &&
565 (up->type != CLK_COPERNICUS ) )
567 if ((up->rpt_buf[0] == (char) 0x41) ||
568 (up->rpt_buf[0] == (char) 0x46) ||
569 (up->rpt_buf[0] == (char) 0x54) ||
570 (up->rpt_buf[0] == (char) 0x4B) ||
571 (up->rpt_buf[0] == (char) 0x6D)) {
573 /* standard time packet - GPS time and GPS week number */
575 printf("Palisade Port B packets detected. Connect to Port A\n");
583 * We cast both to u_char as 0x8f uses the sign bit on a char
585 if ((u_char) up->rpt_buf[0] == (u_char) 0x8f) {
589 event = (unsigned short) (getint((u_char *) &mb(1)) & 0xffff);
590 if (!((pp->sloppyclockflag & CLK_FLAG2) || event))
594 switch (mb(0) & 0xff) {
601 if (up->rpt_cnt != LENCODE_8F0B) /* check length */
607 double lat, lon, alt;
608 lat = getdbl((u_char *) &mb(42)) * R2D;
609 lon = getdbl((u_char *) &mb(50)) * R2D;
610 alt = getdbl((u_char *) &mb(58));
612 printf("TSIP_decode: unit %d: Latitude: %03.4f Longitude: %03.4f Alt: %05.2f m\n",
613 up->unit, lat,lon,alt);
614 printf("TSIP_decode: unit %d: Sats:",
616 for (st = 66, ts = 0; st <= 73; st++)
618 if (mb(st) > 0) ts++;
619 printf(" %02d", mb(st));
621 printf(" : Tracking %d\n", ts);
625 GPS_UTC_Offset = getint((u_char *) &mb(16));
626 if (GPS_UTC_Offset == 0) { /* Check UTC offset */
628 printf("TSIP_decode: UTC Offset Unknown\n");
633 secs = getdbl((u_char *) &mb(3));
634 secint = (long) secs;
635 secfrac = secs - secint; /* 0.0 <= secfrac < 1.0 */
637 pp->nsec = (long) (secfrac * 1000000000);
639 secint %= 86400; /* Only care about today */
640 pp->hour = secint / 3600;
642 pp->minute = secint / 60;
644 pp->second = secint % 60;
646 mmday = decode_date(pp, &mb(11));
652 printf("TSIP_decode: unit %d: %02X #%d %02d:%02d:%02d.%09ld %02d/%02d/%04d UTC %02d\n",
653 up->unit, mb(0) & 0xff, event, pp->hour, pp->minute,
654 pp->second, pp->nsec, (mmday >> 5), (mmday & 31), pp->year, GPS_UTC_Offset);
656 /* Only use this packet when no
657 * 8F-AD's are being received
660 if (up->leap_status) {
669 /* Palisade-NTP Packet */
671 if (up->rpt_cnt != LENCODE_NTP) /* check length */
674 up->leap_status = mb(19);
679 /* Check Tracking Status */
681 if (st < 0 || st > 14)
683 if ((st >= 2 && st <= 7) || st == 11 || st == 12) {
685 printf("TSIP_decode: Not Tracking Sats : %s\n",
686 *Tracking_Status[st]);
688 refclock_report(peer, CEVNT_BADTIME);
694 mmday = decode_date(pp, &mb(14));
697 up->month = (mmday >> 5); /* Save for LEAP check */
699 if ( (up->leap_status & PALISADE_LEAP_PENDING) &&
700 /* Avoid early announce: https://bugs.ntp.org/2773 */
701 (6 == up->month || 12 == up->month) ) {
702 if (up->leap_status & PALISADE_UTC_TIME)
703 pp->leap = LEAP_ADDSECOND;
705 pp->leap = LEAP_DELSECOND;
707 else if (up->leap_status)
708 pp->leap = LEAP_NOWARNING;
710 else { /* UTC flag is not set:
711 * Receiver may have been reset, and lost
712 * its UTC almanac data */
713 pp->leap = LEAP_NOTINSYNC;
715 printf("TSIP_decode: UTC Almanac unavailable: %d\n",
718 refclock_report(peer, CEVNT_BADTIME);
723 pp->nsec = (long) (getdbl((u_char *) &mb(3))
732 printf("TSIP_decode: unit %d: %02X #%d %02d:%02d:%02d.%09ld %02d/%02d/%04d UTC %02x %s\n",
733 up->unit, mb(0) & 0xff, event, pp->hour, pp->minute,
734 pp->second, pp->nsec, (mmday >> 5), (mmday & 31), pp->year,
735 mb(19), *Tracking_Status[st]);
744 if (up->rpt_cnt != LENCODE_8FAC)/* check length */
749 double lat, lon, alt;
750 lat = getdbl((u_char *) &mb(36)) * R2D;
751 lon = getdbl((u_char *) &mb(44)) * R2D;
752 alt = getdbl((u_char *) &mb(52));
754 printf("TSIP_decode: unit %d: Latitude: %03.4f Longitude: %03.4f Alt: %05.2f m\n",
755 up->unit, lat,lon,alt);
756 printf("TSIP_decode: unit %d\n", up->unit);
759 if ( (getint((u_char *) &mb(10)) & 0x80) &&
760 /* Avoid early announce: https://bugs.ntp.org/2773 */
761 (6 == up->month || 12 == up->month) )
762 pp->leap = LEAP_ADDSECOND; /* we ASSUME addsecond */
764 pp->leap = LEAP_NOWARNING;
768 printf("TSIP_decode: unit %d: 0x%02x leap %d\n",
769 up->unit, mb(0) & 0xff, pp->leap);
771 printf("Receiver MODE: 0x%02X\n", (u_char)mb(1));
773 printf(" AUTOMATIC\n");
775 printf(" SINGLE SATELLITE\n");
777 printf(" HORIZONTAL(2D)\n");
779 printf(" FULL POSITION(3D)\n");
781 printf(" DGPR REFERENCE\n");
783 printf(" CLOCK HOLD(2D)\n");
785 printf(" OVERDETERMINED CLOCK\n");
787 printf("\n** Disciplining MODE 0x%02X:\n", (u_char)mb(2));
791 printf(" POWER-UP\n");
793 printf(" AUTO HOLDOVER\n");
795 printf(" MANUAL HOLDOVER\n");
797 printf(" RECOVERY\n");
799 printf(" DISCIPLINING DISABLED\n");
806 /* Thunderbolt Primary Timing Packet */
808 if (up->rpt_cnt != LENCODE_8FAB) /* check length */
814 GPS_UTC_Offset = getint((u_char *) &mb(7));
816 if (GPS_UTC_Offset == 0){ /* Check UTC Offset */
818 printf("TSIP_decode: UTC Offset Unknown\n");
824 if ((mb(9) & 0x1d) == 0x0) {
825 /* if we know the GPS time and the UTC offset,
826 we expect UTC timing information !!! */
828 pp->leap = LEAP_NOTINSYNC;
829 refclock_report(peer, CEVNT_BADTIME);
836 printf("\nTiming Flags are:\n");
837 printf("Timing flag value is: 0x%X\n", mb(9));
838 if ((mb(9) & 0x01) != 0)
839 printf (" Getting UTC time\n");
841 printf (" Getting GPS time\n");
842 if ((mb(9) & 0x02) != 0)
843 printf (" PPS is from UTC\n");
845 printf (" PPS is from GPS\n");
846 if ((mb(9) & 0x04) != 0)
847 printf (" Time is not Set\n");
849 printf (" Time is Set\n");
850 if ((mb(9) & 0x08) != 0)
851 printf(" I dont have UTC info\n");
853 printf (" I have UTC info\n");
854 if ((mb(9) & 0x10) != 0)
855 printf (" Time is from USER\n\n");
857 printf (" Time is from GPS\n\n");
860 mmday = decode_date(pp, &mb(13));
863 tow = getlong((u_char *) &mb(1));
866 printf("pp->day: %d\n", pp->day);
867 printf("TOW: %ld\n", tow);
868 printf("DAY: %d\n", (mmday & 31));
878 printf("TSIP_decode: unit %d: %02X #%d %02d:%02d:%02d.%09ld %02d/%02d/%04d ",
879 up->unit, mb(0) & 0xff, event, pp->hour, pp->minute, pp->second,
880 pp->nsec, (mmday >> 5), (mmday & 31), pp->year);
889 } /* if 8F packets */
891 else if (up->rpt_buf[0] == (u_char)0x42) {
895 else if (up->rpt_buf[0] == (u_char)0x43) {
899 else if ((up->rpt_buf[0] == PACKET_41) & (up->type == CLK_THUNDERBOLT)){
900 printf("Undocumented 0x41 packet on Thunderbolt\n");
903 else if ((up->rpt_buf[0] == PACKET_41A) & (up->type == CLK_ACUTIME)) {
905 printf("GPS TOW: %ld\n", (long)getlong((u_char *) &mb(0)));
906 printf("GPS WN: %d\n", getint((u_char *) &mb(4)));
907 printf("GPS UTC-GPS Offset: %ld\n", (long)getlong((u_char *) &mb(6)));
912 /* GPS time packet for ACE III or Copernicus II receiver */
913 else if ((up->rpt_buf[0] == PACKET_41) &&
914 ((up->type == CLK_ACE) || (up->type == CLK_COPERNICUS))) {
916 if ((debug > 1) && (up->type == CLK_ACE))
917 printf("TSIP_decode: Packet 0x41 seen in ACE III mode\n");
918 if ((debug > 1) && (up->type == CLK_COPERNICUS))
919 printf("TSIP_decode: Packet 0x41 seen in Copernicus II mode\n");
921 if (up->rpt_cnt != LENCODE_41) { /* check length */
922 refclock_report(peer, CEVNT_BADREPLY);
925 printf("TSIP_decode: unit %d: bad packet %02x len %d\n",
926 up->unit, up->rpt_buf[0] & 0xff, up->rpt_cnt);
932 tow = (long)getsingle((u_char *) &mb(0));
933 wn = (uint16_t)getint((u_char *) &mb(4));
934 GPS_UTC_Offset = (int)getsingle((u_char *) &mb(6));
935 if (GPS_UTC_Offset == 0){ /* Check UTC Offset */
937 printf("TSIP_decode: UTC Offset Unknown\n");
939 refclock_report(peer, CEVNT_BADREPLY);
943 /* Get date & time from WN & ToW minus offset */
946 l_fp ugo; /* UTC-GPS offset, negative number */
947 ugo.Ul_i.Xl_i = (int32_t)-GPS_UTC_Offset;
949 wd = gpscal_from_gpsweek((wn % 1024), (int32_t)tow, ugo);
950 gpscal_to_calendar(&cd, &wd);
952 pp->day = cd.yearday;
954 pp->minute = cd.minute;
955 pp->second = cd.second;
957 pp->leap = LEAP_NOWARNING;
960 printf("GPS TOW: %ld\n", tow);
961 printf("GPS WN: %d\n", wn);
962 printf("GPS UTC-GPS Offset: %d\n", GPS_UTC_Offset);
963 printf("TSIP_decode: unit %d: %02X #%d %02d:%02d:%02d.%09ld %02d/%02d/%04d ",
964 up->unit, mb(0) & 0xff, event, pp->hour, pp->minute, pp->second,
965 pp->nsec, cd.month, cd.monthday, pp->year);
971 /* Health Status for Acutime Receiver */
972 else if ((up->rpt_buf[0] == PACKET_46) & (up->type == CLK_ACUTIME)) {
978 printf ("Doing Position Fixes\n");
981 printf ("Do not have GPS time yet\n");
984 printf ("PDOP is too high\n");
987 printf ("No usable satellites\n");
990 printf ("Only 1 usable satellite\n");
993 printf ("Only 2 usable satellites\n");
996 printf ("Only 3 usable satellites\n");
999 printf("The Chosen satellite is unusable\n");
1006 refclock_report(peer, CEVNT_BADTIME);
1011 printf ("Signal Processor Error, reset unit.\n");
1013 printf ("Alignment error, channel or chip 1, reset unit.\n");
1015 printf ("Alignment error, channel or chip 2, reset unit.\n");
1017 printf ("Antenna feed line fault (open or short)\n");
1019 printf ("Excessive reference frequency error, refer to packet 0x2D and packet 0x4D documentation for further information\n");
1027 /* Health Status for Copernicus II Receiver */
1028 else if ((up->rpt_buf[0] == PACKET_46) && (up->type == CLK_COPERNICUS)) {
1034 printf ("Doing Position Fixes\n");
1037 printf ("Do not have GPS time yet\n");
1040 printf ("PDOP is too high\n");
1043 printf("The Chosen satellite is unusable\n");
1046 printf ("No usable satellites\n");
1049 printf ("Only 1 usable satellite\n");
1052 printf ("Only 2 usable satellites\n");
1055 printf ("Only 3 usable satellites\n");
1060 if ((mb(1) & 0x3E) != 0) { /* Don't regard bits 0 and 6 as errors */
1061 refclock_report(peer, CEVNT_BADTIME);
1065 if ((mb(1) & 0x18) == 0x08)
1066 printf ("Antenna feed line fault (open)\n");
1067 if ((mb(1) & 0x18) == 0x18)
1068 printf ("Antenna feed line fault (short)\n");
1075 /* Other packets output by ACE III & Copernicus II Receivers, dropped silently */
1076 else if (((up->rpt_buf[0] == (char) 0x4A) ||
1077 (up->rpt_buf[0] == (char) 0x4B) ||
1078 (up->rpt_buf[0] == (char) 0x56) ||
1079 (up->rpt_buf[0] == (char) 0x5F) ||
1080 (up->rpt_buf[0] == (char) 0x6D) ||
1081 (up->rpt_buf[0] == (char) 0x82) ||
1082 (up->rpt_buf[0] == (char) 0x84)) &&
1083 ((up->type == CLK_ACE) || (up->type == CLK_COPERNICUS))) {
1085 if ((debug > 1) && (up->type == CLK_ACE))
1086 printf("TSIP_decode: Packet 0x%2x seen in ACE III mode\n", (up->rpt_buf[0] & 0XFF));
1087 if ((debug > 1) && (up->type == CLK_COPERNICUS))
1088 printf("TSIP_decode: Packet 0x%2x seen in Copernicus II mode\n", (up->rpt_buf[0] & 0XFF));
1093 else if (up->rpt_buf[0] == 0x54)
1096 else if (up->rpt_buf[0] == PACKET_6D) {
1100 if ((mb(0) & 0x01) && (mb(0) & 0x02))
1101 printf("2d Fix Dimension\n");
1103 printf("3d Fix Dimension\n");
1106 printf("Fix Mode is MANUAL\n");
1108 printf("Fix Mode is AUTO\n");
1110 sats = mb(0) & 0xF0;
1112 printf("Tracking %d Satellites\n", sats);
1115 } /* else if not super packet */
1116 refclock_report(peer, CEVNT_BADREPLY);
1119 printf("TSIP_decode: unit %d: bad packet %02x-%02x event %d len %d\n",
1120 up->unit, up->rpt_buf[0] & 0xff, mb(0) & 0xff,
1121 event, up->rpt_cnt);
1127 * palisade__receive - receive data from the serial interface
1135 struct palisade_unit *up;
1136 struct refclockproc *pp;
1139 * Initialize pointers and read the timecode and timestamp.
1144 if (! TSIP_decode(peer)) return;
1146 if (up->polled <= 0)
1147 return; /* no poll pending, already received or timeout */
1149 up->polled = 0; /* Poll reply received */
1150 pp->lencode = 0; /* clear time code */
1154 "palisade_receive: unit %d: %4d %03d %02d:%02d:%02d.%09ld\n",
1155 up->unit, pp->year, pp->day, pp->hour, pp->minute,
1156 pp->second, pp->nsec);
1160 * Process the sample
1161 * Generate timecode: YYYY DoY HH:MM:SS.microsec
1162 * report and process
1165 snprintf(pp->a_lastcode, sizeof(pp->a_lastcode),
1166 "%4d %03d %02d:%02d:%02d.%09ld",
1168 pp->hour,pp->minute, pp->second, pp->nsec);
1171 if (!refclock_process(pp)) {
1172 refclock_report(peer, CEVNT_BADTIME);
1175 printf("palisade_receive: unit %d: refclock_process failed!\n",
1181 record_clock_stats(&peer->srcadr, pp->a_lastcode);
1185 printf("palisade_receive: unit %d: %s\n",
1186 up->unit, prettydate(&pp->lastrec));
1188 pp->lastref = pp->lastrec;
1189 refclock_receive(peer);
1194 * palisade_poll - called by the transmit procedure
1203 struct palisade_unit *up;
1204 struct refclockproc *pp;
1210 if (up->polled > 0) /* last reply never arrived or error */
1211 refclock_report(peer, CEVNT_TIMEOUT);
1213 up->polled = 2; /* synchronous packet + 1 event */
1217 printf("palisade_poll: unit %d: polling %s\n", unit,
1218 (pp->sloppyclockflag & CLK_FLAG2) ?
1219 "synchronous packet" : "event");
1222 if (pp->sloppyclockflag & CLK_FLAG2)
1223 return; /* using synchronous packet input */
1225 if(up->type == CLK_PRAECIS) {
1226 if(write(peer->procptr->io.fd,"SPSTAT\r\n",8) < 0)
1227 msyslog(LOG_ERR, "Palisade(%d) write: %m:",unit);
1234 if (HW_poll(pp) < 0)
1235 refclock_report(peer, CEVNT_FAULT);
1240 struct recvbuf *rbufp,
1244 static char buf[100];
1246 struct refclockproc *pp;
1250 memcpy(buf+p,rbufp->recv_space.X_recv_buffer, rbufp->recv_length);
1251 p += rbufp->recv_length;
1253 if(buf[p-2] == '\r' && buf[p-1] == '\n') {
1255 record_clock_stats(&peer->srcadr, buf);
1260 if (HW_poll(pp) < 0)
1261 refclock_report(peer, CEVNT_FAULT);
1268 struct recvbuf *rbufp
1272 * Initialize pointers and read the timecode and timestamp.
1274 struct palisade_unit *up;
1275 struct refclockproc *pp;
1280 peer = rbufp->recv_peer;
1284 if(up->type == CLK_PRAECIS) {
1286 praecis_parse(rbufp,peer);
1291 c = (char *) &rbufp->recv_space;
1292 d = c + rbufp->recv_length;
1296 /* Build time packet */
1297 switch (up->rpt_status) {
1299 case TSIP_PARSED_DLE_1:
1305 up->rpt_status = TSIP_PARSED_EMPTY;
1309 up->rpt_status = TSIP_PARSED_DATA;
1310 /* save packet ID */
1311 up->rpt_buf[0] = *c;
1316 case TSIP_PARSED_DATA:
1318 up->rpt_status = TSIP_PARSED_DLE_2;
1320 mb(up->rpt_cnt++) = *c;
1323 case TSIP_PARSED_DLE_2:
1325 up->rpt_status = TSIP_PARSED_DATA;
1330 up->rpt_status = TSIP_PARSED_FULL;
1332 /* error: start new report packet */
1333 up->rpt_status = TSIP_PARSED_DLE_1;
1334 up->rpt_buf[0] = *c;
1338 case TSIP_PARSED_FULL:
1339 case TSIP_PARSED_EMPTY:
1342 up->rpt_status = TSIP_PARSED_EMPTY;
1344 up->rpt_status = TSIP_PARSED_DLE_1;
1350 if (up->rpt_status == TSIP_PARSED_DLE_1) {
1352 if (pp->sloppyclockflag & CLK_FLAG2)
1354 get_systime(&pp->lastrec);
1356 else if (up->rpt_status == TSIP_PARSED_EMPTY)
1359 else if (up->rpt_cnt > BMAX)
1360 up->rpt_status =TSIP_PARSED_EMPTY;
1362 if (up->rpt_status == TSIP_PARSED_FULL)
1363 palisade_receive(peer);
1365 } /* while chars in buffer */
1370 * Trigger the Palisade's event input, which is driven off the RTS
1372 * Take a system time stamp to match the GPS time stamp.
1377 struct refclockproc * pp /* pointer to unit structure */
1380 int x; /* state before & after RTS set */
1381 struct palisade_unit *up;
1386 if (up->type == CLK_ACE) {
1387 /* Poll by sending a 0x21 command */
1389 tx.data = (u_char *) emalloc(100);
1390 sendcmd (&tx, 0x21);
1391 sendetx (&tx, pp->io.fd);
1395 /* read the current status, so we put things back right */
1396 if (ioctl(pp->io.fd, TIOCMGET, &x) < 0) {
1397 DPRINTF(1, ("Palisade HW_poll: unit %d: GET %m\n",
1399 msyslog(LOG_ERR, "Palisade(%d) HW_poll: ioctl(fd,GET): %m",
1404 x |= TIOCM_RTS; /* turn on RTS */
1407 if (up->type == CLK_ACUTIME)
1408 write (pp->io.fd, "", 1);
1410 if (ioctl(pp->io.fd, TIOCMSET, &x) < 0) {
1413 printf("Palisade HW_poll: unit %d: SET \n", up->unit);
1416 "Palisade(%d) HW_poll: ioctl(fd, SET, RTS_on): %m",
1421 x &= ~TIOCM_RTS; /* turn off RTS */
1423 } /* (up->type != CLK_ACE) */
1425 /* poll timestamp */
1426 get_systime(&pp->lastrec);
1428 if (up->type != CLK_ACE) {
1429 if (ioctl(pp->io.fd, TIOCMSET, &x) == -1) {
1432 printf("Palisade HW_poll: unit %d: UNSET \n", up->unit);
1435 "Palisade(%d) HW_poll: ioctl(fd, UNSET, RTS_off): %m",
1445 * copy/swap a big-endian palisade double into a host double
1452 #ifdef WORDS_BIGENDIAN
1455 memcpy(&out, bp, sizeof(out));
1468 memcpy(ui.ch, bp, sizeof(ui.ch));
1469 /* least-significant 32 bits of double from swapped bp[4] to bp[7] */
1470 uo.u32[0] = ntohl(ui.u32[1]);
1471 /* most-significant 32 bits from swapped bp[0] to bp[3] */
1472 uo.u32[1] = ntohl(ui.u32[0]);
1479 * copy/swap a big-endian palisade short into a host short
1488 memcpy(&us, bp, sizeof(us));
1489 return (short)ntohs(us);
1493 * copy/swap a big-endian palisade 32-bit int into a host 32-bit int
1502 memcpy(&u32, bp, sizeof(u32));
1503 return (int32)(u_int32)ntohl(u32);
1507 * copy/swap a big-endian 32-bit single-precision floating point into a host 32-bit int
1516 uint8_t sign, exp_field;
1519 memcpy(&mantissa, bp, sizeof(mantissa));
1520 mantissa = ((u_int32)ntohl(mantissa) & 0x7FFFFF) | 0x800000;
1521 exp_field = ((uint8_t)bp[0] << 1) + ((uint8_t)bp[1] >> 7);
1522 exponent = (int8_t)exp_field - 127;
1523 sign = ((uint8_t)bp[0] >> 7);
1525 res = (int32)(mantissa << (exponent - 23));
1527 res = (int32)(mantissa >> (23 - exponent));
1528 return sign ? -res : res;
1531 #else /* REFCLOCK && CLOCK_PALISADE*/
1532 int refclock_palisade_c_notempty;