Annotation of embedaddon/ntp/ntpd/refclock_wwv.c, revision 1.1.1.1

1.1       misho       1: /*
                      2:  * refclock_wwv - clock driver for NIST WWV/H time/frequency station
                      3:  */
                      4: #ifdef HAVE_CONFIG_H
                      5: #include <config.h>
                      6: #endif
                      7: 
                      8: #if defined(REFCLOCK) && defined(CLOCK_WWV)
                      9: 
                     10: #include "ntpd.h"
                     11: #include "ntp_io.h"
                     12: #include "ntp_refclock.h"
                     13: #include "ntp_calendar.h"
                     14: #include "ntp_stdlib.h"
                     15: #include "audio.h"
                     16: 
                     17: #include <stdio.h>
                     18: #include <ctype.h>
                     19: #include <math.h>
                     20: #ifdef HAVE_SYS_IOCTL_H
                     21: # include <sys/ioctl.h>
                     22: #endif /* HAVE_SYS_IOCTL_H */
                     23: 
                     24: #define ICOM 1
                     25: 
                     26: #ifdef ICOM
                     27: #include "icom.h"
                     28: #endif /* ICOM */
                     29: 
                     30: /*
                     31:  * Audio WWV/H demodulator/decoder
                     32:  *
                     33:  * This driver synchronizes the computer time using data encoded in
                     34:  * radio transmissions from NIST time/frequency stations WWV in Boulder,
                     35:  * CO, and WWVH in Kauai, HI. Transmissions are made continuously on
                     36:  * 2.5, 5, 10 and 15 MHz from WWV and WWVH, and 20 MHz from WWV. An
                     37:  * ordinary AM shortwave receiver can be tuned manually to one of these
                     38:  * frequencies or, in the case of ICOM receivers, the receiver can be
                     39:  * tuned automatically using this program as propagation conditions
                     40:  * change throughout the weasons, both day and night.
                     41:  *
                     42:  * The driver requires an audio codec or sound card with sampling rate 8
                     43:  * kHz and mu-law companding. This is the same standard as used by the
                     44:  * telephone industry and is supported by most hardware and operating
                     45:  * systems, including Solaris, SunOS, FreeBSD, NetBSD and Linux. In this
                     46:  * implementation, only one audio driver and codec can be supported on a
                     47:  * single machine.
                     48:  *
                     49:  * The demodulation and decoding algorithms used in this driver are
                     50:  * based on those developed for the TAPR DSP93 development board and the
                     51:  * TI 320C25 digital signal processor described in: Mills, D.L. A
                     52:  * precision radio clock for WWV transmissions. Electrical Engineering
                     53:  * Report 97-8-1, University of Delaware, August 1997, 25 pp., available
                     54:  * from www.eecis.udel.edu/~mills/reports.html. The algorithms described
                     55:  * in this report have been modified somewhat to improve performance
                     56:  * under weak signal conditions and to provide an automatic station
                     57:  * identification feature.
                     58:  *
                     59:  * The ICOM code is normally compiled in the driver. It isn't used,
                     60:  * unless the mode keyword on the server configuration command specifies
                     61:  * a nonzero ICOM ID select code. The C-IV trace is turned on if the
                     62:  * debug level is greater than one.
                     63:  *
                     64:  * Fudge factors
                     65:  *
                     66:  * Fudge flag4 causes the dubugging output described above to be
                     67:  * recorded in the clockstats file. Fudge flag2 selects the audio input
                     68:  * port, where 0 is the mike port (default) and 1 is the line-in port.
                     69:  * It does not seem useful to select the compact disc player port. Fudge
                     70:  * flag3 enables audio monitoring of the input signal. For this purpose,
                     71:  * the monitor gain is set to a default value.
                     72:  *
                     73:  * CEVNT_BADTIME       invalid date or time
                     74:  * CEVNT_PROP          propagation failure - no stations heard
                     75:  * CEVNT_TIMEOUT       timeout (see newgame() below)
                     76:  */
                     77: /*
                     78:  * General definitions. These ordinarily do not need to be changed.
                     79:  */
                     80: #define        DEVICE_AUDIO    "/dev/audio" /* audio device name */
                     81: #define        AUDIO_BUFSIZ    320     /* audio buffer size (50 ms) */
                     82: #define        PRECISION       (-10)   /* precision assumed (about 1 ms) */
                     83: #define        DESCRIPTION     "WWV/H Audio Demodulator/Decoder" /* WRU */
                     84: #define SECOND         8000    /* second epoch (sample rate) (Hz) */
                     85: #define MINUTE         (SECOND * 60) /* minute epoch */
                     86: #define OFFSET         128     /* companded sample offset */
                     87: #define SIZE           256     /* decompanding table size */
                     88: #define        MAXAMP          6000.   /* max signal level reference */
                     89: #define        MAXCLP          100     /* max clips above reference per s */
                     90: #define MAXSNR         40.     /* max SNR reference */
                     91: #define MAXFREQ                1.5     /* max frequency tolerance (187 PPM) */
                     92: #define DATCYC         170     /* data filter cycles */
                     93: #define DATSIZ         (DATCYC * MS) /* data filter size */
                     94: #define SYNCYC         800     /* minute filter cycles */
                     95: #define SYNSIZ         (SYNCYC * MS) /* minute filter size */
                     96: #define TCKCYC         5       /* tick filter cycles */
                     97: #define TCKSIZ         (TCKCYC * MS) /* tick filter size */
                     98: #define NCHAN          5       /* number of radio channels */
                     99: #define        AUDIO_PHI       5e-6    /* dispersion growth factor */
                    100: #define        TBUF            128     /* max monitor line length */
                    101: 
                    102: /*
                    103:  * Tunable parameters. The DGAIN parameter can be changed to fit the
                    104:  * audio response of the radio at 100 Hz. The WWV/WWVH data subcarrier
                    105:  * is transmitted at about 20 percent percent modulation; the matched
                    106:  * filter boosts it by a factor of 17 and the receiver response does
                    107:  * what it does. The compromise value works for ICOM radios. If the
                    108:  * radio is not tunable, the DCHAN parameter can be changed to fit the
                    109:  * expected best propagation frequency: higher if further from the
                    110:  * transmitter, lower if nearer. The compromise value works for the US
                    111:  * right coast.
                    112:  */
                    113: #define DCHAN          3       /* default radio channel (15 Mhz) */
                    114: #define DGAIN          5.      /* subcarrier gain */
                    115: 
                    116: /*
                    117:  * General purpose status bits (status)
                    118:  *
                    119:  * SELV and/or SELH are set when WWV or WWVH have been heard and cleared
                    120:  * on signal loss. SSYNC is set when the second sync pulse has been
                    121:  * acquired and cleared by signal loss. MSYNC is set when the minute
                    122:  * sync pulse has been acquired. DSYNC is set when the units digit has
                    123:  * has reached the threshold and INSYNC is set when all nine digits have
                    124:  * reached the threshold. The MSYNC, DSYNC and INSYNC bits are cleared
                    125:  * only by timeout, upon which the driver starts over from scratch.
                    126:  *
                    127:  * DGATE is lit if the data bit amplitude or SNR is below thresholds and
                    128:  * BGATE is lit if the pulse width amplitude or SNR is below thresolds.
                    129:  * LEPSEC is set during the last minute of the leap day. At the end of
                    130:  * this minute the driver inserts second 60 in the seconds state machine
                    131:  * and the minute sync slips a second.
                    132:  */
                    133: #define MSYNC          0x0001  /* minute epoch sync */
                    134: #define SSYNC          0x0002  /* second epoch sync */
                    135: #define DSYNC          0x0004  /* minute units sync */
                    136: #define INSYNC         0x0008  /* clock synchronized */
                    137: #define FGATE          0x0010  /* frequency gate */
                    138: #define DGATE          0x0020  /* data pulse amplitude error */
                    139: #define BGATE          0x0040  /* data pulse width error */
                    140: #define        METRIC          0x0080  /* one or more stations heard */
                    141: #define LEPSEC         0x1000  /* leap minute */
                    142: 
                    143: /*
                    144:  * Station scoreboard bits
                    145:  *
                    146:  * These are used to establish the signal quality for each of the five
                    147:  * frequencies and two stations.
                    148:  */
                    149: #define SELV           0x0100  /* WWV station select */
                    150: #define SELH           0x0200  /* WWVH station select */
                    151: 
                    152: /*
                    153:  * Alarm status bits (alarm)
                    154:  *
                    155:  * These bits indicate various alarm conditions, which are decoded to
                    156:  * form the quality character included in the timecode.
                    157:  */
                    158: #define CMPERR         0x1     /* digit or misc bit compare error */
                    159: #define LOWERR         0x2     /* low bit or digit amplitude or SNR */
                    160: #define NINERR         0x4     /* less than nine digits in minute */
                    161: #define SYNERR         0x8     /* not tracking second sync */
                    162: 
                    163: /*
                    164:  * Watchcat timeouts (watch)
                    165:  *
                    166:  * If these timeouts expire, the status bits are mashed to zero and the
                    167:  * driver starts from scratch. Suitably more refined procedures may be
                    168:  * developed in future. All these are in minutes.
                    169:  */
                    170: #define ACQSN          6       /* station acquisition timeout */
                    171: #define DATA           15      /* unit minutes timeout */
                    172: #define SYNCH          40      /* station sync timeout */
                    173: #define PANIC          (2 * 1440) /* panic timeout */
                    174: 
                    175: /*
                    176:  * Thresholds. These establish the minimum signal level, minimum SNR and
                    177:  * maximum jitter thresholds which establish the error and false alarm
                    178:  * rates of the driver. The values defined here may be on the
                    179:  * adventurous side in the interest of the highest sensitivity.
                    180:  */
                    181: #define MTHR           13.     /* minute sync gate (percent) */
                    182: #define TTHR           50.     /* minute sync threshold (percent) */
                    183: #define AWND           20      /* minute sync jitter threshold (ms) */
                    184: #define ATHR           2500.   /* QRZ minute sync threshold */
                    185: #define ASNR           20.     /* QRZ minute sync SNR threshold (dB) */
                    186: #define QTHR           2500.   /* QSY minute sync threshold */
                    187: #define QSNR           20.     /* QSY minute sync SNR threshold (dB) */
                    188: #define STHR           2500.   /* second sync threshold */
                    189: #define        SSNR            15.     /* second sync SNR threshold (dB) */
                    190: #define SCMP           10      /* second sync compare threshold */
                    191: #define DTHR           1000.   /* bit threshold */
                    192: #define DSNR           10.     /* bit SNR threshold (dB) */
                    193: #define AMIN           3       /* min bit count */
                    194: #define AMAX           6       /* max bit count */
                    195: #define BTHR           1000.   /* digit threshold */
                    196: #define BSNR           3.      /* digit likelihood threshold (dB) */
                    197: #define BCMP           3       /* digit compare threshold */
                    198: #define        MAXERR          40      /* maximum error alarm */
                    199: 
                    200: /*
                    201:  * Tone frequency definitions. The increments are for 4.5-deg sine
                    202:  * table.
                    203:  */
                    204: #define MS             (SECOND / 1000) /* samples per millisecond */
                    205: #define IN100          ((100 * 80) / SECOND) /* 100 Hz increment */
                    206: #define IN1000         ((1000 * 80) / SECOND) /* 1000 Hz increment */
                    207: #define IN1200         ((1200 * 80) / SECOND) /* 1200 Hz increment */
                    208: 
                    209: /*
                    210:  * Acquisition and tracking time constants
                    211:  */
                    212: #define MINAVG         8       /* min averaging time */
                    213: #define MAXAVG         1024    /* max averaging time */
                    214: #define FCONST         3       /* frequency time constant */
                    215: #define TCONST         16      /* data bit/digit time constant */
                    216: 
                    217: /*
                    218:  * Miscellaneous status bits (misc)
                    219:  *
                    220:  * These bits correspond to designated bits in the WWV/H timecode. The
                    221:  * bit probabilities are exponentially averaged over several minutes and
                    222:  * processed by a integrator and threshold.
                    223:  */
                    224: #define DUT1           0x01    /* 56 DUT .1 */
                    225: #define DUT2           0x02    /* 57 DUT .2 */
                    226: #define DUT4           0x04    /* 58 DUT .4 */
                    227: #define DUTS           0x08    /* 50 DUT sign */
                    228: #define DST1           0x10    /* 55 DST1 leap warning */
                    229: #define DST2           0x20    /* 2 DST2 DST1 delayed one day */
                    230: #define SECWAR         0x40    /* 3 leap second warning */
                    231: 
                    232: /*
                    233:  * The on-time synchronization point is the positive-going zero crossing
                    234:  * of the first cycle of the 5-ms second pulse. The IIR baseband filter
                    235:  * phase delay is 0.91 ms, while the receiver delay is approximately 4.7
                    236:  * ms at 1000 Hz. The fudge value -0.45 ms due to the codec and other
                    237:  * causes was determined by calibrating to a PPS signal from a GPS
                    238:  * receiver. The additional propagation delay specific to each receiver
                    239:  * location can be  programmed in the fudge time1 and time2 values for
                    240:  * WWV and WWVH, respectively.
                    241:  *
                    242:  * The resulting offsets with a 2.4-GHz P4 running FreeBSD 6.1 are
                    243:  * generally within .02 ms short-term with .02 ms jitter. The long-term
                    244:  * offsets vary up to 0.3 ms due to ionosperhic layer height variations.
                    245:  * The processor load due to the driver is 5.8 percent.
                    246:  */
                    247: #define PDELAY ((.91 + 4.7 - 0.45) / 1000) /* system delay (s) */
                    248: 
                    249: /*
                    250:  * Table of sine values at 4.5-degree increments. This is used by the
                    251:  * synchronous matched filter demodulators.
                    252:  */
                    253: double sintab[] = {
                    254:  0.000000e+00,  7.845910e-02,  1.564345e-01,  2.334454e-01, /* 0-3 */
                    255:  3.090170e-01,  3.826834e-01,  4.539905e-01,  5.224986e-01, /* 4-7 */
                    256:  5.877853e-01,  6.494480e-01,  7.071068e-01,  7.604060e-01, /* 8-11 */
                    257:  8.090170e-01,  8.526402e-01,  8.910065e-01,  9.238795e-01, /* 12-15 */
                    258:  9.510565e-01,  9.723699e-01,  9.876883e-01,  9.969173e-01, /* 16-19 */
                    259:  1.000000e+00,  9.969173e-01,  9.876883e-01,  9.723699e-01, /* 20-23 */
                    260:  9.510565e-01,  9.238795e-01,  8.910065e-01,  8.526402e-01, /* 24-27 */
                    261:  8.090170e-01,  7.604060e-01,  7.071068e-01,  6.494480e-01, /* 28-31 */
                    262:  5.877853e-01,  5.224986e-01,  4.539905e-01,  3.826834e-01, /* 32-35 */
                    263:  3.090170e-01,  2.334454e-01,  1.564345e-01,  7.845910e-02, /* 36-39 */
                    264: -0.000000e+00, -7.845910e-02, -1.564345e-01, -2.334454e-01, /* 40-43 */
                    265: -3.090170e-01, -3.826834e-01, -4.539905e-01, -5.224986e-01, /* 44-47 */
                    266: -5.877853e-01, -6.494480e-01, -7.071068e-01, -7.604060e-01, /* 48-51 */
                    267: -8.090170e-01, -8.526402e-01, -8.910065e-01, -9.238795e-01, /* 52-55 */
                    268: -9.510565e-01, -9.723699e-01, -9.876883e-01, -9.969173e-01, /* 56-59 */
                    269: -1.000000e+00, -9.969173e-01, -9.876883e-01, -9.723699e-01, /* 60-63 */
                    270: -9.510565e-01, -9.238795e-01, -8.910065e-01, -8.526402e-01, /* 64-67 */
                    271: -8.090170e-01, -7.604060e-01, -7.071068e-01, -6.494480e-01, /* 68-71 */
                    272: -5.877853e-01, -5.224986e-01, -4.539905e-01, -3.826834e-01, /* 72-75 */
                    273: -3.090170e-01, -2.334454e-01, -1.564345e-01, -7.845910e-02, /* 76-79 */
                    274:  0.000000e+00};                                                    /* 80 */
                    275: 
                    276: /*
                    277:  * Decoder operations at the end of each second are driven by a state
                    278:  * machine. The transition matrix consists of a dispatch table indexed
                    279:  * by second number. Each entry in the table contains a case switch
                    280:  * number and argument.
                    281:  */
                    282: struct progx {
                    283:        int sw;                 /* case switch number */
                    284:        int arg;                /* argument */
                    285: };
                    286: 
                    287: /*
                    288:  * Case switch numbers
                    289:  */
                    290: #define IDLE           0       /* no operation */
                    291: #define COEF           1       /* BCD bit */
                    292: #define COEF1          2       /* BCD bit for minute unit */
                    293: #define COEF2          3       /* BCD bit not used */
                    294: #define DECIM9         4       /* BCD digit 0-9 */
                    295: #define DECIM6         5       /* BCD digit 0-6 */
                    296: #define DECIM3         6       /* BCD digit 0-3 */
                    297: #define DECIM2         7       /* BCD digit 0-2 */
                    298: #define MSCBIT         8       /* miscellaneous bit */
                    299: #define MSC20          9       /* miscellaneous bit */         
                    300: #define MSC21          10      /* QSY probe channel */         
                    301: #define MIN1           11      /* latch time */                
                    302: #define MIN2           12      /* leap second */
                    303: #define SYNC2          13      /* latch minute sync pulse */           
                    304: #define SYNC3          14      /* latch data pulse */          
                    305: 
                    306: /*
                    307:  * Offsets in decoding matrix
                    308:  */
                    309: #define MN             0       /* minute digits (2) */
                    310: #define HR             2       /* hour digits (2) */
                    311: #define DA             4       /* day digits (3) */
                    312: #define YR             7       /* year digits (2) */
                    313: 
                    314: struct progx progx[] = {
                    315:        {SYNC2, 0},             /* 0 latch minute sync pulse */
                    316:        {SYNC3, 0},             /* 1 latch data pulse */
                    317:        {MSCBIT, DST2},         /* 2 dst2 */
                    318:        {MSCBIT, SECWAR},       /* 3 lw */
                    319:        {COEF,  0},             /* 4 1 year units */
                    320:        {COEF,  1},             /* 5 2 */
                    321:        {COEF,  2},             /* 6 4 */
                    322:        {COEF,  3},             /* 7 8 */
                    323:        {DECIM9, YR},           /* 8 */
                    324:        {IDLE,  0},             /* 9 p1 */
                    325:        {COEF1, 0},             /* 10 1 minute units */
                    326:        {COEF1, 1},             /* 11 2 */
                    327:        {COEF1, 2},             /* 12 4 */
                    328:        {COEF1, 3},             /* 13 8 */
                    329:        {DECIM9, MN},           /* 14 */
                    330:        {COEF,  0},             /* 15 10 minute tens */
                    331:        {COEF,  1},             /* 16 20 */
                    332:        {COEF,  2},             /* 17 40 */
                    333:        {COEF2, 3},             /* 18 80 (not used) */
                    334:        {DECIM6, MN + 1},       /* 19 p2 */
                    335:        {COEF,  0},             /* 20 1 hour units */
                    336:        {COEF,  1},             /* 21 2 */
                    337:        {COEF,  2},             /* 22 4 */
                    338:        {COEF,  3},             /* 23 8 */
                    339:        {DECIM9, HR},           /* 24 */
                    340:        {COEF,  0},             /* 25 10 hour tens */
                    341:        {COEF,  1},             /* 26 20 */
                    342:        {COEF2, 2},             /* 27 40 (not used) */
                    343:        {COEF2, 3},             /* 28 80 (not used) */
                    344:        {DECIM2, HR + 1},       /* 29 p3 */
                    345:        {COEF,  0},             /* 30 1 day units */
                    346:        {COEF,  1},             /* 31 2 */
                    347:        {COEF,  2},             /* 32 4 */
                    348:        {COEF,  3},             /* 33 8 */
                    349:        {DECIM9, DA},           /* 34 */
                    350:        {COEF,  0},             /* 35 10 day tens */
                    351:        {COEF,  1},             /* 36 20 */
                    352:        {COEF,  2},             /* 37 40 */
                    353:        {COEF,  3},             /* 38 80 */
                    354:        {DECIM9, DA + 1},       /* 39 p4 */
                    355:        {COEF,  0},             /* 40 100 day hundreds */
                    356:        {COEF,  1},             /* 41 200 */
                    357:        {COEF2, 2},             /* 42 400 (not used) */
                    358:        {COEF2, 3},             /* 43 800 (not used) */
                    359:        {DECIM3, DA + 2},       /* 44 */
                    360:        {IDLE,  0},             /* 45 */
                    361:        {IDLE,  0},             /* 46 */
                    362:        {IDLE,  0},             /* 47 */
                    363:        {IDLE,  0},             /* 48 */
                    364:        {IDLE,  0},             /* 49 p5 */
                    365:        {MSCBIT, DUTS},         /* 50 dut+- */
                    366:        {COEF,  0},             /* 51 10 year tens */
                    367:        {COEF,  1},             /* 52 20 */
                    368:        {COEF,  2},             /* 53 40 */
                    369:        {COEF,  3},             /* 54 80 */
                    370:        {MSC20, DST1},          /* 55 dst1 */
                    371:        {MSCBIT, DUT1},         /* 56 0.1 dut */
                    372:        {MSCBIT, DUT2},         /* 57 0.2 */
                    373:        {MSC21, DUT4},          /* 58 0.4 QSY probe channel */
                    374:        {MIN1,  0},             /* 59 p6 latch time */
                    375:        {MIN2,  0}              /* 60 leap second */
                    376: };
                    377: 
                    378: /*
                    379:  * BCD coefficients for maximum-likelihood digit decode
                    380:  */
                    381: #define P15    1.              /* max positive number */
                    382: #define N15    -1.             /* max negative number */
                    383: 
                    384: /*
                    385:  * Digits 0-9
                    386:  */
                    387: #define P9     (P15 / 4)       /* mark (+1) */
                    388: #define N9     (N15 / 4)       /* space (-1) */
                    389: 
                    390: double bcd9[][4] = {
                    391:        {N9, N9, N9, N9},       /* 0 */
                    392:        {P9, N9, N9, N9},       /* 1 */
                    393:        {N9, P9, N9, N9},       /* 2 */
                    394:        {P9, P9, N9, N9},       /* 3 */
                    395:        {N9, N9, P9, N9},       /* 4 */
                    396:        {P9, N9, P9, N9},       /* 5 */
                    397:        {N9, P9, P9, N9},       /* 6 */
                    398:        {P9, P9, P9, N9},       /* 7 */
                    399:        {N9, N9, N9, P9},       /* 8 */
                    400:        {P9, N9, N9, P9},       /* 9 */
                    401:        {0, 0, 0, 0}            /* backstop */
                    402: };
                    403: 
                    404: /*
                    405:  * Digits 0-6 (minute tens)
                    406:  */
                    407: #define P6     (P15 / 3)       /* mark (+1) */
                    408: #define N6     (N15 / 3)       /* space (-1) */
                    409: 
                    410: double bcd6[][4] = {
                    411:        {N6, N6, N6, 0},        /* 0 */
                    412:        {P6, N6, N6, 0},        /* 1 */
                    413:        {N6, P6, N6, 0},        /* 2 */
                    414:        {P6, P6, N6, 0},        /* 3 */
                    415:        {N6, N6, P6, 0},        /* 4 */
                    416:        {P6, N6, P6, 0},        /* 5 */
                    417:        {N6, P6, P6, 0},        /* 6 */
                    418:        {0, 0, 0, 0}            /* backstop */
                    419: };
                    420: 
                    421: /*
                    422:  * Digits 0-3 (day hundreds)
                    423:  */
                    424: #define P3     (P15 / 2)       /* mark (+1) */
                    425: #define N3     (N15 / 2)       /* space (-1) */
                    426: 
                    427: double bcd3[][4] = {
                    428:        {N3, N3, 0, 0},         /* 0 */
                    429:        {P3, N3, 0, 0},         /* 1 */
                    430:        {N3, P3, 0, 0},         /* 2 */
                    431:        {P3, P3, 0, 0},         /* 3 */
                    432:        {0, 0, 0, 0}            /* backstop */
                    433: };
                    434: 
                    435: /*
                    436:  * Digits 0-2 (hour tens)
                    437:  */
                    438: #define P2     (P15 / 2)       /* mark (+1) */
                    439: #define N2     (N15 / 2)       /* space (-1) */
                    440: 
                    441: double bcd2[][4] = {
                    442:        {N2, N2, 0, 0},         /* 0 */
                    443:        {P2, N2, 0, 0},         /* 1 */
                    444:        {N2, P2, 0, 0},         /* 2 */
                    445:        {0, 0, 0, 0}            /* backstop */
                    446: };
                    447: 
                    448: /*
                    449:  * DST decode (DST2 DST1) for prettyprint
                    450:  */
                    451: char dstcod[] = {
                    452:        'S',                    /* 00 standard time */
                    453:        'I',                    /* 01 set clock ahead at 0200 local */
                    454:        'O',                    /* 10 set clock back at 0200 local */
                    455:        'D'                     /* 11 daylight time */
                    456: };
                    457: 
                    458: /*
                    459:  * The decoding matrix consists of nine row vectors, one for each digit
                    460:  * of the timecode. The digits are stored from least to most significant
                    461:  * order. The maximum-likelihood timecode is formed from the digits
                    462:  * corresponding to the maximum-likelihood values reading in the
                    463:  * opposite order: yy ddd hh:mm.
                    464:  */
                    465: struct decvec {
                    466:        int radix;              /* radix (3, 4, 6, 10) */
                    467:        int digit;              /* current clock digit */
                    468:        int count;              /* match count */
                    469:        double digprb;          /* max digit probability */
                    470:        double digsnr;          /* likelihood function (dB) */
                    471:        double like[10];        /* likelihood integrator 0-9 */
                    472: };
                    473: 
                    474: /*
                    475:  * The station structure (sp) is used to acquire the minute pulse from
                    476:  * WWV and/or WWVH. These stations are distinguished by the frequency
                    477:  * used for the second and minute sync pulses, 1000 Hz for WWV and 1200
                    478:  * Hz for WWVH. Other than frequency, the format is the same.
                    479:  */
                    480: struct sync {
                    481:        double  epoch;          /* accumulated epoch differences */
                    482:        double  maxeng;         /* sync max energy */
                    483:        double  noieng;         /* sync noise energy */
                    484:        long    pos;            /* max amplitude position */
                    485:        long    lastpos;        /* last max position */
                    486:        long    mepoch;         /* minute synch epoch */
                    487: 
                    488:        double  amp;            /* sync signal */
                    489:        double  syneng;         /* sync signal max */
                    490:        double  synmax;         /* sync signal max latched at 0 s */
                    491:        double  synsnr;         /* sync signal SNR */
                    492:        double  metric;         /* signal quality metric */
                    493:        int     reach;          /* reachability register */
                    494:        int     count;          /* bit counter */
                    495:        int     select;         /* select bits */
                    496:        char    refid[5];       /* reference identifier */
                    497: };
                    498: 
                    499: /*
                    500:  * The channel structure (cp) is used to mitigate between channels.
                    501:  */
                    502: struct chan {
                    503:        int     gain;           /* audio gain */
                    504:        struct sync wwv;        /* wwv station */
                    505:        struct sync wwvh;       /* wwvh station */
                    506: };
                    507: 
                    508: /*
                    509:  * WWV unit control structure (up)
                    510:  */
                    511: struct wwvunit {
                    512:        l_fp    timestamp;      /* audio sample timestamp */
                    513:        l_fp    tick;           /* audio sample increment */
                    514:        double  phase, freq;    /* logical clock phase and frequency */
                    515:        double  monitor;        /* audio monitor point */
                    516:        double  pdelay;         /* propagation delay (s) */
                    517: #ifdef ICOM
                    518:        int     fd_icom;        /* ICOM file descriptor */
                    519: #endif /* ICOM */
                    520:        int     errflg;         /* error flags */
                    521:        int     watch;          /* watchcat */
                    522: 
                    523:        /*
                    524:         * Audio codec variables
                    525:         */
                    526:        double  comp[SIZE];     /* decompanding table */
                    527:        int     port;           /* codec port */
                    528:        int     gain;           /* codec gain */
                    529:        int     mongain;        /* codec monitor gain */
                    530:        int     clipcnt;        /* sample clipped count */
                    531: 
                    532:        /*
                    533:         * Variables used to establish basic system timing
                    534:         */
                    535:        int     avgint;         /* master time constant */
                    536:        int     yepoch;         /* sync epoch */
                    537:        int     repoch;         /* buffered sync epoch */
                    538:        double  epomax;         /* second sync amplitude */
                    539:        double  eposnr;         /* second sync SNR */
                    540:        double  irig;           /* data I channel amplitude */
                    541:        double  qrig;           /* data Q channel amplitude */
                    542:        int     datapt;         /* 100 Hz ramp */
                    543:        double  datpha;         /* 100 Hz VFO control */
                    544:        int     rphase;         /* second sample counter */
                    545:        long    mphase;         /* minute sample counter */
                    546: 
                    547:        /*
                    548:         * Variables used to mitigate which channel to use
                    549:         */
                    550:        struct chan mitig[NCHAN]; /* channel data */
                    551:        struct sync *sptr;      /* station pointer */
                    552:        int     dchan;          /* data channel */
                    553:        int     schan;          /* probe channel */
                    554:        int     achan;          /* active channel */
                    555: 
                    556:        /*
                    557:         * Variables used by the clock state machine
                    558:         */
                    559:        struct decvec decvec[9]; /* decoding matrix */
                    560:        int     rsec;           /* seconds counter */
                    561:        int     digcnt;         /* count of digits synchronized */
                    562: 
                    563:        /*
                    564:         * Variables used to estimate signal levels and bit/digit
                    565:         * probabilities
                    566:         */
                    567:        double  datsig;         /* data signal max */
                    568:        double  datsnr;         /* data signal SNR (dB) */
                    569: 
                    570:        /*
                    571:         * Variables used to establish status and alarm conditions
                    572:         */
                    573:        int     status;         /* status bits */
                    574:        int     alarm;          /* alarm flashers */
                    575:        int     misc;           /* miscellaneous timecode bits */
                    576:        int     errcnt;         /* data bit error counter */
                    577: };
                    578: 
                    579: /*
                    580:  * Function prototypes
                    581:  */
                    582: static int     wwv_start       (int, struct peer *);
                    583: static void    wwv_shutdown    (int, struct peer *);
                    584: static void    wwv_receive     (struct recvbuf *);
                    585: static void    wwv_poll        (int, struct peer *);
                    586: 
                    587: /*
                    588:  * More function prototypes
                    589:  */
                    590: static void    wwv_epoch       (struct peer *);
                    591: static void    wwv_rf          (struct peer *, double);
                    592: static void    wwv_endpoc      (struct peer *, int);
                    593: static void    wwv_rsec        (struct peer *, double);
                    594: static void    wwv_qrz         (struct peer *, struct sync *, int);
                    595: static void    wwv_corr4       (struct peer *, struct decvec *,
                    596:                                    double [], double [][4]);
                    597: static void    wwv_gain        (struct peer *);
                    598: static void    wwv_tsec        (struct peer *);
                    599: static int     timecode        (struct wwvunit *, char *);
                    600: static double  wwv_snr         (double, double);
                    601: static int     carry           (struct decvec *);
                    602: static int     wwv_newchan     (struct peer *);
                    603: static void    wwv_newgame     (struct peer *);
                    604: static double  wwv_metric      (struct sync *);
                    605: static void    wwv_clock       (struct peer *);
                    606: #ifdef ICOM
                    607: static int     wwv_qsy         (struct peer *, int);
                    608: #endif /* ICOM */
                    609: 
                    610: static double qsy[NCHAN] = {2.5, 5, 10, 15, 20}; /* frequencies (MHz) */
                    611: 
                    612: /*
                    613:  * Transfer vector
                    614:  */
                    615: struct refclock refclock_wwv = {
                    616:        wwv_start,              /* start up driver */
                    617:        wwv_shutdown,           /* shut down driver */
                    618:        wwv_poll,               /* transmit poll message */
                    619:        noentry,                /* not used (old wwv_control) */
                    620:        noentry,                /* initialize driver (not used) */
                    621:        noentry,                /* not used (old wwv_buginfo) */
                    622:        NOFLAGS                 /* not used */
                    623: };
                    624: 
                    625: 
                    626: /*
                    627:  * wwv_start - open the devices and initialize data for processing
                    628:  */
                    629: static int
                    630: wwv_start(
                    631:        int     unit,           /* instance number (used by PCM) */
                    632:        struct peer *peer       /* peer structure pointer */
                    633:        )
                    634: {
                    635:        struct refclockproc *pp;
                    636:        struct wwvunit *up;
                    637: #ifdef ICOM
                    638:        int     temp;
                    639: #endif /* ICOM */
                    640: 
                    641:        /*
                    642:         * Local variables
                    643:         */
                    644:        int     fd;             /* file descriptor */
                    645:        int     i;              /* index */
                    646:        double  step;           /* codec adjustment */
                    647: 
                    648:        /*
                    649:         * Open audio device
                    650:         */
                    651:        fd = audio_init(DEVICE_AUDIO, AUDIO_BUFSIZ, unit);
                    652:        if (fd < 0)
                    653:                return (0);
                    654: #ifdef DEBUG
                    655:        if (debug)
                    656:                audio_show();
                    657: #endif /* DEBUG */
                    658: 
                    659:        /*
                    660:         * Allocate and initialize unit structure
                    661:         */
                    662:        if (!(up = (struct wwvunit *)emalloc(sizeof(struct wwvunit)))) {
                    663:                close(fd);
                    664:                return (0);
                    665:        }
                    666:        memset(up, 0, sizeof(struct wwvunit));
                    667:        pp = peer->procptr;
                    668:        pp->unitptr = (caddr_t)up;
                    669:        pp->io.clock_recv = wwv_receive;
                    670:        pp->io.srcclock = (caddr_t)peer;
                    671:        pp->io.datalen = 0;
                    672:        pp->io.fd = fd;
                    673:        if (!io_addclock(&pp->io)) {
                    674:                close(fd);
                    675:                free(up);
                    676:                return (0);
                    677:        }
                    678: 
                    679:        /*
                    680:         * Initialize miscellaneous variables
                    681:         */
                    682:        peer->precision = PRECISION;
                    683:        pp->clockdesc = DESCRIPTION;
                    684: 
                    685:        /*
                    686:         * The companded samples are encoded sign-magnitude. The table
                    687:         * contains all the 256 values in the interest of speed.
                    688:         */
                    689:        up->comp[0] = up->comp[OFFSET] = 0.;
                    690:        up->comp[1] = 1.; up->comp[OFFSET + 1] = -1.;
                    691:        up->comp[2] = 3.; up->comp[OFFSET + 2] = -3.;
                    692:        step = 2.;
                    693:        for (i = 3; i < OFFSET; i++) {
                    694:                up->comp[i] = up->comp[i - 1] + step;
                    695:                up->comp[OFFSET + i] = -up->comp[i];
                    696:                 if (i % 16 == 0)
                    697:                    step *= 2.;
                    698:        }
                    699:        DTOLFP(1. / SECOND, &up->tick);
                    700: 
                    701:        /*
                    702:         * Initialize the decoding matrix with the radix for each digit
                    703:         * position.
                    704:         */
                    705:        up->decvec[MN].radix = 10;      /* minutes */
                    706:        up->decvec[MN + 1].radix = 6;
                    707:        up->decvec[HR].radix = 10;      /* hours */
                    708:        up->decvec[HR + 1].radix = 3;
                    709:        up->decvec[DA].radix = 10;      /* days */
                    710:        up->decvec[DA + 1].radix = 10;
                    711:        up->decvec[DA + 2].radix = 4;
                    712:        up->decvec[YR].radix = 10;      /* years */
                    713:        up->decvec[YR + 1].radix = 10;
                    714: 
                    715: #ifdef ICOM
                    716:        /*
                    717:         * Initialize autotune if available. Note that the ICOM select
                    718:         * code must be less than 128, so the high order bit can be used
                    719:         * to select the line speed 0 (9600 bps) or 1 (1200 bps). Note
                    720:         * we don't complain if the ICOM device is not there; but, if it
                    721:         * is, the radio better be working.
                    722:         */
                    723:        temp = 0;
                    724: #ifdef DEBUG
                    725:        if (debug > 1)
                    726:                temp = P_TRACE;
                    727: #endif /* DEBUG */
                    728:        if (peer->ttl != 0) {
                    729:                if (peer->ttl & 0x80)
                    730:                        up->fd_icom = icom_init("/dev/icom", B1200,
                    731:                            temp);
                    732:                else
                    733:                        up->fd_icom = icom_init("/dev/icom", B9600,
                    734:                            temp);
                    735:        }
                    736:        if (up->fd_icom > 0) {
                    737:                if (wwv_qsy(peer, DCHAN) != 0) {
                    738:                        msyslog(LOG_NOTICE, "icom: radio not found");
                    739:                        close(up->fd_icom);
                    740:                        up->fd_icom = 0;
                    741:                } else {
                    742:                        msyslog(LOG_NOTICE, "icom: autotune enabled");
                    743:                }
                    744:        }
                    745: #endif /* ICOM */
                    746: 
                    747:        /*
                    748:         * Let the games begin.
                    749:         */
                    750:        wwv_newgame(peer);
                    751:        return (1);
                    752: }
                    753: 
                    754: 
                    755: /*
                    756:  * wwv_shutdown - shut down the clock
                    757:  */
                    758: static void
                    759: wwv_shutdown(
                    760:        int     unit,           /* instance number (not used) */
                    761:        struct peer *peer       /* peer structure pointer */
                    762:        )
                    763: {
                    764:        struct refclockproc *pp;
                    765:        struct wwvunit *up;
                    766: 
                    767:        pp = peer->procptr;
                    768:        up = (struct wwvunit *)pp->unitptr;
                    769:        if (up == NULL)
                    770:                return;
                    771: 
                    772:        io_closeclock(&pp->io);
                    773: #ifdef ICOM
                    774:        if (up->fd_icom > 0)
                    775:                close(up->fd_icom);
                    776: #endif /* ICOM */
                    777:        free(up);
                    778: }
                    779: 
                    780: 
                    781: /*
                    782:  * wwv_receive - receive data from the audio device
                    783:  *
                    784:  * This routine reads input samples and adjusts the logical clock to
                    785:  * track the A/D sample clock by dropping or duplicating codec samples.
                    786:  * It also controls the A/D signal level with an AGC loop to mimimize
                    787:  * quantization noise and avoid overload.
                    788:  */
                    789: static void
                    790: wwv_receive(
                    791:        struct recvbuf *rbufp   /* receive buffer structure pointer */
                    792:        )
                    793: {
                    794:        struct peer *peer;
                    795:        struct refclockproc *pp;
                    796:        struct wwvunit *up;
                    797: 
                    798:        /*
                    799:         * Local variables
                    800:         */
                    801:        double  sample;         /* codec sample */
                    802:        u_char  *dpt;           /* buffer pointer */
                    803:        int     bufcnt;         /* buffer counter */
                    804:        l_fp    ltemp;
                    805: 
                    806:        peer = (struct peer *)rbufp->recv_srcclock;
                    807:        pp = peer->procptr;
                    808:        up = (struct wwvunit *)pp->unitptr;
                    809: 
                    810:        /*
                    811:         * Main loop - read until there ain't no more. Note codec
                    812:         * samples are bit-inverted.
                    813:         */
                    814:        DTOLFP((double)rbufp->recv_length / SECOND, &ltemp);
                    815:        L_SUB(&rbufp->recv_time, &ltemp);
                    816:        up->timestamp = rbufp->recv_time;
                    817:        dpt = rbufp->recv_buffer;
                    818:        for (bufcnt = 0; bufcnt < rbufp->recv_length; bufcnt++) {
                    819:                sample = up->comp[~*dpt++ & 0xff];
                    820: 
                    821:                /*
                    822:                 * Clip noise spikes greater than MAXAMP (6000) and
                    823:                 * record the number of clips to be used later by the
                    824:                 * AGC.
                    825:                 */
                    826:                if (sample > MAXAMP) {
                    827:                        sample = MAXAMP;
                    828:                        up->clipcnt++;
                    829:                } else if (sample < -MAXAMP) {
                    830:                        sample = -MAXAMP;
                    831:                        up->clipcnt++;
                    832:                }
                    833: 
                    834:                /*
                    835:                 * Variable frequency oscillator. The codec oscillator
                    836:                 * runs at the nominal rate of 8000 samples per second,
                    837:                 * or 125 us per sample. A frequency change of one unit
                    838:                 * results in either duplicating or deleting one sample
                    839:                 * per second, which results in a frequency change of
                    840:                 * 125 PPM.
                    841:                 */
                    842:                up->phase += (up->freq + clock_codec) / SECOND;
                    843:                if (up->phase >= .5) {
                    844:                        up->phase -= 1.;
                    845:                } else if (up->phase < -.5) {
                    846:                        up->phase += 1.;
                    847:                        wwv_rf(peer, sample);
                    848:                        wwv_rf(peer, sample);
                    849:                } else {
                    850:                        wwv_rf(peer, sample);
                    851:                }
                    852:                L_ADD(&up->timestamp, &up->tick);
                    853:        }
                    854: 
                    855:        /*
                    856:         * Set the input port and monitor gain for the next buffer.
                    857:         */
                    858:        if (pp->sloppyclockflag & CLK_FLAG2)
                    859:                up->port = 2;
                    860:        else
                    861:                up->port = 1;
                    862:        if (pp->sloppyclockflag & CLK_FLAG3)
                    863:                up->mongain = MONGAIN;
                    864:        else
                    865:                up->mongain = 0;
                    866: }
                    867: 
                    868: 
                    869: /*
                    870:  * wwv_poll - called by the transmit procedure
                    871:  *
                    872:  * This routine keeps track of status. If no offset samples have been
                    873:  * processed during a poll interval, a timeout event is declared. If
                    874:  * errors have have occurred during the interval, they are reported as
                    875:  * well.
                    876:  */
                    877: static void
                    878: wwv_poll(
                    879:        int     unit,           /* instance number (not used) */
                    880:        struct peer *peer       /* peer structure pointer */
                    881:        )
                    882: {
                    883:        struct refclockproc *pp;
                    884:        struct wwvunit *up;
                    885: 
                    886:        pp = peer->procptr;
                    887:        up = (struct wwvunit *)pp->unitptr;
                    888:        if (up->errflg)
                    889:                refclock_report(peer, up->errflg);
                    890:        up->errflg = 0;
                    891:        pp->polls++;
                    892: }
                    893: 
                    894: 
                    895: /*
                    896:  * wwv_rf - process signals and demodulate to baseband
                    897:  *
                    898:  * This routine grooms and filters decompanded raw audio samples. The
                    899:  * output signal is the 100-Hz filtered baseband data signal in
                    900:  * quadrature phase. The routine also determines the minute synch epoch,
                    901:  * as well as certain signal maxima, minima and related values.
                    902:  *
                    903:  * There are two 1-s ramps used by this program. Both count the 8000
                    904:  * logical clock samples spanning exactly one second. The epoch ramp
                    905:  * counts the samples starting at an arbitrary time. The rphase ramp
                    906:  * counts the samples starting at the 5-ms second sync pulse found
                    907:  * during the epoch ramp.
                    908:  *
                    909:  * There are two 1-m ramps used by this program. The mphase ramp counts
                    910:  * the 480,000 logical clock samples spanning exactly one minute and
                    911:  * starting at an arbitrary time. The rsec ramp counts the 60 seconds of
                    912:  * the minute starting at the 800-ms minute sync pulse found during the
                    913:  * mphase ramp. The rsec ramp drives the seconds state machine to
                    914:  * determine the bits and digits of the timecode. 
                    915:  *
                    916:  * Demodulation operations are based on three synthesized quadrature
                    917:  * sinusoids: 100 Hz for the data signal, 1000 Hz for the WWV sync
                    918:  * signal and 1200 Hz for the WWVH sync signal. These drive synchronous
                    919:  * matched filters for the data signal (170 ms at 100 Hz), WWV minute
                    920:  * sync signal (800 ms at 1000 Hz) and WWVH minute sync signal (800 ms
                    921:  * at 1200 Hz). Two additional matched filters are switched in
                    922:  * as required for the WWV second sync signal (5 cycles at 1000 Hz) and
                    923:  * WWVH second sync signal (6 cycles at 1200 Hz).
                    924:  */
                    925: static void
                    926: wwv_rf(
                    927:        struct peer *peer,      /* peerstructure pointer */
                    928:        double isig             /* input signal */
                    929:        )
                    930: {
                    931:        struct refclockproc *pp;
                    932:        struct wwvunit *up;
                    933:        struct sync *sp, *rp;
                    934: 
                    935:        static double lpf[5];   /* 150-Hz lpf delay line */
                    936:        double data;            /* lpf output */
                    937:        static double bpf[9];   /* 1000/1200-Hz bpf delay line */
                    938:        double syncx;           /* bpf output */
                    939:        static double mf[41];   /* 1000/1200-Hz mf delay line */
                    940:        double mfsync;          /* mf output */
                    941: 
                    942:        static int iptr;        /* data channel pointer */
                    943:        static double ibuf[DATSIZ]; /* data I channel delay line */
                    944:        static double qbuf[DATSIZ]; /* data Q channel delay line */
                    945: 
                    946:        static int jptr;        /* sync channel pointer */
                    947:        static int kptr;        /* tick channel pointer */
                    948: 
                    949:        static int csinptr;     /* wwv channel phase */
                    950:        static double cibuf[SYNSIZ]; /* wwv I channel delay line */
                    951:        static double cqbuf[SYNSIZ]; /* wwv Q channel delay line */
                    952:        static double ciamp;    /* wwv I channel amplitude */
                    953:        static double cqamp;    /* wwv Q channel amplitude */
                    954: 
                    955:        static double csibuf[TCKSIZ]; /* wwv I tick delay line */
                    956:        static double csqbuf[TCKSIZ]; /* wwv Q tick delay line */
                    957:        static double csiamp;   /* wwv I tick amplitude */
                    958:        static double csqamp;   /* wwv Q tick amplitude */
                    959: 
                    960:        static int hsinptr;     /* wwvh channel phase */
                    961:        static double hibuf[SYNSIZ]; /* wwvh I channel delay line */
                    962:        static double hqbuf[SYNSIZ]; /* wwvh Q channel delay line */
                    963:        static double hiamp;    /* wwvh I channel amplitude */
                    964:        static double hqamp;    /* wwvh Q channel amplitude */
                    965: 
                    966:        static double hsibuf[TCKSIZ]; /* wwvh I tick delay line */
                    967:        static double hsqbuf[TCKSIZ]; /* wwvh Q tick delay line */
                    968:        static double hsiamp;   /* wwvh I tick amplitude */
                    969:        static double hsqamp;   /* wwvh Q tick amplitude */
                    970: 
                    971:        static double epobuf[SECOND]; /* second sync comb filter */
                    972:        static double epomax, nxtmax; /* second sync amplitude buffer */
                    973:        static int epopos;      /* epoch second sync position buffer */
                    974: 
                    975:        static int iniflg;      /* initialization flag */
                    976:        int     epoch;          /* comb filter index */
                    977:        double  dtemp;
                    978:        int     i;
                    979: 
                    980:        pp = peer->procptr;
                    981:        up = (struct wwvunit *)pp->unitptr;
                    982: 
                    983:        if (!iniflg) {
                    984:                iniflg = 1;
                    985:                memset((char *)lpf, 0, sizeof(lpf));
                    986:                memset((char *)bpf, 0, sizeof(bpf));
                    987:                memset((char *)mf, 0, sizeof(mf));
                    988:                memset((char *)ibuf, 0, sizeof(ibuf));
                    989:                memset((char *)qbuf, 0, sizeof(qbuf));
                    990:                memset((char *)cibuf, 0, sizeof(cibuf));
                    991:                memset((char *)cqbuf, 0, sizeof(cqbuf));
                    992:                memset((char *)csibuf, 0, sizeof(csibuf));
                    993:                memset((char *)csqbuf, 0, sizeof(csqbuf));
                    994:                memset((char *)hibuf, 0, sizeof(hibuf));
                    995:                memset((char *)hqbuf, 0, sizeof(hqbuf));
                    996:                memset((char *)hsibuf, 0, sizeof(hsibuf));
                    997:                memset((char *)hsqbuf, 0, sizeof(hsqbuf));
                    998:                memset((char *)epobuf, 0, sizeof(epobuf));
                    999:        }
                   1000: 
                   1001:        /*
                   1002:         * Baseband data demodulation. The 100-Hz subcarrier is
                   1003:         * extracted using a 150-Hz IIR lowpass filter. This attenuates
                   1004:         * the 1000/1200-Hz sync signals, as well as the 440-Hz and
                   1005:         * 600-Hz tones and most of the noise and voice modulation
                   1006:         * components.
                   1007:         *
                   1008:         * The subcarrier is transmitted 10 dB down from the carrier.
                   1009:         * The DGAIN parameter can be adjusted for this and to
                   1010:         * compensate for the radio audio response at 100 Hz.
                   1011:         *
                   1012:         * Matlab IIR 4th-order IIR elliptic, 150 Hz lowpass, 0.2 dB
                   1013:         * passband ripple, -50 dB stopband ripple, phase delay 0.97 ms.
                   1014:         */
                   1015:        data = (lpf[4] = lpf[3]) * 8.360961e-01;
                   1016:        data += (lpf[3] = lpf[2]) * -3.481740e+00;
                   1017:        data += (lpf[2] = lpf[1]) * 5.452988e+00;
                   1018:        data += (lpf[1] = lpf[0]) * -3.807229e+00;
                   1019:        lpf[0] = isig * DGAIN - data;
                   1020:        data = lpf[0] * 3.281435e-03
                   1021:            + lpf[1] * -1.149947e-02
                   1022:            + lpf[2] * 1.654858e-02
                   1023:            + lpf[3] * -1.149947e-02
                   1024:            + lpf[4] * 3.281435e-03;
                   1025: 
                   1026:        /*
                   1027:         * The 100-Hz data signal is demodulated using a pair of
                   1028:         * quadrature multipliers, matched filters and a phase lock
                   1029:         * loop. The I and Q quadrature data signals are produced by
                   1030:         * multiplying the filtered signal by 100-Hz sine and cosine
                   1031:         * signals, respectively. The signals are processed by 170-ms
                   1032:         * synchronous matched filters to produce the amplitude and
                   1033:         * phase signals used by the demodulator. The signals are scaled
                   1034:         * to produce unit energy at the maximum value.
                   1035:         */
                   1036:        i = up->datapt;
                   1037:        up->datapt = (up->datapt + IN100) % 80;
                   1038:        dtemp = sintab[i] * data / (MS / 2. * DATCYC);
                   1039:        up->irig -= ibuf[iptr];
                   1040:        ibuf[iptr] = dtemp;
                   1041:        up->irig += dtemp;
                   1042: 
                   1043:        i = (i + 20) % 80;
                   1044:        dtemp = sintab[i] * data / (MS / 2. * DATCYC);
                   1045:        up->qrig -= qbuf[iptr];
                   1046:        qbuf[iptr] = dtemp;
                   1047:        up->qrig += dtemp;
                   1048:        iptr = (iptr + 1) % DATSIZ;
                   1049: 
                   1050:        /*
                   1051:         * Baseband sync demodulation. The 1000/1200 sync signals are
                   1052:         * extracted using a 600-Hz IIR bandpass filter. This removes
                   1053:         * the 100-Hz data subcarrier, as well as the 440-Hz and 600-Hz
                   1054:         * tones and most of the noise and voice modulation components.
                   1055:         *
                   1056:         * Matlab 4th-order IIR elliptic, 800-1400 Hz bandpass, 0.2 dB
                   1057:         * passband ripple, -50 dB stopband ripple, phase delay 0.91 ms.
                   1058:         */
                   1059:        syncx = (bpf[8] = bpf[7]) * 4.897278e-01;
                   1060:        syncx += (bpf[7] = bpf[6]) * -2.765914e+00;
                   1061:        syncx += (bpf[6] = bpf[5]) * 8.110921e+00;
                   1062:        syncx += (bpf[5] = bpf[4]) * -1.517732e+01;
                   1063:        syncx += (bpf[4] = bpf[3]) * 1.975197e+01;
                   1064:        syncx += (bpf[3] = bpf[2]) * -1.814365e+01;
                   1065:        syncx += (bpf[2] = bpf[1]) * 1.159783e+01;
                   1066:        syncx += (bpf[1] = bpf[0]) * -4.735040e+00;
                   1067:        bpf[0] = isig - syncx;
                   1068:        syncx = bpf[0] * 8.203628e-03
                   1069:            + bpf[1] * -2.375732e-02
                   1070:            + bpf[2] * 3.353214e-02
                   1071:            + bpf[3] * -4.080258e-02
                   1072:            + bpf[4] * 4.605479e-02
                   1073:            + bpf[5] * -4.080258e-02
                   1074:            + bpf[6] * 3.353214e-02
                   1075:            + bpf[7] * -2.375732e-02
                   1076:            + bpf[8] * 8.203628e-03;
                   1077: 
                   1078:        /*
                   1079:         * The 1000/1200 sync signals are demodulated using a pair of
                   1080:         * quadrature multipliers and matched filters. However,
                   1081:         * synchronous demodulation at these frequencies is impractical,
                   1082:         * so only the signal amplitude is used. The I and Q quadrature
                   1083:         * sync signals are produced by multiplying the filtered signal
                   1084:         * by 1000-Hz (WWV) and 1200-Hz (WWVH) sine and cosine signals,
                   1085:         * respectively. The WWV and WWVH signals are processed by 800-
                   1086:         * ms synchronous matched filters and combined to produce the
                   1087:         * minute sync signal and detect which one (or both) the WWV or
                   1088:         * WWVH signal is present. The WWV and WWVH signals are also
                   1089:         * processed by 5-ms synchronous matched filters and combined to
                   1090:         * produce the second sync signal. The signals are scaled to
                   1091:         * produce unit energy at the maximum value.
                   1092:         *
                   1093:         * Note the master timing ramps, which run continuously. The
                   1094:         * minute counter (mphase) counts the samples in the minute,
                   1095:         * while the second counter (epoch) counts the samples in the
                   1096:         * second.
                   1097:         */
                   1098:        up->mphase = (up->mphase + 1) % MINUTE;
                   1099:        epoch = up->mphase % SECOND;
                   1100: 
                   1101:        /*
                   1102:         * WWV
                   1103:         */
                   1104:        i = csinptr;
                   1105:        csinptr = (csinptr + IN1000) % 80;
                   1106: 
                   1107:        dtemp = sintab[i] * syncx / (MS / 2.);
                   1108:        ciamp -= cibuf[jptr];
                   1109:        cibuf[jptr] = dtemp;
                   1110:        ciamp += dtemp;
                   1111:        csiamp -= csibuf[kptr];
                   1112:        csibuf[kptr] = dtemp;
                   1113:        csiamp += dtemp;
                   1114: 
                   1115:        i = (i + 20) % 80;
                   1116:        dtemp = sintab[i] * syncx / (MS / 2.);
                   1117:        cqamp -= cqbuf[jptr];
                   1118:        cqbuf[jptr] = dtemp;
                   1119:        cqamp += dtemp;
                   1120:        csqamp -= csqbuf[kptr];
                   1121:        csqbuf[kptr] = dtemp;
                   1122:        csqamp += dtemp;
                   1123: 
                   1124:        sp = &up->mitig[up->achan].wwv;
                   1125:        sp->amp = sqrt(ciamp * ciamp + cqamp * cqamp) / SYNCYC;
                   1126:        if (!(up->status & MSYNC))
                   1127:                wwv_qrz(peer, sp, (int)(pp->fudgetime1 * SECOND));
                   1128: 
                   1129:        /*
                   1130:         * WWVH
                   1131:         */
                   1132:        i = hsinptr;
                   1133:        hsinptr = (hsinptr + IN1200) % 80;
                   1134: 
                   1135:        dtemp = sintab[i] * syncx / (MS / 2.);
                   1136:        hiamp -= hibuf[jptr];
                   1137:        hibuf[jptr] = dtemp;
                   1138:        hiamp += dtemp;
                   1139:        hsiamp -= hsibuf[kptr];
                   1140:        hsibuf[kptr] = dtemp;
                   1141:        hsiamp += dtemp;
                   1142: 
                   1143:        i = (i + 20) % 80;
                   1144:        dtemp = sintab[i] * syncx / (MS / 2.);
                   1145:        hqamp -= hqbuf[jptr];
                   1146:        hqbuf[jptr] = dtemp;
                   1147:        hqamp += dtemp;
                   1148:        hsqamp -= hsqbuf[kptr];
                   1149:        hsqbuf[kptr] = dtemp;
                   1150:        hsqamp += dtemp;
                   1151: 
                   1152:        rp = &up->mitig[up->achan].wwvh;
                   1153:        rp->amp = sqrt(hiamp * hiamp + hqamp * hqamp) / SYNCYC;
                   1154:        if (!(up->status & MSYNC))
                   1155:                wwv_qrz(peer, rp, (int)(pp->fudgetime2 * SECOND));
                   1156:        jptr = (jptr + 1) % SYNSIZ;
                   1157:        kptr = (kptr + 1) % TCKSIZ;
                   1158: 
                   1159:        /*
                   1160:         * The following section is called once per minute. It does
                   1161:         * housekeeping and timeout functions and empties the dustbins.
                   1162:         */
                   1163:        if (up->mphase == 0) {
                   1164:                up->watch++;
                   1165:                if (!(up->status & MSYNC)) {
                   1166: 
                   1167:                        /*
                   1168:                         * If minute sync has not been acquired before
                   1169:                         * ACQSN timeout (6 min), or if no signal is
                   1170:                         * heard, the program cycles to the next
                   1171:                         * frequency and tries again.
                   1172:                         */
                   1173:                        if (!wwv_newchan(peer))
                   1174:                                up->watch = 0;
                   1175:                } else {
                   1176: 
                   1177:                        /*
                   1178:                         * If the leap bit is set, set the minute epoch
                   1179:                         * back one second so the station processes
                   1180:                         * don't miss a beat.
                   1181:                         */
                   1182:                        if (up->status & LEPSEC) {
                   1183:                                up->mphase -= SECOND;
                   1184:                                if (up->mphase < 0)
                   1185:                                        up->mphase += MINUTE;
                   1186:                        }
                   1187:                }
                   1188:        }
                   1189: 
                   1190:        /*
                   1191:         * When the channel metric reaches threshold and the second
                   1192:         * counter matches the minute epoch within the second, the
                   1193:         * driver has synchronized to the station. The second number is
                   1194:         * the remaining seconds until the next minute epoch, while the
                   1195:         * sync epoch is zero. Watch out for the first second; if
                   1196:         * already synchronized to the second, the buffered sync epoch
                   1197:         * must be set.
                   1198:         *
                   1199:         * Note the guard interval is 200 ms; if for some reason the
                   1200:         * clock drifts more than that, it might wind up in the wrong
                   1201:         * second. If the maximum frequency error is not more than about
                   1202:         * 1 PPM, the clock can go as much as two days while still in
                   1203:         * the same second.
                   1204:         */
                   1205:        if (up->status & MSYNC) {
                   1206:                wwv_epoch(peer);
                   1207:        } else if (up->sptr != NULL) {
                   1208:                sp = up->sptr;
                   1209:                if (sp->metric >= TTHR && epoch == sp->mepoch % SECOND)
                   1210:                    {
                   1211:                        up->rsec = (60 - sp->mepoch / SECOND) % 60;
                   1212:                        up->rphase = 0;
                   1213:                        up->status |= MSYNC;
                   1214:                        up->watch = 0;
                   1215:                        if (!(up->status & SSYNC))
                   1216:                                up->repoch = up->yepoch = epoch;
                   1217:                        else
                   1218:                                up->repoch = up->yepoch;
                   1219:                        
                   1220:                }
                   1221:        }
                   1222: 
                   1223:        /*
                   1224:         * The second sync pulse is extracted using 5-ms (40 sample) FIR
                   1225:         * matched filters at 1000 Hz for WWV or 1200 Hz for WWVH. This
                   1226:         * pulse is used for the most precise synchronization, since if
                   1227:         * provides a resolution of one sample (125 us). The filters run
                   1228:         * only if the station has been reliably determined.
                   1229:         */
                   1230:        if (up->status & SELV)
                   1231:                mfsync = sqrt(csiamp * csiamp + csqamp * csqamp) /
                   1232:                    TCKCYC;
                   1233:        else if (up->status & SELH)
                   1234:                mfsync = sqrt(hsiamp * hsiamp + hsqamp * hsqamp) /
                   1235:                    TCKCYC;
                   1236:        else
                   1237:                mfsync = 0;
                   1238: 
                   1239:        /*
                   1240:         * Enhance the seconds sync pulse using a 1-s (8000-sample) comb
                   1241:         * filter. Correct for the FIR matched filter delay, which is 5
                   1242:         * ms for both the WWV and WWVH filters, and also for the
                   1243:         * propagation delay. Once each second look for second sync. If
                   1244:         * not in minute sync, fiddle the codec gain. Note the SNR is
                   1245:         * computed from the maximum sample and the envelope of the
                   1246:         * sample 6 ms before it, so if we slip more than a cycle the
                   1247:         * SNR should plummet. The signal is scaled to produce unit
                   1248:         * energy at the maximum value.
                   1249:         */
                   1250:        dtemp = (epobuf[epoch] += (mfsync - epobuf[epoch]) /
                   1251:            up->avgint);
                   1252:        if (dtemp > epomax) {
                   1253:                int     j;
                   1254: 
                   1255:                epomax = dtemp;
                   1256:                epopos = epoch;
                   1257:                j = epoch - 6 * MS;
                   1258:                if (j < 0)
                   1259:                        j += SECOND;
                   1260:                nxtmax = fabs(epobuf[j]);
                   1261:        }
                   1262:        if (epoch == 0) {
                   1263:                up->epomax = epomax;
                   1264:                up->eposnr = wwv_snr(epomax, nxtmax);
                   1265:                epopos -= TCKCYC * MS;
                   1266:                if (epopos < 0)
                   1267:                        epopos += SECOND;
                   1268:                wwv_endpoc(peer, epopos);
                   1269:                if (!(up->status & SSYNC))
                   1270:                        up->alarm |= SYNERR;
                   1271:                epomax = 0;
                   1272:                if (!(up->status & MSYNC))
                   1273:                        wwv_gain(peer);
                   1274:        }
                   1275: }
                   1276: 
                   1277: 
                   1278: /*
                   1279:  * wwv_qrz - identify and acquire WWV/WWVH minute sync pulse
                   1280:  *
                   1281:  * This routine implements a virtual station process used to acquire
                   1282:  * minute sync and to mitigate among the ten frequency and station
                   1283:  * combinations. During minute sync acquisition the process probes each
                   1284:  * frequency and station in turn for the minute pulse, which
                   1285:  * involves searching through the entire 480,000-sample minute. The
                   1286:  * process finds the maximum signal and RMS noise plus signal. Then, the
                   1287:  * actual noise is determined by subtracting the energy of the matched
                   1288:  * filter.
                   1289:  *
                   1290:  * Students of radar receiver technology will discover this algorithm
                   1291:  * amounts to a range-gate discriminator. A valid pulse must have peak
                   1292:  * amplitude at least QTHR (2500) and SNR at least QSNR (20) dB and the
                   1293:  * difference between the current and previous epoch must be less than
                   1294:  * AWND (20 ms). Note that the discriminator peak occurs about 800 ms
                   1295:  * into the second, so the timing is retarded to the previous second
                   1296:  * epoch.
                   1297:  */
                   1298: static void
                   1299: wwv_qrz(
                   1300:        struct peer *peer,      /* peer structure pointer */
                   1301:        struct sync *sp,        /* sync channel structure */
                   1302:        int     pdelay          /* propagation delay (samples) */
                   1303:        )
                   1304: {
                   1305:        struct refclockproc *pp;
                   1306:        struct wwvunit *up;
                   1307:        char    tbuf[TBUF];     /* monitor buffer */
                   1308:        long    epoch;
                   1309: 
                   1310:        pp = peer->procptr;
                   1311:        up = (struct wwvunit *)pp->unitptr;
                   1312: 
                   1313:        /*
                   1314:         * Find the sample with peak amplitude, which defines the minute
                   1315:         * epoch. Accumulate all samples to determine the total noise
                   1316:         * energy.
                   1317:         */
                   1318:        epoch = up->mphase - pdelay - SYNSIZ;
                   1319:        if (epoch < 0)
                   1320:                epoch += MINUTE;
                   1321:        if (sp->amp > sp->maxeng) {
                   1322:                sp->maxeng = sp->amp;
                   1323:                sp->pos = epoch;
                   1324:        }
                   1325:        sp->noieng += sp->amp;
                   1326: 
                   1327:        /*
                   1328:         * At the end of the minute, determine the epoch of the minute
                   1329:         * sync pulse, as well as the difference between the current and
                   1330:         * previous epoches due to the intrinsic frequency error plus
                   1331:         * jitter. When calculating the SNR, subtract the pulse energy
                   1332:         * from the total noise energy and then normalize.
                   1333:         */
                   1334:        if (up->mphase == 0) {
                   1335:                sp->synmax = sp->maxeng;
                   1336:                sp->synsnr = wwv_snr(sp->synmax, (sp->noieng -
                   1337:                    sp->synmax) / MINUTE);
                   1338:                if (sp->count == 0)
                   1339:                        sp->lastpos = sp->pos;
                   1340:                epoch = (sp->pos - sp->lastpos) % MINUTE;
                   1341:                sp->reach <<= 1;
                   1342:                if (sp->reach & (1 << AMAX))
                   1343:                        sp->count--;
                   1344:                if (sp->synmax > ATHR && sp->synsnr > ASNR) {
                   1345:                        if (abs(epoch) < AWND * MS) {
                   1346:                                sp->reach |= 1;
                   1347:                                sp->count++;
                   1348:                                sp->mepoch = sp->lastpos = sp->pos;
                   1349:                        } else if (sp->count == 1) {
                   1350:                                sp->lastpos = sp->pos;
                   1351:                        }
                   1352:                }
                   1353:                if (up->watch > ACQSN)
                   1354:                        sp->metric = 0;
                   1355:                else
                   1356:                        sp->metric = wwv_metric(sp);
                   1357:                if (pp->sloppyclockflag & CLK_FLAG4) {
                   1358:                        sprintf(tbuf,
                   1359:                            "wwv8 %04x %3d %s %04x %.0f %.0f/%.1f %ld %ld",
                   1360:                            up->status, up->gain, sp->refid,
                   1361:                            sp->reach & 0xffff, sp->metric, sp->synmax,
                   1362:                            sp->synsnr, sp->pos % SECOND, epoch);
                   1363:                        record_clock_stats(&peer->srcadr, tbuf);
                   1364: #ifdef DEBUG
                   1365:                        if (debug)
                   1366:                                printf("%s\n", tbuf);
                   1367: #endif /* DEBUG */
                   1368:                }
                   1369:                sp->maxeng = sp->noieng = 0;
                   1370:        }
                   1371: }
                   1372: 
                   1373: 
                   1374: /*
                   1375:  * wwv_endpoc - identify and acquire second sync pulse
                   1376:  *
                   1377:  * This routine is called at the end of the second sync interval. It
                   1378:  * determines the second sync epoch position within the second and
                   1379:  * disciplines the sample clock using a frequency-lock loop (FLL).
                   1380:  *
                   1381:  * Second sync is determined in the RF input routine as the maximum
                   1382:  * over all 8000 samples in the second comb filter. To assure accurate
                   1383:  * and reliable time and frequency discipline, this routine performs a
                   1384:  * great deal of heavy-handed heuristic data filtering and grooming.
                   1385:  */
                   1386: static void
                   1387: wwv_endpoc(
                   1388:        struct peer *peer,      /* peer structure pointer */
                   1389:        int epopos              /* epoch max position */
                   1390:        )
                   1391: {
                   1392:        struct refclockproc *pp;
                   1393:        struct wwvunit *up;
                   1394:        static int epoch_mf[3]; /* epoch median filter */
                   1395:        static int tepoch;      /* current second epoch */
                   1396:        static int xepoch;      /* last second epoch */
                   1397:        static int zepoch;      /* last run epoch */
                   1398:        static int zcount;      /* last run end time */
                   1399:        static int scount;      /* seconds counter */
                   1400:        static int syncnt;      /* run length counter */
                   1401:        static int maxrun;      /* longest run length */
                   1402:        static int mepoch;      /* longest run end epoch */
                   1403:        static int mcount;      /* longest run end time */
                   1404:        static int avgcnt;      /* averaging interval counter */
                   1405:        static int avginc;      /* averaging ratchet */
                   1406:        static int iniflg;      /* initialization flag */
                   1407:        char tbuf[TBUF];                /* monitor buffer */
                   1408:        double dtemp;
                   1409:        int tmp2;
                   1410: 
                   1411:        pp = peer->procptr;
                   1412:        up = (struct wwvunit *)pp->unitptr;
                   1413:        if (!iniflg) {
                   1414:                iniflg = 1;
                   1415:                memset((char *)epoch_mf, 0, sizeof(epoch_mf));
                   1416:        }
                   1417: 
                   1418:        /*
                   1419:         * If the signal amplitude or SNR fall below thresholds, dim the
                   1420:         * second sync lamp and wait for hotter ions. If no stations are
                   1421:         * heard, we are either in a probe cycle or the ions are really
                   1422:         * cold. 
                   1423:         */
                   1424:        scount++;
                   1425:        if (up->epomax < STHR || up->eposnr < SSNR) {
                   1426:                up->status &= ~(SSYNC | FGATE);
                   1427:                avgcnt = syncnt = maxrun = 0;
                   1428:                return;
                   1429:        }
                   1430:        if (!(up->status & (SELV | SELH)))
                   1431:                return;
                   1432: 
                   1433:        /*
                   1434:         * A three-stage median filter is used to help denoise the
                   1435:         * second sync pulse. The median sample becomes the candidate
                   1436:         * epoch.
                   1437:         */
                   1438:        epoch_mf[2] = epoch_mf[1];
                   1439:        epoch_mf[1] = epoch_mf[0];
                   1440:        epoch_mf[0] = epopos;
                   1441:        if (epoch_mf[0] > epoch_mf[1]) {
                   1442:                if (epoch_mf[1] > epoch_mf[2])
                   1443:                        tepoch = epoch_mf[1];   /* 0 1 2 */
                   1444:                else if (epoch_mf[2] > epoch_mf[0])
                   1445:                        tepoch = epoch_mf[0];   /* 2 0 1 */
                   1446:                else
                   1447:                        tepoch = epoch_mf[2];   /* 0 2 1 */
                   1448:        } else {
                   1449:                if (epoch_mf[1] < epoch_mf[2])
                   1450:                        tepoch = epoch_mf[1];   /* 2 1 0 */
                   1451:                else if (epoch_mf[2] < epoch_mf[0])
                   1452:                        tepoch = epoch_mf[0];   /* 1 0 2 */
                   1453:                else
                   1454:                        tepoch = epoch_mf[2];   /* 1 2 0 */
                   1455:        }
                   1456: 
                   1457: 
                   1458:        /*
                   1459:         * If the epoch candidate is the same as the last one, increment
                   1460:         * the run counter. If not, save the length, epoch and end
                   1461:         * time of the current run for use later and reset the counter.
                   1462:         * The epoch is considered valid if the run is at least SCMP
                   1463:         * (10) s, the minute is synchronized and the interval since the
                   1464:         * last epoch  is not greater than the averaging interval. Thus,
                   1465:         * after a long absence, the program will wait a full averaging
                   1466:         * interval while the comb filter charges up and noise
                   1467:         * dissapates..
                   1468:         */
                   1469:        tmp2 = (tepoch - xepoch) % SECOND;
                   1470:        if (tmp2 == 0) {
                   1471:                syncnt++;
                   1472:                if (syncnt > SCMP && up->status & MSYNC && (up->status &
                   1473:                    FGATE || scount - zcount <= up->avgint)) {
                   1474:                        up->status |= SSYNC;
                   1475:                        up->yepoch = tepoch;
                   1476:                }
                   1477:        } else if (syncnt >= maxrun) {
                   1478:                maxrun = syncnt;
                   1479:                mcount = scount;
                   1480:                mepoch = xepoch;
                   1481:                syncnt = 0;
                   1482:        }
                   1483:        if ((pp->sloppyclockflag & CLK_FLAG4) && !(up->status &
                   1484:            MSYNC)) {
                   1485:                sprintf(tbuf,
                   1486:                    "wwv1 %04x %3d %4d %5.0f %5.1f %5d %4d %4d %4d",
                   1487:                    up->status, up->gain, tepoch, up->epomax,
                   1488:                    up->eposnr, tmp2, avgcnt, syncnt,
                   1489:                    maxrun);
                   1490:                record_clock_stats(&peer->srcadr, tbuf);
                   1491: #ifdef DEBUG
                   1492:                if (debug)
                   1493:                        printf("%s\n", tbuf);
                   1494: #endif /* DEBUG */
                   1495:        }
                   1496:        avgcnt++;
                   1497:        if (avgcnt < up->avgint) {
                   1498:                xepoch = tepoch;
                   1499:                return;
                   1500:        }
                   1501: 
                   1502:        /*
                   1503:         * The sample clock frequency is disciplined using a first-order
                   1504:         * feedback loop with time constant consistent with the Allan
                   1505:         * intercept of typical computer clocks. During each averaging
                   1506:         * interval the candidate epoch at the end of the longest run is
                   1507:         * determined. If the longest run is zero, all epoches in the
                   1508:         * interval are different, so the candidate epoch is the current
                   1509:         * epoch. The frequency update is computed from the candidate
                   1510:         * epoch difference (125-us units) and time difference (seconds)
                   1511:         * between updates.
                   1512:         */
                   1513:        if (syncnt >= maxrun) {
                   1514:                maxrun = syncnt;
                   1515:                mcount = scount;
                   1516:                mepoch = xepoch;
                   1517:        }
                   1518:        xepoch = tepoch;
                   1519:        if (maxrun == 0) {
                   1520:                mepoch = tepoch;
                   1521:                mcount = scount;
                   1522:        }
                   1523: 
                   1524:        /*
                   1525:         * The master clock runs at the codec sample frequency of 8000
                   1526:         * Hz, so the intrinsic time resolution is 125 us. The frequency
                   1527:         * resolution ranges from 18 PPM at the minimum averaging
                   1528:         * interval of 8 s to 0.12 PPM at the maximum interval of 1024
                   1529:         * s. An offset update is determined at the end of the longest
                   1530:         * run in each averaging interval. The frequency adjustment is
                   1531:         * computed from the difference between offset updates and the
                   1532:         * interval between them.
                   1533:         *
                   1534:         * The maximum frequency adjustment ranges from 187 PPM at the
                   1535:         * minimum interval to 1.5 PPM at the maximum. If the adjustment
                   1536:         * exceeds the maximum, the update is discarded and the
                   1537:         * hysteresis counter is decremented. Otherwise, the frequency
                   1538:         * is incremented by the adjustment, but clamped to the maximum
                   1539:         * 187.5 PPM. If the update is less than half the maximum, the
                   1540:         * hysteresis counter is incremented. If the counter increments
                   1541:         * to +3, the averaging interval is doubled and the counter set
                   1542:         * to zero; if it decrements to -3, the interval is halved and
                   1543:         * the counter set to zero.
                   1544:         */
                   1545:        dtemp = (mepoch - zepoch) % SECOND;
                   1546:        if (up->status & FGATE) {
                   1547:                if (abs(dtemp) < MAXFREQ * MINAVG) {
                   1548:                        up->freq += (dtemp / 2.) / ((mcount - zcount) *
                   1549:                            FCONST);
                   1550:                        if (up->freq > MAXFREQ)
                   1551:                                up->freq = MAXFREQ;
                   1552:                        else if (up->freq < -MAXFREQ)
                   1553:                                up->freq = -MAXFREQ;
                   1554:                        if (abs(dtemp) < MAXFREQ * MINAVG / 2.) {
                   1555:                                if (avginc < 3) {
                   1556:                                        avginc++;
                   1557:                                } else {
                   1558:                                        if (up->avgint < MAXAVG) {
                   1559:                                                up->avgint <<= 1;
                   1560:                                                avginc = 0;
                   1561:                                        }
                   1562:                                }
                   1563:                        }
                   1564:                } else {
                   1565:                        if (avginc > -3) {
                   1566:                                avginc--;
                   1567:                        } else {
                   1568:                                if (up->avgint > MINAVG) {
                   1569:                                        up->avgint >>= 1;
                   1570:                                        avginc = 0;
                   1571:                                }
                   1572:                        }
                   1573:                }
                   1574:        }
                   1575:        if (pp->sloppyclockflag & CLK_FLAG4) {
                   1576:                sprintf(tbuf,
                   1577:                    "wwv2 %04x %5.0f %5.1f %5d %4d %4d %4d %4.0f %7.2f",
                   1578:                    up->status, up->epomax, up->eposnr, mepoch,
                   1579:                    up->avgint, maxrun, mcount - zcount, dtemp,
                   1580:                    up->freq * 1e6 / SECOND);
                   1581:                record_clock_stats(&peer->srcadr, tbuf);
                   1582: #ifdef DEBUG
                   1583:                if (debug)
                   1584:                        printf("%s\n", tbuf);
                   1585: #endif /* DEBUG */
                   1586:        }
                   1587: 
                   1588:        /*
                   1589:         * This is a valid update; set up for the next interval.
                   1590:         */
                   1591:        up->status |= FGATE;
                   1592:        zepoch = mepoch;
                   1593:        zcount = mcount;
                   1594:        avgcnt = syncnt = maxrun = 0;
                   1595: }
                   1596: 
                   1597: 
                   1598: /*
                   1599:  * wwv_epoch - epoch scanner
                   1600:  *
                   1601:  * This routine extracts data signals from the 100-Hz subcarrier. It
                   1602:  * scans the receiver second epoch to determine the signal amplitudes
                   1603:  * and pulse timings. Receiver synchronization is determined by the
                   1604:  * minute sync pulse detected in the wwv_rf() routine and the second
                   1605:  * sync pulse detected in the wwv_epoch() routine. The transmitted
                   1606:  * signals are delayed by the propagation delay, receiver delay and
                   1607:  * filter delay of this program. Delay corrections are introduced
                   1608:  * separately for WWV and WWVH. 
                   1609:  *
                   1610:  * Most communications radios use a highpass filter in the audio stages,
                   1611:  * which can do nasty things to the subcarrier phase relative to the
                   1612:  * sync pulses. Therefore, the data subcarrier reference phase is
                   1613:  * disciplined using the hardlimited quadrature-phase signal sampled at
                   1614:  * the same time as the in-phase signal. The phase tracking loop uses
                   1615:  * phase adjustments of plus-minus one sample (125 us). 
                   1616:  */
                   1617: static void
                   1618: wwv_epoch(
                   1619:        struct peer *peer       /* peer structure pointer */
                   1620:        )
                   1621: {
                   1622:        struct refclockproc *pp;
                   1623:        struct wwvunit *up;
                   1624:        struct chan *cp;
                   1625:        static double sigmin, sigzer, sigone, engmax, engmin;
                   1626: 
                   1627:        pp = peer->procptr;
                   1628:        up = (struct wwvunit *)pp->unitptr;
                   1629: 
                   1630:        /*
                   1631:         * Find the maximum minute sync pulse energy for both the
                   1632:         * WWV and WWVH stations. This will be used later for channel
                   1633:         * and station mitigation. Also set the seconds epoch at 800 ms
                   1634:         * well before the end of the second to make sure we never set
                   1635:         * the epoch backwards.
                   1636:         */
                   1637:        cp = &up->mitig[up->achan];
                   1638:        if (cp->wwv.amp > cp->wwv.syneng) 
                   1639:                cp->wwv.syneng = cp->wwv.amp;
                   1640:        if (cp->wwvh.amp > cp->wwvh.syneng) 
                   1641:                cp->wwvh.syneng = cp->wwvh.amp;
                   1642:        if (up->rphase == 800 * MS)
                   1643:                up->repoch = up->yepoch;
                   1644: 
                   1645:        /*
                   1646:         * Use the signal amplitude at epoch 15 ms as the noise floor.
                   1647:         * This gives a guard time of +-15 ms from the beginning of the
                   1648:         * second until the second pulse rises at 30 ms. There is a
                   1649:         * compromise here; we want to delay the sample as long as
                   1650:         * possible to give the radio time to change frequency and the
                   1651:         * AGC to stabilize, but as early as possible if the second
                   1652:         * epoch is not exact.
                   1653:         */
                   1654:        if (up->rphase == 15 * MS)
                   1655:                sigmin = sigzer = sigone = up->irig;
                   1656: 
                   1657:        /*
                   1658:         * Latch the data signal at 200 ms. Keep this around until the
                   1659:         * end of the second. Use the signal energy as the peak to
                   1660:         * compute the SNR. Use the Q sample to adjust the 100-Hz
                   1661:         * reference oscillator phase.
                   1662:         */
                   1663:        if (up->rphase == 200 * MS) {
                   1664:                sigzer = up->irig;
                   1665:                engmax = sqrt(up->irig * up->irig + up->qrig *
                   1666:                    up->qrig);
                   1667:                up->datpha = up->qrig / up->avgint;
                   1668:                if (up->datpha >= 0) {
                   1669:                        up->datapt++;
                   1670:                        if (up->datapt >= 80)
                   1671:                                up->datapt -= 80;
                   1672:                } else {
                   1673:                        up->datapt--;
                   1674:                        if (up->datapt < 0)
                   1675:                                up->datapt += 80;
                   1676:                }
                   1677:        }
                   1678: 
                   1679: 
                   1680:        /*
                   1681:         * Latch the data signal at 500 ms. Keep this around until the
                   1682:         * end of the second.
                   1683:         */
                   1684:        else if (up->rphase == 500 * MS)
                   1685:                sigone = up->irig;
                   1686: 
                   1687:        /*
                   1688:         * At the end of the second crank the clock state machine and
                   1689:         * adjust the codec gain. Note the epoch is buffered from the
                   1690:         * center of the second in order to avoid jitter while the
                   1691:         * seconds synch is diddling the epoch. Then, determine the true
                   1692:         * offset and update the median filter in the driver interface.
                   1693:         *
                   1694:         * Use the energy at the end of the second as the noise to
                   1695:         * compute the SNR for the data pulse. This gives a better
                   1696:         * measurement than the beginning of the second, especially when
                   1697:         * returning from the probe channel. This gives a guard time of
                   1698:         * 30 ms from the decay of the longest pulse to the rise of the
                   1699:         * next pulse.
                   1700:         */
                   1701:        up->rphase++;
                   1702:        if (up->mphase % SECOND == up->repoch) {
                   1703:                up->status &= ~(DGATE | BGATE);
                   1704:                engmin = sqrt(up->irig * up->irig + up->qrig *
                   1705:                    up->qrig);
                   1706:                up->datsig = engmax;
                   1707:                up->datsnr = wwv_snr(engmax, engmin);
                   1708: 
                   1709:                /*
                   1710:                 * If the amplitude or SNR is below threshold, average a
                   1711:                 * 0 in the the integrators; otherwise, average the
                   1712:                 * bipolar signal. This is done to avoid noise polution.
                   1713:                 */
                   1714:                if (engmax < DTHR || up->datsnr < DSNR) {
                   1715:                        up->status |= DGATE;
                   1716:                        wwv_rsec(peer, 0);
                   1717:                } else {
                   1718:                        sigzer -= sigone;
                   1719:                        sigone -= sigmin;
                   1720:                        wwv_rsec(peer, sigone - sigzer);
                   1721:                }
                   1722:                if (up->status & (DGATE | BGATE))
                   1723:                        up->errcnt++;
                   1724:                if (up->errcnt > MAXERR)
                   1725:                        up->alarm |= LOWERR;
                   1726:                wwv_gain(peer);
                   1727:                cp = &up->mitig[up->achan];
                   1728:                cp->wwv.syneng = 0;
                   1729:                cp->wwvh.syneng = 0;
                   1730:                up->rphase = 0;
                   1731:        }
                   1732: }
                   1733: 
                   1734: 
                   1735: /*
                   1736:  * wwv_rsec - process receiver second
                   1737:  *
                   1738:  * This routine is called at the end of each receiver second to
                   1739:  * implement the per-second state machine. The machine assembles BCD
                   1740:  * digit bits, decodes miscellaneous bits and dances the leap seconds.
                   1741:  *
                   1742:  * Normally, the minute has 60 seconds numbered 0-59. If the leap
                   1743:  * warning bit is set, the last minute (1439) of 30 June (day 181 or 182
                   1744:  * for leap years) or 31 December (day 365 or 366 for leap years) is
                   1745:  * augmented by one second numbered 60. This is accomplished by
                   1746:  * extending the minute interval by one second and teaching the state
                   1747:  * machine to ignore it.
                   1748:  */
                   1749: static void
                   1750: wwv_rsec(
                   1751:        struct peer *peer,      /* peer structure pointer */
                   1752:        double bit
                   1753:        )
                   1754: {
                   1755:        static int iniflg;      /* initialization flag */
                   1756:        static double bcddld[4]; /* BCD data bits */
                   1757:        static double bitvec[61]; /* bit integrator for misc bits */
                   1758:        struct refclockproc *pp;
                   1759:        struct wwvunit *up;
                   1760:        struct chan *cp;
                   1761:        struct sync *sp, *rp;
                   1762:        char    tbuf[TBUF];     /* monitor buffer */
                   1763:        int     sw, arg, nsec;
                   1764: 
                   1765:        pp = peer->procptr;
                   1766:        up = (struct wwvunit *)pp->unitptr;
                   1767:        if (!iniflg) {
                   1768:                iniflg = 1;
                   1769:                memset((char *)bitvec, 0, sizeof(bitvec));
                   1770:        }
                   1771: 
                   1772:        /*
                   1773:         * The bit represents the probability of a hit on zero (negative
                   1774:         * values), a hit on one (positive values) or a miss (zero
                   1775:         * value). The likelihood vector is the exponential average of
                   1776:         * these probabilities. Only the bits of this vector
                   1777:         * corresponding to the miscellaneous bits of the timecode are
                   1778:         * used, but it's easier to do them all. After that, crank the
                   1779:         * seconds state machine.
                   1780:         */
                   1781:        nsec = up->rsec;
                   1782:        up->rsec++;
                   1783:        bitvec[nsec] += (bit - bitvec[nsec]) / TCONST;
                   1784:        sw = progx[nsec].sw;
                   1785:        arg = progx[nsec].arg;
                   1786: 
                   1787:        /*
                   1788:         * The minute state machine. Fly off to a particular section as
                   1789:         * directed by the transition matrix and second number.
                   1790:         */
                   1791:        switch (sw) {
                   1792: 
                   1793:        /*
                   1794:         * Ignore this second.
                   1795:         */
                   1796:        case IDLE:                      /* 9, 45-49 */
                   1797:                break;
                   1798: 
                   1799:        /*
                   1800:         * Probe channel stuff
                   1801:         *
                   1802:         * The WWV/H format contains data pulses in second 59 (position
                   1803:         * identifier) and second 1, but not in second 0. The minute
                   1804:         * sync pulse is contained in second 0. At the end of second 58
                   1805:         * QSY to the probe channel, which rotates in turn over all
                   1806:         * WWV/H frequencies. At the end of second 0 measure the minute
                   1807:         * sync pulse. At the end of second 1 measure the data pulse and
                   1808:         * QSY back to the data channel. Note that the actions commented
                   1809:         * here happen at the end of the second numbered as shown.
                   1810:         *
                   1811:         * At the end of second 0 save the minute sync amplitude latched
                   1812:         * at 800 ms as the signal later used to calculate the SNR. 
                   1813:         */
                   1814:        case SYNC2:                     /* 0 */
                   1815:                cp = &up->mitig[up->achan];
                   1816:                cp->wwv.synmax = cp->wwv.syneng;
                   1817:                cp->wwvh.synmax = cp->wwvh.syneng;
                   1818:                break;
                   1819: 
                   1820:        /*
                   1821:         * At the end of second 1 use the minute sync amplitude latched
                   1822:         * at 800 ms as the noise to calculate the SNR. If the minute
                   1823:         * sync pulse and SNR are above thresholds and the data pulse
                   1824:         * amplitude and SNR are above thresolds, shift a 1 into the
                   1825:         * station reachability register; otherwise, shift a 0. The
                   1826:         * number of 1 bits in the last six intervals is a component of
                   1827:         * the channel metric computed by the wwv_metric() routine.
                   1828:         * Finally, QSY back to the data channel.
                   1829:         */
                   1830:        case SYNC3:                     /* 1 */
                   1831:                cp = &up->mitig[up->achan];
                   1832: 
                   1833:                /*
                   1834:                 * WWV station
                   1835:                 */
                   1836:                sp = &cp->wwv;
                   1837:                sp->synsnr = wwv_snr(sp->synmax, sp->amp);
                   1838:                sp->reach <<= 1;
                   1839:                if (sp->reach & (1 << AMAX))
                   1840:                        sp->count--;
                   1841:                if (sp->synmax >= QTHR && sp->synsnr >= QSNR &&
                   1842:                    !(up->status & (DGATE | BGATE))) {
                   1843:                        sp->reach |= 1;
                   1844:                        sp->count++;
                   1845:                }
                   1846:                sp->metric = wwv_metric(sp);
                   1847: 
                   1848:                /*
                   1849:                 * WWVH station
                   1850:                 */
                   1851:                rp = &cp->wwvh;
                   1852:                rp->synsnr = wwv_snr(rp->synmax, rp->amp);
                   1853:                rp->reach <<= 1;
                   1854:                if (rp->reach & (1 << AMAX))
                   1855:                        rp->count--;
                   1856:                if (rp->synmax >= QTHR && rp->synsnr >= QSNR &&
                   1857:                    !(up->status & (DGATE | BGATE))) {
                   1858:                        rp->reach |= 1;
                   1859:                        rp->count++;
                   1860:                }
                   1861:                rp->metric = wwv_metric(rp);
                   1862:                if (pp->sloppyclockflag & CLK_FLAG4) {
                   1863:                        sprintf(tbuf,
                   1864:                            "wwv5 %04x %3d %4d %.0f/%.1f %.0f/%.1f %s %04x %.0f %.0f/%.1f %s %04x %.0f %.0f/%.1f",
                   1865:                            up->status, up->gain, up->yepoch,
                   1866:                            up->epomax, up->eposnr, up->datsig,
                   1867:                            up->datsnr,
                   1868:                            sp->refid, sp->reach & 0xffff,
                   1869:                            sp->metric, sp->synmax, sp->synsnr,
                   1870:                            rp->refid, rp->reach & 0xffff,
                   1871:                            rp->metric, rp->synmax, rp->synsnr);
                   1872:                        record_clock_stats(&peer->srcadr, tbuf);
                   1873: #ifdef DEBUG
                   1874:                        if (debug)
                   1875:                                printf("%s\n", tbuf);
                   1876: #endif /* DEBUG */
                   1877:                }
                   1878:                up->errcnt = up->digcnt = up->alarm = 0;
                   1879: 
                   1880:                /*
                   1881:                 * If synchronized to a station, restart if no stations
                   1882:                 * have been heard within the PANIC timeout (2 days). If
                   1883:                 * not and the minute digit has been found, restart if
                   1884:                 * not synchronized withing the SYNCH timeout (40 m). If
                   1885:                 * not, restart if the unit digit has not been found
                   1886:                 * within the DATA timeout (15 m).
                   1887:                 */
                   1888:                if (up->status & INSYNC) {
                   1889:                        if (up->watch > PANIC) {
                   1890:                                wwv_newgame(peer);
                   1891:                                return;
                   1892:                        }
                   1893:                } else if (up->status & DSYNC) {
                   1894:                        if (up->watch > SYNCH) {
                   1895:                                wwv_newgame(peer);
                   1896:                                return;
                   1897:                        }
                   1898:                } else if (up->watch > DATA) {
                   1899:                        wwv_newgame(peer);
                   1900:                        return;
                   1901:                }
                   1902:                wwv_newchan(peer);
                   1903:                break;
                   1904: 
                   1905:        /*
                   1906:         * Save the bit probability in the BCD data vector at the index
                   1907:         * given by the argument. Bits not used in the digit are forced
                   1908:         * to zero.
                   1909:         */
                   1910:        case COEF1:                     /* 4-7 */ 
                   1911:                bcddld[arg] = bit;
                   1912:                break;
                   1913: 
                   1914:        case COEF:                      /* 10-13, 15-17, 20-23, 25-26,
                   1915:                                           30-33, 35-38, 40-41, 51-54 */
                   1916:                if (up->status & DSYNC) 
                   1917:                        bcddld[arg] = bit;
                   1918:                else
                   1919:                        bcddld[arg] = 0;
                   1920:                break;
                   1921: 
                   1922:        case COEF2:                     /* 18, 27-28, 42-43 */
                   1923:                bcddld[arg] = 0;
                   1924:                break;
                   1925: 
                   1926:        /*
                   1927:         * Correlate coefficient vector with each valid digit vector and
                   1928:         * save in decoding matrix. We step through the decoding matrix
                   1929:         * digits correlating each with the coefficients and saving the
                   1930:         * greatest and the next lower for later SNR calculation.
                   1931:         */
                   1932:        case DECIM2:                    /* 29 */
                   1933:                wwv_corr4(peer, &up->decvec[arg], bcddld, bcd2);
                   1934:                break;
                   1935: 
                   1936:        case DECIM3:                    /* 44 */
                   1937:                wwv_corr4(peer, &up->decvec[arg], bcddld, bcd3);
                   1938:                break;
                   1939: 
                   1940:        case DECIM6:                    /* 19 */
                   1941:                wwv_corr4(peer, &up->decvec[arg], bcddld, bcd6);
                   1942:                break;
                   1943: 
                   1944:        case DECIM9:                    /* 8, 14, 24, 34, 39 */
                   1945:                wwv_corr4(peer, &up->decvec[arg], bcddld, bcd9);
                   1946:                break;
                   1947: 
                   1948:        /*
                   1949:         * Miscellaneous bits. If above the positive threshold, declare
                   1950:         * 1; if below the negative threshold, declare 0; otherwise
                   1951:         * raise the BGATE bit. The design is intended to avoid
                   1952:         * integrating noise under low SNR conditions.
                   1953:         */
                   1954:        case MSC20:                     /* 55 */
                   1955:                wwv_corr4(peer, &up->decvec[YR + 1], bcddld, bcd9);
                   1956:                /* fall through */
                   1957: 
                   1958:        case MSCBIT:                    /* 2-3, 50, 56-57 */
                   1959:                if (bitvec[nsec] > BTHR) {
                   1960:                        if (!(up->misc & arg))
                   1961:                                up->alarm |= CMPERR;
                   1962:                        up->misc |= arg;
                   1963:                } else if (bitvec[nsec] < -BTHR) {
                   1964:                        if (up->misc & arg)
                   1965:                                up->alarm |= CMPERR;
                   1966:                        up->misc &= ~arg;
                   1967:                } else {
                   1968:                        up->status |= BGATE;
                   1969:                }
                   1970:                break;
                   1971: 
                   1972:        /*
                   1973:         * Save the data channel gain, then QSY to the probe channel and
                   1974:         * dim the seconds comb filters. The www_newchan() routine will
                   1975:         * light them back up.
                   1976:         */
                   1977:        case MSC21:                     /* 58 */
                   1978:                if (bitvec[nsec] > BTHR) {
                   1979:                        if (!(up->misc & arg))
                   1980:                                up->alarm |= CMPERR;
                   1981:                        up->misc |= arg;
                   1982:                } else if (bitvec[nsec] < -BTHR) {
                   1983:                        if (up->misc & arg)
                   1984:                                up->alarm |= CMPERR;
                   1985:                        up->misc &= ~arg;
                   1986:                } else {
                   1987:                        up->status |= BGATE;
                   1988:                }
                   1989:                up->status &= ~(SELV | SELH);
                   1990: #ifdef ICOM
                   1991:                if (up->fd_icom > 0) {
                   1992:                        up->schan = (up->schan + 1) % NCHAN;
                   1993:                        wwv_qsy(peer, up->schan);
                   1994:                } else {
                   1995:                        up->mitig[up->achan].gain = up->gain;
                   1996:                }
                   1997: #else
                   1998:                up->mitig[up->achan].gain = up->gain;
                   1999: #endif /* ICOM */
                   2000:                break;
                   2001: 
                   2002:        /*
                   2003:         * The endgames
                   2004:         *
                   2005:         * During second 59 the receiver and codec AGC are settling
                   2006:         * down, so the data pulse is unusable as quality metric. If
                   2007:         * LEPSEC is set on the last minute of 30 June or 31 December,
                   2008:         * the transmitter and receiver insert an extra second (60) in
                   2009:         * the timescale and the minute sync repeats the second. Once
                   2010:         * leaps occurred at intervals of about 18 months, but the last
                   2011:         * leap before the most recent leap in 1995 was in  1998.
                   2012:         */
                   2013:        case MIN1:                      /* 59 */
                   2014:                if (up->status & LEPSEC)
                   2015:                        break;
                   2016: 
                   2017:                /* fall through */
                   2018: 
                   2019:        case MIN2:                      /* 60 */
                   2020:                up->status &= ~LEPSEC;
                   2021:                wwv_tsec(peer);
                   2022:                up->rsec = 0;
                   2023:                wwv_clock(peer);
                   2024:                break;
                   2025:        }
                   2026:        if ((pp->sloppyclockflag & CLK_FLAG4) && !(up->status &
                   2027:            DSYNC)) {
                   2028:                sprintf(tbuf,
                   2029:                    "wwv3 %2d %04x %3d %4d %5.0f %5.1f %5.0f %5.1f %5.0f",
                   2030:                    nsec, up->status, up->gain, up->yepoch, up->epomax,
                   2031:                    up->eposnr, up->datsig, up->datsnr, bit);
                   2032:                record_clock_stats(&peer->srcadr, tbuf);
                   2033: #ifdef DEBUG
                   2034:                if (debug)
                   2035:                        printf("%s\n", tbuf);
                   2036: #endif /* DEBUG */
                   2037:        }
                   2038:        pp->disp += AUDIO_PHI;
                   2039: }
                   2040: 
                   2041: /*
                   2042:  * The radio clock is set if the alarm bits are all zero. After that,
                   2043:  * the time is considered valid if the second sync bit is lit. It should
                   2044:  * not be a surprise, especially if the radio is not tunable, that
                   2045:  * sometimes no stations are above the noise and the integrators
                   2046:  * discharge below the thresholds. We assume that, after a day of signal
                   2047:  * loss, the minute sync epoch will be in the same second. This requires
                   2048:  * the codec frequency be accurate within 6 PPM. Practical experience
                   2049:  * shows the frequency typically within 0.1 PPM, so after a day of
                   2050:  * signal loss, the time should be within 8.6 ms.. 
                   2051:  */
                   2052: static void
                   2053: wwv_clock(
                   2054:        struct peer *peer       /* peer unit pointer */
                   2055:        )
                   2056: {
                   2057:        struct refclockproc *pp;
                   2058:        struct wwvunit *up;
                   2059:        l_fp    offset;         /* offset in NTP seconds */
                   2060: 
                   2061:        pp = peer->procptr;
                   2062:        up = (struct wwvunit *)pp->unitptr;
                   2063:        if (!(up->status & SSYNC))
                   2064:                up->alarm |= SYNERR;
                   2065:        if (up->digcnt < 9)
                   2066:                up->alarm |= NINERR;
                   2067:        if (!(up->alarm))
                   2068:                up->status |= INSYNC;
                   2069:        if (up->status & INSYNC && up->status & SSYNC) {
                   2070:                if (up->misc & SECWAR)
                   2071:                        pp->leap = LEAP_ADDSECOND;
                   2072:                else
                   2073:                        pp->leap = LEAP_NOWARNING;
                   2074:                pp->second = up->rsec;
                   2075:                pp->minute = up->decvec[MN].digit + up->decvec[MN +
                   2076:                    1].digit * 10;
                   2077:                pp->hour = up->decvec[HR].digit + up->decvec[HR +
                   2078:                    1].digit * 10;
                   2079:                pp->day = up->decvec[DA].digit + up->decvec[DA +
                   2080:                    1].digit * 10 + up->decvec[DA + 2].digit * 100;
                   2081:                pp->year = up->decvec[YR].digit + up->decvec[YR +
                   2082:                    1].digit * 10;
                   2083:                pp->year += 2000;
                   2084:                L_CLR(&offset);
                   2085:                if (!clocktime(pp->day, pp->hour, pp->minute,
                   2086:                    pp->second, GMT, up->timestamp.l_ui,
                   2087:                    &pp->yearstart, &offset.l_ui)) {
                   2088:                        up->errflg = CEVNT_BADTIME;
                   2089:                } else {
                   2090:                        up->watch = 0;
                   2091:                        pp->disp = 0;
                   2092:                        pp->lastref = up->timestamp;
                   2093:                        refclock_process_offset(pp, offset,
                   2094:                            up->timestamp, PDELAY + up->pdelay);
                   2095:                        refclock_receive(peer);
                   2096:                }
                   2097:        }
                   2098:        pp->lencode = timecode(up, pp->a_lastcode);
                   2099:        record_clock_stats(&peer->srcadr, pp->a_lastcode);
                   2100: #ifdef DEBUG
                   2101:        if (debug)
                   2102:                printf("wwv: timecode %d %s\n", pp->lencode,
                   2103:                    pp->a_lastcode);
                   2104: #endif /* DEBUG */
                   2105: }
                   2106: 
                   2107: 
                   2108: /*
                   2109:  * wwv_corr4 - determine maximum-likelihood digit
                   2110:  *
                   2111:  * This routine correlates the received digit vector with the BCD
                   2112:  * coefficient vectors corresponding to all valid digits at the given
                   2113:  * position in the decoding matrix. The maximum value corresponds to the
                   2114:  * maximum-likelihood digit, while the ratio of this value to the next
                   2115:  * lower value determines the likelihood function. Note that, if the
                   2116:  * digit is invalid, the likelihood vector is averaged toward a miss.
                   2117:  */
                   2118: static void
                   2119: wwv_corr4(
                   2120:        struct peer *peer,      /* peer unit pointer */
                   2121:        struct decvec *vp,      /* decoding table pointer */
                   2122:        double  data[],         /* received data vector */
                   2123:        double  tab[][4]        /* correlation vector array */
                   2124:        )
                   2125: {
                   2126:        struct refclockproc *pp;
                   2127:        struct wwvunit *up;
                   2128:        double  topmax, nxtmax; /* metrics */
                   2129:        double  acc;            /* accumulator */
                   2130:        char    tbuf[TBUF];     /* monitor buffer */
                   2131:        int     mldigit;        /* max likelihood digit */
                   2132:        int     i, j;
                   2133: 
                   2134:        pp = peer->procptr;
                   2135:        up = (struct wwvunit *)pp->unitptr;
                   2136: 
                   2137:        /*
                   2138:         * Correlate digit vector with each BCD coefficient vector. If
                   2139:         * any BCD digit bit is bad, consider all bits a miss. Until the
                   2140:         * minute units digit has been resolved, don't to anything else.
                   2141:         * Note the SNR is calculated as the ratio of the largest
                   2142:         * likelihood value to the next largest likelihood value.
                   2143:         */
                   2144:        mldigit = 0;
                   2145:        topmax = nxtmax = -MAXAMP;
                   2146:        for (i = 0; tab[i][0] != 0; i++) {
                   2147:                acc = 0;
                   2148:                for (j = 0; j < 4; j++)
                   2149:                        acc += data[j] * tab[i][j];
                   2150:                acc = (vp->like[i] += (acc - vp->like[i]) / TCONST);
                   2151:                if (acc > topmax) {
                   2152:                        nxtmax = topmax;
                   2153:                        topmax = acc;
                   2154:                        mldigit = i;
                   2155:                } else if (acc > nxtmax) {
                   2156:                        nxtmax = acc;
                   2157:                }
                   2158:        }
                   2159:        vp->digprb = topmax;
                   2160:        vp->digsnr = wwv_snr(topmax, nxtmax);
                   2161: 
                   2162:        /*
                   2163:         * The current maximum-likelihood digit is compared to the last
                   2164:         * maximum-likelihood digit. If different, the compare counter
                   2165:         * and maximum-likelihood digit are reset.  When the compare
                   2166:         * counter reaches the BCMP threshold (3), the digit is assumed
                   2167:         * correct. When the compare counter of all nine digits have
                   2168:         * reached threshold, the clock is assumed correct.
                   2169:         *
                   2170:         * Note that the clock display digit is set before the compare
                   2171:         * counter has reached threshold; however, the clock display is
                   2172:         * not considered correct until all nine clock digits have
                   2173:         * reached threshold. This is intended as eye candy, but avoids
                   2174:         * mistakes when the signal is low and the SNR is very marginal.
                   2175:         */
                   2176:        if (vp->digprb < BTHR || vp->digsnr < BSNR) {
                   2177:                up->status |= BGATE;
                   2178:        } else {
                   2179:                if (vp->digit != mldigit) {
                   2180:                        up->alarm |= CMPERR;
                   2181:                        if (vp->count > 0)
                   2182:                                vp->count--;
                   2183:                        if (vp->count == 0)
                   2184:                                vp->digit = mldigit;
                   2185:                } else {
                   2186:                        if (vp->count < BCMP)
                   2187:                                vp->count++;
                   2188:                        if (vp->count == BCMP) {
                   2189:                                up->status |= DSYNC;
                   2190:                                up->digcnt++;
                   2191:                        }
                   2192:                }
                   2193:        }
                   2194:        if ((pp->sloppyclockflag & CLK_FLAG4) && !(up->status &
                   2195:            INSYNC)) {
                   2196:                sprintf(tbuf,
                   2197:                    "wwv4 %2d %04x %3d %4d %5.0f %2d %d %d %d %5.0f %5.1f",
                   2198:                    up->rsec - 1, up->status, up->gain, up->yepoch,
                   2199:                    up->epomax, vp->radix, vp->digit, mldigit,
                   2200:                    vp->count, vp->digprb, vp->digsnr);
                   2201:                record_clock_stats(&peer->srcadr, tbuf);
                   2202: #ifdef DEBUG
                   2203:                if (debug)
                   2204:                        printf("%s\n", tbuf);
                   2205: #endif /* DEBUG */
                   2206:        }
                   2207: }
                   2208: 
                   2209: 
                   2210: /*
                   2211:  * wwv_tsec - transmitter minute processing
                   2212:  *
                   2213:  * This routine is called at the end of the transmitter minute. It
                   2214:  * implements a state machine that advances the logical clock subject to
                   2215:  * the funny rules that govern the conventional clock and calendar.
                   2216:  */
                   2217: static void
                   2218: wwv_tsec(
                   2219:        struct peer *peer       /* driver structure pointer */
                   2220:        )
                   2221: {
                   2222:        struct refclockproc *pp;
                   2223:        struct wwvunit *up;
                   2224:        int minute, day, isleap;
                   2225:        int temp;
                   2226: 
                   2227:        pp = peer->procptr;
                   2228:        up = (struct wwvunit *)pp->unitptr;
                   2229: 
                   2230:        /*
                   2231:         * Advance minute unit of the day. Don't propagate carries until
                   2232:         * the unit minute digit has been found.
                   2233:         */
                   2234:        temp = carry(&up->decvec[MN]);  /* minute units */
                   2235:        if (!(up->status & DSYNC))
                   2236:                return;
                   2237: 
                   2238:        /*
                   2239:         * Propagate carries through the day.
                   2240:         */ 
                   2241:        if (temp == 0)                  /* carry minutes */
                   2242:                temp = carry(&up->decvec[MN + 1]);
                   2243:        if (temp == 0)                  /* carry hours */
                   2244:                temp = carry(&up->decvec[HR]);
                   2245:        if (temp == 0)
                   2246:                temp = carry(&up->decvec[HR + 1]);
                   2247: 
                   2248:        /*
                   2249:         * Decode the current minute and day. Set leap day if the
                   2250:         * timecode leap bit is set on 30 June or 31 December. Set leap
                   2251:         * minute if the last minute on leap day, but only if the clock
                   2252:         * is syncrhronized. This code fails in 2400 AD.
                   2253:         */
                   2254:        minute = up->decvec[MN].digit + up->decvec[MN + 1].digit *
                   2255:            10 + up->decvec[HR].digit * 60 + up->decvec[HR +
                   2256:            1].digit * 600;
                   2257:        day = up->decvec[DA].digit + up->decvec[DA + 1].digit * 10 +
                   2258:            up->decvec[DA + 2].digit * 100;
                   2259: 
                   2260:        /*
                   2261:         * Set the leap bit on the last minute of the leap day.
                   2262:         */
                   2263:        isleap = up->decvec[YR].digit & 0x3;
                   2264:        if (up->misc & SECWAR && up->status & INSYNC) {
                   2265:                if ((day == (isleap ? 182 : 183) || day == (isleap ?
                   2266:                    365 : 366)) && minute == 1439)
                   2267:                        up->status |= LEPSEC;
                   2268:        }
                   2269: 
                   2270:        /*
                   2271:         * Roll the day if this the first minute and propagate carries
                   2272:         * through the year.
                   2273:         */
                   2274:        if (minute != 1440)
                   2275:                return;
                   2276: 
                   2277:        minute = 0;
                   2278:        while (carry(&up->decvec[HR]) != 0); /* advance to minute 0 */
                   2279:        while (carry(&up->decvec[HR + 1]) != 0);
                   2280:        day++;
                   2281:        temp = carry(&up->decvec[DA]);  /* carry days */
                   2282:        if (temp == 0)
                   2283:                temp = carry(&up->decvec[DA + 1]);
                   2284:        if (temp == 0)
                   2285:                temp = carry(&up->decvec[DA + 2]);
                   2286: 
                   2287:        /*
                   2288:         * Roll the year if this the first day and propagate carries
                   2289:         * through the century.
                   2290:         */
                   2291:        if (day != (isleap ? 365 : 366))
                   2292:                return;
                   2293: 
                   2294:        day = 1;
                   2295:        while (carry(&up->decvec[DA]) != 1); /* advance to day 1 */
                   2296:        while (carry(&up->decvec[DA + 1]) != 0);
                   2297:        while (carry(&up->decvec[DA + 2]) != 0);
                   2298:        temp = carry(&up->decvec[YR]);  /* carry years */
                   2299:        if (temp == 0)
                   2300:                carry(&up->decvec[YR + 1]);
                   2301: }
                   2302: 
                   2303: 
                   2304: /*
                   2305:  * carry - process digit
                   2306:  *
                   2307:  * This routine rotates a likelihood vector one position and increments
                   2308:  * the clock digit modulo the radix. It returns the new clock digit or
                   2309:  * zero if a carry occurred. Once synchronized, the clock digit will
                   2310:  * match the maximum-likelihood digit corresponding to that position.
                   2311:  */
                   2312: static int
                   2313: carry(
                   2314:        struct decvec *dp       /* decoding table pointer */
                   2315:        )
                   2316: {
                   2317:        int temp;
                   2318:        int j;
                   2319: 
                   2320:        dp->digit++;
                   2321:        if (dp->digit == dp->radix)
                   2322:                dp->digit = 0;
                   2323:        temp = dp->like[dp->radix - 1];
                   2324:        for (j = dp->radix - 1; j > 0; j--)
                   2325:                dp->like[j] = dp->like[j - 1];
                   2326:        dp->like[0] = temp;
                   2327:        return (dp->digit);
                   2328: }
                   2329: 
                   2330: 
                   2331: /*
                   2332:  * wwv_snr - compute SNR or likelihood function
                   2333:  */
                   2334: static double
                   2335: wwv_snr(
                   2336:        double signal,          /* signal */
                   2337:        double noise            /* noise */
                   2338:        )
                   2339: {
                   2340:        double rval;
                   2341: 
                   2342:        /*
                   2343:         * This is a little tricky. Due to the way things are measured,
                   2344:         * either or both the signal or noise amplitude can be negative
                   2345:         * or zero. The intent is that, if the signal is negative or
                   2346:         * zero, the SNR must always be zero. This can happen with the
                   2347:         * subcarrier SNR before the phase has been aligned. On the
                   2348:         * other hand, in the likelihood function the "noise" is the
                   2349:         * next maximum down from the peak and this could be negative.
                   2350:         * However, in this case the SNR is truly stupendous, so we
                   2351:         * simply cap at MAXSNR dB (40).
                   2352:         */
                   2353:        if (signal <= 0) {
                   2354:                rval = 0;
                   2355:        } else if (noise <= 0) {
                   2356:                rval = MAXSNR;
                   2357:        } else {
                   2358:                rval = 20. * log10(signal / noise);
                   2359:                if (rval > MAXSNR)
                   2360:                        rval = MAXSNR;
                   2361:        }
                   2362:        return (rval);
                   2363: }
                   2364: 
                   2365: 
                   2366: /*
                   2367:  * wwv_newchan - change to new data channel
                   2368:  *
                   2369:  * The radio actually appears to have ten channels, one channel for each
                   2370:  * of five frequencies and each of two stations (WWV and WWVH), although
                   2371:  * if not tunable only the DCHAN channel appears live. While the radio
                   2372:  * is tuned to the working data channel frequency and station for most
                   2373:  * of the minute, during seconds 59, 0 and 1 the radio is tuned to a
                   2374:  * probe frequency in order to search for minute sync pulse and data
                   2375:  * subcarrier from other transmitters.
                   2376:  *
                   2377:  * The search for WWV and WWVH operates simultaneously, with WWV minute
                   2378:  * sync pulse at 1000 Hz and WWVH at 1200 Hz. The probe frequency
                   2379:  * rotates each minute over 2.5, 5, 10, 15 and 20 MHz in order and yes,
                   2380:  * we all know WWVH is dark on 20 MHz, but few remember when WWV was lit
                   2381:  * on 25 MHz.
                   2382:  *
                   2383:  * This routine selects the best channel using a metric computed from
                   2384:  * the reachability register and minute pulse amplitude. Normally, the
                   2385:  * award goes to the the channel with the highest metric; but, in case
                   2386:  * of ties, the award goes to the channel with the highest minute sync
                   2387:  * pulse amplitude and then to the highest frequency.
                   2388:  *
                   2389:  * The routine performs an important squelch function to keep dirty data
                   2390:  * from polluting the integrators. In order to consider a station valid,
                   2391:  * the metric must be at least MTHR (13); otherwise, the station select
                   2392:  * bits are cleared so the second sync is disabled and the data bit
                   2393:  * integrators averaged to a miss. 
                   2394:  */
                   2395: static int
                   2396: wwv_newchan(
                   2397:        struct peer *peer       /* peer structure pointer */
                   2398:        )
                   2399: {
                   2400:        struct refclockproc *pp;
                   2401:        struct wwvunit *up;
                   2402:        struct sync *sp, *rp;
                   2403:        double rank, dtemp;
                   2404:        int i, j, rval;
                   2405: 
                   2406:        pp = peer->procptr;
                   2407:        up = (struct wwvunit *)pp->unitptr;
                   2408: 
                   2409:        /*
                   2410:         * Search all five station pairs looking for the channel with
                   2411:         * maximum metric.
                   2412:         */
                   2413:        sp = NULL;
                   2414:        j = 0;
                   2415:        rank = 0;
                   2416:        for (i = 0; i < NCHAN; i++) {
                   2417:                rp = &up->mitig[i].wwvh;
                   2418:                dtemp = rp->metric;
                   2419:                if (dtemp >= rank) {
                   2420:                        rank = dtemp;
                   2421:                        sp = rp;
                   2422:                        j = i;
                   2423:                }
                   2424:                rp = &up->mitig[i].wwv;
                   2425:                dtemp = rp->metric;
                   2426:                if (dtemp >= rank) {
                   2427:                        rank = dtemp;
                   2428:                        sp = rp;
                   2429:                        j = i;
                   2430:                }
                   2431:        }
                   2432: 
                   2433:        /*
                   2434:         * If the strongest signal is less than the MTHR threshold (13),
                   2435:         * we are beneath the waves, so squelch the second sync and
                   2436:         * advance to the next station. This makes sure all stations are
                   2437:         * scanned when the ions grow dim. If the strongest signal is
                   2438:         * greater than the threshold, tune to that frequency and
                   2439:         * transmitter QTH.
                   2440:         */
                   2441:        up->status &= ~(SELV | SELH);
                   2442:        if (rank < MTHR) {
                   2443:                up->dchan = (up->dchan + 1) % NCHAN;
                   2444:                if (up->status & METRIC) {
                   2445:                        up->status &= ~METRIC;
                   2446:                        refclock_report(peer, CEVNT_PROP);
                   2447:                }
                   2448:                rval = FALSE;
                   2449:        } else {
                   2450:                up->dchan = j;
                   2451:                up->sptr = sp;
                   2452:                memcpy(&pp->refid, sp->refid, 4);
                   2453:                peer->refid = pp->refid;
                   2454:                up->status |= METRIC;
                   2455:                if (sp->select & SELV) {
                   2456:                        up->status |= SELV;
                   2457:                        up->pdelay = pp->fudgetime1;
                   2458:                } else if (sp->select & SELH) {
                   2459:                        up->status |= SELH;
                   2460:                        up->pdelay = pp->fudgetime2;
                   2461:                } else {
                   2462:                        up->pdelay = 0;
                   2463:                }
                   2464:                rval = TRUE;
                   2465:        }
                   2466: #ifdef ICOM
                   2467:        if (up->fd_icom > 0)
                   2468:                wwv_qsy(peer, up->dchan);
                   2469: #endif /* ICOM */
                   2470:        return (rval);
                   2471: }
                   2472: 
                   2473: 
                   2474: /*
                   2475:  * wwv_newgame - reset and start over
                   2476:  *
                   2477:  * There are three conditions resulting in a new game:
                   2478:  *
                   2479:  * 1   After finding the minute pulse (MSYNC lit), going 15 minutes
                   2480:  *     (DATA) without finding the unit seconds digit.
                   2481:  *
                   2482:  * 2   After finding good data (DSYNC lit), going more than 40 minutes
                   2483:  *     (SYNCH) without finding station sync (INSYNC lit).
                   2484:  *
                   2485:  * 3   After finding station sync (INSYNC lit), going more than 2 days
                   2486:  *     (PANIC) without finding any station. 
                   2487:  */
                   2488: static void
                   2489: wwv_newgame(
                   2490:        struct peer *peer       /* peer structure pointer */
                   2491:        )
                   2492: {
                   2493:        struct refclockproc *pp;
                   2494:        struct wwvunit *up;
                   2495:        struct chan *cp;
                   2496:        int i;
                   2497: 
                   2498:        pp = peer->procptr;
                   2499:        up = (struct wwvunit *)pp->unitptr;
                   2500: 
                   2501:        /*
                   2502:         * Initialize strategic values. Note we set the leap bits
                   2503:         * NOTINSYNC and the refid "NONE".
                   2504:         */
                   2505:        if (up->status)
                   2506:                up->errflg = CEVNT_TIMEOUT;
                   2507:        peer->leap = LEAP_NOTINSYNC;
                   2508:        up->watch = up->status = up->alarm = 0;
                   2509:        up->avgint = MINAVG;
                   2510:        up->freq = 0;
                   2511:        up->gain = MAXGAIN / 2;
                   2512: 
                   2513:        /*
                   2514:         * Initialize the station processes for audio gain, select bit,
                   2515:         * station/frequency identifier and reference identifier. Start
                   2516:         * probing at the strongest channel or the default channel if
                   2517:         * nothing heard.
                   2518:         */
                   2519:        memset(up->mitig, 0, sizeof(up->mitig));
                   2520:        for (i = 0; i < NCHAN; i++) {
                   2521:                cp = &up->mitig[i];
                   2522:                cp->gain = up->gain;
                   2523:                cp->wwv.select = SELV;
                   2524:                sprintf(cp->wwv.refid, "WV%.0f", floor(qsy[i])); 
                   2525:                cp->wwvh.select = SELH;
                   2526:                sprintf(cp->wwvh.refid, "WH%.0f", floor(qsy[i])); 
                   2527:        }
                   2528:        up->dchan = (DCHAN + NCHAN - 1) % NCHAN;
                   2529:        wwv_newchan(peer);
                   2530:        up->schan = up->dchan;
                   2531: }
                   2532: 
                   2533: /*
                   2534:  * wwv_metric - compute station metric
                   2535:  *
                   2536:  * The most significant bits represent the number of ones in the
                   2537:  * station reachability register. The least significant bits represent
                   2538:  * the minute sync pulse amplitude. The combined value is scaled 0-100.
                   2539:  */
                   2540: double
                   2541: wwv_metric(
                   2542:        struct sync *sp         /* station pointer */
                   2543:        )
                   2544: {
                   2545:        double  dtemp;
                   2546: 
                   2547:        dtemp = sp->count * MAXAMP;
                   2548:        if (sp->synmax < MAXAMP)
                   2549:                dtemp += sp->synmax;
                   2550:        else
                   2551:                dtemp += MAXAMP - 1;
                   2552:        dtemp /= (AMAX + 1) * MAXAMP;
                   2553:        return (dtemp * 100.);
                   2554: }
                   2555: 
                   2556: 
                   2557: #ifdef ICOM
                   2558: /*
                   2559:  * wwv_qsy - Tune ICOM receiver
                   2560:  *
                   2561:  * This routine saves the AGC for the current channel, switches to a new
                   2562:  * channel and restores the AGC for that channel. If a tunable receiver
                   2563:  * is not available, just fake it.
                   2564:  */
                   2565: static int
                   2566: wwv_qsy(
                   2567:        struct peer *peer,      /* peer structure pointer */
                   2568:        int     chan            /* channel */
                   2569:        )
                   2570: {
                   2571:        int rval = 0;
                   2572:        struct refclockproc *pp;
                   2573:        struct wwvunit *up;
                   2574: 
                   2575:        pp = peer->procptr;
                   2576:        up = (struct wwvunit *)pp->unitptr;
                   2577:        if (up->fd_icom > 0) {
                   2578:                up->mitig[up->achan].gain = up->gain;
                   2579:                rval = icom_freq(up->fd_icom, peer->ttl & 0x7f,
                   2580:                    qsy[chan]);
                   2581:                up->achan = chan;
                   2582:                up->gain = up->mitig[up->achan].gain;
                   2583:        }
                   2584:        return (rval);
                   2585: }
                   2586: #endif /* ICOM */
                   2587: 
                   2588: 
                   2589: /*
                   2590:  * timecode - assemble timecode string and length
                   2591:  *
                   2592:  * Prettytime format - similar to Spectracom
                   2593:  *
                   2594:  * sq yy ddd hh:mm:ss ld dut lset agc iden sig errs freq avgt
                   2595:  *
                   2596:  * s   sync indicator ('?' or ' ')
                   2597:  * q   error bits (hex 0-F)
                   2598:  * yyyy        year of century
                   2599:  * ddd day of year
                   2600:  * hh  hour of day
                   2601:  * mm  minute of hour
                   2602:  * ss  second of minute)
                   2603:  * l   leap second warning (' ' or 'L')
                   2604:  * d   DST state ('S', 'D', 'I', or 'O')
                   2605:  * dut DUT sign and magnitude (0.1 s)
                   2606:  * lset        minutes since last clock update
                   2607:  * agc audio gain (0-255)
                   2608:  * iden        reference identifier (station and frequency)
                   2609:  * sig signal quality (0-100)
                   2610:  * errs        bit errors in last minute
                   2611:  * freq        frequency offset (PPM)
                   2612:  * avgt        averaging time (s)
                   2613:  */
                   2614: static int
                   2615: timecode(
                   2616:        struct wwvunit *up,     /* driver structure pointer */
                   2617:        char *ptr               /* target string */
                   2618:        )
                   2619: {
                   2620:        struct sync *sp;
                   2621:        int year, day, hour, minute, second, dut;
                   2622:        char synchar, leapchar, dst;
                   2623:        char cptr[50];
                   2624:        
                   2625: 
                   2626:        /*
                   2627:         * Common fixed-format fields
                   2628:         */
                   2629:        synchar = (up->status & INSYNC) ? ' ' : '?';
                   2630:        year = up->decvec[YR].digit + up->decvec[YR + 1].digit * 10 +
                   2631:            2000;
                   2632:        day = up->decvec[DA].digit + up->decvec[DA + 1].digit * 10 +
                   2633:            up->decvec[DA + 2].digit * 100;
                   2634:        hour = up->decvec[HR].digit + up->decvec[HR + 1].digit * 10;
                   2635:        minute = up->decvec[MN].digit + up->decvec[MN + 1].digit * 10;
                   2636:        second = 0;
                   2637:        leapchar = (up->misc & SECWAR) ? 'L' : ' ';
                   2638:        dst = dstcod[(up->misc >> 4) & 0x3];
                   2639:        dut = up->misc & 0x7;
                   2640:        if (!(up->misc & DUTS))
                   2641:                dut = -dut;
                   2642:        sprintf(ptr, "%c%1X", synchar, up->alarm);
                   2643:        sprintf(cptr, " %4d %03d %02d:%02d:%02d %c%c %+d",
                   2644:            year, day, hour, minute, second, leapchar, dst, dut);
                   2645:        strcat(ptr, cptr);
                   2646: 
                   2647:        /*
                   2648:         * Specific variable-format fields
                   2649:         */
                   2650:        sp = up->sptr;
                   2651:        sprintf(cptr, " %d %d %s %.0f %d %.1f %d", up->watch,
                   2652:            up->mitig[up->dchan].gain, sp->refid, sp->metric,
                   2653:            up->errcnt, up->freq / SECOND * 1e6, up->avgint);
                   2654:        strcat(ptr, cptr);
                   2655:        return (strlen(ptr));
                   2656: }
                   2657: 
                   2658: 
                   2659: /*
                   2660:  * wwv_gain - adjust codec gain
                   2661:  *
                   2662:  * This routine is called at the end of each second. During the second
                   2663:  * the number of signal clips above the MAXAMP threshold (6000). If
                   2664:  * there are no clips, the gain is bumped up; if there are more than
                   2665:  * MAXCLP clips (100), it is bumped down. The decoder is relatively
                   2666:  * insensitive to amplitude, so this crudity works just peachy. The
                   2667:  * routine also jiggles the input port and selectively mutes the
                   2668:  * monitor.
                   2669:  */
                   2670: static void
                   2671: wwv_gain(
                   2672:        struct peer *peer       /* peer structure pointer */
                   2673:        )
                   2674: {
                   2675:        struct refclockproc *pp;
                   2676:        struct wwvunit *up;
                   2677: 
                   2678:        pp = peer->procptr;
                   2679:        up = (struct wwvunit *)pp->unitptr;
                   2680: 
                   2681:        /*
                   2682:         * Apparently, the codec uses only the high order bits of the
                   2683:         * gain control field. Thus, it may take awhile for changes to
                   2684:         * wiggle the hardware bits.
                   2685:         */
                   2686:        if (up->clipcnt == 0) {
                   2687:                up->gain += 4;
                   2688:                if (up->gain > MAXGAIN)
                   2689:                        up->gain = MAXGAIN;
                   2690:        } else if (up->clipcnt > MAXCLP) {
                   2691:                up->gain -= 4;
                   2692:                if (up->gain < 0)
                   2693:                        up->gain = 0;
                   2694:        }
                   2695:        audio_gain(up->gain, up->mongain, up->port);
                   2696:        up->clipcnt = 0;
                   2697: #if DEBUG
                   2698:        if (debug > 1)
                   2699:                audio_show();
                   2700: #endif
                   2701: }
                   2702: 
                   2703: 
                   2704: #else
                   2705: int refclock_wwv_bs;
                   2706: #endif /* REFCLOCK */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>