Coverage Report

Created: 2023-05-19 06:16

/src/ntp-dev/ntpd/refclock_hopfser.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 *
3
 * refclock_hopfser.c
4
 * - clock driver for hopf serial boards (GPS or DCF77)
5
 *
6
 * Date: 30.03.2000 Revision: 01.10
7
 *
8
 * latest source and further information can be found at:
9
 * http://www.ATLSoft.de/ntp
10
 *
11
 */
12
13
#ifdef HAVE_CONFIG_H
14
# include "config.h"
15
#endif
16
17
#if defined(REFCLOCK) && (defined(CLOCK_HOPF_SERIAL))
18
19
#include "ntpd.h"
20
#include "ntp_io.h"
21
#include "ntp_control.h"
22
#include "ntp_refclock.h"
23
#include "ntp_unixtime.h"
24
#include "ntp_stdlib.h"
25
26
#if defined HAVE_SYS_MODEM_H
27
# include <sys/modem.h>
28
# ifndef __QNXNTO__
29
#  define TIOCMSET MCSETA
30
#  define TIOCMGET MCGETA
31
#  define TIOCM_RTS MRTS
32
# endif
33
#endif
34
35
#ifdef HAVE_TERMIOS_H
36
# ifdef TERMIOS_NEEDS__SVID3
37
#  define _SVID3
38
# endif
39
# include <termios.h>
40
# ifdef TERMIOS_NEEDS__SVID3
41
#  undef _SVID3
42
# endif
43
#endif
44
45
#ifdef HAVE_SYS_IOCTL_H
46
# include <sys/ioctl.h>
47
#endif
48
49
#ifdef SYS_WINNT
50
extern int async_write(int, const void *, unsigned int);
51
#undef write
52
#define write(fd, data, octets) async_write(fd, data, octets)
53
#endif
54
55
/*
56
 * clock definitions
57
 */
58
0
#define DESCRIPTION "hopf Elektronik serial clock" /* Long name */
59
0
#define PRECISION (-10)  /* precision assumed (about 1 ms) */
60
0
#define REFID   "hopf\0"  /* reference ID */
61
/*
62
 * I/O definitions
63
 */
64
#define DEVICE    "/dev/hopfclock%d"  /* device name and unit */
65
0
#define SPEED232  B9600          /* uart speed (9600 baud) */
66
67
68
#define STX 0x02
69
#define ETX 0x03
70
#define CR  0x0c
71
#define LF  0x0a
72
73
/* parse states */
74
#define REC_QUEUE_EMPTY       0
75
#define REC_QUEUE_FULL        1
76
77
0
#define HOPF_OPMODE 0x0C  /* operation mode mask */
78
0
#define HOPF_INVALID  0x00  /* no time code available */
79
0
#define HOPF_INTERNAL 0x04  /* internal clock */
80
#define HOPF_RADIO  0x08  /* radio clock */
81
#define HOPF_RADIOHP  0x0C  /* high precision radio clock */
82
83
/*
84
 * hopfclock unit control structure.
85
 */
86
struct hopfclock_unit {
87
  l_fp  laststamp;  /* last receive timestamp */
88
  short unit;   /* NTP refclock unit number */
89
  u_long  polled;   /* flag to detect noreplies */
90
  char  leap_status;  /* leap second flag */
91
  int rpt_next;
92
};
93
94
/*
95
 * Function prototypes
96
 */
97
98
static  int hopfserial_start  (int, struct peer *);
99
static  void  hopfserial_shutdown (int, struct peer *);
100
static  void  hopfserial_receive  (struct recvbuf *);
101
static  void  hopfserial_poll   (int, struct peer *);
102
/* static  void hopfserial_io   (struct recvbuf *); */
103
/*
104
 * Transfer vector
105
 */
106
struct refclock refclock_hopfser = {
107
  hopfserial_start, /* start up driver */
108
  hopfserial_shutdown,  /* shut down driver */
109
  hopfserial_poll,  /* transmit poll message */
110
  noentry,    /* not used  */
111
  noentry,    /* initialize driver (not used) */
112
  noentry,    /* not used */
113
  NOFLAGS     /* not used */
114
};
115
116
/*
117
 * hopfserial_start - open the devices and initialize data for processing
118
 */
119
static int
120
hopfserial_start (
121
  int unit,
122
  struct peer *peer
123
  )
124
0
{
125
0
  register struct hopfclock_unit *up;
126
0
  struct refclockproc *pp;
127
0
  int fd;
128
0
  char gpsdev[20];
129
130
0
  snprintf(gpsdev, sizeof(gpsdev), DEVICE, unit);
131
132
  /* LDISC_STD, LDISC_RAW
133
   * Open serial port. Use CLK line discipline, if available.
134
   */
135
0
  fd = refclock_open(gpsdev, SPEED232, LDISC_CLK);
136
0
  if (fd <= 0) {
137
0
#ifdef DEBUG
138
0
    printf("hopfSerialClock(%d) start: open %s failed\n", unit, gpsdev);
139
0
#endif
140
0
    return 0;
141
0
  }
142
143
0
  msyslog(LOG_NOTICE, "hopfSerialClock(%d) fd: %d dev: %s", unit, fd,
144
0
    gpsdev);
145
146
  /*
147
   * Allocate and initialize unit structure
148
   */
149
0
  up = emalloc_zero(sizeof(*up));
150
0
  pp = peer->procptr;
151
0
  pp->unitptr = up;
152
0
  pp->io.clock_recv = hopfserial_receive;
153
0
  pp->io.srcclock = peer;
154
0
  pp->io.datalen = 0;
155
0
  pp->io.fd = fd;
156
0
  if (!io_addclock(&pp->io)) {
157
0
#ifdef DEBUG
158
0
    printf("hopfSerialClock(%d) io_addclock\n", unit);
159
0
#endif
160
0
    close(fd);
161
0
    pp->io.fd = -1;
162
0
    free(up);
163
0
    pp->unitptr = NULL;
164
0
    return (0);
165
0
  }
166
167
  /*
168
   * Initialize miscellaneous variables
169
   */
170
0
  pp->clockdesc = DESCRIPTION;
171
0
  peer->precision = PRECISION;
172
0
  memcpy((char *)&pp->refid, REFID, 4);
173
174
0
  up->leap_status = 0;
175
0
  up->unit = (short) unit;
176
177
0
  return (1);
178
0
}
179
180
181
/*
182
 * hopfserial_shutdown - shut down the clock
183
 */
184
static void
185
hopfserial_shutdown (
186
  int unit,
187
  struct peer *peer
188
  )
189
0
{
190
0
  register struct hopfclock_unit *up;
191
0
  struct refclockproc *pp;
192
193
0
  pp = peer->procptr;
194
0
  up = pp->unitptr;
195
196
0
  if (-1 != pp->io.fd)
197
0
    io_closeclock(&pp->io);
198
0
  if (NULL != up)
199
0
    free(up);
200
0
}
201
202
203
204
/*
205
 * hopfserial_receive - receive data from the serial interface
206
 */
207
208
static void
209
hopfserial_receive (
210
  struct recvbuf *rbufp
211
  )
