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