📄 refclock_wwv.c
字号:
* DST decode (DST2 DST1) for prettyprint */char dstcod[] = { 'S', /* 00 standard time */ 'I', /* 01 set clock ahead at 0200 local */ 'O', /* 10 set clock back at 0200 local */ 'D' /* 11 daylight time */};/* * The decoding matrix consists of nine row vectors, one for each digit * of the timecode. The digits are stored from least to most significant * order. The maximum likelihood timecode is formed from the digits * corresponding to the maximum likelihood values reading in the * opposite order: yy ddd hh:mm. */struct decvec { int radix; /* radix (3, 4, 6, 10) */ int digit; /* current clock digit */ int mldigit; /* maximum likelihood digit */ int count; /* match count */ double digprb; /* max digit probability */ double digsnr; /* likelihood function (dB) */ double like[10]; /* likelihood integrator 0-9 */};/* * The station structure (sp) is used to acquire the minute pulse from * WWV and/or WWVH. These stations are distinguished by the frequency * used for the second and minute sync pulses, 1000 Hz for WWV and 1200 * Hz for WWVH. Other than frequency, the format is the same. */struct sync { double epoch; /* accumulated epoch differences */ double maxeng; /* sync max energy */ double noieng; /* sync noise energy */ long pos; /* max amplitude position */ long lastpos; /* last max position */ long mepoch; /* minute synch epoch */ double amp; /* sync signal */ double syneng; /* sync signal max 800 ms */ double synmax; /* sync signal max 0 s */ double synsnr; /* sync signal SNR */ double metric; /* signal quality metric */ int reach; /* reachability register */ int count; /* bit counter */ int select; /* select bits */ char refid[5]; /* reference identifier */};/* * The channel structure (cp) is used to mitigate between channels. */struct chan { int gain; /* audio gain */ struct sync wwv; /* wwv station */ struct sync wwvh; /* wwvh station */};/* * WWV unit control structure (up) */struct wwvunit { l_fp timestamp; /* audio sample timestamp */ l_fp tick; /* audio sample increment */ double phase, freq; /* logical clock phase and frequency */ double monitor; /* audio monitor point */#ifdef ICOM int fd_icom; /* ICOM file descriptor */#endif /* ICOM */ int errflg; /* error flags */ int watch; /* watchcat */ /* * Audio codec variables */ double comp[SIZE]; /* decompanding table */ int port; /* codec port */ int gain; /* codec gain */ int mongain; /* codec monitor gain */ int clipcnt; /* sample clipped count */ /* * Variables used to establish basic system timing */ int avgint; /* master time constant */ int tepoch; /* sync epoch median */ int yepoch; /* sync epoch */ int repoch; /* buffered sync epoch */ double epomax; /* second sync amplitude */ double eposnr; /* second sync SNR */ double irig; /* data I channel amplitude */ double qrig; /* data Q channel amplitude */ int datapt; /* 100 Hz ramp */ double datpha; /* 100 Hz VFO control */ int rphase; /* second sample counter */ long mphase; /* minute sample counter */ /* * Variables used to mitigate which channel to use */ struct chan mitig[NCHAN]; /* channel data */ struct sync *sptr; /* station pointer */ int dchan; /* data channel */ int schan; /* probe channel */ int achan; /* active channel */ /* * Variables used by the clock state machine */ struct decvec decvec[9]; /* decoding matrix */ int rsec; /* seconds counter */ int digcnt; /* count of digits synchronized */ /* * Variables used to estimate signal levels and bit/digit * probabilities */ double datsig; /* data signal max */ double datsnr; /* data signal SNR (dB) */ /* * Variables used to establish status and alarm conditions */ int status; /* status bits */ int alarm; /* alarm flashers */ int misc; /* miscellaneous timecode bits */ int errcnt; /* data bit error counter */};/* * Function prototypes */static int wwv_start P((int, struct peer *));static void wwv_shutdown P((int, struct peer *));static void wwv_receive P((struct recvbuf *));static void wwv_poll P((int, struct peer *));/* * More function prototypes */static void wwv_epoch P((struct peer *));static void wwv_rf P((struct peer *, double));static void wwv_endpoc P((struct peer *, int));static void wwv_rsec P((struct peer *, double));static void wwv_qrz P((struct peer *, struct sync *, int));static void wwv_corr4 P((struct peer *, struct decvec *, double [], double [][4]));static void wwv_gain P((struct peer *));static void wwv_tsec P((struct peer *));static int timecode P((struct wwvunit *, char *));static double wwv_snr P((double, double));static int carry P((struct decvec *));static int wwv_newchan P((struct peer *));static void wwv_newgame P((struct peer *, int));static double wwv_metric P((struct sync *));static void wwv_clock P((struct peer *));#ifdef ICOMstatic int wwv_qsy P((struct peer *, int));#endif /* ICOM */static double qsy[NCHAN] = {2.5, 5, 10, 15, 20}; /* frequencies (MHz) *//* * Transfer vector */struct refclock refclock_wwv = { wwv_start, /* start up driver */ wwv_shutdown, /* shut down driver */ wwv_poll, /* transmit poll message */ noentry, /* not used (old wwv_control) */ noentry, /* initialize driver (not used) */ noentry, /* not used (old wwv_buginfo) */ NOFLAGS /* not used */};/* * wwv_start - open the devices and initialize data for processing */static intwwv_start( int unit, /* instance number (used by PCM) */ struct peer *peer /* peer structure pointer */ ){ struct refclockproc *pp; struct wwvunit *up;#ifdef ICOM int temp;#endif /* ICOM */ /* * Local variables */ int fd; /* file descriptor */ int i; /* index */ double step; /* codec adjustment */ /* * Open audio device */ fd = audio_init(DEVICE_AUDIO, AUDIO_BUFSIZ, unit); if (fd < 0) return (0);#ifdef DEBUG if (debug) audio_show();#endif /* * Allocate and initialize unit structure */ if (!(up = (struct wwvunit *)emalloc(sizeof(struct wwvunit)))) { close(fd); return (0); } memset(up, 0, sizeof(struct wwvunit)); pp = peer->procptr; pp->unitptr = (caddr_t)up; pp->io.clock_recv = wwv_receive; pp->io.srcclock = (caddr_t)peer; pp->io.datalen = 0; pp->io.fd = fd; if (!io_addclock(&pp->io)) { close(fd); free(up); return (0); } /* * Initialize miscellaneous variables */ peer->precision = PRECISION; pp->clockdesc = DESCRIPTION; /* * The companded samples are encoded sign-magnitude. The table * contains all the 256 values in the interest of speed. */ up->comp[0] = up->comp[OFFSET] = 0.; up->comp[1] = 1.; up->comp[OFFSET + 1] = -1.; up->comp[2] = 3.; up->comp[OFFSET + 2] = -3.; step = 2.; for (i = 3; i < OFFSET; i++) { up->comp[i] = up->comp[i - 1] + step; up->comp[OFFSET + i] = -up->comp[i]; if (i % 16 == 0) step *= 2.; } DTOLFP(1. / SECOND, &up->tick); /* * Initialize the decoding matrix with the radix for each digit * position. */ up->decvec[MN].radix = 10; /* minutes */ up->decvec[MN + 1].radix = 6; up->decvec[HR].radix = 10; /* hours */ up->decvec[HR + 1].radix = 3; up->decvec[DA].radix = 10; /* days */ up->decvec[DA + 1].radix = 10; up->decvec[DA + 2].radix = 4; up->decvec[YR].radix = 10; /* years */ up->decvec[YR + 1].radix = 10;#ifdef ICOM /* * Initialize autotune if available. Note that the ICOM select * code must be less than 128, so the high order bit can be used * to select the line speed 0 (9600 bps) or 1 (1200 bps). */ temp = 0;#ifdef DEBUG if (debug > 1) temp = P_TRACE;#endif if (peer->ttl != 0) { if (peer->ttl & 0x80) up->fd_icom = icom_init("/dev/icom", B1200, temp); else up->fd_icom = icom_init("/dev/icom", B9600, temp); if (up->fd_icom < 0) { NLOG(NLOG_SYNCEVENT | NLOG_SYSEVENT) msyslog(LOG_NOTICE, "icom: %m"); up->errflg = CEVNT_FAULT; } } if (up->fd_icom > 0) { if (wwv_qsy(peer, DCHAN) != 0) { NLOG(NLOG_SYNCEVENT | NLOG_SYSEVENT) msyslog(LOG_NOTICE, "icom: radio not found"); up->errflg = CEVNT_FAULT; close(up->fd_icom); up->fd_icom = 0; } else { NLOG(NLOG_SYNCEVENT | NLOG_SYSEVENT) msyslog(LOG_NOTICE, "icom: autotune enabled"); } }#endif /* ICOM */ /* * Let the games begin. */ wwv_newgame(peer, DCHAN); return (1);}/* * wwv_shutdown - shut down the clock */static voidwwv_shutdown( int unit, /* instance number (not used) */ struct peer *peer /* peer structure pointer */ ){ struct refclockproc *pp; struct wwvunit *up; pp = peer->procptr; up = (struct wwvunit *)pp->unitptr; io_closeclock(&pp->io);#ifdef ICOM if (up->fd_icom > 0) close(up->fd_icom);#endif /* ICOM */ free(up);}/* * wwv_receive - receive data from the audio device * * This routine reads input samples and adjusts the logical clock to * track the A/D sample clock by dropping or duplicating codec samples. * It also controls the A/D signal level with an AGC loop to mimimize * quantization noise and avoid overload. */static voidwwv_receive( struct recvbuf *rbufp /* receive buffer structure pointer */ ){ struct peer *peer; struct refclockproc *pp; struct wwvunit *up; /* * Local variables */ double sample; /* codec sample */ u_char *dpt; /* buffer pointer */ int bufcnt; /* buffer counter */ l_fp ltemp; peer = (struct peer *)rbufp->recv_srcclock; pp = peer->procptr; up = (struct wwvunit *)pp->unitptr; /* * Main loop - read until there ain't no more. Note codec * samples are bit-inverted. */ DTOLFP((double)rbufp->recv_length / SECOND, <emp); L_SUB(&rbufp->recv_time, <emp); up->timestamp = rbufp->recv_time; dpt = rbufp->recv_buffer; for (bufcnt = 0; bufcnt < rbufp->recv_length; bufcnt++) { sample = up->comp[~*dpt++ & 0xff]; /* * Clip noise spikes greater than MAXSIG. If no clips, * increase the gain a tad; if the clips are too high, * decrease a tad. */ if (sample > MAXSIG) { sample = MAXSIG; up->clipcnt++; } else if (sample < -MAXSIG) { sample = -MAXSIG; up->clipcnt++; } /* * Variable frequency oscillator. The codec oscillator * runs at the nominal rate of 8000 samples per second, * or 125 us per sample. A frequency change of one unit * results in either duplicating or deleting one sample * per second, which results in a frequency change of * 125 PPM. */ up->phase += up->freq / SECOND; up->phase += pp->fudgetime2 / 1e6; if (up->phase >= .5) { up->phase -= 1.; } else if (up->phase < -.5) { up->phase += 1.; wwv_rf(peer, sample); wwv_rf(peer, sample); } else { wwv_rf(peer, sample); } L_ADD(&up->timestamp, &up->tick); } /* * Set the input port and monitor gain for the next buffer. */ if (pp->sloppyclockflag & CLK_FLAG2) up->port = 2; else up->port = 1; if (pp->sloppyclockflag & CLK_FLAG3) up->mongain = MONGAIN; else up->mongain = 0;}/*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -