Coverage Report

Created: 2023-05-19 06:16

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