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