182498Sroberto/* 282498Sroberto * refclock_hopfpci.c 382498Sroberto * 482498Sroberto * - clock driver for hopf 6039 PCI board (GPS or DCF77) 582498Sroberto * Bernd Altmeier altmeier@atlsoft.de 682498Sroberto * 782498Sroberto * latest source and further information can be found at: 882498Sroberto * http://www.ATLSoft.de/ntp 982498Sroberto * 1082498Sroberto * In order to run this driver you have to install and test 1182498Sroberto * the PCI-board driver for your system first. 1282498Sroberto * 1382498Sroberto * On Linux/UNIX 1482498Sroberto * 1582498Sroberto * The driver attempts to open the device /dev/hopf6039 . 1682498Sroberto * The device entry will be made by the installation process of 1782498Sroberto * the kernel module for the PCI-bus board. The driver sources 1882498Sroberto * belongs to the delivery equipment of the PCI-board. 1982498Sroberto * 2082498Sroberto * On Windows NT/2000 2182498Sroberto * 2282498Sroberto * The driver attempts to open the device by calling the function 2382498Sroberto * "OpenHopfDevice()". This function will be installed by the 2482498Sroberto * Device Driver for the PCI-bus board. The driver belongs to the 2582498Sroberto * delivery equipment of the PCI-board. 2682498Sroberto * 2782498Sroberto * 2882498Sroberto * Start 21.03.2000 Revision: 01.20 2982498Sroberto * changes 22.12.2000 Revision: 01.40 flag1 = 1 sync even if Quarz 3082498Sroberto * 3182498Sroberto */ 3282498Sroberto 3382498Sroberto#ifdef HAVE_CONFIG_H 3482498Sroberto# include <config.h> 3582498Sroberto#endif 3682498Sroberto 3782498Sroberto#if defined(REFCLOCK) && defined(CLOCK_HOPF_PCI) 3882498Sroberto 3982498Sroberto#include "ntpd.h" 4082498Sroberto#include "ntp_io.h" 4182498Sroberto#include "ntp_refclock.h" 4282498Sroberto#include "ntp_unixtime.h" 4382498Sroberto#include "ntp_stdlib.h" 4482498Sroberto 4582498Sroberto#undef fileno 4682498Sroberto#include <ctype.h> 4782498Sroberto#undef fileno 4882498Sroberto 4982498Sroberto#ifndef SYS_WINNT 5082498Sroberto# include <sys/ipc.h> 51132451Sroberto# include <sys/ioctl.h> 5282498Sroberto# include <assert.h> 5382498Sroberto# include <unistd.h> 5482498Sroberto# include <stdio.h> 5582498Sroberto# include "hopf6039.h" 5682498Sroberto#else 5782498Sroberto# include "hopf_PCI_io.h" 5882498Sroberto#endif 5982498Sroberto 6082498Sroberto/* 6182498Sroberto * hopfpci interface definitions 6282498Sroberto */ 6382498Sroberto#define PRECISION (-10) /* precision assumed (1 ms) */ 6482498Sroberto#define REFID "hopf" /* reference ID */ 6582498Sroberto#define DESCRIPTION "hopf Elektronik PCI radio board" 6682498Sroberto 6782498Sroberto#define NSAMPLES 3 /* stages of median filter */ 6882498Sroberto#ifndef SYS_WINNT 6982498Sroberto# define DEVICE "/dev/hopf6039" /* device name inode*/ 7082498Sroberto#else 7182498Sroberto# define DEVICE "hopf6039" /* device name WinNT */ 7282498Sroberto#endif 7382498Sroberto 7482498Sroberto#define LEWAPWAR 0x20 /* leap second warning bit */ 7582498Sroberto 7682498Sroberto#define HOPF_OPMODE 0xC0 /* operation mode mask */ 7782498Sroberto#define HOPF_INVALID 0x00 /* no time code available */ 7882498Sroberto#define HOPF_INTERNAL 0x40 /* internal clock */ 7982498Sroberto#define HOPF_RADIO 0x80 /* radio clock */ 8082498Sroberto#define HOPF_RADIOHP 0xC0 /* high precision radio clock */ 8182498Sroberto 8282498Sroberto 8382498Sroberto/* 8482498Sroberto * hopfclock unit control structure. 8582498Sroberto */ 8682498Srobertostruct hopfclock_unit { 8782498Sroberto short unit; /* NTP refclock unit number */ 8882498Sroberto char leap_status; /* leap second flag */ 8982498Sroberto}; 9082498Srobertoint fd; /* file descr. */ 9182498Sroberto 9282498Sroberto/* 9382498Sroberto * Function prototypes 9482498Sroberto */ 9582498Srobertostatic int hopfpci_start (int, struct peer *); 9682498Srobertostatic void hopfpci_shutdown (int, struct peer *); 9782498Srobertostatic void hopfpci_poll (int unit, struct peer *); 9882498Sroberto 9982498Sroberto/* 10082498Sroberto * Transfer vector 10182498Sroberto */ 10282498Srobertostruct refclock refclock_hopfpci = { 10382498Sroberto hopfpci_start, /* start up driver */ 10482498Sroberto hopfpci_shutdown, /* shut down driver */ 10582498Sroberto hopfpci_poll, /* transmit poll message */ 10682498Sroberto noentry, /* not used */ 10782498Sroberto noentry, /* initialize driver (not used) */ 10882498Sroberto noentry, /* not used */ 10982498Sroberto NOFLAGS /* not used */ 11082498Sroberto}; 11182498Sroberto 11282498Sroberto/* 11382498Sroberto * hopfpci_start - attach to hopf PCI board 6039 11482498Sroberto */ 11582498Srobertostatic int 11682498Srobertohopfpci_start( 11782498Sroberto int unit, 11882498Sroberto struct peer *peer 11982498Sroberto ) 12082498Sroberto{ 12182498Sroberto struct refclockproc *pp; 12282498Sroberto struct hopfclock_unit *up; 12382498Sroberto 12482498Sroberto /* 12582498Sroberto * Allocate and initialize unit structure 12682498Sroberto */ 12782498Sroberto up = (struct hopfclock_unit *) emalloc(sizeof(struct hopfclock_unit)); 12882498Sroberto 12982498Sroberto if (!(up)) { 13082498Sroberto msyslog(LOG_ERR, "hopfPCIClock(%d) emalloc: %m",unit); 13182498Sroberto#ifdef DEBUG 13282498Sroberto printf("hopfPCIClock(%d) emalloc\n",unit); 13382498Sroberto#endif 13482498Sroberto return (0); 13582498Sroberto } 13682498Sroberto memset((char *)up, 0, sizeof(struct hopfclock_unit)); 13782498Sroberto 13882498Sroberto#ifndef SYS_WINNT 13982498Sroberto 14082498Sroberto fd = open(DEVICE,O_RDWR); /* try to open hopf clock device */ 14182498Sroberto 14282498Sroberto#else 14382498Sroberto if (!OpenHopfDevice()){ 14482498Sroberto msyslog(LOG_ERR,"Start: %s unit: %d failed!",DEVICE,unit); 14582498Sroberto return (0); 14682498Sroberto } 14782498Sroberto#endif 14882498Sroberto 14982498Sroberto pp = peer->procptr; 15082498Sroberto pp->io.clock_recv = noentry; 15182498Sroberto pp->io.srcclock = (caddr_t)peer; 15282498Sroberto pp->io.datalen = 0; 153132451Sroberto pp->io.fd = INVALID_SOCKET; 15482498Sroberto pp->unitptr = (caddr_t)up; 15582498Sroberto 15682498Sroberto get_systime(&pp->lastrec); 15782498Sroberto 15882498Sroberto /* 15982498Sroberto * Initialize miscellaneous peer variables 16082498Sroberto */ 16182498Sroberto if (pp->unitptr!=0) { 16282498Sroberto memcpy((char *)&pp->refid, REFID, 4); 16382498Sroberto peer->precision = PRECISION; 16482498Sroberto pp->clockdesc = DESCRIPTION; 16582498Sroberto up->leap_status = 0; 16682498Sroberto up->unit = (short) unit; 16782498Sroberto return (1); 16882498Sroberto } 16982498Sroberto else { 17082498Sroberto return 0; 17182498Sroberto } 17282498Sroberto} 17382498Sroberto 17482498Sroberto 17582498Sroberto/* 17682498Sroberto * hopfpci_shutdown - shut down the clock 17782498Sroberto */ 17882498Srobertostatic void 17982498Srobertohopfpci_shutdown( 18082498Sroberto int unit, 18182498Sroberto struct peer *peer 18282498Sroberto ) 18382498Sroberto{ 18482498Sroberto 18582498Sroberto#ifndef SYS_WINNT 18682498Sroberto close(fd); 18782498Sroberto#else 18882498Sroberto CloseHopfDevice(); 18982498Sroberto#endif 19082498Sroberto} 19182498Sroberto 19282498Sroberto 19382498Sroberto/* 19482498Sroberto * hopfpci_poll - called by the transmit procedure 19582498Sroberto */ 19682498Srobertostatic void 19782498Srobertohopfpci_poll( 19882498Sroberto int unit, 19982498Sroberto struct peer *peer 20082498Sroberto ) 20182498Sroberto{ 20282498Sroberto struct refclockproc *pp; 20382498Sroberto HOPFTIME m_time; 20482498Sroberto 20582498Sroberto pp = peer->procptr; 20682498Sroberto 20782498Sroberto#ifndef SYS_WINNT 208132451Sroberto ioctl(fd,HOPF_CLOCK_GET_UTC,&m_time); 20982498Sroberto#else 21082498Sroberto GetHopfSystemTime(&m_time); 21182498Sroberto#endif 21282498Sroberto pp->polls++; 21382498Sroberto 21482498Sroberto pp->day = ymd2yd(m_time.wYear,m_time.wMonth,m_time.wDay); 21582498Sroberto pp->hour = m_time.wHour; 21682498Sroberto pp->minute = m_time.wMinute; 21782498Sroberto pp->second = m_time.wSecond; 218132451Sroberto pp->nsec = m_time.wMilliseconds * 1000000; 21982498Sroberto if (m_time.wStatus & LEWAPWAR) 22082498Sroberto pp->leap = LEAP_ADDSECOND; 22182498Sroberto else 22282498Sroberto pp->leap = LEAP_NOWARNING; 22382498Sroberto 224132451Sroberto sprintf(pp->a_lastcode,"ST: %02X T: %02d:%02d:%02d.%03ld D: %02d.%02d.%04d", 225132451Sroberto m_time.wStatus, pp->hour, pp->minute, pp->second, 226132451Sroberto pp->nsec / 1000000, m_time.wDay, m_time.wMonth, m_time.wYear); 227132451Sroberto pp->lencode = (u_short)strlen(pp->a_lastcode); 22882498Sroberto 22982498Sroberto get_systime(&pp->lastrec); 23082498Sroberto 23182498Sroberto /* 23282498Sroberto * If clock has no valid status then report error and exit 23382498Sroberto */ 23482498Sroberto if ((m_time.wStatus & HOPF_OPMODE) == HOPF_INVALID) { /* time ok? */ 23582498Sroberto refclock_report(peer, CEVNT_BADTIME); 23682498Sroberto pp->leap = LEAP_NOTINSYNC; 23782498Sroberto return; 23882498Sroberto } 23982498Sroberto 24082498Sroberto /* 24182498Sroberto * Test if time is running on internal quarz 24282498Sroberto * if CLK_FLAG1 is set, sychronize even if no radio operation 24382498Sroberto */ 24482498Sroberto 24582498Sroberto if ((m_time.wStatus & HOPF_OPMODE) == HOPF_INTERNAL){ 24682498Sroberto if ((pp->sloppyclockflag & CLK_FLAG1) == 0) { 24782498Sroberto refclock_report(peer, CEVNT_BADTIME); 24882498Sroberto pp->leap = LEAP_NOTINSYNC; 24982498Sroberto return; 25082498Sroberto } 25182498Sroberto } 25282498Sroberto 25382498Sroberto if (!refclock_process(pp)) { 25482498Sroberto refclock_report(peer, CEVNT_BADTIME); 25582498Sroberto return; 25682498Sroberto } 257132451Sroberto pp->lastref = pp->lastrec; 25882498Sroberto refclock_receive(peer); 25982498Sroberto record_clock_stats(&peer->srcadr, pp->a_lastcode); 26082498Sroberto return; 26182498Sroberto} 26282498Sroberto 26382498Sroberto#else 26482498Srobertoint refclock_hopfpci_bs; 26582498Sroberto#endif /* REFCLOCK */ 266