📄 refclock_chu.c
字号:
}/* * chu_uart - maximum likelihood UART * * This routine updates a shift register holding the last 11 envelope * samples. It then computes the slice level and span over these samples * and determines the tentative data bits and distance. The calling * program selects over the last eight survivors the one with maximum * distance to determine the decoded character. */static voidchu_uart( struct surv *sp, /* survivor structure pointer */ double sample /* baseband signal */ ){ double es_max, es_min; /* max/min envelope */ double slice; /* slice level */ double dist; /* distance */ double dtemp; int i; /* * Save the sample and shift right. At the same time, measure * the maximum and minimum over all eleven samples. */ es_max = -1e6; es_min = 1e6; sp->shift[0] = sample; for (i = 11; i > 0; i--) { sp->shift[i] = sp->shift[i - 1]; if (sp->shift[i] > es_max) es_max = sp->shift[i]; if (sp->shift[i] < es_min) es_min = sp->shift[i]; } /* * Determine the slice level midway beteen the maximum and * minimum and the span as the maximum less the minimum. Compute * the distance on the assumption the first and last bits must * be mark, the second space and the rest either mark or space. */ slice = (es_max + es_min) / 2.; dist = 0; sp->uart = 0; for (i = 1; i < 12; i++) { sp->uart <<= 1; dtemp = sp->shift[i]; if (dtemp > slice) sp->uart |= 0x1; if (i == 1 || i == 11) { dist += dtemp - es_min; } else if (i == 10) { dist += es_max - dtemp; } else { if (dtemp > slice) dist += dtemp - es_min; else dist += es_max - dtemp; } } sp->es_max = es_max; sp->es_min = es_min; sp->dist = dist / (11 * (es_max - es_min));}#endif /* HAVE_AUDIO *//* * chu_serial_receive - receive data from the serial device */static voidchu_serial_receive( struct recvbuf *rbufp /* receive buffer structure pointer */ ){ struct chuunit *up; struct refclockproc *pp; struct peer *peer; u_char *dpt; /* receive buffer pointer */ peer = (struct peer *)rbufp->recv_srcclock; pp = peer->procptr; up = (struct chuunit *)pp->unitptr; /* * Initialize pointers and read the timecode and timestamp. */ up->timestamp = rbufp->recv_time; dpt = (u_char *)&rbufp->recv_space; chu_decode(peer, *dpt);}/* * chu_decode - decode the character data */static voidchu_decode( struct peer *peer, /* peer structure pointer */ int hexhex /* data character */ ){ struct refclockproc *pp; struct chuunit *up; l_fp tstmp; /* timestamp temp */ double dtemp; pp = peer->procptr; up = (struct chuunit *)pp->unitptr; /* * If the interval since the last character is greater than the * longest burst, process the last burst and start a new one. If * the interval is less than this but greater than two * characters, consider this a noise burst and reject it. */ tstmp = up->timestamp; if (L_ISZERO(&up->laststamp)) up->laststamp = up->timestamp; L_SUB(&tstmp, &up->laststamp); up->laststamp = up->timestamp; LFPTOD(&tstmp, dtemp); if (dtemp > BURST * CHAR) { chu_burst(peer); up->ndx = 0; } else if (dtemp > 2.5 * CHAR) { up->ndx = 0; } /* * Append the character to the current burst and append the * timestamp to the timestamp list. */ if (up->ndx < BURST) { up->cbuf[up->ndx] = hexhex & 0xff; up->cstamp[up->ndx] = up->timestamp; up->ndx++; }}/* * chu_burst - search for valid burst format */static voidchu_burst( struct peer *peer ){ struct chuunit *up; struct refclockproc *pp; int i; pp = peer->procptr; up = (struct chuunit *)pp->unitptr; /* * Correlate a block of five characters with the next block of * five characters. The burst distance is defined as the number * of bits that match in the two blocks for format A and that * match the inverse for format B. */ if (up->ndx < MINCHAR) { up->status |= RUNT; return; } up->burdist = 0; for (i = 0; i < 5 && i < up->ndx - 5; i++) up->burdist += chu_dist(up->cbuf[i], up->cbuf[i + 5]); /* * If the burst distance is at least MINDIST, this must be a * format A burst; if the value is not greater than -MINDIST, it * must be a format B burst. If the B burst is perfect, we * believe it; otherwise, it is a noise burst and of no use to * anybody. */ if (up->burdist >= MINDIST) { chu_a(peer, up->ndx); } else if (up->burdist <= -MINDIST) { chu_b(peer, up->ndx); } else { up->status |= NOISE; return; } /* * If this is a valid burst, wait a guard time of ten seconds to * allow for more bursts, then arm the poll update routine to * process the minute. Don't do this if this is called from the * timer interrupt routine. */ if (peer->outdate != current_time) peer->nextdate = current_time + 10;}/* * chu_b - decode format B burst */static voidchu_b( struct peer *peer, int nchar ){ struct refclockproc *pp; struct chuunit *up; u_char code[11]; /* decoded timecode */ char tbuf[80]; /* trace buffer */ l_fp offset; /* timestamp offset */ int i; pp = peer->procptr; up = (struct chuunit *)pp->unitptr; /* * In a format B burst, a character is considered valid only if * the first occurrence matches the last occurrence. The burst * is considered valid only if all characters are valid; that * is, only if the distance is 40. Note that once a valid frame * has been found errors are ignored. */ sprintf(tbuf, "chuB %04x %2d %2d ", up->status, nchar, -up->burdist); for (i = 0; i < nchar; i++) sprintf(&tbuf[strlen(tbuf)], "%02x", up->cbuf[i]); if (pp->sloppyclockflag & CLK_FLAG4) record_clock_stats(&peer->srcadr, tbuf);#ifdef DEBUG if (debug) printf("%s\n", tbuf);#endif if (up->burdist > -40) { up->status |= BFRAME; return; } up->status |= BVALID; /* * Convert the burst data to internal format. If this succeeds, * save the timestamps for later. */ for (i = 0; i < 5; i++) { code[2 * i] = hexchar[up->cbuf[i] & 0xf]; code[2 * i + 1] = hexchar[(up->cbuf[i] >> 4) & 0xf]; } if (sscanf((char *)code, "%1x%1d%4d%2d%2x", &up->leap, &up->dut, &pp->year, &up->tai, &up->dst) != 5) { up->status |= BFORMAT; return; } if (up->leap & 0x8) up->dut = -up->dut; offset.l_ui = 31; offset.l_f = 0; for (i = 0; i < nchar && i < 10; i++) { up->tstamp[up->ntstamp] = up->cstamp[i]; L_SUB(&up->tstamp[up->ntstamp], &offset); L_ADD(&offset, &up->charstamp); if (up->ntstamp < MAXSTAGE) up->ntstamp++; }}/* * chu_a - decode format A burst */static voidchu_a( struct peer *peer, int nchar ){ struct refclockproc *pp; struct chuunit *up; char tbuf[80]; /* trace buffer */ l_fp offset; /* timestamp offset */ int val; /* distance */ int temp; int i, j, k; pp = peer->procptr; up = (struct chuunit *)pp->unitptr; /* * Determine correct burst phase. There are three cases * corresponding to in-phase, one character early or one * character late. These cases are distinguished by the position * of the framing digits x6 at positions 0 and 5 and x3 at * positions 4 and 9. The correct phase is when the distance * relative to the framing digits is maximum. The burst is valid * only if the maximum distance is at least MINSYNC. */ up->syndist = k = 0; val = -16; for (i = -1; i < 2; i++) { temp = up->cbuf[i + 4] & 0xf; if (i >= 0) temp |= (up->cbuf[i] & 0xf) << 4; val = chu_dist(temp, 0x63); temp = (up->cbuf[i + 5] & 0xf) << 4; if (i + 9 < nchar) temp |= up->cbuf[i + 9] & 0xf; val += chu_dist(temp, 0x63); if (val > up->syndist) { up->syndist = val; k = i; } } temp = (up->cbuf[k + 4] >> 4) & 0xf; if (temp > 9 || k + 9 >= nchar || temp != ((up->cbuf[k + 9] >> 4) & 0xf)) temp = 0;#ifdef HAVE_AUDIO if (up->fd_audio) sprintf(tbuf, "chuA %04x %4.0f %2d %2d %2d %2d %1d ", up->status, up->maxsignal, nchar, up->burdist, k, up->syndist, temp); else sprintf(tbuf, "chuA %04x %2d %2d %2d %2d %1d ", up->status, nchar, up->burdist, k, up->syndist, temp);#else sprintf(tbuf, "chuA %04x %2d %2d %2d %2d %1d ", up->status, nchar, up->burdist, k, up->syndist, temp);#endif /* HAVE_AUDIO */ for (i = 0; i < nchar; i++) sprintf(&tbuf[strlen(tbuf)], "%02x", up->cbuf[i]); if (pp->sloppyclockflag & CLK_FLAG4) record_clock_stats(&peer->srcadr, tbuf);#ifdef DEBUG if (debug) printf("%s\n", tbuf);#endif if (up->syndist < MINSYNC) { up->status |= AFRAME; return; } /* * A valid burst requires the first seconds number to match the * last seconds number. If so, the burst timestamps are * corrected to the current minute and saved for later * processing. In addition, the seconds decode is advanced from * the previous burst to the current one. */ if (temp != 0) { pp->second = 30 + temp; offset.l_ui = 30 + temp; offset.l_f = 0; i = 0; if (k < 0) offset = up->charstamp; else if (k > 0) i = 1; for (; i < nchar && i < k + 10; i++) { up->tstamp[up->ntstamp] = up->cstamp[i]; L_SUB(&up->tstamp[up->ntstamp], &offset); L_ADD(&offset, &up->charstamp); if (up->ntstamp < MAXSTAGE) up->ntstamp++; } while (temp > up->prevsec) { for (j = 15; j > 0; j--) { up->decode[9][j] = up->decode[9][j - 1]; up->decode[19][j] = up->decode[19][j - 1]; } up->decode[9][j] = up->decode[19][j] = 0; up->prevsec++; } } i = -(2 * k); for (j = 0; j < nchar; j++) { if (i < 0 || i > 19) { i += 2; continue; } up->decode[i][up->cbuf[j] & 0xf]++; i++; up->decode[i][(up->cbuf[j] >> 4) & 0xf]++; i++; } up->status |= AVALID; up->burstcnt++;}/* * chu_poll - called by the transmit procedure */static voidchu_poll( int unit, struct peer *peer /* peer structure pointer */ ){ struct refclockproc *pp; struct chuunit *up; l_fp offset; char synchar, qual, leapchar; int minset, i; double dtemp; pp = peer->procptr; up = (struct chuunit *)pp->unitptr; if (pp->coderecv == pp->codeproc)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -