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