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