1 /* 2 * 3 * refclock_hopfser.c 4 * - clock driver for hopf serial boards (GPS or DCF77) 5 * 6 * Date: 30.03.2000 Revision: 01.10 7 * 8 * latest source and further information can be found at: 9 * http://www.ATLSoft.de/ntp 10 * 11 */ 12 13 #ifdef HAVE_CONFIG_H 14 # include "config.h" 15 #endif 16 17 #if defined(SYS_WINNT) 18 #undef close 19 #define close closesocket 20 #endif 21 22 #if defined(REFCLOCK) && (defined(CLOCK_HOPF_SERIAL)) 23 24 #include "ntpd.h" 25 #include "ntp_io.h" 26 #include "ntp_control.h" 27 #include "ntp_refclock.h" 28 #include "ntp_unixtime.h" 29 #include "ntp_stdlib.h" 30 31 #if defined HAVE_SYS_MODEM_H 32 # include <sys/modem.h> 33 # ifndef __QNXNTO__ 34 # define TIOCMSET MCSETA 35 # define TIOCMGET MCGETA 36 # define TIOCM_RTS MRTS 37 # endif 38 #endif 39 40 #ifdef HAVE_TERMIOS_H 41 # ifdef TERMIOS_NEEDS__SVID3 42 # define _SVID3 43 # endif 44 # include <termios.h> 45 # ifdef TERMIOS_NEEDS__SVID3 46 # undef _SVID3 47 # endif 48 #endif 49 50 #ifdef HAVE_SYS_IOCTL_H 51 # include <sys/ioctl.h> 52 #endif 53 54 /* 55 * clock definitions 56 */ 57 #define DESCRIPTION "hopf Elektronik serial clock" /* Long name */ 58 #define PRECISION (-10) /* precision assumed (about 1 ms) */ 59 #define REFID "hopf\0" /* reference ID */ 60 /* 61 * I/O definitions 62 */ 63 #define DEVICE "/dev/hopfclock%d" /* device name and unit */ 64 #define SPEED232 B9600 /* uart speed (9600 baud) */ 65 66 67 #define STX 0x02 68 #define ETX 0x03 69 #define CR 0x0c 70 #define LF 0x0a 71 72 /* parse states */ 73 #define REC_QUEUE_EMPTY 0 74 #define REC_QUEUE_FULL 1 75 76 #define HOPF_OPMODE 0x0C /* operation mode mask */ 77 #define HOPF_INVALID 0x00 /* no time code available */ 78 #define HOPF_INTERNAL 0x04 /* internal clock */ 79 #define HOPF_RADIO 0x08 /* radio clock */ 80 #define HOPF_RADIOHP 0x0C /* high precision radio clock */ 81 82 /* 83 * hopfclock unit control structure. 84 */ 85 struct hopfclock_unit { 86 l_fp laststamp; /* last receive timestamp */ 87 short unit; /* NTP refclock unit number */ 88 u_long polled; /* flag to detect noreplies */ 89 char leap_status; /* leap second flag */ 90 int rpt_next; 91 }; 92 93 /* 94 * Function prototypes 95 */ 96 97 static int hopfserial_start P((int, struct peer *)); 98 static void hopfserial_shutdown P((int, struct peer *)); 99 static void hopfserial_receive P((struct recvbuf *)); 100 static void hopfserial_poll P((int, struct peer *)); 101 /* static void hopfserial_io P((struct recvbuf *)); */ 102 /* 103 * Transfer vector 104 */ 105 struct refclock refclock_hopfser = { 106 hopfserial_start, /* start up driver */ 107 hopfserial_shutdown, /* shut down driver */ 108 hopfserial_poll, /* transmit poll message */ 109 noentry, /* not used */ 110 noentry, /* initialize driver (not used) */ 111 noentry, /* not used */ 112 NOFLAGS /* not used */ 113 }; 114 115 /* 116 * hopfserial_start - open the devices and initialize data for processing 117 */ 118 static int 119 hopfserial_start ( 120 int unit, 121 struct peer *peer 122 ) 123 { 124 register struct hopfclock_unit *up; 125 struct refclockproc *pp; 126 int fd; 127 char gpsdev[20]; 128 129 #ifdef SYS_WINNT 130 (void) sprintf(gpsdev, "COM%d:", unit); 131 #else 132 (void) sprintf(gpsdev, DEVICE, unit); 133 #endif 134 /* LDISC_STD, LDISC_RAW 135 * Open serial port. Use CLK line discipline, if available. 136 */ 137 fd = refclock_open(gpsdev, SPEED232, LDISC_CLK); 138 if (fd <= 0) { 139 #ifdef DEBUG 140 printf("hopfSerialClock(%d) start: open %s failed\n", unit, gpsdev); 141 #endif 142 return 0; 143 } 144 145 msyslog(LOG_NOTICE, "hopfSerialClock(%d) fd: %d dev: %s", unit, fd, 146 gpsdev); 147 148 /* 149 * Allocate and initialize unit structure 150 */ 151 up = (struct hopfclock_unit *) emalloc(sizeof(struct hopfclock_unit)); 152 153 if (!(up)) { 154 msyslog(LOG_ERR, "hopfSerialClock(%d) emalloc: %m",unit); 155 #ifdef DEBUG 156 printf("hopfSerialClock(%d) emalloc\n",unit); 157 #endif 158 (void) close(fd); 159 return (0); 160 } 161 162 memset((char *)up, 0, sizeof(struct hopfclock_unit)); 163 pp = peer->procptr; 164 pp->unitptr = (caddr_t)up; 165 pp->io.clock_recv = hopfserial_receive; 166 pp->io.srcclock = (caddr_t)peer; 167 pp->io.datalen = 0; 168 pp->io.fd = fd; 169 if (!io_addclock(&pp->io)) { 170 #ifdef DEBUG 171 printf("hopfSerialClock(%d) io_addclock\n",unit); 172 #endif 173 (void) close(fd); 174 free(up); 175 return (0); 176 } 177 178 /* 179 * Initialize miscellaneous variables 180 */ 181 pp->clockdesc = DESCRIPTION; 182 peer->precision = PRECISION; 183 peer->burst = NSTAGE; 184 memcpy((char *)&pp->refid, REFID, 4); 185 186 up->leap_status = 0; 187 up->unit = (short) unit; 188 189 return (1); 190 } 191 192 193 /* 194 * hopfserial_shutdown - shut down the clock 195 */ 196 static void 197 hopfserial_shutdown ( 198 int unit, 199 struct peer *peer 200 ) 201 { 202 register struct hopfclock_unit *up; 203 struct refclockproc *pp; 204 205 pp = peer->procptr; 206 up = (struct hopfclock_unit *)pp->unitptr; 207 io_closeclock(&pp->io); 208 free(up); 209 } 210 211 212 213 /* 214 * hopfserial_receive - receive data from the serial interface 215 */ 216 217 static void 218 hopfserial_receive ( 219 struct recvbuf *rbufp 220 ) 221 { 222 struct hopfclock_unit *up; 223 struct refclockproc *pp; 224 struct peer *peer; 225 226 int synch; /* synchhronization indicator */ 227 int DoW; /* Dow */ 228 229 int day, month; /* ddd conversion */ 230 231 /* 232 * Initialize pointers and read the timecode and timestamp. 233 */ 234 peer = (struct peer *)rbufp->recv_srcclock; 235 pp = peer->procptr; 236 up = (struct hopfclock_unit *)pp->unitptr; 237 238 if (up->rpt_next == 0 ) 239 return; 240 241 242 up->rpt_next = 0; /* wait until next poll interval occur */ 243 244 pp->lencode = (u_short)refclock_gtlin(rbufp, pp->a_lastcode, BMAX, &pp->lastrec); 245 246 if (pp->lencode == 0) 247 return; 248 249 sscanf(pp->a_lastcode, 250 #if 1 251 "%1x%1x%2d%2d%2d%2d%2d%2d", /* ...cr,lf */ 252 #else 253 "%*c%1x%1x%2d%2d%2d%2d%2d%2d", /* stx...cr,lf,etx */ 254 #endif 255 &synch, 256 &DoW, 257 &pp->hour, 258 &pp->minute, 259 &pp->second, 260 &day, 261 &month, 262 &pp->year); 263 264 265 /* 266 Validate received values at least enough to prevent internal 267 array-bounds problems, etc. 268 */ 269 if((pp->hour < 0) || (pp->hour > 23) || 270 (pp->minute < 0) || (pp->minute > 59) || 271 (pp->second < 0) || (pp->second > 60) /*Allow for leap seconds.*/ || 272 (day < 1) || (day > 31) || 273 (month < 1) || (month > 12) || 274 (pp->year < 0) || (pp->year > 99)) { 275 /* Data out of range. */ 276 refclock_report(peer, CEVNT_BADREPLY); 277 return; 278 } 279 /* 280 some preparations 281 */ 282 pp->day = ymd2yd(pp->year,month,day); 283 pp->leap=0; 284 285 /* Year-2000 check! */ 286 /* wrap 2-digit date into 4-digit */ 287 288 if(pp->year < YEAR_PIVOT) { pp->year += 100; } /* < 98 */ 289 pp->year += 1900; 290 291 /* preparation for timecode ntpq rl command ! */ 292 293 #if 0 294 wsprintf(pp->a_lastcode, 295 "STATUS: %1X%1X, DATE: %02d.%02d.%04d TIME: %02d:%02d:%02d", 296 synch, 297 DoW, 298 day, 299 month, 300 pp->year, 301 pp->hour, 302 pp->minute, 303 pp->second); 304 305 pp->lencode = strlen(pp->a_lastcode); 306 if ((synch && 0xc) == 0 ){ /* time ok? */ 307 refclock_report(peer, CEVNT_BADTIME); 308 pp->leap = LEAP_NOTINSYNC; 309 return; 310 } 311 #endif 312 /* 313 * If clock has no valid status then report error and exit 314 */ 315 if ((synch & HOPF_OPMODE) == HOPF_INVALID ){ /* time ok? */ 316 refclock_report(peer, CEVNT_BADTIME); 317 pp->leap = LEAP_NOTINSYNC; 318 return; 319 } 320 321 /* 322 * Test if time is running on internal quarz 323 * if CLK_FLAG1 is set, sychronize even if no radio operation 324 */ 325 326 if ((synch & HOPF_OPMODE) == HOPF_INTERNAL){ 327 if ((pp->sloppyclockflag & CLK_FLAG1) == 0) { 328 refclock_report(peer, CEVNT_BADTIME); 329 pp->leap = LEAP_NOTINSYNC; 330 return; 331 } 332 } 333 334 335 if (!refclock_process(pp)) { 336 refclock_report(peer, CEVNT_BADTIME); 337 return; 338 } 339 pp->lastref = pp->lastrec; 340 refclock_receive(peer); 341 342 #if 0 343 msyslog(LOG_ERR, " D:%x D:%d D:%d",synch,pp->minute,pp->second); 344 #endif 345 346 record_clock_stats(&peer->srcadr, pp->a_lastcode); 347 348 return; 349 } 350 351 352 /* 353 * hopfserial_poll - called by the transmit procedure 354 * 355 */ 356 static void 357 hopfserial_poll ( 358 int unit, 359 struct peer *peer 360 ) 361 { 362 register struct hopfclock_unit *up; 363 struct refclockproc *pp; 364 pp = peer->procptr; 365 366 up = (struct hopfclock_unit *)pp->unitptr; 367 368 pp->polls++; 369 up->rpt_next = 1; 370 371 #if 0 372 record_clock_stats(&peer->srcadr, pp->a_lastcode); 373 #endif 374 375 return; 376 } 377 378 #else 379 int refclock_hopfser_bs; 380 #endif /* REFCLOCK */ 381