156746Sroberto/* 256746Sroberto * refclock_pcf - clock driver for the Conrad parallel port radio clock 356746Sroberto */ 456746Sroberto 556746Sroberto#ifdef HAVE_CONFIG_H 656746Sroberto# include <config.h> 756746Sroberto#endif 856746Sroberto 956746Sroberto#if defined(REFCLOCK) && defined(CLOCK_PCF) 1056746Sroberto 1156746Sroberto#include "ntpd.h" 1256746Sroberto#include "ntp_io.h" 1356746Sroberto#include "ntp_refclock.h" 1456746Sroberto#include "ntp_calendar.h" 1556746Sroberto#include "ntp_stdlib.h" 1656746Sroberto 1756746Sroberto/* 1882498Sroberto * This driver supports the parallel port radio clock sold by Conrad 1956746Sroberto * Electronic under order numbers 967602 and 642002. 2056746Sroberto * 2156746Sroberto * It requires that the local timezone be CET/CEST and that the pcfclock 2282498Sroberto * device driver be installed. A device driver for Linux is available at 2382498Sroberto * http://home.pages.de/~voegele/pcf.html. Information about a FreeBSD 2482498Sroberto * driver is available at http://schumann.cx/pcfclock/. 2556746Sroberto */ 2656746Sroberto 2756746Sroberto/* 2856746Sroberto * Interface definitions 2956746Sroberto */ 3082498Sroberto#define DEVICE "/dev/pcfclocks/%d" 3182498Sroberto#define OLDDEVICE "/dev/pcfclock%d" 3256746Sroberto#define PRECISION (-1) /* precision assumed (about 0.5 s) */ 3356746Sroberto#define REFID "PCF" 3456746Sroberto#define DESCRIPTION "Conrad parallel port radio clock" 3556746Sroberto 3656746Sroberto#define LENPCF 18 /* timecode length */ 3756746Sroberto 3856746Sroberto/* 3956746Sroberto * Function prototypes 4056746Sroberto */ 4156746Srobertostatic int pcf_start P((int, struct peer *)); 4256746Srobertostatic void pcf_shutdown P((int, struct peer *)); 4356746Srobertostatic void pcf_poll P((int, struct peer *)); 4456746Sroberto 4556746Sroberto/* 4656746Sroberto * Transfer vector 4756746Sroberto */ 4856746Srobertostruct refclock refclock_pcf = { 4956746Sroberto pcf_start, /* start up driver */ 5056746Sroberto pcf_shutdown, /* shut down driver */ 5156746Sroberto pcf_poll, /* transmit poll message */ 5256746Sroberto noentry, /* not used */ 5356746Sroberto noentry, /* initialize driver (not used) */ 5456746Sroberto noentry, /* not used */ 5556746Sroberto NOFLAGS /* not used */ 5656746Sroberto}; 5756746Sroberto 5856746Sroberto 5956746Sroberto/* 6056746Sroberto * pcf_start - open the device and initialize data for processing 6156746Sroberto */ 6256746Srobertostatic int 6356746Srobertopcf_start( 6456746Sroberto int unit, 6556746Sroberto struct peer *peer 6656746Sroberto ) 6756746Sroberto{ 6856746Sroberto struct refclockproc *pp; 6956746Sroberto int fd; 7082498Sroberto char device[128]; 7156746Sroberto 7256746Sroberto /* 7356746Sroberto * Open device file for reading. 7456746Sroberto */ 7556746Sroberto (void)sprintf(device, DEVICE, unit); 7682498Sroberto fd = open(device, O_RDONLY); 7782498Sroberto if (fd == -1) { 7882498Sroberto (void)sprintf(device, OLDDEVICE, unit); 7982498Sroberto fd = open(device, O_RDONLY); 8082498Sroberto } 8156746Sroberto#ifdef DEBUG 8256746Sroberto if (debug) 8356746Sroberto printf ("starting PCF with device %s\n",device); 8456746Sroberto#endif 8582498Sroberto if (fd == -1) { 8656746Sroberto return (0); 8756746Sroberto } 8856746Sroberto 8956746Sroberto pp = peer->procptr; 9056746Sroberto pp->io.clock_recv = noentry; 9156746Sroberto pp->io.srcclock = (caddr_t)peer; 9256746Sroberto pp->io.datalen = 0; 9356746Sroberto pp->io.fd = fd; 9456746Sroberto 9556746Sroberto /* 9656746Sroberto * Initialize miscellaneous variables 9756746Sroberto */ 9856746Sroberto peer->precision = PRECISION; 9956746Sroberto pp->clockdesc = DESCRIPTION; 10082498Sroberto /* one transmission takes 172.5 milliseconds since the radio clock 10182498Sroberto transmits 69 bits with a period of 2.5 milliseconds per bit */ 10282498Sroberto pp->fudgetime1 = 0.1725; 10356746Sroberto memcpy((char *)&pp->refid, REFID, 4); 10456746Sroberto 10556746Sroberto return (1); 10656746Sroberto} 10756746Sroberto 10856746Sroberto 10956746Sroberto/* 11056746Sroberto * pcf_shutdown - shut down the clock 11156746Sroberto */ 11256746Srobertostatic void 11356746Srobertopcf_shutdown( 11456746Sroberto int unit, 11556746Sroberto struct peer *peer 11656746Sroberto ) 11756746Sroberto{ 11856746Sroberto struct refclockproc *pp; 11956746Sroberto 12056746Sroberto pp = peer->procptr; 12156746Sroberto (void)close(pp->io.fd); 12256746Sroberto} 12356746Sroberto 12456746Sroberto 12556746Sroberto/* 12656746Sroberto * pcf_poll - called by the transmit procedure 12756746Sroberto */ 12856746Srobertostatic void 12956746Srobertopcf_poll( 13056746Sroberto int unit, 13156746Sroberto struct peer *peer 13256746Sroberto ) 13356746Sroberto{ 13456746Sroberto struct refclockproc *pp; 13556746Sroberto char buf[LENPCF]; 13656746Sroberto struct tm tm, *tp; 13756746Sroberto time_t t; 13856746Sroberto 13956746Sroberto pp = peer->procptr; 14056746Sroberto 14156746Sroberto buf[0] = 0; 14256746Sroberto if (read(pp->io.fd, buf, sizeof(buf)) < sizeof(buf) || buf[0] != 9) { 14356746Sroberto refclock_report(peer, CEVNT_FAULT); 14456746Sroberto return; 14556746Sroberto } 14656746Sroberto 14756746Sroberto tm.tm_mday = buf[11] * 10 + buf[10]; 14856746Sroberto tm.tm_mon = buf[13] * 10 + buf[12] - 1; 14956746Sroberto tm.tm_year = buf[15] * 10 + buf[14]; 15056746Sroberto tm.tm_hour = buf[7] * 10 + buf[6]; 15156746Sroberto tm.tm_min = buf[5] * 10 + buf[4]; 15256746Sroberto tm.tm_sec = buf[3] * 10 + buf[2]; 15382498Sroberto tm.tm_isdst = (buf[8] & 1) ? 1 : (buf[8] & 2) ? 0 : -1; 15456746Sroberto 15556746Sroberto /* 15656746Sroberto * Y2K convert the 2-digit year 15756746Sroberto */ 15856746Sroberto if (tm.tm_year < 99) 15956746Sroberto tm.tm_year += 100; 16056746Sroberto 16156746Sroberto t = mktime(&tm); 16256746Sroberto if (t == (time_t) -1) { 16356746Sroberto refclock_report(peer, CEVNT_BADTIME); 16456746Sroberto return; 16556746Sroberto } 16656746Sroberto 16756746Sroberto#if defined(__GLIBC__) && defined(_BSD_SOURCE) 16856746Sroberto if ((tm.tm_isdst > 0 && tm.tm_gmtoff != 7200) 16956746Sroberto || (tm.tm_isdst == 0 && tm.tm_gmtoff != 3600) 17056746Sroberto || tm.tm_isdst < 0) { 17156746Sroberto#ifdef DEBUG 17256746Sroberto if (debug) 17356746Sroberto printf ("local time zone not set to CET/CEST\n"); 17456746Sroberto#endif 17556746Sroberto refclock_report(peer, CEVNT_BADTIME); 17656746Sroberto return; 17756746Sroberto } 17856746Sroberto#endif 17956746Sroberto 18056746Sroberto pp->lencode = strftime(pp->a_lastcode, BMAX, "%Y %m %d %H %M %S", &tm); 18156746Sroberto 18256746Sroberto#if defined(_REENTRANT) || defined(_THREAD_SAFE) 18356746Sroberto tp = gmtime_r(&t, &tm); 18456746Sroberto#else 18556746Sroberto tp = gmtime(&t); 18656746Sroberto#endif 18756746Sroberto if (!tp) { 18856746Sroberto refclock_report(peer, CEVNT_FAULT); 18956746Sroberto return; 19056746Sroberto } 19156746Sroberto 19256746Sroberto get_systime(&pp->lastrec); 19356746Sroberto pp->polls++; 19456746Sroberto pp->year = tp->tm_year + 1900; 19556746Sroberto pp->day = tp->tm_yday + 1; 19656746Sroberto pp->hour = tp->tm_hour; 19756746Sroberto pp->minute = tp->tm_min; 19856746Sroberto pp->second = tp->tm_sec; 199132451Sroberto pp->nsec = buf[16] * 31250000; 20056746Sroberto if (buf[17] & 1) 201132451Sroberto pp->nsec += 500000000; 20256746Sroberto 20356746Sroberto#ifdef DEBUG 20456746Sroberto if (debug) 20556746Sroberto printf ("pcf%d: time is %04d/%02d/%02d %02d:%02d:%02d UTC\n", 20656746Sroberto unit, pp->year, tp->tm_mon + 1, tp->tm_mday, pp->hour, 20756746Sroberto pp->minute, pp->second); 20856746Sroberto#endif 20956746Sroberto 21056746Sroberto if (!refclock_process(pp)) { 21156746Sroberto refclock_report(peer, CEVNT_BADTIME); 21256746Sroberto return; 21356746Sroberto } 21456746Sroberto record_clock_stats(&peer->srcadr, pp->a_lastcode); 21582498Sroberto if ((buf[1] & 1) && !(pp->sloppyclockflag & CLK_FLAG2)) 21656746Sroberto pp->leap = LEAP_NOTINSYNC; 21756746Sroberto else 21856746Sroberto pp->leap = LEAP_NOWARNING; 219132451Sroberto pp->lastref = pp->lastrec; 22056746Sroberto refclock_receive(peer); 22156746Sroberto} 22256746Sroberto#else 22356746Srobertoint refclock_pcf_bs; 22456746Sroberto#endif /* REFCLOCK */ 225