1c0b746e5SOllivier Robert /* 2c0b746e5SOllivier Robert * ntp_refclock - processing support for reference clocks 3c0b746e5SOllivier Robert */ 4c0b746e5SOllivier Robert #ifdef HAVE_CONFIG_H 5c0b746e5SOllivier Robert # include <config.h> 6c0b746e5SOllivier Robert #endif 7c0b746e5SOllivier Robert 8c0b746e5SOllivier Robert #include "ntpd.h" 9c0b746e5SOllivier Robert #include "ntp_io.h" 10c0b746e5SOllivier Robert #include "ntp_unixtime.h" 11224ba2bdSOllivier Robert #include "ntp_tty.h" 12c0b746e5SOllivier Robert #include "ntp_refclock.h" 13a466cc55SCy Schubert #include "ntp_clockdev.h" 14c0b746e5SOllivier Robert #include "ntp_stdlib.h" 152b15cb3dSCy Schubert #include "ntp_assert.h" 162d4e511cSCy Schubert #include "timespecops.h" 17c0b746e5SOllivier Robert 18224ba2bdSOllivier Robert #include <stdio.h> 19224ba2bdSOllivier Robert 20224ba2bdSOllivier Robert #ifdef HAVE_SYS_IOCTL_H 21224ba2bdSOllivier Robert # include <sys/ioctl.h> 22224ba2bdSOllivier Robert #endif /* HAVE_SYS_IOCTL_H */ 23224ba2bdSOllivier Robert 24c0b746e5SOllivier Robert #ifdef REFCLOCK 25c0b746e5SOllivier Robert 26224ba2bdSOllivier Robert #ifdef KERNEL_PLL 27224ba2bdSOllivier Robert #include "ntp_syscall.h" 28224ba2bdSOllivier Robert #endif /* KERNEL_PLL */ 29c0b746e5SOllivier Robert 302b15cb3dSCy Schubert #ifdef HAVE_PPSAPI 312b15cb3dSCy Schubert #include "ppsapi_timepps.h" 322b15cb3dSCy Schubert #include "refclock_atom.h" 332b15cb3dSCy Schubert #endif /* HAVE_PPSAPI */ 342b15cb3dSCy Schubert 35c0b746e5SOllivier Robert /* 36c0b746e5SOllivier Robert * Reference clock support is provided here by maintaining the fiction 372b15cb3dSCy Schubert * that the clock is actually a peer. As no packets are exchanged with 382b15cb3dSCy Schubert * a reference clock, however, we replace the transmit, receive and 392b15cb3dSCy Schubert * packet procedures with separate code to simulate them. Routines 40c0b746e5SOllivier Robert * refclock_transmit() and refclock_receive() maintain the peer 41c0b746e5SOllivier Robert * variables in a state analogous to an actual peer and pass reference 42c0b746e5SOllivier Robert * clock data on through the filters. Routines refclock_peer() and 43c0b746e5SOllivier Robert * refclock_unpeer() are called to initialize and terminate reference 44c0b746e5SOllivier Robert * clock associations. A set of utility routines is included to open 452b15cb3dSCy Schubert * serial devices, process sample data, and to perform various debugging 462b15cb3dSCy Schubert * functions. 47c0b746e5SOllivier Robert * 48c0b746e5SOllivier Robert * The main interface used by these routines is the refclockproc 492b15cb3dSCy Schubert * structure, which contains for most drivers the decimal equivalants 502b15cb3dSCy Schubert * of the year, day, month, hour, second and millisecond/microsecond 512b15cb3dSCy Schubert * decoded from the ASCII timecode. Additional information includes 522b15cb3dSCy Schubert * the receive timestamp, exception report, statistics tallies, etc. 532b15cb3dSCy Schubert * In addition, there may be a driver-specific unit structure used for 54c0b746e5SOllivier Robert * local control of the device. 55c0b746e5SOllivier Robert * 56c0b746e5SOllivier Robert * The support routines are passed a pointer to the peer structure, 572b15cb3dSCy Schubert * which is used for all peer-specific processing and contains a 582b15cb3dSCy Schubert * pointer to the refclockproc structure, which in turn contains a 592b15cb3dSCy Schubert * pointer to the unit structure, if used. The peer structure is 602b15cb3dSCy Schubert * identified by an interface address in the dotted quad form 612b15cb3dSCy Schubert * 127.127.t.u, where t is the clock type and u the unit. 62c0b746e5SOllivier Robert */ 63c0b746e5SOllivier Robert #define FUDGEFAC .1 /* fudge correction factor */ 64ea906c41SOllivier Robert #define LF 0x0a /* ASCII LF */ 65c0b746e5SOllivier Robert 66224ba2bdSOllivier Robert int cal_enable; /* enable refclock calibrate */ 67224ba2bdSOllivier Robert 68c0b746e5SOllivier Robert /* 69c0b746e5SOllivier Robert * Forward declarations 70c0b746e5SOllivier Robert */ 712b15cb3dSCy Schubert static int refclock_cmpl_fp (const void *, const void *); 722b15cb3dSCy Schubert static int refclock_sample (struct refclockproc *); 732b15cb3dSCy Schubert static int refclock_ioctl(int, u_int); 742d4e511cSCy Schubert static void refclock_checkburst(struct peer *, struct refclockproc *); 75c0b746e5SOllivier Robert 762d4e511cSCy Schubert /* circular buffer functions 772d4e511cSCy Schubert * 782d4e511cSCy Schubert * circular buffer management comes in two flovours: 792d4e511cSCy Schubert * for powers of two, and all others. 802d4e511cSCy Schubert */ 812d4e511cSCy Schubert 822d4e511cSCy Schubert #if MAXSTAGE & (MAXSTAGE - 1) 832d4e511cSCy Schubert 842d4e511cSCy Schubert static void clk_add_sample( 852d4e511cSCy Schubert struct refclockproc * const pp, 862d4e511cSCy Schubert double sv 872d4e511cSCy Schubert ) 882d4e511cSCy Schubert { 892d4e511cSCy Schubert pp->coderecv = (pp->coderecv + 1) % MAXSTAGE; 902d4e511cSCy Schubert if (pp->coderecv == pp->codeproc) 912d4e511cSCy Schubert pp->codeproc = (pp->codeproc + 1) % MAXSTAGE; 922d4e511cSCy Schubert pp->filter[pp->coderecv] = sv; 932d4e511cSCy Schubert } 942d4e511cSCy Schubert 952d4e511cSCy Schubert static double clk_pop_sample( 962d4e511cSCy Schubert struct refclockproc * const pp 972d4e511cSCy Schubert ) 982d4e511cSCy Schubert { 992d4e511cSCy Schubert if (pp->coderecv == pp->codeproc) 1002d4e511cSCy Schubert return 0; /* Maybe a NaN would be better? */ 1012d4e511cSCy Schubert pp->codeproc = (pp->codeproc + 1) % MAXSTAGE; 1022d4e511cSCy Schubert return pp->filter[pp->codeproc]; 1032d4e511cSCy Schubert } 1042d4e511cSCy Schubert 1052d4e511cSCy Schubert static inline u_int clk_cnt_sample( 1062d4e511cSCy Schubert struct refclockproc * const pp 1072d4e511cSCy Schubert ) 1082d4e511cSCy Schubert { 1092d4e511cSCy Schubert u_int retv = pp->coderecv - pp->codeproc; 1102d4e511cSCy Schubert if (retv > MAXSTAGE) 1112d4e511cSCy Schubert retv += MAXSTAGE; 1122d4e511cSCy Schubert return retv; 1132d4e511cSCy Schubert } 1142d4e511cSCy Schubert 1152d4e511cSCy Schubert #else 1162d4e511cSCy Schubert 1172d4e511cSCy Schubert static inline void clk_add_sample( 1182d4e511cSCy Schubert struct refclockproc * const pp, 1192d4e511cSCy Schubert double sv 1202d4e511cSCy Schubert ) 1212d4e511cSCy Schubert { 1222d4e511cSCy Schubert pp->coderecv = (pp->coderecv + 1) & (MAXSTAGE - 1); 1232d4e511cSCy Schubert if (pp->coderecv == pp->codeproc) 1242d4e511cSCy Schubert pp->codeproc = (pp->codeproc + 1) & (MAXSTAGE - 1); 1252d4e511cSCy Schubert pp->filter[pp->coderecv] = sv; 1262d4e511cSCy Schubert } 1272d4e511cSCy Schubert 1282d4e511cSCy Schubert static inline double clk_pop_sample( 1292d4e511cSCy Schubert struct refclockproc * const pp 1302d4e511cSCy Schubert ) 1312d4e511cSCy Schubert { 1322d4e511cSCy Schubert if (pp->coderecv == pp->codeproc) 1332d4e511cSCy Schubert return 0; /* Maybe a NaN would be better? */ 1342d4e511cSCy Schubert pp->codeproc = (pp->codeproc + 1) & (MAXSTAGE - 1); 1352d4e511cSCy Schubert return pp->filter[pp->codeproc]; 1362d4e511cSCy Schubert } 1372d4e511cSCy Schubert 1382d4e511cSCy Schubert static inline u_int clk_cnt_sample( 1392d4e511cSCy Schubert struct refclockproc * const pp 1402d4e511cSCy Schubert ) 1412d4e511cSCy Schubert { 1422d4e511cSCy Schubert return (pp->coderecv - pp->codeproc) & (MAXSTAGE - 1); 1432d4e511cSCy Schubert } 1442d4e511cSCy Schubert 1452d4e511cSCy Schubert #endif 146ea906c41SOllivier Robert 147c0b746e5SOllivier Robert /* 148c0b746e5SOllivier Robert * refclock_report - note the occurance of an event 149c0b746e5SOllivier Robert * 150c0b746e5SOllivier Robert * This routine presently just remembers the report and logs it, but 151c0b746e5SOllivier Robert * does nothing heroic for the trap handler. It tries to be a good 152c0b746e5SOllivier Robert * citizen and bothers the system log only if things change. 153c0b746e5SOllivier Robert */ 154c0b746e5SOllivier Robert void 155c0b746e5SOllivier Robert refclock_report( 156c0b746e5SOllivier Robert struct peer *peer, 157c0b746e5SOllivier Robert int code 158c0b746e5SOllivier Robert ) 159c0b746e5SOllivier Robert { 160c0b746e5SOllivier Robert struct refclockproc *pp; 161c0b746e5SOllivier Robert 1629c2daa00SOllivier Robert pp = peer->procptr; 1639c2daa00SOllivier Robert if (pp == NULL) 164c0b746e5SOllivier Robert return; 165ea906c41SOllivier Robert 166ea906c41SOllivier Robert switch (code) { 167ea906c41SOllivier Robert 168ea906c41SOllivier Robert case CEVNT_TIMEOUT: 169c0b746e5SOllivier Robert pp->noreply++; 170ea906c41SOllivier Robert break; 171ea906c41SOllivier Robert 172ea906c41SOllivier Robert case CEVNT_BADREPLY: 173ea906c41SOllivier Robert pp->badformat++; 174ea906c41SOllivier Robert break; 175ea906c41SOllivier Robert 176ea906c41SOllivier Robert case CEVNT_FAULT: 177ea906c41SOllivier Robert break; 178ea906c41SOllivier Robert 179ea906c41SOllivier Robert case CEVNT_BADDATE: 180ea906c41SOllivier Robert case CEVNT_BADTIME: 181ea906c41SOllivier Robert pp->baddata++; 182ea906c41SOllivier Robert break; 183ea906c41SOllivier Robert 184ea906c41SOllivier Robert default: 1852b15cb3dSCy Schubert /* ignore others */ 186ea906c41SOllivier Robert break; 187ea906c41SOllivier Robert } 1884e1ef62aSXin LI if ((code != CEVNT_NOMINAL) && (pp->lastevent < 15)) 1892b15cb3dSCy Schubert pp->lastevent++; 190c0b746e5SOllivier Robert if (pp->currentstatus != code) { 1919c2daa00SOllivier Robert pp->currentstatus = (u_char)code; 1922b15cb3dSCy Schubert report_event(PEVNT_CLOCK, peer, ceventstr(code)); 193ea906c41SOllivier Robert } 194ea906c41SOllivier Robert } 195c0b746e5SOllivier Robert 1962b15cb3dSCy Schubert 197c0b746e5SOllivier Robert /* 198c0b746e5SOllivier Robert * init_refclock - initialize the reference clock drivers 199c0b746e5SOllivier Robert * 200c0b746e5SOllivier Robert * This routine calls each of the drivers in turn to initialize internal 201c0b746e5SOllivier Robert * variables, if necessary. Most drivers have nothing to say at this 202c0b746e5SOllivier Robert * point. 203c0b746e5SOllivier Robert */ 204c0b746e5SOllivier Robert void 205c0b746e5SOllivier Robert init_refclock(void) 206c0b746e5SOllivier Robert { 2072b15cb3dSCy Schubert int i; 208c0b746e5SOllivier Robert 2092b15cb3dSCy Schubert for (i = 0; i < (int)num_refclock_conf; i++) 210c0b746e5SOllivier Robert if (refclock_conf[i]->clock_init != noentry) 211c0b746e5SOllivier Robert (refclock_conf[i]->clock_init)(); 212c0b746e5SOllivier Robert } 213c0b746e5SOllivier Robert 214c0b746e5SOllivier Robert 215c0b746e5SOllivier Robert /* 216c0b746e5SOllivier Robert * refclock_newpeer - initialize and start a reference clock 217c0b746e5SOllivier Robert * 218c0b746e5SOllivier Robert * This routine allocates and initializes the interface structure which 219c0b746e5SOllivier Robert * supports a reference clock in the form of an ordinary NTP peer. A 220c0b746e5SOllivier Robert * driver-specific support routine completes the initialization, if 221c0b746e5SOllivier Robert * used. Default peer variables which identify the clock and establish 222c0b746e5SOllivier Robert * its reference ID and stratum are set here. It returns one if success 223c0b746e5SOllivier Robert * and zero if the clock address is invalid or already running, 224c0b746e5SOllivier Robert * insufficient resources are available or the driver declares a bum 225c0b746e5SOllivier Robert * rap. 226c0b746e5SOllivier Robert */ 227c0b746e5SOllivier Robert int 228c0b746e5SOllivier Robert refclock_newpeer( 229c0b746e5SOllivier Robert struct peer *peer /* peer structure pointer */ 230c0b746e5SOllivier Robert ) 231c0b746e5SOllivier Robert { 232c0b746e5SOllivier Robert struct refclockproc *pp; 233c0b746e5SOllivier Robert u_char clktype; 234c0b746e5SOllivier Robert int unit; 235c0b746e5SOllivier Robert 236c0b746e5SOllivier Robert /* 237c0b746e5SOllivier Robert * Check for valid clock address. If already running, shut it 238c0b746e5SOllivier Robert * down first. 239c0b746e5SOllivier Robert */ 240c0b746e5SOllivier Robert if (!ISREFCLOCKADR(&peer->srcadr)) { 241c0b746e5SOllivier Robert msyslog(LOG_ERR, 242c0b746e5SOllivier Robert "refclock_newpeer: clock address %s invalid", 2439c2daa00SOllivier Robert stoa(&peer->srcadr)); 244c0b746e5SOllivier Robert return (0); 245c0b746e5SOllivier Robert } 246c0b746e5SOllivier Robert clktype = (u_char)REFCLOCKTYPE(&peer->srcadr); 247c0b746e5SOllivier Robert unit = REFCLOCKUNIT(&peer->srcadr); 2482b15cb3dSCy Schubert if (clktype >= num_refclock_conf || 249c0b746e5SOllivier Robert refclock_conf[clktype]->clock_start == noentry) { 250c0b746e5SOllivier Robert msyslog(LOG_ERR, 251c0b746e5SOllivier Robert "refclock_newpeer: clock type %d invalid\n", 252c0b746e5SOllivier Robert clktype); 253c0b746e5SOllivier Robert return (0); 254c0b746e5SOllivier Robert } 255c0b746e5SOllivier Robert 256c0b746e5SOllivier Robert /* 257c0b746e5SOllivier Robert * Allocate and initialize interface structure 258c0b746e5SOllivier Robert */ 2592b15cb3dSCy Schubert pp = emalloc_zero(sizeof(*pp)); 260c0b746e5SOllivier Robert peer->procptr = pp; 261c0b746e5SOllivier Robert 262c0b746e5SOllivier Robert /* 263c0b746e5SOllivier Robert * Initialize structures 264c0b746e5SOllivier Robert */ 265c0b746e5SOllivier Robert peer->refclktype = clktype; 2669c2daa00SOllivier Robert peer->refclkunit = (u_char)unit; 2672b15cb3dSCy Schubert peer->flags |= FLAG_REFCLOCK; 268ea906c41SOllivier Robert peer->leap = LEAP_NOTINSYNC; 2699c2daa00SOllivier Robert peer->stratum = STRATUM_REFCLOCK; 270ea906c41SOllivier Robert peer->ppoll = peer->maxpoll; 271c0b746e5SOllivier Robert pp->type = clktype; 2722b15cb3dSCy Schubert pp->conf = refclock_conf[clktype]; 273c0b746e5SOllivier Robert pp->timestarted = current_time; 2742b15cb3dSCy Schubert pp->io.fd = -1; 275c0b746e5SOllivier Robert 276c0b746e5SOllivier Robert /* 277c0b746e5SOllivier Robert * Set peer.pmode based on the hmode. For appearances only. 278c0b746e5SOllivier Robert */ 279c0b746e5SOllivier Robert switch (peer->hmode) { 280c0b746e5SOllivier Robert case MODE_ACTIVE: 281c0b746e5SOllivier Robert peer->pmode = MODE_PASSIVE; 282c0b746e5SOllivier Robert break; 283c0b746e5SOllivier Robert 284c0b746e5SOllivier Robert default: 285c0b746e5SOllivier Robert peer->pmode = MODE_SERVER; 286c0b746e5SOllivier Robert break; 287c0b746e5SOllivier Robert } 288c0b746e5SOllivier Robert 289c0b746e5SOllivier Robert /* 290c0b746e5SOllivier Robert * Do driver dependent initialization. The above defaults 291c0b746e5SOllivier Robert * can be wiggled, then finish up for consistency. 292c0b746e5SOllivier Robert */ 293c0b746e5SOllivier Robert if (!((refclock_conf[clktype]->clock_start)(unit, peer))) { 294224ba2bdSOllivier Robert refclock_unpeer(peer); 295c0b746e5SOllivier Robert return (0); 296c0b746e5SOllivier Robert } 297c0b746e5SOllivier Robert peer->refid = pp->refid; 298c0b746e5SOllivier Robert return (1); 299c0b746e5SOllivier Robert } 300c0b746e5SOllivier Robert 301c0b746e5SOllivier Robert 302c0b746e5SOllivier Robert /* 303c0b746e5SOllivier Robert * refclock_unpeer - shut down a clock 304c0b746e5SOllivier Robert */ 305c0b746e5SOllivier Robert void 306c0b746e5SOllivier Robert refclock_unpeer( 307c0b746e5SOllivier Robert struct peer *peer /* peer structure pointer */ 308c0b746e5SOllivier Robert ) 309c0b746e5SOllivier Robert { 310c0b746e5SOllivier Robert u_char clktype; 311c0b746e5SOllivier Robert int unit; 312c0b746e5SOllivier Robert 313c0b746e5SOllivier Robert /* 314c0b746e5SOllivier Robert * Wiggle the driver to release its resources, then give back 315c0b746e5SOllivier Robert * the interface structure. 316c0b746e5SOllivier Robert */ 3172b15cb3dSCy Schubert if (NULL == peer->procptr) 318c0b746e5SOllivier Robert return; 319ea906c41SOllivier Robert 320c0b746e5SOllivier Robert clktype = peer->refclktype; 321c0b746e5SOllivier Robert unit = peer->refclkunit; 322c0b746e5SOllivier Robert if (refclock_conf[clktype]->clock_shutdown != noentry) 323c0b746e5SOllivier Robert (refclock_conf[clktype]->clock_shutdown)(unit, peer); 324c0b746e5SOllivier Robert free(peer->procptr); 3252b15cb3dSCy Schubert peer->procptr = NULL; 326c0b746e5SOllivier Robert } 327c0b746e5SOllivier Robert 328c0b746e5SOllivier Robert 329c0b746e5SOllivier Robert /* 330ea906c41SOllivier Robert * refclock_timer - called once per second for housekeeping. 331ea906c41SOllivier Robert */ 332ea906c41SOllivier Robert void 333ea906c41SOllivier Robert refclock_timer( 3342b15cb3dSCy Schubert struct peer *p 335ea906c41SOllivier Robert ) 336ea906c41SOllivier Robert { 3372b15cb3dSCy Schubert struct refclockproc * pp; 338ea906c41SOllivier Robert int unit; 339ea906c41SOllivier Robert 3402b15cb3dSCy Schubert unit = p->refclkunit; 3412b15cb3dSCy Schubert pp = p->procptr; 3422b15cb3dSCy Schubert if (pp->conf->clock_timer != noentry) 3432b15cb3dSCy Schubert (*pp->conf->clock_timer)(unit, p); 3442b15cb3dSCy Schubert if (pp->action != NULL && pp->nextaction <= current_time) 3452b15cb3dSCy Schubert (*pp->action)(p); 346ea906c41SOllivier Robert } 347ea906c41SOllivier Robert 348ea906c41SOllivier Robert 349ea906c41SOllivier Robert /* 350c0b746e5SOllivier Robert * refclock_transmit - simulate the transmit procedure 351c0b746e5SOllivier Robert * 352c0b746e5SOllivier Robert * This routine implements the NTP transmit procedure for a reference 353c0b746e5SOllivier Robert * clock. This provides a mechanism to call the driver at the NTP poll 354c0b746e5SOllivier Robert * interval, as well as provides a reachability mechanism to detect a 355c0b746e5SOllivier Robert * broken radio or other madness. 356c0b746e5SOllivier Robert */ 357c0b746e5SOllivier Robert void 358c0b746e5SOllivier Robert refclock_transmit( 359c0b746e5SOllivier Robert struct peer *peer /* peer structure pointer */ 360c0b746e5SOllivier Robert ) 361c0b746e5SOllivier Robert { 362c0b746e5SOllivier Robert u_char clktype; 363c0b746e5SOllivier Robert int unit; 364c0b746e5SOllivier Robert 365c0b746e5SOllivier Robert clktype = peer->refclktype; 366c0b746e5SOllivier Robert unit = peer->refclkunit; 367c0b746e5SOllivier Robert peer->sent++; 368ea906c41SOllivier Robert get_systime(&peer->xmt); 369c0b746e5SOllivier Robert 370c0b746e5SOllivier Robert /* 371c0b746e5SOllivier Robert * This is a ripoff of the peer transmit routine, but 372c0b746e5SOllivier Robert * specialized for reference clocks. We do a little less 373c0b746e5SOllivier Robert * protocol here and call the driver-specific transmit routine. 374c0b746e5SOllivier Robert */ 375c0b746e5SOllivier Robert if (peer->burst == 0) { 376c0b746e5SOllivier Robert u_char oreach; 377c0b746e5SOllivier Robert #ifdef DEBUG 378c0b746e5SOllivier Robert if (debug) 379c0b746e5SOllivier Robert printf("refclock_transmit: at %ld %s\n", 3809c2daa00SOllivier Robert current_time, stoa(&(peer->srcadr))); 381c0b746e5SOllivier Robert #endif 382c0b746e5SOllivier Robert 383c0b746e5SOllivier Robert /* 384c0b746e5SOllivier Robert * Update reachability and poll variables like the 385c0b746e5SOllivier Robert * network code. 386c0b746e5SOllivier Robert */ 3872b15cb3dSCy Schubert oreach = peer->reach & 0xfe; 388c0b746e5SOllivier Robert peer->reach <<= 1; 3892b15cb3dSCy Schubert if (!(peer->reach & 0x0f)) 3902b15cb3dSCy Schubert clock_filter(peer, 0., 0., MAXDISPERSE); 391ea906c41SOllivier Robert peer->outdate = current_time; 392224ba2bdSOllivier Robert if (!peer->reach) { 393224ba2bdSOllivier Robert if (oreach) { 3942b15cb3dSCy Schubert report_event(PEVNT_UNREACH, peer, NULL); 395c0b746e5SOllivier Robert peer->timereachable = current_time; 396c0b746e5SOllivier Robert } 397c0b746e5SOllivier Robert } else { 398c0b746e5SOllivier Robert if (peer->flags & FLAG_BURST) 399c0b746e5SOllivier Robert peer->burst = NSTAGE; 400c0b746e5SOllivier Robert } 401ea906c41SOllivier Robert } else { 402ea906c41SOllivier Robert peer->burst--; 403c0b746e5SOllivier Robert } 4042d4e511cSCy Schubert peer->procptr->inpoll = TRUE; 405c0b746e5SOllivier Robert if (refclock_conf[clktype]->clock_poll != noentry) 406c0b746e5SOllivier Robert (refclock_conf[clktype]->clock_poll)(unit, peer); 4072d4e511cSCy Schubert poll_update(peer, peer->hpoll, 0); 408c0b746e5SOllivier Robert } 409c0b746e5SOllivier Robert 410c0b746e5SOllivier Robert 411c0b746e5SOllivier Robert /* 412c0b746e5SOllivier Robert * Compare two doubles - used with qsort() 413c0b746e5SOllivier Robert */ 414c0b746e5SOllivier Robert static int 415c0b746e5SOllivier Robert refclock_cmpl_fp( 416c0b746e5SOllivier Robert const void *p1, 417c0b746e5SOllivier Robert const void *p2 418c0b746e5SOllivier Robert ) 419c0b746e5SOllivier Robert { 420c0b746e5SOllivier Robert const double *dp1 = (const double *)p1; 421c0b746e5SOllivier Robert const double *dp2 = (const double *)p2; 422c0b746e5SOllivier Robert 423c0b746e5SOllivier Robert if (*dp1 < *dp2) 4242b15cb3dSCy Schubert return -1; 425c0b746e5SOllivier Robert if (*dp1 > *dp2) 4262b15cb3dSCy Schubert return 1; 4272b15cb3dSCy Schubert return 0; 428c0b746e5SOllivier Robert } 429ea906c41SOllivier Robert 4302d4e511cSCy Schubert /* 4312d4e511cSCy Schubert * Get number of available samples 4322d4e511cSCy Schubert */ 4332d4e511cSCy Schubert int 4342d4e511cSCy Schubert refclock_samples_avail( 4352d4e511cSCy Schubert struct refclockproc const * pp 4362d4e511cSCy Schubert ) 4372d4e511cSCy Schubert { 4382d4e511cSCy Schubert u_int na; 4392d4e511cSCy Schubert 4402d4e511cSCy Schubert # if MAXSTAGE & (MAXSTAGE - 1) 4412d4e511cSCy Schubert 4422d4e511cSCy Schubert na = pp->coderecv - pp->codeproc; 4432d4e511cSCy Schubert if (na > MAXSTAGE) 4442d4e511cSCy Schubert na += MAXSTAGE; 4452d4e511cSCy Schubert 4462d4e511cSCy Schubert # else 4472d4e511cSCy Schubert 4482d4e511cSCy Schubert na = (pp->coderecv - pp->codeproc) & (MAXSTAGE - 1); 4492d4e511cSCy Schubert 4502d4e511cSCy Schubert # endif 4512d4e511cSCy Schubert return na; 4522d4e511cSCy Schubert } 4532d4e511cSCy Schubert 4542d4e511cSCy Schubert /* 4552d4e511cSCy Schubert * Expire (remove) samples from the tail (oldest samples removed) 4562d4e511cSCy Schubert * 4572d4e511cSCy Schubert * Returns number of samples deleted 4582d4e511cSCy Schubert */ 4592d4e511cSCy Schubert int 4602d4e511cSCy Schubert refclock_samples_expire( 4612d4e511cSCy Schubert struct refclockproc * pp, 4622d4e511cSCy Schubert int nd 4632d4e511cSCy Schubert ) 4642d4e511cSCy Schubert { 4652d4e511cSCy Schubert u_int na; 4662d4e511cSCy Schubert 4672d4e511cSCy Schubert if (nd <= 0) 4682d4e511cSCy Schubert return 0; 4692d4e511cSCy Schubert 4702d4e511cSCy Schubert # if MAXSTAGE & (MAXSTAGE - 1) 4712d4e511cSCy Schubert 4722d4e511cSCy Schubert na = pp->coderecv - pp->codeproc; 4732d4e511cSCy Schubert if (na > MAXSTAGE) 4742d4e511cSCy Schubert na += MAXSTAGE; 4752d4e511cSCy Schubert if ((u_int)nd < na) 4762d4e511cSCy Schubert nd = na; 4772d4e511cSCy Schubert pp->codeproc = (pp->codeproc + nd) % MAXSTAGE; 4782d4e511cSCy Schubert 4792d4e511cSCy Schubert # else 4802d4e511cSCy Schubert 4812d4e511cSCy Schubert na = (pp->coderecv - pp->codeproc) & (MAXSTAGE - 1); 4822d4e511cSCy Schubert if ((u_int)nd > na) 4832d4e511cSCy Schubert nd = (int)na; 4842d4e511cSCy Schubert pp->codeproc = (pp->codeproc + nd) & (MAXSTAGE - 1); 4852d4e511cSCy Schubert 4862d4e511cSCy Schubert # endif 4872d4e511cSCy Schubert return nd; 4882d4e511cSCy Schubert } 489c0b746e5SOllivier Robert 490c0b746e5SOllivier Robert /* 491c0b746e5SOllivier Robert * refclock_process_offset - update median filter 492c0b746e5SOllivier Robert * 493224ba2bdSOllivier Robert * This routine uses the given offset and timestamps to construct a new 494224ba2bdSOllivier Robert * entry in the median filter circular buffer. Samples that overflow the 495224ba2bdSOllivier Robert * filter are quietly discarded. 496c0b746e5SOllivier Robert */ 497c0b746e5SOllivier Robert void 498c0b746e5SOllivier Robert refclock_process_offset( 4999c2daa00SOllivier Robert struct refclockproc *pp, /* refclock structure pointer */ 5009c2daa00SOllivier Robert l_fp lasttim, /* last timecode timestamp */ 5019c2daa00SOllivier Robert l_fp lastrec, /* last receive timestamp */ 502c0b746e5SOllivier Robert double fudge 503c0b746e5SOllivier Robert ) 504c0b746e5SOllivier Robert { 5059c2daa00SOllivier Robert l_fp lftemp; 506c0b746e5SOllivier Robert double doffset; 507c0b746e5SOllivier Robert 508c0b746e5SOllivier Robert pp->lastrec = lastrec; 5099c2daa00SOllivier Robert lftemp = lasttim; 5109c2daa00SOllivier Robert L_SUB(&lftemp, &lastrec); 5119c2daa00SOllivier Robert LFPTOD(&lftemp, doffset); 5122d4e511cSCy Schubert clk_add_sample(pp, doffset + fudge); 5132d4e511cSCy Schubert refclock_checkburst(pp->io.srcclock, pp); 514c0b746e5SOllivier Robert } 515c0b746e5SOllivier Robert 516ea906c41SOllivier Robert 517c0b746e5SOllivier Robert /* 518c0b746e5SOllivier Robert * refclock_process - process a sample from the clock 5192b15cb3dSCy Schubert * refclock_process_f - refclock_process with other than time1 fudge 520c0b746e5SOllivier Robert * 521c0b746e5SOllivier Robert * This routine converts the timecode in the form days, hours, minutes, 522c0b746e5SOllivier Robert * seconds and milliseconds/microseconds to internal timestamp format, 523c0b746e5SOllivier Robert * then constructs a new entry in the median filter circular buffer. 524c0b746e5SOllivier Robert * Return success (1) if the data are correct and consistent with the 5252d4e511cSCy Schubert * conventional calendar. 526ea906c41SOllivier Robert * 527ea906c41SOllivier Robert * Important for PPS users: Normally, the pp->lastrec is set to the 528ea906c41SOllivier Robert * system time when the on-time character is received and the pp->year, 529ea906c41SOllivier Robert * ..., pp->second decoded and the seconds fraction pp->nsec in 530ea906c41SOllivier Robert * nanoseconds). When a PPS offset is available, pp->nsec is forced to 531ea906c41SOllivier Robert * zero and the fraction for pp->lastrec is set to the PPS offset. 532c0b746e5SOllivier Robert */ 533c0b746e5SOllivier Robert int 5342b15cb3dSCy Schubert refclock_process_f( 5352b15cb3dSCy Schubert struct refclockproc *pp, /* refclock structure pointer */ 5362b15cb3dSCy Schubert double fudge 537c0b746e5SOllivier Robert ) 538c0b746e5SOllivier Robert { 5399c2daa00SOllivier Robert l_fp offset, ltemp; 540c0b746e5SOllivier Robert 541c0b746e5SOllivier Robert /* 542c0b746e5SOllivier Robert * Compute the timecode timestamp from the days, hours, minutes, 543c0b746e5SOllivier Robert * seconds and milliseconds/microseconds of the timecode. Use 544c0b746e5SOllivier Robert * clocktime() for the aggregate seconds and the msec/usec for 545c0b746e5SOllivier Robert * the fraction, when present. Note that this code relies on the 546c0b746e5SOllivier Robert * file system time for the years and does not use the years of 547c0b746e5SOllivier Robert * the timecode. 548c0b746e5SOllivier Robert */ 549c0b746e5SOllivier Robert if (!clocktime(pp->day, pp->hour, pp->minute, pp->second, GMT, 550c0b746e5SOllivier Robert pp->lastrec.l_ui, &pp->yearstart, &offset.l_ui)) 551c0b746e5SOllivier Robert return (0); 552ea906c41SOllivier Robert 5539c2daa00SOllivier Robert offset.l_uf = 0; 5549c2daa00SOllivier Robert DTOLFP(pp->nsec / 1e9, <emp); 5559c2daa00SOllivier Robert L_ADD(&offset, <emp); 5562b15cb3dSCy Schubert refclock_process_offset(pp, offset, pp->lastrec, fudge); 557c0b746e5SOllivier Robert return (1); 558c0b746e5SOllivier Robert } 559c0b746e5SOllivier Robert 560ea906c41SOllivier Robert 5612b15cb3dSCy Schubert int 5622b15cb3dSCy Schubert refclock_process( 5632b15cb3dSCy Schubert struct refclockproc *pp /* refclock structure pointer */ 5642b15cb3dSCy Schubert ) 5652b15cb3dSCy Schubert { 5662b15cb3dSCy Schubert return refclock_process_f(pp, pp->fudgetime1); 5672b15cb3dSCy Schubert } 5682b15cb3dSCy Schubert 5692b15cb3dSCy Schubert 570c0b746e5SOllivier Robert /* 571c0b746e5SOllivier Robert * refclock_sample - process a pile of samples from the clock 572c0b746e5SOllivier Robert * 573c0b746e5SOllivier Robert * This routine implements a recursive median filter to suppress spikes 574c0b746e5SOllivier Robert * in the data, as well as determine a performance statistic. It 575ea906c41SOllivier Robert * calculates the mean offset and RMS jitter. A time adjustment 576224ba2bdSOllivier Robert * fudgetime1 can be added to the final offset to compensate for various 577224ba2bdSOllivier Robert * systematic errors. The routine returns the number of samples 578224ba2bdSOllivier Robert * processed, which could be zero. 579c0b746e5SOllivier Robert */ 580c0b746e5SOllivier Robert static int 581c0b746e5SOllivier Robert refclock_sample( 5829c2daa00SOllivier Robert struct refclockproc *pp /* refclock structure pointer */ 583c0b746e5SOllivier Robert ) 584c0b746e5SOllivier Robert { 5852b15cb3dSCy Schubert size_t i, j, k, m, n; 586c0b746e5SOllivier Robert double off[MAXSTAGE]; 587c0b746e5SOllivier Robert 588c0b746e5SOllivier Robert /* 589c0b746e5SOllivier Robert * Copy the raw offsets and sort into ascending order. Don't do 590c0b746e5SOllivier Robert * anything if the buffer is empty. 591c0b746e5SOllivier Robert */ 592c0b746e5SOllivier Robert n = 0; 5932d4e511cSCy Schubert while (pp->codeproc != pp->coderecv) 5942d4e511cSCy Schubert off[n++] = clk_pop_sample(pp); 5959c2daa00SOllivier Robert if (n == 0) 5969c2daa00SOllivier Robert return (0); 597ea906c41SOllivier Robert 598c0b746e5SOllivier Robert if (n > 1) 5992b15cb3dSCy Schubert qsort(off, n, sizeof(off[0]), refclock_cmpl_fp); 600c0b746e5SOllivier Robert 601c0b746e5SOllivier Robert /* 602c0b746e5SOllivier Robert * Reject the furthest from the median of the samples until 603c0b746e5SOllivier Robert * approximately 60 percent of the samples remain. 604a466cc55SCy Schubert * 605a466cc55SCy Schubert * [Bug 3672] The elimination is now based on the proper 606a466cc55SCy Schubert * definition of the median. The true median is not calculated 607a466cc55SCy Schubert * directly, though. 608c0b746e5SOllivier Robert */ 609c0b746e5SOllivier Robert i = 0; j = n; 610ea906c41SOllivier Robert m = n - (n * 4) / 10; 611a466cc55SCy Schubert while ((k = j - i) > m) { 612a466cc55SCy Schubert k = (k - 1) >> 1; 613a466cc55SCy Schubert if ((off[j - 1] - off[j - k - 1]) < (off[i + k] - off[i])) 614c0b746e5SOllivier Robert i++; /* reject low end */ 615c0b746e5SOllivier Robert else 616c0b746e5SOllivier Robert j--; /* reject high end */ 617c0b746e5SOllivier Robert } 618c0b746e5SOllivier Robert 619c0b746e5SOllivier Robert /* 620224ba2bdSOllivier Robert * Determine the offset and jitter. 621c0b746e5SOllivier Robert */ 622767173ceSCy Schubert pp->offset = off[i]; 623224ba2bdSOllivier Robert pp->jitter = 0; 624767173ceSCy Schubert for (k = i + 1; k < j; k++) { 625ea906c41SOllivier Robert pp->offset += off[k]; 626ea906c41SOllivier Robert pp->jitter += SQUARE(off[k] - off[k - 1]); 627ea906c41SOllivier Robert } 628ea906c41SOllivier Robert pp->offset /= m; 629767173ceSCy Schubert m -= (m > 1); /* only (m-1) terms attribute to jitter! */ 630ea906c41SOllivier Robert pp->jitter = max(SQRT(pp->jitter / m), LOGTOD(sys_precision)); 6312d4e511cSCy Schubert 6322d4e511cSCy Schubert /* 6332d4e511cSCy Schubert * If the source has a jitter that cannot be estimated, because 6342d4e511cSCy Schubert * it is not statistic jitter, the source will be detected as 6352d4e511cSCy Schubert * falseticker sooner or later. Enforcing a minimal jitter value 6362d4e511cSCy Schubert * avoids a too low estimation while still detecting higher jitter. 6372d4e511cSCy Schubert * 6382d4e511cSCy Schubert * Note that this changes the refclock samples and ends up in the 6392d4e511cSCy Schubert * clock dispersion, not the clock jitter, despite being called 6402d4e511cSCy Schubert * jitter. To see the modified values, check the NTP clock variable 6412d4e511cSCy Schubert * "filtdisp", not "jitter". 6422d4e511cSCy Schubert */ 6432d4e511cSCy Schubert pp->jitter = max(pp->jitter, pp->fudgeminjitter); 6442d4e511cSCy Schubert 645c0b746e5SOllivier Robert #ifdef DEBUG 646c0b746e5SOllivier Robert if (debug) 647c0b746e5SOllivier Robert printf( 648224ba2bdSOllivier Robert "refclock_sample: n %d offset %.6f disp %.6f jitter %.6f\n", 6492b15cb3dSCy Schubert (int)n, pp->offset, pp->disp, pp->jitter); 650c0b746e5SOllivier Robert #endif 6512b15cb3dSCy Schubert return (int)n; 652c0b746e5SOllivier Robert } 653c0b746e5SOllivier Robert 654c0b746e5SOllivier Robert 655c0b746e5SOllivier Robert /* 656c0b746e5SOllivier Robert * refclock_receive - simulate the receive and packet procedures 657c0b746e5SOllivier Robert * 658c0b746e5SOllivier Robert * This routine simulates the NTP receive and packet procedures for a 659c0b746e5SOllivier Robert * reference clock. This provides a mechanism in which the ordinary NTP 660c0b746e5SOllivier Robert * filter, selection and combining algorithms can be used to suppress 661c0b746e5SOllivier Robert * misbehaving radios and to mitigate between them when more than one is 662c0b746e5SOllivier Robert * available for backup. 663c0b746e5SOllivier Robert */ 664c0b746e5SOllivier Robert void 665c0b746e5SOllivier Robert refclock_receive( 666c0b746e5SOllivier Robert struct peer *peer /* peer structure pointer */ 667c0b746e5SOllivier Robert ) 668c0b746e5SOllivier Robert { 669c0b746e5SOllivier Robert struct refclockproc *pp; 670c0b746e5SOllivier Robert 671c0b746e5SOllivier Robert #ifdef DEBUG 672c0b746e5SOllivier Robert if (debug) 673c0b746e5SOllivier Robert printf("refclock_receive: at %lu %s\n", 6749c2daa00SOllivier Robert current_time, stoa(&peer->srcadr)); 675c0b746e5SOllivier Robert #endif 676c0b746e5SOllivier Robert 677c0b746e5SOllivier Robert /* 678c0b746e5SOllivier Robert * Do a little sanity dance and update the peer structure. Groom 679c0b746e5SOllivier Robert * the median filter samples and give the data to the clock 680c0b746e5SOllivier Robert * filter. 681c0b746e5SOllivier Robert */ 682c0b746e5SOllivier Robert pp = peer->procptr; 6832d4e511cSCy Schubert pp->inpoll = FALSE; 684c0b746e5SOllivier Robert peer->leap = pp->leap; 685ea906c41SOllivier Robert if (peer->leap == LEAP_NOTINSYNC) 686c0b746e5SOllivier Robert return; 687ea906c41SOllivier Robert 688ea906c41SOllivier Robert peer->received++; 689ea906c41SOllivier Robert peer->timereceived = current_time; 690ea906c41SOllivier Robert if (!peer->reach) { 6912b15cb3dSCy Schubert report_event(PEVNT_REACH, peer, NULL); 692ea906c41SOllivier Robert peer->timereachable = current_time; 693ea906c41SOllivier Robert } 6942d4e511cSCy Schubert peer->reach = (peer->reach << (peer->reach & 1)) | 1; 6959c2daa00SOllivier Robert peer->reftime = pp->lastref; 6962b15cb3dSCy Schubert peer->aorg = pp->lastrec; 6972b15cb3dSCy Schubert peer->rootdisp = pp->disp; 6982b15cb3dSCy Schubert get_systime(&peer->dst); 699c0b746e5SOllivier Robert if (!refclock_sample(pp)) 700c0b746e5SOllivier Robert return; 701ea906c41SOllivier Robert 702224ba2bdSOllivier Robert clock_filter(peer, pp->offset, 0., pp->jitter); 7032b15cb3dSCy Schubert if (cal_enable && fabs(last_offset) < sys_mindisp && sys_peer != 7042b15cb3dSCy Schubert NULL) { 7052b15cb3dSCy Schubert if (sys_peer->refclktype == REFCLK_ATOM_PPS && 7062b15cb3dSCy Schubert peer->refclktype != REFCLK_ATOM_PPS) 707c0b746e5SOllivier Robert pp->fudgetime1 -= pp->offset * FUDGEFAC; 708224ba2bdSOllivier Robert } 709c0b746e5SOllivier Robert } 710c0b746e5SOllivier Robert 711ea906c41SOllivier Robert 712c0b746e5SOllivier Robert /* 713c0b746e5SOllivier Robert * refclock_gtlin - groom next input line and extract timestamp 714c0b746e5SOllivier Robert * 715c0b746e5SOllivier Robert * This routine processes the timecode received from the clock and 716ea906c41SOllivier Robert * strips the parity bit and control characters. It returns the number 717ea906c41SOllivier Robert * of characters in the line followed by a NULL character ('\0'), which 718ea906c41SOllivier Robert * is not included in the count. In case of an empty line, the previous 719ea906c41SOllivier Robert * line is preserved. 720c0b746e5SOllivier Robert */ 721c0b746e5SOllivier Robert int 722c0b746e5SOllivier Robert refclock_gtlin( 723c0b746e5SOllivier Robert struct recvbuf *rbufp, /* receive buffer pointer */ 724c0b746e5SOllivier Robert char *lineptr, /* current line pointer */ 725c0b746e5SOllivier Robert int bmax, /* remaining characters in line */ 726c0b746e5SOllivier Robert l_fp *tsptr /* pointer to timestamp returned */ 727c0b746e5SOllivier Robert ) 728c0b746e5SOllivier Robert { 7292b15cb3dSCy Schubert const char *sp, *spend; 7302b15cb3dSCy Schubert char *dp, *dpend; 7312b15cb3dSCy Schubert int dlen; 732ea906c41SOllivier Robert 7332b15cb3dSCy Schubert if (bmax <= 0) 7342b15cb3dSCy Schubert return (0); 7352b15cb3dSCy Schubert 7362b15cb3dSCy Schubert dp = lineptr; 7372b15cb3dSCy Schubert dpend = dp + bmax - 1; /* leave room for NUL pad */ 7382b15cb3dSCy Schubert sp = (const char *)rbufp->recv_buffer; 7392b15cb3dSCy Schubert spend = sp + rbufp->recv_length; 7402b15cb3dSCy Schubert 7412b15cb3dSCy Schubert while (sp != spend && dp != dpend) { 742c0b746e5SOllivier Robert char c; 743c0b746e5SOllivier Robert 7442b15cb3dSCy Schubert c = *sp++ & 0x7f; 745ea906c41SOllivier Robert if (c >= 0x20 && c < 0x7f) 746ea906c41SOllivier Robert *dp++ = c; 747ea906c41SOllivier Robert } 7482b15cb3dSCy Schubert /* Get length of data written to the destination buffer. If 7492b15cb3dSCy Schubert * zero, do *not* place a NUL byte to preserve the previous 7502b15cb3dSCy Schubert * buffer content. 7512b15cb3dSCy Schubert */ 7522b15cb3dSCy Schubert dlen = dp - lineptr; 7532b15cb3dSCy Schubert if (dlen) 754ea906c41SOllivier Robert *dp = '\0'; 7552b15cb3dSCy Schubert *tsptr = rbufp->recv_time; 7562b15cb3dSCy Schubert DPRINTF(2, ("refclock_gtlin: fd %d time %s timecode %d %s\n", 7572b15cb3dSCy Schubert rbufp->fd, ulfptoa(&rbufp->recv_time, 6), dlen, 7582b15cb3dSCy Schubert (dlen != 0) 7592b15cb3dSCy Schubert ? lineptr 7602b15cb3dSCy Schubert : "")); 7612b15cb3dSCy Schubert return (dlen); 762ea906c41SOllivier Robert } 763ea906c41SOllivier Robert 764ea906c41SOllivier Robert 765ea906c41SOllivier Robert /* 766ea906c41SOllivier Robert * refclock_gtraw - get next line/chunk of data 767ea906c41SOllivier Robert * 768ea906c41SOllivier Robert * This routine returns the raw data received from the clock in both 769ea906c41SOllivier Robert * canonical or raw modes. The terminal interface routines map CR to LF. 770ea906c41SOllivier Robert * In canonical mode this results in two lines, one containing data 771ea906c41SOllivier Robert * followed by LF and another containing only LF. In raw mode the 772ea906c41SOllivier Robert * interface routines can deliver arbitraty chunks of data from one 773ea906c41SOllivier Robert * character to a maximum specified by the calling routine. In either 774ea906c41SOllivier Robert * mode the routine returns the number of characters in the line 775ea906c41SOllivier Robert * followed by a NULL character ('\0'), which is not included in the 776ea906c41SOllivier Robert * count. 777ea906c41SOllivier Robert * 7782b15cb3dSCy Schubert * *tsptr receives a copy of the buffer timestamp. 779ea906c41SOllivier Robert */ 780ea906c41SOllivier Robert int 781ea906c41SOllivier Robert refclock_gtraw( 782ea906c41SOllivier Robert struct recvbuf *rbufp, /* receive buffer pointer */ 783ea906c41SOllivier Robert char *lineptr, /* current line pointer */ 784ea906c41SOllivier Robert int bmax, /* remaining characters in line */ 785ea906c41SOllivier Robert l_fp *tsptr /* pointer to timestamp returned */ 786ea906c41SOllivier Robert ) 787ea906c41SOllivier Robert { 7882b15cb3dSCy Schubert if (bmax <= 0) 7892b15cb3dSCy Schubert return (0); 7902b15cb3dSCy Schubert bmax -= 1; /* leave room for trailing NUL */ 7912b15cb3dSCy Schubert if (bmax > rbufp->recv_length) 7922b15cb3dSCy Schubert bmax = rbufp->recv_length; 7932b15cb3dSCy Schubert memcpy(lineptr, rbufp->recv_buffer, bmax); 7942b15cb3dSCy Schubert lineptr[bmax] = '\0'; 795ea906c41SOllivier Robert 7962b15cb3dSCy Schubert *tsptr = rbufp->recv_time; 7972b15cb3dSCy Schubert DPRINTF(2, ("refclock_gtraw: fd %d time %s timecode %d %s\n", 7982b15cb3dSCy Schubert rbufp->fd, ulfptoa(&rbufp->recv_time, 6), bmax, 7992b15cb3dSCy Schubert lineptr)); 8002b15cb3dSCy Schubert return (bmax); 801c0b746e5SOllivier Robert } 802c0b746e5SOllivier Robert 803a466cc55SCy Schubert /* 804a466cc55SCy Schubert * refclock_fdwrite() 805a466cc55SCy Schubert * 806a466cc55SCy Schubert * Write data to a clock device. Does the necessary result checks and 807a466cc55SCy Schubert * logging, and encapsulates OS dependencies. 808a466cc55SCy Schubert */ 809a466cc55SCy Schubert #ifdef SYS_WINNT 810a466cc55SCy Schubert extern int async_write(int fd, const void * buf, unsigned int len); 811a466cc55SCy Schubert #endif 812a466cc55SCy Schubert 813a466cc55SCy Schubert size_t 814a466cc55SCy Schubert refclock_fdwrite( 815a466cc55SCy Schubert const struct peer * peer, 816a466cc55SCy Schubert int fd, 817a466cc55SCy Schubert const void * buf, 818a466cc55SCy Schubert size_t len, 819a466cc55SCy Schubert const char * what 820a466cc55SCy Schubert ) 821a466cc55SCy Schubert { 822a466cc55SCy Schubert size_t nret, nout; 823a466cc55SCy Schubert int nerr; 824a466cc55SCy Schubert 825a466cc55SCy Schubert nout = (INT_MAX > len) ? len : INT_MAX; 826a466cc55SCy Schubert # ifdef SYS_WINNT 827a466cc55SCy Schubert nret = (size_t)async_write(fd, buf, (unsigned int)nout); 828a466cc55SCy Schubert # else 829a466cc55SCy Schubert nret = (size_t)write(fd, buf, nout); 830a466cc55SCy Schubert # endif 831a466cc55SCy Schubert if (NULL != what) { 832a466cc55SCy Schubert if (nret == FDWRITE_ERROR) { 833a466cc55SCy Schubert nerr = errno; 834a466cc55SCy Schubert msyslog(LOG_INFO, 835a466cc55SCy Schubert "%s: write %s failed, fd=%d, %m", 836a466cc55SCy Schubert refnumtoa(&peer->srcadr), what, 837a466cc55SCy Schubert fd); 838a466cc55SCy Schubert errno = nerr; 839a466cc55SCy Schubert } else if (nret != len) { 840a466cc55SCy Schubert nerr = errno; 841a466cc55SCy Schubert msyslog(LOG_NOTICE, 842*f5f40dd6SCy Schubert "%s: %s shortened, fd=%d, wrote %u of %u bytes", 843a466cc55SCy Schubert refnumtoa(&peer->srcadr), what, 844*f5f40dd6SCy Schubert fd, (u_int)nret, (u_int)len); 845a466cc55SCy Schubert errno = nerr; 846a466cc55SCy Schubert } 847a466cc55SCy Schubert } 848a466cc55SCy Schubert return nret; 849a466cc55SCy Schubert } 850a466cc55SCy Schubert 851a466cc55SCy Schubert size_t 852a466cc55SCy Schubert refclock_write( 853a466cc55SCy Schubert const struct peer * peer, 854a466cc55SCy Schubert const void * buf, 855a466cc55SCy Schubert size_t len, 856a466cc55SCy Schubert const char * what 857a466cc55SCy Schubert ) 858a466cc55SCy Schubert { 859a466cc55SCy Schubert if ( ! (peer && peer->procptr)) { 860a466cc55SCy Schubert if (NULL != what) 861a466cc55SCy Schubert msyslog(LOG_INFO, 862a466cc55SCy Schubert "%s: write %s failed, invalid clock peer", 863a466cc55SCy Schubert refnumtoa(&peer->srcadr), what); 864a466cc55SCy Schubert errno = EINVAL; 865a466cc55SCy Schubert return FDWRITE_ERROR; 866a466cc55SCy Schubert } 867a466cc55SCy Schubert return refclock_fdwrite(peer, peer->procptr->io.fd, 868a466cc55SCy Schubert buf, len, what); 869a466cc55SCy Schubert } 8702b15cb3dSCy Schubert 871c0b746e5SOllivier Robert /* 8722b15cb3dSCy Schubert * indicate_refclock_packet() 8732b15cb3dSCy Schubert * 8742b15cb3dSCy Schubert * Passes a fragment of refclock input read from the device to the 8752b15cb3dSCy Schubert * driver direct input routine, which may consume it (batch it for 8762b15cb3dSCy Schubert * queuing once a logical unit is assembled). If it is not so 8772b15cb3dSCy Schubert * consumed, queue it for the driver's receive entrypoint. 8782b15cb3dSCy Schubert * 8792b15cb3dSCy Schubert * The return value is TRUE if the data has been consumed as a fragment 8802b15cb3dSCy Schubert * and should not be counted as a received packet. 881c0b746e5SOllivier Robert */ 8822b15cb3dSCy Schubert int 8832b15cb3dSCy Schubert indicate_refclock_packet( 8842b15cb3dSCy Schubert struct refclockio * rio, 8852b15cb3dSCy Schubert struct recvbuf * rb 8862b15cb3dSCy Schubert ) 8872b15cb3dSCy Schubert { 8882b15cb3dSCy Schubert /* Does this refclock use direct input routine? */ 8892b15cb3dSCy Schubert if (rio->io_input != NULL && (*rio->io_input)(rb) == 0) { 8902b15cb3dSCy Schubert /* 8912b15cb3dSCy Schubert * data was consumed - nothing to pass up 8922b15cb3dSCy Schubert * into block input machine 8932b15cb3dSCy Schubert */ 8942b15cb3dSCy Schubert freerecvbuf(rb); 8952b15cb3dSCy Schubert 8962b15cb3dSCy Schubert return TRUE; 897c0b746e5SOllivier Robert } 8982b15cb3dSCy Schubert add_full_recv_buffer(rb); 8992b15cb3dSCy Schubert 9002b15cb3dSCy Schubert return FALSE; 9012b15cb3dSCy Schubert } 9022b15cb3dSCy Schubert 9032b15cb3dSCy Schubert 9042b15cb3dSCy Schubert /* 9052b15cb3dSCy Schubert * process_refclock_packet() 9062b15cb3dSCy Schubert * 9072b15cb3dSCy Schubert * Used for deferred processing of 'io_input' on systems where threading 9082b15cb3dSCy Schubert * is used (notably Windows). This is acting as a trampoline to make the 9092b15cb3dSCy Schubert * real calls to the refclock functions. 9102b15cb3dSCy Schubert */ 9112b15cb3dSCy Schubert #ifdef HAVE_IO_COMPLETION_PORT 9122b15cb3dSCy Schubert void 9132b15cb3dSCy Schubert process_refclock_packet( 9142b15cb3dSCy Schubert struct recvbuf * rb 9152b15cb3dSCy Schubert ) 9162b15cb3dSCy Schubert { 9172b15cb3dSCy Schubert struct refclockio * rio; 9182b15cb3dSCy Schubert 9192b15cb3dSCy Schubert /* get the refclockio structure from the receive buffer */ 9202b15cb3dSCy Schubert rio = &rb->recv_peer->procptr->io; 9212b15cb3dSCy Schubert 9222b15cb3dSCy Schubert /* call 'clock_recv' if either there is no input function or the 9232b15cb3dSCy Schubert * raw input function tells us to feed the packet to the 9242b15cb3dSCy Schubert * receiver. 9252b15cb3dSCy Schubert */ 9262b15cb3dSCy Schubert if (rio->io_input == NULL || (*rio->io_input)(rb) != 0) { 9272b15cb3dSCy Schubert rio->recvcount++; 9282b15cb3dSCy Schubert packets_received++; 9292b15cb3dSCy Schubert handler_pkts++; 9302b15cb3dSCy Schubert (*rio->clock_recv)(rb); 9312b15cb3dSCy Schubert } 9322b15cb3dSCy Schubert } 9332b15cb3dSCy Schubert #endif /* HAVE_IO_COMPLETION_PORT */ 934c0b746e5SOllivier Robert 935ea906c41SOllivier Robert 936c0b746e5SOllivier Robert /* 937c0b746e5SOllivier Robert * The following code does not apply to WINNT & VMS ... 938c0b746e5SOllivier Robert */ 9392b15cb3dSCy Schubert #if !defined(SYS_VXWORKS) && !defined(SYS_WINNT) 940c0b746e5SOllivier Robert #if defined(HAVE_TERMIOS) || defined(HAVE_SYSV_TTYS) || defined(HAVE_BSD_TTYS) 941c0b746e5SOllivier Robert 942c0b746e5SOllivier Robert /* 943c0b746e5SOllivier Robert * refclock_open - open serial port for reference clock 944c0b746e5SOllivier Robert * 945c0b746e5SOllivier Robert * This routine opens a serial port for I/O and sets default options. It 9462b15cb3dSCy Schubert * returns the file descriptor if successful, or logs an error and 9472b15cb3dSCy Schubert * returns -1. 948c0b746e5SOllivier Robert */ 949c0b746e5SOllivier Robert int 950c0b746e5SOllivier Robert refclock_open( 951a466cc55SCy Schubert const sockaddr_u *srcadr, 9523311ff84SXin LI const char *dev, /* device name pointer */ 953ea906c41SOllivier Robert u_int speed, /* serial port speed (code) */ 954ea906c41SOllivier Robert u_int lflags /* line discipline flags */ 955c0b746e5SOllivier Robert ) 956c0b746e5SOllivier Robert { 957a466cc55SCy Schubert const char *cdev; 958ea906c41SOllivier Robert int fd; 959224ba2bdSOllivier Robert int omode; 9602b15cb3dSCy Schubert #ifdef O_NONBLOCK 9612b15cb3dSCy Schubert char trash[128]; /* litter bin for old input data */ 9622b15cb3dSCy Schubert #endif 963c0b746e5SOllivier Robert 964c0b746e5SOllivier Robert /* 965c0b746e5SOllivier Robert * Open serial port and set default options 966c0b746e5SOllivier Robert */ 967224ba2bdSOllivier Robert omode = O_RDWR; 968c0b746e5SOllivier Robert #ifdef O_NONBLOCK 969224ba2bdSOllivier Robert omode |= O_NONBLOCK; 970224ba2bdSOllivier Robert #endif 971224ba2bdSOllivier Robert #ifdef O_NOCTTY 972224ba2bdSOllivier Robert omode |= O_NOCTTY; 973224ba2bdSOllivier Robert #endif 974224ba2bdSOllivier Robert 975a466cc55SCy Schubert if (NULL != (cdev = clockdev_lookup(srcadr, 0))) 976a466cc55SCy Schubert dev = cdev; 977a466cc55SCy Schubert 978224ba2bdSOllivier Robert fd = open(dev, omode, 0777); 9792b15cb3dSCy Schubert /* refclock_open() long returned 0 on failure, avoid it. */ 9802b15cb3dSCy Schubert if (0 == fd) { 9812b15cb3dSCy Schubert fd = dup(0); 9822b15cb3dSCy Schubert SAVE_ERRNO( 9832b15cb3dSCy Schubert close(0); 9842b15cb3dSCy Schubert ) 9852b15cb3dSCy Schubert } 986224ba2bdSOllivier Robert if (fd < 0) { 9872b15cb3dSCy Schubert SAVE_ERRNO( 988ea906c41SOllivier Robert msyslog(LOG_ERR, "refclock_open %s: %m", dev); 9892b15cb3dSCy Schubert ) 9902b15cb3dSCy Schubert return -1; 991c0b746e5SOllivier Robert } 992ea906c41SOllivier Robert if (!refclock_setup(fd, speed, lflags)) { 993ea906c41SOllivier Robert close(fd); 9942b15cb3dSCy Schubert return -1; 995ea906c41SOllivier Robert } 996ea906c41SOllivier Robert if (!refclock_ioctl(fd, lflags)) { 997ea906c41SOllivier Robert close(fd); 9982b15cb3dSCy Schubert return -1; 999ea906c41SOllivier Robert } 1000a466cc55SCy Schubert msyslog(LOG_NOTICE, "%s serial %s open at %d bps", 1001a466cc55SCy Schubert refnumtoa(srcadr), dev, symBaud2numBaud(speed)); 1002a466cc55SCy Schubert 10032b15cb3dSCy Schubert #ifdef O_NONBLOCK 10042b15cb3dSCy Schubert /* 10052b15cb3dSCy Schubert * We want to make sure there is no pending trash in the input 10062b15cb3dSCy Schubert * buffer. Since we have non-blocking IO available, this is a 10072b15cb3dSCy Schubert * good moment to read and dump all available outdated stuff 10082b15cb3dSCy Schubert * that might have become toxic for the driver. 10092b15cb3dSCy Schubert */ 10102b15cb3dSCy Schubert while (read(fd, trash, sizeof(trash)) > 0 || errno == EINTR) 10112b15cb3dSCy Schubert /*NOP*/; 10122b15cb3dSCy Schubert #endif 10132b15cb3dSCy Schubert return fd; 1014ea906c41SOllivier Robert } 1015c0b746e5SOllivier Robert 10162b15cb3dSCy Schubert 1017c0b746e5SOllivier Robert /* 1018ea906c41SOllivier Robert * refclock_setup - initialize terminal interface structure 1019224ba2bdSOllivier Robert */ 1020ea906c41SOllivier Robert int 1021ea906c41SOllivier Robert refclock_setup( 1022ea906c41SOllivier Robert int fd, /* file descriptor */ 1023ea906c41SOllivier Robert u_int speed, /* serial port speed (code) */ 1024ea906c41SOllivier Robert u_int lflags /* line discipline flags */ 1025ea906c41SOllivier Robert ) 1026ea906c41SOllivier Robert { 1027ea906c41SOllivier Robert int i; 1028ea906c41SOllivier Robert TTY ttyb, *ttyp; 1029224ba2bdSOllivier Robert 1030224ba2bdSOllivier Robert /* 1031ea906c41SOllivier Robert * By default, the serial line port is initialized in canonical 1032ea906c41SOllivier Robert * (line-oriented) mode at specified line speed, 8 bits and no 1033ea906c41SOllivier Robert * parity. LF ends the line and CR is mapped to LF. The break, 1034ea906c41SOllivier Robert * erase and kill functions are disabled. There is a different 1035ea906c41SOllivier Robert * section for each terminal interface, as selected at compile 1036ea906c41SOllivier Robert * time. The flag bits can be used to set raw mode and echo. 1037c0b746e5SOllivier Robert */ 1038c0b746e5SOllivier Robert ttyp = &ttyb; 1039c0b746e5SOllivier Robert #ifdef HAVE_TERMIOS 1040ea906c41SOllivier Robert 1041c0b746e5SOllivier Robert /* 1042c0b746e5SOllivier Robert * POSIX serial line parameters (termios interface) 1043c0b746e5SOllivier Robert */ 1044c0b746e5SOllivier Robert if (tcgetattr(fd, ttyp) < 0) { 10452b15cb3dSCy Schubert SAVE_ERRNO( 1046c0b746e5SOllivier Robert msyslog(LOG_ERR, 10472b15cb3dSCy Schubert "refclock_setup fd %d tcgetattr: %m", 10482b15cb3dSCy Schubert fd); 10492b15cb3dSCy Schubert ) 10502b15cb3dSCy Schubert return FALSE; 1051c0b746e5SOllivier Robert } 1052c0b746e5SOllivier Robert 1053c0b746e5SOllivier Robert /* 1054c0b746e5SOllivier Robert * Set canonical mode and local connection; set specified speed, 1055c0b746e5SOllivier Robert * 8 bits and no parity; map CR to NL; ignore break. 1056c0b746e5SOllivier Robert */ 1057ea906c41SOllivier Robert if (speed) { 1058ea906c41SOllivier Robert u_int ltemp = 0; 1059ea906c41SOllivier Robert 1060c0b746e5SOllivier Robert ttyp->c_iflag = IGNBRK | IGNPAR | ICRNL; 1061c0b746e5SOllivier Robert ttyp->c_oflag = 0; 1062c0b746e5SOllivier Robert ttyp->c_cflag = CS8 | CLOCAL | CREAD; 1063ea906c41SOllivier Robert if (lflags & LDISC_7O1) { 1064ea906c41SOllivier Robert /* HP Z3801A needs 7-bit, odd parity */ 1065ea906c41SOllivier Robert ttyp->c_cflag = CS7 | PARENB | PARODD | CLOCAL | CREAD; 1066ea906c41SOllivier Robert } 1067ea906c41SOllivier Robert cfsetispeed(&ttyb, speed); 1068ea906c41SOllivier Robert cfsetospeed(&ttyb, speed); 1069c0b746e5SOllivier Robert for (i = 0; i < NCCS; ++i) 1070c0b746e5SOllivier Robert ttyp->c_cc[i] = '\0'; 1071ea906c41SOllivier Robert 1072ea906c41SOllivier Robert #if defined(TIOCMGET) && !defined(SCO5_CLOCK) 1073ea906c41SOllivier Robert 1074ea906c41SOllivier Robert /* 1075ea906c41SOllivier Robert * If we have modem control, check to see if modem leads 1076ea906c41SOllivier Robert * are active; if so, set remote connection. This is 1077ea906c41SOllivier Robert * necessary for the kernel pps mods to work. 1078ea906c41SOllivier Robert */ 1079ea906c41SOllivier Robert if (ioctl(fd, TIOCMGET, (char *)<emp) < 0) 1080ea906c41SOllivier Robert msyslog(LOG_ERR, 1081ea906c41SOllivier Robert "refclock_setup fd %d TIOCMGET: %m", fd); 1082ea906c41SOllivier Robert #ifdef DEBUG 1083ea906c41SOllivier Robert if (debug) 1084ea906c41SOllivier Robert printf("refclock_setup fd %d modem status: 0x%x\n", 1085ea906c41SOllivier Robert fd, ltemp); 1086ea906c41SOllivier Robert #endif 1087ea906c41SOllivier Robert if (ltemp & TIOCM_DSR && lflags & LDISC_REMOTE) 1088ea906c41SOllivier Robert ttyp->c_cflag &= ~CLOCAL; 1089ea906c41SOllivier Robert #endif /* TIOCMGET */ 1090c0b746e5SOllivier Robert } 1091c0b746e5SOllivier Robert 1092c0b746e5SOllivier Robert /* 1093ea906c41SOllivier Robert * Set raw and echo modes. These can be changed on-fly. 1094c0b746e5SOllivier Robert */ 1095ea906c41SOllivier Robert ttyp->c_lflag = ICANON; 1096ea906c41SOllivier Robert if (lflags & LDISC_RAW) { 1097c0b746e5SOllivier Robert ttyp->c_lflag = 0; 1098ea906c41SOllivier Robert ttyp->c_iflag = 0; 1099c0b746e5SOllivier Robert ttyp->c_cc[VMIN] = 1; 1100c0b746e5SOllivier Robert } 1101ea906c41SOllivier Robert if (lflags & LDISC_ECHO) 1102ea906c41SOllivier Robert ttyp->c_lflag |= ECHO; 1103c0b746e5SOllivier Robert if (tcsetattr(fd, TCSANOW, ttyp) < 0) { 11042b15cb3dSCy Schubert SAVE_ERRNO( 1105c0b746e5SOllivier Robert msyslog(LOG_ERR, 11062b15cb3dSCy Schubert "refclock_setup fd %d TCSANOW: %m", 11072b15cb3dSCy Schubert fd); 11082b15cb3dSCy Schubert ) 11092b15cb3dSCy Schubert return FALSE; 1110c0b746e5SOllivier Robert } 11112b15cb3dSCy Schubert 11122b15cb3dSCy Schubert /* 11132b15cb3dSCy Schubert * flush input and output buffers to discard any outdated stuff 11142b15cb3dSCy Schubert * that might have become toxic for the driver. Failing to do so 11152b15cb3dSCy Schubert * is logged, but we keep our fingers crossed otherwise. 11162b15cb3dSCy Schubert */ 11172b15cb3dSCy Schubert if (tcflush(fd, TCIOFLUSH) < 0) 11182b15cb3dSCy Schubert msyslog(LOG_ERR, "refclock_setup fd %d tcflush(): %m", 11192b15cb3dSCy Schubert fd); 1120c0b746e5SOllivier Robert #endif /* HAVE_TERMIOS */ 1121c0b746e5SOllivier Robert 1122c0b746e5SOllivier Robert #ifdef HAVE_SYSV_TTYS 1123c0b746e5SOllivier Robert 1124c0b746e5SOllivier Robert /* 1125c0b746e5SOllivier Robert * System V serial line parameters (termio interface) 1126c0b746e5SOllivier Robert * 1127c0b746e5SOllivier Robert */ 1128c0b746e5SOllivier Robert if (ioctl(fd, TCGETA, ttyp) < 0) { 11292b15cb3dSCy Schubert SAVE_ERRNO( 1130c0b746e5SOllivier Robert msyslog(LOG_ERR, 11312b15cb3dSCy Schubert "refclock_setup fd %d TCGETA: %m", 11322b15cb3dSCy Schubert fd); 11332b15cb3dSCy Schubert ) 11342b15cb3dSCy Schubert return FALSE; 1135c0b746e5SOllivier Robert } 1136c0b746e5SOllivier Robert 1137c0b746e5SOllivier Robert /* 1138c0b746e5SOllivier Robert * Set canonical mode and local connection; set specified speed, 1139c0b746e5SOllivier Robert * 8 bits and no parity; map CR to NL; ignore break. 1140c0b746e5SOllivier Robert */ 1141ea906c41SOllivier Robert if (speed) { 1142ea906c41SOllivier Robert u_int ltemp = 0; 1143ea906c41SOllivier Robert 1144c0b746e5SOllivier Robert ttyp->c_iflag = IGNBRK | IGNPAR | ICRNL; 1145c0b746e5SOllivier Robert ttyp->c_oflag = 0; 1146c0b746e5SOllivier Robert ttyp->c_cflag = speed | CS8 | CLOCAL | CREAD; 1147ea906c41SOllivier Robert for (i = 0; i < NCCS; ++i) 1148ea906c41SOllivier Robert ttyp->c_cc[i] = '\0'; 1149ea906c41SOllivier Robert 1150ea906c41SOllivier Robert #if defined(TIOCMGET) && !defined(SCO5_CLOCK) 1151c0b746e5SOllivier Robert 1152c0b746e5SOllivier Robert /* 1153ea906c41SOllivier Robert * If we have modem control, check to see if modem leads 1154ea906c41SOllivier Robert * are active; if so, set remote connection. This is 1155ea906c41SOllivier Robert * necessary for the kernel pps mods to work. 1156c0b746e5SOllivier Robert */ 1157c0b746e5SOllivier Robert if (ioctl(fd, TIOCMGET, (char *)<emp) < 0) 1158c0b746e5SOllivier Robert msyslog(LOG_ERR, 1159ea906c41SOllivier Robert "refclock_setup fd %d TIOCMGET: %m", fd); 1160c0b746e5SOllivier Robert #ifdef DEBUG 1161c0b746e5SOllivier Robert if (debug) 1162ea906c41SOllivier Robert printf("refclock_setup fd %d modem status: %x\n", 1163c0b746e5SOllivier Robert fd, ltemp); 1164c0b746e5SOllivier Robert #endif 1165c0b746e5SOllivier Robert if (ltemp & TIOCM_DSR) 1166c0b746e5SOllivier Robert ttyp->c_cflag &= ~CLOCAL; 1167c0b746e5SOllivier Robert #endif /* TIOCMGET */ 1168ea906c41SOllivier Robert } 1169ea906c41SOllivier Robert 1170ea906c41SOllivier Robert /* 1171ea906c41SOllivier Robert * Set raw and echo modes. These can be changed on-fly. 1172ea906c41SOllivier Robert */ 1173ea906c41SOllivier Robert ttyp->c_lflag = ICANON; 1174ea906c41SOllivier Robert if (lflags & LDISC_RAW) { 1175ea906c41SOllivier Robert ttyp->c_lflag = 0; 1176ea906c41SOllivier Robert ttyp->c_iflag = 0; 1177ea906c41SOllivier Robert ttyp->c_cc[VMIN] = 1; 1178ea906c41SOllivier Robert } 1179c0b746e5SOllivier Robert if (ioctl(fd, TCSETA, ttyp) < 0) { 11802b15cb3dSCy Schubert SAVE_ERRNO( 1181c0b746e5SOllivier Robert msyslog(LOG_ERR, 1182ea906c41SOllivier Robert "refclock_setup fd %d TCSETA: %m", fd); 11832b15cb3dSCy Schubert ) 11842b15cb3dSCy Schubert return FALSE; 1185c0b746e5SOllivier Robert } 1186c0b746e5SOllivier Robert #endif /* HAVE_SYSV_TTYS */ 1187c0b746e5SOllivier Robert 1188c0b746e5SOllivier Robert #ifdef HAVE_BSD_TTYS 1189c0b746e5SOllivier Robert 1190c0b746e5SOllivier Robert /* 1191c0b746e5SOllivier Robert * 4.3bsd serial line parameters (sgttyb interface) 1192c0b746e5SOllivier Robert */ 1193c0b746e5SOllivier Robert if (ioctl(fd, TIOCGETP, (char *)ttyp) < 0) { 11942b15cb3dSCy Schubert SAVE_ERRNO( 1195c0b746e5SOllivier Robert msyslog(LOG_ERR, 11962b15cb3dSCy Schubert "refclock_setup fd %d TIOCGETP: %m", 11972b15cb3dSCy Schubert fd); 11982b15cb3dSCy Schubert ) 11992b15cb3dSCy Schubert return FALSE; 1200c0b746e5SOllivier Robert } 1201ea906c41SOllivier Robert if (speed) 1202c0b746e5SOllivier Robert ttyp->sg_ispeed = ttyp->sg_ospeed = speed; 1203c0b746e5SOllivier Robert ttyp->sg_flags = EVENP | ODDP | CRMOD; 1204c0b746e5SOllivier Robert if (ioctl(fd, TIOCSETP, (char *)ttyp) < 0) { 12052b15cb3dSCy Schubert SAVE_ERRNO( 12062b15cb3dSCy Schubert msyslog(LOG_ERR, "refclock_setup TIOCSETP: %m"); 12072b15cb3dSCy Schubert ) 12082b15cb3dSCy Schubert return FALSE; 1209c0b746e5SOllivier Robert } 1210c0b746e5SOllivier Robert #endif /* HAVE_BSD_TTYS */ 1211ea906c41SOllivier Robert return(1); 1212c0b746e5SOllivier Robert } 1213c0b746e5SOllivier Robert #endif /* HAVE_TERMIOS || HAVE_SYSV_TTYS || HAVE_BSD_TTYS */ 1214c0b746e5SOllivier Robert 1215ea906c41SOllivier Robert 1216c0b746e5SOllivier Robert /* 1217c0b746e5SOllivier Robert * refclock_ioctl - set serial port control functions 1218c0b746e5SOllivier Robert * 1219c0b746e5SOllivier Robert * This routine attempts to hide the internal, system-specific details 1220c0b746e5SOllivier Robert * of serial ports. It can handle POSIX (termios), SYSV (termio) and BSD 1221c0b746e5SOllivier Robert * (sgtty) interfaces with varying degrees of success. The routine sets 12222b15cb3dSCy Schubert * up optional features such as tty_clk. The routine returns TRUE if 12232b15cb3dSCy Schubert * successful. 1224c0b746e5SOllivier Robert */ 1225c0b746e5SOllivier Robert int 1226c0b746e5SOllivier Robert refclock_ioctl( 1227c0b746e5SOllivier Robert int fd, /* file descriptor */ 1228ea906c41SOllivier Robert u_int lflags /* line discipline flags */ 1229c0b746e5SOllivier Robert ) 1230c0b746e5SOllivier Robert { 1231ea906c41SOllivier Robert /* 12322b15cb3dSCy Schubert * simply return TRUE if no UNIX line discipline is supported 1233ea906c41SOllivier Robert */ 12342b15cb3dSCy Schubert DPRINTF(1, ("refclock_ioctl: fd %d flags 0x%x\n", fd, lflags)); 1235c0b746e5SOllivier Robert 12362b15cb3dSCy Schubert return TRUE; 1237ea906c41SOllivier Robert } 12382b15cb3dSCy Schubert #endif /* !defined(SYS_VXWORKS) && !defined(SYS_WINNT) */ 1239c0b746e5SOllivier Robert 1240ea906c41SOllivier Robert 1241c0b746e5SOllivier Robert /* 1242c0b746e5SOllivier Robert * refclock_control - set and/or return clock values 1243c0b746e5SOllivier Robert * 1244c0b746e5SOllivier Robert * This routine is used mainly for debugging. It returns designated 1245c0b746e5SOllivier Robert * values from the interface structure that can be displayed using 1246c0b746e5SOllivier Robert * ntpdc and the clockstat command. It can also be used to initialize 1247c0b746e5SOllivier Robert * configuration variables, such as fudgetimes, fudgevalues, reference 1248c0b746e5SOllivier Robert * ID and stratum. 1249c0b746e5SOllivier Robert */ 1250c0b746e5SOllivier Robert void 1251c0b746e5SOllivier Robert refclock_control( 12522b15cb3dSCy Schubert sockaddr_u *srcadr, 12532b15cb3dSCy Schubert const struct refclockstat *in, 1254c0b746e5SOllivier Robert struct refclockstat *out 1255c0b746e5SOllivier Robert ) 1256c0b746e5SOllivier Robert { 1257c0b746e5SOllivier Robert struct peer *peer; 1258c0b746e5SOllivier Robert struct refclockproc *pp; 1259c0b746e5SOllivier Robert u_char clktype; 1260c0b746e5SOllivier Robert int unit; 1261c0b746e5SOllivier Robert 1262c0b746e5SOllivier Robert /* 1263c0b746e5SOllivier Robert * Check for valid address and running peer 1264c0b746e5SOllivier Robert */ 1265c0b746e5SOllivier Robert if (!ISREFCLOCKADR(srcadr)) 1266c0b746e5SOllivier Robert return; 1267ea906c41SOllivier Robert 1268c0b746e5SOllivier Robert clktype = (u_char)REFCLOCKTYPE(srcadr); 1269c0b746e5SOllivier Robert unit = REFCLOCKUNIT(srcadr); 12702b15cb3dSCy Schubert 127109100258SXin LI peer = findexistingpeer(srcadr, NULL, NULL, -1, 0, NULL); 12722b15cb3dSCy Schubert 12732b15cb3dSCy Schubert if (NULL == peer) 1274c0b746e5SOllivier Robert return; 1275ea906c41SOllivier Robert 12769034852cSGleb Smirnoff INSIST(peer->procptr != NULL); 1277c0b746e5SOllivier Robert pp = peer->procptr; 1278c0b746e5SOllivier Robert 1279c0b746e5SOllivier Robert /* 1280c0b746e5SOllivier Robert * Initialize requested data 1281c0b746e5SOllivier Robert */ 12822b15cb3dSCy Schubert if (in != NULL) { 1283c0b746e5SOllivier Robert if (in->haveflags & CLK_HAVETIME1) 1284c0b746e5SOllivier Robert pp->fudgetime1 = in->fudgetime1; 1285c0b746e5SOllivier Robert if (in->haveflags & CLK_HAVETIME2) 1286c0b746e5SOllivier Robert pp->fudgetime2 = in->fudgetime2; 1287c0b746e5SOllivier Robert if (in->haveflags & CLK_HAVEVAL1) 1288ea906c41SOllivier Robert peer->stratum = pp->stratum = (u_char)in->fudgeval1; 1289c0b746e5SOllivier Robert if (in->haveflags & CLK_HAVEVAL2) 1290ea906c41SOllivier Robert peer->refid = pp->refid = in->fudgeval2; 1291c0b746e5SOllivier Robert if (in->haveflags & CLK_HAVEFLAG1) { 1292c0b746e5SOllivier Robert pp->sloppyclockflag &= ~CLK_FLAG1; 1293c0b746e5SOllivier Robert pp->sloppyclockflag |= in->flags & CLK_FLAG1; 1294c0b746e5SOllivier Robert } 1295c0b746e5SOllivier Robert if (in->haveflags & CLK_HAVEFLAG2) { 1296c0b746e5SOllivier Robert pp->sloppyclockflag &= ~CLK_FLAG2; 1297c0b746e5SOllivier Robert pp->sloppyclockflag |= in->flags & CLK_FLAG2; 1298c0b746e5SOllivier Robert } 1299c0b746e5SOllivier Robert if (in->haveflags & CLK_HAVEFLAG3) { 1300c0b746e5SOllivier Robert pp->sloppyclockflag &= ~CLK_FLAG3; 1301c0b746e5SOllivier Robert pp->sloppyclockflag |= in->flags & CLK_FLAG3; 1302c0b746e5SOllivier Robert } 1303c0b746e5SOllivier Robert if (in->haveflags & CLK_HAVEFLAG4) { 1304c0b746e5SOllivier Robert pp->sloppyclockflag &= ~CLK_FLAG4; 1305c0b746e5SOllivier Robert pp->sloppyclockflag |= in->flags & CLK_FLAG4; 1306c0b746e5SOllivier Robert } 13072d4e511cSCy Schubert if (in->haveflags & CLK_HAVEMINJIT) 13082d4e511cSCy Schubert pp->fudgeminjitter = in->fudgeminjitter; 1309c0b746e5SOllivier Robert } 1310c0b746e5SOllivier Robert 1311c0b746e5SOllivier Robert /* 1312c0b746e5SOllivier Robert * Readback requested data 1313c0b746e5SOllivier Robert */ 13142b15cb3dSCy Schubert if (out != NULL) { 13159c2daa00SOllivier Robert out->fudgeval1 = pp->stratum; 1316c0b746e5SOllivier Robert out->fudgeval2 = pp->refid; 13172b15cb3dSCy Schubert out->haveflags = CLK_HAVEVAL1 | CLK_HAVEVAL2; 13182b15cb3dSCy Schubert out->fudgetime1 = pp->fudgetime1; 13192b15cb3dSCy Schubert if (0.0 != out->fudgetime1) 13202b15cb3dSCy Schubert out->haveflags |= CLK_HAVETIME1; 13212b15cb3dSCy Schubert out->fudgetime2 = pp->fudgetime2; 13222b15cb3dSCy Schubert if (0.0 != out->fudgetime2) 13232b15cb3dSCy Schubert out->haveflags |= CLK_HAVETIME2; 1324c0b746e5SOllivier Robert out->flags = (u_char) pp->sloppyclockflag; 13252b15cb3dSCy Schubert if (CLK_FLAG1 & out->flags) 13262b15cb3dSCy Schubert out->haveflags |= CLK_HAVEFLAG1; 13272b15cb3dSCy Schubert if (CLK_FLAG2 & out->flags) 13282b15cb3dSCy Schubert out->haveflags |= CLK_HAVEFLAG2; 13292b15cb3dSCy Schubert if (CLK_FLAG3 & out->flags) 13302b15cb3dSCy Schubert out->haveflags |= CLK_HAVEFLAG3; 13312b15cb3dSCy Schubert if (CLK_FLAG4 & out->flags) 13322b15cb3dSCy Schubert out->haveflags |= CLK_HAVEFLAG4; 13332d4e511cSCy Schubert out->fudgeminjitter = pp->fudgeminjitter; 13342d4e511cSCy Schubert if (0.0 != out->fudgeminjitter) 13352d4e511cSCy Schubert out->haveflags |= CLK_HAVEMINJIT; 1336c0b746e5SOllivier Robert 1337c0b746e5SOllivier Robert out->timereset = current_time - pp->timestarted; 1338c0b746e5SOllivier Robert out->polls = pp->polls; 1339c0b746e5SOllivier Robert out->noresponse = pp->noreply; 1340c0b746e5SOllivier Robert out->badformat = pp->badformat; 1341c0b746e5SOllivier Robert out->baddata = pp->baddata; 1342c0b746e5SOllivier Robert 1343c0b746e5SOllivier Robert out->lastevent = pp->lastevent; 1344c0b746e5SOllivier Robert out->currentstatus = pp->currentstatus; 1345c0b746e5SOllivier Robert out->type = pp->type; 1346c0b746e5SOllivier Robert out->clockdesc = pp->clockdesc; 13472b15cb3dSCy Schubert out->lencode = (u_short)pp->lencode; 1348c0b746e5SOllivier Robert out->p_lastcode = pp->a_lastcode; 1349c0b746e5SOllivier Robert } 1350c0b746e5SOllivier Robert 1351c0b746e5SOllivier Robert /* 1352c0b746e5SOllivier Robert * Give the stuff to the clock 1353c0b746e5SOllivier Robert */ 1354c0b746e5SOllivier Robert if (refclock_conf[clktype]->clock_control != noentry) 1355c0b746e5SOllivier Robert (refclock_conf[clktype]->clock_control)(unit, in, out, peer); 1356c0b746e5SOllivier Robert } 1357c0b746e5SOllivier Robert 1358c0b746e5SOllivier Robert 1359c0b746e5SOllivier Robert /* 1360c0b746e5SOllivier Robert * refclock_buginfo - return debugging info 1361c0b746e5SOllivier Robert * 1362c0b746e5SOllivier Robert * This routine is used mainly for debugging. It returns designated 1363c0b746e5SOllivier Robert * values from the interface structure that can be displayed using 1364c0b746e5SOllivier Robert * ntpdc and the clkbug command. 1365c0b746e5SOllivier Robert */ 1366c0b746e5SOllivier Robert void 1367c0b746e5SOllivier Robert refclock_buginfo( 13682b15cb3dSCy Schubert sockaddr_u *srcadr, /* clock address */ 1369c0b746e5SOllivier Robert struct refclockbug *bug /* output structure */ 1370c0b746e5SOllivier Robert ) 1371c0b746e5SOllivier Robert { 1372c0b746e5SOllivier Robert struct peer *peer; 1373c0b746e5SOllivier Robert struct refclockproc *pp; 13742b15cb3dSCy Schubert int clktype; 1375c0b746e5SOllivier Robert int unit; 13762b15cb3dSCy Schubert unsigned u; 1377c0b746e5SOllivier Robert 1378c0b746e5SOllivier Robert /* 1379c0b746e5SOllivier Robert * Check for valid address and peer structure 1380c0b746e5SOllivier Robert */ 1381c0b746e5SOllivier Robert if (!ISREFCLOCKADR(srcadr)) 1382c0b746e5SOllivier Robert return; 1383ea906c41SOllivier Robert 1384c0b746e5SOllivier Robert clktype = (u_char) REFCLOCKTYPE(srcadr); 1385c0b746e5SOllivier Robert unit = REFCLOCKUNIT(srcadr); 1386ea906c41SOllivier Robert 138709100258SXin LI peer = findexistingpeer(srcadr, NULL, NULL, -1, 0, NULL); 13882b15cb3dSCy Schubert 13892b15cb3dSCy Schubert if (NULL == peer || NULL == peer->procptr) 1390c0b746e5SOllivier Robert return; 1391ea906c41SOllivier Robert 1392c0b746e5SOllivier Robert pp = peer->procptr; 1393c0b746e5SOllivier Robert 1394c0b746e5SOllivier Robert /* 1395c0b746e5SOllivier Robert * Copy structure values 1396c0b746e5SOllivier Robert */ 1397c0b746e5SOllivier Robert bug->nvalues = 8; 1398c0b746e5SOllivier Robert bug->svalues = 0x0000003f; 1399c0b746e5SOllivier Robert bug->values[0] = pp->year; 1400c0b746e5SOllivier Robert bug->values[1] = pp->day; 1401c0b746e5SOllivier Robert bug->values[2] = pp->hour; 1402c0b746e5SOllivier Robert bug->values[3] = pp->minute; 1403c0b746e5SOllivier Robert bug->values[4] = pp->second; 14049c2daa00SOllivier Robert bug->values[5] = pp->nsec; 1405c0b746e5SOllivier Robert bug->values[6] = pp->yearstart; 1406c0b746e5SOllivier Robert bug->values[7] = pp->coderecv; 1407c0b746e5SOllivier Robert bug->stimes = 0xfffffffc; 1408c0b746e5SOllivier Robert bug->times[0] = pp->lastref; 1409c0b746e5SOllivier Robert bug->times[1] = pp->lastrec; 14102b15cb3dSCy Schubert for (u = 2; u < bug->ntimes; u++) 14112b15cb3dSCy Schubert DTOLFP(pp->filter[u - 2], &bug->times[u]); 1412c0b746e5SOllivier Robert 1413c0b746e5SOllivier Robert /* 1414c0b746e5SOllivier Robert * Give the stuff to the clock 1415c0b746e5SOllivier Robert */ 1416c0b746e5SOllivier Robert if (refclock_conf[clktype]->clock_buginfo != noentry) 1417c0b746e5SOllivier Robert (refclock_conf[clktype]->clock_buginfo)(unit, bug, peer); 1418c0b746e5SOllivier Robert } 1419c0b746e5SOllivier Robert 14202b15cb3dSCy Schubert 14212b15cb3dSCy Schubert #ifdef HAVE_PPSAPI 14222b15cb3dSCy Schubert /* 14232b15cb3dSCy Schubert * refclock_ppsapi - initialize/update ppsapi 14242b15cb3dSCy Schubert * 14252b15cb3dSCy Schubert * This routine is called after the fudge command to open the PPSAPI 14262b15cb3dSCy Schubert * interface for later parameter setting after the fudge command. 14272b15cb3dSCy Schubert */ 14282b15cb3dSCy Schubert int 14292b15cb3dSCy Schubert refclock_ppsapi( 14302b15cb3dSCy Schubert int fddev, /* fd device */ 14312b15cb3dSCy Schubert struct refclock_atom *ap /* atom structure pointer */ 14322b15cb3dSCy Schubert ) 14332b15cb3dSCy Schubert { 14342b15cb3dSCy Schubert if (ap->handle == 0) { 14352b15cb3dSCy Schubert if (time_pps_create(fddev, &ap->handle) < 0) { 14362b15cb3dSCy Schubert msyslog(LOG_ERR, 14372b15cb3dSCy Schubert "refclock_ppsapi: time_pps_create: %m"); 14382b15cb3dSCy Schubert return (0); 14392b15cb3dSCy Schubert } 1440f391d6bcSXin LI ZERO(ap->ts); /* [Bug 2689] defined INIT state */ 14412b15cb3dSCy Schubert } 14422b15cb3dSCy Schubert return (1); 14432b15cb3dSCy Schubert } 14442b15cb3dSCy Schubert 14452b15cb3dSCy Schubert 14462b15cb3dSCy Schubert /* 14472b15cb3dSCy Schubert * refclock_params - set ppsapi parameters 14482b15cb3dSCy Schubert * 14492b15cb3dSCy Schubert * This routine is called to set the PPSAPI parameters after the fudge 14502b15cb3dSCy Schubert * command. 14512b15cb3dSCy Schubert */ 14522b15cb3dSCy Schubert int 14532b15cb3dSCy Schubert refclock_params( 14542b15cb3dSCy Schubert int mode, /* mode bits */ 14552b15cb3dSCy Schubert struct refclock_atom *ap /* atom structure pointer */ 14562b15cb3dSCy Schubert ) 14572b15cb3dSCy Schubert { 14582b15cb3dSCy Schubert ZERO(ap->pps_params); 14592b15cb3dSCy Schubert ap->pps_params.api_version = PPS_API_VERS_1; 14602b15cb3dSCy Schubert 14612b15cb3dSCy Schubert /* 14622b15cb3dSCy Schubert * Solaris serial ports provide PPS pulse capture only on the 14632b15cb3dSCy Schubert * assert edge. FreeBSD serial ports provide capture on the 14642b15cb3dSCy Schubert * clear edge, while FreeBSD parallel ports provide capture 14652b15cb3dSCy Schubert * on the assert edge. Your mileage may vary. 14662b15cb3dSCy Schubert */ 14672b15cb3dSCy Schubert if (mode & CLK_FLAG2) 14682b15cb3dSCy Schubert ap->pps_params.mode = PPS_TSFMT_TSPEC | PPS_CAPTURECLEAR; 14692b15cb3dSCy Schubert else 14702b15cb3dSCy Schubert ap->pps_params.mode = PPS_TSFMT_TSPEC | PPS_CAPTUREASSERT; 14712b15cb3dSCy Schubert if (time_pps_setparams(ap->handle, &ap->pps_params) < 0) { 14722b15cb3dSCy Schubert msyslog(LOG_ERR, 14732b15cb3dSCy Schubert "refclock_params: time_pps_setparams: %m"); 14742b15cb3dSCy Schubert return (0); 14752b15cb3dSCy Schubert } 14762b15cb3dSCy Schubert 14772b15cb3dSCy Schubert /* 14782b15cb3dSCy Schubert * If flag3 is lit, select the kernel PPS if we can. 147909100258SXin LI * 148009100258SXin LI * Note: EOPNOTSUPP is the only 'legal' error code we deal with; 148109100258SXin LI * it is part of the 'if we can' strategy. Any other error 148209100258SXin LI * indicates something more sinister and makes this function fail. 14832b15cb3dSCy Schubert */ 14842b15cb3dSCy Schubert if (mode & CLK_FLAG3) { 14852b15cb3dSCy Schubert if (time_pps_kcbind(ap->handle, PPS_KC_HARDPPS, 14862b15cb3dSCy Schubert ap->pps_params.mode & ~PPS_TSFMT_TSPEC, 148709100258SXin LI PPS_TSFMT_TSPEC) < 0) 148809100258SXin LI { 148909100258SXin LI if (errno != EOPNOTSUPP) { 14902b15cb3dSCy Schubert msyslog(LOG_ERR, 14912b15cb3dSCy Schubert "refclock_params: time_pps_kcbind: %m"); 14922b15cb3dSCy Schubert return (0); 14932b15cb3dSCy Schubert } 149409100258SXin LI } else { 14952b15cb3dSCy Schubert hardpps_enable = 1; 14962b15cb3dSCy Schubert } 149709100258SXin LI } 14982b15cb3dSCy Schubert return (1); 14992b15cb3dSCy Schubert } 15002b15cb3dSCy Schubert 15012b15cb3dSCy Schubert 15022b15cb3dSCy Schubert /* 15032b15cb3dSCy Schubert * refclock_pps - called once per second 15042b15cb3dSCy Schubert * 15052b15cb3dSCy Schubert * This routine is called once per second. It snatches the PPS 15062b15cb3dSCy Schubert * timestamp from the kernel and saves the sign-extended fraction in 15072b15cb3dSCy Schubert * a circular buffer for processing at the next poll event. 15082b15cb3dSCy Schubert */ 15092b15cb3dSCy Schubert int 15102b15cb3dSCy Schubert refclock_pps( 15112b15cb3dSCy Schubert struct peer *peer, /* peer structure pointer */ 15122b15cb3dSCy Schubert struct refclock_atom *ap, /* atom structure pointer */ 15132b15cb3dSCy Schubert int mode /* mode bits */ 15142b15cb3dSCy Schubert ) 15152b15cb3dSCy Schubert { 15162b15cb3dSCy Schubert struct refclockproc *pp; 15172b15cb3dSCy Schubert pps_info_t pps_info; 15182b15cb3dSCy Schubert struct timespec timeout; 1519f391d6bcSXin LI double dtemp, dcorr, trash; 15202b15cb3dSCy Schubert 15212b15cb3dSCy Schubert /* 15222b15cb3dSCy Schubert * We require the clock to be synchronized before setting the 15232b15cb3dSCy Schubert * parameters. When the parameters have been set, fetch the 15242b15cb3dSCy Schubert * most recent PPS timestamp. 15252b15cb3dSCy Schubert */ 15262b15cb3dSCy Schubert pp = peer->procptr; 15272b15cb3dSCy Schubert if (ap->handle == 0) 15282b15cb3dSCy Schubert return (0); 15292b15cb3dSCy Schubert 15302b15cb3dSCy Schubert if (ap->pps_params.mode == 0 && sys_leap != LEAP_NOTINSYNC) { 15312b15cb3dSCy Schubert if (refclock_params(pp->sloppyclockflag, ap) < 1) 15322b15cb3dSCy Schubert return (0); 15332b15cb3dSCy Schubert } 1534f391d6bcSXin LI ZERO(timeout); 15352b15cb3dSCy Schubert ZERO(pps_info); 15362b15cb3dSCy Schubert if (time_pps_fetch(ap->handle, PPS_TSFMT_TSPEC, &pps_info, 15372b15cb3dSCy Schubert &timeout) < 0) { 15382b15cb3dSCy Schubert refclock_report(peer, CEVNT_FAULT); 15392b15cb3dSCy Schubert return (0); 15402b15cb3dSCy Schubert } 1541f391d6bcSXin LI timeout = ap->ts; /* save old timestamp for check */ 15422b15cb3dSCy Schubert if (ap->pps_params.mode & PPS_CAPTUREASSERT) 15432b15cb3dSCy Schubert ap->ts = pps_info.assert_timestamp; 15442b15cb3dSCy Schubert else if (ap->pps_params.mode & PPS_CAPTURECLEAR) 15452b15cb3dSCy Schubert ap->ts = pps_info.clear_timestamp; 15462b15cb3dSCy Schubert else 15472b15cb3dSCy Schubert return (0); 15482b15cb3dSCy Schubert 1549f391d6bcSXin LI /* [Bug 2689] Discard the first sample we read -- if the PPS 1550f391d6bcSXin LI * source is currently down / disconnected, we have read a 1551f391d6bcSXin LI * potentially *very* stale value here. So if our old TS value 1552f391d6bcSXin LI * is all-zero, we consider this sample unrealiable and drop it. 1553f391d6bcSXin LI * 1554f391d6bcSXin LI * Note 1: a better check would compare the PPS time stamp to 1555f391d6bcSXin LI * the current system time and drop it if it's more than say 3s 1556f391d6bcSXin LI * away. 1557f391d6bcSXin LI * 1558f391d6bcSXin LI * Note 2: If we ever again get an all-zero PPS sample, the next 1559f391d6bcSXin LI * one will be discarded. This can happen every 136yrs and is 1560f391d6bcSXin LI * unlikely to be ever observed. 1561f391d6bcSXin LI */ 1562f391d6bcSXin LI if (0 == (timeout.tv_sec | timeout.tv_nsec)) 1563f391d6bcSXin LI return (0); 1564f391d6bcSXin LI 1565f391d6bcSXin LI /* If the PPS source fails to deliver a new sample between 1566f391d6bcSXin LI * polls, it regurgitates the last sample. We do not want to 1567f391d6bcSXin LI * process the same sample multiple times. 1568f391d6bcSXin LI */ 15692b15cb3dSCy Schubert if (0 == memcmp(&timeout, &ap->ts, sizeof(timeout))) 15702b15cb3dSCy Schubert return (0); 15712b15cb3dSCy Schubert 15722b15cb3dSCy Schubert /* 1573f391d6bcSXin LI * Convert to signed fraction offset, apply fudge and properly 1574f391d6bcSXin LI * fold the correction into the [-0.5s,0.5s] range. Handle 1575f391d6bcSXin LI * excessive fudge times, too. 1576f391d6bcSXin LI */ 1577f391d6bcSXin LI dtemp = ap->ts.tv_nsec / 1e9; 1578f391d6bcSXin LI dcorr = modf((pp->fudgetime1 - dtemp), &trash); 1579f391d6bcSXin LI if (dcorr > 0.5) 1580f391d6bcSXin LI dcorr -= 1.0; 1581f391d6bcSXin LI else if (dcorr < -0.5) 1582f391d6bcSXin LI dcorr += 1.0; 1583f391d6bcSXin LI 1584f391d6bcSXin LI /* phase gate check: avoid wobbling by +/-1s when too close to 1585f391d6bcSXin LI * the switch-over point. We allow +/-400ms max phase deviation. 1586f391d6bcSXin LI * The trade-off is clear: The smaller the limit, the less 1587f391d6bcSXin LI * sensitive to sampling noise the clock becomes. OTOH the 1588f391d6bcSXin LI * system must get into phase gate range by other means for the 1589f391d6bcSXin LI * PPS clock to lock in. 1590f391d6bcSXin LI */ 1591f391d6bcSXin LI if (fabs(dcorr) > 0.4) 1592f391d6bcSXin LI return (0); 1593f391d6bcSXin LI 1594f391d6bcSXin LI /* 1595f391d6bcSXin LI * record this time stamp and stuff in median filter 15962b15cb3dSCy Schubert */ 15972b15cb3dSCy Schubert pp->lastrec.l_ui = (u_int32)ap->ts.tv_sec + JAN_1970; 15982b15cb3dSCy Schubert pp->lastrec.l_uf = (u_int32)(dtemp * FRAC); 15992d4e511cSCy Schubert clk_add_sample(pp, dcorr); 16002d4e511cSCy Schubert refclock_checkburst(peer, pp); 1601f391d6bcSXin LI 16022b15cb3dSCy Schubert #ifdef DEBUG 16032b15cb3dSCy Schubert if (debug > 1) 16042b15cb3dSCy Schubert printf("refclock_pps: %lu %f %f\n", current_time, 1605f391d6bcSXin LI dcorr, pp->fudgetime1); 16062b15cb3dSCy Schubert #endif 16072b15cb3dSCy Schubert return (1); 16082b15cb3dSCy Schubert } 16092b15cb3dSCy Schubert #endif /* HAVE_PPSAPI */ 16102d4e511cSCy Schubert 16112d4e511cSCy Schubert 16122d4e511cSCy Schubert /* 16132d4e511cSCy Schubert * ------------------------------------------------------------------- 16142d4e511cSCy Schubert * refclock_ppsaugment(...) -- correlate with PPS edge 16152d4e511cSCy Schubert * 16162d4e511cSCy Schubert * This function is used to correlate a receive time stamp with a PPS 16172d4e511cSCy Schubert * edge time stamp. It applies the necessary fudges and then tries to 16182d4e511cSCy Schubert * move the receive time stamp to the corresponding edge. This can warp 16192d4e511cSCy Schubert * into future, if a transmission delay of more than 500ms is not 16202d4e511cSCy Schubert * compensated with a corresponding fudge time2 value, because then the 16212d4e511cSCy Schubert * next PPS edge is nearer than the last. (Similiar to what the PPS ATOM 16222d4e511cSCy Schubert * driver does, but we deal with full time stamps here, not just phase 16232d4e511cSCy Schubert * shift information.) Likewise, a negative fudge time2 value must be 16242d4e511cSCy Schubert * used if the reference time stamp correlates with the *following* PPS 16252d4e511cSCy Schubert * pulse. 16262d4e511cSCy Schubert * 16272d4e511cSCy Schubert * Note that the receive time fudge value only needs to move the receive 16282d4e511cSCy Schubert * stamp near a PPS edge but that close proximity is not required; 16292d4e511cSCy Schubert * +/-100ms precision should be enough. But since the fudge value will 16302d4e511cSCy Schubert * probably also be used to compensate the transmission delay when no 16312d4e511cSCy Schubert * PPS edge can be related to the time stamp, it's best to get it as 16322d4e511cSCy Schubert * close as possible. 16332d4e511cSCy Schubert * 16342d4e511cSCy Schubert * It should also be noted that the typical use case is matching to the 16352d4e511cSCy Schubert * preceeding edge, as most units relate their sentences to the current 16362d4e511cSCy Schubert * second. 16372d4e511cSCy Schubert * 16382d4e511cSCy Schubert * The function returns FALSE if there is no correlation possible, TRUE 16392d4e511cSCy Schubert * otherwise. Reason for failures are: 16402d4e511cSCy Schubert * 16412d4e511cSCy Schubert * - no PPS/ATOM unit given 16422d4e511cSCy Schubert * - PPS stamp is stale (that is, the difference between the PPS stamp 16432d4e511cSCy Schubert * and the corrected time stamp would exceed two seconds) 16442d4e511cSCy Schubert * - The phase difference is too close to 0.5, and the decision wether 16452d4e511cSCy Schubert * to move up or down is too sensitive to noise. 16462d4e511cSCy Schubert * 16472d4e511cSCy Schubert * On output, the receive time stamp is updated with the 'fixed' receive 16482d4e511cSCy Schubert * time. 16492d4e511cSCy Schubert * ------------------------------------------------------------------- 16502d4e511cSCy Schubert */ 16512d4e511cSCy Schubert 1652*f5f40dd6SCy Schubert int 16532d4e511cSCy Schubert refclock_ppsaugment( 16542d4e511cSCy Schubert const struct refclock_atom * ap , /* for PPS io */ 16552d4e511cSCy Schubert l_fp * rcvtime , 16562d4e511cSCy Schubert double rcvfudge, /* i/o read fudge */ 16572d4e511cSCy Schubert double ppsfudge /* pps fudge */ 16582d4e511cSCy Schubert ) 16592d4e511cSCy Schubert { 16602d4e511cSCy Schubert l_fp delta[1]; 16612d4e511cSCy Schubert 16622d4e511cSCy Schubert #ifdef HAVE_PPSAPI 16632d4e511cSCy Schubert 16642d4e511cSCy Schubert pps_info_t pps_info; 16652d4e511cSCy Schubert struct timespec timeout; 16662d4e511cSCy Schubert l_fp stamp[1]; 16672d4e511cSCy Schubert uint32_t phase; 16682d4e511cSCy Schubert 16692d4e511cSCy Schubert static const uint32_t s_plim_hi = UINT32_C(1932735284); 16702d4e511cSCy Schubert static const uint32_t s_plim_lo = UINT32_C(2362232013); 16712d4e511cSCy Schubert 16722d4e511cSCy Schubert /* fixup receive time in case we have to bail out early */ 16732d4e511cSCy Schubert DTOLFP(rcvfudge, delta); 16742d4e511cSCy Schubert L_SUB(rcvtime, delta); 16752d4e511cSCy Schubert 16762d4e511cSCy Schubert if (NULL == ap) 16772d4e511cSCy Schubert return FALSE; 16782d4e511cSCy Schubert 16792d4e511cSCy Schubert ZERO(timeout); 16802d4e511cSCy Schubert ZERO(pps_info); 16812d4e511cSCy Schubert 16822d4e511cSCy Schubert /* fetch PPS stamp from ATOM block */ 16832d4e511cSCy Schubert if (time_pps_fetch(ap->handle, PPS_TSFMT_TSPEC, 16842d4e511cSCy Schubert &pps_info, &timeout) < 0) 16852d4e511cSCy Schubert return FALSE; /* can't get time stamps */ 16862d4e511cSCy Schubert 16872d4e511cSCy Schubert /* get last active PPS edge before receive */ 16882d4e511cSCy Schubert if (ap->pps_params.mode & PPS_CAPTUREASSERT) 16892d4e511cSCy Schubert timeout = pps_info.assert_timestamp; 16902d4e511cSCy Schubert else if (ap->pps_params.mode & PPS_CAPTURECLEAR) 16912d4e511cSCy Schubert timeout = pps_info.clear_timestamp; 16922d4e511cSCy Schubert else 16932d4e511cSCy Schubert return FALSE; /* WHICH edge, please?!? */ 16942d4e511cSCy Schubert 16952d4e511cSCy Schubert /* convert PPS stamp to l_fp and apply fudge */ 16962d4e511cSCy Schubert *stamp = tspec_stamp_to_lfp(timeout); 16972d4e511cSCy Schubert DTOLFP(ppsfudge, delta); 16982d4e511cSCy Schubert L_SUB(stamp, delta); 16992d4e511cSCy Schubert 17002d4e511cSCy Schubert /* Get difference between PPS stamp (--> yield) and receive time 17012d4e511cSCy Schubert * (--> base) 17022d4e511cSCy Schubert */ 17032d4e511cSCy Schubert *delta = *stamp; 17042d4e511cSCy Schubert L_SUB(delta, rcvtime); 17052d4e511cSCy Schubert 17062d4e511cSCy Schubert /* check if either the PPS or the STAMP is stale in relation 17072d4e511cSCy Schubert * to each other. Bail if it is so... 17082d4e511cSCy Schubert */ 17092d4e511cSCy Schubert phase = delta->l_ui; 17102d4e511cSCy Schubert if (phase >= 2 && phase < (uint32_t)-2) 17112d4e511cSCy Schubert return FALSE; /* PPS is stale, don't use it */ 17122d4e511cSCy Schubert 17132d4e511cSCy Schubert /* If the phase is too close to 0.5, the decision whether to 17142d4e511cSCy Schubert * move up or down is becoming noise sensitive. That is, we 17152d4e511cSCy Schubert * might amplify usec noise between samples into seconds with a 17162d4e511cSCy Schubert * simple threshold. This can be solved by a Schmitt Trigger 17172d4e511cSCy Schubert * characteristic, but that would also require additional state 17182d4e511cSCy Schubert * where we could remember previous decisions. Easier to play 17192d4e511cSCy Schubert * dead duck and wait for the conditions to become clear. 17202d4e511cSCy Schubert */ 17212d4e511cSCy Schubert phase = delta->l_uf; 17222d4e511cSCy Schubert if (phase > s_plim_hi && phase < s_plim_lo) 17232d4e511cSCy Schubert return FALSE; /* we're in the noise lock gap */ 17242d4e511cSCy Schubert 17252d4e511cSCy Schubert /* sign-extend fraction into seconds */ 17262d4e511cSCy Schubert delta->l_ui = UINT32_C(0) - ((phase >> 31) & 1); 17272d4e511cSCy Schubert /* add it up now */ 17282d4e511cSCy Schubert L_ADD(rcvtime, delta); 17292d4e511cSCy Schubert return TRUE; 17302d4e511cSCy Schubert 17312d4e511cSCy Schubert # else /* have no PPS support at all */ 17322d4e511cSCy Schubert 17332d4e511cSCy Schubert /* just fixup receive time and fail */ 17342d4e511cSCy Schubert UNUSED_ARG(ap); 17352d4e511cSCy Schubert UNUSED_ARG(ppsfudge); 17362d4e511cSCy Schubert 17372d4e511cSCy Schubert DTOLFP(rcvfudge, delta); 17382d4e511cSCy Schubert L_SUB(rcvtime, delta); 17392d4e511cSCy Schubert return FALSE; 17402d4e511cSCy Schubert 17412d4e511cSCy Schubert # endif 17422d4e511cSCy Schubert } 17432d4e511cSCy Schubert 17442d4e511cSCy Schubert /* 17452d4e511cSCy Schubert * ------------------------------------------------------------------- 17462d4e511cSCy Schubert * check if it makes sense to schedule an 'early' poll to get the clock 17472d4e511cSCy Schubert * up fast after start or longer signal dropout. 17482d4e511cSCy Schubert */ 17492d4e511cSCy Schubert static void 17502d4e511cSCy Schubert refclock_checkburst( 17512d4e511cSCy Schubert struct peer * peer, 17522d4e511cSCy Schubert struct refclockproc * pp 17532d4e511cSCy Schubert ) 17542d4e511cSCy Schubert { 17552d4e511cSCy Schubert uint32_t limit; /* when we should poll */ 17562d4e511cSCy Schubert u_int needs; /* needed number of samples */ 17572d4e511cSCy Schubert 17582d4e511cSCy Schubert /* Paranoia: stop here if peer and clockproc don't match up. 17592d4e511cSCy Schubert * And when a poll is actually pending, we don't have to do 17602d4e511cSCy Schubert * anything, either. Likewise if the reach mask is full, of 17612d4e511cSCy Schubert * course, and if the filter has stabilized. 17622d4e511cSCy Schubert */ 17632d4e511cSCy Schubert if (pp->inpoll || (peer->procptr != pp) || 17642d4e511cSCy Schubert ((peer->reach == 0xFF) && (peer->disp <= MAXDISTANCE))) 17652d4e511cSCy Schubert return; 17662d4e511cSCy Schubert 17672d4e511cSCy Schubert /* If the next poll is soon enough, bail out, too: */ 17682d4e511cSCy Schubert limit = current_time + 1; 17692d4e511cSCy Schubert if (peer->nextdate <= limit) 17702d4e511cSCy Schubert return; 17712d4e511cSCy Schubert 17722d4e511cSCy Schubert /* Derive the number of samples needed from the popcount of the 17732d4e511cSCy Schubert * reach mask. With less samples available, we break away. 17742d4e511cSCy Schubert */ 17752d4e511cSCy Schubert needs = peer->reach; 17762d4e511cSCy Schubert needs -= (needs >> 1) & 0x55; 17772d4e511cSCy Schubert needs = (needs & 0x33) + ((needs >> 2) & 0x33); 17782d4e511cSCy Schubert needs = (needs + (needs >> 4)) & 0x0F; 17792d4e511cSCy Schubert if (needs > 6) 17802d4e511cSCy Schubert needs = 6; 17812d4e511cSCy Schubert else if (needs < 3) 17822d4e511cSCy Schubert needs = 3; 17832d4e511cSCy Schubert if (clk_cnt_sample(pp) < needs) 17842d4e511cSCy Schubert return; 17852d4e511cSCy Schubert 17862d4e511cSCy Schubert /* Get serious. Reduce the poll to minimum and schedule early. 17872d4e511cSCy Schubert * (Changing the peer poll is probably in vain, as it will be 17882d4e511cSCy Schubert * re-adjusted, but maybe some time the hint will work...) 17892d4e511cSCy Schubert */ 17902d4e511cSCy Schubert peer->hpoll = peer->minpoll; 17912d4e511cSCy Schubert peer->nextdate = limit; 17922d4e511cSCy Schubert } 17932d4e511cSCy Schubert 17942d4e511cSCy Schubert /* 17952d4e511cSCy Schubert * ------------------------------------------------------------------- 17962d4e511cSCy Schubert * Save the last timecode string, making sure it's properly truncated 17972d4e511cSCy Schubert * if necessary and NUL terminated in any case. 17982d4e511cSCy Schubert */ 17992d4e511cSCy Schubert void 18002d4e511cSCy Schubert refclock_save_lcode( 18012d4e511cSCy Schubert struct refclockproc * pp, 18022d4e511cSCy Schubert char const * tc, 18032d4e511cSCy Schubert size_t len 18042d4e511cSCy Schubert ) 18052d4e511cSCy Schubert { 18062d4e511cSCy Schubert if (len == (size_t)-1) 18072d4e511cSCy Schubert len = strnlen(tc, sizeof(pp->a_lastcode) - 1); 18082d4e511cSCy Schubert else if (len >= sizeof(pp->a_lastcode)) 18092d4e511cSCy Schubert len = sizeof(pp->a_lastcode) - 1; 18102d4e511cSCy Schubert 18112d4e511cSCy Schubert pp->lencode = (u_short)len; 18122d4e511cSCy Schubert memcpy(pp->a_lastcode, tc, len); 18132d4e511cSCy Schubert pp->a_lastcode[len] = '\0'; 18142d4e511cSCy Schubert } 18152d4e511cSCy Schubert 18162d4e511cSCy Schubert /* format data into a_lastcode */ 18172d4e511cSCy Schubert void 18182d4e511cSCy Schubert refclock_vformat_lcode( 18192d4e511cSCy Schubert struct refclockproc * pp, 18202d4e511cSCy Schubert char const * fmt, 18212d4e511cSCy Schubert va_list va 18222d4e511cSCy Schubert ) 18232d4e511cSCy Schubert { 18242d4e511cSCy Schubert long len; 18252d4e511cSCy Schubert 18262d4e511cSCy Schubert len = vsnprintf(pp->a_lastcode, sizeof(pp->a_lastcode), fmt, va); 1827*f5f40dd6SCy Schubert if (len <= 0) { 18282d4e511cSCy Schubert len = 0; 1829*f5f40dd6SCy Schubert } else if (len >= sizeof(pp->a_lastcode)) { 18302d4e511cSCy Schubert len = sizeof(pp->a_lastcode) - 1; 1831*f5f40dd6SCy Schubert } 18322d4e511cSCy Schubert 18332d4e511cSCy Schubert pp->lencode = (u_short)len; 18342d4e511cSCy Schubert pp->a_lastcode[len] = '\0'; 18352d4e511cSCy Schubert /* !note! the NUL byte is needed in case vsnprintf() really fails */ 18362d4e511cSCy Schubert } 18372d4e511cSCy Schubert 18382d4e511cSCy Schubert void 18392d4e511cSCy Schubert refclock_format_lcode( 18402d4e511cSCy Schubert struct refclockproc * pp, 18412d4e511cSCy Schubert char const * fmt, 18422d4e511cSCy Schubert ... 18432d4e511cSCy Schubert ) 18442d4e511cSCy Schubert { 18452d4e511cSCy Schubert va_list va; 18462d4e511cSCy Schubert 18472d4e511cSCy Schubert va_start(va, fmt); 18482d4e511cSCy Schubert refclock_vformat_lcode(pp, fmt, va); 18492d4e511cSCy Schubert va_end(va); 18502d4e511cSCy Schubert } 18512d4e511cSCy Schubert 1852c0b746e5SOllivier Robert #endif /* REFCLOCK */ 1853