Coverage Report

Created: 2026-02-26 06:20

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