Coverage Report

Created: 2023-05-19 06:16

/src/ntp-dev/ntpd/refclock_pcf.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * refclock_pcf - clock driver for the Conrad parallel port radio clock
3
 */
4
5
#ifdef HAVE_CONFIG_H
6
# include <config.h>
7
#endif
8
9
#if defined(REFCLOCK) && defined(CLOCK_PCF)
10
11
#include "ntpd.h"
12
#include "ntp_io.h"
13
#include "ntp_refclock.h"
14
#include "ntp_calendar.h"
15
#include "ntp_stdlib.h"
16
17
/*
18
 * This driver supports the parallel port radio clock sold by Conrad
19
 * Electronic under order numbers 967602 and 642002.
20
 *
21
 * It requires that the local timezone be CET/CEST and that the pcfclock
22
 * device driver be installed.  A device driver for Linux is available at
23
 * http://home.pages.de/~voegele/pcf.html.  Information about a FreeBSD
24
 * driver is available at http://schumann.cx/pcfclock/.
25
 */
26
27
/*
28
 * Interface definitions
29
 */
30
#define DEVICE    "/dev/pcfclocks/%d"
31
#define OLDDEVICE "/dev/pcfclock%d"
32
0
#define PRECISION (-1)  /* precision assumed (about 0.5 s) */
33
0
#define REFID   "PCF"
34
0
#define DESCRIPTION "Conrad parallel port radio clock"
35
36
#define LENPCF    18  /* timecode length */
37
38
/*
39
 * Function prototypes
40
 */
41
static  int   pcf_start     (int, struct peer *);
42
static  void  pcf_shutdown    (int, struct peer *);
43
static  void  pcf_poll    (int, struct peer *);
44
45
/*
46
 * Transfer vector
47
 */
48
struct  refclock refclock_pcf = {
49
  pcf_start,              /* start up driver */
50
  pcf_shutdown,           /* shut down driver */
51
  pcf_poll,               /* transmit poll message */
52
  noentry,                /* not used */
53
  noentry,                /* initialize driver (not used) */
54
  noentry,                /* not used */
55
  NOFLAGS                 /* not used */
56
};
57
58
59
/*
60
 * pcf_start - open the device and initialize data for processing
61
 */
62
static int
63
pcf_start(
64
      int unit,
65
  struct peer *peer
66
  )
67
0
{
68
0
  struct refclockproc *pp;
69
0
  int fd;
70
0
  char device[128];
71
72
  /*
73
   * Open device file for reading.
74
   */
75
0
  snprintf(device, sizeof(device), DEVICE, unit);
76
0
  fd = open(device, O_RDONLY);
77
0
  if (fd == -1) {
78
0
    snprintf(device, sizeof(device), OLDDEVICE, unit);
79
0
    fd = open(device, O_RDONLY);
80
0
  }
81
0
#ifdef DEBUG
82
0
  if (debug)
83
0
    printf ("starting PCF with device %s\n",device);
84
0
#endif
85
0
  if (fd == -1) {
86
0
    return (0);
87
0
  }
88
  
89
0
  pp = peer->procptr;
90
0
  pp->io.clock_recv = noentry;
91
0
  pp->io.srcclock = peer;
92
0
  pp->io.datalen = 0;
93
0
  pp->io.fd = fd;
94
  
95
  /*
96
   * Initialize miscellaneous variables
97
   */
98
0
  peer->precision = PRECISION;
99
0
  pp->clockdesc = DESCRIPTION;
100
  /* one transmission takes 172.5 milliseconds since the radio clock
101
     transmits 69 bits with a period of 2.5 milliseconds per bit */
102
0
  pp->fudgetime1 = 0.1725;
103
0
  memcpy((char *)&pp->refid, REFID, 4);
104
105
0
  return (1);
106
0
}
107
108
109
/*
110
 * pcf_shutdown - shut down the clock
111
 */
112
static void
113
pcf_shutdown(
114
  int unit,
115
  struct peer *peer
116
  )
117
0
{
118
0
  struct refclockproc *pp;
119
  
120
0
  pp = peer->procptr;
121
0
  if (NULL != pp)
122
0
    close(pp->io.fd);
123
0
}
124
125
126
/*
127
 * pcf_poll - called by the transmit procedure
128
 */
