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 */ 86 struct hopfclock_unit { 87 short unit; /* NTP refclock unit number */ 88 char leap_status; /* leap second flag */ 89 }; 90 int fd; /* file descr. */ 91 92 /* 93 * Function prototypes 94 */ 95 static int hopfpci_start (int, struct peer *); 96 static void hopfpci_shutdown (int, struct peer *); 97 static void hopfpci_poll (int unit, struct peer *); 98 99 /* 100 * Transfer vector 101 */ 102 struct 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 */ 115 static int 116 hopfpci_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 = emalloc_zero(sizeof(*up)); 128 129 #ifndef SYS_WINNT 130 131 fd = open(DEVICE,O_RDWR); /* try to open hopf clock device */ 132 133 #else 134 if (!OpenHopfDevice()) { 135 msyslog(LOG_ERR, "Start: %s unit: %d failed!", DEVICE, unit); 136 free(up); 137 return (0); 138 } 139 #endif 140 141 pp = peer->procptr; 142 pp->io.clock_recv = noentry; 143 pp->io.srcclock = peer; 144 pp->io.datalen = 0; 145 pp->io.fd = INVALID_SOCKET; 146 pp->unitptr = up; 147 148 get_systime(&pp->lastrec); 149 150 /* 151 * Initialize miscellaneous peer variables 152 */ 153 memcpy((char *)&pp->refid, REFID, 4); 154 peer->precision = PRECISION; 155 pp->clockdesc = DESCRIPTION; 156 up->leap_status = 0; 157 up->unit = (short) unit; 158 return (1); 159 } 160 161 162 /* 163 * hopfpci_shutdown - shut down the clock 164 */ 165 static void 166 hopfpci_shutdown( 167 int unit, 168 struct peer *peer 169 ) 170 { 171 172 #ifndef SYS_WINNT 173 close(fd); 174 #else 175 CloseHopfDevice(); 176 #endif 177 if (NULL != peer->procptr->unitptr) 178 free(peer->procptr->unitptr); 179 } 180 181 182 /* 183 * hopfpci_poll - called by the transmit procedure 184 */ 185 static void 186 hopfpci_poll( 187 int unit, 188 struct peer *peer 189 ) 190 { 191 struct refclockproc *pp; 192 HOPFTIME m_time; 193 194 pp = peer->procptr; 195 196 #ifndef SYS_WINNT 197 if (ioctl(fd, HOPF_CLOCK_GET_UTC, &m_time) < 0) 198 msyslog(LOG_ERR, "HOPF_P(%d): HOPF_CLOCK_GET_UTC: %m", 199 unit); 200 #else 201 GetHopfSystemTime(&m_time); 202 #endif 203 pp->polls++; 204 205 pp->day = ymd2yd(m_time.wYear,m_time.wMonth,m_time.wDay); 206 pp->hour = m_time.wHour; 207 pp->minute = m_time.wMinute; 208 pp->second = m_time.wSecond; 209 pp->nsec = m_time.wMilliseconds * 1000000; 210 if (m_time.wStatus & LEWAPWAR) 211 pp->leap = LEAP_ADDSECOND; 212 else 213 pp->leap = LEAP_NOWARNING; 214 215 snprintf(pp->a_lastcode, sizeof(pp->a_lastcode), 216 "ST: %02X T: %02d:%02d:%02d.%03ld D: %02d.%02d.%04d", 217 m_time.wStatus, pp->hour, pp->minute, pp->second, 218 pp->nsec / 1000000, m_time.wDay, m_time.wMonth, 219 m_time.wYear); 220 pp->lencode = (u_short)strlen(pp->a_lastcode); 221 222 get_systime(&pp->lastrec); 223 224 /* 225 * If clock has no valid status then report error and exit 226 */ 227 if ((m_time.wStatus & HOPF_OPMODE) == HOPF_INVALID) { /* time ok? */ 228 refclock_report(peer, CEVNT_BADTIME); 229 pp->leap = LEAP_NOTINSYNC; 230 return; 231 } 232 233 /* 234 * Test if time is running on internal quarz 235 * if CLK_FLAG1 is set, sychronize even if no radio operation 236 */ 237 238 if ((m_time.wStatus & HOPF_OPMODE) == HOPF_INTERNAL){ 239 if ((pp->sloppyclockflag & CLK_FLAG1) == 0) { 240 refclock_report(peer, CEVNT_BADTIME); 241 pp->leap = LEAP_NOTINSYNC; 242 return; 243 } 244 } 245 246 if (!refclock_process(pp)) { 247 refclock_report(peer, CEVNT_BADTIME); 248 return; 249 } 250 pp->lastref = pp->lastrec; 251 refclock_receive(peer); 252 record_clock_stats(&peer->srcadr, pp->a_lastcode); 253 return; 254 } 255 256 #else 257 int refclock_hopfpci_bs; 258 #endif /* REFCLOCK */ 259