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