Coverage Report

Created: 2023-05-19 06:16

/src/ntp-dev/ntpd/refclock_leitch.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * refclock_leitch - clock driver for the Leitch CSD-5300 Master Clock
3
 */
4
5
#ifdef HAVE_CONFIG_H
6
# include <config.h>
7
#endif
8
9
#include "ntp_types.h"
10
11
#if defined(REFCLOCK) && defined(CLOCK_LEITCH)
12
13
#include <stdio.h>
14
#include <ctype.h>
15
16
#include "ntpd.h"
17
#include "ntp_io.h"
18
#include "ntp_refclock.h"
19
#include "timevalops.h"
20
#include "ntp_stdlib.h"
21
22
23
/*
24
 * Driver for Leitch CSD-5300 Master Clock System
25
 *
26
 * COMMANDS:
27
 *  DATE: D <CR>
28
 *  TIME: T <CR>
29
 *  STATUS: S <CR>
30
 *  LOOP: L <CR>
31
 *
32
 * FORMAT:
33
 *  DATE: YYMMDD<CR>
34
 *  TIME: <CR>/HHMMSS <CR>/HHMMSS <CR>/HHMMSS <CR>/
35
 *    second bondaried on the stop bit of the <CR>
36
 *    second boundaries at '/' above.
37
 *  STATUS: G (good), D (diag fail), T (time not provided) or
38
 *    P (last phone update failed)
39
 */
40
0
#define PRECISION (-20)  /* 1x10-8 */
41
0
#define MAXUNITS 1    /* max number of LEITCH units */
42
0
#define LEITCHREFID "ATOM"  /* reference id */
43
0
#define LEITCH_DESCRIPTION "Leitch: CSD 5300 Master Clock System Driver"
44
#define LEITCH232 "/dev/leitch%d" /* name of radio device */
45
0
#define SPEED232 B300    /* uart speed (300 baud) */ 
46
#ifdef DEBUG
47
0
#define leitch_send(A,M) \
48
0
if (debug) fprintf(stderr,"write leitch %s\n",M); \
49
0
if ((write(A->leitchio.fd,M,sizeof(M)) < 0)) {\
50
0
  if (debug) \
51
0
      fprintf(stderr, "leitch_send: unit %d send failed\n", A->unit); \
52
0
  else \
53
0
      msyslog(LOG_ERR, "leitch_send: unit %d send failed %m",A->unit);}
54
#else
55
#define leitch_send(A,M) \
56
if ((write(A->leitchio.fd,M,sizeof(M)) < 0)) {\
57
  msyslog(LOG_ERR, "leitch_send: unit %d send failed %m",A->unit);}
58
#endif
59
60
0
#define STATE_IDLE 0
61
0
#define STATE_DATE 1
62
0
#define STATE_TIME1 2
63
0
#define STATE_TIME2 3
64
0
#define STATE_TIME3 4
65
66
/*
67
 * LEITCH unit control structure
68
 */
69
struct leitchunit {
70
  struct peer *peer;
71
  struct refclockio leitchio;
72
  u_char unit;
73
  short year;
74
  short yearday;
75
  short month;
76
  short day;
77
  short hour;
78
  short second;
79
  short minute;
80
  short state;
81
  u_short fudge1;
82
  l_fp reftime1;
83
  l_fp reftime2;
84
  l_fp reftime3;
85
  l_fp codetime1;
86
  l_fp codetime2;
87
  l_fp codetime3;
88
  u_long yearstart;
89
};
90
91
/*
92
 * Function prototypes
93
 */
