+* codec (audio) and ICOM changes from Dave Mills.
+\f
(4.2.4) Released by Harlan Stenn <stenn@ntp.org>
* monopt.html fixes from Dave Mills.
* [Bug 452] Do not report kernel PLL/FLL flips.
#define LOOP_HUFFPUFF 9 /* set huff-n'-puff filter length */
#define LOOP_FREQ 10 /* set initial frequency */
#define LOOP_KERN_CLEAR 11 /* reset kernel pll parameters */
+#define LOOP_CODEC 12 /* set audio codec frequency */
/*
* Configuration items for the stats printer
#define CONF_CLOCK_ALLAN 5
#define CONF_CLOCK_HUFFPUFF 6
#define CONF_CLOCK_FREQ 7
+#define CONF_CLOCK_CODEC 8
/*
* "tos" modifier keywords
extern double clock_panic; /* max offset before panic (s) */
extern double clock_phi; /* dispersion rate (s/s) */
extern double clock_minstep; /* step timeout (s) */
+extern double clock_codec; /* codec frequency */
extern u_long pps_control; /* last pps sample time */
#ifdef KERNEL_PLL
extern int pll_status; /* status bits for kernel pll */
if (debug > 1)
printf("audio_gain: gain %d/%d\n", gain, l);
# endif
+#if 0 /* not a good idea to do this; connector wiring dependency */
/* figure out what channel(s) to use. just nuke right for now. */
r = 0 ; /* setting to zero nicely mutes the channel */
-
+#endif
l |= r << 8;
if ( cf_agc )
rval = ioctl(ctl_fd, agc, &l);
#include "l_stdlib.h"
/*
- * Scraps
+ * Packet routines
+ *
+ * These routines send a packet and receive the response. If an error
+ * (collision) occurs on transmit, the packet is resent. If an error
+ * occurs on receive (timeout), all input to the terminating FI is
+ * discarded and the packet is resent. If the maximum number of retries
+ * is not exceeded, the program returns the number of octets in the user
+ * buffer; otherwise, it returns zero.
+ *
+ * ICOM frame format
+ *
+ * Frames begin with a two-octet preamble PR-PR followyd by the
+ * transceiver address RE, controller address TX, control code CN, zero
+ * or more data octets DA (depending on command), and terminator FI.
+ * Since the bus is bidirectional, every octet output is echoed on
+ * input. Every valid frame sent is answered with a frame in the same
+ * format, but with the RE and TX fields interchanged. The CN field is
+ * set to NAK if an error has occurred. Otherwise, the data are returned
+ * in this and following DA octets. If no data are returned, the CN
+ * octet is set to ACK.
+ *
+ * +------+------+------+------+------+--//--+------+
+ * | PR | PR | RE | TX | CN | DA | FI |
+ * +------+------+------+------+------+--//--+------+
*/
-#define BMAX 50 /* max command length */
-#define DICOM /dev/icom/ /* ICOM port link */
-
/*
- * FSA definitions
+ * Scraps
*/
-#define S_IDLE 0 /* idle */
-#define S_HDR 1 /* header */
-#define S_TX 2 /* address */
-#define S_DATA 3 /* data */
-#define S_ERROR 4 /* error */
+#define DICOM /dev/icom/ /* ICOM port link */
/*
* Local function prototypes
*/
static void doublefreq P((double, u_char *, int));
-static int sndpkt P((int, int, u_char *, u_char *));
-static int sndoctet P((int, int));
-static int rcvoctet P((int));
-
-/*
- * Local variables
- */
-static int flags; /* trace flags */
-static int state; /* fsa state */
/*
double freq /* frequency (MHz) */
)
{
- u_char cmd[BMAX], rsp[BMAX];
+ u_char cmd[] = {PAD, PR, PR, 0, TX, V_SFREQ, 0, 0, 0, 0, FI,
+ FI};
int temp;
- cmd[0] = V_SFREQ;
+ cmd[3] = ident;
if (ident == IC735)
temp = 4;
else
temp = 5;
- doublefreq(freq * 1e6, &cmd[1], temp);
- temp = sndpkt(fd, ident, cmd, rsp);
- if (temp < 1 || rsp[0] != ACK)
- return (EIO);
+ doublefreq(freq * 1e6, &cmd[6], temp);
+ temp = write(fd, cmd, temp + 7);
return (0);
}
x[i] = FI;
}
-
-/*
- * Packet routines
- *
- * These routines send a packet and receive the response. If an error
- * (collision) occurs on transmit, the packet is resent. If an error
- * occurs on receive (timeout), all input to the terminating FI is
- * discarded and the packet is resent. If the maximum number of retries
- * is not exceeded, the program returns the number of octets in the user
- * buffer; otherwise, it returns zero.
- *
- * ICOM frame format
- *
- * Frames begin with a two-octet preamble PR-PR followyd by the
- * transceiver address RE, controller address TX, control code CN, zero
- * or more data octets DA (depending on command), and terminator FI.
- * Since the bus is bidirectional, every octet output is echoed on
- * input. Every valid frame sent is answered with a frame in the same
- * format, but with the RE and TX fields interchanged. The CN field is
- * set to NAK if an error has occurred. Otherwise, the data are returned
- * in this and following DA octets. If no data are returned, the CN
- * octet is set to ACK.
- *
- * +------+------+------+------+------+--//--+------+
- * | PR | PR | RE | TX | CN | DA | FI |
- * +------+------+------+------+------+--//--+------+
- */
/*
* icom_open() - open and initialize serial interface
*
int trace /* trace flags */ )
{
TTY ttyb;
- int fd;
+ int fd, flags;
flags = trace;
fd = open(device, O_RDWR, 0777);
tcgetattr(fd, &ttyb);
ttyb.c_iflag = 0; /* input modes */
ttyb.c_oflag = 0; /* output modes */
- ttyb.c_cflag = IBAUD|CS8|CREAD|CLOCAL; /* control modes */
+ ttyb.c_cflag = IBAUD|CS8|CLOCAL; /* control modes (no read) */
ttyb.c_lflag = 0; /* local modes */
ttyb.c_cc[VMIN] = 0; /* min chars */
ttyb.c_cc[VTIME] = 5; /* receive timeout */
return (fd);
}
-
-/*
- * sndpkt(r, x, y) - send packet and receive response
- *
- * This routine sends a command frame, which consists of all except the
- * preamble octets PR-PR. It then listens for the response frame and
- * returns the payload to the caller. The routine checks for correct
- * response header format; that is, the length of the response vector
- * returned to the caller must be at least 2 and the RE and TX octets
- * must be interchanged; otherwise, the operation is retried up to
- * the number of times specified in a global variable.
- *
- * The trace function, which is enabled by the P_TRACE bit of the global
- * flags variable, prints all characters received or echoed on the bus
- * preceded by a T (transmit) or R (receive). The P_ERMSG bit of the
- * flags variable enables printing of bus error messages.
- *
- * Note that the first octet sent is a PAD in order to allow time for
- * the radio to flush its receive buffer after sending the previous
- * response. Even with this precaution, some of the older radios
- * occasionally fail to receive a command and it has to be sent again.
- */
-static int
-sndpkt( /* returns octet count */
- int fd, /* file descriptor */
- int r, /* radio address */
- u_char *cmd, /* command vector */
- u_char *rsp /* response vector */
- )
-{
- int i, j, temp;
-
- (void)tcflush(fd, TCIOFLUSH);
- for (i = 0; i < RETRY; i++) {
- state = S_IDLE;
-
- /*
- * Transmit packet.
- */
- if (flags & P_TRACE)
- printf("icom T:");
- sndoctet(fd, PAD); /* send header */
- sndoctet(fd, PR);
- sndoctet(fd, PR);
- sndoctet(fd, r);
- sndoctet(fd, TX);
- for (j = 0; j < BMAX; j++) { /* send body */
- if (sndoctet(fd, cmd[j]) == FI)
- break;
- }
- while (rcvoctet(fd) != FI); /* purge echos */
- if (cmd[0] == V_FREQT || cmd[0] == V_MODET)
- return (0); /* shortcut for broadcast */
-
- /*
- * Receive packet. First, delete all characters
- * preceeding a PR, then discard all PRs. Check that the
- * RE and TX fields are correctly interchanged, then
- * copy the remaining data and FI to the user buffer.
- */
- if (flags & P_TRACE)
- printf("\nicom R:");
- j = 0;
- while ((temp = rcvoctet(fd)) != FI) {
- switch (state) {
-
- case S_IDLE:
- if (temp != PR)
- continue;
- state = S_HDR;
- break;
-
- case S_HDR:
- if (temp == PR) {
- continue;
- } else if (temp != TX) {
- if (flags & P_ERMSG)
- printf(
- "icom: TX error\n");
- state = S_ERROR;
- }
- state = S_TX;
- break;
-
- case S_TX:
- if (temp != r) {
- if (flags & P_ERMSG)
- printf(
- "icom: RE error\n");
- state = S_ERROR;
- }
- state = S_DATA;
- break;
-
- case S_DATA:
- if (j >= BMAX ) {
- if (flags & P_ERMSG)
- printf(
- "icom: buffer overrun\n");
- state = S_ERROR;
- j = 0;
- }
- rsp[j++] = (u_char)temp;
- break;
-
- case S_ERROR:
- break;
- }
- }
- if (flags & P_TRACE)
- printf("\n");
- if (j > 0) {
- rsp[j++] = FI;
- return (j);
- }
- }
- if (flags & P_ERMSG)
- printf("icom: retries exceeded\n");
- return (0);
-}
-
-
-/*
- * Interface routines
- *
- * These routines read and write octets on the bus. In case of receive
- * timeout a FI code is returned. In case of output collision (echo
- * does not match octet sent), the remainder of the collision frame
- * (including the trailing FI) is discarded.
- */
-/*
- * sndoctet(fd, x) - send octet
- */
-static int
-sndoctet( /* returns octet */
- int fd, /* file descriptor */
- int x /* octet */
- )
-{
- u_char y;
-
- y = (u_char)x;
- write(fd, &y, 1);
- return (x);
-}
-
-
-/*
- * rcvoctet(fd) - receive octet
- */
-static int
-rcvoctet( /* returns octet */
- int fd /* file descriptor */
- )
-{
- u_char y;
-
- if (read(fd, &y, 1) < 1)
- y = FI; /* come here if timeout */
- if (flags & P_TRACE && y != PAD)
- printf(" %02x", y);
- return (y);
-}
-
/* end program */
{ "allan", CONF_CLOCK_ALLAN },
{ "huffpuff", CONF_CLOCK_HUFFPUFF },
{ "freq", CONF_CLOCK_FREQ },
+ { "codec", CONF_CLOCK_CODEC },
{ "", CONFIG_UNKNOWN }
};
case CONF_CLOCK_FREQ:
loop_config(LOOP_FREQ, ftemp);
+
+ case CONF_CLOCK_CODEC:
+ loop_config(LOOP_CODEC, ftemp);
break;
}
}
double clock_jitter; /* offset jitter (s) */
double drift_comp; /* frequency (s/s) */
double clock_stability; /* frequency stability (wander) (s/s) */
+double clock_codec; /* audio codec frequency (sambles/s) */
u_long sys_clocktime; /* last system clock update */
u_long pps_control; /* last pps update */
u_long sys_tai; /* UTC offset from TAI (s) */
}
}
- /*
- * Switch to FLL mode if the poll interval is
- * greater than MAXDPOLL, so that the kernel
- * loop behaves as the daemon loop; viz.,
- * selects the FLL when necessary, etc. For
- * legacy only.
- */
- if (sys_poll > NTP_MAXDPOLL)
- ntv.status |= STA_FLL;
-
/*
* If the PPS signal is up and enabled, light
* the frequency bit. If the PPS driver is
drift_comp = freq / 1e6;
rstclock(S_FSET, 0, 0);
break;
+
+ case LOOP_CODEC: /* audio codec frequency */
+ clock_codec = freq;
+ break;
}
}
* per second, which results in a frequency change of
* 125 PPM.
*/
- up->phase += up->freq / SECOND;
+ up->phase += (up->freq + clock_codec) / SECOND;
up->phase += pp->fudgetime2 / 1e6;
if (up->phase >= .5) {
up->phase -= 1.;
#define TCKSIZ (TCKCYC * MS) /* tick filter size */
#define NCHAN 5 /* number of radio channels */
#define AUDIO_PHI 5e-6 /* dispersion growth factor */
+#define TBUF 128 /* max monitor line length */
/*
* Tunable parameters. The DGAIN parameter can be changed to fit the
* radio is not tunable, the DCHAN parameter can be changed to fit the
* expected best propagation frequency: higher if further from the
* transmitter, lower if nearer. The compromise value works for the US
- * right coast. The FREQ_OFFSET parameter can be used as a frequency
- * vernier to correct codec requency if greater than MAXFREQ.
+ * right coast.
*/
#define DCHAN 3 /* default radio channel (15 Mhz) */
#define DGAIN 5. /* subcarrier gain */
-#define FREQ_OFFSET 0. /* codec frequency correction (PPM) */
/*
* General purpose status bits (status)
* per second, which results in a frequency change of
* 125 PPM.
*/
- up->phase += up->freq / SECOND;
- up->phase += FREQ_OFFSET / 1e6;
+ up->phase += (up->freq + clock_codec) / SECOND;
if (up->phase >= .5) {
up->phase -= 1.;
} else if (up->phase < -.5) {
*/
if (!wwv_newchan(peer))
up->watch = 0;
-#ifdef ICOM
- if (up->fd_icom > 0)
- wwv_qsy(peer, up->dchan);
-#endif /* ICOM */
} else {
/*
wwv_epoch(peer);
} else if (up->sptr != NULL) {
sp = up->sptr;
- if (sp->metric >= TTHR && epoch == sp->mepoch % SECOND) {
+ if (sp->metric >= TTHR && epoch == sp->mepoch % SECOND)
+ {
up->rsec = (60 - sp->mepoch / SECOND) % 60;
up->rphase = 0;
up->status |= MSYNC;
{
struct refclockproc *pp;
struct wwvunit *up;
- char tbuf[80]; /* monitor buffer */
+ char tbuf[TBUF]; /* monitor buffer */
long epoch;
pp = peer->procptr;
sp->metric = wwv_metric(sp);
if (pp->sloppyclockflag & CLK_FLAG4) {
sprintf(tbuf,
- "wwv8 %04x %3d %s %04x %.0f %.0f/%.1f %4ld %4ld",
+ "wwv8 %04x %3d %s %04x %.0f %.0f/%.1f %ld %ld",
up->status, up->gain, sp->refid,
sp->reach & 0xffff, sp->metric, sp->synmax,
sp->synsnr, sp->pos % SECOND, epoch);
static int avgcnt; /* averaging interval counter */
static int avginc; /* averaging ratchet */
static int iniflg; /* initialization flag */
- char tbuf[80]; /* monitor buffer */
+ char tbuf[TBUF]; /* monitor buffer */
double dtemp;
int tmp2;
struct wwvunit *up;
struct chan *cp;
struct sync *sp, *rp;
- char tbuf[80]; /* monitor buffer */
+ char tbuf[TBUF]; /* monitor buffer */
int sw, arg, nsec;
pp = peer->procptr;
up->errcnt = up->digcnt = up->alarm = 0;
/*
- * We now begin the minute scan. If not yet synchronized
- * to a station, restart if the units digit has not been
- * found within the DATA timeout (15 m) or if not
- * synchronized within the SYNCH timeout (40 m). After
- * synchronizing to a station, restart if no stations
- * are found within the PANIC timeout (2 days).
+ * If synchronized to a station, restart if no stations
+ * have been heard within the PANIC timeout (2 days). If
+ * not and the minute digit has been found, restart if
+ * not synchronized withing the SYNCH timeout (40 m). If
+ * not, restart if the unit digit has not been found
+ * within the DATA timeout (15 m).
*/
if (up->status & INSYNC) {
if (up->watch > PANIC) {
wwv_newgame(peer);
return;
}
- } else {
- if (!(up->status & DSYNC)) {
- if (up->watch > DATA) {
- wwv_newgame(peer);
- return;
- }
- }
+ } else if (up->status & DSYNC) {
if (up->watch > SYNCH) {
wwv_newgame(peer);
return;
}
+ } else if (up->watch > DATA) {
+ wwv_newgame(peer);
+ return;
}
wwv_newchan(peer);
-#ifdef ICOM
- if (up->fd_icom > 0)
- wwv_qsy(peer, up->dchan);
-#endif /* ICOM */
break;
/*
/*
* Save the data channel gain, then QSY to the probe channel and
- * dim the seconds comb filters. The newchan() routine will
+ * dim the seconds comb filters. The www_newchan() routine will
* light them back up.
*/
case MSC21: /* 58 */
struct wwvunit *up;
double topmax, nxtmax; /* metrics */
double acc; /* accumulator */
- char tbuf[80]; /* monitor buffer */
+ char tbuf[TBUF]; /* monitor buffer */
int mldigit; /* max likelihood digit */
int i, j;
struct wwvunit *up;
struct sync *sp, *rp;
double rank, dtemp;
- int i, j;
+ int i, j, rval;
pp = peer->procptr;
up = (struct wwvunit *)pp->unitptr;
/*
* Search all five station pairs looking for the channel with
- * maximum metric. If no station is found above thresholds, tune
- * to WWV on 15 MHz, set the reference ID to NONE and wait for
- * hotter ions.
+ * maximum metric.
*/
sp = NULL;
j = 0;
/*
* If the strongest signal is less than the MTHR threshold (13),
- * we are beneath the waves, so squelch the second sync. If the
- * strongest signal is greater than the threshold, tune to that
- * frequency and transmitter QTH.
+ * we are beneath the waves, so squelch the second sync and
+ * advance to the next station. This makes sure all stations are
+ * scanned when the ions grow dim. If the strongest signal is
+ * greater than the threshold, tune to that frequency and
+ * transmitter QTH.
*/
if (rank < MTHR) {
up->dchan = (up->dchan + 1) % NCHAN;
up->status &= ~(SELV | SELH);
- return (FALSE);
+ rval = FALSE;
+ } else {
+ up->dchan = j;
+ up->status |= SELV | SELH;
+ up->sptr = sp;
+ memcpy(&pp->refid, sp->refid, 4);
+ peer->refid = pp->refid;
+ rval = TRUE;
}
- up->dchan = j;
- up->status |= SELV | SELH;
- up->sptr = sp;
- memcpy(&pp->refid, sp->refid, 4);
- peer->refid = pp->refid;
- return (TRUE);
+#ifdef ICOM
+ if (up->fd_icom > 0)
+ wwv_qsy(peer, up->dchan);
+#endif /* ICOM */
+ return (rval);
}
/*
* Initialize the station processes for audio gain, select bit,
* station/frequency identifier and reference identifier. Start
- * probing at the next channel after the data channel.
+ * probing at the strongest channel or the default channel if
+ * nothing heard.
*/
memset(up->mitig, 0, sizeof(up->mitig));
for (i = 0; i < NCHAN; i++) {
cp->wwvh.select = SELH;
sprintf(cp->wwvh.refid, "WH%.0f", floor(qsy[i]));
}
- up->dchan = (DCHAN + NCHAN - 1) % NCHAN;;
+ up->dchan = (DCHAN + NCHAN - 1) % NCHAN;
wwv_newchan(peer);
- up->achan = up->schan = up->dchan;
-#ifdef ICOM
- if (up->fd_icom > 0)
- wwv_qsy(peer, up->dchan);
-#endif /* ICOM */
+ up->schan = up->dchan;
}
/*