From 803a0cf5a0e09fc8bb1ed093b62689ae19f92e61 Mon Sep 17 00:00:00 2001 From: dttsp Date: Fri, 3 Jun 2005 13:14:32 +0000 Subject: [PATCH] Major update --- jDttSP/Makefile | 16 ++- jDttSP/banal.h | 1 + jDttSP/command-vocabulary | 142 +++++++++++++-------------- jDttSP/common.h | 2 + jDttSP/dcblock.c | 199 ++++++++++++++++++++++++++++++++++++++ jDttSP/dcblock.h | 64 ++++++++++++ jDttSP/defs.h | 1 + jDttSP/digitalagc.c | 109 +++++++++++---------- jDttSP/digitalagc.h | 6 +- jDttSP/enums.m4 | 23 +++++ jDttSP/keyer.c | 110 --------------------- jDttSP/local.h | 2 +- jDttSP/main.c | 10 ++ jDttSP/meter.c | 1 - jDttSP/meter.h | 6 +- jDttSP/mkchan.c | 84 ---------------- jDttSP/ringb.c | 14 +++ jDttSP/ringb.h | 14 +++ jDttSP/sdr.c | 156 ++++++++++++++++++++---------- jDttSP/sdrexport.h | 39 ++++++-- jDttSP/spectrum.c | 32 +++--- jDttSP/spectrum.h | 3 +- jDttSP/update.c | 92 ++++++++++++------ jDttSP/wscompand.c | 108 +++++++++++++++++++++ jDttSP/wscompand.h | 60 ++++++++++++ 25 files changed, 868 insertions(+), 426 deletions(-) create mode 100644 jDttSP/dcblock.c create mode 100644 jDttSP/dcblock.h delete mode 100644 jDttSP/mkchan.c create mode 100644 jDttSP/wscompand.c create mode 100644 jDttSP/wscompand.h diff --git a/jDttSP/Makefile b/jDttSP/Makefile index 8130ea6..86b1699 100644 --- a/jDttSP/Makefile +++ b/jDttSP/Makefile @@ -1,5 +1,5 @@ -#CFLAGS = -g -O3 -I. -I/usr/local/include -CFLAGS = -g -I. -I/usr/local/include +CFLAGS = -g -O3 -I. -I/usr/local/include +#CFLAGS = -g -I. -I/usr/local/include LIBS = -L/usr/local/lib -ljack -lpthread -lgsl -lgslcblas -lfftw -lm #LIBS = -lefence -L/usr/local/lib -ljack -lpthread -lgsl -lgslcblas -lfftw -lm @@ -13,6 +13,7 @@ OBJ = am_demod.o\ correctIQ.o\ crc16.o\ cxops.o\ + dcblock.o\ digitalagc.o\ fastrig.o\ filter.o\ @@ -31,6 +32,7 @@ OBJ = am_demod.o\ spottone.o\ thunk.o\ window.o\ + wscompand.o\ update.o KOBJ = oscillator.o cwtones.o chan.o ringb.o banal.o bufvec.o splitfields.o cxops.o @@ -40,13 +42,14 @@ jsdr: main.o $(OBJ) all: jsdr ipc metermon specmon keyd keyb -keyd: keyd.o keyer.o $(KOBJ) - $(CC) -o keyd keyd.o keyer.o $(KOBJ) $(LIBS) +keyd: keyd.o keyer.o keyerio.o $(KOBJ) + $(CC) -o keyd keyd.o keyer.o keyerio.o $(KOBJ) $(LIBS) -keyb: keyb.o keyer.o $(KOBJ) +keyb: keyb.o keyer.o keyerio.o $(KOBJ) $(CC) -o keyb keyb.o keyer.o $(KOBJ) $(LIBS) + $(OBJ): sdrexport.h metermon: metermon.o @@ -78,3 +81,6 @@ staticlib: $(OBJ) # sharedlib: $(OBJ) # gcc -shared -Wl,-soname,$(sharedlib) -o $(sharedlib) $(OBJ) -lc +keybun: keybun.o keyer.o keyerio.o $(KOBJ) + $(CC) -o keybun keybun.o keyer.o $(KOBJ) $(LIBS) + diff --git a/jDttSP/banal.h b/jDttSP/banal.h index e6af09b..1235232 100644 --- a/jDttSP/banal.h +++ b/jDttSP/banal.h @@ -37,6 +37,7 @@ #define _banal_h #include +#include #include #ifndef min diff --git a/jDttSP/command-vocabulary b/jDttSP/command-vocabulary index 448f6d1..458c7cb 100644 --- a/jDttSP/command-vocabulary +++ b/jDttSP/command-vocabulary @@ -1,70 +1,72 @@ -[TRX] indicates optional arg (RX or TX), RX default -T|F indicates TRUE or FALSE - -If first char of command is '-', eg --setNR ON -command is not echoed to log output.x - -setFilter low-freq high-freq TRX -setMode mode [TRX] // mode = USB, LSB, CWL, CWU, etc. -setOsc freq [TRX] // freq in Hz (float) -setSampleRate rate // Hz (float) -setNR T|F // on/off, RX only -setANF T|F // on/off, RX only -setNB T|F // on/off, RX only -setBIN T|F // binaural mode, on/off, RX only -setNBvals thresh // float, RX only -setfixedAGC gain [TRX] // float -setRXAGC T|F // on/off -setRXAGCCompression lev // float -setRXAGCHang dur // float -setRXAGCLimit lim // float -setTXAGC T|F // on/off -setTXAGCCompression lev // float -setTXAGCHang dur // float -setTXAGCLimit lim // float -setTXSpeechCompression T|F // on/off -setTXSpeechCompressionGain gain // float -setRXEQ // f0 dB0 f1 dB1 f2 dB2 ... fN -setTXEQ // f0 dB0 f1 dB1 f2 dB2 ... fN - // typical: - // 0 dB1 75 dB2 150 dB3 300 dB4 600 dB5 1200 dB6 2000 dB7 2800 dB8 3600 - // approximates W2IHY bandcenters -setRXAGC mode // mode = agcOFF, agcSLOW, etc. -setANFvals taps delay gain leak // int, int, float, float, RX only -setNRvals taps delay gain leak // int, int, float, float, RX only -setcorrectIQ phase gain // int, int -setcorrectIQphase phase // int -setcorrectIQgain gain // int -setSquelch lev // float, gain, RX only; default -30dB -setSquelchSt T|F // on/off, RX only -setTRX trx // trx = RX|TX -setRunState state // RUN_MUTE, RUN_PASS, RUN_PLAY -setRXPreScl T|F // on/off -setRXPreSclVal valQ // dB -setTXPreScl T|F // on/off -setTXPreSclVal valQ // dB -setRXPostScl T|F // on/off -setRXPostSclVal valQ // dB -setTXPostScl T|F // on/off -setTXPostSclVal valQ // dB -setSWCH trx [zap] // trx = RX|TX, int (always zaps at least 1) -setSpotToneVals gain freq rise fall // dB, Hz, msec, msec [-12, 700, 5, 5] -setSpotTone T|F // turn on, off -setFinished // shutdown gracefully -setRXListen rx // tell receiver rx to listen to commands to follow -setRXOn [rx] // turn currently listening receiver on, or receiver rx -setRXOff [rx] // turn currently listening receiver off, or receiver rx -setRXPan pos // set azimuth for currently listening receiver to pos (0...1) -setAuxMixGain [gain [trx]] // set mixing level for aux inputs -setAuxMixSt [flag [trx]] // set aux input mix on/off - -setMeterType type [trx] // set meter type for trx, default rx - // types: SIG, AVG, REAL, IMAG; default SIG -setSpectrumType [type [scale [rx]]] // set spectrum type, scale, which rx - // types: SEMI_RAW, PRE_FILT, POST_FILT (deflt POST) - // scale: PWR, MAG (dflt PWR) - // which rx dflt 0 -reqMeter [label] // sends entire rx or tx meter block to METERPATH -reqSpectrum [label] // sends current spec snapshot to SPECPATH - +// [TRX] indicates optional arg (RX or TX), RX default +// T|F indicates TRUE or FALSE +// +// If first char of command is '-', eg +// -setNR ON +// command is not echoed to log output. +// +// setFilter low-freq high-freq TRX +// setMode mode [TRX] // mode = USB, LSB, CWL, CWU, etc. +// setOsc freq [TRX] // freq in Hz (float) +// setSampleRate rate // Hz (float) +// setNR T|F // on/off, RX only +// setANF T|F // on/off, RX only +// setNB T|F // on/off, RX only +// setBIN T|F // binaural mode, on/off, RX only +// setNBvals thresh // float, RX only +// setfixedAGC gain [TRX] // float +// setRXAGC T|F // on/off +// setRXAGCCompression lev // float +// setRXAGCHang dur // float +// setRXAGCLimit lim // float +// setTXAGC T|F // on/off +// setTXAGCCompression lev // float +// setTXAGCHang dur // float +// setTXAGCLimit lim // float +// setTXSpeechCompression T|F // on/off +// setTXSpeechCompressionGain gain // float +// setRXEQ // f0 dB0 f1 dB1 f2 dB2 ... fN +// setTXEQ // f0 dB0 f1 dB1 f2 dB2 ... fN +// // typical: +// // 0 dB1 75 dB2 150 dB3 300 dB4 600 dB5 1200 dB6 2000 dB7 2800 dB8 3600 +// // approximates W2IHY bandcenters +// setRXAGC mode // mode = agcOFF, agcSLOW, etc. +// setANFvals taps delay gain leak // int, int, float, float, RX only +// setNRvals taps delay gain leak // int, int, float, float, RX only +// setcorrectIQ phase gain // int, int +// setcorrectIQphase phase // int +// setcorrectIQgain gain // int +// setSquelch lev // float, gain, RX only; default -30dB +// setSquelchSt T|F // on/off, RX only +// setTRX trx // trx = RX|TX +// setRunState state // RUN_MUTE, RUN_PASS, RUN_PLAY +// setRXPreScl T|F // on/off +// setRXPreSclVal valQ // dB +// setTXPreScl T|F // on/off +// setTXPreSclVal valQ // dB +// setRXPostScl T|F // on/off +// setRXPostSclVal valQ // dB +// setTXPostScl T|F // on/off +// setTXPostSclVal valQ // dB +// setSWCH trx [zap] // trx = RX|TX, int (always zaps at least 1) +// setSpotToneVals gain freq rise fall // dB, Hz, msec, msec [-12, 700, 5, 5] +// setSpotTone T|F // turn on, off +// setFinished // shutdown gracefully +// setRXListen rx // tell receiver rx to listen to commands to follow +// setRXOn [rx] // turn currently listening receiver on, or receiver rx +// setRXOff [rx] // turn currently listening receiver off, or receiver rx +// setRXPan pos // set azimuth for currently listening receiver to pos (0...1) +// setAuxMixGain [gain [trx]] // set mixing level for aux inputs +// setAuxMixSt [flag [trx]] // set aux input mix on/off +// setCompandSt [T|F [trx]] // *** NB *** trx dflt TX!!! +// setCompand fac [trx] // probably > 0 for RX, < 0 for TX +// setMeterType type [trx] // set meter type for trx, default rx +// // types: SIG, AVG, REAL, IMAG; default SIG +// setSpectrumType [type [scale [rx]]] // set spectrum type, scale, which rx +// // types: SEMI_RAW, PRE_FILT, POST_FILT (dflt POST) +// // scale: PWR, MAG (dflt PWR) +// // which rx dflt 0 +// ========================================================================= +// reqMeter [label] // sends entire rx or tx meter block to METERPATH +// reqSpectrum [label] // sends current spec snapshot to SPECPATH +// diff --git a/jDttSP/common.h b/jDttSP/common.h index e31c20c..a7fadfe 100644 --- a/jDttSP/common.h +++ b/jDttSP/common.h @@ -55,7 +55,9 @@ Bridgewater, NJ 08807 #include #include #include +#include #include +#include #include #include #include diff --git a/jDttSP/dcblock.c b/jDttSP/dcblock.c new file mode 100644 index 0000000..bc0cab4 --- /dev/null +++ b/jDttSP/dcblock.c @@ -0,0 +1,199 @@ +// dcblock.h +/* +This file is part of a program that implements a Software-Defined Radio. + +Copyright (C) 2004-2005 by Frank Brickle, AB2KT and Bob McGwier, N4HY + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +The authors can be reached by email at + +ab2kt@arrl.net +or +rwmcgwier@comcast.net + +or by paper mail at + +The DTTS Microwave Society +6 Kathleen Place +Bridgewater, NJ 08807 +*/ + +#include + +// NB may have to ramify this a little +// for other sampling rates; maybe not + +PRIVATE REAL +butterworth_hipass_100_2(REAL xin, REAL *xv, REAL *yv), +butterworth_hipass_100_4(REAL xin, REAL *xv, REAL *yv), +butterworth_hipass_100_6(REAL xin, REAL *xv, REAL *yv), +butterworth_hipass_100_8(REAL xin, REAL *xv, REAL *yv); + +void +DCBlock(DCBlocker dcb) { + int i; + REAL x, y; + + switch (dcb->lev) { + + case DCB_LOW: + for (i = 0; i < CXBsize(dcb->buf); i++) { + x = CXBreal(dcb->buf, i); + y = butterworth_hipass_100_2(x, dcb->old.inp, dcb->old.out); + CXBdata(dcb->buf, i) = Cmplx(y, 0.0); + } + break; + + case DCB_MED: + for (i = 0; i < CXBsize(dcb->buf); i++) { + x = CXBreal(dcb->buf, i); + y = butterworth_hipass_100_4(x, dcb->old.inp, dcb->old.out); + CXBdata(dcb->buf, i) = Cmplx(y, 0.0); + } + break; + + case DCB_HIGH: + for (i = 0; i < CXBsize(dcb->buf); i++) { + x = CXBreal(dcb->buf, i); + y = butterworth_hipass_100_6(x, dcb->old.inp, dcb->old.out); + CXBdata(dcb->buf, i) = Cmplx(y, 0.0); + } + break; + + case DCB_SUPER: + for (i = 0; i < CXBsize(dcb->buf); i++) { + x = CXBreal(dcb->buf, i); + y = butterworth_hipass_100_8(x, dcb->old.inp, dcb->old.out); + CXBdata(dcb->buf, i) = Cmplx(y, 0.0); + } + break; + + default: + break; + } +} + +void +resetDCBlocker(DCBlocker dcb, int lev) { + memset((char *) dcb->old.inp, 0, BLKMEM * sizeof(REAL)); + memset((char *) dcb->old.out, 0, BLKMEM * sizeof(REAL)); + dcb->lev = lev; +} + +DCBlocker +newDCBlocker(int lev, CXB buf) { + DCBlocker dcb = + (DCBlocker) safealloc(1, sizeof(DCBlockerInfo), "DCBlocker"); + dcb->buf = newCXB(CXBsize(buf), CXBbase(buf), "DCBlocker"); + dcb->lev = lev; + return dcb; +} + +void +delDCBlocker(DCBlocker dcb) { + if (dcb) { + delCXB(dcb->buf); + safefree((char *) dcb); + } +} + +// f == 0.002083 == 100 Hz at 48k + +PRIVATE REAL +butterworth_hipass_100_2(REAL xin, REAL *xv, REAL *yv) { + int i; + + for (i = 1; i < 2; i++) + xv[i - 1] = xv[i], yv[i - 1] = yv[i]; + + xv[2] = xin / 1.009297482; + + yv[2] = (xv[0] + xv[2]) + + -2.0 * xv[1] + + -0.9816611902 * yv[0] + + 1.9814914708 * yv[1]; + + return yv[2]; +} + +PRIVATE REAL +butterworth_hipass_100_4(REAL xin, REAL *xv, REAL *yv) { + int i; + + for (i = 1; i < 4; i++) + xv[i - 1] = xv[i], yv[i - 1] = yv[i]; + + xv[4] = xin / 1.017247322; + + yv[4] = (xv[0] + xv[4]) + + -4.0 * (xv[1] + xv[3]) + + 6.0 * xv[2] + + -0.9663776767 * yv[0] + + 3.8985609655 * yv[1] + + -5.8979831706 * yv[2] + + 3.9657998529 * yv[3]; + + return yv[4]; +} + +PRIVATE REAL +butterworth_hipass_100_6(REAL xin, REAL *xv, REAL *yv) { + int i; + + for (i = 1; i < 6; i++) + xv[i - 1] = xv[i], yv[i - 1] = yv[i]; + + xv[6] = xin / 1.025606415; + + yv[6] = (xv[0] + xv[6]) + + -6.0 * (xv[1] + xv[5]) + + 15.0 * (xv[2] + xv[4]) + + -20.0 * xv[3] + + -0.9506891622 * yv[0] + + 5.7522090378 * yv[1] + + -14.5019247580 * yv[2] + + 19.4994114580 * yv[3] + + -14.7484389800 * yv[4] + + 5.9494324049 * yv[5]; + + return yv[6]; +} + +PRIVATE REAL +butterworth_hipass_100_8(REAL xin, REAL *xv, REAL *yv) { + int i; + + for (i = 1; i < 8; i++) + xv[i - 1] = xv[i], yv[i - 1] = yv[i]; + + xv[8] = xin / 1.034112352; + + yv[8] = (xv[0] + xv[8]) + + -8.0 * (xv[1] + xv[7]) + + 28.0 * (xv[2] + xv[6]) + + -56.0 * (xv[3] + xv[5]) + + 70.0 * xv[4] + + -0.9351139781 * yv[0] + + 7.5436450525 * yv[1] + + -26.6244301320 * yv[2] + + 53.6964633920 * yv[3] + + -67.6854640540 * yv[4] + + 54.6046308830 * yv[5] + + -27.5326449810 * yv[6] + + 7.9329138172 * yv[7]; + + return yv[8]; +} diff --git a/jDttSP/dcblock.h b/jDttSP/dcblock.h new file mode 100644 index 0000000..1fa3e4a --- /dev/null +++ b/jDttSP/dcblock.h @@ -0,0 +1,64 @@ +// dcblock.h +/* +This file is part of a program that implements a Software-Defined Radio. + +Copyright (C) 2004-2005 by Frank Brickle, AB2KT and Bob McGwier, N4HY + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +The authors can be reached by email at + +ab2kt@arrl.net +or +rwmcgwier@comcast.net + +or by paper mail at + +The DTTS Microwave Society +6 Kathleen Place +Bridgewater, NJ 08807 +*/ + +#ifndef _dcblock_h +#define _dcblock_h + +#include +#include +#include +#include +#include +#include +#include + +#define BLKMEM (9) +#define DCB_LOW (0) +#define DCB_MED (1) +#define DCB_HIGH (2) +#define DCB_SUPER (3) + +typedef struct _dcblocker { + struct { + REAL inp[BLKMEM], out[BLKMEM]; + } old; + int lev; + CXB buf; +} DCBlockerInfo, *DCBlocker; + +extern void DCBlock(DCBlocker dcb); +extern void resetDCBlocker(DCBlocker dcb, int lev); +extern DCBlocker newDCBlocker(int lev, CXB buf); +extern void delDCBlocker(DCBlocker dcb); + +#endif diff --git a/jDttSP/defs.h b/jDttSP/defs.h index b75f456..283337e 100644 --- a/jDttSP/defs.h +++ b/jDttSP/defs.h @@ -41,6 +41,7 @@ Bridgewater, NJ 08807 #define DEFSIZE (2048) #define DEFMODE (SAM) #define DEFSPEC (4096) +#define DEFCOMP (4096) #define MAXRX (4) diff --git a/jDttSP/digitalagc.c b/jDttSP/digitalagc.c index 352ebb2..c9fc7e5 100644 --- a/jDttSP/digitalagc.c +++ b/jDttSP/digitalagc.c @@ -36,6 +36,59 @@ Bridgewater, NJ 08807 #include +void +DigitalAgc(DIGITALAGC a, int tick) { + + if (a->mode == agcOFF) { + int i; + for (i = 0; i < CXBsize(a->buff); i++) + CXBdata(a->buff, i) = Cscl(CXBdata(a->buff, i), a->gain.fix); + + } else { + int i, k, hang; + REAL peak = 0.0; + + hang = tick < a->over ? a->rcov : a->hang; + k = a->indx; + + for (i = 0; i < CXBsize(a->buff); i++) + peak = max(peak, Cmag(CXBdata(a->buff, i))); + + if (peak != 0) { + a->hist[a->indx] = a->gain.lim / peak; + for (i = 1, a->gain.now = a->hist[0]; i < hang; i++) + a->gain.now = min(a->hist[i], a->gain.now); + } + a->gain.raw = a->gain.now; + a->gain.now = min(a->gain.now, a->gain.top); + + for (i = 0, k = (a->sndx + a->ramp) % a->mask; + i < CXBsize(a->buff); + i++, k = (k + 1) % a->mask) + a->circ[k] = CXBdata(a->buff, i); + + if (a->gain.now != a->gain.old) { + REAL step = (a->gain.now - a->gain.old) / a->ramp; + for (i = 0, k = a->sndx; + i < a->ramp; + i++, k = (k + 1) % a->mask) + CXBdata(a->buff, i) = Cscl(a->circ[k], a->gain.old + i * step); + for (; i < CXBsize(a->buff); i++, k = (k + 1) % a->mask) + CXBdata(a->buff, i) = Cscl(a->circ[k], a->gain.now); + a->gain.old = a->gain.now; + + } else { + for (i = 0, k = a->sndx; + i < CXBsize(a->buff); + i++, k = (k + 1) % a->mask) + CXBdata(a->buff, i) = Cscl(a->circ[k], a->gain.now); + } + + a->sndx = (a->sndx + CXBsize(a->buff)) % a->mask; + a->indx = ((a->indx + 1) % hang); + } +} + /* * Mode is gross agc mode: off, slow, med, fast; just info * Hang is basic hang time @@ -48,22 +101,17 @@ Bridgewater, NJ 08807 DIGITALAGC newDigitalAgc(int Mode, int Hang, - int Size, + int Ramp, int Over, int Rcov, - int Ramp, int BufSize, - REAL MaxGain, - REAL Limit, - REAL CurGain, - COMPLEX *Vec) { + REAL MaxGain, REAL Limit, REAL CurGain, COMPLEX * Vec) { DIGITALAGC a = (DIGITALAGC) safealloc(1, sizeof(digital_agc_state), "new digital agc state"); assert((Ramp >= 2) && (Ramp < BufSize)); a->mode = Mode; a->hang = Hang; - a->size = Size; a->over = Over; a->rcov = Rcov; a->ramp = Ramp; @@ -71,9 +119,12 @@ newDigitalAgc(int Mode, a->gain.lim = Limit; a->gain.old = a->gain.now = CurGain; a->buff = newCXB(BufSize, Vec, "agc buffer"); + a->mask = 2 * CXBsize(a->buff); + a->circ = newvec_COMPLEX(2 * BufSize, "circular agc buffer"); memset((void *) a->hist, 0, sizeof(a->hist)); a->indx = 0; - a->gain.fix = 1000.0; + a->sndx = a->mask - Ramp; + a->gain.fix = 10.0; return a; } @@ -81,47 +132,7 @@ void delDigitalAgc(DIGITALAGC a) { if (a) { delCXB(a->buff); + delvec_COMPLEX(a->circ); safefree((void *) a); } } - -void -DigitalAgc(DIGITALAGC a, int tick) { - - if (a->mode == agcOFF) { - int i; - for (i = 0; i < CXBsize(a->buff); i++) - CXBdata(a->buff, i) = Cscl(CXBdata(a->buff, i), a->gain.fix); - - } else { - int i, - k = a->indx, - hang = tick < a->over ? a->rcov : a->hang; - REAL peak = 0.0; - - for (i = 0; i < CXBsize(a->buff); i++) - peak = max(peak, Cmag(CXBdata(a->buff, i))); - - if (peak != 0) { - a->size = hang; - a->hist[k] = a->gain.lim / peak; - for (i = 1, a->gain.now = a->hist[0]; i < hang; i++) - a->gain.now = max(a->hist[i], a->gain.now); - } - a->gain.now = min(a->gain.now, a->gain.top); - - if (a->gain.now != a->gain.old) { - REAL step = (a->gain.now - a->gain.old) / (a->ramp - 1); - for (i = 0; i < a->ramp; i++) - CXBdata(a->buff, i) = Cscl(CXBdata(a->buff, i), a->gain.old + i * step); - for (; i < CXBsize(a->buff); i++) - CXBdata(a->buff, i) = Cscl(CXBdata(a->buff, i), a->gain.now); - a->gain.old = a->gain.now; - - } else - for (i = 0; i < CXBsize(a->buff); i++) - CXBdata(a->buff, i) = Cscl(CXBdata(a->buff, i), a->gain.now); - - a->indx = ++k % a->size; - } -} diff --git a/jDttSP/digitalagc.h b/jDttSP/digitalagc.h index ae886a7..5a6fea1 100644 --- a/jDttSP/digitalagc.h +++ b/jDttSP/digitalagc.h @@ -46,12 +46,13 @@ typedef enum _agcmode { agcOFF, agcLONG, agcSLOW, agcMED, agcFAST } AGCMODE; typedef struct _digitalagc { AGCMODE mode; - int hang, indx, over, ramp, rcov, size; + int hang, indx, over, ramp, rcov, mask, sndx; struct { - REAL fix, lim, now, old, top; + REAL fix, lim, now, old, raw, top; } gain; REAL hist[AGCHIST]; CXB buff; + COMPLEX *circ; } digital_agc_state, *DIGITALAGC; extern void delDigitalAgc(DIGITALAGC agc); @@ -59,7 +60,6 @@ extern void delDigitalAgc(DIGITALAGC agc); extern DIGITALAGC newDigitalAgc(int Mode, int Hang, - int Size, int Ramp, int Over, int Rcov, diff --git a/jDttSP/enums.m4 b/jDttSP/enums.m4 index f9669f7..35133e7 100644 --- a/jDttSP/enums.m4 +++ b/jDttSP/enums.m4 @@ -62,3 +62,26 @@ define(RUN_MUTE,0)dnl define(RUN_PASS,1)dnl define(RUN_PLAY,2)dnl define(RUN_SWCH,3)dnl +dnl Metering +define(SIG,0)dnl +define(AVG,1)dnl +define(REAL,2)dnl +define(IMAG,3)dnl +define(GAIN,4)dnl +define(ALC,5)dnl +define(PWR,6)dnl +define(PKPWR,7)dnl +dnl Spectrum +define(SEMI_RAW,0)dnl +define(PRE_CONV,0)dnl +define(PRE_FILT,1)dnl +define(POST_FILT,2)dnl +define(POST_AGC,3)dnl +define(POST_MOD,0)dnl +define(MAG,0)dnl +define(PWR,1)dnl +dnl +define(DCB_LOW,0)dnl +define(DCB_MED,1)dnl +define(DCB_HIGH,2)dnl +define(DCB_SUPER,3)dnl \ No newline at end of file diff --git a/jDttSP/keyer.c b/jDttSP/keyer.c index 581e51e..031b5f0 100644 --- a/jDttSP/keyer.c +++ b/jDttSP/keyer.c @@ -201,116 +201,6 @@ klogic(KeyerLogic kl, return kl->timeout.beep > 0 && kl->timeout.dlay <= 0; } -//======================================================================== - -/* Read a straight key connected to a serial port, do debouncing, then - return the key state */ - -BOOLEAN -read_straight_key_serial(KeyerState ks, int fd) { - int i, j, serstatus; - static BOOLEAN keystate = 0; - static int debounce_buf_i = 0, - debounce_buf[DEBOUNCE_BUF_MAX_SIZE]; - - //*************************************************** - // replace this with parallel port logic if necessary - //*************************************************** - // - /* Read the key state */ - if (ioctl(fd, TIOCMGET, &serstatus) != -1) { - debounce_buf[debounce_buf_i] = - (serstatus & (TIOCM_DSR | TIOCM_CTS)) ? - DSR_LINE_CLOSED_KEY : !DSR_LINE_CLOSED_KEY; - - debounce_buf_i++; - } - // - //*************************************************** - // back to business as usual - //*************************************************** - - /* If the debounce buffer is full, determine the state of the key */ - if (debounce_buf_i >= ks->debounce) { - debounce_buf_i = 0; - - j = 0; - for (i = 0; i < ks->debounce; i++) - if (debounce_buf[i]) - j++; - keystate = (j > ks->debounce / 2) ? 1 : 0; - } - - return keystate; -} - -//------------------------------------------------------------------------ - -/* Read an iambic key connected to a serial port, do debouncing, emulate a - straight key, then return the emulated key state */ - -BOOLEAN -read_iambic_key_serial(KeyerState ks, int fd, KeyerLogic kl, double ticklen) { - int i, j, serstatus; - static BOOLEAN dah_debounce_buf[DEBOUNCE_BUF_MAX_SIZE], - dit_debounce_buf[DEBOUNCE_BUF_MAX_SIZE]; - static int dah = 0, debounce_buf_i = 0, dit = 0; - - //*************************************************** - // replace this with parallel port logic if necessary - //*************************************************** - // - /* Read the key states */ - if (ioctl(fd, TIOCMGET, &serstatus) != -1) { - if (ks->flag.revpdl) { - dah_debounce_buf[debounce_buf_i] = - (serstatus & TIOCM_DSR) ? DSR_LINE_CLOSED_KEY : !DSR_LINE_CLOSED_KEY; - dit_debounce_buf[debounce_buf_i] = - (serstatus & TIOCM_CTS) ? CTS_LINE_CLOSED_KEY : !CTS_LINE_CLOSED_KEY; - } else { - dit_debounce_buf[debounce_buf_i] = - (serstatus & TIOCM_DSR) ? DSR_LINE_CLOSED_KEY : !DSR_LINE_CLOSED_KEY; - dah_debounce_buf[debounce_buf_i] = - (serstatus & TIOCM_CTS) ? CTS_LINE_CLOSED_KEY : !CTS_LINE_CLOSED_KEY; - } - - debounce_buf_i++; - } - // - //*************************************************** - // back to business as usual - //*************************************************** - - /* If the debounce buffer is full, determine the state of the keys */ - if (debounce_buf_i >= ks->debounce) { - debounce_buf_i = 0; - - j = 0; - for (i = 0; i < ks->debounce; i++) - if (dah_debounce_buf[i]) j++; - dah = (j > ks->debounce / 2) ? 1 : 0; - - j = 0; - for (i = 0; i < ks->debounce; i++) - if (dit_debounce_buf[i]) j++; - dit = (j > ks->debounce / 2) ? 1 : 0; - } - - return klogic(kl, - dit, - dah, - ks->wpm, - ks->mode, - ks->flag.mdlmdB, - ks->flag.memory.dit, - ks->flag.memory.dah, - ks->flag.autospace.khar, - ks->flag.autospace.word, - ks->weight, - ticklen); -} - -//======================================================================== KeyerState newKeyerState(void) { diff --git a/jDttSP/local.h b/jDttSP/local.h index 724a8f6..f2f4d2a 100644 --- a/jDttSP/local.h +++ b/jDttSP/local.h @@ -61,7 +61,7 @@ extern struct _loc { } path; struct { REAL rate; - int size, nrx, spec; + int size, nrx, spec, comp; SDRMODE mode; } def; struct { int ring; } mult; diff --git a/jDttSP/main.c b/jDttSP/main.c index 7575afb..b288112 100644 --- a/jDttSP/main.c +++ b/jDttSP/main.c @@ -48,6 +48,7 @@ extern void reset_counters(void); extern void process_samples(float *, float *, float *, float *, int); extern void setup_workspace(void); extern void destroy_workspace(void); +extern void clear_jack_ringbuffer(jack_ringbuffer_t *rb, int nbytes); //======================================================================== @@ -71,6 +72,12 @@ spectrum_thread(void) { exit(1); } + if (fwrite((char *) uni.spec.oscope, sizeof(float), uni.spec.size, top.meas.spec.fp) + != uni.spec.size) { + fprintf(stderr, "error writing oscope\n"); + exit(1); + } + fflush(top.meas.spec.fp); } @@ -246,6 +253,8 @@ run_swch(void) { jack_ringbuffer_reset(top.jack.ring.o.l); jack_ringbuffer_reset(top.jack.ring.o.r); + clear_jack_ringbuffer(top.jack.ring.o.l, top.hold.size.bytes); + clear_jack_ringbuffer(top.jack.ring.o.r, top.hold.size.bytes); reset_meters(); reset_spectrum(); @@ -576,6 +585,7 @@ setup_defaults(void) { loc.def.size = DEFSIZE; loc.def.mode = DEFMODE; loc.def.spec = DEFSPEC; + loc.def.comp = DEFCOMP; loc.def.nrx = MAXRX; loc.mult.ring = RINGMULT; diff --git a/jDttSP/meter.c b/jDttSP/meter.c index d27e80d..ee15fd1 100644 --- a/jDttSP/meter.c +++ b/jDttSP/meter.c @@ -44,4 +44,3 @@ snap_meter(MeterBlock *mb, int label) { TXMETERPTS * sizeof(REAL)); mb->label = label; } - diff --git a/jDttSP/meter.h b/jDttSP/meter.h index 3deb654..f02cdb8 100644 --- a/jDttSP/meter.h +++ b/jDttSP/meter.h @@ -62,7 +62,11 @@ typedef enum { SIGNAL_STRENGTH, AVG_SIGNAL_STRENGTH, ADC_REAL, - ADC_IMAG + ADC_IMAG, + AGC_GAIN, + ALC, + PWR, + PKPWR } METERTYPE; #define RXMETERPTS (3) diff --git a/jDttSP/mkchan.c b/jDttSP/mkchan.c deleted file mode 100644 index 2855980..0000000 --- a/jDttSP/mkchan.c +++ /dev/null @@ -1,84 +0,0 @@ -/* mkchan.c */ -/* create a file big enough to accommodate - a header + a ringbuffer of a given size */ - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -char *rng_name = 0, - *buf_asks = 0; -FILE *rng_file = 0; -size_t rng_size = 0, - buf_size = 0, - blk_size = 0, - tot_size = 0; - -BOOLEAN verbose = FALSE; - -void -execute(void) { - int i; - rng_size = sizeof(ringb_t); - if ((buf_size = atoi(buf_asks)) <= 0) { - fprintf(stderr, "buffer size %s?\n", buf_asks); - exit(1); - } - if (!(rng_file = fopen(rng_name, "w"))) { - perror(rng_name); - exit(1); - } - blk_size = nblock2(buf_size); - tot_size = rng_size + blk_size; - for (i = 0; i < tot_size; i++) putc(0, rng_file); - fclose(rng_file); - if (verbose) - fprintf(stderr, - "created chan file %s (%d + [%d -> %d] = %d)\n", - rng_name, rng_size, buf_size, blk_size, tot_size); -} - -void -closeup(void) { exit(0); } - -static void -usage(void) { - fprintf(stderr, "usage:\n"); - fprintf(stderr, "mkchan [-v] name size\n"); - exit(1); -} - -static void -setup(int argc, char **argv) { - int i; - - for (i = 1; i < argc; i++) - if (argv[i][0] == '-') - switch (argv[i][1]) { - case 'v': verbose = TRUE; break; - default: usage(); - } - else break; - if (i < (argc - 2)) usage(); - rng_name = argv[i++]; - buf_asks = argv[i++]; -} - -int -main(int argc, char **argv) { setup(argc, argv), execute(), closeup(); } diff --git a/jDttSP/ringb.c b/jDttSP/ringb.c index 1e6c31e..8a1cfaf 100644 --- a/jDttSP/ringb.c +++ b/jDttSP/ringb.c @@ -45,6 +45,20 @@ ringb_reset(ringb_t *rb) { rb->wptr = 0; } +void +ringb_clear(ringb_t *rb, size_t nbytes) { + size_t i; + char zero = 0; + for (i = 0; i < nbytes; i++) + ringb_write(rb, &zero, 1); +} + +void +ringb_restart(ringb_t *rb, size_t nbytes) { + ringb_reset(rb); + ringb_clear(rb, nbytes); +} + size_t ringb_read_space(const ringb_t *rb) { size_t w = rb->wptr, r = rb->rptr; diff --git a/jDttSP/ringb.h b/jDttSP/ringb.h index c92fd3c..55f4a2e 100644 --- a/jDttSP/ringb.h +++ b/jDttSP/ringb.h @@ -169,4 +169,18 @@ extern void ringb_write_advance(ringb_t *rb, size_t cnt); extern size_t ringb_write_space(const ringb_t *rb); +/* Fill the ring buffer for nbytes at the beginning with zeros + * rb a pointer to the ring buffer structure + * nbytes the number of bytes to be written */ + +extern void ringb_clear(ringb_t *rb, size_t nbytes); + +/* Reset the read and write pointers, making an empty buffer. + * This is not thread safe. + * Fill the ring buffer for nbytes at the beginning with zeros + * rb a pointer to the ring buffer structure + * nbytes the number of bytes to be written */ + +extern void ringb_restart(ringb_t *rb, size_t nbytes); + #endif diff --git a/jDttSP/sdr.c b/jDttSP/sdr.c index aad64d3..9374813 100644 --- a/jDttSP/sdr.c +++ b/jDttSP/sdr.c @@ -115,6 +115,8 @@ setup_all(void) { uni.mix.rx.flag = uni.mix.tx.flag = FALSE; uni.mix.rx.gain = uni.mix.tx.gain = 1.0; + uni.cpdlen = loc.def.comp; + uni.tick = 0; } @@ -146,7 +148,7 @@ setup_rx(int k) { we just created */ rx[k].buf.i = newCXB(FiltOvSv_fetchsize(rx[k].filt.ovsv), FiltOvSv_fetchpoint(rx[k].filt.ovsv), - "init rx.buf.i"); + "init rx[k].buf.i"); rx[k].buf.o = newCXB(FiltOvSv_storesize(rx[k].filt.ovsv), FiltOvSv_storepoint(rx[k].filt.ovsv), "init rx[k].buf.o"); @@ -161,17 +163,16 @@ setup_rx(int k) { uni.samplerate, "SDR RX Oscillator"); - rx[k].agc.gen = newDigitalAgc(agcMED, // Mode - 7, // Hang - 7, // Size - 48, // Ramp - 3, // Over - 3, // Rcov - CXBsize(rx[k].buf.o), // BufSize - 100.0, // MaxGain - 0.707, // Limit - 1.0, // CurGain - CXBbase(rx[k].buf.o)); + rx[k].agc.gen = newDigitalAgc(agcSLOW, // Mode + 7, // Hang + 48, // Ramp + 3, // Over + 3, // Rcov + CXBsize(rx[k].buf.o), // BufSize + 2500.0, // MaxGain + 0.707, // Limit + 1.0, // CurGain + CXBbase(rx[k].buf.o)); rx[k].agc.flag = TRUE; /* demods */ @@ -236,7 +237,12 @@ setup_rx(int k) { rx[k].squelch.thresh = -30.0; rx[k].squelch.power = 0.0; rx[k].squelch.flag = rx[k].squelch.running = rx[k].squelch.set = FALSE; - rx[k].squelch.num = (int) (0.0395 * uni.samplerate + 0.5); + rx[k].squelch.num = uni.buflen - 10; + + rx[k].cpd.gen = newWSCompander(uni.cpdlen, + 0.0, + rx[k].buf.o); + rx[k].cpd.flag = FALSE; rx[k].mode = uni.mode.sdr; rx[k].bin.flag = FALSE; @@ -281,6 +287,9 @@ setup_tx(void) { FiltOvSv_storepoint(tx.filt.ovsv), "init tx.buf.o"); + tx.dcb.flag = FALSE; + tx.dcb.gen = newDCBlocker(DCB_MED, tx.buf.i); + /* conversion */ tx.osc.freq = 0.0; tx.osc.phase = 0.0; @@ -291,12 +300,12 @@ setup_tx(void) { uni.samplerate, "SDR TX Oscillator"); + tx.agc.gen = newDigitalAgc(agcFAST, // Mode 3, // Hang - 3, // Size + 48, // Ramp 3, // Over 3, // Rcov - 48, // Ramp CXBsize(tx.buf.o), // BufSize 1.0, // MaxGain 0.900, // Limit @@ -304,9 +313,14 @@ setup_tx(void) { CXBbase(tx.buf.o)); tx.agc.flag = TRUE; - tx.spr.gen = newSpeechProc(0.4, 10.0, CXBbase(tx.buf.i), CXBsize(tx.buf.i)); + tx.spr.gen = newSpeechProc(0.4, 10.0, CXBbase(tx.buf.o), CXBsize(tx.buf.o)); tx.spr.flag = FALSE; + tx.cpd.gen = newWSCompander(uni.cpdlen, + 0.0, + tx.buf.o); + tx.cpd.flag = FALSE; + tx.scl.dc = cxzero; tx.scl.pre.val = 1.0; tx.scl.pre.flag = FALSE; @@ -345,6 +359,7 @@ destroy_workspace(void) { delSpeechProc(tx.spr.gen); delDigitalAgc(tx.agc.gen); delOSC(tx.osc.gen); + delDCBlocker(tx.dcb.gen); delvec_COMPLEX(tx.filt.save); delFiltOvSv(tx.filt.ovsv); delFIR_Bandpass_COMPLEX(tx.filt.coef); @@ -405,20 +420,21 @@ do_rx_meter(int k, CXB buf, int tap) { 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]); + if (tap == 3) rx[k].norm = uni.meter.rx.val[k][tap] / len; 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 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 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]); @@ -429,6 +445,9 @@ do_rx_meter(int k, CXB buf, int tap) { 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; + case AGC_GAIN: + uni.meter.rx.val[k][tap] = 20.0 * log10(rx[k].agc.gen->gain.now + 1e-80); + break; default: break; } @@ -456,28 +475,35 @@ do_tx_meter(CXB buf, int 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.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); + case ALC: + { + REAL tmp = 20.0 * log10(tx.agc.gen->gain.now); + uni.meter.tx.val[tap] = + tmp < 0.0 ? tmp : min(20.0, 20.0 * log10(tx.agc.gen->gain.raw)); + } break; - case ADC_IMAG: - for(i = 0; i < len; i++) - 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); + case PWR: + for(i = 0, uni.meter.tx.val[tap] = 1e-20; i < CXBhave(tx.buf.o); i++) + uni.meter.tx.val[tap] += Csqrmag(CXBdata(tx.buf.o, i)); + uni.meter.tx.val[tap] /= 2048.0; + break; + case PKPWR: + for(i = 0, uni.meter.tx.val[tap] = 1e-20; i < CXBhave(tx.buf.o); i++) + uni.meter.tx.val[tap] = max(uni.meter.tx.val[tap], + Csqrmag(CXBdata(tx.buf.o,i))); break; default: break; } } -PRIVATE BOOLEAN +PRIVATE void 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; + CXBsize(buf) * sizeof(COMPLEX)); + uni.spec.fill = (uni.spec.fill + CXBsize(buf)) % uni.spec.size; } } @@ -485,8 +511,8 @@ 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; + CXBsize(buf) * sizeof(COMPLEX)); + uni.spec.fill = (uni.spec.fill + CXBsize(buf)) % uni.spec.size; } //======================================================================== @@ -497,9 +523,13 @@ should_do_rx_squelch(int k) { if (rx[k].squelch.flag) { int i, n = CXBhave(rx[k].buf.o); rx[k].squelch.power = 0.0; + for (i = 0; i < n; i++) rx[k].squelch.power += Csqrmag(CXBdata(rx[k].buf.o, i)); - return rx[k].squelch.thresh > 10.0 * log10(rx[k].squelch.power); + + return + 10.0 * log10(rx[k].squelch.power) < rx[k].squelch.thresh; + } else return rx[k].squelch.set = FALSE; } @@ -510,14 +540,25 @@ should_do_rx_squelch(int k) { PRIVATE void do_squelch(int k) { rx[k].squelch.set = TRUE; + if (!rx[k].squelch.running) { - int i, m = rx[k].squelch.num, n = CXBhave(rx[k].buf.o) - m; + int i, + m = rx[k].squelch.num, + n = CXBhave(rx[k].buf.o) - m; + for (i = 0; i < m; i++) - CXBdata(rx[k].buf.o, i) = Cscl(CXBdata(rx[k].buf.o, i), 1.0 - (REAL) i / m); - memset((void *) (CXBbase(rx[k].buf.o) + m), 0, n * sizeof(COMPLEX)); + CXBdata(rx[k].buf.o, i) = + Cscl(CXBdata(rx[k].buf.o, i), 1.0 - (REAL) i / m); + + memset((void *) (CXBbase(rx[k].buf.o) + m), + 0, + n * sizeof(COMPLEX)); rx[k].squelch.running = TRUE; + } else - memset((void *) CXBbase(rx[k].buf.o), 0, CXBhave(rx[k].buf.o) * sizeof(COMPLEX)); + memset((void *) CXBbase(rx[k].buf.o), + 0, + CXBhave(rx[k].buf.o) * sizeof(COMPLEX)); } // lift squelch @@ -527,8 +568,11 @@ PRIVATE void no_squelch(int k) { if (rx[k].squelch.running) { int i, m = rx[k].squelch.num; + for (i = 0; i < m; i++) - CXBdata(rx[k].buf.o, i) = Cscl(CXBdata(rx[k].buf.o, i), (REAL) i / m); + CXBdata(rx[k].buf.o, i) = + Cscl(CXBdata(rx[k].buf.o, i), (REAL) i / m); + rx[k].squelch.running = FALSE; } } @@ -582,12 +626,16 @@ do_rx_pre(int k) { do_rx_meter(k, rx[k].buf.o, RXMETER_POST_FILT); do_rx_spectrum(k, rx[k].buf.o, SPEC_POST_FILT); + if (rx[k].cpd.flag) + WSCompand(rx[k].cpd.gen); + if (should_do_rx_squelch(k)) do_squelch(k); else if (rx[k].agc.flag) DigitalAgc(rx[k].agc.gen, rx[k].tick); - + + do_rx_spectrum(k, rx[k].buf.o, SPEC_POST_AGC); } } @@ -682,18 +730,19 @@ do_rx(int k) { 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); } correctIQ(tx.buf.i, tx.iqfix); - if (tx.spr.flag) SpeechProcessor(tx.spr.gen); + if (tx.dcb.flag) DCBlock(tx.dcb.gen); if (tx.tick == 0) reset_OvSv(tx.filt.ovsv); filter_OvSv(tx.filt.ovsv); + } PRIVATE void @@ -712,6 +761,9 @@ do_tx_post(void) { CXBdata(tx.buf.o, i) = Cscl(CXBdata(tx.buf.o, i), tx.scl.post.val); } + if (tx.spr.flag) SpeechProcessor(tx.spr.gen); + if (tx.cpd.flag) WSCompand(tx.cpd.gen); + if (uni.spec.flag) do_tx_spectrum(tx.buf.o); @@ -825,16 +877,16 @@ process_samples(float *bufl, float *bufr, do_rx(k), rx[k].tick++; // mix for (i = 0; i < n; i++) - bufl[i] += CXBimag(rx[k].buf.o, i), - bufr[i] += CXBreal(rx[k].buf.o, i); + bufl[i] += (float) CXBimag(rx[k].buf.o, i), + bufr[i] += (float) 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, - bufr[i] += auxr[i] * uni.mix.rx.gain; + bufl[i] += (float) (auxl[i] * uni.mix.rx.gain), + bufr[i] += (float) (auxr[i] * uni.mix.rx.gain); break; @@ -843,8 +895,8 @@ process_samples(float *bufl, float *bufr, // early mixing of aux buffers if (uni.mix.tx.flag) for (i = 0; i < n; i++) - bufl[i] += auxl[i] * uni.mix.tx.gain, - bufr[i] += auxr[i] * uni.mix.tx.gain; + bufl[i] += (float) (auxl[i] * uni.mix.tx.gain), + bufr[i] += (float) (auxr[i] * uni.mix.tx.gain); for (i = 0; i < n; i++) CXBimag(tx.buf.i, i) = bufl[i], CXBreal(tx.buf.i, i) = bufr[i]; diff --git a/jDttSP/sdrexport.h b/jDttSP/sdrexport.h index 6303a65..68de488 100644 --- a/jDttSP/sdrexport.h +++ b/jDttSP/sdrexport.h @@ -60,13 +60,12 @@ Bridgewater, NJ 08807 #include #include #include + //------------------------------------------------------------------------ // max no. simultaneous receivers #ifndef MAXRX #define MAXRX (4) #endif -//------------------------------------------------------------------------ -/* modulation types, modes */ //======================================================================== /* RX/TX both */ @@ -110,6 +109,8 @@ extern struct _uni { } rx, tx; } mix; + int cpdlen; + long tick; } uni; @@ -167,6 +168,12 @@ extern struct _rx { BOOLEAN flag, running, set; int num; } squelch; + + struct { + BOOLEAN flag; + WSCompander gen; + } cpd; + SDRMODE mode; struct { BOOLEAN flag; } bin; REAL norm; @@ -178,32 +185,50 @@ extern struct _rx { /* TX */ //------------------------------------------------------------------------ extern struct _tx { + struct { CXB i, o; } buf; + IQ iqfix; + + struct { + BOOLEAN flag; + DCBlocker gen; + } dcb; + struct { REAL freq, phase; OSC gen; } osc; + struct { ComplexFIR coef; FiltOvSv ovsv; COMPLEX *save; } filt; + + struct { + SpeechProc gen; + BOOLEAN flag; + } spr; + + struct { + BOOLEAN flag; + WSCompander gen; + } cpd; + struct { ComplexFIR coef; FiltOvSv ovsv; CXB in, out; } fm; + struct { DIGITALAGC gen; BOOLEAN flag; } agc; - struct { - SpeechProc gen; - BOOLEAN flag; - } spr; + struct { COMPLEX dc; struct { @@ -211,6 +236,7 @@ extern struct _tx { BOOLEAN flag; } pre, post; } scl; + SDRMODE mode; long tick; REAL norm; @@ -320,6 +346,7 @@ extern struct _top { } run; int fade, tail; } swch; + } top; #endif diff --git a/jDttSP/spectrum.c b/jDttSP/spectrum.c index 441f92e..e547567 100644 --- a/jDttSP/spectrum.c +++ b/jDttSP/spectrum.c @@ -39,12 +39,14 @@ snap_spectrum(SpecBlock *sb, int label) { int i, j; // where most recent signal started - j = (sb->fill - sb->buflen + sb->size) % sb->size; + j = sb->fill; // copy starting from there in circular fashion, // applying window as we go for (i = 0; i < sb->size; i++) { - CXBdata(sb->timebuf, i) = Cscl(CXBdata(sb->timebuf, j), sb->window[i]); + COMPLEX z = CXBdata(sb->accum, j); + sb->oscope[i] = (float) z.re; + CXBdata(sb->timebuf, i) = Cscl(z, sb->window[i]); j = ++j % sb->size; } @@ -62,18 +64,17 @@ compute_spectrum(SpecBlock *sb) { (fftw_complex *) CXBbase(sb->timebuf), (fftw_complex *) CXBbase(sb->freqbuf)); - if (sb->scale == SPEC_MAG) { - for (i = 0; i < half; i++) - sb->output[i + half] = Cmag(CXBdata(sb->freqbuf, i)); - for (; i < sb->size; i++) - sb->output[i] = Cmag(CXBdata(sb->freqbuf, i)); - - } else { // SPEC_PWR - for (i = 0; i < half; i++) - sb->output[i + half] = 10.0 * log10(Csqrmag(CXBdata(sb->freqbuf, i)) + 1e-60); - for (; i < sb->size; i++) - sb->output[i] = 10.0 * log10(Csqrmag(CXBdata(sb->freqbuf, i)) + 1e-60); - } + if (sb->scale == SPEC_MAG) + + for (i = 0; i < sb->size; i++) + sb->output[i] = + (float) Cmag(CXBdata(sb->freqbuf, (i + half) % sb->size)); + + else // SPEC_PWR + + for (i = 0; i < sb->size; i++) + sb->output[i] = + (float) (10.0 * log10(Csqrmag(CXBdata(sb->freqbuf, (i + half) % sb->size)) + 1e-60)); } void @@ -84,6 +85,7 @@ init_spectrum(SpecBlock *sb) { sb->freqbuf = newCXB(sb->size, 0, "spectrum freqbuf"); sb->window = newvec_REAL(sb->size, "spectrum window"); sb->output = (float *) safealloc(sb->size, sizeof(float), "spectrum output"); + sb->oscope = (float *) safealloc(sb->size, sizeof(float), "spectrum oscope"); sb->plan = fftw_create_plan(sb->size, FFTW_FORWARD, sb->planbits); } @@ -92,6 +94,7 @@ reinit_spectrum(SpecBlock *sb) { sb->fill = sb->size - sb->buflen; memset((char *) CXBbase(sb->accum), 0, sb->size * sizeof(REAL)); memset((char *) sb->output, 0, sb->size * sizeof(float)); + memset((char *) sb->oscope, 0, sb->size * sizeof(float)); } void @@ -102,6 +105,7 @@ finish_spectrum(SpecBlock *sb) { delCXB(sb->freqbuf); delvec_REAL(sb->window); safefree((char *) sb->output); + safefree((char *) sb->oscope); fftw_destroy_plan(sb->plan); } } diff --git a/jDttSP/spectrum.h b/jDttSP/spectrum.h index adef3dc..52575ba 100644 --- a/jDttSP/spectrum.h +++ b/jDttSP/spectrum.h @@ -64,6 +64,7 @@ Bridgewater, NJ 08807 #define SPEC_SEMI_RAW (0) #define SPEC_PRE_FILT (1) #define SPEC_POST_FILT (2) +#define SPEC_POST_AGC (3) typedef struct _spec_block { @@ -72,7 +73,7 @@ struct _spec_block { CXB accum, timebuf, freqbuf; int fill, buflen, rxk, scale, size, type; REAL *window; - float *output; + float *output, *oscope; int planbits; fftw_plan plan; } SpecBlock; diff --git a/jDttSP/update.c b/jDttSP/update.c index 0e6ef67..ceed465 100644 --- a/jDttSP/update.c +++ b/jDttSP/update.c @@ -562,7 +562,7 @@ setcorrectIQgain(int n, char **p) { PRIVATE int setSquelch(int n, char **p) { - rx[RL].squelch.thresh = -atof(p[0]); + rx[RL].squelch.thresh = atof(p[0]); return 0; } @@ -816,6 +816,43 @@ setAuxMixGain(int n, char **p) { } } +PRIVATE int +setCompandSt(int n, char **p) { + if (n < 1) { + tx.cpd.flag = FALSE; + return 0; + } else { + BOOLEAN flag = atoi(p[0]); + if (n > 1) { + switch (atoi(p[1])) { + case RX: rx[RL].cpd.flag = flag; break; + case TX: + default: tx.cpd.flag = flag; break; + } + } else + tx.cpd.flag = flag; + return 0; + } +} + +PRIVATE int +setCompand(int n, char **p) { + if (n < 1) + return -1; + else { + REAL fac = atof(p[0]); + if (n > 1) { + switch (atoi(p[1])) { + case RX: WSCReset(rx[RL].cpd.gen, fac); break; + case TX: + default: WSCReset(tx.cpd.gen, fac); break; + } + } else + WSCReset(tx.cpd.gen, fac); + return 0; + } +} + //------------------------------------------------------------------------ // [type] @@ -846,48 +883,41 @@ setSpectrumType(int n, char **p) { uni.spec.rxk = RL; switch (n) { case 3: - uni.spec.rxk = atoi(p[2]); + uni.spec.rxk = atoi(p[2]); case 2: uni.spec.scale = atoi(p[1]); + break; case 1: - uni.spec.type = atoi(p[0]); + uni.spec.type = atoi(p[0]); break; case 0: - return 0; + break; default: return -1; } + return uni.spec.type; } -#if 0 PRIVATE int -setSpectrumType(int n, char **p) { - switch (n) { - case 3: - uni.spec.type = atoi(p[0]); - uni.spec.scale = atoi(p[1]); - uni.spec.rxk = atoi(p[2]); - case 2: - uni.spec.type = atoi(p[0]); - uni.spec.scale = atoi(p[1]); - uni.spec.rxk = RL; - break; - case 1: - uni.spec.type = atoi(p[0]); - uni.spec.scale = SPEC_PWR; - uni.spec.rxk = RL; - break; - case 0: - uni.spec.type = SPEC_POST_FILT; - uni.spec.scale = SPEC_PWR; - uni.spec.rxk = RL; - break; - default: +setDCBlockSt(int n, char **p) { + if (n < 1) { + tx.dcb.flag = FALSE; + return 0; + } else { + tx.dcb.flag = atoi(p[0]); + return 0; + } +} + +PRIVATE int +setDCBlock(int n, char **p) { + if (n < 1) return -1; + else { + resetDCBlocker(tx.dcb.gen, atoi(p[0])); + return 0; } - return 0; } -#endif //======================================================================== @@ -968,8 +998,12 @@ CTE update_cmds[] = { {"setRXPan", setRXPan}, {"setAuxMixSt", setAuxMixSt}, {"setAuxMixGain", setAuxMixGain}, + {"setCompandSt", setCompandSt}, + {"setCompand", setCompand}, {"setMeterType", setMeterType}, {"setSpectrumType", setSpectrumType}, + {"setDCBlockSt", setDCBlockSt}, + {"setDCBlock", setDCBlock}, { 0, 0 } }; diff --git a/jDttSP/wscompand.c b/jDttSP/wscompand.c new file mode 100644 index 0000000..0931ef7 --- /dev/null +++ b/jDttSP/wscompand.c @@ -0,0 +1,108 @@ +// wscompand.c +// waveshaping compander, mostly for speech +/* +This file is part of a program that implements a Software-Defined Radio. + +Copyright (C) 2004-2005 by Frank Brickle, AB2KT and Bob McGwier, N4HY + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +The authors can be reached by email at + +ab2kt@arrl.net +or +rwmcgwier@comcast.net + +or by paper mail at + +The DTTS Microwave Society +6 Kathleen Place +Bridgewater, NJ 08807 +*/ + +#include + +PRIVATE INLINE REAL +WSCLookup(WSCompander wsc, REAL x) { + if (x > 0.0) { + REAL d = x - (int) x, y, *tbl = wsc->tbl; + int i = (int) (x * wsc->npts), end = wsc->nend; + if (i < end) + y = tbl[i] + d * (tbl[i + 1] - tbl[i]); + else + y = tbl[end]; + return y / x; + } else + return 0.0; +} + +void +WSCompand(WSCompander wsc) { + int i, n = CXBsize(wsc->buff); + for (i = 0; i < n; i++) { + COMPLEX val = CXBdata(wsc->buff, i); + REAL mag = Cmag(val), + scl = WSCLookup(wsc, mag); + CXBdata(wsc->buff, i) = Cscl(val, scl); + } +} + +void +WSCReset(WSCompander wsc, REAL fac) { + int i; + REAL *tbl = wsc->tbl; + + if (fac == 0.0) // just linear + for (i = 0; i < wsc->npts; i++) + tbl[i] = i / (REAL) wsc->npts; + + else { // exponential + REAL del = fac / wsc->nend, + scl = 1.0 - exp(fac); + for (i = 0; i < wsc->npts; i++) + tbl[i] = (1.0 - exp(i * del)) / scl; + } + + wsc->fac = fac; +} + +// fac < 0: compression +// fac > 0: expansion + +WSCompander +newWSCompander(int npts, + REAL fac, + CXB buff) { + WSCompander wsc; + + wsc = (WSCompander) safealloc(1, + sizeof(WSCompanderInfo), + "WSCompander struct"); + wsc->npts = npts; + wsc->nend = npts - 1; + wsc->tbl = newvec_REAL(npts, "WSCompander table"); + wsc->buff = newCXB(npts, CXBbase(buff), "WSCompander buff"); + WSCReset(wsc, fac); + return wsc; +} + +void +delWSCompander(WSCompander wsc) { + if (wsc) { + delvec_REAL(wsc->tbl); + delCXB(wsc->buff); + safefree((char *) wsc); + } +} diff --git a/jDttSP/wscompand.h b/jDttSP/wscompand.h new file mode 100644 index 0000000..88d2411 --- /dev/null +++ b/jDttSP/wscompand.h @@ -0,0 +1,60 @@ +// wscompand.h +/* +This file is part of a program that implements a Software-Defined Radio. + +Copyright (C) 2004-2005 by Frank Brickle, AB2KT and Bob McGwier, N4HY + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +The authors can be reached by email at + +ab2kt@arrl.net +or +rwmcgwier@comcast.net + +or by paper mail at + +The DTTS Microwave Society +6 Kathleen Place +Bridgewater, NJ 08807 +*/ + +#ifndef _wscompand_h +#define _wscompand_h + +#include +#include +#include +#include +#include +#include +#include + +typedef struct _wscompander { + int npts, nend; + REAL fac, *tbl; + CXB buff; +} WSCompanderInfo, *WSCompander; + +extern void WSCompand(WSCompander wsc); + +// fac < 0: compression +// fac > 0: expansion + +extern void WSCReset(WSCompander wsc, REAL fac); +extern WSCompander newWSCompander(int npts, REAL fac, CXB buff); +extern void delWSCompander(WSCompander wsc); + +#endif -- 2.37.2