94
static  void  leitch_init (void);
95
static  int leitch_start  (int, struct peer *);
96
static  void  leitch_shutdown (int, struct peer *);
97
static  void  leitch_poll (int, struct peer *);
98
static  void  leitch_control  (int, const struct refclockstat *, struct refclockstat *, struct peer *);
99
#define leitch_buginfo  noentry
100
static  void  leitch_receive  (struct recvbuf *);
101
static  void  leitch_process  (struct leitchunit *);
102
#if 0
103
static  void  leitch_timeout  (struct peer *);
104
#endif
105
static  int leitch_get_date (struct recvbuf *, struct leitchunit *);
106
static  int leitch_get_time (struct recvbuf *, struct leitchunit *, int);
107
static  int days_per_year   (int);
108
109
static struct leitchunit leitchunits[MAXUNITS];
110
static u_char unitinuse[MAXUNITS];
111
static u_char stratumtouse[MAXUNITS];
112
static u_int32 refid[MAXUNITS];
113
114
static  char days_in_month [] = { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
115
116
/*
117
 * Transfer vector
118
 */
119
struct  refclock refclock_leitch = {
120
  leitch_start, leitch_shutdown, leitch_poll,
121
  leitch_control, leitch_init, leitch_buginfo, NOFLAGS
122
};
123
124
/*
125
 * leitch_init - initialize internal leitch driver data
126
 */
127
static void
128
leitch_init(void)
129
0
{
130
0
  int i;
131
132
0
  memset((char*)leitchunits, 0, sizeof(leitchunits));
133
0
  memset((char*)unitinuse, 0, sizeof(unitinuse));
134
0
  for (i = 0; i < MAXUNITS; i++)
135
0
      memcpy((char *)&refid[i], LEITCHREFID, 4);
136
0
}
137
138
/*
139
 * leitch_shutdown - shut down a LEITCH clock
140
 */
141
static void
142
leitch_shutdown(
143
  int unit,
144
  struct peer *peer
145
  )
146
0
{
147
0
  struct leitchunit *leitch;
148
149
0
  if (unit >= MAXUNITS) {
150
0
    return;
151
0
  }
152
0
  leitch = &leitchunits[unit];
153
0
  if (-1 != leitch->leitchio.fd)
154
0
    io_closeclock(&leitch->leitchio);
155
0
#ifdef DEBUG
156
0
  if (debug)
157
0
    fprintf(stderr, "leitch_shutdown()\n");
158
0
#endif
159
0
}
160
161
/*
162
 * leitch_poll - called by the transmit procedure
163
 */
164
static void
165
leitch_poll(
166
  int unit,
167
  struct peer *peer
168
  )
169
0
{
170
0
  struct leitchunit *leitch;
171
172
  /* start the state machine rolling */
173
174
0
#ifdef DEBUG
175
0
  if (debug)
176
0
      fprintf(stderr, "leitch_poll()\n");
177
0
#endif
178
0
  if (unit >= MAXUNITS) {
179
    /* XXXX syslog it */
180
0
    return;
181
0
  }
182
183
0
  leitch = &leitchunits[unit];
184
185
0
  if (leitch->state != STATE_IDLE) {
186
    /* reset and wait for next poll */
187
    /* XXXX syslog it */
188
0
    leitch->state = STATE_IDLE;
189
0
  } else {
190
0
    leitch_send(leitch,"D\r");
191
0
    leitch->state = STATE_DATE;
192
0
  }
193
0
}
194
195
static void
196
leitch_control(
197
  int unit,
198
  const struct refclockstat *in,
199
  struct refclockstat *out,
200
  struct peer *passed_peer
201
  )
202
0
{
203
0
  if (unit >= MAXUNITS) {
204
0
    msyslog(LOG_ERR,
205
0
      "leitch_control: unit %d invalid", unit);
206
0
    return;
207
0
  }
208
209
0
  if (in) {
210
0
    if (in->haveflags & CLK_HAVEVAL1)
211
0
        stratumtouse[unit] = (u_char)(in->fudgeval1);
212
0
    if (in->haveflags & CLK_HAVEVAL2)
213
0
        refid[unit] = in->fudgeval2;
214
0
    if (unitinuse[unit]) {
215
0
      struct peer *peer;
216
217
0
      peer = (&leitchunits[unit])->peer;
218
0
      peer->stratum = stratumtouse[unit];
219
0
      peer->refid = refid[unit];
220
0
    }
221
0
  }
222
223
0
  if (out) {
224
0
    memset((char *)out, 0, sizeof (struct refclockstat));
225
0
    out->type = REFCLK_ATOM_LEITCH;
226
0
    out->haveflags = CLK_HAVEVAL1 | CLK_HAVEVAL2;
227
0
    out->fudgeval1 = (int32)stratumtouse[unit];
228
0
    out->fudgeval2 = refid[unit];
229
0
    out->p_lastcode = "";
230
0
    out->clockdesc = LEITCH_DESCRIPTION;
231
0
  }
232
0
}
233
234
/*
235
 * leitch_start - open the LEITCH devices and initialize data for processing
236
 */
237
static int
238
leitch_start(
239
  int unit,
240
  struct peer *peer
241
  )
242
0
{
243
0
  struct leitchunit *leitch;
244
0
  int fd232;
245
0
  char leitchdev[20];
246
247
  /*
248
   * Check configuration info.
249
   */
250
0
  if (unit >= MAXUNITS) {
251
0
    msyslog(LOG_ERR, "leitch_start: unit %d invalid", unit);
252
0
    return (0);
253
0
  }
254
255
0
  if (unitinuse[unit]) {
256
0
    msyslog(LOG_ERR, "leitch_start: unit %d in use", unit);
257
0
    return (0);
258
0
  }
259
260
  /*
261
   * Open serial port.
262
   */
263
0
  snprintf(leitchdev, sizeof(leitchdev), LEITCH232, unit);
264
0
  fd232 = open(leitchdev, O_RDWR, 0777);
265
0
  if (fd232 == -1) {
266
0
    msyslog(LOG_ERR,
267
0
      "leitch_start: open of %s: %m", leitchdev);
268
0
    return (0);
269
0
  }
270
271
0
  leitch = &leitchunits[unit];
272
0
  memset(leitch, 0, sizeof(*leitch));
273
274
#if defined(HAVE_SYSV_TTYS)
275
  /*
276
   * System V serial line parameters (termio interface)
277
   *
278
   */
279
  { struct termio ttyb;
280
  if (ioctl(fd232, TCGETA, &ttyb) < 0) {
281
    msyslog(LOG_ERR,
282
      "leitch_start: ioctl(%s, TCGETA): %m", leitchdev);
283
    goto screwed;
284
  }
285
  ttyb.c_iflag = IGNBRK|IGNPAR|ICRNL;
286
  ttyb.c_oflag = 0;
287
  ttyb.c_cflag = SPEED232|CS8|CLOCAL|CREAD;
288
  ttyb.c_lflag = ICANON;
289
  ttyb.c_cc[VERASE] = ttyb.c_cc[VKILL] = '\0';
290
  if (ioctl(fd232, TCSETA, &ttyb) < 0) {
291
    msyslog(LOG_ERR,
292
      "leitch_start: ioctl(%s, TCSETA): %m", leitchdev);
293
    goto screwed;
294
  }
295
  }
296
#endif /* HAVE_SYSV_TTYS */
297
0
#if defined(HAVE_TERMIOS)
298
  /*
299
   * POSIX serial line parameters (termios interface)
300
   */
301
0
  { struct termios ttyb, *ttyp;
302
303
0
  ttyp = &ttyb;
304
0
  if (tcgetattr(fd232, ttyp) < 0) {
305
0
    msyslog(LOG_ERR,
306
0
      "leitch_start: tcgetattr(%s): %m", leitchdev);
307
0
    goto screwed;
308
0
  }
309
0
  ttyp->c_iflag = IGNBRK|IGNPAR|ICRNL;
310
0
  ttyp->c_oflag = 0;
311
0
  ttyp->c_cflag = SPEED232|CS8|CLOCAL|CREAD;
312
0
  ttyp->c_lflag = ICANON;
313
0
  ttyp->c_cc[VERASE] = ttyp->c_cc[VKILL] = '\0';
314
0
  if (tcsetattr(fd232, TCSANOW, ttyp) < 0) {
315
0
    msyslog(LOG_ERR,
316
0
      "leitch_start: tcsetattr(%s): %m", leitchdev);
317
0
    goto screwed;
318
0
  }
319
0
  if (tcflush(fd232, TCIOFLUSH) < 0) {
320
0
    msyslog(LOG_ERR,
321
0
      "leitch_start: tcflush(%s): %m", leitchdev);
322
0
    goto screwed;
323
0
  }
324
0
  }
325
0
#endif /* HAVE_TERMIOS */
326
#if defined(HAVE_BSD_TTYS)
327
  /*
328
   * 4.3bsd serial line parameters (sgttyb interface)
329
   */
330
  {
331
    struct sgttyb ttyb;
332
333
  if (ioctl(fd232, TIOCGETP, &ttyb) < 0) {
334
    msyslog(LOG_ERR,
335
      "leitch_start: ioctl(%s, TIOCGETP): %m", leitchdev);
336
    goto screwed;
337
  }
338
  ttyb.sg_ispeed = ttyb.sg_ospeed = SPEED232;
339
  ttyb.sg_erase = ttyb.sg_kill = '\0';
340
  ttyb.sg_flags = EVENP|ODDP|CRMOD;
341
  if (ioctl(fd232, TIOCSETP, &ttyb) < 0) {
342
    msyslog(LOG_ERR,
343
      "leitch_start: ioctl(%s, TIOCSETP): %m", leitchdev);
344
    goto screwed;
345
  }
346
  }
347
#endif /* HAVE_BSD_TTYS */
348
349
  /*
350
   * Set up the structures
351
   */
352
0
  leitch->peer = peer;
353
0
  leitch->unit = unit;
354
0
  leitch->state = STATE_IDLE;
355
0
  leitch->fudge1 = 15;  /* 15ms */
356
357
0
  leitch->leitchio.clock_recv = leitch_receive;
358
0
  leitch->leitchio.srcclock = peer;
359
0
  leitch->leitchio.datalen = 0;
360
0
  leitch->leitchio.fd = fd232;
361
0
  if (!io_addclock(&leitch->leitchio)) {
362
0
    leitch->leitchio.fd = -1;
363
0
    goto screwed;
364
0
  }
365
366
  /*
367
   * All done.  Initialize a few random peer variables, then
368
   * return success.
369
   */
370
0
  peer->precision = PRECISION;
371
0
  peer->stratum = stratumtouse[unit];
372
0
  peer->refid = refid[unit];
373
0
  unitinuse[unit] = 1;
374
0
  return(1);
375
376
  /*
377
   * Something broke; abandon ship.
378
   */
379
0
    screwed:
380
0
  close(fd232);
381
0
  return(0);
382
0
}
383
384
/*
385
 * leitch_receive - receive data from the serial interface on a leitch
386
 * clock
387
 */
388
static void
389
leitch_receive(
390
  struct recvbuf *rbufp
391
  )
392
0
{
393
0
  struct leitchunit *leitch = rbufp->recv_peer->procptr->unitptr;
394
395
0
#ifdef DEBUG
396
0
  if (debug)
397
0
      fprintf(stderr, "leitch_recieve(%*.*s)\n", 
398
0
        rbufp->recv_length, rbufp->recv_length,
399
0
        rbufp->recv_buffer);
400
0
#endif
401
0
  if (rbufp->recv_length != 7)
402
0
      return; /* The date is return with a trailing newline,
403
           discard it. */
404
405
0
  switch (leitch->state) {
406
0
      case STATE_IDLE: /* unexpected, discard and resync */
407
0
    return;
408
0
      case STATE_DATE:
409
0
    if (!leitch_get_date(rbufp,leitch)) {
410
0
      leitch->state = STATE_IDLE;
411
0
      break;
412
0
    }
413
0
    leitch_send(leitch,"T\r");
414
0
#ifdef DEBUG
415
0
    if (debug)
416
0
        fprintf(stderr, "%u\n",leitch->yearday);
417
0
#endif
418
0
    leitch->state = STATE_TIME1;
419
0
    break;
420
0
      case STATE_TIME1:
421
0
    if (!leitch_get_time(rbufp,leitch,1)) {
422
0
    }
423
0
    if (!clocktime(leitch->yearday,leitch->hour,leitch->minute,
424
0
             leitch->second, 1, rbufp->recv_time.l_ui,
425
0
             &leitch->yearstart, &leitch->reftime1.l_ui)) {
426
0
      leitch->state = STATE_IDLE;
427
0
      break;
428
0
    }
429
0
    leitch->reftime1.l_uf = 0;
430
0
#ifdef DEBUG
431
0
    if (debug)
432
0
        fprintf(stderr, "%lu\n", (u_long)leitch->reftime1.l_ui);
433
0
#endif
434
0
    MSUTOTSF(leitch->fudge1, leitch->reftime1.l_uf);
435
0
    leitch->codetime1 = rbufp->recv_time;
436
0
    leitch->state = STATE_TIME2;
437
0
    break;
438
0
      case STATE_TIME2:
439
0
    if (!leitch_get_time(rbufp,leitch,2)) {
440
0
    }
441
0
    if (!clocktime(leitch->yearday,leitch->hour,leitch->minute,
442
0
             leitch->second, 1, rbufp->recv_time.l_ui,
443
0
             &leitch->yearstart, &leitch->reftime2.l_ui)) {
444
0
      leitch->state = STATE_IDLE;
445
0
      break;
446
0
    }
447
0
#ifdef DEBUG
448
0
    if (debug)
449
0
        fprintf(stderr, "%lu\n", (u_long)leitch->reftime2.l_ui);
450
0
#endif
451
0
    MSUTOTSF(leitch->fudge1, leitch->reftime2.l_uf);
452
0
    leitch->codetime2 = rbufp->recv_time;
453
0
    leitch->state = STATE_TIME3;
454
0
    break;
455
0
      case STATE_TIME3:
456
0
    if (!leitch_get_time(rbufp,leitch,3)) {
457
0
    }
458
0
    if (!clocktime(leitch->yearday,leitch->hour,leitch->minute,
459
0
             leitch->second, GMT, rbufp->recv_time.l_ui,
460
0
             &leitch->yearstart, &leitch->reftime3.l_ui)) {
461
0
      leitch->state = STATE_IDLE;
462
0
      break;
463
0
    }
464
0
#ifdef DEBUG
465
0
    if (debug)
466
0
        fprintf(stderr, "%lu\n", (u_long)leitch->reftime3.l_ui);
467
0
#endif
468
0
    MSUTOTSF(leitch->fudge1, leitch->reftime3.l_uf);
469
0
    leitch->codetime3 = rbufp->recv_time;
470
0
    leitch_process(leitch);
471
0
    leitch->state = STATE_IDLE;
472
0
    break;
473
0
      default:
474
0
    msyslog(LOG_ERR,
475
0
      "leitech_receive: invalid state %d unit %d",
476
0
      leitch->state, leitch->unit);
477
0
  }
478
0
}
479
480
/*
481
 * leitch_process - process a pile of samples from the clock
482
 *
483
 * This routine uses a three-stage median filter to calculate offset and
484
 * dispersion. reduce jitter. The dispersion is calculated as the span
485
 * of the filter (max - min), unless the quality character (format 2) is
486
 * non-blank, in which case the dispersion is calculated on the basis of
487
 * the inherent tolerance of the internal radio oscillator, which is
488
 * +-2e-5 according to the radio specifications.
489
 */
490
static void
491
leitch_process(
492
  struct leitchunit *leitch
493
  )
494
0
{
495
0
  l_fp off;
496
0
  l_fp tmp_fp;
497
      /*double doffset;*/
498
499
0
  off = leitch->reftime1;
500
0
  L_SUB(&off,&leitch->codetime1);
501
0
  tmp_fp = leitch->reftime2;
502
0
  L_SUB(&tmp_fp,&leitch->codetime2);
503
0
  if (L_ISGEQ(&off,&tmp_fp))
504
0
      off = tmp_fp;
505
0
  tmp_fp = leitch->reftime3;
506
0
  L_SUB(&tmp_fp,&leitch->codetime3);
507
508
0
  if (L_ISGEQ(&off,&tmp_fp))
509
0
      off = tmp_fp;
510
      /*LFPTOD(&off, doffset);*/
511
0
  refclock_receive(leitch->peer);
512
0
}
513
514
/*
515
 * days_per_year
516
 */
517
static int
518
days_per_year(
519
  int year
520
  )
521
0
{
522
0
  if (year%4) { /* not a potential leap year */
523
0
    return (365);
524
0
  } else {
525
0
    if (year % 100) { /* is a leap year */
526
0
      return (366);
527
0
    } else { 
528
0
      if (year % 400) {
529
0
        return (365);
530
0
      } else {
531
0
        return (366);
532
0
      }
533
0
    }
534
0
  }
535
0
}
536
537
static int
538
leitch_get_date(
539
  struct recvbuf *rbufp,
540
  struct leitchunit *leitch
541
  )
542
0
{
543
0
  int i;
544
545
0
  if (rbufp->recv_length < 6)
546
0
      return(0);
547
0
#undef  BAD    /* confict: defined as (-1) in AIX sys/param.h */
548
0
#define BAD(A) (rbufp->recv_buffer[A] < '0') || (rbufp->recv_buffer[A] > '9')
549
0
  if (BAD(0)||BAD(1)||BAD(2)||BAD(3)||BAD(4)||BAD(5))
550
0
      return(0);
551
0
#define ATOB(A) ((rbufp->recv_buffer[A])-'0')
552
0
  leitch->year = ATOB(0)*10 + ATOB(1);
553
0
  leitch->month = ATOB(2)*10 + ATOB(3);
554
0
  leitch->day = ATOB(4)*10 + ATOB(5);
555
556
  /* sanity checks */
557
0
  if (leitch->month > 12)
558
0
      return(0);
559
0
  if (leitch->day > days_in_month[leitch->month-1])
560
0
      return(0);
561
562
  /* calculate yearday */
563
0
  i = 0;
564
0
  leitch->yearday = leitch->day;
565
566
0
  while ( i < (leitch->month-1) )
567
0
      leitch->yearday += days_in_month[i++];
568
569
0
  if ((days_per_year((leitch->year>90?1900:2000)+leitch->year)==365) && 
570
0
      leitch->month > 2)
571
0
      leitch->yearday--;
572
573
0
  return(1);
574
0
}
575
576
/*
577
 * leitch_get_time
578
 */
579
static int
580
leitch_get_time(
581
  struct recvbuf *rbufp,
582
  struct leitchunit *leitch,
583
  int which
584
  )
585
0
{
586
0
  if (BAD(0)||BAD(1)||BAD(2)||BAD(3)||BAD(4)||BAD(5))
587
0
      return(0);
588
0
  leitch->hour = ATOB(0)*10 +ATOB(1);
589
0
  leitch->minute = ATOB(2)*10 +ATOB(3);
590
0
  leitch->second = ATOB(4)*10 +ATOB(5);
591
592
0
  if ((leitch->hour > 23) || (leitch->minute > 60) ||
593
0
      (leitch->second > 60))
594
0
      return(0);
595
0
  return(1);
596
0
}
597
598
#else
599
NONEMPTY_TRANSLATION_UNIT
600
#endif /* REFCLOCK */