Annotation of embedaddon/ntp/ntpd/refclock_chu.c, revision 1.1

1.1     ! misho       1: /*
        !             2:  * refclock_chu - clock driver for Canadian CHU time/frequency station
        !             3:  */
        !             4: #ifdef HAVE_CONFIG_H
        !             5: #include <config.h>
        !             6: #endif
        !             7: 
        !             8: #if defined(REFCLOCK) && defined(CLOCK_CHU)
        !             9: 
        !            10: #include "ntpd.h"
        !            11: #include "ntp_io.h"
        !            12: #include "ntp_refclock.h"
        !            13: #include "ntp_calendar.h"
        !            14: #include "ntp_stdlib.h"
        !            15: 
        !            16: #include <stdio.h>
        !            17: #include <ctype.h>
        !            18: #include <math.h>
        !            19: 
        !            20: #ifdef HAVE_AUDIO
        !            21: #include "audio.h"
        !            22: #endif /* HAVE_AUDIO */
        !            23: 
        !            24: #define ICOM   1               /* undefine to suppress ICOM code */
        !            25: 
        !            26: #ifdef ICOM
        !            27: #include "icom.h"
        !            28: #endif /* ICOM */
        !            29: /*
        !            30:  * Audio CHU demodulator/decoder
        !            31:  *
        !            32:  * This driver synchronizes the computer time using data encoded in
        !            33:  * radio transmissions from Canadian time/frequency station CHU in
        !            34:  * Ottawa, Ontario. Transmissions are made continuously on 3330 kHz,
        !            35:  * 7850 kHz and 14670 kHz in upper sideband, compatible AM mode. An
        !            36:  * ordinary shortwave receiver can be tuned manually to one of these
        !            37:  * frequencies or, in the case of ICOM receivers, the receiver can be
        !            38:  * tuned automatically as propagation conditions change throughout the
        !            39:  * day and season.
        !            40:  *
        !            41:  * The driver requires an audio codec or sound card with sampling rate 8
        !            42:  * kHz and mu-law companding. This is the same standard as used by the
        !            43:  * telephone industry and is supported by most hardware and operating
        !            44:  * systems, including Solaris, SunOS, FreeBSD, NetBSD and Linux. In this
        !            45:  * implementation, only one audio driver and codec can be supported on a
        !            46:  * single machine.
        !            47:  *
        !            48:  * The driver can be compiled to use a Bell 103 compatible modem or
        !            49:  * modem chip to receive the radio signal and demodulate the data.
        !            50:  * Alternatively, the driver can be compiled to use the audio codec of
        !            51:  * the workstation or another with compatible audio drivers. In the
        !            52:  * latter case, the driver implements the modem using DSP routines, so
        !            53:  * the radio can be connected directly to either the microphone on line
        !            54:  * input port. In either case, the driver decodes the data using a
        !            55:  * maximum-likelihood technique which exploits the considerable degree
        !            56:  * of redundancy available to maximize accuracy and minimize errors.
        !            57:  *
        !            58:  * The CHU time broadcast includes an audio signal compatible with the
        !            59:  * Bell 103 modem standard (mark = 2225 Hz, space = 2025 Hz). The signal
        !            60:  * consists of nine, ten-character bursts transmitted at 300 bps between
        !            61:  * seconds 31 and 39 of each minute. Each character consists of eight
        !            62:  * data bits plus one start bit and two stop bits to encode two hex
        !            63:  * digits. The burst data consist of five characters (ten hex digits)
        !            64:  * followed by a repeat of these characters. In format A, the characters
        !            65:  * are repeated in the same polarity; in format B, the characters are
        !            66:  * repeated in the opposite polarity.
        !            67:  *
        !            68:  * Format A bursts are sent at seconds 32 through 39 of the minute in
        !            69:  * hex digits (nibble swapped)
        !            70:  *
        !            71:  *     6dddhhmmss6dddhhmmss
        !            72:  *
        !            73:  * The first ten digits encode a frame marker (6) followed by the day
        !            74:  * (ddd), hour (hh in UTC), minute (mm) and the second (ss). Since
        !            75:  * format A bursts are sent during the third decade of seconds the tens
        !            76:  * digit of ss is always 3. The driver uses this to determine correct
        !            77:  * burst synchronization. These digits are then repeated with the same
        !            78:  * polarity.
        !            79:  *
        !            80:  * Format B bursts are sent at second 31 of the minute in hex digits
        !            81:  *
        !            82:  *     xdyyyyttaaxdyyyyttaa
        !            83:  *
        !            84:  * The first ten digits encode a code (x described below) followed by
        !            85:  * the DUT1 (d in deciseconds), Gregorian year (yyyy), difference TAI -
        !            86:  * UTC (tt) and daylight time indicator (aa) peculiar to Canada. These
        !            87:  * digits are then repeated with inverted polarity.
        !            88:  *
        !            89:  * The x is coded
        !            90:  *
        !            91:  * 1 Sign of DUT (0 = +)
        !            92:  * 2 Leap second warning. One second will be added.
        !            93:  * 4 Leap second warning. One second will be subtracted.
        !            94:  * 8 Even parity bit for this nibble.
        !            95:  *
        !            96:  * By design, the last stop bit of the last character in the burst
        !            97:  * coincides with 0.5 second. Since characters have 11 bits and are
        !            98:  * transmitted at 300 bps, the last stop bit of the first character
        !            99:  * coincides with 0.5 - 9 * 11/300 = 0.170 second. Depending on the
        !           100:  * UART, character interrupts can vary somewhere between the end of bit
        !           101:  * 9 and end of bit 11. These eccentricities can be corrected along with
        !           102:  * the radio propagation delay using fudge time 1.
        !           103:  *
        !           104:  * Debugging aids
        !           105:  *
        !           106:  * The timecode format used for debugging and data recording includes
        !           107:  * data helpful in diagnosing problems with the radio signal and serial
        !           108:  * connections. With debugging enabled (-d on the ntpd command line),
        !           109:  * the driver produces one line for each burst in two formats
        !           110:  * corresponding to format A and B.Each line begins with the format code
        !           111:  * chuA or chuB followed by the status code and signal level (0-9999).
        !           112:  * The remainder of the line is as follows.
        !           113:  *
        !           114:  * Following is format A:
        !           115:  *
        !           116:  *     n b f s m code
        !           117:  *
        !           118:  * where n is the number of characters in the burst (0-10), b the burst
        !           119:  * distance (0-40), f the field alignment (-1, 0, 1), s the
        !           120:  * synchronization distance (0-16), m the burst number (2-9) and code
        !           121:  * the burst characters as received. Note that the hex digits in each
        !           122:  * character are reversed, so the burst
        !           123:  *
        !           124:  *     10 38 0 16 9 06851292930685129293
        !           125:  *
        !           126:  * is interpreted as containing 10 characters with burst distance 38,
        !           127:  * field alignment 0, synchronization distance 16 and burst number 9.
        !           128:  * The nibble-swapped timecode shows day 58, hour 21, minute 29 and
        !           129:  * second 39.
        !           130:  *
        !           131:  * Following is format B:
        !           132:  * 
        !           133:  *     n b s code
        !           134:  *
        !           135:  * where n is the number of characters in the burst (0-10), b the burst
        !           136:  * distance (0-40), s the synchronization distance (0-40) and code the
        !           137:  * burst characters as received. Note that the hex digits in each
        !           138:  * character are reversed and the last ten digits inverted, so the burst
        !           139:  *
        !           140:  *     10 40 1091891300ef6e76ec
        !           141:  *
        !           142:  * is interpreted as containing 10 characters with burst distance 40.
        !           143:  * The nibble-swapped timecode shows DUT1 +0.1 second, year 1998 and TAI
        !           144:  * - UTC 31 seconds.
        !           145:  *
        !           146:  * Each line is preceeded by the code chuA or chuB, as appropriate. If
        !           147:  * the audio driver is compiled, the current gain (0-255) and relative
        !           148:  * signal level (0-9999) follow the code. The receiver volume control
        !           149:  * should be set so that the gain is somewhere near the middle of the
        !           150:  * range 0-255, which results in a signal level near 1000.
        !           151:  *
        !           152:  * In addition to the above, the reference timecode is updated and
        !           153:  * written to the clockstats file and debug score after the last burst
        !           154:  * received in the minute. The format is
        !           155:  *
        !           156:  *     sq yyyy ddd hh:mm:ss l s dd t agc ident m b      
        !           157:  *
        !           158:  * s   '?' before first synchronized and ' ' after that
        !           159:  * q   status code (see below)
        !           160:  * yyyy        year
        !           161:  * ddd day of year
        !           162:  * hh:mm:ss time of day
        !           163:  * l   leap second indicator (space, L or D)
        !           164:  * dst Canadian daylight code (opaque)
        !           165:  * t   number of minutes since last synchronized
        !           166:  * agc audio gain (0 - 255)
        !           167:  * ident identifier (CHU0 3330 kHz, CHU1 7850 kHz, CHU2 14670 kHz)
        !           168:  * m   signal metric (0 - 100)
        !           169:  * b   number of timecodes for the previous minute (0 - 59)
        !           170:  *
        !           171:  * Fudge factors
        !           172:  *
        !           173:  * For accuracies better than the low millisceconds, fudge time1 can be
        !           174:  * set to the radio propagation delay from CHU to the receiver. This can
        !           175:  * be done conviently using the minimuf program.
        !           176:  *
        !           177:  * Fudge flag4 causes the dubugging output described above to be
        !           178:  * recorded in the clockstats file. When the audio driver is compiled,
        !           179:  * fudge flag2 selects the audio input port, where 0 is the mike port
        !           180:  * (default) and 1 is the line-in port. It does not seem useful to
        !           181:  * select the compact disc player port. Fudge flag3 enables audio
        !           182:  * monitoring of the input signal. For this purpose, the monitor gain is
        !           183:  * set to a default value.
        !           184:  *
        !           185:  * The audio codec code is normally compiled in the driver if the
        !           186:  * architecture supports it (HAVE_AUDIO defined), but is used only if
        !           187:  * the link /dev/chu_audio is defined and valid. The serial port code is
        !           188:  * always compiled in the driver, but is used only if the autdio codec
        !           189:  * is not available and the link /dev/chu%d is defined and valid.
        !           190:  *
        !           191:  * The ICOM code is normally compiled in the driver if selected (ICOM
        !           192:  * defined), but is used only if the link /dev/icom%d is defined and
        !           193:  * valid and the mode keyword on the server configuration command
        !           194:  * specifies a nonzero mode (ICOM ID select code). The C-IV speed is
        !           195:  * 9600 bps if the high order 0x80 bit of the mode is zero and 1200 bps
        !           196:  * if one. The C-IV trace is turned on if the debug level is greater
        !           197:  * than one.
        !           198:  *
        !           199:  * Alarm codes
        !           200:  *
        !           201:  * CEVNT_BADTIME       invalid date or time
        !           202:  * CEVNT_PROP          propagation failure - no stations heard
        !           203:  */
        !           204: /*
        !           205:  * Interface definitions
        !           206:  */
        !           207: #define        SPEED232        B300    /* uart speed (300 baud) */
        !           208: #define        PRECISION       (-10)   /* precision assumed (about 1 ms) */
        !           209: #define        REFID           "CHU"   /* reference ID */
        !           210: #define        DEVICE          "/dev/chu%d" /* device name and unit */
        !           211: #define        SPEED232        B300    /* UART speed (300 baud) */
        !           212: #ifdef ICOM
        !           213: #define TUNE           .001    /* offset for narrow filter (MHz) */
        !           214: #define DWELL          5       /* minutes in a dwell */
        !           215: #define NCHAN          3       /* number of channels */
        !           216: #define ISTAGE         3       /* number of integrator stages */
        !           217: #endif /* ICOM */
        !           218: 
        !           219: #ifdef HAVE_AUDIO
        !           220: /*
        !           221:  * Audio demodulator definitions
        !           222:  */
        !           223: #define SECOND         8000    /* nominal sample rate (Hz) */
        !           224: #define BAUD           300     /* modulation rate (bps) */
        !           225: #define OFFSET         128     /* companded sample offset */
        !           226: #define SIZE           256     /* decompanding table size */
        !           227: #define        MAXAMP          6000.   /* maximum signal level */
        !           228: #define        MAXCLP          100     /* max clips above reference per s */
        !           229: #define        SPAN            800.    /* min envelope span */
        !           230: #define LIMIT          1000.   /* soft limiter threshold */
        !           231: #define AGAIN          6.      /* baseband gain */
        !           232: #define LAG            10      /* discriminator lag */
        !           233: #define        DEVICE_AUDIO    "/dev/audio" /* device name */
        !           234: #define        DESCRIPTION     "CHU Audio/Modem Receiver" /* WRU */
        !           235: #define        AUDIO_BUFSIZ    240     /* audio buffer size (30 ms) */
        !           236: #else
        !           237: #define        DESCRIPTION     "CHU Modem Receiver" /* WRU */
        !           238: #endif /* HAVE_AUDIO */
        !           239: 
        !           240: /*
        !           241:  * Decoder definitions
        !           242:  */
        !           243: #define CHAR           (11. / 300.) /* character time (s) */
        !           244: #define BURST          11      /* max characters per burst */
        !           245: #define MINCHAR                9       /* min characters per burst */
        !           246: #define MINDIST                28      /* min burst distance (of 40)  */
        !           247: #define MINSYNC                8       /* min sync distance (of 16) */
        !           248: #define MINSTAMP       20      /* min timestamps (of 60) */
        !           249: #define MINMETRIC      50      /* min channel metric (of 160) */
        !           250: 
        !           251: /*
        !           252:  * The on-time synchronization point for the driver is the last stop bit
        !           253:  * of the first character 170 ms. The modem delay is 0.8 ms, while the
        !           254:  * receiver delay is approxmately 4.7 ms at 2125 Hz. The fudge value 1.3
        !           255:  * ms due to the codec and other causes was determined by calibrating to
        !           256:  * a PPS signal from a GPS receiver. The additional propagation delay
        !           257:  * specific to each receiver location can be programmed in the fudge
        !           258:  * time1. 
        !           259:  *
        !           260:  * The resulting offsets with a 2.4-GHz P4 running FreeBSD 6.1 are
        !           261:  * generally within 0.5 ms short term with 0.3 ms jitter. The long-term
        !           262:  * offsets vary up to 0.3 ms due to ionospheric layer height variations.
        !           263:  * The processor load due to the driver is 0.4 percent.
        !           264:  */
        !           265: #define        PDELAY  ((170 + .8 + 4.7 + 1.3) / 1000) /* system delay (s) */
        !           266: 
        !           267: /*
        !           268:  * Status bits (status)
        !           269:  */
        !           270: #define RUNT           0x0001  /* runt burst */
        !           271: #define NOISE          0x0002  /* noise burst */
        !           272: #define BFRAME         0x0004  /* invalid format B frame sync */
        !           273: #define BFORMAT                0x0008  /* invalid format B data */
        !           274: #define AFRAME         0x0010  /* invalid format A frame sync */
        !           275: #define AFORMAT                0x0020  /* invalid format A data */
        !           276: #define DECODE         0x0040  /* invalid data decode */
        !           277: #define STAMP          0x0080  /* too few timestamps */
        !           278: #define AVALID         0x0100  /* valid A frame */
        !           279: #define BVALID         0x0200  /* valid B frame */
        !           280: #define INSYNC         0x0400  /* clock synchronized */
        !           281: #define        METRIC          0x0800  /* one or more stations heard */
        !           282: 
        !           283: /*
        !           284:  * Alarm status bits (alarm)
        !           285:  *
        !           286:  * These alarms are set at the end of a minute in which at least one
        !           287:  * burst was received. SYNERR is raised if the AFRAME or BFRAME status
        !           288:  * bits are set during the minute, FMTERR is raised if the AFORMAT or
        !           289:  * BFORMAT status bits are set, DECERR is raised if the DECODE status
        !           290:  * bit is set and TSPERR is raised if the STAMP status bit is set.
        !           291:  */
        !           292: #define SYNERR         0x01    /* frame sync error */
        !           293: #define FMTERR         0x02    /* data format error */
        !           294: #define DECERR         0x04    /* data decoding error */
        !           295: #define TSPERR         0x08    /* insufficient data */
        !           296: 
        !           297: #ifdef HAVE_AUDIO
        !           298: /*
        !           299:  * Maximum-likelihood UART structure. There are eight of these
        !           300:  * corresponding to the number of phases.
        !           301:  */ 
        !           302: struct surv {
        !           303:        l_fp    cstamp;         /* last bit timestamp */
        !           304:        double  shift[12];      /* sample shift register */
        !           305:        double  span;           /* shift register envelope span */
        !           306:        double  dist;           /* sample distance */
        !           307:        int     uart;           /* decoded character */
        !           308: };
        !           309: #endif /* HAVE_AUDIO */
        !           310: 
        !           311: #ifdef ICOM
        !           312: /*
        !           313:  * CHU station structure. There are three of these corresponding to the
        !           314:  * three frequencies.
        !           315:  */
        !           316: struct xmtr {
        !           317:        double  integ[ISTAGE];  /* circular integrator */
        !           318:        double  metric;         /* integrator sum */
        !           319:        int     iptr;           /* integrator pointer */
        !           320:        int     probe;          /* dwells since last probe */
        !           321: };
        !           322: #endif /* ICOM */
        !           323: 
        !           324: /*
        !           325:  * CHU unit control structure
        !           326:  */
        !           327: struct chuunit {
        !           328:        u_char  decode[20][16]; /* maximum-likelihood decoding matrix */
        !           329:        l_fp    cstamp[BURST];  /* character timestamps */
        !           330:        l_fp    tstamp[MAXSTAGE]; /* timestamp samples */
        !           331:        l_fp    timestamp;      /* current buffer timestamp */
        !           332:        l_fp    laststamp;      /* last buffer timestamp */
        !           333:        l_fp    charstamp;      /* character time as a l_fp */
        !           334:        int     second;         /* counts the seconds of the minute */
        !           335:        int     errflg;         /* error flags */
        !           336:        int     status;         /* status bits */
        !           337:        char    ident[5];       /* station ID and channel */
        !           338: #ifdef ICOM
        !           339:        int     fd_icom;        /* ICOM file descriptor */
        !           340:        int     chan;           /* radio channel */
        !           341:        int     dwell;          /* dwell cycle */
        !           342:        struct xmtr xmtr[NCHAN]; /* station metric */
        !           343: #endif /* ICOM */
        !           344: 
        !           345:        /*
        !           346:         * Character burst variables
        !           347:         */
        !           348:        int     cbuf[BURST];    /* character buffer */
        !           349:        int     ntstamp;        /* number of timestamp samples */
        !           350:        int     ndx;            /* buffer start index */
        !           351:        int     prevsec;        /* previous burst second */
        !           352:        int     burdist;        /* burst distance */
        !           353:        int     syndist;        /* sync distance */
        !           354:        int     burstcnt;       /* format A bursts this minute */
        !           355:        double  maxsignal;      /* signal level (modem only) */
        !           356:        int     gain;           /* codec gain (modem only) */
        !           357: 
        !           358:        /*
        !           359:         * Format particulars
        !           360:         */
        !           361:        int     leap;           /* leap/dut code */
        !           362:        int     dut;            /* UTC1 correction */
        !           363:        int     tai;            /* TAI - UTC correction */
        !           364:        int     dst;            /* Canadian DST code */
        !           365: 
        !           366: #ifdef HAVE_AUDIO
        !           367:        /*
        !           368:         * Audio codec variables
        !           369:         */
        !           370:        int     fd_audio;       /* audio port file descriptor */
        !           371:        double  comp[SIZE];     /* decompanding table */
        !           372:        int     port;           /* codec port */
        !           373:        int     mongain;        /* codec monitor gain */
        !           374:        int     clipcnt;        /* sample clip count */
        !           375:        int     seccnt;         /* second interval counter */
        !           376: 
        !           377:        /*
        !           378:         * Modem variables
        !           379:         */
        !           380:        l_fp    tick;           /* audio sample increment */
        !           381:        double  bpf[9];         /* IIR bandpass filter */
        !           382:        double  disc[LAG];      /* discriminator shift register */
        !           383:        double  lpf[27];        /* FIR lowpass filter */
        !           384:        double  monitor;        /* audio monitor */
        !           385:        int     discptr;        /* discriminator pointer */
        !           386: 
        !           387:        /*
        !           388:         * Maximum-likelihood UART variables
        !           389:         */
        !           390:        double  baud;           /* baud interval */
        !           391:        struct surv surv[8];    /* UART survivor structures */
        !           392:        int     decptr;         /* decode pointer */
        !           393:        int     decpha;         /* decode phase */
        !           394:        int     dbrk;           /* holdoff counter */
        !           395: #endif /* HAVE_AUDIO */
        !           396: };
        !           397: 
        !           398: /*
        !           399:  * Function prototypes
        !           400:  */
        !           401: static int     chu_start       (int, struct peer *);
        !           402: static void    chu_shutdown    (int, struct peer *);
        !           403: static void    chu_receive     (struct recvbuf *);
        !           404: static void    chu_second      (int, struct peer *);
        !           405: static void    chu_poll        (int, struct peer *);
        !           406: 
        !           407: /*
        !           408:  * More function prototypes
        !           409:  */
        !           410: static void    chu_decode      (struct peer *, int, l_fp);
        !           411: static void    chu_burst       (struct peer *);
        !           412: static void    chu_clear       (struct peer *);
        !           413: static void    chu_a           (struct peer *, int);
        !           414: static void    chu_b           (struct peer *, int);
        !           415: static int     chu_dist        (int, int);
        !           416: static double  chu_major       (struct peer *);
        !           417: #ifdef HAVE_AUDIO
        !           418: static void    chu_uart        (struct surv *, double);
        !           419: static void    chu_rf          (struct peer *, double);
        !           420: static void    chu_gain        (struct peer *);
        !           421: static void    chu_audio_receive (struct recvbuf *rbufp);
        !           422: #endif /* HAVE_AUDIO */
        !           423: #ifdef ICOM
        !           424: static int     chu_newchan     (struct peer *, double);
        !           425: #endif /* ICOM */
        !           426: static void    chu_serial_receive (struct recvbuf *rbufp);
        !           427: 
        !           428: /*
        !           429:  * Global variables
        !           430:  */
        !           431: static char hexchar[] = "0123456789abcdef_*=";
        !           432: 
        !           433: #ifdef ICOM
        !           434: /*
        !           435:  * Note the tuned frequencies are 1 kHz higher than the carrier. CHU
        !           436:  * transmits on USB with carrier so we can use AM and the narrow SSB
        !           437:  * filter.
        !           438:  */
        !           439: static double qsy[NCHAN] = {3.330, 7.850, 14.670}; /* freq (MHz) */
        !           440: #endif /* ICOM */
        !           441: 
        !           442: /*
        !           443:  * Transfer vector
        !           444:  */
        !           445: struct refclock refclock_chu = {
        !           446:        chu_start,              /* start up driver */
        !           447:        chu_shutdown,           /* shut down driver */
        !           448:        chu_poll,               /* transmit poll message */
        !           449:        noentry,                /* not used (old chu_control) */
        !           450:        noentry,                /* initialize driver (not used) */
        !           451:        noentry,                /* not used (old chu_buginfo) */
        !           452:        chu_second              /* housekeeping timer */
        !           453: };
        !           454: 
        !           455: 
        !           456: /*
        !           457:  * chu_start - open the devices and initialize data for processing
        !           458:  */
        !           459: static int
        !           460: chu_start(
        !           461:        int     unit,           /* instance number (not used) */
        !           462:        struct peer *peer       /* peer structure pointer */
        !           463:        )
        !           464: {
        !           465:        struct chuunit *up;
        !           466:        struct refclockproc *pp;
        !           467:        char device[20];        /* device name */
        !           468:        int     fd;             /* file descriptor */
        !           469: #ifdef ICOM
        !           470:        int     temp;
        !           471: #endif /* ICOM */
        !           472: #ifdef HAVE_AUDIO
        !           473:        int     fd_audio;       /* audio port file descriptor */
        !           474:        int     i;              /* index */
        !           475:        double  step;           /* codec adjustment */
        !           476: 
        !           477:        /*
        !           478:         * Open audio device. Don't complain if not there.
        !           479:         */
        !           480:        fd_audio = audio_init(DEVICE_AUDIO, AUDIO_BUFSIZ, unit);
        !           481: #ifdef DEBUG
        !           482:        if (fd_audio > 0 && debug)
        !           483:                audio_show();
        !           484: #endif
        !           485: 
        !           486:        /*
        !           487:         * If audio is unavailable, Open serial port in raw mode.
        !           488:         */
        !           489:        if (fd_audio > 0) {
        !           490:                fd = fd_audio;
        !           491:        } else {
        !           492:                snprintf(device, sizeof(device), DEVICE, unit);
        !           493:                fd = refclock_open(device, SPEED232, LDISC_RAW);
        !           494:        }
        !           495: #else /* HAVE_AUDIO */
        !           496: 
        !           497:        /*
        !           498:         * Open serial port in raw mode.
        !           499:         */
        !           500:        snprintf(device, sizeof(device), DEVICE, unit);
        !           501:        fd = refclock_open(device, SPEED232, LDISC_RAW);
        !           502: #endif /* HAVE_AUDIO */
        !           503:        if (fd <= 0)
        !           504:                return (0);
        !           505: 
        !           506:        /*
        !           507:         * Allocate and initialize unit structure
        !           508:         */
        !           509:        up = emalloc(sizeof(*up));
        !           510:        memset(up, 0, sizeof(*up));
        !           511:        pp = peer->procptr;
        !           512:        pp->unitptr = (caddr_t)up;
        !           513:        pp->io.clock_recv = chu_receive;
        !           514:        pp->io.srcclock = (caddr_t)peer;
        !           515:        pp->io.datalen = 0;
        !           516:        pp->io.fd = fd;
        !           517:        if (!io_addclock(&pp->io)) {
        !           518:                close(fd);
        !           519:                pp->io.fd = -1;
        !           520:                free(up);
        !           521:                pp->unitptr = NULL;
        !           522:                return (0);
        !           523:        }
        !           524: 
        !           525:        /*
        !           526:         * Initialize miscellaneous variables
        !           527:         */
        !           528:        peer->precision = PRECISION;
        !           529:        pp->clockdesc = DESCRIPTION;
        !           530:        strcpy(up->ident, "CHU");
        !           531:        memcpy(&pp->refid, up->ident, 4); 
        !           532:        DTOLFP(CHAR, &up->charstamp);
        !           533: #ifdef HAVE_AUDIO
        !           534: 
        !           535:        /*
        !           536:         * The companded samples are encoded sign-magnitude. The table
        !           537:         * contains all the 256 values in the interest of speed. We do
        !           538:         * this even if the audio codec is not available. C'est la lazy.
        !           539:         */
        !           540:        up->fd_audio = fd_audio;
        !           541:        up->gain = 127;
        !           542:        up->comp[0] = up->comp[OFFSET] = 0.;
        !           543:        up->comp[1] = 1; up->comp[OFFSET + 1] = -1.;
        !           544:        up->comp[2] = 3; up->comp[OFFSET + 2] = -3.;
        !           545:        step = 2.;
        !           546:        for (i = 3; i < OFFSET; i++) {
        !           547:                up->comp[i] = up->comp[i - 1] + step;
        !           548:                up->comp[OFFSET + i] = -up->comp[i];
        !           549:                 if (i % 16 == 0)
        !           550:                        step *= 2.;
        !           551:        }
        !           552:        DTOLFP(1. / SECOND, &up->tick);
        !           553: #endif /* HAVE_AUDIO */
        !           554: #ifdef ICOM
        !           555:        temp = 0;
        !           556: #ifdef DEBUG
        !           557:        if (debug > 1)
        !           558:                temp = P_TRACE;
        !           559: #endif
        !           560:        if (peer->ttl > 0) {
        !           561:                if (peer->ttl & 0x80)
        !           562:                        up->fd_icom = icom_init("/dev/icom", B1200,
        !           563:                            temp);
        !           564:                else
        !           565:                        up->fd_icom = icom_init("/dev/icom", B9600,
        !           566:                            temp);
        !           567:        }
        !           568:        if (up->fd_icom > 0) {
        !           569:                if (chu_newchan(peer, 0) != 0) {
        !           570:                        msyslog(LOG_NOTICE, "icom: radio not found");
        !           571:                        close(up->fd_icom);
        !           572:                        up->fd_icom = 0;
        !           573:                } else {
        !           574:                        msyslog(LOG_NOTICE, "icom: autotune enabled");
        !           575:                }
        !           576:        }
        !           577: #endif /* ICOM */
        !           578:        return (1);
        !           579: }
        !           580: 
        !           581: 
        !           582: /*
        !           583:  * chu_shutdown - shut down the clock
        !           584:  */
        !           585: static void
        !           586: chu_shutdown(
        !           587:        int     unit,           /* instance number (not used) */
        !           588:        struct peer *peer       /* peer structure pointer */
        !           589:        )
        !           590: {
        !           591:        struct chuunit *up;
        !           592:        struct refclockproc *pp;
        !           593: 
        !           594:        pp = peer->procptr;
        !           595:        up = (struct chuunit *)pp->unitptr;
        !           596:        if (up == NULL)
        !           597:                return;
        !           598: 
        !           599:        io_closeclock(&pp->io);
        !           600: #ifdef ICOM
        !           601:        if (up->fd_icom > 0)
        !           602:                close(up->fd_icom);
        !           603: #endif /* ICOM */
        !           604:        free(up);
        !           605: }
        !           606: 
        !           607: 
        !           608: /*
        !           609:  * chu_receive - receive data from the audio or serial device
        !           610:  */
        !           611: static void
        !           612: chu_receive(
        !           613:        struct recvbuf *rbufp   /* receive buffer structure pointer */
        !           614:        )
        !           615: {
        !           616: #ifdef HAVE_AUDIO
        !           617:        struct chuunit *up;
        !           618:        struct refclockproc *pp;
        !           619:        struct peer *peer;
        !           620: 
        !           621:        peer = (struct peer *)rbufp->recv_srcclock;
        !           622:        pp = peer->procptr;
        !           623:        up = (struct chuunit *)pp->unitptr;
        !           624: 
        !           625:        /*
        !           626:         * If the audio codec is warmed up, the buffer contains codec
        !           627:         * samples which need to be demodulated and decoded into CHU
        !           628:         * characters using the software UART. Otherwise, the buffer
        !           629:         * contains CHU characters from the serial port, so the software
        !           630:         * UART is bypassed. In this case the CPU will probably run a
        !           631:         * few degrees cooler.
        !           632:         */
        !           633:        if (up->fd_audio > 0)
        !           634:                chu_audio_receive(rbufp);
        !           635:        else
        !           636:                chu_serial_receive(rbufp);
        !           637: #else
        !           638:        chu_serial_receive(rbufp);
        !           639: #endif /* HAVE_AUDIO */
        !           640: }
        !           641: 
        !           642: 
        !           643: #ifdef HAVE_AUDIO
        !           644: /*
        !           645:  * chu_audio_receive - receive data from the audio device
        !           646:  */
        !           647: static void
        !           648: chu_audio_receive(
        !           649:        struct recvbuf *rbufp   /* receive buffer structure pointer */
        !           650:        )
        !           651: {
        !           652:        struct chuunit *up;
        !           653:        struct refclockproc *pp;
        !           654:        struct peer *peer;
        !           655: 
        !           656:        double  sample;         /* codec sample */
        !           657:        u_char  *dpt;           /* buffer pointer */
        !           658:        int     bufcnt;         /* buffer counter */
        !           659:        l_fp    ltemp;          /* l_fp temp */
        !           660: 
        !           661:        peer = (struct peer *)rbufp->recv_srcclock;
        !           662:        pp = peer->procptr;
        !           663:        up = (struct chuunit *)pp->unitptr;
        !           664: 
        !           665:        /*
        !           666:         * Main loop - read until there ain't no more. Note codec
        !           667:         * samples are bit-inverted.
        !           668:         */
        !           669:        DTOLFP((double)rbufp->recv_length / SECOND, &ltemp);
        !           670:        L_SUB(&rbufp->recv_time, &ltemp);
        !           671:        up->timestamp = rbufp->recv_time;
        !           672:        dpt = rbufp->recv_buffer;
        !           673:        for (bufcnt = 0; bufcnt < rbufp->recv_length; bufcnt++) {
        !           674:                sample = up->comp[~*dpt++ & 0xff];
        !           675: 
        !           676:                /*
        !           677:                 * Clip noise spikes greater than MAXAMP. If no clips,
        !           678:                 * increase the gain a tad; if the clips are too high, 
        !           679:                 * decrease a tad.
        !           680:                 */
        !           681:                if (sample > MAXAMP) {
        !           682:                        sample = MAXAMP;
        !           683:                        up->clipcnt++;
        !           684:                } else if (sample < -MAXAMP) {
        !           685:                        sample = -MAXAMP;
        !           686:                        up->clipcnt++;
        !           687:                }
        !           688:                chu_rf(peer, sample);
        !           689:                L_ADD(&up->timestamp, &up->tick);
        !           690: 
        !           691:                /*
        !           692:                 * Once each second ride gain.
        !           693:                 */
        !           694:                up->seccnt = (up->seccnt + 1) % SECOND;
        !           695:                if (up->seccnt == 0) {
        !           696:                        chu_gain(peer);
        !           697:                }
        !           698:        }
        !           699: 
        !           700:        /*
        !           701:         * Set the input port and monitor gain for the next buffer.
        !           702:         */
        !           703:        if (pp->sloppyclockflag & CLK_FLAG2)
        !           704:                up->port = 2;
        !           705:        else
        !           706:                up->port = 1;
        !           707:        if (pp->sloppyclockflag & CLK_FLAG3)
        !           708:                up->mongain = MONGAIN;
        !           709:        else
        !           710:                up->mongain = 0;
        !           711: }
        !           712: 
        !           713: 
        !           714: /*
        !           715:  * chu_rf - filter and demodulate the FSK signal
        !           716:  *
        !           717:  * This routine implements a 300-baud Bell 103 modem with mark 2225 Hz
        !           718:  * and space 2025 Hz. It uses a bandpass filter followed by a soft
        !           719:  * limiter, FM discriminator and lowpass filter. A maximum-likelihood
        !           720:  * decoder samples the baseband signal at eight times the baud rate and
        !           721:  * detects the start bit of each character.
        !           722:  *
        !           723:  * The filters are built for speed, which explains the rather clumsy
        !           724:  * code. Hopefully, the compiler will efficiently implement the move-
        !           725:  * and-muiltiply-and-add operations.
        !           726:  */
        !           727: static void
        !           728: chu_rf(
        !           729:        struct peer *peer,      /* peer structure pointer */
        !           730:        double  sample          /* analog sample */
        !           731:        )
        !           732: {
        !           733:        struct refclockproc *pp;
        !           734:        struct chuunit *up;
        !           735:        struct surv *sp;
        !           736: 
        !           737:        /*
        !           738:         * Local variables
        !           739:         */
        !           740:        double  signal;         /* bandpass signal */
        !           741:        double  limit;          /* limiter signal */
        !           742:        double  disc;           /* discriminator signal */
        !           743:        double  lpf;            /* lowpass signal */
        !           744:        double  dist;           /* UART signal distance */
        !           745:        int     i, j;
        !           746: 
        !           747:        pp = peer->procptr;
        !           748:        up = (struct chuunit *)pp->unitptr;
        !           749: 
        !           750:        /*
        !           751:         * Bandpass filter. 4th-order elliptic, 500-Hz bandpass centered
        !           752:         * at 2125 Hz. Passband ripple 0.3 dB, stopband ripple 50 dB,
        !           753:         * phase delay 0.24 ms.
        !           754:         */
        !           755:        signal = (up->bpf[8] = up->bpf[7]) * 5.844676e-01;
        !           756:        signal += (up->bpf[7] = up->bpf[6]) * 4.884860e-01;
        !           757:        signal += (up->bpf[6] = up->bpf[5]) * 2.704384e+00;
        !           758:        signal += (up->bpf[5] = up->bpf[4]) * 1.645032e+00;
        !           759:        signal += (up->bpf[4] = up->bpf[3]) * 4.644557e+00;
        !           760:        signal += (up->bpf[3] = up->bpf[2]) * 1.879165e+00;
        !           761:        signal += (up->bpf[2] = up->bpf[1]) * 3.522634e+00;
        !           762:        signal += (up->bpf[1] = up->bpf[0]) * 7.315738e-01;
        !           763:        up->bpf[0] = sample - signal;
        !           764:        signal = up->bpf[0] * 6.176213e-03
        !           765:            + up->bpf[1] * 3.156599e-03
        !           766:            + up->bpf[2] * 7.567487e-03
        !           767:            + up->bpf[3] * 4.344580e-03
        !           768:            + up->bpf[4] * 1.190128e-02
        !           769:            + up->bpf[5] * 4.344580e-03
        !           770:            + up->bpf[6] * 7.567487e-03
        !           771:            + up->bpf[7] * 3.156599e-03
        !           772:            + up->bpf[8] * 6.176213e-03;
        !           773: 
        !           774:        up->monitor = signal / 4.;      /* note monitor after filter */
        !           775: 
        !           776:        /*
        !           777:         * Soft limiter/discriminator. The 11-sample discriminator lag
        !           778:         * interval corresponds to three cycles of 2125 Hz, which
        !           779:         * requires the sample frequency to be 2125 * 11 / 3 = 7791.7
        !           780:         * Hz. The discriminator output varies +-0.5 interval for input
        !           781:         * frequency 2025-2225 Hz. However, we don't get to sample at
        !           782:         * this frequency, so the discriminator output is biased. Life
        !           783:         * at 8000 Hz sucks.
        !           784:         */
        !           785:        limit = signal;
        !           786:        if (limit > LIMIT)
        !           787:                limit = LIMIT;
        !           788:        else if (limit < -LIMIT)
        !           789:                limit = -LIMIT;
        !           790:        disc = up->disc[up->discptr] * -limit;
        !           791:        up->disc[up->discptr] = limit;
        !           792:        up->discptr = (up->discptr + 1 ) % LAG;
        !           793:        if (disc >= 0)
        !           794:                disc = SQRT(disc);
        !           795:        else
        !           796:                disc = -SQRT(-disc);
        !           797: 
        !           798:        /*
        !           799:         * Lowpass filter. Raised cosine FIR, Ts = 1 / 300, beta = 0.1.
        !           800:         */
        !           801:        lpf = (up->lpf[26] = up->lpf[25]) * 2.538771e-02;
        !           802:        lpf += (up->lpf[25] = up->lpf[24]) * 1.084671e-01;
        !           803:        lpf += (up->lpf[24] = up->lpf[23]) * 2.003159e-01;
        !           804:        lpf += (up->lpf[23] = up->lpf[22]) * 2.985303e-01;
        !           805:        lpf += (up->lpf[22] = up->lpf[21]) * 4.003697e-01;
        !           806:        lpf += (up->lpf[21] = up->lpf[20]) * 5.028552e-01;
        !           807:        lpf += (up->lpf[20] = up->lpf[19]) * 6.028795e-01;
        !           808:        lpf += (up->lpf[19] = up->lpf[18]) * 6.973249e-01;
        !           809:        lpf += (up->lpf[18] = up->lpf[17]) * 7.831828e-01;
        !           810:        lpf += (up->lpf[17] = up->lpf[16]) * 8.576717e-01;
        !           811:        lpf += (up->lpf[16] = up->lpf[15]) * 9.183463e-01;
        !           812:        lpf += (up->lpf[15] = up->lpf[14]) * 9.631951e-01;
        !           813:        lpf += (up->lpf[14] = up->lpf[13]) * 9.907208e-01;
        !           814:        lpf += (up->lpf[13] = up->lpf[12]) * 1.000000e+00;
        !           815:        lpf += (up->lpf[12] = up->lpf[11]) * 9.907208e-01;
        !           816:        lpf += (up->lpf[11] = up->lpf[10]) * 9.631951e-01;
        !           817:        lpf += (up->lpf[10] = up->lpf[9]) * 9.183463e-01;
        !           818:        lpf += (up->lpf[9] = up->lpf[8]) * 8.576717e-01;
        !           819:        lpf += (up->lpf[8] = up->lpf[7]) * 7.831828e-01;
        !           820:        lpf += (up->lpf[7] = up->lpf[6]) * 6.973249e-01;
        !           821:        lpf += (up->lpf[6] = up->lpf[5]) * 6.028795e-01;
        !           822:        lpf += (up->lpf[5] = up->lpf[4]) * 5.028552e-01;
        !           823:        lpf += (up->lpf[4] = up->lpf[3]) * 4.003697e-01;
        !           824:        lpf += (up->lpf[3] = up->lpf[2]) * 2.985303e-01;
        !           825:        lpf += (up->lpf[2] = up->lpf[1]) * 2.003159e-01;
        !           826:        lpf += (up->lpf[1] = up->lpf[0]) * 1.084671e-01;
        !           827:        lpf += up->lpf[0] = disc * 2.538771e-02;
        !           828: 
        !           829:        /*
        !           830:         * Maximum-likelihood decoder. The UART updates each of the
        !           831:         * eight survivors and determines the span, slice level and
        !           832:         * tentative decoded character. Valid 11-bit characters are
        !           833:         * framed so that bit 10 and bit 11 (stop bits) are mark and bit
        !           834:         * 1 (start bit) is space. When a valid character is found, the
        !           835:         * survivor with maximum distance determines the final decoded
        !           836:         * character.
        !           837:         */
        !           838:        up->baud += 1. / SECOND;
        !           839:        if (up->baud > 1. / (BAUD * 8.)) {
        !           840:                up->baud -= 1. / (BAUD * 8.);
        !           841:                up->decptr = (up->decptr + 1) % 8;
        !           842:                sp = &up->surv[up->decptr];
        !           843:                sp->cstamp = up->timestamp;
        !           844:                chu_uart(sp, -lpf * AGAIN);
        !           845:                if (up->dbrk > 0) {
        !           846:                        up->dbrk--;
        !           847:                        if (up->dbrk > 0)
        !           848:                                return;
        !           849: 
        !           850:                        up->decpha = up->decptr;
        !           851:                }
        !           852:                if (up->decptr != up->decpha)
        !           853:                        return;
        !           854: 
        !           855:                dist = 0;
        !           856:                j = -1;
        !           857:                for (i = 0; i < 8; i++) {
        !           858: 
        !           859:                        /*
        !           860:                         * The timestamp is taken at the last bit, so
        !           861:                         * for correct decoding we reqire sufficient
        !           862:                         * span and correct start bit and two stop bits.
        !           863:                         */
        !           864:                        if ((up->surv[i].uart & 0x601) != 0x600 ||
        !           865:                            up->surv[i].span < SPAN)
        !           866:                                continue;
        !           867: 
        !           868:                        if (up->surv[i].dist > dist) {
        !           869:                                dist = up->surv[i].dist;
        !           870:                                j = i;
        !           871:                        }
        !           872:                }
        !           873:                if (j < 0)
        !           874:                        return;
        !           875: 
        !           876:                /*
        !           877:                 * Process the character, then blank the decoder until
        !           878:                 * the end of the next character.This sets the decoding
        !           879:                 * phase of the entire burst from the phase of the first
        !           880:                 * character.
        !           881:                 */
        !           882:                up->maxsignal = up->surv[j].span;
        !           883:                chu_decode(peer, (up->surv[j].uart >> 1) & 0xff,
        !           884:                    up->surv[j].cstamp);
        !           885:                up->dbrk = 88;
        !           886:        }
        !           887: }
        !           888: 
        !           889: 
        !           890: /*
        !           891:  * chu_uart - maximum-likelihood UART
        !           892:  *
        !           893:  * This routine updates a shift register holding the last 11 envelope
        !           894:  * samples. It then computes the slice level and span over these samples
        !           895:  * and determines the tentative data bits and distance. The calling
        !           896:  * program selects over the last eight survivors the one with maximum
        !           897:  * distance to determine the decoded character.
        !           898:  */
        !           899: static void
        !           900: chu_uart(
        !           901:        struct surv *sp,        /* survivor structure pointer */
        !           902:        double  sample          /* baseband signal */
        !           903:        )
        !           904: {
        !           905:        double  es_max, es_min; /* max/min envelope */
        !           906:        double  slice;          /* slice level */
        !           907:        double  dist;           /* distance */
        !           908:        double  dtemp;
        !           909:        int     i;
        !           910: 
        !           911:        /*
        !           912:         * Save the sample and shift right. At the same time, measure
        !           913:         * the maximum and minimum over all eleven samples.
        !           914:         */
        !           915:        es_max = -1e6;
        !           916:        es_min = 1e6;
        !           917:        sp->shift[0] = sample;
        !           918:        for (i = 11; i > 0; i--) {
        !           919:                sp->shift[i] = sp->shift[i - 1];
        !           920:                if (sp->shift[i] > es_max)
        !           921:                        es_max = sp->shift[i];
        !           922:                if (sp->shift[i] < es_min)
        !           923:                        es_min = sp->shift[i];
        !           924:        }
        !           925: 
        !           926:        /*
        !           927:         * Determine the span as the maximum less the minimum and the
        !           928:         * slice level as the minimum plus a fraction of the span. Note
        !           929:         * the slight bias toward mark to correct for the modem tendency
        !           930:         * to make more mark than space errors. Compute the distance on
        !           931:         * the assumption the last two bits must be mark, the first
        !           932:         * space and the rest either mark or space. 
        !           933:         */ 
        !           934:        sp->span = es_max - es_min;
        !           935:        slice = es_min + .45 * sp->span;
        !           936:        dist = 0;
        !           937:        sp->uart = 0;
        !           938:        for (i = 1; i < 12; i++) {
        !           939:                sp->uart <<= 1;
        !           940:                dtemp = sp->shift[i];
        !           941:                if (dtemp > slice)
        !           942:                        sp->uart |= 0x1;
        !           943:                if (i == 1 || i == 2) {
        !           944:                        dist += dtemp - es_min;
        !           945:                } else if (i == 11) {
        !           946:                        dist += es_max - dtemp;
        !           947:                } else {
        !           948:                        if (dtemp > slice)
        !           949:                                dist += dtemp - es_min;
        !           950:                        else
        !           951:                                dist += es_max - dtemp;
        !           952:                }
        !           953:        }
        !           954:        sp->dist = dist / (11 * sp->span);
        !           955: }
        !           956: #endif /* HAVE_AUDIO */
        !           957: 
        !           958: 
        !           959: /*
        !           960:  * chu_serial_receive - receive data from the serial device
        !           961:  */
        !           962: static void
        !           963: chu_serial_receive(
        !           964:        struct recvbuf *rbufp   /* receive buffer structure pointer */
        !           965:        )
        !           966: {
        !           967:        struct chuunit *up;
        !           968:        struct refclockproc *pp;
        !           969:        struct peer *peer;
        !           970: 
        !           971:        u_char  *dpt;           /* receive buffer pointer */
        !           972: 
        !           973:        peer = (struct peer *)rbufp->recv_srcclock;
        !           974:        pp = peer->procptr;
        !           975:        up = (struct chuunit *)pp->unitptr;
        !           976: 
        !           977:        dpt = (u_char *)&rbufp->recv_space;
        !           978:        chu_decode(peer, *dpt, rbufp->recv_time);
        !           979: }
        !           980: 
        !           981: 
        !           982: /*
        !           983:  * chu_decode - decode the character data
        !           984:  */
        !           985: static void
        !           986: chu_decode(
        !           987:        struct peer *peer,      /* peer structure pointer */
        !           988:        int     hexhex,         /* data character */
        !           989:        l_fp    cstamp          /* data character timestamp */
        !           990:        )
        !           991: {
        !           992:        struct refclockproc *pp;
        !           993:        struct chuunit *up;
        !           994: 
        !           995:        l_fp    tstmp;          /* timestamp temp */
        !           996:        double  dtemp;
        !           997: 
        !           998:        pp = peer->procptr;
        !           999:        up = (struct chuunit *)pp->unitptr;
        !          1000: 
        !          1001:        /*
        !          1002:         * If the interval since the last character is greater than the
        !          1003:         * longest burst, process the last burst and start a new one. If
        !          1004:         * the interval is less than this but greater than two
        !          1005:         * characters, consider this a noise burst and reject it.
        !          1006:         */
        !          1007:        tstmp = up->timestamp;
        !          1008:        if (L_ISZERO(&up->laststamp))
        !          1009:                up->laststamp = up->timestamp;
        !          1010:        L_SUB(&tstmp, &up->laststamp);
        !          1011:        up->laststamp = up->timestamp;
        !          1012:        LFPTOD(&tstmp, dtemp);
        !          1013:        if (dtemp > BURST * CHAR) {
        !          1014:                chu_burst(peer);
        !          1015:                up->ndx = 0;
        !          1016:        } else if (dtemp > 2.5 * CHAR) {
        !          1017:                up->ndx = 0;
        !          1018:        }
        !          1019: 
        !          1020:        /*
        !          1021:         * Append the character to the current burst and append the
        !          1022:         * character timestamp to the timestamp list.
        !          1023:         */
        !          1024:        if (up->ndx < BURST) {
        !          1025:                up->cbuf[up->ndx] = hexhex & 0xff;
        !          1026:                up->cstamp[up->ndx] = cstamp;
        !          1027:                up->ndx++;
        !          1028: 
        !          1029:        }
        !          1030: }
        !          1031: 
        !          1032: 
        !          1033: /*
        !          1034:  * chu_burst - search for valid burst format
        !          1035:  */
        !          1036: static void
        !          1037: chu_burst(
        !          1038:        struct peer *peer
        !          1039:        )
        !          1040: {
        !          1041:        struct chuunit *up;
        !          1042:        struct refclockproc *pp;
        !          1043: 
        !          1044:        int     i;
        !          1045: 
        !          1046:        pp = peer->procptr;
        !          1047:        up = (struct chuunit *)pp->unitptr;
        !          1048: 
        !          1049:        /*
        !          1050:         * Correlate a block of five characters with the next block of
        !          1051:         * five characters. The burst distance is defined as the number
        !          1052:         * of bits that match in the two blocks for format A and that
        !          1053:         * match the inverse for format B.
        !          1054:         */
        !          1055:        if (up->ndx < MINCHAR) {
        !          1056:                up->status |= RUNT;
        !          1057:                return;
        !          1058:        }
        !          1059:        up->burdist = 0;
        !          1060:        for (i = 0; i < 5 && i < up->ndx - 5; i++)
        !          1061:                up->burdist += chu_dist(up->cbuf[i], up->cbuf[i + 5]);
        !          1062: 
        !          1063:        /*
        !          1064:         * If the burst distance is at least MINDIST, this must be a
        !          1065:         * format A burst; if the value is not greater than -MINDIST, it
        !          1066:         * must be a format B burst. If the B burst is perfect, we
        !          1067:         * believe it; otherwise, it is a noise burst and of no use to
        !          1068:         * anybody.
        !          1069:         */
        !          1070:        if (up->burdist >= MINDIST) {
        !          1071:                chu_a(peer, up->ndx);
        !          1072:        } else if (up->burdist <= -MINDIST) {
        !          1073:                chu_b(peer, up->ndx);
        !          1074:        } else {
        !          1075:                up->status |= NOISE;
        !          1076:                return;
        !          1077:        }
        !          1078: 
        !          1079:        /*
        !          1080:         * If this is a valid burst, wait a guard time of ten seconds to
        !          1081:         * allow for more bursts, then arm the poll update routine to
        !          1082:         * process the minute. Don't do this if this is called from the
        !          1083:         * timer interrupt routine.
        !          1084:         */
        !          1085:        if (peer->outdate != current_time)
        !          1086:                peer->nextdate = current_time + 10;
        !          1087: }
        !          1088: 
        !          1089: 
        !          1090: /*
        !          1091:  * chu_b - decode format B burst
        !          1092:  */
        !          1093: static void
        !          1094: chu_b(
        !          1095:        struct peer *peer,
        !          1096:        int     nchar
        !          1097:        )
        !          1098: {
        !          1099:        struct  refclockproc *pp;
        !          1100:        struct  chuunit *up;
        !          1101: 
        !          1102:        u_char  code[11];       /* decoded timecode */
        !          1103:        char    tbuf[80];       /* trace buffer */
        !          1104:        char *  p;
        !          1105:        size_t  chars;
        !          1106:        size_t  cb;
        !          1107:        int     i;
        !          1108: 
        !          1109:        pp = peer->procptr;
        !          1110:        up = (struct chuunit *)pp->unitptr;
        !          1111: 
        !          1112:        /*
        !          1113:         * In a format B burst, a character is considered valid only if
        !          1114:         * the first occurence matches the last occurence. The burst is
        !          1115:         * considered valid only if all characters are valid; that is,
        !          1116:         * only if the distance is 40. Note that once a valid frame has
        !          1117:         * been found errors are ignored.
        !          1118:         */
        !          1119:        snprintf(tbuf, sizeof(tbuf), "chuB %04x %4.0f %2d %2d ",
        !          1120:                 up->status, up->maxsignal, nchar, -up->burdist);
        !          1121:        cb = sizeof(tbuf);
        !          1122:        p = tbuf;
        !          1123:        for (i = 0; i < nchar; i++) {
        !          1124:                chars = strlen(p);
        !          1125:                if (cb < chars + 1) {
        !          1126:                        msyslog(LOG_ERR, "chu_b() fatal out buffer");
        !          1127:                        exit(1);
        !          1128:                }
        !          1129:                cb -= chars;
        !          1130:                p += chars;
        !          1131:                snprintf(p, cb, "%02x", up->cbuf[i]);
        !          1132:        }
        !          1133:        if (pp->sloppyclockflag & CLK_FLAG4)
        !          1134:                record_clock_stats(&peer->srcadr, tbuf);
        !          1135: #ifdef DEBUG
        !          1136:        if (debug)
        !          1137:                printf("%s\n", tbuf);
        !          1138: #endif
        !          1139:        if (up->burdist > -40) {
        !          1140:                up->status |= BFRAME;
        !          1141:                return;
        !          1142:        }
        !          1143: 
        !          1144:        /*
        !          1145:         * Convert the burst data to internal format. Don't bother with
        !          1146:         * the timestamps.
        !          1147:         */
        !          1148:        for (i = 0; i < 5; i++) {
        !          1149:                code[2 * i] = hexchar[up->cbuf[i] & 0xf];
        !          1150:                code[2 * i + 1] = hexchar[(up->cbuf[i] >>
        !          1151:                    4) & 0xf];
        !          1152:        }
        !          1153:        if (sscanf((char *)code, "%1x%1d%4d%2d%2x", &up->leap, &up->dut,
        !          1154:            &pp->year, &up->tai, &up->dst) != 5) {
        !          1155:                up->status |= BFORMAT;
        !          1156:                return;
        !          1157:        }
        !          1158:        up->status |= BVALID;
        !          1159:        if (up->leap & 0x8)
        !          1160:                up->dut = -up->dut;
        !          1161: }
        !          1162: 
        !          1163: 
        !          1164: /*
        !          1165:  * chu_a - decode format A burst
        !          1166:  */
        !          1167: static void
        !          1168: chu_a(
        !          1169:        struct peer *peer,
        !          1170:        int nchar
        !          1171:        )
        !          1172: {
        !          1173:        struct refclockproc *pp;
        !          1174:        struct chuunit *up;
        !          1175: 
        !          1176:        char    tbuf[80];       /* trace buffer */
        !          1177:        char *  p;
        !          1178:        size_t  chars;
        !          1179:        size_t  cb;
        !          1180:        l_fp    offset;         /* timestamp offset */
        !          1181:        int     val;            /* distance */
        !          1182:        int     temp;
        !          1183:        int     i, j, k;
        !          1184: 
        !          1185:        pp = peer->procptr;
        !          1186:        up = (struct chuunit *)pp->unitptr;
        !          1187: 
        !          1188:        /*
        !          1189:         * Determine correct burst phase. There are three cases
        !          1190:         * corresponding to in-phase, one character early or one
        !          1191:         * character late. These cases are distinguished by the position
        !          1192:         * of the framing digits 0x6 at positions 0 and 5 and 0x3 at
        !          1193:         * positions 4 and 9. The correct phase is when the distance
        !          1194:         * relative to the framing digits is maximum. The burst is valid
        !          1195:         * only if the maximum distance is at least MINSYNC.
        !          1196:         */
        !          1197:        up->syndist = k = 0;
        !          1198:        val = -16;
        !          1199:        for (i = -1; i < 2; i++) {
        !          1200:                temp = up->cbuf[i + 4] & 0xf;
        !          1201:                if (i >= 0)
        !          1202:                        temp |= (up->cbuf[i] & 0xf) << 4;
        !          1203:                val = chu_dist(temp, 0x63);
        !          1204:                temp = (up->cbuf[i + 5] & 0xf) << 4;
        !          1205:                if (i + 9 < nchar)
        !          1206:                        temp |= up->cbuf[i + 9] & 0xf;
        !          1207:                val += chu_dist(temp, 0x63);
        !          1208:                if (val > up->syndist) {
        !          1209:                        up->syndist = val;
        !          1210:                        k = i;
        !          1211:                }
        !          1212:        }
        !          1213: 
        !          1214:        /*
        !          1215:         * Extract the second number; it must be in the range 2 through
        !          1216:         * 9 and the two repititions must be the same.
        !          1217:         */
        !          1218:        temp = (up->cbuf[k + 4] >> 4) & 0xf;
        !          1219:        if (temp < 2 || temp > 9 || k + 9 >= nchar || temp !=
        !          1220:            ((up->cbuf[k + 9] >> 4) & 0xf))
        !          1221:                temp = 0;
        !          1222:        snprintf(tbuf, sizeof(tbuf),
        !          1223:                 "chuA %04x %4.0f %2d %2d %2d %2d %1d ", up->status,
        !          1224:                 up->maxsignal, nchar, up->burdist, k, up->syndist,
        !          1225:                 temp);
        !          1226:        cb = sizeof(tbuf);
        !          1227:        p = tbuf;
        !          1228:        for (i = 0; i < nchar; i++) {
        !          1229:                chars = strlen(p);
        !          1230:                if (cb < chars + 1) {
        !          1231:                        msyslog(LOG_ERR, "chu_a() fatal out buffer");
        !          1232:                        exit(1);
        !          1233:                }
        !          1234:                cb -= chars;
        !          1235:                p += chars;
        !          1236:                snprintf(p, cb, "%02x", up->cbuf[i]);
        !          1237:        }
        !          1238:        if (pp->sloppyclockflag & CLK_FLAG4)
        !          1239:                record_clock_stats(&peer->srcadr, tbuf);
        !          1240: #ifdef DEBUG
        !          1241:        if (debug)
        !          1242:                printf("%s\n", tbuf);
        !          1243: #endif
        !          1244:        if (up->syndist < MINSYNC) {
        !          1245:                up->status |= AFRAME;
        !          1246:                return;
        !          1247:        }
        !          1248: 
        !          1249:        /*
        !          1250:         * A valid burst requires the first seconds number to match the
        !          1251:         * last seconds number. If so, the burst timestamps are
        !          1252:         * corrected to the current minute and saved for later
        !          1253:         * processing. In addition, the seconds decode is advanced from
        !          1254:         * the previous burst to the current one.
        !          1255:         */
        !          1256:        if (temp == 0) {
        !          1257:                up->status |= AFORMAT;
        !          1258:        } else {
        !          1259:                up->status |= AVALID;
        !          1260:                up->second = pp->second = 30 + temp;
        !          1261:                offset.l_ui = 30 + temp;
        !          1262:                offset.l_f = 0;
        !          1263:                i = 0;
        !          1264:                if (k < 0)
        !          1265:                        offset = up->charstamp;
        !          1266:                else if (k > 0)
        !          1267:                        i = 1;
        !          1268:                for (; i < nchar && i < k + 10; i++) {
        !          1269:                        up->tstamp[up->ntstamp] = up->cstamp[i];
        !          1270:                        L_SUB(&up->tstamp[up->ntstamp], &offset);
        !          1271:                        L_ADD(&offset, &up->charstamp);
        !          1272:                        if (up->ntstamp < MAXSTAGE - 1)
        !          1273:                                up->ntstamp++;
        !          1274:                }
        !          1275:                while (temp > up->prevsec) {
        !          1276:                        for (j = 15; j > 0; j--) {
        !          1277:                                up->decode[9][j] = up->decode[9][j - 1];
        !          1278:                                up->decode[19][j] =
        !          1279:                                    up->decode[19][j - 1];
        !          1280:                        }
        !          1281:                        up->decode[9][j] = up->decode[19][j] = 0;
        !          1282:                        up->prevsec++;
        !          1283:                }
        !          1284:        }
        !          1285: 
        !          1286:        /*
        !          1287:         * Stash the data in the decoding matrix.
        !          1288:         */
        !          1289:        i = -(2 * k);
        !          1290:        for (j = 0; j < nchar; j++) {
        !          1291:                if (i < 0 || i > 18) {
        !          1292:                        i += 2;
        !          1293:                        continue;
        !          1294:                }
        !          1295:                up->decode[i][up->cbuf[j] & 0xf]++;
        !          1296:                i++;
        !          1297:                up->decode[i][(up->cbuf[j] >> 4) & 0xf]++;
        !          1298:                i++;
        !          1299:        }
        !          1300:        up->burstcnt++;
        !          1301: }
        !          1302: 
        !          1303: 
        !          1304: /*
        !          1305:  * chu_poll - called by the transmit procedure
        !          1306:  */
        !          1307: static void
        !          1308: chu_poll(
        !          1309:        int unit,
        !          1310:        struct peer *peer       /* peer structure pointer */
        !          1311:        )
        !          1312: {
        !          1313:        struct refclockproc *pp;
        !          1314: 
        !          1315:        pp = peer->procptr;
        !          1316:        pp->polls++;
        !          1317: }
        !          1318: 
        !          1319: 
        !          1320: /*
        !          1321:  * chu_second - process minute data
        !          1322:  */
        !          1323: static void
        !          1324: chu_second(
        !          1325:        int unit,
        !          1326:        struct peer *peer       /* peer structure pointer */
        !          1327:        )
        !          1328: {
        !          1329:        struct refclockproc *pp;
        !          1330:        struct chuunit *up;
        !          1331:        l_fp    offset;
        !          1332:        char    synchar, qual, leapchar;
        !          1333:        int     minset, i;
        !          1334:        double  dtemp;
        !          1335: 
        !          1336:        pp = peer->procptr;
        !          1337:        up = (struct chuunit *)pp->unitptr;
        !          1338: 
        !          1339:        /*
        !          1340:         * This routine is called once per minute to process the
        !          1341:         * accumulated burst data. We do a bit of fancy footwork so that
        !          1342:         * this doesn't run while burst data are being accumulated.
        !          1343:         */
        !          1344:        up->second = (up->second + 1) % 60;
        !          1345:        if (up->second != 0)
        !          1346:                return;
        !          1347: 
        !          1348:        /*
        !          1349:         * Process the last burst, if still in the burst buffer.
        !          1350:         * If the minute contains a valid B frame with sufficient A
        !          1351:         * frame metric, it is considered valid. However, the timecode
        !          1352:         * is sent to clockstats even if invalid.
        !          1353:         */
        !          1354:        chu_burst(peer);
        !          1355:        minset = ((current_time - peer->update) + 30) / 60;
        !          1356:        dtemp = chu_major(peer);
        !          1357:        qual = 0;
        !          1358:        if (up->status & (BFRAME | AFRAME))
        !          1359:                qual |= SYNERR;
        !          1360:        if (up->status & (BFORMAT | AFORMAT))
        !          1361:                qual |= FMTERR;
        !          1362:        if (up->status & DECODE)
        !          1363:                qual |= DECERR;
        !          1364:        if (up->status & STAMP)
        !          1365:                qual |= TSPERR;
        !          1366:        if (up->status & BVALID && dtemp >= MINMETRIC)
        !          1367:                up->status |= INSYNC;
        !          1368:        synchar = leapchar = ' ';
        !          1369:        if (!(up->status & INSYNC)) {
        !          1370:                pp->leap = LEAP_NOTINSYNC;
        !          1371:                synchar = '?';
        !          1372:        } else if (up->leap & 0x2) {
        !          1373:                pp->leap = LEAP_ADDSECOND;
        !          1374:                leapchar = 'L';
        !          1375:        } else if (up->leap & 0x4) {
        !          1376:                pp->leap = LEAP_DELSECOND;
        !          1377:                leapchar = 'l';
        !          1378:        } else {
        !          1379:                pp->leap = LEAP_NOWARNING;
        !          1380:        }
        !          1381:        snprintf(pp->a_lastcode, sizeof(pp->a_lastcode),
        !          1382:            "%c%1X %04d %03d %02d:%02d:%02d %c%x %+d %d %d %s %.0f %d",
        !          1383:            synchar, qual, pp->year, pp->day, pp->hour, pp->minute,
        !          1384:            pp->second, leapchar, up->dst, up->dut, minset, up->gain,
        !          1385:            up->ident, dtemp, up->ntstamp);
        !          1386:        pp->lencode = strlen(pp->a_lastcode);
        !          1387: 
        !          1388:        /*
        !          1389:         * If in sync and the signal metric is above threshold, the
        !          1390:         * timecode is ipso fatso valid and can be selected to
        !          1391:         * discipline the clock.
        !          1392:         */
        !          1393:        if (up->status & INSYNC && !(up->status & (DECODE | STAMP)) &&
        !          1394:            dtemp > MINMETRIC) {
        !          1395:                if (!clocktime(pp->day, pp->hour, pp->minute, 0, GMT,
        !          1396:                    up->tstamp[0].l_ui, &pp->yearstart, &offset.l_ui)) {
        !          1397:                        up->errflg = CEVNT_BADTIME;
        !          1398:                } else {
        !          1399:                        offset.l_uf = 0;
        !          1400:                        for (i = 0; i < up->ntstamp; i++)
        !          1401:                                refclock_process_offset(pp, offset,
        !          1402:                                up->tstamp[i], PDELAY +
        !          1403:                                    pp->fudgetime1);
        !          1404:                        pp->lastref = up->timestamp;
        !          1405:                        refclock_receive(peer);
        !          1406:                }
        !          1407:        }
        !          1408:        if (dtemp > 0)
        !          1409:                record_clock_stats(&peer->srcadr, pp->a_lastcode);
        !          1410: #ifdef DEBUG
        !          1411:        if (debug)
        !          1412:                printf("chu: timecode %d %s\n", pp->lencode,
        !          1413:                    pp->a_lastcode);
        !          1414: #endif
        !          1415: #ifdef ICOM
        !          1416:        chu_newchan(peer, dtemp);
        !          1417: #endif /* ICOM */
        !          1418:        chu_clear(peer);
        !          1419:        if (up->errflg)
        !          1420:                refclock_report(peer, up->errflg);
        !          1421:        up->errflg = 0;
        !          1422: }
        !          1423: 
        !          1424: 
        !          1425: /*
        !          1426:  * chu_major - majority decoder
        !          1427:  */
        !          1428: static double
        !          1429: chu_major(
        !          1430:        struct peer *peer       /* peer structure pointer */
        !          1431:        )
        !          1432: {
        !          1433:        struct refclockproc *pp;
        !          1434:        struct chuunit *up;
        !          1435: 
        !          1436:        u_char  code[11];       /* decoded timecode */
        !          1437:        int     metric;         /* distance metric */
        !          1438:        int     val1;           /* maximum distance */
        !          1439:        int     synchar;        /* stray cat */
        !          1440:        int     temp;
        !          1441:        int     i, j, k;
        !          1442: 
        !          1443:        pp = peer->procptr;
        !          1444:        up = (struct chuunit *)pp->unitptr;
        !          1445: 
        !          1446:        /*
        !          1447:         * Majority decoder. Each burst encodes two replications at each
        !          1448:         * digit position in the timecode. Each row of the decoding
        !          1449:         * matrix encodes the number of occurences of each digit found
        !          1450:         * at the corresponding position. The maximum over all
        !          1451:         * occurrences at each position is the distance for this
        !          1452:         * position and the corresponding digit is the maximum-
        !          1453:         * likelihood candidate. If the distance is not more than half
        !          1454:         * the total number of occurences, a majority has not been found
        !          1455:         * and the data are discarded. The decoding distance is defined
        !          1456:         * as the sum of the distances over the first nine digits. The
        !          1457:         * tenth digit varies over the seconds, so we don't count it.
        !          1458:         */
        !          1459:        metric = 0;
        !          1460:        for (i = 0; i < 9; i++) {
        !          1461:                val1 = 0;
        !          1462:                k = 0;
        !          1463:                for (j = 0; j < 16; j++) {
        !          1464:                        temp = up->decode[i][j] + up->decode[i + 10][j];
        !          1465:                        if (temp > val1) {
        !          1466:                                val1 = temp;
        !          1467:                                k = j;
        !          1468:                        }
        !          1469:                }
        !          1470:                if (val1 <= up->burstcnt)
        !          1471:                        up->status |= DECODE;
        !          1472:                metric += val1;
        !          1473:                code[i] = hexchar[k];
        !          1474:        }
        !          1475: 
        !          1476:        /*
        !          1477:         * Compute the timecode timestamp from the days, hours and
        !          1478:         * minutes of the timecode. Use clocktime() for the aggregate
        !          1479:         * minutes and the minute offset computed from the burst
        !          1480:         * seconds. Note that this code relies on the filesystem time
        !          1481:         * for the years and does not use the years of the timecode.
        !          1482:         */
        !          1483:        if (sscanf((char *)code, "%1x%3d%2d%2d", &synchar, &pp->day,
        !          1484:            &pp->hour, &pp->minute) != 4)
        !          1485:                up->status |= DECODE;
        !          1486:        if (up->ntstamp < MINSTAMP)
        !          1487:                up->status |= STAMP;
        !          1488:        return (metric);
        !          1489: }
        !          1490: 
        !          1491: 
        !          1492: /*
        !          1493:  * chu_clear - clear decoding matrix
        !          1494:  */
        !          1495: static void
        !          1496: chu_clear(
        !          1497:        struct peer *peer       /* peer structure pointer */
        !          1498:        )
        !          1499: {
        !          1500:        struct refclockproc *pp;
        !          1501:        struct chuunit *up;
        !          1502:        int     i, j;
        !          1503: 
        !          1504:        pp = peer->procptr;
        !          1505:        up = (struct chuunit *)pp->unitptr;
        !          1506: 
        !          1507:        /*
        !          1508:         * Clear stuff for the minute.
        !          1509:         */
        !          1510:        up->ndx = up->prevsec = 0;
        !          1511:        up->burstcnt = up->ntstamp = 0;
        !          1512:        up->status &= INSYNC | METRIC;
        !          1513:        for (i = 0; i < 20; i++) {
        !          1514:                for (j = 0; j < 16; j++)
        !          1515:                        up->decode[i][j] = 0;
        !          1516:        }
        !          1517: }
        !          1518: 
        !          1519: #ifdef ICOM
        !          1520: /*
        !          1521:  * chu_newchan - called once per minute to find the best channel;
        !          1522:  * returns zero on success, nonzero if ICOM error.
        !          1523:  */
        !          1524: static int
        !          1525: chu_newchan(
        !          1526:        struct peer *peer,
        !          1527:        double  met
        !          1528:        )
        !          1529: {
        !          1530:        struct chuunit *up;
        !          1531:        struct refclockproc *pp;
        !          1532:        struct xmtr *sp;
        !          1533:        int     rval;
        !          1534:        double  metric;
        !          1535:        int     i;
        !          1536: 
        !          1537:        pp = peer->procptr;
        !          1538:        up = (struct chuunit *)pp->unitptr;
        !          1539: 
        !          1540:        /*
        !          1541:         * The radio can be tuned to three channels: 0 (3330 kHz), 1
        !          1542:         * (7850 kHz) and 2 (14670 kHz). There are five one-minute
        !          1543:         * dwells in each cycle. During the first dwell the radio is
        !          1544:         * tuned to one of the three channels to measure the channel
        !          1545:         * metric. The channel is selected as the one least recently
        !          1546:         * measured. During the remaining four dwells the radio is tuned
        !          1547:         * to the channel with the highest channel metric. 
        !          1548:         */
        !          1549:        if (up->fd_icom <= 0)
        !          1550:                return (0);
        !          1551: 
        !          1552:        /*
        !          1553:         * Update the current channel metric and age of all channels.
        !          1554:         * Scan all channels for the highest metric.
        !          1555:         */
        !          1556:        sp = &up->xmtr[up->chan];
        !          1557:        sp->metric -= sp->integ[sp->iptr];
        !          1558:        sp->integ[sp->iptr] = met;
        !          1559:        sp->metric += sp->integ[sp->iptr];
        !          1560:        sp->probe = 0;
        !          1561:        sp->iptr = (sp->iptr + 1) % ISTAGE;
        !          1562:        metric = 0;
        !          1563:        for (i = 0; i < NCHAN; i++) {
        !          1564:                up->xmtr[i].probe++;
        !          1565:                if (up->xmtr[i].metric > metric) {
        !          1566:                        up->status |= METRIC;
        !          1567:                        metric = up->xmtr[i].metric;
        !          1568:                        up->chan = i;
        !          1569:                }
        !          1570:        }
        !          1571: 
        !          1572:        /*
        !          1573:         * Start the next dwell. If the first dwell or no stations have
        !          1574:         * been heard, continue round-robin scan.
        !          1575:         */
        !          1576:        up->dwell = (up->dwell + 1) % DWELL;
        !          1577:        if (up->dwell == 0 || metric == 0) {
        !          1578:                rval = 0;
        !          1579:                for (i = 0; i < NCHAN; i++) {
        !          1580:                        if (up->xmtr[i].probe > rval) {
        !          1581:                                rval = up->xmtr[i].probe;
        !          1582:                                up->chan = i;
        !          1583:                        }
        !          1584:                }
        !          1585:        }
        !          1586: 
        !          1587:        /* Retune the radio at each dwell in case somebody nudges the
        !          1588:         * tuning knob.
        !          1589:         */
        !          1590:        rval = icom_freq(up->fd_icom, peer->ttl & 0x7f, qsy[up->chan] +
        !          1591:            TUNE);
        !          1592:        snprintf(up->ident, sizeof(up->ident), "CHU%d", up->chan);
        !          1593:        memcpy(&pp->refid, up->ident, 4); 
        !          1594:        memcpy(&peer->refid, up->ident, 4);
        !          1595:        if (metric == 0 && up->status & METRIC) {
        !          1596:                up->status &= ~METRIC;
        !          1597:                refclock_report(peer, CEVNT_PROP);
        !          1598:        } 
        !          1599:        return (rval);
        !          1600: }
        !          1601: #endif /* ICOM */
        !          1602: 
        !          1603: 
        !          1604: /*
        !          1605:  * chu_dist - determine the distance of two octet arguments
        !          1606:  */
        !          1607: static int
        !          1608: chu_dist(
        !          1609:        int     x,              /* an octet of bits */
        !          1610:        int     y               /* another octet of bits */
        !          1611:        )
        !          1612: {
        !          1613:        int     val;            /* bit count */ 
        !          1614:        int     temp;
        !          1615:        int     i;
        !          1616: 
        !          1617:        /*
        !          1618:         * The distance is determined as the weight of the exclusive OR
        !          1619:         * of the two arguments. The weight is determined by the number
        !          1620:         * of one bits in the result. Each one bit increases the weight,
        !          1621:         * while each zero bit decreases it.
        !          1622:         */
        !          1623:        temp = x ^ y;
        !          1624:        val = 0;
        !          1625:        for (i = 0; i < 8; i++) {
        !          1626:                if ((temp & 0x1) == 0)
        !          1627:                        val++;
        !          1628:                else
        !          1629:                        val--;
        !          1630:                temp >>= 1;
        !          1631:        }
        !          1632:        return (val);
        !          1633: }
        !          1634: 
        !          1635: 
        !          1636: #ifdef HAVE_AUDIO
        !          1637: /*
        !          1638:  * chu_gain - adjust codec gain
        !          1639:  *
        !          1640:  * This routine is called at the end of each second. During the second
        !          1641:  * the number of signal clips above the MAXAMP threshold (6000). If
        !          1642:  * there are no clips, the gain is bumped up; if there are more than
        !          1643:  * MAXCLP clips (100), it is bumped down. The decoder is relatively
        !          1644:  * insensitive to amplitude, so this crudity works just peachy. The
        !          1645:  * routine also jiggles the input port and selectively mutes the
        !          1646:  */
        !          1647: static void
        !          1648: chu_gain(
        !          1649:        struct peer *peer       /* peer structure pointer */
        !          1650:        )
        !          1651: {
        !          1652:        struct refclockproc *pp;
        !          1653:        struct chuunit *up;
        !          1654: 
        !          1655:        pp = peer->procptr;
        !          1656:        up = (struct chuunit *)pp->unitptr;
        !          1657: 
        !          1658:        /*
        !          1659:         * Apparently, the codec uses only the high order bits of the
        !          1660:         * gain control field. Thus, it may take awhile for changes to
        !          1661:         * wiggle the hardware bits.
        !          1662:         */
        !          1663:        if (up->clipcnt == 0) {
        !          1664:                up->gain += 4;
        !          1665:                if (up->gain > MAXGAIN)
        !          1666:                        up->gain = MAXGAIN;
        !          1667:        } else if (up->clipcnt > MAXCLP) {
        !          1668:                up->gain -= 4;
        !          1669:                if (up->gain < 0)
        !          1670:                        up->gain = 0;
        !          1671:        }
        !          1672:        audio_gain(up->gain, up->mongain, up->port);
        !          1673:        up->clipcnt = 0;
        !          1674: }
        !          1675: #endif /* HAVE_AUDIO */
        !          1676: 
        !          1677: 
        !          1678: #else
        !          1679: int refclock_chu_bs;
        !          1680: #endif /* REFCLOCK */

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