212
0
{
213
0
  struct hopfclock_unit *up;
214
0
  struct refclockproc *pp;
215
0
  struct peer *peer;
216
217
0
  int synch;  /* synchhronization indicator */
218
0
  int DoW;  /* Day of Week */
219
220
0
  int day, month; /* ddd conversion */
221
0
  int converted;
222
223
  /*
224
   * Initialize pointers and read the timecode and timestamp.
225
   */
226
0
  peer = rbufp->recv_peer;
227
0
  pp = peer->procptr;
228
0
  up = pp->unitptr;
229
230
0
  if (up->rpt_next == 0 )
231
0
    return;
232
233
0
  up->rpt_next = 0; /* wait until next poll interval occur */
234
235
0
  pp->lencode = (u_short)refclock_gtlin(rbufp, pp->a_lastcode,
236
0
                sizeof(pp->a_lastcode),
237
0
                &pp->lastrec);
238
0
  if (pp->lencode == 0)
239
0
    return;
240
241
0
  converted = sscanf(pp->a_lastcode,
242
0
#if 1
243
0
         "%1x%1x%2d%2d%2d%2d%2d%2d",   /* ...cr,lf */
244
#else
245
         "%*c%1x%1x%2d%2d%2d%2d%2d%2d", /* stx...cr,lf,etx */
246
#endif
247
0
         &synch,
248
0
         &DoW,
249
0
         &pp->hour,
250
0
         &pp->minute,
251
0
         &pp->second,
252
0
         &day,
253
0
         &month,
254
0
         &pp->year);
255
256
257
  /*
258
    Validate received values at least enough to prevent internal
259
    array-bounds problems, etc.
260
  */
261
0
  if ((8 != converted) || (pp->hour < 0) || (pp->hour > 23) ||
262
0
     (pp->minute < 0) || (pp->minute > 59) || (pp->second < 0) ||
263
0
     (pp->second > 60) /*Allow for leap seconds.*/ ||
264
0
     (day < 1) || (day > 31) ||
265
0
     (month < 1) || (month > 12) ||
266
0
     (pp->year < 0) || (pp->year > 99)) {
267
    /* Data out of range. */
268
0
    refclock_report(peer, CEVNT_BADREPLY);
269
0
    return;
270
0
  }
271
  /*
272
    some preparations
273
  */
274
0
  pp->day    = ymd2yd(pp->year,month,day);
275
0
  pp->leap=0;
276
277
  /* Year-2000 check! */
278
  /* wrap 2-digit date into 4-digit */
279
280
0
  if(pp->year < YEAR_PIVOT) { pp->year += 100; }    /* < 98 */
281
0
  pp->year += 1900;
282
283
  /* preparation for timecode ntpq rl command ! */
284
285
#if 0
286
  snprintf(pp->a_lastcode, sizeof(pp->a_lastcode),
287
     "STATUS: %1X%1X, DATE: %02d.%02d.%04d  TIME: %02d:%02d:%02d",
288
     synch,
289
     DoW,
290
     day,
291
     month,
292
     pp->year,
293
     pp->hour,
294
     pp->minute,
295
     pp->second);
296
297
  pp->lencode = strlen(pp->a_lastcode);
298
  if ((synch && 0xc) == 0 ){  /* time ok? */
299
    refclock_report(peer, CEVNT_BADTIME);
300
    pp->leap = LEAP_NOTINSYNC;
301
    return;
302
  }
303
#endif
304
  /*
305
   * If clock has no valid status then report error and exit
306
   */
307
0
  if ((synch & HOPF_OPMODE) == HOPF_INVALID ){  /* time ok? */
308
0
    refclock_report(peer, CEVNT_BADTIME);
309
0
    pp->leap = LEAP_NOTINSYNC;
310
0
    return;
311
0
  }
312
313
  /*
314
   * Test if time is running on internal quarz
315
   * if CLK_FLAG1 is set, sychronize even if no radio operation
316
   */
317
318
0
  if ((synch & HOPF_OPMODE) == HOPF_INTERNAL){
319
0
    if ((pp->sloppyclockflag & CLK_FLAG1) == 0) {
320
0
      refclock_report(peer, CEVNT_BADTIME);
321
0
      pp->leap = LEAP_NOTINSYNC;
322
0
      return;
323
0
    }
324
0
  }
325
326
327
0
  if (!refclock_process(pp)) {
328
0
    refclock_report(peer, CEVNT_BADTIME);
329
0
    return;
330
0
  }
331
0
  pp->lastref = pp->lastrec;
332
0
  refclock_receive(peer);
333
334
#if 0
335
  msyslog(LOG_ERR, " D:%x  D:%d D:%d",synch,pp->minute,pp->second);
336
#endif
337
338
0
  record_clock_stats(&peer->srcadr, pp->a_lastcode);
339
340
0
  return;
341
0
}
342
343
344
/*
345
 * hopfserial_poll - called by the transmit procedure
346
 *
347
 */
348
static void
349
hopfserial_poll (
350
  int unit,
351
  struct peer *peer
352
  )
353
0
{
354
0
  register struct hopfclock_unit *up;
355
0
  struct refclockproc *pp;
356
0
  pp = peer->procptr;
357
358
0
  up = pp->unitptr;
359
360
0
  pp->polls++;
361
0
  up->rpt_next = 1;
362
363
#if 0
364
  record_clock_stats(&peer->srcadr, pp->a_lastcode);
365
#endif
366
367
0
  return;
368
0
}
369
370
#else
371
int refclock_hopfser_bs;
372
#endif /* REFCLOCK */