154359Sroberto/* 254359Sroberto * refclock_irig - audio IRIG-B/E demodulator/decoder 354359Sroberto */ 454359Sroberto#ifdef HAVE_CONFIG_H 554359Sroberto#include <config.h> 654359Sroberto#endif 754359Sroberto 854359Sroberto#if defined(REFCLOCK) && defined(CLOCK_IRIG) 954359Sroberto 1082498Sroberto#include "ntpd.h" 1182498Sroberto#include "ntp_io.h" 1282498Sroberto#include "ntp_refclock.h" 1382498Sroberto#include "ntp_calendar.h" 1482498Sroberto#include "ntp_stdlib.h" 1582498Sroberto 1654359Sroberto#include <stdio.h> 1754359Sroberto#include <ctype.h> 1854359Sroberto#include <math.h> 1954359Sroberto#ifdef HAVE_SYS_IOCTL_H 2054359Sroberto#include <sys/ioctl.h> 2154359Sroberto#endif /* HAVE_SYS_IOCTL_H */ 2254359Sroberto 2356746Sroberto#include "audio.h" 2454359Sroberto 2554359Sroberto/* 2654359Sroberto * Audio IRIG-B/E demodulator/decoder 2754359Sroberto * 28290000Sglebius * This driver synchronizes the computer time using data encoded in 29290000Sglebius * IRIG-B/E signals commonly produced by GPS receivers and other timing 30290000Sglebius * devices. The IRIG signal is an amplitude-modulated carrier with 31290000Sglebius * pulse-width modulated data bits. For IRIG-B, the carrier frequency is 32290000Sglebius * 1000 Hz and bit rate 100 b/s; for IRIG-E, the carrier frequenchy is 33290000Sglebius * 100 Hz and bit rate 10 b/s. The driver automatically recognizes which 34290000Sglebius & format is in use. 3554359Sroberto * 36290000Sglebius * The driver requires an audio codec or sound card with sampling rate 8 37290000Sglebius * kHz and mu-law companding. This is the same standard as used by the 38290000Sglebius * telephone industry and is supported by most hardware and operating 39290000Sglebius * systems, including Solaris, SunOS, FreeBSD, NetBSD and Linux. In this 40290000Sglebius * implementation, only one audio driver and codec can be supported on a 41290000Sglebius * single machine. 42290000Sglebius * 4354359Sroberto * The program processes 8000-Hz mu-law companded samples using separate 4454359Sroberto * signal filters for IRIG-B and IRIG-E, a comb filter, envelope 4554359Sroberto * detector and automatic threshold corrector. Cycle crossings relative 4654359Sroberto * to the corrected slice level determine the width of each pulse and 47290000Sglebius * its value - zero, one or position identifier. 4854359Sroberto * 49290000Sglebius * The data encode 20 BCD digits which determine the second, minute, 50290000Sglebius * hour and day of the year and sometimes the year and synchronization 51290000Sglebius * condition. The comb filter exponentially averages the corresponding 52290000Sglebius * samples of successive baud intervals in order to reliably identify 53290000Sglebius * the reference carrier cycle. A type-II phase-lock loop (PLL) performs 54290000Sglebius * additional integration and interpolation to accurately determine the 55290000Sglebius * zero crossing of that cycle, which determines the reference 56290000Sglebius * timestamp. A pulse-width discriminator demodulates the data pulses, 57290000Sglebius * which are then encoded as the BCD digits of the timecode. 58290000Sglebius * 5954359Sroberto * The timecode and reference timestamp are updated once each second 6054359Sroberto * with IRIG-B (ten seconds with IRIG-E) and local clock offset samples 6154359Sroberto * saved for later processing. At poll intervals of 64 s, the saved 6254359Sroberto * samples are processed by a trimmed-mean filter and used to update the 6354359Sroberto * system clock. 6454359Sroberto * 6554359Sroberto * An automatic gain control feature provides protection against 6654359Sroberto * overdriven or underdriven input signal amplitudes. It is designed to 6754359Sroberto * maintain adequate demodulator signal amplitude while avoiding 6854359Sroberto * occasional noise spikes. In order to assure reliable capture, the 6954359Sroberto * decompanded input signal amplitude must be greater than 100 units and 7054359Sroberto * the codec sample frequency error less than 250 PPM (.025 percent). 7154359Sroberto * 72290000Sglebius * Monitor Data 7354359Sroberto * 74290000Sglebius * The timecode format used for debugging and data recording includes 75290000Sglebius * data helpful in diagnosing problems with the IRIG signal and codec 76290000Sglebius * connections. The driver produces one line for each timecode in the 77290000Sglebius * following format: 7854359Sroberto * 79290000Sglebius * 00 00 98 23 19:26:52 2782 143 0.694 10 0.3 66.5 3094572411.00027 8054359Sroberto * 81290000Sglebius * If clockstats is enabled, the most recent line is written to the 82290000Sglebius * clockstats file every 64 s. If verbose recording is enabled (fudge 83290000Sglebius * flag 4) each line is written as generated. 8454359Sroberto * 85290000Sglebius * The first field containes the error flags in hex, where the hex bits 86290000Sglebius * are interpreted as below. This is followed by the year of century, 87290000Sglebius * day of year and time of day. Note that the time of day is for the 88290000Sglebius * previous minute, not the current time. The status indicator and year 89290000Sglebius * are not produced by some IRIG devices and appear as zeros. Following 90290000Sglebius * these fields are the carrier amplitude (0-3000), codec gain (0-255), 91290000Sglebius * modulation index (0-1), time constant (4-10), carrier phase error 92290000Sglebius * +-.5) and carrier frequency error (PPM). The last field is the on- 93290000Sglebius * time timestamp in NTP format. 9454359Sroberto * 95290000Sglebius * The error flags are defined as follows in hex: 9654359Sroberto * 97290000Sglebius * x01 Low signal. The carrier amplitude is less than 100 units. This 98290000Sglebius * is usually the result of no signal or wrong input port. 99290000Sglebius * x02 Frequency error. The codec frequency error is greater than 250 100290000Sglebius * PPM. This may be due to wrong signal format or (rarely) 101290000Sglebius * defective codec. 102290000Sglebius * x04 Modulation error. The IRIG modulation index is less than 0.5. 103290000Sglebius * This is usually the result of an overdriven codec, wrong signal 104290000Sglebius * format or wrong input port. 105290000Sglebius * x08 Frame synch error. The decoder frame does not match the IRIG 106290000Sglebius * frame. This is usually the result of an overdriven codec, wrong 107290000Sglebius * signal format or noisy IRIG signal. It may also be the result of 108290000Sglebius * an IRIG signature check which indicates a failure of the IRIG 109290000Sglebius * signal synchronization source. 110290000Sglebius * x10 Data bit error. The data bit length is out of tolerance. This is 111290000Sglebius * usually the result of an overdriven codec, wrong signal format 112290000Sglebius * or noisy IRIG signal. 113290000Sglebius * x20 Seconds numbering discrepancy. The decoder second does not match 114290000Sglebius * the IRIG second. This is usually the result of an overdriven 115290000Sglebius * codec, wrong signal format or noisy IRIG signal. 116290000Sglebius * x40 Codec error (overrun). The machine is not fast enough to keep up 117290000Sglebius * with the codec. 118290000Sglebius * x80 Device status error (Spectracom). 11954359Sroberto * 12054359Sroberto * 121290000Sglebius * Once upon a time, an UltrSPARC 30 and Solaris 2.7 kept the clock 122290000Sglebius * within a few tens of microseconds relative to the IRIG-B signal. 123290000Sglebius * Accuracy with IRIG-E was about ten times worse. Unfortunately, Sun 124290000Sglebius * broke the 2.7 audio driver in 2.8, which has a 10-ms sawtooth 125290000Sglebius * modulation. 12654359Sroberto * 12754359Sroberto * Unlike other drivers, which can have multiple instantiations, this 12854359Sroberto * one supports only one. It does not seem likely that more than one 12954359Sroberto * audio codec would be useful in a single machine. More than one would 13054359Sroberto * probably chew up too much CPU time anyway. 13154359Sroberto * 13254359Sroberto * Fudge factors 13354359Sroberto * 134132451Sroberto * Fudge flag4 causes the dubugging output described above to be 135182007Sroberto * recorded in the clockstats file. Fudge flag2 selects the audio input 136182007Sroberto * port, where 0 is the mike port (default) and 1 is the line-in port. 137182007Sroberto * It does not seem useful to select the compact disc player port. Fudge 138182007Sroberto * flag3 enables audio monitoring of the input signal. For this purpose, 139290000Sglebius * the monitor gain is set t a default value. Fudgetime2 is used as a 140182007Sroberto * frequency vernier for broken codec sample frequency. 141290000Sglebius * 142290000Sglebius * Alarm codes 143290000Sglebius * 144290000Sglebius * CEVNT_BADTIME invalid date or time 145290000Sglebius * CEVNT_TIMEOUT no IRIG data since last poll 14654359Sroberto */ 14754359Sroberto/* 14854359Sroberto * Interface definitions 14954359Sroberto */ 15082498Sroberto#define DEVICE_AUDIO "/dev/audio" /* audio device name */ 15154359Sroberto#define PRECISION (-17) /* precision assumed (about 10 us) */ 15254359Sroberto#define REFID "IRIG" /* reference ID */ 15354359Sroberto#define DESCRIPTION "Generic IRIG Audio Driver" /* WRU */ 154132451Sroberto#define AUDIO_BUFSIZ 320 /* audio buffer size (40 ms) */ 15556746Sroberto#define SECOND 8000 /* nominal sample rate (Hz) */ 15654359Sroberto#define BAUD 80 /* samples per baud interval */ 15754359Sroberto#define OFFSET 128 /* companded sample offset */ 15854359Sroberto#define SIZE 256 /* decompanding table size */ 159290000Sglebius#define CYCLE 8 /* samples per bit */ 160290000Sglebius#define SUBFLD 10 /* bits per frame */ 161290000Sglebius#define FIELD 100 /* bits per second */ 16254359Sroberto#define MINTC 2 /* min PLL time constant */ 163290000Sglebius#define MAXTC 10 /* max PLL time constant max */ 164290000Sglebius#define MAXAMP 3000. /* maximum signal amplitude */ 165290000Sglebius#define MINAMP 2000. /* minimum signal amplitude */ 166290000Sglebius#define DRPOUT 100. /* dropout signal amplitude */ 16754359Sroberto#define MODMIN 0.5 /* minimum modulation index */ 16856746Sroberto#define MAXFREQ (250e-6 * SECOND) /* freq tolerance (.025%) */ 16954359Sroberto 17054359Sroberto/* 171290000Sglebius * The on-time synchronization point is the positive-going zero crossing 172290000Sglebius * of the first cycle of the second. The IIR baseband filter phase delay 173290000Sglebius * is 1.03 ms for IRIG-B and 3.47 ms for IRIG-E. The fudge value 2.68 ms 174290000Sglebius * due to the codec and other causes was determined by calibrating to a 175290000Sglebius * PPS signal from a GPS receiver. 176290000Sglebius * 177290000Sglebius * The results with a 2.4-GHz P4 running FreeBSD 6.1 are generally 178290000Sglebius * within .02 ms short-term with .02 ms jitter. The processor load due 179290000Sglebius * to the driver is 0.51 percent. 18054359Sroberto */ 181290000Sglebius#define IRIG_B ((1.03 + 2.68) / 1000) /* IRIG-B system delay (s) */ 182290000Sglebius#define IRIG_E ((3.47 + 2.68) / 1000) /* IRIG-E system delay (s) */ 18354359Sroberto 18454359Sroberto/* 18554359Sroberto * Data bit definitions 18654359Sroberto */ 18754359Sroberto#define BIT0 0 /* zero */ 18854359Sroberto#define BIT1 1 /* one */ 18954359Sroberto#define BITP 2 /* position identifier */ 19054359Sroberto 19154359Sroberto/* 192290000Sglebius * Error flags 19354359Sroberto */ 19454359Sroberto#define IRIG_ERR_AMP 0x01 /* low carrier amplitude */ 19554359Sroberto#define IRIG_ERR_FREQ 0x02 /* frequency tolerance exceeded */ 19654359Sroberto#define IRIG_ERR_MOD 0x04 /* low modulation index */ 19754359Sroberto#define IRIG_ERR_SYNCH 0x08 /* frame synch error */ 19854359Sroberto#define IRIG_ERR_DECODE 0x10 /* frame decoding error */ 19954359Sroberto#define IRIG_ERR_CHECK 0x20 /* second numbering discrepancy */ 20054359Sroberto#define IRIG_ERR_ERROR 0x40 /* codec error (overrun) */ 201132451Sroberto#define IRIG_ERR_SIGERR 0x80 /* IRIG status error (Spectracom) */ 20254359Sroberto 203290000Sglebiusstatic char hexchar[] = "0123456789abcdef"; 204290000Sglebius 20554359Sroberto/* 20654359Sroberto * IRIG unit control structure 20754359Sroberto */ 20854359Srobertostruct irigunit { 209290000Sglebius u_char timecode[2 * SUBFLD + 1]; /* timecode string */ 21054359Sroberto l_fp timestamp; /* audio sample timestamp */ 21154359Sroberto l_fp tick; /* audio sample increment */ 212290000Sglebius l_fp refstamp; /* reference timestamp */ 213290000Sglebius l_fp chrstamp; /* baud timestamp */ 214290000Sglebius l_fp prvstamp; /* previous baud timestamp */ 21554359Sroberto double integ[BAUD]; /* baud integrator */ 21654359Sroberto double phase, freq; /* logical clock phase and frequency */ 21754359Sroberto double zxing; /* phase detector integrator */ 218132451Sroberto double yxing; /* cycle phase */ 219132451Sroberto double exing; /* envelope phase */ 22054359Sroberto double modndx; /* modulation index */ 22154359Sroberto double irig_b; /* IRIG-B signal amplitude */ 22254359Sroberto double irig_e; /* IRIG-E signal amplitude */ 22354359Sroberto int errflg; /* error flags */ 224132451Sroberto /* 225132451Sroberto * Audio codec variables 226132451Sroberto */ 227132451Sroberto double comp[SIZE]; /* decompanding table */ 228290000Sglebius double signal; /* peak signal for AGC */ 22954359Sroberto int port; /* codec port */ 23054359Sroberto int gain; /* codec gain */ 231132451Sroberto int mongain; /* codec monitor gain */ 23254359Sroberto int seccnt; /* second interval counter */ 23354359Sroberto 23454359Sroberto /* 23554359Sroberto * RF variables 23654359Sroberto */ 237290000Sglebius double bpf[9]; /* IRIG-B filter shift register */ 23854359Sroberto double lpf[5]; /* IRIG-E filter shift register */ 239290000Sglebius double envmin, envmax; /* envelope min and max */ 240290000Sglebius double slice; /* envelope slice level */ 24154359Sroberto double intmin, intmax; /* integrated envelope min and max */ 24254359Sroberto double maxsignal; /* integrated peak amplitude */ 24354359Sroberto double noise; /* integrated noise amplitude */ 24454359Sroberto double lastenv[CYCLE]; /* last cycle amplitudes */ 24554359Sroberto double lastint[CYCLE]; /* last integrated cycle amplitudes */ 24654359Sroberto double lastsig; /* last carrier sample */ 24754359Sroberto double fdelay; /* filter delay */ 248132451Sroberto int decim; /* sample decimation factor */ 24954359Sroberto int envphase; /* envelope phase */ 25054359Sroberto int envptr; /* envelope phase pointer */ 25154359Sroberto int envsw; /* envelope state */ 25254359Sroberto int envxing; /* envelope slice crossing */ 25354359Sroberto int tc; /* time constant */ 25454359Sroberto int tcount; /* time constant counter */ 25554359Sroberto int badcnt; /* decimation interval counter */ 25654359Sroberto 25754359Sroberto /* 25854359Sroberto * Decoder variables 25954359Sroberto */ 26054359Sroberto int pulse; /* cycle counter */ 26154359Sroberto int cycles; /* carrier cycles */ 26254359Sroberto int dcycles; /* data cycles */ 263290000Sglebius int lastbit; /* last code element */ 26454359Sroberto int second; /* previous second */ 265290000Sglebius int bitcnt; /* bit count in frame */ 266290000Sglebius int frmcnt; /* bit count in second */ 267290000Sglebius int xptr; /* timecode pointer */ 26854359Sroberto int bits; /* demodulated bits */ 26954359Sroberto}; 27054359Sroberto 27154359Sroberto/* 27254359Sroberto * Function prototypes 27354359Sroberto */ 274290000Sglebiusstatic int irig_start (int, struct peer *); 275290000Sglebiusstatic void irig_shutdown (int, struct peer *); 276290000Sglebiusstatic void irig_receive (struct recvbuf *); 277290000Sglebiusstatic void irig_poll (int, struct peer *); 27854359Sroberto 27954359Sroberto/* 28054359Sroberto * More function prototypes 28154359Sroberto */ 282290000Sglebiusstatic void irig_base (struct peer *, double); 283290000Sglebiusstatic void irig_rf (struct peer *, double); 284290000Sglebiusstatic void irig_baud (struct peer *, int); 285290000Sglebiusstatic void irig_decode (struct peer *, int); 286290000Sglebiusstatic void irig_gain (struct peer *); 28754359Sroberto 28854359Sroberto/* 28954359Sroberto * Transfer vector 29054359Sroberto */ 29154359Srobertostruct refclock refclock_irig = { 29254359Sroberto irig_start, /* start up driver */ 29354359Sroberto irig_shutdown, /* shut down driver */ 29454359Sroberto irig_poll, /* transmit poll message */ 29554359Sroberto noentry, /* not used (old irig_control) */ 29654359Sroberto noentry, /* initialize driver (not used) */ 29754359Sroberto noentry, /* not used (old irig_buginfo) */ 29854359Sroberto NOFLAGS /* not used */ 29954359Sroberto}; 30054359Sroberto 30154359Sroberto 30254359Sroberto/* 30354359Sroberto * irig_start - open the devices and initialize data for processing 30454359Sroberto */ 30554359Srobertostatic int 30654359Srobertoirig_start( 307132451Sroberto int unit, /* instance number (used for PCM) */ 30854359Sroberto struct peer *peer /* peer structure pointer */ 30954359Sroberto ) 31054359Sroberto{ 31154359Sroberto struct refclockproc *pp; 31254359Sroberto struct irigunit *up; 31354359Sroberto 31454359Sroberto /* 31554359Sroberto * Local variables 31654359Sroberto */ 31754359Sroberto int fd; /* file descriptor */ 31854359Sroberto int i; /* index */ 31954359Sroberto double step; /* codec adjustment */ 32054359Sroberto 32154359Sroberto /* 32254359Sroberto * Open audio device 32354359Sroberto */ 324132451Sroberto fd = audio_init(DEVICE_AUDIO, AUDIO_BUFSIZ, unit); 32556746Sroberto if (fd < 0) 32654359Sroberto return (0); 32756746Sroberto#ifdef DEBUG 32856746Sroberto if (debug) 32956746Sroberto audio_show(); 33056746Sroberto#endif 33154359Sroberto 33254359Sroberto /* 33354359Sroberto * Allocate and initialize unit structure 33454359Sroberto */ 335290000Sglebius up = emalloc_zero(sizeof(*up)); 33654359Sroberto pp = peer->procptr; 33754359Sroberto pp->io.clock_recv = irig_receive; 338290000Sglebius pp->io.srcclock = peer; 33954359Sroberto pp->io.datalen = 0; 34054359Sroberto pp->io.fd = fd; 34154359Sroberto if (!io_addclock(&pp->io)) { 342290000Sglebius close(fd); 343290000Sglebius pp->io.fd = -1; 34454359Sroberto free(up); 34554359Sroberto return (0); 34654359Sroberto } 347290000Sglebius pp->unitptr = up; 34854359Sroberto 34954359Sroberto /* 35054359Sroberto * Initialize miscellaneous variables 35154359Sroberto */ 35254359Sroberto peer->precision = PRECISION; 35354359Sroberto pp->clockdesc = DESCRIPTION; 35454359Sroberto memcpy((char *)&pp->refid, REFID, 4); 35554359Sroberto up->tc = MINTC; 35654359Sroberto up->decim = 1; 35756746Sroberto up->gain = 127; 35854359Sroberto 35954359Sroberto /* 36054359Sroberto * The companded samples are encoded sign-magnitude. The table 36154359Sroberto * contains all the 256 values in the interest of speed. 36254359Sroberto */ 36354359Sroberto up->comp[0] = up->comp[OFFSET] = 0.; 36454359Sroberto up->comp[1] = 1; up->comp[OFFSET + 1] = -1.; 36554359Sroberto up->comp[2] = 3; up->comp[OFFSET + 2] = -3.; 36654359Sroberto step = 2.; 36754359Sroberto for (i = 3; i < OFFSET; i++) { 36854359Sroberto up->comp[i] = up->comp[i - 1] + step; 36954359Sroberto up->comp[OFFSET + i] = -up->comp[i]; 370290000Sglebius if (i % 16 == 0) 371132451Sroberto step *= 2.; 37254359Sroberto } 37356746Sroberto DTOLFP(1. / SECOND, &up->tick); 37454359Sroberto return (1); 37554359Sroberto} 37654359Sroberto 37754359Sroberto 37854359Sroberto/* 37954359Sroberto * irig_shutdown - shut down the clock 38054359Sroberto */ 38154359Srobertostatic void 38254359Srobertoirig_shutdown( 38354359Sroberto int unit, /* instance number (not used) */ 38454359Sroberto struct peer *peer /* peer structure pointer */ 38554359Sroberto ) 38654359Sroberto{ 38754359Sroberto struct refclockproc *pp; 38854359Sroberto struct irigunit *up; 38954359Sroberto 39054359Sroberto pp = peer->procptr; 391290000Sglebius up = pp->unitptr; 392290000Sglebius if (-1 != pp->io.fd) 393290000Sglebius io_closeclock(&pp->io); 394290000Sglebius if (NULL != up) 395290000Sglebius free(up); 39654359Sroberto} 39754359Sroberto 39854359Sroberto 39954359Sroberto/* 40054359Sroberto * irig_receive - receive data from the audio device 40154359Sroberto * 40254359Sroberto * This routine reads input samples and adjusts the logical clock to 40354359Sroberto * track the irig clock by dropping or duplicating codec samples. 40454359Sroberto */ 40554359Srobertostatic void 40654359Srobertoirig_receive( 40754359Sroberto struct recvbuf *rbufp /* receive buffer structure pointer */ 40854359Sroberto ) 40954359Sroberto{ 41054359Sroberto struct peer *peer; 41154359Sroberto struct refclockproc *pp; 41254359Sroberto struct irigunit *up; 41354359Sroberto 41454359Sroberto /* 41554359Sroberto * Local variables 41654359Sroberto */ 41754359Sroberto double sample; /* codec sample */ 41854359Sroberto u_char *dpt; /* buffer pointer */ 419132451Sroberto int bufcnt; /* buffer counter */ 42054359Sroberto l_fp ltemp; /* l_fp temp */ 42154359Sroberto 422290000Sglebius peer = rbufp->recv_peer; 42354359Sroberto pp = peer->procptr; 424290000Sglebius up = pp->unitptr; 42554359Sroberto 42654359Sroberto /* 42754359Sroberto * Main loop - read until there ain't no more. Note codec 42854359Sroberto * samples are bit-inverted. 42954359Sroberto */ 430132451Sroberto DTOLFP((double)rbufp->recv_length / SECOND, <emp); 431132451Sroberto L_SUB(&rbufp->recv_time, <emp); 43254359Sroberto up->timestamp = rbufp->recv_time; 43354359Sroberto dpt = rbufp->recv_buffer; 434132451Sroberto for (bufcnt = 0; bufcnt < rbufp->recv_length; bufcnt++) { 43554359Sroberto sample = up->comp[~*dpt++ & 0xff]; 43654359Sroberto 43754359Sroberto /* 438132451Sroberto * Variable frequency oscillator. The codec oscillator 439132451Sroberto * runs at the nominal rate of 8000 samples per second, 440132451Sroberto * or 125 us per sample. A frequency change of one unit 441132451Sroberto * results in either duplicating or deleting one sample 442132451Sroberto * per second, which results in a frequency change of 443132451Sroberto * 125 PPM. 44454359Sroberto */ 445290000Sglebius up->phase += (up->freq + clock_codec) / SECOND; 446132451Sroberto up->phase += pp->fudgetime2 / 1e6; 44754359Sroberto if (up->phase >= .5) { 44854359Sroberto up->phase -= 1.; 44954359Sroberto } else if (up->phase < -.5) { 45054359Sroberto up->phase += 1.; 45154359Sroberto irig_rf(peer, sample); 45254359Sroberto irig_rf(peer, sample); 45354359Sroberto } else { 45454359Sroberto irig_rf(peer, sample); 45554359Sroberto } 45654359Sroberto L_ADD(&up->timestamp, &up->tick); 457290000Sglebius sample = fabs(sample); 458290000Sglebius if (sample > up->signal) 459290000Sglebius up->signal = sample; 460290000Sglebius up->signal += (sample - up->signal) / 461290000Sglebius 1000; 46254359Sroberto 46354359Sroberto /* 464132451Sroberto * Once each second, determine the IRIG format and gain. 46554359Sroberto */ 46656746Sroberto up->seccnt = (up->seccnt + 1) % SECOND; 46754359Sroberto if (up->seccnt == 0) { 46854359Sroberto if (up->irig_b > up->irig_e) { 46954359Sroberto up->decim = 1; 47054359Sroberto up->fdelay = IRIG_B; 47154359Sroberto } else { 47254359Sroberto up->decim = 10; 47354359Sroberto up->fdelay = IRIG_E; 47454359Sroberto } 475290000Sglebius up->irig_b = up->irig_e = 0; 47654359Sroberto irig_gain(peer); 477290000Sglebius 47854359Sroberto } 47954359Sroberto } 48054359Sroberto 48154359Sroberto /* 482132451Sroberto * Set the input port and monitor gain for the next buffer. 48354359Sroberto */ 484132451Sroberto if (pp->sloppyclockflag & CLK_FLAG2) 485132451Sroberto up->port = 2; 486132451Sroberto else 487132451Sroberto up->port = 1; 48854359Sroberto if (pp->sloppyclockflag & CLK_FLAG3) 489132451Sroberto up->mongain = MONGAIN; 490132451Sroberto else 491132451Sroberto up->mongain = 0; 49254359Sroberto} 49354359Sroberto 494290000Sglebius 49554359Sroberto/* 49654359Sroberto * irig_rf - RF processing 49754359Sroberto * 498290000Sglebius * This routine filters the RF signal using a bandass filter for IRIG-B 49954359Sroberto * and a lowpass filter for IRIG-E. In case of IRIG-E, the samples are 500290000Sglebius * decimated by a factor of ten. Note that the codec filters function as 501290000Sglebius * roofing filters to attenuate both the high and low ends of the 50254359Sroberto * passband. IIR filter coefficients were determined using Matlab Signal 50354359Sroberto * Processing Toolkit. 50454359Sroberto */ 50554359Srobertostatic void 50654359Srobertoirig_rf( 50754359Sroberto struct peer *peer, /* peer structure pointer */ 50854359Sroberto double sample /* current signal sample */ 50954359Sroberto ) 51054359Sroberto{ 51154359Sroberto struct refclockproc *pp; 51254359Sroberto struct irigunit *up; 51354359Sroberto 51454359Sroberto /* 51554359Sroberto * Local variables 51654359Sroberto */ 51754359Sroberto double irig_b, irig_e; /* irig filter outputs */ 51854359Sroberto 51954359Sroberto pp = peer->procptr; 520290000Sglebius up = pp->unitptr; 52154359Sroberto 52254359Sroberto /* 523290000Sglebius * IRIG-B filter. Matlab 4th-order IIR elliptic, 800-1200 Hz 524290000Sglebius * bandpass, 0.3 dB passband ripple, -50 dB stopband ripple, 525290000Sglebius * phase delay 1.03 ms. 52654359Sroberto */ 527290000Sglebius irig_b = (up->bpf[8] = up->bpf[7]) * 6.505491e-001; 528290000Sglebius irig_b += (up->bpf[7] = up->bpf[6]) * -3.875180e+000; 529290000Sglebius irig_b += (up->bpf[6] = up->bpf[5]) * 1.151180e+001; 530290000Sglebius irig_b += (up->bpf[5] = up->bpf[4]) * -2.141264e+001; 531290000Sglebius irig_b += (up->bpf[4] = up->bpf[3]) * 2.712837e+001; 532290000Sglebius irig_b += (up->bpf[3] = up->bpf[2]) * -2.384486e+001; 533290000Sglebius irig_b += (up->bpf[2] = up->bpf[1]) * 1.427663e+001; 534290000Sglebius irig_b += (up->bpf[1] = up->bpf[0]) * -5.352734e+000; 535290000Sglebius up->bpf[0] = sample - irig_b; 536290000Sglebius irig_b = up->bpf[0] * 4.952157e-003 537290000Sglebius + up->bpf[1] * -2.055878e-002 538290000Sglebius + up->bpf[2] * 4.401413e-002 539290000Sglebius + up->bpf[3] * -6.558851e-002 540290000Sglebius + up->bpf[4] * 7.462108e-002 541290000Sglebius + up->bpf[5] * -6.558851e-002 542290000Sglebius + up->bpf[6] * 4.401413e-002 543290000Sglebius + up->bpf[7] * -2.055878e-002 544290000Sglebius + up->bpf[8] * 4.952157e-003; 54554359Sroberto up->irig_b += irig_b * irig_b; 54654359Sroberto 54754359Sroberto /* 548290000Sglebius * IRIG-E filter. Matlab 4th-order IIR elliptic, 130-Hz lowpass, 549290000Sglebius * 0.3 dB passband ripple, -50 dB stopband ripple, phase delay 550290000Sglebius * 3.47 ms. 55154359Sroberto */ 552290000Sglebius irig_e = (up->lpf[4] = up->lpf[3]) * 8.694604e-001; 553290000Sglebius irig_e += (up->lpf[3] = up->lpf[2]) * -3.589893e+000; 554290000Sglebius irig_e += (up->lpf[2] = up->lpf[1]) * 5.570154e+000; 555290000Sglebius irig_e += (up->lpf[1] = up->lpf[0]) * -3.849667e+000; 55654359Sroberto up->lpf[0] = sample - irig_e; 557290000Sglebius irig_e = up->lpf[0] * 3.215696e-003 558290000Sglebius + up->lpf[1] * -1.174951e-002 559290000Sglebius + up->lpf[2] * 1.712074e-002 560290000Sglebius + up->lpf[3] * -1.174951e-002 561290000Sglebius + up->lpf[4] * 3.215696e-003; 56254359Sroberto up->irig_e += irig_e * irig_e; 56354359Sroberto 56454359Sroberto /* 56554359Sroberto * Decimate by a factor of either 1 (IRIG-B) or 10 (IRIG-E). 56654359Sroberto */ 56754359Sroberto up->badcnt = (up->badcnt + 1) % up->decim; 56854359Sroberto if (up->badcnt == 0) { 56954359Sroberto if (up->decim == 1) 570132451Sroberto irig_base(peer, irig_b); 57154359Sroberto else 572132451Sroberto irig_base(peer, irig_e); 57354359Sroberto } 57454359Sroberto} 57554359Sroberto 57654359Sroberto/* 57754359Sroberto * irig_base - baseband processing 57854359Sroberto * 57954359Sroberto * This routine processes the baseband signal and demodulates the AM 58054359Sroberto * carrier using a synchronous detector. It then synchronizes to the 581290000Sglebius * data frame at the baud rate and decodes the width-modulated data 582290000Sglebius * pulses. 58354359Sroberto */ 58454359Srobertostatic void 58554359Srobertoirig_base( 58654359Sroberto struct peer *peer, /* peer structure pointer */ 58754359Sroberto double sample /* current signal sample */ 58854359Sroberto ) 58954359Sroberto{ 59054359Sroberto struct refclockproc *pp; 59154359Sroberto struct irigunit *up; 59254359Sroberto 59354359Sroberto /* 59454359Sroberto * Local variables 59554359Sroberto */ 59654359Sroberto double lope; /* integrator output */ 59754359Sroberto double env; /* envelope detector output */ 598290000Sglebius double dtemp; 599290000Sglebius int carphase; /* carrier phase */ 60054359Sroberto 60154359Sroberto pp = peer->procptr; 602290000Sglebius up = pp->unitptr; 60354359Sroberto 60454359Sroberto /* 60554359Sroberto * Synchronous baud integrator. Corresponding samples of current 60654359Sroberto * and past baud intervals are integrated to refine the envelope 607290000Sglebius * amplitude and phase estimate. We keep one cycle (1 ms) of the 608290000Sglebius * raw data and one baud (10 ms) of the integrated data. 60954359Sroberto */ 61054359Sroberto up->envphase = (up->envphase + 1) % BAUD; 61154359Sroberto up->integ[up->envphase] += (sample - up->integ[up->envphase]) / 61254359Sroberto (5 * up->tc); 61354359Sroberto lope = up->integ[up->envphase]; 614290000Sglebius carphase = up->envphase % CYCLE; 615290000Sglebius up->lastenv[carphase] = sample; 616290000Sglebius up->lastint[carphase] = lope; 61754359Sroberto 61854359Sroberto /* 619290000Sglebius * Phase detector. Find the negative-going zero crossing 620290000Sglebius * relative to sample 4 in the 8-sample sycle. A phase change of 621290000Sglebius * 360 degrees produces an output change of one unit. 62254359Sroberto */ 623290000Sglebius if (up->lastsig > 0 && lope <= 0) 624290000Sglebius up->zxing += (double)(carphase - 4) / CYCLE; 62554359Sroberto up->lastsig = lope; 62654359Sroberto 62754359Sroberto /* 628290000Sglebius * End of the baud. Update signal/noise estimates and PLL 629290000Sglebius * phase, frequency and time constant. 63054359Sroberto */ 63154359Sroberto if (up->envphase == 0) { 632290000Sglebius up->maxsignal = up->intmax; up->noise = up->intmin; 633290000Sglebius up->intmin = 1e6; up->intmax = -1e6; 63454359Sroberto if (up->maxsignal < DRPOUT) 635132451Sroberto up->errflg |= IRIG_ERR_AMP; 636132451Sroberto if (up->maxsignal > 0) 637290000Sglebius up->modndx = (up->maxsignal - up->noise) / 638290000Sglebius up->maxsignal; 63954359Sroberto else 640132451Sroberto up->modndx = 0; 64154359Sroberto if (up->modndx < MODMIN) 642132451Sroberto up->errflg |= IRIG_ERR_MOD; 64354359Sroberto if (up->errflg & (IRIG_ERR_AMP | IRIG_ERR_FREQ | 644132451Sroberto IRIG_ERR_MOD | IRIG_ERR_SYNCH)) { 64554359Sroberto up->tc = MINTC; 64654359Sroberto up->tcount = 0; 64754359Sroberto } 64854359Sroberto 64954359Sroberto /* 65054359Sroberto * Update PLL phase and frequency. The PLL time constant 65154359Sroberto * is set initially to stabilize the frequency within a 65254359Sroberto * minute or two, then increases to the maximum. The 65354359Sroberto * frequency is clamped so that the PLL capture range 65454359Sroberto * cannot be exceeded. 65554359Sroberto */ 65654359Sroberto dtemp = up->zxing * up->decim / BAUD; 65754359Sroberto up->yxing = dtemp; 65854359Sroberto up->zxing = 0.; 65954359Sroberto up->phase += dtemp / up->tc; 66054359Sroberto up->freq += dtemp / (4. * up->tc * up->tc); 66154359Sroberto if (up->freq > MAXFREQ) { 66254359Sroberto up->freq = MAXFREQ; 66354359Sroberto up->errflg |= IRIG_ERR_FREQ; 66454359Sroberto } else if (up->freq < -MAXFREQ) { 66554359Sroberto up->freq = -MAXFREQ; 66654359Sroberto up->errflg |= IRIG_ERR_FREQ; 66754359Sroberto } 66854359Sroberto } 66954359Sroberto 67054359Sroberto /* 67154359Sroberto * Synchronous demodulator. There are eight samples in the cycle 672290000Sglebius * and ten cycles in the baud. Since the PLL has aligned the 673290000Sglebius * negative-going zero crossing at sample 4, the maximum 674290000Sglebius * amplitude is at sample 2 and minimum at sample 6. The 67554359Sroberto * beginning of the data pulse is determined from the integrated 67654359Sroberto * samples, while the end of the pulse is determined from the 67754359Sroberto * raw samples. The raw data bits are demodulated relative to 67854359Sroberto * the slice level and left-shifted in the decoding register. 67954359Sroberto */ 680290000Sglebius if (carphase != 7) 681132451Sroberto return; 682182007Sroberto 68354359Sroberto lope = (up->lastint[2] - up->lastint[6]) / 2.; 68454359Sroberto if (lope > up->intmax) 685132451Sroberto up->intmax = lope; 68654359Sroberto if (lope < up->intmin) 687132451Sroberto up->intmin = lope; 68854359Sroberto 68954359Sroberto /* 69054359Sroberto * Pulse code demodulator and reference timestamp. The decoder 69154359Sroberto * looks for a sequence of ten bits; the first two bits must be 69254359Sroberto * one, the last two bits must be zero. Frame synch is asserted 69354359Sroberto * when three correct frames have been found. 69454359Sroberto */ 69554359Sroberto up->pulse = (up->pulse + 1) % 10; 69654359Sroberto up->cycles <<= 1; 69754359Sroberto if (lope >= (up->maxsignal + up->noise) / 2.) 698132451Sroberto up->cycles |= 1; 69954359Sroberto if ((up->cycles & 0x303c0f03) == 0x300c0300) { 700290000Sglebius if (up->pulse != 0) 701290000Sglebius up->errflg |= IRIG_ERR_SYNCH; 702290000Sglebius up->pulse = 0; 703290000Sglebius } 70454359Sroberto 705290000Sglebius /* 706290000Sglebius * Assemble the baud and max/min to get the slice level for the 707290000Sglebius * next baud. The slice level is based on the maximum over the 708290000Sglebius * first two bits and the minimum over the last two bits, with 709290000Sglebius * the slice level halfway between the maximum and minimum. 710290000Sglebius */ 711290000Sglebius env = (up->lastenv[2] - up->lastenv[6]) / 2.; 712290000Sglebius up->dcycles <<= 1; 713290000Sglebius if (env >= up->slice) 714290000Sglebius up->dcycles |= 1; 715290000Sglebius switch(up->pulse) { 716290000Sglebius 717290000Sglebius case 0: 718290000Sglebius irig_baud(peer, up->dcycles); 719290000Sglebius if (env < up->envmin) 720290000Sglebius up->envmin = env; 721290000Sglebius up->slice = (up->envmax + up->envmin) / 2; 722290000Sglebius up->envmin = 1e6; up->envmax = -1e6; 723290000Sglebius break; 724290000Sglebius 725290000Sglebius case 1: 726290000Sglebius up->envmax = env; 727290000Sglebius break; 728290000Sglebius 729290000Sglebius case 2: 730290000Sglebius if (env > up->envmax) 731290000Sglebius up->envmax = env; 732290000Sglebius break; 733290000Sglebius 734290000Sglebius case 9: 735290000Sglebius up->envmin = env; 736290000Sglebius break; 737290000Sglebius } 738290000Sglebius} 739290000Sglebius 740290000Sglebius/* 741290000Sglebius * irig_baud - update the PLL and decode the pulse-width signal 742290000Sglebius */ 743290000Sglebiusstatic void 744290000Sglebiusirig_baud( 745290000Sglebius struct peer *peer, /* peer structure pointer */ 746290000Sglebius int bits /* decoded bits */ 747290000Sglebius ) 748290000Sglebius{ 749290000Sglebius struct refclockproc *pp; 750290000Sglebius struct irigunit *up; 751290000Sglebius double dtemp; 752290000Sglebius l_fp ltemp; 753290000Sglebius 754290000Sglebius pp = peer->procptr; 755290000Sglebius up = pp->unitptr; 756290000Sglebius 757290000Sglebius /* 758290000Sglebius * The PLL time constant starts out small, in order to 759290000Sglebius * sustain a frequency tolerance of 250 PPM. It 760290000Sglebius * gradually increases as the loop settles down. Note 761290000Sglebius * that small wiggles are not believed, unless they 762290000Sglebius * persist for lots of samples. 763290000Sglebius */ 764290000Sglebius up->exing = -up->yxing; 765290000Sglebius if (abs(up->envxing - up->envphase) <= 1) { 766290000Sglebius up->tcount++; 767290000Sglebius if (up->tcount > 20 * up->tc) { 768290000Sglebius up->tc++; 769290000Sglebius if (up->tc > MAXTC) 770290000Sglebius up->tc = MAXTC; 77154359Sroberto up->tcount = 0; 77254359Sroberto up->envxing = up->envphase; 773290000Sglebius } else { 774290000Sglebius up->exing -= up->envxing - up->envphase; 77554359Sroberto } 776290000Sglebius } else { 777290000Sglebius up->tcount = 0; 778290000Sglebius up->envxing = up->envphase; 779290000Sglebius } 78054359Sroberto 781290000Sglebius /* 782290000Sglebius * Strike the baud timestamp as the positive zero crossing of 783290000Sglebius * the first bit, accounting for the codec delay and filter 784290000Sglebius * delay. 785290000Sglebius */ 786290000Sglebius up->prvstamp = up->chrstamp; 787290000Sglebius dtemp = up->decim * (up->exing / SECOND) + up->fdelay; 788290000Sglebius DTOLFP(dtemp, <emp); 789290000Sglebius up->chrstamp = up->timestamp; 790290000Sglebius L_SUB(&up->chrstamp, <emp); 79154359Sroberto 792290000Sglebius /* 793290000Sglebius * The data bits are collected in ten-bit bauds. The first two 794290000Sglebius * bits are not used. The resulting patterns represent runs of 795290000Sglebius * 0-1 bits (0), 2-4 bits (1) and 5-7 bits (PI). The remaining 796290000Sglebius * 8-bit run represents a soft error and is treated as 0. 797290000Sglebius */ 798290000Sglebius switch (up->dcycles & 0xff) { 79954359Sroberto 800290000Sglebius case 0x00: /* 0-1 bits (0) */ 801290000Sglebius case 0x80: 802290000Sglebius irig_decode(peer, BIT0); 803290000Sglebius break; 80454359Sroberto 805290000Sglebius case 0xc0: /* 2-4 bits (1) */ 806290000Sglebius case 0xe0: 807290000Sglebius case 0xf0: 808290000Sglebius irig_decode(peer, BIT1); 809290000Sglebius break; 81054359Sroberto 811290000Sglebius case 0xf8: /* (5-7 bits (PI) */ 812290000Sglebius case 0xfc: 813290000Sglebius case 0xfe: 814290000Sglebius irig_decode(peer, BITP); 815290000Sglebius break; 81654359Sroberto 817290000Sglebius default: /* 8 bits (error) */ 818290000Sglebius irig_decode(peer, BIT0); 819290000Sglebius up->errflg |= IRIG_ERR_DECODE; 82054359Sroberto } 82154359Sroberto} 82254359Sroberto 82354359Sroberto 82454359Sroberto/* 82554359Sroberto * irig_decode - decode the data 82654359Sroberto * 827290000Sglebius * This routine assembles bauds into digits, digits into frames and 828290000Sglebius * frames into the timecode fields. Bits can have values of zero, one 829290000Sglebius * or position identifier. There are four bits per digit, ten digits per 830290000Sglebius * frame and ten frames per second. 83154359Sroberto */ 83254359Srobertostatic void 83354359Srobertoirig_decode( 83454359Sroberto struct peer *peer, /* peer structure pointer */ 83554359Sroberto int bit /* data bit (0, 1 or 2) */ 83654359Sroberto ) 83754359Sroberto{ 83854359Sroberto struct refclockproc *pp; 83954359Sroberto struct irigunit *up; 84054359Sroberto 84154359Sroberto /* 84254359Sroberto * Local variables 84354359Sroberto */ 844290000Sglebius int syncdig; /* sync digit (Spectracom) */ 845290000Sglebius char sbs[6 + 1]; /* binary seconds since 0h */ 846290000Sglebius char spare[2 + 1]; /* mulligan digits */ 847290000Sglebius int temp; 84854359Sroberto 849290000Sglebius syncdig = 0; 850290000Sglebius pp = peer->procptr; 851290000Sglebius up = pp->unitptr; 85254359Sroberto 85354359Sroberto /* 854290000Sglebius * Assemble frame bits. 85554359Sroberto */ 856290000Sglebius up->bits >>= 1; 85754359Sroberto if (bit == BIT1) { 858290000Sglebius up->bits |= 0x200; 85954359Sroberto } else if (bit == BITP && up->lastbit == BITP) { 86054359Sroberto 86154359Sroberto /* 862290000Sglebius * Frame sync - two adjacent position identifiers, which 863290000Sglebius * mark the beginning of the second. The reference time 864290000Sglebius * is the beginning of the second position identifier, 865290000Sglebius * so copy the character timestamp to the reference 866290000Sglebius * timestamp. 86754359Sroberto */ 868290000Sglebius if (up->frmcnt != 1) 869290000Sglebius up->errflg |= IRIG_ERR_SYNCH; 870290000Sglebius up->frmcnt = 1; 871290000Sglebius up->refstamp = up->prvstamp; 87254359Sroberto } 873290000Sglebius up->lastbit = bit; 874290000Sglebius if (up->frmcnt % SUBFLD == 0) { 87554359Sroberto 87654359Sroberto /* 877290000Sglebius * End of frame. Encode two hexadecimal digits in 878290000Sglebius * little-endian timecode field. Note frame 1 is shifted 879290000Sglebius * right one bit to account for the marker PI. 88054359Sroberto */ 881290000Sglebius temp = up->bits; 882290000Sglebius if (up->frmcnt == 10) 883290000Sglebius temp >>= 1; 884290000Sglebius if (up->xptr >= 2) { 885290000Sglebius up->timecode[--up->xptr] = hexchar[temp & 0xf]; 886290000Sglebius up->timecode[--up->xptr] = hexchar[(temp >> 5) & 887290000Sglebius 0xf]; 888290000Sglebius } 889290000Sglebius if (up->frmcnt == 0) { 89054359Sroberto 89154359Sroberto /* 892290000Sglebius * End of second. Decode the timecode and wind 893132451Sroberto * the clock. Not all IRIG generators have the 894132451Sroberto * year; if so, it is nonzero after year 2000. 895132451Sroberto * Not all have the hardware status bit; if so, 896132451Sroberto * it is lit when the source is okay and dim 897132451Sroberto * when bad. We watch this only if the year is 898132451Sroberto * nonzero. Not all are configured for signature 899132451Sroberto * control. If so, all BCD digits are set to 900132451Sroberto * zero if the source is bad. In this case the 901132451Sroberto * refclock_process() will reject the timecode 902132451Sroberto * as invalid. 90354359Sroberto */ 904290000Sglebius up->xptr = 2 * SUBFLD; 90554359Sroberto if (sscanf((char *)up->timecode, 906290000Sglebius "%6s%2d%1d%2s%3d%2d%2d%2d", sbs, &pp->year, 907290000Sglebius &syncdig, spare, &pp->day, &pp->hour, 908132451Sroberto &pp->minute, &pp->second) != 8) 909132451Sroberto pp->leap = LEAP_NOTINSYNC; 91054359Sroberto else 911132451Sroberto pp->leap = LEAP_NOWARNING; 91254359Sroberto up->second = (up->second + up->decim) % 60; 913290000Sglebius 914290000Sglebius /* 915290000Sglebius * Raise an alarm if the day field is zero, 916290000Sglebius * which happens when signature control is 917290000Sglebius * enabled and the device has lost 918290000Sglebius * synchronization. Raise an alarm if the year 919290000Sglebius * field is nonzero and the sync indicator is 920290000Sglebius * zero, which happens when a Spectracom radio 921290000Sglebius * has lost synchronization. Raise an alarm if 922290000Sglebius * the expected second does not agree with the 923290000Sglebius * decoded second, which happens with a garbled 924290000Sglebius * IRIG signal. We are very particular. 925290000Sglebius */ 926290000Sglebius if (pp->day == 0 || (pp->year != 0 && syncdig == 927290000Sglebius 0)) 928290000Sglebius up->errflg |= IRIG_ERR_SIGERR; 92954359Sroberto if (pp->second != up->second) 930132451Sroberto up->errflg |= IRIG_ERR_CHECK; 93154359Sroberto up->second = pp->second; 932290000Sglebius 933290000Sglebius /* 934290000Sglebius * Wind the clock only if there are no errors 935290000Sglebius * and the time constant has reached the 936290000Sglebius * maximum. 937290000Sglebius */ 938290000Sglebius if (up->errflg == 0 && up->tc == MAXTC) { 939290000Sglebius pp->lastref = pp->lastrec; 940290000Sglebius pp->lastrec = up->refstamp; 941290000Sglebius if (!refclock_process(pp)) 942290000Sglebius refclock_report(peer, 943290000Sglebius CEVNT_BADTIME); 944290000Sglebius } 945290000Sglebius snprintf(pp->a_lastcode, sizeof(pp->a_lastcode), 946290000Sglebius "%02x %02d %03d %02d:%02d:%02d %4.0f %3d %6.3f %2d %6.2f %6.1f %s", 947290000Sglebius up->errflg, pp->year, pp->day, 948132451Sroberto pp->hour, pp->minute, pp->second, 949132451Sroberto up->maxsignal, up->gain, up->modndx, 950132451Sroberto up->tc, up->exing * 1e6 / SECOND, up->freq * 951290000Sglebius 1e6 / SECOND, ulfptoa(&pp->lastrec, 6)); 95254359Sroberto pp->lencode = strlen(pp->a_lastcode); 953290000Sglebius up->errflg = 0; 954132451Sroberto if (pp->sloppyclockflag & CLK_FLAG4) { 955132451Sroberto record_clock_stats(&peer->srcadr, 956132451Sroberto pp->a_lastcode); 95754359Sroberto#ifdef DEBUG 958132451Sroberto if (debug) 959290000Sglebius printf("irig %s\n", 960132451Sroberto pp->a_lastcode); 96154359Sroberto#endif /* DEBUG */ 962132451Sroberto } 96354359Sroberto } 96454359Sroberto } 965290000Sglebius up->frmcnt = (up->frmcnt + 1) % FIELD; 96654359Sroberto} 96754359Sroberto 96854359Sroberto 96954359Sroberto/* 97054359Sroberto * irig_poll - called by the transmit procedure 97154359Sroberto * 972132451Sroberto * This routine sweeps up the timecode updates since the last poll. For 973132451Sroberto * IRIG-B there should be at least 60 updates; for IRIG-E there should 974290000Sglebius * be at least 6. If nothing is heard, a timeout event is declared. 97554359Sroberto */ 97654359Srobertostatic void 97754359Srobertoirig_poll( 97854359Sroberto int unit, /* instance number (not used) */ 97954359Sroberto struct peer *peer /* peer structure pointer */ 98054359Sroberto ) 98154359Sroberto{ 98254359Sroberto struct refclockproc *pp; 98354359Sroberto 98454359Sroberto pp = peer->procptr; 98554359Sroberto 986132451Sroberto if (pp->coderecv == pp->codeproc) { 98754359Sroberto refclock_report(peer, CEVNT_TIMEOUT); 98854359Sroberto return; 989182007Sroberto 990290000Sglebius } 991290000Sglebius refclock_receive(peer); 992290000Sglebius if (!(pp->sloppyclockflag & CLK_FLAG4)) { 993132451Sroberto record_clock_stats(&peer->srcadr, pp->a_lastcode); 994132451Sroberto#ifdef DEBUG 995132451Sroberto if (debug) 996290000Sglebius printf("irig %s\n", pp->a_lastcode); 997132451Sroberto#endif /* DEBUG */ 99854359Sroberto } 99954359Sroberto pp->polls++; 100054359Sroberto 100154359Sroberto} 100254359Sroberto 100354359Sroberto 100454359Sroberto/* 100554359Sroberto * irig_gain - adjust codec gain 100654359Sroberto * 1007290000Sglebius * This routine is called at the end of each second. It uses the AGC to 1008290000Sglebius * bradket the maximum signal level between MINAMP and MAXAMP to avoid 1009290000Sglebius * hunting. The routine also jiggles the input port and selectively 1010290000Sglebius * mutes the monitor. 101154359Sroberto */ 101254359Srobertostatic void 101354359Srobertoirig_gain( 101454359Sroberto struct peer *peer /* peer structure pointer */ 101554359Sroberto ) 101654359Sroberto{ 101754359Sroberto struct refclockproc *pp; 101854359Sroberto struct irigunit *up; 101954359Sroberto 102054359Sroberto pp = peer->procptr; 1021290000Sglebius up = pp->unitptr; 102254359Sroberto 102354359Sroberto /* 102454359Sroberto * Apparently, the codec uses only the high order bits of the 102554359Sroberto * gain control field. Thus, it may take awhile for changes to 102656746Sroberto * wiggle the hardware bits. 102754359Sroberto */ 1028290000Sglebius if (up->maxsignal < MINAMP) { 102954359Sroberto up->gain += 4; 1030132451Sroberto if (up->gain > MAXGAIN) 1031132451Sroberto up->gain = MAXGAIN; 1032290000Sglebius } else if (up->maxsignal > MAXAMP) { 103354359Sroberto up->gain -= 4; 103456746Sroberto if (up->gain < 0) 103556746Sroberto up->gain = 0; 103654359Sroberto } 1037132451Sroberto audio_gain(up->gain, up->mongain, up->port); 103854359Sroberto} 103954359Sroberto 1040290000Sglebius 104154359Sroberto#else 104254359Srobertoint refclock_irig_bs; 104354359Sroberto#endif /* REFCLOCK */ 1044