📄 refclock_chu.c
字号:
up->errflg = CEVNT_TIMEOUT; else pp->polls++; /* * If once in sync and the radio has not been heard for awhile * (30 m), it is no longer reachable. If not heard in a long * while (one day), turn out the lights and start from scratch. */ minset = ((current_time - peer->update) + 30) / 60; if (up->status & INSYNC) { if (minset > PANIC) up->status = 0; else if (minset <= HOLD) peer->reach |= 1; } /* * Process the last burst, if still in the burst buffer. * Don't mess with anything if nothing has been heard. If the * minute contains a valid A frame and valid B frame, assume * synchronized; however, believe the time only if within metric * threshold. Note the quality indicator is only for * diagnostics; the data are used only if in sync and above * metric threshold. */ chu_burst(peer); if (up->burstcnt == 0) {#ifdef ICOM chu_newchan(peer, 0);#endif /* ICOM */ return; } dtemp = chu_major(peer); qual = 0; if (up->status & (BFRAME | AFRAME)) qual |= SYNERR; if (up->status & (BFORMAT | AFORMAT)) qual |= FMTERR; if (up->status & DECODE) qual |= DECERR; if (up->status & STAMP) qual |= TSPERR; if (up->status & AVALID && up->status & BVALID) up->status |= INSYNC; synchar = leapchar = ' '; if (!(up->status & INSYNC)) { pp->leap = LEAP_NOTINSYNC; synchar = '?'; } else if (up->leap & 0x2) { pp->leap = LEAP_ADDSECOND; leapchar = 'L'; } else if (up->leap & 0x4) { pp->leap = LEAP_DELSECOND; leapchar = 'l'; } else { pp->leap = LEAP_NOWARNING; }#ifdef HAVE_AUDIO if (up->fd_audio) sprintf(pp->a_lastcode, "%c%1X %04d %3d %02d:%02d:%02d %c%x %+d %d %d %s %.0f %d", synchar, qual, pp->year, pp->day, pp->hour, pp->minute, pp->second, leapchar, up->dst, up->dut, minset, up->gain, up->ident, dtemp, up->ntstamp); else sprintf(pp->a_lastcode, "%c%1X %04d %3d %02d:%02d:%02d %c%x %+d %d %s %.0f %d", synchar, qual, pp->year, pp->day, pp->hour, pp->minute, pp->second, leapchar, up->dst, up->dut, minset, up->ident, dtemp, up->ntstamp);#else sprintf(pp->a_lastcode, "%c%1X %04d %3d %02d:%02d:%02d %c%x %+d %d %s %.0f %d", synchar, qual, pp->year, pp->day, pp->hour, pp->minute, pp->second, leapchar, up->dst, up->dut, minset, up->ident, dtemp, up->ntstamp);#endif /* HAVE_AUDIO */ pp->lencode = strlen(pp->a_lastcode); /* * If in sync and the signal metric is above threshold, the * timecode is ipso fatso valid and can be selected to * discipline the clock. Be sure not to leave stray timestamps * around if signals are too weak or the clock time is invalid. */ if (up->status & INSYNC && dtemp > METRIC) { if (!clocktime(pp->day, pp->hour, pp->minute, 0, GMT, up->tstamp[0].l_ui, &pp->yearstart, &offset.l_ui)) { up->errflg = CEVNT_BADTIME; } else { offset.l_uf = 0; for (i = 0; i < up->ntstamp; i++) refclock_process_offset(pp, offset, up->tstamp[i], FUDGE + pp->fudgetime1); pp->lastref = up->timestamp; refclock_receive(peer); } record_clock_stats(&peer->srcadr, pp->a_lastcode); } else if (pp->sloppyclockflag & CLK_FLAG4) { record_clock_stats(&peer->srcadr, pp->a_lastcode); }#ifdef DEBUG if (debug) printf("chu: timecode %d %s\n", pp->lencode, pp->a_lastcode);#endif#ifdef ICOM chu_newchan(peer, dtemp);#endif /* ICOM */ chu_clear(peer); if (up->errflg) refclock_report(peer, up->errflg); up->errflg = 0;}/* * chu_major - majority decoder */static doublechu_major( struct peer *peer /* peer structure pointer */ ){ struct refclockproc *pp; struct chuunit *up; u_char code[11]; /* decoded timecode */ int mindist; /* minimum distance */ int val1, val2; /* maximum distance */ int synchar; /* stray cat */ int temp; int i, j, k; pp = peer->procptr; up = (struct chuunit *)pp->unitptr; /* * Majority decoder. Each burst encodes two replications at each * digit position in the timecode. Each row of the decoding * matrix encodes the number of occurrences of each digit found * at the corresponding position. The maximum over all * occurrences at each position is the distance for this * position and the corresponding digit is the maximum * likelihood candidate. If the distance is zero, assume a miss * '_'; if the distance is not more than half the total number * of occurrences, assume a soft error '*'; if two different * digits with the same distance are found, assume a hard error * '='. These will later cause a format error when the timecode * is interpreted. The decoding distance is defined as the * minimum distance over the first nine digits. The tenth digit * varies over the seconds, so we don't count it. */ mindist = 16; for (i = 0; i < 9; i++) { val1 = val2 = 0; k = 0; for (j = 0; j < 16; j++) { temp = up->decode[i][j] + up->decode[i + 10][j]; if (temp > val1) { val2 = val1; val1 = temp; k = j; } } if (val1 == 0) code[i] = HEX_MISS; else if (val1 == val2) code[i] = HEX_HARD; else if (val1 <= up->burstcnt) code[i] = HEX_SOFT; else code[i] = k; if (val1 < mindist) mindist = val1; code[i] = hexchar[code[i]]; } code[i] = 0; /* * A valid timecode requires a minimum distance at least half * the total number of occurrences. A valid timecode also * requires at least 20 valid timestamps. */ if (up->burstcnt < MINBURST || mindist < up->burstcnt) up->status |= DECODE; if (up->ntstamp < MINSTAMP) up->status |= STAMP; /* * Compute the timecode timestamp from the days, hours and * minutes of the timecode. Use clocktime() for the aggregate * minutes and the minute offset computed from the burst * seconds. Note that this code relies on the filesystem time * for the years and does not use the years of the timecode. */ if (sscanf((char *)code, "%1x%3d%2d%2d", &synchar, &pp->day, &pp->hour, &pp->minute) != 4) { up->status |= AFORMAT; return (0); } if (up->status & (DECODE | STAMP)) { up->errflg = CEVNT_BADREPLY; return (0); } return (mindist * 100. / (2. * up->burstcnt));}/* * chu_clear - clear decoding matrix */static voidchu_clear( struct peer *peer /* peer structure pointer */ ){ struct refclockproc *pp; struct chuunit *up; int i, j; pp = peer->procptr; up = (struct chuunit *)pp->unitptr; /* * Clear stuff for the minute. */ up->ndx = up->prevsec = 0; up->burstcnt = up->ntstamp = 0; up->status &= INSYNC; for (i = 0; i < 20; i++) { for (j = 0; j < 16; j++) up->decode[i][j] = 0; }}#ifdef ICOM/* * chu_newchan - called once per minute to find the best channel; * returns zero on success, nonzero if ICOM error. */static intchu_newchan( struct peer *peer, double met ){ struct chuunit *up; struct refclockproc *pp; struct xmtr *sp; char tbuf[80]; /* trace buffer */ int rval; double metric; int i, j; pp = peer->procptr; up = (struct chuunit *)pp->unitptr; /* * The radio can be tuned to three channels: 0 (3330 kHz), 1 * (7335 kHz) and 2 (14670 kHz). There are five one-minute * dwells in each cycle. During the first dwell the radio is * tuned to one of three probe channels; during the remaining * four dwells the radio is tuned to the data channel. The probe * channel is selects as the least recently used. At the end of * each dwell the channel metrics are measured and the highest * one is selected as the data channel. */ if (up->fd_icom <= 0) return (0); sp = &up->xmtr[up->achan]; sp->metric -= sp->integ[sp->iptr]; sp->integ[sp->iptr] = met; sp->metric += sp->integ[sp->iptr]; sp->iptr = (sp->iptr + 1) % ISTAGE; metric = 0; j = 0; for (i = 0; i < NCHAN; i++) { up->xmtr[i].probe++; if (i == up->achan) up->xmtr[i].probe = 0; if (up->xmtr[i].metric < metric) continue; metric = up->xmtr[i].metric; j = i; } if (j != up->chan && metric > 0) { up->chan = j; sprintf(tbuf, "chu: QSY to %.3f MHz metric %.0f", qsy[up->chan], metric); if (pp->sloppyclockflag & CLK_FLAG4) record_clock_stats(&peer->srcadr, tbuf);#ifdef DEBUG if (debug) printf("%s\n", tbuf);#endif } /* * Start the next dwell. We speed up the initial sync a little. * If not in sync and no bursts were heard the previous dwell, * restart the probe. */ rval = 0; if (up->burstcnt == 0 && !(up->status & INSYNC)) up->dwell = 0;#ifdef DEBUG if (debug) printf( "chu: at %ld dwell %d achan %d metric %.0f chan %d\n", current_time, up->dwell, up->achan, sp->metric, up->chan);#endif if (up->dwell == 0) { rval = 0; for (i = 0; i < NCHAN; i++) { if (up->xmtr[i].probe < rval) continue; rval = up->xmtr[i].probe; up->achan = i; } rval = icom_freq(up->fd_icom, peer->ttl & 0x7f, qsy[up->achan] + TUNE);#ifdef DEBUG if (debug) printf("chu: at %ld probe channel %d\n", current_time, up->achan);#endif } else { if (up->achan != up->chan) { rval = icom_freq(up->fd_icom, peer->ttl & 0x7f, qsy[up->chan] + TUNE); up->achan = up->chan; } } sprintf(up->ident, "CHU%d", up->achan); memcpy(&peer->refid, up->ident, 4); up->dwell = (up->dwell + 1) % DWELL; return (rval);}#endif /* ICOM *//* * chu_dist - determine the distance of two octet arguments */static intchu_dist( int x, /* an octet of bits */ int y /* another octet of bits */ ){ int val; /* bit count */ int temp; int i; /* * The distance is determined as the weight of the exclusive OR * of the two arguments. The weight is determined by the number * of one bits in the result. Each one bit increases the weight, * while each zero bit decreases it. */ temp = x ^ y; val = 0; for (i = 0; i < 8; i++) { if ((temp & 0x1) == 0) val++; else val--; temp >>= 1; } return (val);}#ifdef HAVE_AUDIO/* * chu_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 voidchu_gain( struct peer *peer /* peer structure pointer */ ){ struct refclockproc *pp; struct chuunit *up; pp = peer->procptr; up = (struct chuunit *)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;}#endif /* HAVE_AUDIO */#elseint refclock_chu_bs;#endif /* REFCLOCK */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -