📄 refclock_irig.c
字号:
/* * Pulse code demodulator and reference timestamp. The decoder * looks for a sequence of ten bits; the first two bits must be * one, the last two bits must be zero. Frame synch is asserted * when three correct frames have been found. */ up->pulse = (up->pulse + 1) % 10; if (up->pulse == 1) up->envmax = env; else if (up->pulse == 9) up->envmin = env; up->dcycles <<= 1; if (env >= (up->envmax + up->envmin) / 2.) up->dcycles |= 1; up->cycles <<= 1; if (lope >= (up->maxsignal + up->noise) / 2.) up->cycles |= 1; if ((up->cycles & 0x303c0f03) == 0x300c0300) { l_fp ltemp; int bitz; /* * The PLL time constant starts out small, in order to * sustain a frequency tolerance of 250 PPM. It * gradually increases as the loop settles down. Note * that small wiggles are not believed, unless they * persist for lots of samples. */ if (up->pulse != 9) up->errflg |= IRIG_ERR_SYNCH; up->pulse = 9; up->exing = -up->yxing; if (fabs(up->envxing - up->envphase) <= 1) { up->tcount++; if (up->tcount > 50 * up->tc) { up->tc++; if (up->tc > MAXTC) up->tc = MAXTC; up->tcount = 0; up->envxing = up->envphase; } else { up->exing -= up->envxing - up->envphase; } } else { up->tcount = 0; up->envxing = up->envphase; } /* * Determine a reference timestamp, accounting for the * codec delay and filter delay. Note the timestamp is * for the previous frame, so we have to backtrack for * this plus the delay since the last carrier positive * zero crossing. */ dtemp = up->decim * ((up->exing + BAUD) / SECOND + 1.) + up->fdelay; DTOLFP(dtemp, <emp); pp->lastrec = up->timestamp; L_SUB(&pp->lastrec, <emp); /* * The data bits are collected in ten-bit frames. The * first two and last two bits are determined by frame * sync and ignored here; the resulting patterns * represent zero (0-1 bits), one (2-4 bits) and * position identifier (5-6 bits). The remaining * patterns represent errors and are treated as zeros. */ bitz = up->dcycles & 0xfc; switch(bitz) { case 0x00: case 0x80: irig_decode(peer, BIT0); break; case 0xc0: case 0xe0: case 0xf0: irig_decode(peer, BIT1); break; case 0xf8: case 0xfc: irig_decode(peer, BITP); break; default: irig_decode(peer, 0); up->errflg |= IRIG_ERR_DECODE; } }}/* * irig_decode - decode the data * * This routine assembles bits into digits, digits into subfields and * subfields into the timecode field. Bits can have values of zero, one * or position identifier. There are four bits per digit, two digits per * subfield and ten subfields per field. The last bit in every subfield * and the first bit in the first subfield are position identifiers. */static voidirig_decode( struct peer *peer, /* peer structure pointer */ int bit /* data bit (0, 1 or 2) */ ){ struct refclockproc *pp; struct irigunit *up;#ifdef IRIG_SUCKS int i;#endif /* IRIG_SUCKS */ /* * Local variables */ char syncchar; /* sync character (Spectracom) */ char sbs[6]; /* binary seconds since 0h */ char spare[2]; /* mulligan digits */ pp = peer->procptr; up = (struct irigunit *)pp->unitptr; /* * Assemble subfield bits. */ up->bits <<= 1; if (bit == BIT1) { up->bits |= 1; } else if (bit == BITP && up->lastbit == BITP) { /* * Frame sync - two adjacent position identifiers. * Monitor the reference timestamp and wiggle the * clock, but only if no errors have occurred. */ up->bitcnt = 1; up->fieldcnt = 0; up->lastbit = 0; if (up->errflg == 0) {#ifdef IRIG_SUCKS l_fp ltemp; /* * You really don't wanna know what comes down * here. Leave it to say Solaris 2.8 broke the * nice clean audio stream, apparently affected * by a 5-ms sawtooth jitter. Sundown on * Solaris. This leaves a little twilight. * * The scheme involves differentiation, forward * learning and integration. The sawtooth has a * period of 11 seconds. The timestamp * differences are integrated and subtracted * from the signal. */ ltemp = pp->lastrec; L_SUB(<emp, &pp->lastref); if (ltemp.l_f < 0) ltemp.l_i = -1; else ltemp.l_i = 0; pp->lastref = pp->lastrec; if (!L_ISNEG(<emp)) L_CLR(&up->wigwag); else L_ADD(&up->wigwag, <emp); L_SUB(&pp->lastrec, &up->wigwag); up->wiggle[up->wp] = ltemp; /* * Bottom fisher. To understand this, you have * to know about velocity microphones and AM * transmitters. No further explanation is * offered, as this is truly a black art. */ up->wigbot[up->wp] = pp->lastrec; for (i = 0; i < WIGGLE; i++) { if (i != up->wp) up->wigbot[i].l_ui++; L_SUB(&pp->lastrec, &up->wigbot[i]); if (L_ISNEG(&pp->lastrec)) L_ADD(&pp->lastrec, &up->wigbot[i]); else pp->lastrec = up->wigbot[i]; } up->wp++; up->wp %= WIGGLE; up->wuggle = pp->lastrec; refclock_process(pp);#else /* IRIG_SUCKS */ pp->lastref = pp->lastrec; up->wuggle = pp->lastrec; refclock_process(pp);#endif /* IRIG_SUCKS */ } up->errflg = 0; } up->bitcnt = (up->bitcnt + 1) % SUBFLD; if (up->bitcnt == 0) { /* * End of subfield. Encode two hexadecimal digits in * little-endian timecode field. */ if (up->fieldcnt == 0) up->bits <<= 1; if (up->xptr < 2) up->xptr = 2 * FIELD; up->timecode[--up->xptr] = hexchar[(up->bits >> 5) & 0xf]; up->timecode[--up->xptr] = hexchar[up->bits & 0xf]; up->fieldcnt = (up->fieldcnt + 1) % FIELD; if (up->fieldcnt == 0) { /* * End of field. Decode the timecode and wind * the clock. Not all IRIG generators have the * year; if so, it is nonzero after year 2000. * Not all have the hardware status bit; if so, * it is lit when the source is okay and dim * when bad. We watch this only if the year is * nonzero. Not all are configured for signature * control. If so, all BCD digits are set to * zero if the source is bad. In this case the * refclock_process() will reject the timecode * as invalid. */ up->xptr = 2 * FIELD; if (sscanf((char *)up->timecode, "%6s%2d%c%2s%3d%2d%2d%2d", sbs, &pp->year, &syncchar, spare, &pp->day, &pp->hour, &pp->minute, &pp->second) != 8) pp->leap = LEAP_NOTINSYNC; else pp->leap = LEAP_NOWARNING; up->second = (up->second + up->decim) % 60; if (pp->year > 0) pp->year += 2000; if (pp->second != up->second) up->errflg |= IRIG_ERR_CHECK; up->second = pp->second; sprintf(pp->a_lastcode, "%02x %c %2d %3d %02d:%02d:%02d %4.0f %3d %6.3f %2d %6.1f %6.1f %s", up->errflg, syncchar, pp->year, pp->day, pp->hour, pp->minute, pp->second, up->maxsignal, up->gain, up->modndx, up->tc, up->exing * 1e6 / SECOND, up->freq * 1e6 / SECOND, ulfptoa(&up->wuggle, 6)); pp->lencode = strlen(pp->a_lastcode); if (pp->sloppyclockflag & CLK_FLAG4) { record_clock_stats(&peer->srcadr, pp->a_lastcode);#ifdef DEBUG if (debug) printf("irig: %s\n", pp->a_lastcode);#endif /* DEBUG */ } } } up->lastbit = bit;}/* * irig_poll - called by the transmit procedure * * This routine sweeps up the timecode updates since the last poll. For * IRIG-B there should be at least 60 updates; for IRIG-E there should * be at least 6. If nothing is heard, a timeout event is declared and * any orphaned timecode updates are sent to foster care. */static voidirig_poll( int unit, /* instance number (not used) */ struct peer *peer /* peer structure pointer */ ){ struct refclockproc *pp; struct irigunit *up; pp = peer->procptr; up = (struct irigunit *)pp->unitptr; if (pp->coderecv == pp->codeproc) { refclock_report(peer, CEVNT_TIMEOUT); return; } else { refclock_receive(peer); record_clock_stats(&peer->srcadr, pp->a_lastcode);#ifdef DEBUG if (debug) printf("irig: %s\n", pp->a_lastcode);#endif /* DEBUG */ } pp->polls++; }/* * irig_gain - adjust codec gain * * This routine is called once each second. If the signal envelope * amplitude is too low, the codec gain is bumped up by four units; if * too high, it is bumped down. The decoder is relatively insensitive to * amplitude, so this crudity works just fine. The input port is set and * the error flag is cleared, mostly to be ornery. */static voidirig_gain( struct peer *peer /* peer structure pointer */ ){ struct refclockproc *pp; struct irigunit *up; pp = peer->procptr; up = (struct irigunit *)pp->unitptr; /* * Apparently, the codec uses only the high order bits of the * gain control field. Thus, it may take awhile for changes to * wiggle the hardware bits. */ if (up->clipcnt == 0) { up->gain += 4; if (up->gain > MAXGAIN) up->gain = MAXGAIN; } else if (up->clipcnt > MAXCLP) { up->gain -= 4; if (up->gain < 0) up->gain = 0; } audio_gain(up->gain, up->mongain, up->port); up->clipcnt = 0;}#elseint refclock_irig_bs;#endif /* REFCLOCK */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -