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