int refclock_process( struct refclockproc *pp /* refclock structure pointer */ ) { return refclock_process_f(pp, pp->fudgetime1); }
/* * wwvb_receive - receive data from the serial interface */ static void wwvb_receive( struct recvbuf *rbufp ) { struct wwvbunit *up; struct refclockproc *pp; struct peer *peer; l_fp trtmp; /* arrival timestamp */ int tz; /* time zone */ int day, month; /* ddd conversion */ int temp; /* int temp */ char syncchar; /* synchronization indicator */ char qualchar; /* quality indicator */ char leapchar; /* leap indicator */ char dstchar; /* daylight/standard indicator */ char tmpchar; /* trashbin */ /* * Initialize pointers and read the timecode and timestamp */ peer = rbufp->recv_peer; pp = peer->procptr; up = pp->unitptr; temp = refclock_gtlin(rbufp, pp->a_lastcode, BMAX, &trtmp); /* * Note we get a buffer and timestamp for both a <cr> and <lf>, * but only the <cr> timestamp is retained. Note: in format 0 on * a Netclock/2 or upgraded 8170 the start bit is delayed 100 * +-50 us relative to the pps; however, on an unmodified 8170 * the start bit can be delayed up to 10 ms. In format 2 the * reading precision is only to the millisecond. Thus, unless * you have a PPS gadget and don't have to have the year, format * 0 provides the lowest jitter. * Save the timestamp of each <CR> in up->laststamp. Lines with * no characters occur for every <LF>, and for some <CR>s when * format 0 is used. Format 0 starts and ends each cycle with a * <CR><LF> pair, format 2 starts each cycle with its only pair. * The preceding <CR> is the on-time character for both formats. * The timestamp provided with non-empty lines corresponds to * the <CR> following the timecode, which is ultimately not used * with format 0 and is used for the following timecode for * format 2. */ if (temp == 0) { if (up->prev_eol_cr) { DPRINTF(2, ("wwvb: <LF> @ %s\n", prettydate(&trtmp))); } else { up->laststamp = trtmp; DPRINTF(2, ("wwvb: <CR> @ %s\n", prettydate(&trtmp))); } up->prev_eol_cr = !up->prev_eol_cr; return; } pp->lencode = temp; pp->lastrec = up->laststamp; up->laststamp = trtmp; up->prev_eol_cr = TRUE; DPRINTF(2, ("wwvb: code @ %s\n" " using %s minus one char\n", prettydate(&trtmp), prettydate(&pp->lastrec))); if (L_ISZERO(&pp->lastrec)) return; /* * We get down to business, check the timecode format and decode * its contents. This code uses the timecode length to determine * format 0, 2 or 3. If the timecode has invalid length or is * not in proper format, we declare bad format and exit. */ syncchar = qualchar = leapchar = dstchar = ' '; tz = 0; switch (pp->lencode) { case LENWWVB0: /* * Timecode format 0: "I ddd hh:mm:ss DTZ=nn" */ if (sscanf(pp->a_lastcode, "%c %3d %2d:%2d:%2d%c%cTZ=%2d", &syncchar, &pp->day, &pp->hour, &pp->minute, &pp->second, &tmpchar, &dstchar, &tz) == 8) { pp->nsec = 0; break; } goto bad_format; case LENWWVB2: /* * Timecode format 2: "IQyy ddd hh:mm:ss.mmm LD" */ if (sscanf(pp->a_lastcode, "%c%c %2d %3d %2d:%2d:%2d.%3ld %c", &syncchar, &qualchar, &pp->year, &pp->day, &pp->hour, &pp->minute, &pp->second, &pp->nsec, &leapchar) == 9) { pp->nsec *= 1000000; break; } goto bad_format; case LENWWVB3: /* * Timecode format 3: "0003I yyyymmdd hhmmss+0000SL#" * WARNING: Undocumented, and the on-time character # is * not yet handled correctly by this driver. It may be * as simple as compensating for an additional 1/960 s. */ if (sscanf(pp->a_lastcode, "0003%c %4d%2d%2d %2d%2d%2d+0000%c%c", &syncchar, &pp->year, &month, &day, &pp->hour, &pp->minute, &pp->second, &dstchar, &leapchar) == 8) { pp->day = ymd2yd(pp->year, month, day); pp->nsec = 0; break; } goto bad_format; default: bad_format: /* * Unknown format: If dumping internal table, record * stats; otherwise, declare bad format. */ if (up->linect > 0) { up->linect--; record_clock_stats(&peer->srcadr, pp->a_lastcode); } else { refclock_report(peer, CEVNT_BADREPLY); } return; } /* * Decode synchronization, quality and leap characters. If * unsynchronized, set the leap bits accordingly and exit. * Otherwise, set the leap bits according to the leap character. * Once synchronized, the dispersion depends only on the * quality character. */ switch (qualchar) { case ' ': pp->disp = .001; pp->lastref = pp->lastrec; break; case 'A': pp->disp = .01; break; case 'B': pp->disp = .1; break; case 'C': pp->disp = .5; break; case 'D': pp->disp = MAXDISPERSE; break; default: pp->disp = MAXDISPERSE; refclock_report(peer, CEVNT_BADREPLY); break; } if (syncchar != ' ') pp->leap = LEAP_NOTINSYNC; else if (leapchar == 'L') pp->leap = LEAP_ADDSECOND; else pp->leap = LEAP_NOWARNING; /* * Process the new sample in the median filter and determine the * timecode timestamp, but only if the PPS is not in control. */ #ifdef HAVE_PPSAPI up->tcount++; if (peer->flags & FLAG_PPS) return; #endif /* HAVE_PPSAPI */ if (!refclock_process_f(pp, pp->fudgetime2)) refclock_report(peer, CEVNT_BADTIME); }