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 * 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
60 * www.iar.unlp.edu.ar
61 *
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
65 *
66 * 30/08/09: Added support for Trimble Acutime Gold Receiver.
67 * Fernando P. Hauscarriaga (fernandoph@iar.unlp.edu.ar)
68 */
69
70 #ifdef HAVE_CONFIG_H
71 # include "config.h"
72 #endif
73
74 #if defined(REFCLOCK) && defined(CLOCK_PALISADE)
75
76 #ifdef SYS_WINNT
77 extern int async_write(int, const void *, unsigned int);
78 #undef write
79 #define write(fd, data, octets) async_write(fd, data, octets)
80 #endif
81
82 #include "refclock_palisade.h"
83
84 #ifdef DEBUG
85 const char * Tracking_Status[15][15] = {
86 { "Doing Fixes\0" }, { "Good 1SV\0" }, { "Approx. 1SV\0" },
87 {"Need Time\0" }, { "Need INIT\0" }, { "PDOP too High\0" },
88 { "Bad 1SV\0" }, { "0SV Usable\0" }, { "1SV Usable\0" },
89 { "2SV Usable\0" }, { "3SV Usable\0" }, { "No Integrity\0" },
90 { "Diff Corr\0" }, { "Overdet Clock\0" }, { "Invalid\0" } };
91 #endif
92
93 /*
94 * Transfer vector
95 */
96 struct refclock refclock_palisade = {
97 palisade_start, /* start up driver */
98 palisade_shutdown, /* shut down driver */
99 palisade_poll, /* transmit poll message */
100 noentry, /* not used */
101 noentry, /* initialize driver (not used) */
102 noentry, /* not used */
103 NOFLAGS /* not used */
104 };
105
106 static int decode_date(struct refclockproc *pp, const char *cp);
107
108 /* Extract the clock type from the mode setting */
109 #define CLK_TYPE(x) ((int)(((x)->ttl) & 0x7F))
110
111 /* Supported clock types */
112 #define CLK_TRIMBLE 0 /* Trimble Palisade */
113 #define CLK_PRAECIS 1 /* Endrun Technologies Praecis */
114 #define CLK_THUNDERBOLT 2 /* Trimble Thunderbolt GPS Receiver */
115 #define CLK_ACUTIME 3 /* Trimble Acutime Gold */
116 #define CLK_ACUTIMEB 4 /* Trimble Actutime Gold Port B */
117
118 int praecis_msg;
119 static void praecis_parse(struct recvbuf *rbufp, struct peer *peer);
120
121 /* These routines are for sending packets to the Thunderbolt receiver
122 * They are taken from Markus Prosch
123 */
124
125 #ifdef PALISADE_SENDCMD_RESURRECTED
126 /*
127 * sendcmd - Build data packet for sending
128 */
129 static void
sendcmd(struct packettx * buffer,int c)130 sendcmd (
131 struct packettx *buffer,
132 int c
133 )
134 {
135 *buffer->data = DLE;
136 *(buffer->data + 1) = (unsigned char)c;
137 buffer->size = 2;
138 }
139 #endif /* PALISADE_SENDCMD_RESURRECTED */
140
141 /*
142 * sendsupercmd - Build super data packet for sending
143 */
144 static void
sendsupercmd(struct packettx * buffer,int c1,int c2)145 sendsupercmd (
146 struct packettx *buffer,
147 int c1,
148 int c2
149 )
150 {
151 *buffer->data = DLE;
152 *(buffer->data + 1) = (unsigned char)c1;
153 *(buffer->data + 2) = (unsigned char)c2;
154 buffer->size = 3;
155 }
156
157 /*
158 * sendbyte -
159 */
160 static void
sendbyte(struct packettx * buffer,int b)161 sendbyte (
162 struct packettx *buffer,
163 int b
164 )
165 {
166 if (b == DLE)
167 *(buffer->data+buffer->size++) = DLE;
168 *(buffer->data+buffer->size++) = (unsigned char)b;
169 }
170
171 /*
172 * sendint -
173 */
174 static void
sendint(struct packettx * buffer,int a)175 sendint (
176 struct packettx *buffer,
177 int a
178 )
179 {
180 sendbyte(buffer, (unsigned char)((a>>8) & 0xff));
181 sendbyte(buffer, (unsigned char)(a & 0xff));
182 }
183
184 /*
185 * sendetx - Send packet or super packet to the device
186 */
187 static int
sendetx(struct packettx * buffer,int fd)188 sendetx (
189 struct packettx *buffer,
190 int fd
191 )
192 {
193 int result;
194
195 *(buffer->data+buffer->size++) = DLE;
196 *(buffer->data+buffer->size++) = ETX;
197 result = write(fd, buffer->data, (unsigned long)buffer->size);
198
199 if (result != -1)
200 return (result);
201 else
202 return (-1);
203 }
204
205 /*
206 * init_thunderbolt - Prepares Thunderbolt receiver to be used with
207 * NTP (also taken from Markus Prosch).
208 */
209 static void
init_thunderbolt(int fd)210 init_thunderbolt (
211 int fd
212 )
213 {
214 struct packettx tx;
215
216 tx.size = 0;
217 tx.data = (u_char *) emalloc(100);
218
219 /* set UTC time */
220 sendsupercmd (&tx, 0x8E, 0xA2);
221 sendbyte (&tx, 0x3);
222 sendetx (&tx, fd);
223
224 /* activate packets 0x8F-AB and 0x8F-AC */
225 sendsupercmd (&tx, 0x8E, 0xA5);
226 sendint (&tx, 0x5);
227 sendetx (&tx, fd);
228
229 free(tx.data);
230 }
231
232 /*
233 * init_acutime - Prepares Acutime Receiver to be used with NTP
234 */
235 static void
init_acutime(int fd)236 init_acutime (
237 int fd
238 )
239 {
240 /* Disable all outputs, Enable Event-Polling on PortA so
241 we can ask for time packets */
242 struct packettx tx;
243
244 tx.size = 0;
245 tx.data = (u_char *) emalloc(100);
246
247 sendsupercmd(&tx, 0x8E, 0xA5);
248 sendbyte(&tx, 0x02);
249 sendbyte(&tx, 0x00);
250 sendbyte(&tx, 0x00);
251 sendbyte(&tx, 0x00);
252 sendetx(&tx, fd);
253
254 free(tx.data);
255 }
256
257 /*
258 * palisade_start - open the devices and initialize data for processing
259 */
260 static int
palisade_start(int unit,struct peer * peer)261 palisade_start (
262 int unit,
263 struct peer *peer
264 )
265 {
266 struct palisade_unit *up;
267 struct refclockproc *pp;
268 int fd;
269 char gpsdev[20];
270 struct termios tio;
271
272 snprintf(gpsdev, sizeof(gpsdev), DEVICE, unit);
273
274 /*
275 * Open serial port.
276 */
277 fd = refclock_open(gpsdev, SPEED232, LDISC_RAW);
278 if (fd <= 0) {
279 #ifdef DEBUG
280 printf("Palisade(%d) start: open %s failed\n", unit, gpsdev);
281 #endif
282 return 0;
283 }
284
285 msyslog(LOG_NOTICE, "Palisade(%d) fd: %d dev: %s", unit, fd,
286 gpsdev);
287
288 if (tcgetattr(fd, &tio) < 0) {
289 msyslog(LOG_ERR,
290 "Palisade(%d) tcgetattr(fd, &tio): %m",unit);
291 #ifdef DEBUG
292 printf("Palisade(%d) tcgetattr(fd, &tio)\n",unit);
293 #endif
294 close(fd);
295 return (0);
296 }
297
298 tio.c_cflag |= (PARENB|PARODD);
299 tio.c_iflag &= ~ICRNL;
300
301 /*
302 * Allocate and initialize unit structure
303 */
304 up = emalloc_zero(sizeof(*up));
305
306 up->type = CLK_TYPE(peer);
307 switch (up->type) {
308 case CLK_TRIMBLE:
309 /* Normal mode, do nothing */
310 break;
311 case CLK_PRAECIS:
312 msyslog(LOG_NOTICE, "Palisade(%d) Praecis mode enabled"
313 ,unit);
314 break;
315 case CLK_THUNDERBOLT:
316 msyslog(LOG_NOTICE, "Palisade(%d) Thunderbolt mode enabled"
317 ,unit);
318 tio.c_cflag = (CS8|CLOCAL|CREAD);
319 break;
320 case CLK_ACUTIME:
321 msyslog(LOG_NOTICE, "Palisade(%d) Acutime Gold mode enabled"
322 ,unit);
323 break;
324 default:
325 msyslog(LOG_NOTICE, "Palisade(%d) mode unknown",unit);
326 break;
327 }
328 if (tcsetattr(fd, TCSANOW, &tio) == -1) {
329 msyslog(LOG_ERR, "Palisade(%d) tcsetattr(fd, &tio): %m",unit);
330 #ifdef DEBUG
331 printf("Palisade(%d) tcsetattr(fd, &tio)\n",unit);
332 #endif
333 close(fd);
334 free(up);
335 return 0;
336 }
337
338 pp = peer->procptr;
339 pp->io.clock_recv = palisade_io;
340 pp->io.srcclock = peer;
341 pp->io.datalen = 0;
342 pp->io.fd = fd;
343 if (!io_addclock(&pp->io)) {
344 #ifdef DEBUG
345 printf("Palisade(%d) io_addclock\n",unit);
346 #endif
347 close(fd);
348 pp->io.fd = -1;
349 free(up);
350 return (0);
351 }
352
353 /*
354 * Initialize miscellaneous variables
355 */
356 pp->unitptr = up;
357 pp->clockdesc = DESCRIPTION;
358
359 peer->precision = PRECISION;
360 peer->sstclktype = CTL_SST_TS_UHF;
361 peer->minpoll = TRMB_MINPOLL;
362 peer->maxpoll = TRMB_MAXPOLL;
363 memcpy((char *)&pp->refid, REFID, 4);
364
365 up->leap_status = 0;
366 up->unit = (short) unit;
367 up->rpt_status = TSIP_PARSED_EMPTY;
368 up->rpt_cnt = 0;
369
370 if (up->type == CLK_THUNDERBOLT)
371 init_thunderbolt(fd);
372 if (up->type == CLK_ACUTIME)
373 init_acutime(fd);
374
375 return 1;
376 }
377
378
379 /*
380 * palisade_shutdown - shut down the clock
381 */
382 static void
palisade_shutdown(int unit,struct peer * peer)383 palisade_shutdown (
384 int unit,
385 struct peer *peer
386 )
387 {
388 struct palisade_unit *up;
389 struct refclockproc *pp;
390 pp = peer->procptr;
391 up = pp->unitptr;
392 if (-1 != pp->io.fd)
393 io_closeclock(&pp->io);
394 if (NULL != up)
395 free(up);
396 }
397
398
399 /*
400 * unpack helpers
401 */
402
403 static inline uint8_t
get_u8(const char * cp)404 get_u8(
405 const char *cp)
406 {
407 return ((const u_char*)cp)[0];
408 }
409
410 static inline uint16_t
get_u16(const char * cp)411 get_u16(
412 const char *cp)
413 {
414 return ((uint16_t)get_u8(cp) << 8) | get_u8(cp + 1);
415 }
416
417 /*
418 * unpack & fix date (the receiver provides a valid time for 1024 weeks
419 * after 1997-12-14 and therefore folds back in 2017, 2037,...)
420 *
421 * Returns -1 on error, day-of-month + (month * 32) othertwise.
422 */
423 int
decode_date(struct refclockproc * pp,const char * cp)424 decode_date(
425 struct refclockproc *pp,
426 const char *cp)
427 {
428 static int32_t s_baseday = 0;
429
430 struct calendar jd;
431 int32_t rd;
432
433 if (0 == s_baseday) {
434 if (!ntpcal_get_build_date(&jd)) {
435 jd.year = 2015;
436 jd.month = 1;
437 jd.monthday = 1;
438 }
439 s_baseday = ntpcal_date_to_rd(&jd);
440 }
441
442 /* get date fields and convert to RDN */
443 jd.monthday = get_u8 ( cp );
444 jd.month = get_u8 (cp + 1);
445 jd.year = get_u16(cp + 2);
446 rd = ntpcal_date_to_rd(&jd);
447
448 /* for the paranoid: do reverse calculation and cross-check */
449 ntpcal_rd_to_date(&jd, rd);
450 if ((jd.monthday != get_u8 ( cp )) ||
451 (jd.month != get_u8 (cp + 1)) ||
452 (jd.year != get_u16(cp + 2)) )
453 return - 1;
454
455 /* calculate cycle shift to base day and calculate re-folded
456 * date
457 *
458 * One could do a proper modulo calculation here, but a counting
459 * loop is probably faster for the next few rollovers...
460 */
461 while (rd < s_baseday)
462 rd += 7*1024;
463 ntpcal_rd_to_date(&jd, rd);
464
465 /* fill refclock structure & indicate success */
466 pp->day = jd.yearday;
467 pp->year = jd.year;
468 return ((int)jd.month << 5) | jd.monthday;
469 }
470
471
472 /*
473 * TSIP_decode - decode the TSIP data packets
474 */
475 int
TSIP_decode(struct peer * peer)476 TSIP_decode (
477 struct peer *peer
478 )
479 {
480 int st;
481 long secint;
482 double secs;
483 double secfrac;
484 unsigned short event = 0;
485 int mmday;
486
487 struct palisade_unit *up;
488 struct refclockproc *pp;
489
490 pp = peer->procptr;
491 up = pp->unitptr;
492
493 /*
494 * Check the time packet, decode its contents.
495 * If the timecode has invalid length or is not in
496 * proper format, declare bad format and exit.
497 */
498
499 if ((up->type != CLK_THUNDERBOLT) & (up->type != CLK_ACUTIME)){
500 if ((up->rpt_buf[0] == (char) 0x41) ||
501 (up->rpt_buf[0] == (char) 0x46) ||
502 (up->rpt_buf[0] == (char) 0x54) ||
503 (up->rpt_buf[0] == (char) 0x4B) ||
504 (up->rpt_buf[0] == (char) 0x6D)) {
505
506 /* standard time packet - GPS time and GPS week number */
507 #ifdef DEBUG
508 printf("Palisade Port B packets detected. Connect to Port A\n");
509 #endif
510
511 return 0;
512 }
513 }
514
515 /*
516 * We cast both to u_char to as 0x8f uses the sign bit on a char
517 */
518 if ((u_char) up->rpt_buf[0] == (u_char) 0x8f) {
519 /*
520 * Superpackets
521 */
522 event = (unsigned short) (getint((u_char *) &mb(1)) & 0xffff);
523 if (!((pp->sloppyclockflag & CLK_FLAG2) || event))
524 /* Ignore Packet */
525 return 0;
526
527 switch (mb(0) & 0xff) {
528 int GPS_UTC_Offset;
529 long tow;
530
531 case PACKET_8F0B:
532
533 if (up->polled <= 0)
534 return 0;
535
536 if (up->rpt_cnt != LENCODE_8F0B) /* check length */
537 break;
538
539 #ifdef DEBUG
540 if (debug > 1) {
541 int ts;
542 double lat, lon, alt;
543 lat = getdbl((u_char *) &mb(42)) * R2D;
544 lon = getdbl((u_char *) &mb(50)) * R2D;
545 alt = getdbl((u_char *) &mb(58));
546
547 printf("TSIP_decode: unit %d: Latitude: %03.4f Longitude: %03.4f Alt: %05.2f m\n",
548 up->unit, lat,lon,alt);
549 printf("TSIP_decode: unit %d: Sats:",
550 up->unit);
551 for (st = 66, ts = 0; st <= 73; st++)
552 if (mb(st)) {
553 if (mb(st) > 0) ts++;
554 printf(" %02d", mb(st));
555 }
556 printf(" : Tracking %d\n", ts);
557 }
558 #endif
559
560 GPS_UTC_Offset = getint((u_char *) &mb(16));
561 if (GPS_UTC_Offset == 0) { /* Check UTC offset */
562 #ifdef DEBUG
563 printf("TSIP_decode: UTC Offset Unknown\n");
564 #endif
565 break;
566 }
567
568 secs = getdbl((u_char *) &mb(3));
569 secint = (long) secs;
570 secfrac = secs - secint; /* 0.0 <= secfrac < 1.0 */
571
572 pp->nsec = (long) (secfrac * 1000000000);
573
574 secint %= 86400; /* Only care about today */
575 pp->hour = secint / 3600;
576 secint %= 3600;
577 pp->minute = secint / 60;
578 secint %= 60;
579 pp->second = secint % 60;
580
581 mmday = decode_date(pp, &mb(11));
582 if (mmday < 0)
583 break;
584
585 #ifdef DEBUG
586 if (debug > 1)
587 printf("TSIP_decode: unit %d: %02X #%d %02d:%02d:%02d.%09ld %02d/%02d/%04d UTC %02d\n",
588 up->unit, mb(0) & 0xff, event, pp->hour, pp->minute,
589 pp->second, pp->nsec, (mmday >> 5), (mmday & 31), pp->year, GPS_UTC_Offset);
590 #endif
591 /* Only use this packet when no
592 * 8F-AD's are being received
593 */
594
595 if (up->leap_status) {
596 up->leap_status = 0;
597 return 0;
598 }
599
600 return 2;
601 break;
602
603 case PACKET_NTP:
604 /* Palisade-NTP Packet */
605
606 if (up->rpt_cnt != LENCODE_NTP) /* check length */
607 break;
608
609 up->leap_status = mb(19);
610
611 if (up->polled <= 0)
612 return 0;
613
614 /* Check Tracking Status */
615 st = mb(18);
616 if (st < 0 || st > 14)
617 st = 14;
618 if ((st >= 2 && st <= 7) || st == 11 || st == 12) {
619 #ifdef DEBUG
620 printf("TSIP_decode: Not Tracking Sats : %s\n",
621 *Tracking_Status[st]);
622 #endif
623 refclock_report(peer, CEVNT_BADTIME);
624 up->polled = -1;
625 return 0;
626 break;
627 }
628
629 mmday = decode_date(pp, &mb(14));
630 if (mmday < 0)
631 break;
632 up->month = (mmday >> 5); /* Save for LEAP check */
633
634 if ( (up->leap_status & PALISADE_LEAP_PENDING) &&
635 /* Avoid early announce: https://bugs.ntp.org/2773 */
636 (6 == up->month || 12 == up->month) ) {
637 if (up->leap_status & PALISADE_UTC_TIME)
638 pp->leap = LEAP_ADDSECOND;
639 else
640 pp->leap = LEAP_DELSECOND;
641 }
642 else if (up->leap_status)
643 pp->leap = LEAP_NOWARNING;
644
645 else { /* UTC flag is not set:
646 * Receiver may have been reset, and lost
647 * its UTC almanac data */
648 pp->leap = LEAP_NOTINSYNC;
649 #ifdef DEBUG
650 printf("TSIP_decode: UTC Almanac unavailable: %d\n",
651 mb(19));
652 #endif
653 refclock_report(peer, CEVNT_BADTIME);
654 up->polled = -1;
655 return 0;
656 }
657
658 pp->nsec = (long) (getdbl((u_char *) &mb(3))
659 * 1000000000);
660
661 pp->hour = mb(11);
662 pp->minute = mb(12);
663 pp->second = mb(13);
664
665 #ifdef DEBUG
666 if (debug > 1)
667 printf("TSIP_decode: unit %d: %02X #%d %02d:%02d:%02d.%09ld %02d/%02d/%04d UTC %02x %s\n",
668 up->unit, mb(0) & 0xff, event, pp->hour, pp->minute,
669 pp->second, pp->nsec, (mmday >> 5), (mmday & 31), pp->year,
670 mb(19), *Tracking_Status[st]);
671 #endif
672 return 1;
673 break;
674
675 case PACKET_8FAC:
676 if (up->polled <= 0)
677 return 0;
678
679 if (up->rpt_cnt != LENCODE_8FAC)/* check length */
680 break;
681
682 #ifdef DEBUG
683 if (debug > 1) {
684 double lat, lon, alt;
685 lat = getdbl((u_char *) &mb(36)) * R2D;
686 lon = getdbl((u_char *) &mb(44)) * R2D;
687 alt = getdbl((u_char *) &mb(52));
688
689 printf("TSIP_decode: unit %d: Latitude: %03.4f Longitude: %03.4f Alt: %05.2f m\n",
690 up->unit, lat,lon,alt);
691 printf("TSIP_decode: unit %d\n", up->unit);
692 }
693 #endif
694 if ( (getint((u_char *) &mb(10)) & 0x80) &&
695 /* Avoid early announce: https://bugs.ntp.org/2773 */
696 (6 == up->month || 12 == up->month) )
697 pp->leap = LEAP_ADDSECOND; /* we ASSUME addsecond */
698 else
699 pp->leap = LEAP_NOWARNING;
700
701 #ifdef DEBUG
702 if (debug > 1)
703 printf("TSIP_decode: unit %d: 0x%02x leap %d\n",
704 up->unit, mb(0) & 0xff, pp->leap);
705 if (debug > 1) {
706 printf("Receiver MODE: 0x%02X\n", (u_char)mb(1));
707 if (mb(1) == 0x00)
708 printf(" AUTOMATIC\n");
709 if (mb(1) == 0x01)
710 printf(" SINGLE SATELLITE\n");
711 if (mb(1) == 0x03)
712 printf(" HORIZONTAL(2D)\n");
713 if (mb(1) == 0x04)
714 printf(" FULL POSITION(3D)\n");
715 if (mb(1) == 0x05)
716 printf(" DGPR REFERENCE\n");
717 if (mb(1) == 0x06)
718 printf(" CLOCK HOLD(2D)\n");
719 if (mb(1) == 0x07)
720 printf(" OVERDETERMINED CLOCK\n");
721
722 printf("\n** Disciplining MODE 0x%02X:\n", (u_char)mb(2));
723 if (mb(2) == 0x00)
724 printf(" NORMAL\n");
725 if (mb(2) == 0x01)
726 printf(" POWER-UP\n");
727 if (mb(2) == 0x02)
728 printf(" AUTO HOLDOVER\n");
729 if (mb(2) == 0x03)
730 printf(" MANUAL HOLDOVER\n");
731 if (mb(2) == 0x04)
732 printf(" RECOVERY\n");
733 if (mb(2) == 0x06)
734 printf(" DISCIPLINING DISABLED\n");
735 }
736 #endif
737 return 0;
738 break;
739
740 case PACKET_8FAB:
741 /* Thunderbolt Primary Timing Packet */
742
743 if (up->rpt_cnt != LENCODE_8FAB) /* check length */
744 break;
745
746 if (up->polled <= 0)
747 return 0;
748
749 GPS_UTC_Offset = getint((u_char *) &mb(7));
750
751 if (GPS_UTC_Offset == 0){ /* Check UTC Offset */
752 #ifdef DEBUG
753 printf("TSIP_decode: UTC Offset Unknown\n");
754 #endif
755 break;
756 }
757
758
759 if ((mb(9) & 0x1d) == 0x0) {
760 /* if we know the GPS time and the UTC offset,
761 we expect UTC timing information !!! */
762
763 pp->leap = LEAP_NOTINSYNC;
764 refclock_report(peer, CEVNT_BADTIME);
765 up->polled = -1;
766 return 0;
767 }
768
769 pp->nsec = 0;
770 #ifdef DEBUG
771 printf("\nTiming Flags are:\n");
772 printf("Timing flag value is: 0x%X\n", mb(9));
773 if ((mb(9) & 0x01) != 0)
774 printf (" Getting UTC time\n");
775 else
776 printf (" Getting GPS time\n");
777 if ((mb(9) & 0x02) != 0)
778 printf (" PPS is from UTC\n");
779 else
780 printf (" PPS is from GPS\n");
781 if ((mb(9) & 0x04) != 0)
782 printf (" Time is not Set\n");
783 else
784 printf (" Time is Set\n");
785 if ((mb(9) & 0x08) != 0)
786 printf(" I dont have UTC info\n");
787 else
788 printf (" I have UTC info\n");
789 if ((mb(9) & 0x10) != 0)
790 printf (" Time is from USER\n\n");
791 else
792 printf (" Time is from GPS\n\n");
793 #endif
794
795 mmday = decode_date(pp, &mb(13));
796 if (mmday < 0)
797 break;
798 tow = getlong((u_char *) &mb(1));
799 #ifdef DEBUG
800 if (debug > 1) {
801 printf("pp->day: %d\n", pp->day);
802 printf("TOW: %ld\n", tow);
803 printf("DAY: %d\n", (mmday & 31));
804 }
805 #endif
806 pp->hour = mb(12);
807 pp->minute = mb(11);
808 pp->second = mb(10);
809
810
811 #ifdef DEBUG
812 if (debug > 1)
813 printf("TSIP_decode: unit %d: %02X #%d %02d:%02d:%02d.%09ld %02d/%02d/%04d ",
814 up->unit, mb(0) & 0xff, event, pp->hour, pp->minute, pp->second,
815 pp->nsec, (mmday >> 5), (mmday & 31), pp->year);
816 #endif
817 return 1;
818 break;
819
820 default:
821 /* Ignore Packet */
822 return 0;
823 } /* switch */
824 } /* if 8F packets */
825
826 else if (up->rpt_buf[0] == (u_char)0x42) {
827 printf("0x42\n");
828 return 0;
829 }
830 else if (up->rpt_buf[0] == (u_char)0x43) {
831 printf("0x43\n");
832 return 0;
833 }
834 else if ((up->rpt_buf[0] == PACKET_41) & (up->type == CLK_THUNDERBOLT)){
835 printf("Undocumented 0x41 packet on Thunderbolt\n");
836 return 0;
837 }
838 else if ((up->rpt_buf[0] == PACKET_41A) & (up->type == CLK_ACUTIME)) {
839 #ifdef DEBUG
840 printf("GPS TOW: %ld\n", (long)getlong((u_char *) &mb(0)));
841 printf("GPS WN: %d\n", getint((u_char *) &mb(4)));
842 printf("GPS UTC-GPS Offser: %ld\n", (long)getlong((u_char *) &mb(6)));
843 #endif
844 return 0;
845 }
846
847 /* Health Status for Acutime Receiver */
848 else if ((up->rpt_buf[0] == PACKET_46) & (up->type == CLK_ACUTIME)) {
849 #ifdef DEBUG
850 if (debug > 1)
851 /* Status Codes */
852 switch (mb(0)) {
853 case 0x00:
854 printf ("Doing Position Fixes\n");
855 break;
856 case 0x01:
857 printf ("Do no have GPS time yet\n");
858 break;
859 case 0x03:
860 printf ("PDOP is too high\n");
861 break;
862 case 0x08:
863 printf ("No usable satellites\n");
864 break;
865 case 0x09:
866 printf ("Only 1 usable satellite\n");
867 break;
868 case 0x0A:
869 printf ("Only 2 usable satellites\n");
870 break;
871 case 0x0B:
872 printf ("Only 3 usable satellites\n");
873 break;
874 case 0x0C:
875 printf("The Chosen satellite is unusable\n");
876 break;
877 }
878 #endif
879 /* Error Codes */
880 if (mb(1) != 0) {
881
882 refclock_report(peer, CEVNT_BADTIME);
883 up->polled = -1;
884 #ifdef DEBUG
885 if (debug > 1) {
886 if (mb(1) & 0x01)
887 printf ("Signal Processor Error, reset unit.\n");
888 if (mb(1) & 0x02)
889 printf ("Alignment error, channel or chip 1, reset unit.\n");
890 if (mb(1) & 0x03)
891 printf ("Alignment error, channel or chip 2, reset unit.\n");
892 if (mb(1) & 0x04)
893 printf ("Antenna feed line fault (open or short)\n");
894 if (mb(1) & 0x05)
895 printf ("Excessive reference frequency error, refer to packet 0x2D and packet 0x4D documentation for further information\n");
896 }
897 #endif
898
899 return 0;
900 }
901 }
902 else if (up->rpt_buf[0] == 0x54)
903 return 0;
904
905 else if (up->rpt_buf[0] == PACKET_6D) {
906 #ifdef DEBUG
907 int sats;
908
909 if ((mb(0) & 0x01) && (mb(0) & 0x02))
910 printf("2d Fix Dimension\n");
911 if (mb(0) & 0x04)
912 printf("3d Fix Dimension\n");
913
914 if (mb(0) & 0x08)
915 printf("Fix Mode is MANUAL\n");
916 else
917 printf("Fix Mode is AUTO\n");
918
919 sats = mb(0) & 0xF0;
920 sats = sats >> 4;
921 printf("Tracking %d Satellites\n", sats);
922 #endif
923 return 0;
924 } /* else if not super packet */
925 refclock_report(peer, CEVNT_BADREPLY);
926 up->polled = -1;
927 #ifdef DEBUG
928 printf("TSIP_decode: unit %d: bad packet %02x-%02x event %d len %d\n",
929 up->unit, up->rpt_buf[0] & 0xff, mb(0) & 0xff,
930 event, up->rpt_cnt);
931 #endif
932 return 0;
933 }
934
935 /*
936 * palisade__receive - receive data from the serial interface
937 */
938
939 static void
palisade_receive(struct peer * peer)940 palisade_receive (
941 struct peer * peer
942 )
943 {
944 struct palisade_unit *up;
945 struct refclockproc *pp;
946
947 /*
948 * Initialize pointers and read the timecode and timestamp.
949 */
950 pp = peer->procptr;
951 up = pp->unitptr;
952
953 if (! TSIP_decode(peer)) return;
954
955 if (up->polled <= 0)
956 return; /* no poll pending, already received or timeout */
957
958 up->polled = 0; /* Poll reply received */
959 pp->lencode = 0; /* clear time code */
960 #ifdef DEBUG
961 if (debug)
962 printf(
963 "palisade_receive: unit %d: %4d %03d %02d:%02d:%02d.%09ld\n",
964 up->unit, pp->year, pp->day, pp->hour, pp->minute,
965 pp->second, pp->nsec);
966 #endif
967
968 /*
969 * Process the sample
970 * Generate timecode: YYYY DoY HH:MM:SS.microsec
971 * report and process
972 */
973
974 snprintf(pp->a_lastcode, sizeof(pp->a_lastcode),
975 "%4d %03d %02d:%02d:%02d.%09ld",
976 pp->year, pp->day,
977 pp->hour,pp->minute, pp->second, pp->nsec);
978 pp->lencode = 24;
979
980 if (!refclock_process(pp)) {
981 refclock_report(peer, CEVNT_BADTIME);
982
983 #ifdef DEBUG
984 printf("palisade_receive: unit %d: refclock_process failed!\n",
985 up->unit);
986 #endif
987 return;
988 }
989
990 record_clock_stats(&peer->srcadr, pp->a_lastcode);
991
992 #ifdef DEBUG
993 if (debug)
994 printf("palisade_receive: unit %d: %s\n",
995 up->unit, prettydate(&pp->lastrec));
996 #endif
997 pp->lastref = pp->lastrec;
998 refclock_receive(peer);
999 }
1000
1001
1002 /*
1003 * palisade_poll - called by the transmit procedure
1004 *
1005 */
1006 static void
palisade_poll(int unit,struct peer * peer)1007 palisade_poll (
1008 int unit,
1009 struct peer *peer
1010 )
1011 {
1012 struct palisade_unit *up;
1013 struct refclockproc *pp;
1014
1015 pp = peer->procptr;
1016 up = pp->unitptr;
1017
1018 pp->polls++;
1019 if (up->polled > 0) /* last reply never arrived or error */
1020 refclock_report(peer, CEVNT_TIMEOUT);
1021
1022 up->polled = 2; /* synchronous packet + 1 event */
1023
1024 #ifdef DEBUG
1025 if (debug)
1026 printf("palisade_poll: unit %d: polling %s\n", unit,
1027 (pp->sloppyclockflag & CLK_FLAG2) ?
1028 "synchronous packet" : "event");
1029 #endif
1030
1031 if (pp->sloppyclockflag & CLK_FLAG2)
1032 return; /* using synchronous packet input */
1033
1034 if(up->type == CLK_PRAECIS) {
1035 if(write(peer->procptr->io.fd,"SPSTAT\r\n",8) < 0)
1036 msyslog(LOG_ERR, "Palisade(%d) write: %m:",unit);
1037 else {
1038 praecis_msg = 1;
1039 return;
1040 }
1041 }
1042
1043 if (HW_poll(pp) < 0)
1044 refclock_report(peer, CEVNT_FAULT);
1045 }
1046
1047 static void
praecis_parse(struct recvbuf * rbufp,struct peer * peer)1048 praecis_parse (
1049 struct recvbuf *rbufp,
1050 struct peer *peer
1051 )
1052 {
1053 static char buf[100];
1054 static int p = 0;
1055 struct refclockproc *pp;
1056
1057 pp = peer->procptr;
1058
1059 memcpy(buf+p,rbufp->recv_space.X_recv_buffer, rbufp->recv_length);
1060 p += rbufp->recv_length;
1061
1062 if(buf[p-2] == '\r' && buf[p-1] == '\n') {
1063 buf[p-2] = '\0';
1064 record_clock_stats(&peer->srcadr, buf);
1065
1066 p = 0;
1067 praecis_msg = 0;
1068
1069 if (HW_poll(pp) < 0)
1070 refclock_report(peer, CEVNT_FAULT);
1071
1072 }
1073 }
1074
1075 static void
palisade_io(struct recvbuf * rbufp)1076 palisade_io (
1077 struct recvbuf *rbufp
1078 )
1079 {
1080 /*
1081 * Initialize pointers and read the timecode and timestamp.
1082 */
1083 struct palisade_unit *up;
1084 struct refclockproc *pp;
1085 struct peer *peer;
1086
1087 char * c, * d;
1088
1089 peer = rbufp->recv_peer;
1090 pp = peer->procptr;
1091 up = pp->unitptr;
1092
1093 if(up->type == CLK_PRAECIS) {
1094 if(praecis_msg) {
1095 praecis_parse(rbufp,peer);
1096 return;
1097 }
1098 }
1099
1100 c = (char *) &rbufp->recv_space;
1101 d = c + rbufp->recv_length;
1102
1103 while (c != d) {
1104
1105 /* Build time packet */
1106 switch (up->rpt_status) {
1107
1108 case TSIP_PARSED_DLE_1:
1109 switch (*c)
1110 {
1111 case 0:
1112 case DLE:
1113 case ETX:
1114 up->rpt_status = TSIP_PARSED_EMPTY;
1115 break;
1116
1117 default:
1118 up->rpt_status = TSIP_PARSED_DATA;
1119 /* save packet ID */
1120 up->rpt_buf[0] = *c;
1121 break;
1122 }
1123 break;
1124
1125 case TSIP_PARSED_DATA:
1126 if (*c == DLE)
1127 up->rpt_status = TSIP_PARSED_DLE_2;
1128 else
1129 mb(up->rpt_cnt++) = *c;
1130 break;
1131
1132 case TSIP_PARSED_DLE_2:
1133 if (*c == DLE) {
1134 up->rpt_status = TSIP_PARSED_DATA;
1135 mb(up->rpt_cnt++) =
1136 *c;
1137 }
1138 else if (*c == ETX)
1139 up->rpt_status = TSIP_PARSED_FULL;
1140 else {
1141 /* error: start new report packet */
1142 up->rpt_status = TSIP_PARSED_DLE_1;
1143 up->rpt_buf[0] = *c;
1144 }
1145 break;
1146
1147 case TSIP_PARSED_FULL:
1148 case TSIP_PARSED_EMPTY:
1149 default:
1150 if ( *c != DLE)
1151 up->rpt_status = TSIP_PARSED_EMPTY;
1152 else
1153 up->rpt_status = TSIP_PARSED_DLE_1;
1154 break;
1155 }
1156
1157 c++;
1158
1159 if (up->rpt_status == TSIP_PARSED_DLE_1) {
1160 up->rpt_cnt = 0;
1161 if (pp->sloppyclockflag & CLK_FLAG2)
1162 /* stamp it */
1163 get_systime(&pp->lastrec);
1164 }
1165 else if (up->rpt_status == TSIP_PARSED_EMPTY)
1166 up->rpt_cnt = 0;
1167
1168 else if (up->rpt_cnt > BMAX)
1169 up->rpt_status =TSIP_PARSED_EMPTY;
1170
1171 if (up->rpt_status == TSIP_PARSED_FULL)
1172 palisade_receive(peer);
1173
1174 } /* while chars in buffer */
1175 }
1176
1177
1178 /*
1179 * Trigger the Palisade's event input, which is driven off the RTS
1180 *
1181 * Take a system time stamp to match the GPS time stamp.
1182 *
1183 */
1184 long
HW_poll(struct refclockproc * pp)1185 HW_poll (
1186 struct refclockproc * pp /* pointer to unit structure */
1187 )
1188 {
1189 int x; /* state before & after RTS set */
1190 struct palisade_unit *up;
1191
1192 up = pp->unitptr;
1193
1194 /* read the current status, so we put things back right */
1195 if (ioctl(pp->io.fd, TIOCMGET, &x) < 0) {
1196 DPRINTF(1, ("Palisade HW_poll: unit %d: GET %m\n",
1197 up->unit));
1198 msyslog(LOG_ERR, "Palisade(%d) HW_poll: ioctl(fd,GET): %m",
1199 up->unit);
1200 return -1;
1201 }
1202
1203 x |= TIOCM_RTS; /* turn on RTS */
1204
1205 /* Edge trigger */
1206 if (up->type == CLK_ACUTIME)
1207 write (pp->io.fd, "", 1);
1208
1209 if (ioctl(pp->io.fd, TIOCMSET, &x) < 0) {
1210 #ifdef DEBUG
1211 if (debug)
1212 printf("Palisade HW_poll: unit %d: SET \n", up->unit);
1213 #endif
1214 msyslog(LOG_ERR,
1215 "Palisade(%d) HW_poll: ioctl(fd, SET, RTS_on): %m",
1216 up->unit);
1217 return -1;
1218 }
1219
1220 x &= ~TIOCM_RTS; /* turn off RTS */
1221
1222 /* poll timestamp */
1223 get_systime(&pp->lastrec);
1224
1225 if (ioctl(pp->io.fd, TIOCMSET, &x) == -1) {
1226 #ifdef DEBUG
1227 if (debug)
1228 printf("Palisade HW_poll: unit %d: UNSET \n", up->unit);
1229 #endif
1230 msyslog(LOG_ERR,
1231 "Palisade(%d) HW_poll: ioctl(fd, UNSET, RTS_off): %m",
1232 up->unit);
1233 return -1;
1234 }
1235
1236 return 0;
1237 }
1238
1239 /*
1240 * copy/swap a big-endian palisade double into a host double
1241 */
1242 static double
getdbl(u_char * bp)1243 getdbl (
1244 u_char *bp
1245 )
1246 {
1247 #ifdef WORDS_BIGENDIAN
1248 double out;
1249
1250 memcpy(&out, bp, sizeof(out));
1251 return out;
1252 #else
1253 union {
1254 u_char ch[8];
1255 u_int32 u32[2];
1256 } ui;
1257
1258 union {
1259 double out;
1260 u_int32 u32[2];
1261 } uo;
1262
1263 memcpy(ui.ch, bp, sizeof(ui.ch));
1264 /* least-significant 32 bits of double from swapped bp[4] to bp[7] */
1265 uo.u32[0] = ntohl(ui.u32[1]);
1266 /* most-significant 32 bits from swapped bp[0] to bp[3] */
1267 uo.u32[1] = ntohl(ui.u32[0]);
1268
1269 return uo.out;
1270 #endif
1271 }
1272
1273 /*
1274 * copy/swap a big-endian palisade short into a host short
1275 */
1276 static short
getint(u_char * bp)1277 getint (
1278 u_char *bp
1279 )
1280 {
1281 u_short us;
1282
1283 memcpy(&us, bp, sizeof(us));
1284 return (short)ntohs(us);
1285 }
1286
1287 /*
1288 * copy/swap a big-endian palisade 32-bit int into a host 32-bit int
1289 */
1290 static int32
getlong(u_char * bp)1291 getlong(
1292 u_char *bp
1293 )
1294 {
1295 u_int32 u32;
1296
1297 memcpy(&u32, bp, sizeof(u32));
1298 return (int32)(u_int32)ntohl(u32);
1299 }
1300
1301 #else /* REFCLOCK && CLOCK_PALISADE*/
1302 int refclock_palisade_c_notempty;
1303 #endif
1304