/* * refclock_hopfpci.c * * - clock driver for hopf 6039 PCI board (GPS or DCF77) * Bernd Altmeier altmeier@atlsoft.de * * latest source and further information can be found at: * http://www.ATLSoft.de/ntp * * In order to run this driver you have to install and test * the PCI-board driver for your system first. * * On Linux/UNIX * * The driver attempts to open the device /dev/hopf6039 . * The device entry will be made by the installation process of * the kernel module for the PCI-bus board. The driver sources * belongs to the delivery equipment of the PCI-board. * * On Windows NT/2000 * * The driver attempts to open the device by calling the function * "OpenHopfDevice()". This function will be installed by the * Device Driver for the PCI-bus board. The driver belongs to the * delivery equipment of the PCI-board. * * * Start 21.03.2000 Revision: 01.20 * changes 22.12.2000 Revision: 01.40 flag1 = 1 sync even if Quarz * */ #ifdef HAVE_CONFIG_H # include #endif #if defined(REFCLOCK) && defined(CLOCK_HOPF_PCI) #include "ntpd.h" #include "ntp_io.h" #include "ntp_refclock.h" #include "ntp_unixtime.h" #include "ntp_stdlib.h" #undef fileno #include #undef fileno #ifndef SYS_WINNT # include # include # include # include # include # include "hopf6039.h" #else # include "hopf_PCI_io.h" #endif /* * hopfpci interface definitions */ #define PRECISION (-10) /* precision assumed (1 ms) */ #define REFID "hopf" /* reference ID */ #define DESCRIPTION "hopf Elektronik PCI radio board" #define NSAMPLES 3 /* stages of median filter */ #ifndef SYS_WINNT # define DEVICE "/dev/hopf6039" /* device name inode*/ #else # define DEVICE "hopf6039" /* device name WinNT */ #endif #define LEWAPWAR 0x20 /* leap second warning bit */ #define HOPF_OPMODE 0xC0 /* operation mode mask */ #define HOPF_INVALID 0x00 /* no time code available */ #define HOPF_INTERNAL 0x40 /* internal clock */ #define HOPF_RADIO 0x80 /* radio clock */ #define HOPF_RADIOHP 0xC0 /* high precision radio clock */ /* * hopfclock unit control structure. */ struct hopfclock_unit { short unit; /* NTP refclock unit number */ char leap_status; /* leap second flag */ }; int fd; /* file descr. */ /* * Function prototypes */ static int hopfpci_start (int, struct peer *); static void hopfpci_shutdown (int, struct peer *); static void hopfpci_poll (int unit, struct peer *); /* * Transfer vector */ struct refclock refclock_hopfpci = { hopfpci_start, /* start up driver */ hopfpci_shutdown, /* shut down driver */ hopfpci_poll, /* transmit poll message */ noentry, /* not used */ noentry, /* initialize driver (not used) */ noentry, /* not used */ NOFLAGS /* not used */ }; /* * hopfpci_start - attach to hopf PCI board 6039 */ static int hopfpci_start( int unit, struct peer *peer ) { struct refclockproc *pp; struct hopfclock_unit *up; /* * Allocate and initialize unit structure */ up = emalloc_zero(sizeof(*up)); #ifndef SYS_WINNT fd = open(DEVICE,O_RDWR); /* try to open hopf clock device */ #else if (!OpenHopfDevice()) { msyslog(LOG_ERR, "Start: %s unit: %d failed!", DEVICE, unit); free(up); return (0); } #endif pp = peer->procptr; pp->io.clock_recv = noentry; pp->io.srcclock = peer; pp->io.datalen = 0; pp->io.fd = INVALID_SOCKET; pp->unitptr = up; get_systime(&pp->lastrec); /* * Initialize miscellaneous peer variables */ memcpy((char *)&pp->refid, REFID, 4); peer->precision = PRECISION; pp->clockdesc = DESCRIPTION; up->leap_status = 0; up->unit = (short) unit; return (1); } /* * hopfpci_shutdown - shut down the clock */ static void hopfpci_shutdown( int unit, struct peer *peer ) { #ifndef SYS_WINNT close(fd); #else CloseHopfDevice(); #endif if (NULL != peer->procptr->unitptr) free(peer->procptr->unitptr); } /* * hopfpci_poll - called by the transmit procedure */ static void hopfpci_poll( int unit, struct peer *peer ) { struct refclockproc *pp; HOPFTIME m_time; pp = peer->procptr; #ifndef SYS_WINNT if (ioctl(fd, HOPF_CLOCK_GET_UTC, &m_time) < 0) msyslog(LOG_ERR, "HOPF_P(%d): HOPF_CLOCK_GET_UTC: %m", unit); #else GetHopfSystemTime(&m_time); #endif pp->polls++; pp->day = ymd2yd(m_time.wYear,m_time.wMonth,m_time.wDay); pp->hour = m_time.wHour; pp->minute = m_time.wMinute; pp->second = m_time.wSecond; pp->nsec = m_time.wMilliseconds * 1000000; if (m_time.wStatus & LEWAPWAR) pp->leap = LEAP_ADDSECOND; else pp->leap = LEAP_NOWARNING; snprintf(pp->a_lastcode, sizeof(pp->a_lastcode), "ST: %02X T: %02d:%02d:%02d.%03ld D: %02d.%02d.%04d", m_time.wStatus, pp->hour, pp->minute, pp->second, pp->nsec / 1000000, m_time.wDay, m_time.wMonth, m_time.wYear); pp->lencode = (u_short)strlen(pp->a_lastcode); get_systime(&pp->lastrec); /* * If clock has no valid status then report error and exit */ if ((m_time.wStatus & HOPF_OPMODE) == HOPF_INVALID) { /* time ok? */ refclock_report(peer, CEVNT_BADTIME); pp->leap = LEAP_NOTINSYNC; return; } /* * Test if time is running on internal quarz * if CLK_FLAG1 is set, sychronize even if no radio operation */ if ((m_time.wStatus & HOPF_OPMODE) == HOPF_INTERNAL){ if ((pp->sloppyclockflag & CLK_FLAG1) == 0) { refclock_report(peer, CEVNT_BADTIME); pp->leap = LEAP_NOTINSYNC; return; } } if (!refclock_process(pp)) { refclock_report(peer, CEVNT_BADTIME); return; } pp->lastref = pp->lastrec; refclock_receive(peer); record_clock_stats(&peer->srcadr, pp->a_lastcode); return; } #else NONEMPTY_TRANSLATION_UNIT #endif /* REFCLOCK */