//========================================================================
/* initialization and termination */
+void
+reset_meters(void) {
+ if (uni.meter.flag) { // reset metering completely
+ int i, k;
+ for (i = 0; i < RXMETERPTS; i++)
+ for (k = 0; k < MAXRX; k++)
+ uni.meter.rx.val[k][i] = uni.meter.rx.avg[k][i] = -200.0;
+ for (i = 0; i < TXMETERPTS; i++)
+ uni.meter.tx.val[i] = uni.meter.tx.avg[i] = -200.0;
+ }
+}
+
+void
+reset_spectrum(void) {
+ if (uni.spec.flag)
+ reinit_spectrum(&uni.spec);
+}
+
+void
+reset_counters(void) {
+ int k;
+ for (k = 0; k < uni.multirx.nrx; k++) rx[k].tick = 0;
+ tx.tick = 0;
+}
+
+//========================================================================
+
/* global and general info,
not specifically attached to
tx, rx, or scheduling */
PRIVATE void
setup_all(void) {
-
+
uni.samplerate = loc.def.rate;
uni.buflen = loc.def.size;
uni.mode.sdr = loc.def.mode;
uni.mode.trx = RX;
-
- if (uni.meter.flag) {
- uni.meter.chan.path = loc.path.meter;
- uni.meter.chan.size = loc.mult.ring * sizeof(REAL);
- uni.meter.val = -200.0;
- uni.meter.chan.c = openChan(uni.meter.chan.path, uni.meter.chan.size);
- }
-
+
uni.wisdom.path = loc.path.wisdom;
uni.wisdom.bits = FFTW_OUT_OF_PLACE | FFTW_ESTIMATE;
{
fclose(f);
}
}
-
+
+ if (uni.meter.flag) {
+ uni.meter.rx.type = SIGNAL_STRENGTH;
+ uni.meter.tx.type = SIGNAL_STRENGTH;
+ reset_meters();
+ }
+
+ uni.spec.rxk = 0;
+ uni.spec.buflen = uni.buflen;
+ uni.spec.scale = SPEC_PWR;
+ uni.spec.type = SPEC_POST_FILT;
+ uni.spec.size = loc.def.spec;
+ uni.spec.planbits = uni.wisdom.bits;
+ init_spectrum(&uni.spec);
+
+ // set which receiver is listening to commands
uni.multirx.lis = 0;
uni.multirx.nrx = loc.def.nrx;
-
+
+ // set mixing of input from aux ports
uni.mix.rx.flag = uni.mix.tx.flag = FALSE;
uni.mix.rx.gain = uni.mix.tx.gain = 1.0;
-
+
uni.tick = 0;
}
PRIVATE void
setup_rx(int k) {
-
+
/* conditioning */
rx[k].iqfix = newCorrectIQ(0.0, 1.0);
rx[k].filt.coef = newFIR_Bandpass_COMPLEX(-4800.0,
}
uni.multirx.act[0] = TRUE;
uni.multirx.nac = 1;
-
+
setup_tx();
}
}
/* all */
- if (uni.meter.flag)
- closeChan(uni.meter.chan.c);
+ finish_spectrum(&uni.spec);
}
//////////////////////////////////////////////////////////////////////////
//========================================================================
/* all */
-/* tap off S-meter from some buf */
+// unfortunate duplication here, due to
+// multirx vs monotx
PRIVATE void
-do_meter(COMPLEX *vec, int len) {
- int i;
+do_rx_meter(int k, CXB buf, int tap) {
+ COMPLEX *vec = CXBbase(buf);
+ int i, len = CXBhave(buf);
+
+ uni.meter.rx.val[k][tap] = 0;
+
+ switch (uni.meter.rx.type) {
+ case AVG_SIGNAL_STRENGTH:
+ for (i = 0; i < len; i++)
+ uni.meter.rx.val[k][tap] += Csqrmag(vec[i]);
+ uni.meter.rx.val[k][tap] =
+ uni.meter.rx.avg[k][tap] =
+ 0.9 * uni.meter.rx.avg[k][tap] + log10(uni.meter.rx.val[k][tap] + 1e-20);
+ break;
+ case SIGNAL_STRENGTH:
+ for (i = 0; i < len; i++)
+ uni.meter.rx.val[k][tap] += Csqrmag(vec[i]);
+ uni.meter.rx.avg[k][tap] =
+ uni.meter.rx.val[k][tap] =
+ 10.0 * log10(uni.meter.rx.val[k][tap] + 1e-20);
+ break;
+ case ADC_REAL:
+ for(i = 0; i < len; i++)
+ uni.meter.rx.val[k][tap] = max(fabs(vec[i].re), uni.meter.rx.val[k][tap]);
+ uni.meter.rx.val[k][tap] = 20.0 * log10(uni.meter.rx.val[k][tap] + 1e-10);
+ break;
+ case ADC_IMAG:
+ for(i = 0; i < len; i++)
+ uni.meter.rx.val[k][tap] = max(fabs(vec[i].im), uni.meter.rx.val[k][tap]);
+ uni.meter.rx.val[k][tap] = 20.0 * log10(uni.meter.rx.val[k][tap] + 1e-10);
+ break;
+ default:
+ break;
+ }
+}
+
+PRIVATE void
+do_tx_meter(CXB buf, int tap) {
+ COMPLEX *vec = CXBbase(buf);
+ int i, len = CXBhave(buf);
- uni.meter.val = 0;
+ uni.meter.tx.val[tap] = 0;
- switch (uni.meter.type) {
+ switch (uni.meter.tx.type) {
case AVG_SIGNAL_STRENGTH:
for (i = 0; i < len; i++)
- uni.meter.val += Csqrmag(vec[i]);
- uni.meter.val =
- uni.meter.avgval = 0.9 * uni.meter.avgval + log10(uni.meter.val + 1e-20);
+ uni.meter.tx.val[tap] += Csqrmag(vec[i]);
+ uni.meter.tx.val[tap] =
+ uni.meter.tx.avg[tap] =
+ 0.9 * uni.meter.tx.avg[tap] + log10(uni.meter.tx.val[tap] + 1e-20);
break;
case SIGNAL_STRENGTH:
for (i = 0; i < len; i++)
- uni.meter.val += Csqrmag(vec[i]);
- uni.meter.avgval = uni.meter.val = 10.0 * log10(uni.meter.val + 1e-20);
+ uni.meter.tx.val[tap] += Csqrmag(vec[i]);
+ uni.meter.tx.avg[tap] =
+ uni.meter.tx.val[tap] =
+ 10.0 * log10(uni.meter.tx.val[tap] + 1e-20);
break;
case ADC_REAL:
for(i = 0; i < len; i++)
- uni.meter.val = max(fabs(vec[i].re), uni.meter.val);
- uni.meter.val = 20.0 * log10(uni.meter.val + 1e-10);
+ uni.meter.tx.val[tap] = max(fabs(vec[i].re), uni.meter.tx.val[tap]);
+ uni.meter.tx.val[tap] = 20.0 * log10(uni.meter.tx.val[tap] + 1e-10);
break;
case ADC_IMAG:
for(i = 0; i < len; i++)
- uni.meter.val = max(fabs(vec[i].im), uni.meter.val);
- uni.meter.val = 20.0 * log10(uni.meter.val + 1e-10);
+ uni.meter.tx.val[tap] = max(fabs(vec[i].im), uni.meter.tx.val[tap]);
+ uni.meter.tx.val[tap] = 20.0 * log10(uni.meter.tx.val[tap] + 1e-10);
break;
default:
break;
}
+}
- putChan_nowait(uni.meter.chan.c,
- (char *) &uni.meter.val,
- sizeof(uni.meter.val));
+PRIVATE BOOLEAN
+do_rx_spectrum(int k, CXB buf, int type) {
+ if (uni.spec.flag && k == uni.spec.rxk && type == uni.spec.type) {
+ memcpy((char *) &CXBdata(uni.spec.accum, uni.spec.fill),
+ (char *) CXBbase(buf),
+ CXBhave(buf));
+ uni.spec.fill = (uni.spec.fill + uni.spec.buflen) % uni.spec.size;
+ }
+}
+
+PRIVATE void
+do_tx_spectrum(CXB buf) {
+ memcpy((char *) &CXBdata(uni.spec.accum, uni.spec.fill),
+ (char *) CXBbase(buf),
+ CXBhave(buf));
+ uni.spec.fill = (uni.spec.fill + uni.spec.buflen) % uni.spec.size;
}
//========================================================================
do_rx_pre(int k) {
int i, n = min(CXBhave(rx[k].buf.i), uni.buflen);
- //
- // do shrinkage here?
- //
-
if (rx[k].scl.pre.flag)
for (i = 0; i < n; i++)
CXBdata(rx[k].buf.i, i) = Cscl(CXBdata(rx[k].buf.i, i),
if (rx[k].nb.flag) noiseblanker(rx[k].nb.gen);
if (rx[k].nb_sdrom.flag) SDROMnoiseblanker(rx[k].nb_sdrom.gen);
+ // metering for uncorrected values here
+
+ do_rx_meter(k, rx[k].buf.i, RXMETER_PRE_CONV);
+
correctIQ(rx[k].buf.i, rx[k].iqfix);
/* 2nd IF conversion happens here */
OSCCdata(rx[k].osc.gen, i));
}
- /* filtering, metering, squelch, & AGC */
-
- if (rx[k].mode != SPEC) {
-
+ /* filtering, metering, spectrum, squelch, & AGC */
+
+ if (rx[k].mode == SPEC)
+
+ do_rx_spectrum(k, rx[k].buf.i, SPEC_SEMI_RAW);
+
+ else {
+
+ do_rx_meter(k, rx[k].buf.i, RXMETER_PRE_FILT);
+ do_rx_spectrum(k, rx[k].buf.i, SPEC_PRE_FILT);
+
if (rx[k].tick == 0)
reset_OvSv(rx[k].filt.ovsv);
filter_OvSv(rx[k].filt.ovsv);
CXBhave(rx[k].buf.o) = CXBhave(rx[k].buf.i);
-
- if (uni.meter.flag)
- do_meter(CXBbase(rx[k].buf.o), uni.buflen);
-
+
+ do_rx_meter(k, rx[k].buf.o, RXMETER_POST_FILT);
+ do_rx_spectrum(k, rx[k].buf.o, SPEC_POST_FILT);
+
if (should_do_rx_squelch(k))
do_squelch(k);
-
+
else if (rx[k].agc.flag)
DigitalAgc(rx[k].agc.gen, rx[k].tick);
-
- } else if (uni.meter.flag)
- do_meter(CXBbase(rx[k].buf.o), uni.buflen);
+
+ }
}
PRIVATE void
do_rx_post(int k) {
int i, n = CXBhave(rx[k].buf.o);
-
+
if (!rx[k].squelch.set) {
no_squelch(k);
// spotting tone
CXBdata(rx[k].spot.gen->buf, i));
}
}
-
+
// final scaling
-
+
if (rx[k].scl.post.flag)
for (i = 0; i < n; i++)
CXBdata(rx[k].buf.o, i) = Cscl(CXBdata(rx[k].buf.o, i),
rx[k].scl.post.val);
-
+
// not binaural?
// position in stereo field
-
+
if (!rx[k].bin.flag)
for (i = 0; i < n; i++)
CXBdata(rx[k].buf.o, i) = Cscl(rx[k].azim, CXBreal(rx[k].buf.o, i));
PRIVATE void
do_tx_pre(void) {
- if (tx.scl.pre.flag) {
- int i, n = CXBhave(tx.buf.i);
+if (tx.scl.pre.flag) {
+int i, n = CXBhave(tx.buf.i);
for (i = 0; i < n; i++)
CXBdata(tx.buf.i, i) = Cmplx(CXBreal(tx.buf.i, i) * tx.scl.pre.val, 0.0);
}
CXBhave(tx.buf.o) = CXBhave(tx.buf.i);
if (tx.agc.flag) DigitalAgc(tx.agc.gen, tx.tick);
+
+ // meter modulated signal
+
+ do_tx_meter(tx.buf.o, TXMETER_POST_MOD);
+
if (tx.scl.post.flag) {
int i, n = CXBhave(tx.buf.o);
for (i = 0; i < n; i++)
CXBdata(tx.buf.o, i) = Cscl(CXBdata(tx.buf.o, i), tx.scl.post.val);
}
- if (uni.meter.flag) do_meter(CXBbase(tx.buf.o), uni.buflen);
+
+ if (uni.spec.flag)
+ do_tx_spectrum(tx.buf.o);
+
if (tx.osc.gen->Frequency != 0.0) {
int i;
ComplexOSC(tx.osc.gen);
float *auxl, float *auxr,
int n) {
int i, k;
-
+
switch (uni.mode.trx) {
-
+
case RX:
-
+
// make copies of the input for all receivers
for (k = 0; k < uni.multirx.nrx; k++)
if (uni.multirx.act[k]) {
do_rx(k), rx[k].tick++;
// mix
for (i = 0; i < n; i++)
- bufl[i] += CXBimag(rx[k].buf.o, i),
+ bufl[i] += CXBimag(rx[k].buf.o, i),
bufr[i] += CXBreal(rx[k].buf.o, i);
CXBhave(rx[k].buf.o) = n;
}
+ // late mixing of aux buffers
if (uni.mix.rx.flag)
for (i = 0; i < n; i++)
bufl[i] += auxl[i] * uni.mix.rx.gain,
case TX:
+ // early mixing of aux buffers
if (uni.mix.tx.flag)
for (i = 0; i < n; i++)
bufl[i] += auxl[i] * uni.mix.tx.gain,