129
static void
130
pcf_poll(
131
  int unit,
132
  struct peer *peer
133
  )
134
0
{
135
0
  struct refclockproc *pp;
136
0
  char buf[LENPCF];
137
0
  struct tm tm, *tp;
138
0
  time_t t;
139
  
140
0
  pp = peer->procptr;
141
142
0
  buf[0] = 0;
143
0
  if (read(pp->io.fd, buf, sizeof(buf)) < (ssize_t)sizeof(buf) || buf[0] != 9) {
144
0
    refclock_report(peer, CEVNT_FAULT);
145
0
    return;
146
0
  }
147
148
0
  ZERO(tm);
149
150
0
  tm.tm_mday = buf[11] * 10 + buf[10];
151
0
  tm.tm_mon = buf[13] * 10 + buf[12] - 1;
152
0
  tm.tm_year = buf[15] * 10 + buf[14];
153
0
  tm.tm_hour = buf[7] * 10 + buf[6];
154
0
  tm.tm_min = buf[5] * 10 + buf[4];
155
0
  tm.tm_sec = buf[3] * 10 + buf[2];
156
0
  tm.tm_isdst = (buf[8] & 1) ? 1 : (buf[8] & 2) ? 0 : -1;
157
158
  /*
159
   * Y2K convert the 2-digit year
160
   */
161
0
  if (tm.tm_year < 99)
162
0
    tm.tm_year += 100;
163
  
164
0
  t = mktime(&tm);
165
0
  if (t == (time_t) -1) {
166
0
    refclock_report(peer, CEVNT_BADTIME);
167
0
    return;
168
0
  }
169
170
#if defined(__GLIBC__) && defined(_BSD_SOURCE)
171
  if ((tm.tm_isdst > 0 && tm.tm_gmtoff != 7200)
172
      || (tm.tm_isdst == 0 && tm.tm_gmtoff != 3600)
173
      || tm.tm_isdst < 0) {
174
#ifdef DEBUG
175
    if (debug)
176
      printf ("local time zone not set to CET/CEST\n");
177
#endif
178
    refclock_report(peer, CEVNT_BADTIME);
179
    return;
180
  }
181
#endif
182
183
0
  pp->lencode = strftime(pp->a_lastcode, BMAX, "%Y %m %d %H %M %S", &tm);
184
185
0
#if defined(_REENTRANT) || defined(_THREAD_SAFE)
186
0
  tp = gmtime_r(&t, &tm);
187
#else
188
  tp = gmtime(&t);
189
#endif
190
0
  if (!tp) {
191
0
    refclock_report(peer, CEVNT_FAULT);
192
0
    return;
193
0
  }
194
195
0
  get_systime(&pp->lastrec);
196
0
  pp->polls++;
197
0
  pp->year = tp->tm_year + 1900;
198
0
  pp->day = tp->tm_yday + 1;
199
0
  pp->hour = tp->tm_hour;
200
0
  pp->minute = tp->tm_min;
201
0
  pp->second = tp->tm_sec;
202
0
  pp->nsec = buf[16] * 31250000;
203
0
  if (buf[17] & 1)
204
0
    pp->nsec += 500000000;
205
206
0
#ifdef DEBUG
207
0
  if (debug)
208
0
    printf ("pcf%d: time is %04d/%02d/%02d %02d:%02d:%02d UTC\n",
209
0
      unit, pp->year, tp->tm_mon + 1, tp->tm_mday, pp->hour,
210
0
      pp->minute, pp->second);
211
0
#endif
212
213
0
  if (!refclock_process(pp)) {
214
0
    refclock_report(peer, CEVNT_BADTIME);
215
0
    return;
216
0
  }
217
0
  record_clock_stats(&peer->srcadr, pp->a_lastcode);
218
0
  if ((buf[1] & 1) && !(pp->sloppyclockflag & CLK_FLAG2))
219
0
    pp->leap = LEAP_NOTINSYNC;
220
0
  else
221
0
    pp->leap = LEAP_NOWARNING;
222
0
  pp->lastref = pp->lastrec;
223
0
  refclock_receive(peer);
224
0
}
225
#else
226
int refclock_pcf_bs;
227
#endif /* REFCLOCK */