1/* 2 * refclock_hopfpci.c 3 * 4 * - clock driver for hopf 6039 PCI board (GPS or DCF77) 5 * Bernd Altmeier altmeier@atlsoft.de 6 * 7 * latest source and further information can be found at: 8 * http://www.ATLSoft.de/ntp 9 * 10 * In order to run this driver you have to install and test 11 * the PCI-board driver for your system first. 12 * 13 * On Linux/UNIX 14 * 15 * The driver attempts to open the device /dev/hopf6039 . 16 * The device entry will be made by the installation process of 17 * the kernel module for the PCI-bus board. The driver sources 18 * belongs to the delivery equipment of the PCI-board. 19 * 20 * On Windows NT/2000 21 * 22 * The driver attempts to open the device by calling the function 23 * "OpenHopfDevice()". This function will be installed by the 24 * Device Driver for the PCI-bus board. The driver belongs to the 25 * delivery equipment of the PCI-board. 26 * 27 * 28 * Start 21.03.2000 Revision: 01.20 29 * changes 22.12.2000 Revision: 01.40 flag1 = 1 sync even if Quarz 30 * 31 */ 32 33#ifdef HAVE_CONFIG_H 34# include <config.h> 35#endif 36 37#if defined(REFCLOCK) && defined(CLOCK_HOPF_PCI) 38 39#include "ntpd.h" 40#include "ntp_io.h" 41#include "ntp_refclock.h" 42#include "ntp_unixtime.h" 43#include "ntp_stdlib.h" 44 45#undef fileno 46#include <ctype.h> 47#undef fileno 48 49#ifndef SYS_WINNT 50# include <sys/ipc.h> 51# include <sys/ioctl.h> 52# include <assert.h> 53# include <unistd.h> 54# include <stdio.h> 55# include "hopf6039.h" 56#else 57# include "hopf_PCI_io.h" 58#endif 59 60/* 61 * hopfpci interface definitions 62 */ 63#define PRECISION (-10) /* precision assumed (1 ms) */ 64#define REFID "hopf" /* reference ID */ 65#define DESCRIPTION "hopf Elektronik PCI radio board" 66 67#define NSAMPLES 3 /* stages of median filter */ 68#ifndef SYS_WINNT 69# define DEVICE "/dev/hopf6039" /* device name inode*/ 70#else 71# define DEVICE "hopf6039" /* device name WinNT */ 72#endif 73 74#define LEWAPWAR 0x20 /* leap second warning bit */ 75 76#define HOPF_OPMODE 0xC0 /* operation mode mask */ 77#define HOPF_INVALID 0x00 /* no time code available */ 78#define HOPF_INTERNAL 0x40 /* internal clock */ 79#define HOPF_RADIO 0x80 /* radio clock */ 80#define HOPF_RADIOHP 0xC0 /* high precision radio clock */ 81 82 83/* 84 * hopfclock unit control structure. 85 */ 86struct hopfclock_unit { 87 short unit; /* NTP refclock unit number */ 88 char leap_status; /* leap second flag */ 89}; 90int fd; /* file descr. */ 91 92/* 93 * Function prototypes 94 */ 95static int hopfpci_start (int, struct peer *); 96static void hopfpci_shutdown (int, struct peer *); 97static void hopfpci_poll (int unit, struct peer *); 98 99/* 100 * Transfer vector 101 */ 102struct refclock refclock_hopfpci = { 103 hopfpci_start, /* start up driver */ 104 hopfpci_shutdown, /* shut down driver */ 105 hopfpci_poll, /* transmit poll message */ 106 noentry, /* not used */ 107 noentry, /* initialize driver (not used) */ 108 noentry, /* not used */ 109 NOFLAGS /* not used */ 110}; 111 112/* 113 * hopfpci_start - attach to hopf PCI board 6039 114 */ 115static int 116hopfpci_start( 117 int unit, 118 struct peer *peer 119 ) 120{ 121 struct refclockproc *pp; 122 struct hopfclock_unit *up; 123 124 /* 125 * Allocate and initialize unit structure 126 */ 127 up = (struct hopfclock_unit *) emalloc(sizeof(struct hopfclock_unit)); 128 129 if (!(up)) { 130 msyslog(LOG_ERR, "hopfPCIClock(%d) emalloc: %m",unit); 131#ifdef DEBUG 132 printf("hopfPCIClock(%d) emalloc\n",unit); 133#endif 134 return (0); 135 } 136 memset((char *)up, 0, sizeof(struct hopfclock_unit)); 137 138#ifndef SYS_WINNT 139 140 fd = open(DEVICE,O_RDWR); /* try to open hopf clock device */ 141 142#else 143 if (!OpenHopfDevice()){ 144 msyslog(LOG_ERR,"Start: %s unit: %d failed!",DEVICE,unit); 145 return (0); 146 } 147#endif 148 149 pp = peer->procptr; 150 pp->io.clock_recv = noentry; 151 pp->io.srcclock = (caddr_t)peer; 152 pp->io.datalen = 0; 153 pp->io.fd = INVALID_SOCKET; 154 pp->unitptr = (caddr_t)up; 155 156 get_systime(&pp->lastrec); 157 158 /* 159 * Initialize miscellaneous peer variables 160 */ 161 if (pp->unitptr!=0) { 162 memcpy((char *)&pp->refid, REFID, 4); 163 peer->precision = PRECISION; 164 pp->clockdesc = DESCRIPTION; 165 up->leap_status = 0; 166 up->unit = (short) unit; 167 return (1); 168 } 169 else { 170 return 0; 171 } 172} 173 174 175/* 176 * hopfpci_shutdown - shut down the clock 177 */ 178static void 179hopfpci_shutdown( 180 int unit, 181 struct peer *peer 182 ) 183{ 184 185#ifndef SYS_WINNT 186 close(fd); 187#else 188 CloseHopfDevice(); 189#endif 190} 191 192 193/* 194 * hopfpci_poll - called by the transmit procedure 195 */ 196static void 197hopfpci_poll( 198 int unit, 199 struct peer *peer 200 ) 201{ 202 struct refclockproc *pp; 203 HOPFTIME m_time; 204 205 pp = peer->procptr; 206 207#ifndef SYS_WINNT 208 ioctl(fd,HOPF_CLOCK_GET_UTC,&m_time); 209#else 210 GetHopfSystemTime(&m_time); 211#endif 212 pp->polls++; 213 214 pp->day = ymd2yd(m_time.wYear,m_time.wMonth,m_time.wDay); 215 pp->hour = m_time.wHour; 216 pp->minute = m_time.wMinute; 217 pp->second = m_time.wSecond; 218 pp->nsec = m_time.wMilliseconds * 1000000; 219 if (m_time.wStatus & LEWAPWAR) 220 pp->leap = LEAP_ADDSECOND; 221 else 222 pp->leap = LEAP_NOWARNING; 223 224 sprintf(pp->a_lastcode,"ST: %02X T: %02d:%02d:%02d.%03ld D: %02d.%02d.%04d", 225 m_time.wStatus, pp->hour, pp->minute, pp->second, 226 pp->nsec / 1000000, m_time.wDay, m_time.wMonth, m_time.wYear); 227 pp->lencode = (u_short)strlen(pp->a_lastcode); 228 229 get_systime(&pp->lastrec); 230 231 /* 232 * If clock has no valid status then report error and exit 233 */ 234 if ((m_time.wStatus & HOPF_OPMODE) == HOPF_INVALID) { /* time ok? */ 235 refclock_report(peer, CEVNT_BADTIME); 236 pp->leap = LEAP_NOTINSYNC; 237 return; 238 } 239 240 /* 241 * Test if time is running on internal quarz 242 * if CLK_FLAG1 is set, sychronize even if no radio operation 243 */ 244 245 if ((m_time.wStatus & HOPF_OPMODE) == HOPF_INTERNAL){ 246 if ((pp->sloppyclockflag & CLK_FLAG1) == 0) { 247 refclock_report(peer, CEVNT_BADTIME); 248 pp->leap = LEAP_NOTINSYNC; 249 return; 250 } 251 } 252 253 if (!refclock_process(pp)) { 254 refclock_report(peer, CEVNT_BADTIME); 255 return; 256 } 257 pp->lastref = pp->lastrec; 258 refclock_receive(peer); 259 record_clock_stats(&peer->srcadr, pp->a_lastcode); 260 return; 261} 262 263#else 264int refclock_hopfpci_bs; 265#endif /* REFCLOCK */ 266