4 * refclock_pcf - clock driver for the Conrad parallel port radio clock
11 #if defined(REFCLOCK) && defined(CLOCK_PCF)
15 #include "ntp_refclock.h"
16 #include "ntp_calendar.h"
17 #include "ntp_stdlib.h"
20 * This driver supports the parallel port radio clock sold by Conrad
21 * Electronic under order numbers 967602 and 642002.
23 * It requires that the local timezone be CET/CEST and that the pcfclock
24 * device driver be installed. A device driver for Linux is available at
25 * http://home.pages.de/~voegele/pcf.html. Information about a FreeBSD
26 * driver is available at http://schumann.cx/pcfclock/.
30 * Interface definitions
32 #define DEVICE "/dev/pcfclocks/%d"
33 #define OLDDEVICE "/dev/pcfclock%d"
34 #define PRECISION (-1) /* precision assumed (about 0.5 s) */
36 #define DESCRIPTION "Conrad parallel port radio clock"
38 #define LENPCF 18 /* timecode length */
43 static int pcf_start
P((int, struct peer
*));
44 static void pcf_shutdown
P((int, struct peer
*));
45 static void pcf_poll
P((int, struct peer
*));
50 struct refclock refclock_pcf
= {
51 pcf_start
, /* start up driver */
52 pcf_shutdown
, /* shut down driver */
53 pcf_poll
, /* transmit poll message */
54 noentry
, /* not used */
55 noentry
, /* initialize driver (not used) */
56 noentry
, /* not used */
57 NOFLAGS
/* not used */
62 * pcf_start - open the device and initialize data for processing
70 struct refclockproc
*pp
;
75 * Open device file for reading.
77 (void)sprintf(device
, DEVICE
, unit
);
78 fd
= open(device
, O_RDONLY
);
80 (void)sprintf(device
, OLDDEVICE
, unit
);
81 fd
= open(device
, O_RDONLY
);
85 printf ("starting PCF with device %s\n",device
);
92 pp
->io
.clock_recv
= noentry
;
93 pp
->io
.srcclock
= (caddr_t
)peer
;
98 * Initialize miscellaneous variables
100 peer
->precision
= PRECISION
;
101 pp
->clockdesc
= DESCRIPTION
;
102 /* one transmission takes 172.5 milliseconds since the radio clock
103 transmits 69 bits with a period of 2.5 milliseconds per bit */
104 pp
->fudgetime1
= 0.1725;
105 memcpy((char *)&pp
->refid
, REFID
, 4);
112 * pcf_shutdown - shut down the clock
120 struct refclockproc
*pp
;
123 (void)close(pp
->io
.fd
);
128 * pcf_poll - called by the transmit procedure
136 struct refclockproc
*pp
;
144 if (read(pp
->io
.fd
, buf
, sizeof(buf
)) < sizeof(buf
) || buf
[0] != 9) {
145 refclock_report(peer
, CEVNT_FAULT
);
149 tm
.tm_mday
= buf
[11] * 10 + buf
[10];
150 tm
.tm_mon
= buf
[13] * 10 + buf
[12] - 1;
151 tm
.tm_year
= buf
[15] * 10 + buf
[14];
152 tm
.tm_hour
= buf
[7] * 10 + buf
[6];
153 tm
.tm_min
= buf
[5] * 10 + buf
[4];
154 tm
.tm_sec
= buf
[3] * 10 + buf
[2];
155 tm
.tm_isdst
= (buf
[8] & 1) ? 1 : (buf
[8] & 2) ? 0 : -1;
158 * Y2K convert the 2-digit year
164 if (t
== (time_t) -1) {
165 refclock_report(peer
, CEVNT_BADTIME
);
169 #if defined(__GLIBC__) && defined(_BSD_SOURCE)
170 if ((tm
.tm_isdst
> 0 && tm
.tm_gmtoff
!= 7200)
171 || (tm
.tm_isdst
== 0 && tm
.tm_gmtoff
!= 3600)
172 || tm
.tm_isdst
< 0) {
175 printf ("local time zone not set to CET/CEST\n");
177 refclock_report(peer
, CEVNT_BADTIME
);
182 pp
->lencode
= strftime(pp
->a_lastcode
, BMAX
, "%Y %m %d %H %M %S", &tm
);
184 #if defined(_REENTRANT) || defined(_THREAD_SAFE)
185 tp
= gmtime_r(&t
, &tm
);
190 refclock_report(peer
, CEVNT_FAULT
);
194 get_systime(&pp
->lastrec
);
196 pp
->year
= tp
->tm_year
+ 1900;
197 pp
->day
= tp
->tm_yday
+ 1;
198 pp
->hour
= tp
->tm_hour
;
199 pp
->minute
= tp
->tm_min
;
200 pp
->second
= tp
->tm_sec
;
201 pp
->nsec
= buf
[16] * 31250000;
203 pp
->nsec
+= 500000000;
207 printf ("pcf%d: time is %04d/%02d/%02d %02d:%02d:%02d UTC\n",
208 unit
, pp
->year
, tp
->tm_mon
+ 1, tp
->tm_mday
, pp
->hour
,
209 pp
->minute
, pp
->second
);
212 if (!refclock_process(pp
)) {
213 refclock_report(peer
, CEVNT_BADTIME
);
216 record_clock_stats(&peer
->srcadr
, pp
->a_lastcode
);
217 if ((buf
[1] & 1) && !(pp
->sloppyclockflag
& CLK_FLAG2
))
218 pp
->leap
= LEAP_NOTINSYNC
;
220 pp
->leap
= LEAP_NOWARNING
;
221 pp
->lastref
= pp
->lastrec
;
222 refclock_receive(peer
);
226 #endif /* REFCLOCK */