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