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