1 /* 2 * refclock_atom - clock driver for 1-pps signals 3 */ 4 #ifdef HAVE_CONFIG_H 5 #include <config.h> 6 #endif 7 8 #include <stdio.h> 9 #include <ctype.h> 10 11 #include "ntpd.h" 12 #include "ntp_io.h" 13 #include "ntp_unixtime.h" 14 #include "ntp_refclock.h" 15 #include "ntp_stdlib.h" 16 17 #if defined(REFCLOCK) && defined(CLOCK_ATOM) 18 19 #ifdef HAVE_PPSAPI 20 # include "ppsapi_timepps.h" 21 #endif /* HAVE_PPSAPI */ 22 23 /* 24 * This driver furnishes an interface for pulse-per-second (PPS) signals 25 * produced by a cesium clock, timing receiver or related equipment. It 26 * can be used to remove accumulated jitter and retime a secondary 27 * server when synchronized to a primary server over a congested, wide- 28 * area network and before redistributing the time to local clients. 29 * 30 * Before this driver becomes active, the local clock must be set to 31 * within +-500 ms by another means, such as a radio clock or NTP 32 * itself. There are two ways to connect the PPS signal, normally at TTL 33 * levels, to the computer. One is to shift to EIA levels and connect to 34 * pin 8 (DCD) of a serial port. This requires a level converter and 35 * may require a one-shot flipflop to lengthen the pulse. The other is 36 * to connect the PPS signal directly to pin 10 (ACK) of a PC paralell 37 * port. These methods are architecture dependent. 38 * 39 * Both methods require a modified device driver and kernel interface 40 * compatible with the Pulse-per-Second API for Unix-like Operating 41 * Systems, Version 1.0, RFC-2783 (PPSAPI). Implementations are 42 * available for FreeBSD, Linux, SunOS, Solaris and Alpha. However, at 43 * present only the Alpha implementation provides the full generality of 44 * the API with multiple PPS drivers and multiple handles per driver. If 45 * the PPSAPI is normally implemented in the /usr/include/sys/timepps.h 46 * header file and kernel support specific to each operating system. 47 * However, this driver can operate without this interface if means are 48 * proviced to call the pps_sample() routine from another driver. Please 49 * note; if the PPSAPI interface is present, it must be used. 50 * 51 * In many configurations a single port is used for the radio timecode 52 * and PPS signal. In order to provide for this configuration and others 53 * involving dedicated multiple serial/parallel ports, the driver first 54 * attempts to open the device /dev/pps%d, where %d is the unit number. 55 * If this fails, the driver attempts to open the device specified by 56 * the pps configuration command. If a port is to be shared, the pps 57 * command must be placed before the radio device(s) and the radio 58 * device(s) must be placed before the PPS driver(s) in the 59 * configuration file. 60 * 61 * This driver normally uses the PLL/FLL clock discipline implemented in 62 * the ntpd code. Ordinarily, this is the most accurate means, as the 63 * median filter in the driver interface is much larger than in the 64 * kernel. However, if the systemic clock frequency error is large (tens 65 * to hundreds of PPM), it's better to used the kernel support, if 66 * available. 67 * 68 * Fudge Factors 69 * 70 * If flag2 is dim (default), the on-time epoch is the assert edge of 71 * the PPS signal; if lit, the on-time epoch is the clear edge. If flag2 72 * is lit, the assert edge is used; if flag3 is dim (default), the 73 * kernel PPS support is disabled; if lit it is enabled. The time1 74 * parameter can be used to compensate for miscellaneous device driver 75 * and OS delays. 76 */ 77 /* 78 * Interface definitions 79 */ 80 #ifdef HAVE_PPSAPI 81 #define DEVICE "/dev/pps%d" /* device name and unit */ 82 #endif /* HAVE_PPSAPI */ 83 84 #define PRECISION (-20) /* precision assumed (about 1 us) */ 85 #define REFID "PPS\0" /* reference ID */ 86 #define DESCRIPTION "PPS Clock Discipline" /* WRU */ 87 #define NANOSECOND 1000000000 /* one second (ns) */ 88 #define RANGEGATE 500000 /* range gate (ns) */ 89 90 static struct peer *pps_peer; /* atom driver for PPS sources */ 91 92 #ifdef HAVE_PPSAPI 93 /* 94 * PPS unit control structure 95 */ 96 struct ppsunit { 97 struct timespec ts; /* last timestamp */ 98 int fddev; /* pps device descriptor */ 99 pps_params_t pps_params; /* pps parameters */ 100 pps_info_t pps_info; /* last pps data */ 101 pps_handle_t handle; /* pps handlebars */ 102 }; 103 #endif /* HAVE_PPSAPI */ 104 105 /* 106 * Function prototypes 107 */ 108 static int atom_start P((int, struct peer *)); 109 static void atom_poll P((int, struct peer *)); 110 static void atom_shutdown P((int, struct peer *)); 111 #ifdef HAVE_PPSAPI 112 static void atom_control P((int, struct refclockstat *, struct 113 refclockstat *, struct peer *)); 114 static void atom_timer P((int, struct peer *)); 115 static int atom_ppsapi P((struct peer *, int)); 116 #endif /* HAVE_PPSAPI */ 117 118 /* 119 * Transfer vector 120 */ 121 #ifdef HAVE_PPSAPI 122 struct refclock refclock_atom = { 123 atom_start, /* start up driver */ 124 atom_shutdown, /* shut down driver */ 125 atom_poll, /* transmit poll message */ 126 atom_control, /* fudge control */ 127 noentry, /* initialize driver (not used) */ 128 noentry, /* buginfo (not used) */ 129 atom_timer, /* called once per second */ 130 }; 131 #else /* HAVE_PPSAPI */ 132 struct refclock refclock_atom = { 133 atom_start, /* start up driver */ 134 atom_shutdown, /* shut down driver */ 135 atom_poll, /* transmit poll message */ 136 noentry, /* fudge control (not used) */ 137 noentry, /* initialize driver (not used) */ 138 noentry, /* buginfo (not used) */ 139 NOFLAGS /* not used */ 140 }; 141 #endif /* HAVE_PPPSAPI */ 142 143 144 /* 145 * atom_start - initialize data for processing 146 */ 147 static int 148 atom_start( 149 int unit, /* unit number (not used) */ 150 struct peer *peer /* peer structure pointer */ 151 ) 152 { 153 struct refclockproc *pp; 154 #ifdef HAVE_PPSAPI 155 register struct ppsunit *up; 156 char device[80]; 157 int mode; 158 #endif /* HAVE_PPSAPI */ 159 160 /* 161 * Allocate and initialize unit structure 162 */ 163 pps_peer = peer; 164 pp = peer->procptr; 165 peer->precision = PRECISION; 166 pp->clockdesc = DESCRIPTION; 167 pp->stratum = STRATUM_UNSPEC; 168 memcpy((char *)&pp->refid, REFID, 4); 169 #ifdef HAVE_PPSAPI 170 up = emalloc(sizeof(struct ppsunit)); 171 memset(up, 0, sizeof(struct ppsunit)); 172 pp->unitptr = (caddr_t)up; 173 174 /* 175 * Open PPS device. This can be any serial or parallel port and 176 * not necessarily the port used for the associated radio. 177 */ 178 sprintf(device, DEVICE, unit); 179 up->fddev = open(device, O_RDWR, 0777); 180 if (up->fddev <= 0) { 181 msyslog(LOG_ERR, 182 "refclock_atom: %s: %m", device); 183 return (0); 184 } 185 186 /* 187 * Light off the PPSAPI interface. 188 */ 189 if (time_pps_create(up->fddev, &up->handle) < 0) { 190 msyslog(LOG_ERR, 191 "refclock_atom: time_pps_create failed: %m"); 192 return (0); 193 } 194 195 /* 196 * If the mode is nonzero, use that for the time_pps_setparams() 197 * mode; otherwise, PPS_CAPTUREASSERT. Enable kernel PPS if 198 * flag3 is lit. 199 */ 200 mode = peer->ttl; 201 if (mode == 0) 202 mode = PPS_CAPTUREASSERT; 203 return (atom_ppsapi(peer, mode)); 204 #else /* HAVE_PPSAPI */ 205 return (1); 206 #endif /* HAVE_PPSAPI */ 207 } 208 209 210 /* 211 * atom_shutdown - shut down the clock 212 */ 213 static void 214 atom_shutdown( 215 int unit, /* unit number (not used) */ 216 struct peer *peer /* peer structure pointer */ 217 ) 218 { 219 struct refclockproc *pp; 220 register struct ppsunit *up; 221 222 pp = peer->procptr; 223 up = (struct ppsunit *)pp->unitptr; 224 #ifdef HAVE_PPSAPI 225 if (up->fddev > 0) 226 close(up->fddev); 227 if (up->handle != 0) 228 time_pps_destroy(up->handle); 229 #endif /* HAVE_PPSAPI */ 230 if (pps_peer == peer) 231 pps_peer = NULL; 232 free(up); 233 } 234 235 236 #ifdef HAVE_PPSAPI 237 /* 238 * atom_control - fudge control 239 */ 240 static void 241 atom_control( 242 int unit, /* unit (not used */ 243 struct refclockstat *in, /* input parameters (not uded) */ 244 struct refclockstat *out, /* output parameters (not used) */ 245 struct peer *peer /* peer structure pointer */ 246 ) 247 { 248 struct refclockproc *pp; 249 int mode; 250 251 pp = peer->procptr; 252 if (peer->ttl != 0) /* all legal modes must be nonzero */ 253 return; 254 255 if (pp->sloppyclockflag & CLK_FLAG2) 256 mode = PPS_CAPTURECLEAR; 257 else 258 mode = PPS_CAPTUREASSERT; 259 atom_ppsapi(peer, mode); 260 } 261 262 263 /* 264 * Initialize PPSAPI 265 */ 266 int 267 atom_ppsapi( 268 struct peer *peer, /* peer structure pointer */ 269 int mode /* mode */ 270 ) 271 { 272 struct refclockproc *pp; 273 register struct ppsunit *up; 274 int capability; 275 276 pp = peer->procptr; 277 up = (struct ppsunit *)pp->unitptr; 278 if (up->handle == 0) 279 return (0); 280 281 if (time_pps_getcap(up->handle, &capability) < 0) { 282 msyslog(LOG_ERR, 283 "refclock_atom: time_pps_getcap failed: %m"); 284 return (0); 285 } 286 memset(&up->pps_params, 0, sizeof(pps_params_t)); 287 up->pps_params.api_version = PPS_API_VERS_1; 288 up->pps_params.mode = mode | PPS_TSFMT_TSPEC; 289 if (time_pps_setparams(up->handle, &up->pps_params) < 0) { 290 msyslog(LOG_ERR, 291 "refclock_atom: time_pps_setparams failed: %m"); 292 return (0); 293 } 294 if (pp->sloppyclockflag & CLK_FLAG3) { 295 if (time_pps_kcbind(up->handle, PPS_KC_HARDPPS, 296 up->pps_params.mode & ~PPS_TSFMT_TSPEC, 297 PPS_TSFMT_TSPEC) < 0) { 298 msyslog(LOG_ERR, 299 "refclock_atom: time_pps_kcbind failed: %m"); 300 return (0); 301 } 302 pps_enable = 1; 303 } 304 #if DEBUG 305 if (debug) { 306 time_pps_getparams(up->handle, &up->pps_params); 307 printf( 308 "refclock_ppsapi: fd %d capability 0x%x version %d mode 0x%x\n", 309 up->fddev, capability, up->pps_params.api_version, 310 up->pps_params.mode); 311 } 312 #endif 313 return (1); 314 } 315 316 317 /* 318 * atom_timer - called once per second 319 * 320 * This routine is called once per second when the PPSAPI interface is 321 * present. It snatches the PPS timestamp from the kernel and saves the 322 * sign-extended fraction in a circular buffer for processing at the 323 * next poll event. 324 */ 325 static void 326 atom_timer( 327 int unit, /* unit number (not used) */ 328 struct peer *peer /* peer structure pointer */ 329 ) 330 { 331 register struct ppsunit *up; 332 struct refclockproc *pp; 333 pps_info_t pps_info; 334 struct timespec timeout, ts; 335 long sec, nsec; 336 double dtemp; 337 char tbuf[80]; /* monitor buffer */ 338 339 /* 340 * Convert the timespec nanoseconds field to signed double and 341 * save in the median filter. for billboards. No harm is done if 342 * previous data are overwritten. If the discipline comes bum or 343 * the data grow stale, just forget it. A range gate rejects new 344 * samples if less than a jiggle time from the next second. 345 */ 346 pp = peer->procptr; 347 up = (struct ppsunit *)pp->unitptr; 348 if (up->handle == 0) 349 return; 350 351 timeout.tv_sec = 0; 352 timeout.tv_nsec = 0; 353 memcpy(&pps_info, &up->pps_info, sizeof(pps_info_t)); 354 if (time_pps_fetch(up->handle, PPS_TSFMT_TSPEC, &up->pps_info, 355 &timeout) < 0) { 356 refclock_report(peer, CEVNT_FAULT); 357 return; 358 } 359 if (up->pps_params.mode & PPS_CAPTUREASSERT) { 360 ts = up->pps_info.assert_timestamp; 361 } else if (up->pps_params.mode & PPS_CAPTURECLEAR) { 362 ts = up->pps_info.clear_timestamp; 363 } else { 364 refclock_report(peer, CEVNT_FAULT); 365 return; 366 } 367 368 /* 369 * There can be zero, one or two PPS seconds between polls. If 370 * zero, either the poll clock is slightly faster than the PPS 371 * clock or the PPS clock has died. If the PPS clock advanced 372 * once between polls, we make sure the fraction time difference 373 * since the last sample is within the range gate of 5 ms (500 374 * PPM). If the PPS clock advanced twice since the last poll, 375 * the poll bracketed more than one second and the first second 376 * was lost to a slip. Since the interval since the last sample 377 * found is now two seconds, just widen the range gate. If the 378 * PPS clock advanced three or more times, either the signal has 379 * failed for a number of seconds or we have runts, in which 380 * case just ignore them. 381 * 382 * If flag4 is lit, record each second offset to clockstats. 383 * That's so we can make awesome Allan deviation plots. 384 */ 385 sec = ts.tv_sec - up->ts.tv_sec; 386 nsec = ts.tv_nsec - up->ts.tv_nsec; 387 up->ts = ts; 388 if (nsec < 0) { 389 sec --; 390 nsec += NANOSECOND; 391 } else if (nsec >= NANOSECOND) { 392 sec++; 393 nsec -= NANOSECOND; 394 } 395 if (sec * NANOSECOND + nsec > NANOSECOND + RANGEGATE) 396 return; 397 398 else if (sec * NANOSECOND + nsec < NANOSECOND - RANGEGATE) 399 return; 400 401 pp->lastrec.l_ui = ts.tv_sec + JAN_1970; 402 dtemp = ts.tv_nsec * FRAC / 1e9; 403 if (dtemp >= FRAC) 404 pp->lastrec.l_ui++; 405 pp->lastrec.l_uf = (u_int32)dtemp; 406 if (ts.tv_nsec > NANOSECOND / 2) 407 ts.tv_nsec -= NANOSECOND; 408 dtemp = -(double)ts.tv_nsec / NANOSECOND; 409 SAMPLE(dtemp + pp->fudgetime1); 410 if (pp->sloppyclockflag & CLK_FLAG4){ 411 sprintf(tbuf, "%.9f", dtemp); 412 record_clock_stats(&peer->srcadr, tbuf); 413 } 414 #ifdef DEBUG 415 if (debug > 1) 416 printf("atom_timer: %lu %f %f\n", current_time, 417 dtemp, pp->fudgetime1); 418 #endif 419 return; 420 } 421 #endif /* HAVE_PPSAPI */ 422 423 424 /* 425 * pps_sample - receive PPS data from some other clock driver 426 * 427 * This routine is called once per second when the external clock driver 428 * processes PPS information. It processes the PPS timestamp and saves 429 * the sign-extended fraction in a circular buffer for processing at the 430 * next poll event. This works only for a single PPS device. 431 * 432 * The routine should be used by another configured driver ONLY when 433 * this driver is configured as well and the PPSAPI is NOT in use. 434 */ 435 int 436 pps_sample( 437 l_fp *offset /* PPS offset */ 438 ) 439 { 440 register struct peer *peer; 441 struct refclockproc *pp; 442 l_fp lftmp; 443 double doffset; 444 445 peer = pps_peer; 446 if (peer == NULL) 447 return (1); 448 449 pp = peer->procptr; 450 451 /* 452 * Convert the timeval to l_fp and save for billboards. Sign- 453 * extend the fraction and stash in the buffer. No harm is done 454 * if previous data are overwritten. If the discipline comes bum 455 * or the data grow stale, just forget it. 456 */ 457 pp->lastrec = *offset; 458 L_CLR(&lftmp); 459 L_ADDF(&lftmp, pp->lastrec.l_f); 460 LFPTOD(&lftmp, doffset); 461 SAMPLE(-doffset + pp->fudgetime1); 462 return (0); 463 } 464 465 466 /* 467 * atom_poll - called by the transmit procedure 468 */ 469 static void 470 atom_poll( 471 int unit, /* unit number (not used) */ 472 struct peer *peer /* peer structure pointer */ 473 ) 474 { 475 struct refclockproc *pp; 476 pp = peer->procptr; 477 pp->polls++; 478 479 /* 480 * Valid time is returned only if the prefer peer has survived 481 * the intersection algorithm and within 0.4 s of local time 482 * and not too long ago. This ensures the PPS time is within 483 * 0.5 s of the local time and the seconds numbering is 484 * unambiguous. Note that the leap bits, stratum and refid are 485 * set from the prefer peer, unless overriden by a fudge 486 * command. 487 */ 488 if (pp->codeproc == pp->coderecv) { 489 refclock_report(peer, CEVNT_TIMEOUT); 490 return; 491 492 } else if (sys_prefer == NULL) { 493 pp->codeproc = pp->coderecv; 494 return; 495 496 } else if (fabs(sys_prefer->offset) >= 0.4) { 497 pp->codeproc = pp->coderecv; 498 return; 499 } 500 pp->leap = sys_prefer->leap; 501 if (pp->stratum >= STRATUM_UNSPEC) 502 peer->stratum = sys_prefer->stratum; 503 else 504 peer->stratum = pp->stratum; 505 pp->lastref = pp->lastrec; 506 refclock_receive(peer); 507 } 508 #else 509 int refclock_atom_bs; 510 int 511 pps_sample( 512 l_fp *offset /* PPS offset */ 513 ) 514 { 515 return (1); 516 } 517 #endif /* REFCLOCK */ 518