From 219b895aaec3b93a1e4af62026e7a2f8b5391ac0 Mon Sep 17 00:00:00 2001 From: dttsp Date: Tue, 10 May 2005 12:59:01 +0000 Subject: [PATCH] Major changes. Added metering and power spectrum, other fixes. Rearranged headers somewhat. --- jDttSP/Makefile | 21 ++-- jDttSP/chan.c | 14 +++ jDttSP/chan.h | 2 + jDttSP/command-vocabulary | 12 +- jDttSP/common.h | 3 +- jDttSP/defs.h | 68 +++++++++++ jDttSP/keyd.c | 2 +- jDttSP/local.h | 17 +-- jDttSP/main.c | 162 ++++++++++++++++++--------- jDttSP/meter.h | 90 ++++++++++++++- jDttSP/metermon.c | 78 ++++++++----- jDttSP/sdr.c | 229 ++++++++++++++++++++++++++++---------- jDttSP/sdrexport.h | 71 +++++++----- jDttSP/setup-ipc | 9 +- jDttSP/specmon.c | 51 +++++++++ jDttSP/spectrum.c | 107 ++++++++++++++++++ jDttSP/spectrum.h | 86 ++++++++++++++ jDttSP/update.c | 107 +++++++++++++++++- 18 files changed, 925 insertions(+), 204 deletions(-) create mode 100644 jDttSP/defs.h create mode 100644 jDttSP/specmon.c create mode 100644 jDttSP/spectrum.c create mode 100644 jDttSP/spectrum.h diff --git a/jDttSP/Makefile b/jDttSP/Makefile index f2e978e..d9bfdeb 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 @@ -18,12 +18,14 @@ OBJ = am_demod.o\ filter.o\ fm_demod.o\ lmadf.o\ + meter.o\ noiseblanker.o\ oscillator.o\ ovsv.o\ ringb.o\ sdr.o\ sdrexport.o\ + spectrum.o\ speechproc.o\ splitfields.o\ spottone.o\ @@ -36,7 +38,7 @@ KOBJ = oscillator.o cwtones.o chan.o ringb.o banal.o bufvec.o splitfields.o cxop jsdr: main.o $(OBJ) $(CC) -o jsdr main.o $(OBJ) $(LIBS) -all: jsdr mkchan ipc metermon keyd keyb +all: jsdr mkchan ipc metermon specmon keyd keyb keyd: keyd.o keyer.o $(KOBJ) $(CC) -o keyd keyd.o keyer.o $(KOBJ) $(LIBS) @@ -47,11 +49,11 @@ keyb: keyb.o keyer.o $(KOBJ) $(OBJ): sdrexport.h -metermon: metermon.o chan.o ringb.o bufvec.o cxops.o banal.o - $(CC) -o metermon metermon.o chan.o ringb.o bufvec.o cxops.o banal.o $(LIBS) +metermon: metermon.o + $(CC) -o metermon metermon.o $(LIBS) -mkchan: mkchan.o bufvec.o banal.o cxops.o - $(CC) -o mkchan mkchan.o bufvec.o banal.o cxops.o $(LIBS) +specmon: specmon.o + $(CC) -o specmon specmon.o $(LIBS) ipc: mkchan ./setup-ipc @@ -59,13 +61,16 @@ ipc: mkchan obj: $(OBJ) clean: - /bin/rm *.o jsdr mkchan metermon keyd #$(staticlibname) + /bin/rm *.o jsdr keyb keyd metermon #$(staticlibname) #/bin/rm IPC/* staticlib: $(OBJ) ar rcs $(staticlibname) $(OBJ) ranlib $(staticlibname) +#mkchan: mkchan.o bufvec.o banal.o cxops.o +# $(CC) -o mkchan mkchan.o bufvec.o banal.o cxops.o $(LIBS) + #CFLAGS = -fPIC -g -O3 -I. -I/usr/local/include # sharedlibname=libDttSP.so # sharedlibvers=0.0.1 diff --git a/jDttSP/chan.c b/jDttSP/chan.c index 651274c..ba7e246 100644 --- a/jDttSP/chan.c +++ b/jDttSP/chan.c @@ -54,6 +54,17 @@ putChan_nowait(Chan c, char *data, size_t size) { } else return FALSE; } +size_t +putChan_force(Chan c, char *data, size_t size) { + if (ringb_write_space(c->rb) >= size) { + ringb_write(c->rb, data, size); + return size; + } else { + ringb_reset(c->rb); + return ringb_write(c->rb, data, size); + } +} + BOOLEAN getChan_nowait(Chan c, char *data, size_t size) { if (ringb_read_space(c->rb) >= size) { @@ -62,6 +73,9 @@ getChan_nowait(Chan c, char *data, size_t size) { } else return FALSE; } +void +resetChan(Chan c) { ringb_reset(c->rb); } + Chan openChan(char *path, size_t want) { Chan c = (Chan) safealloc(sizeof(ChanDesc), 1, "Chan header"); diff --git a/jDttSP/chan.h b/jDttSP/chan.h index bf92625..28197d6 100644 --- a/jDttSP/chan.h +++ b/jDttSP/chan.h @@ -75,7 +75,9 @@ struct _chan { extern size_t putChan(Chan c, char *data, size_t size); extern size_t getChan(Chan c, char *data, size_t size); extern BOOLEAN putChan_nowait(Chan c, char *data, size_t size); +extern size_t putChan_force(Chan c, char *data, size_t size); extern BOOLEAN getChan_nowait(Chan c, char *data, size_t size); +extern void resetChan(Chan c); // NB want will be rounded up to a power of 2 extern Chan openChan(char *path, size_t want); extern void closeChan(Chan c); diff --git a/jDttSP/command-vocabulary b/jDttSP/command-vocabulary index 7ea1160..9eb1270 100644 --- a/jDttSP/command-vocabulary +++ b/jDttSP/command-vocabulary @@ -33,9 +33,6 @@ setcorrectIQ phase gain // int, int setcorrectIQphase phase // int setcorrectIQgain gain // int setSquelch lev // float, gain, RX only; default -30dB -setMeterOffset lev // float, RX only, appears only in squelch calc -setATTOffset val // float, RX only, appears only in squelch calc -setGainOffset // float, RX only, appears only in squelch calc setSquelchSt T|F // on/off, RX only setTRX trx // trx = RX|TX setRunState state // RUN_MUTE, RUN_PASS, RUN_PLAY @@ -58,3 +55,12 @@ 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 + diff --git a/jDttSP/common.h b/jDttSP/common.h index 0f71b86..e31c20c 100644 --- a/jDttSP/common.h +++ b/jDttSP/common.h @@ -33,10 +33,10 @@ Bridgewater, NJ 08807 */ #ifndef _common_h - #define _common_h #include +#include #include #include #include @@ -59,6 +59,7 @@ Bridgewater, NJ 08807 #include #include #include +#include #include #include diff --git a/jDttSP/defs.h b/jDttSP/defs.h new file mode 100644 index 0000000..b75f456 --- /dev/null +++ b/jDttSP/defs.h @@ -0,0 +1,68 @@ +/* defs.h */ +/* +This file is part of a program that implements a Software-Defined Radio. + +Copyright (C) 2004 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 _defs_h +#define _defs_h + +#define RINGMULT (4) +#define METERMULT (20) +#define SPECMULT (4) +#define DEFRATE (48000.0) +#define DEFSIZE (2048) +#define DEFMODE (SAM) +#define DEFSPEC (4096) + +#define MAXRX (4) + +#ifndef MAXPATHLEN +#define MAXPATHLEN (2048) +#endif + +typedef enum _sdrmode { + LSB, // 0 + USB, // 1 + DSB, // 2 + CWL, // 3 + CWU, // 4 + FMN, // 5 + AM, // 6 + PSK, // 7 + SPEC, // 8 + RTTY, // 9 + SAM, // 10 + DRM // 11 +} SDRMODE; + +typedef enum _trxmode { RX, TX } TRXMODE; + +#endif diff --git a/jDttSP/keyd.c b/jDttSP/keyd.c index 12e7797..a9da384 100644 --- a/jDttSP/keyd.c +++ b/jDttSP/keyd.c @@ -215,7 +215,7 @@ key_thread(void) { //------------------------------------------------------------------------ // update keyer parameters via text input from stdin -// -> set keyer speed to xxx +// -> set keyer speed to xxx // -> set gain to xxx (dB) // -> set freq to xxx // -> set attack/decay times to xxx ms diff --git a/jDttSP/local.h b/jDttSP/local.h index dda789e..724a8f6 100644 --- a/jDttSP/local.h +++ b/jDttSP/local.h @@ -46,17 +46,9 @@ Bridgewater, NJ 08807 #define RCBASE ".DttSPrc" #define PARMPATH "./IPC/SDR-1000-0-commands.fifo" -#define METERPATH "./IPC/SDR-1000-0-meter.chan" +#define METERPATH "./IPC/SDR-1000-0-meter.fifo" +#define SPECPATH "./IPC/SDR-1000-0-spec.fifo" #define WISDOMPATH "./wisdom" -#define RINGMULT (4) -#define METERMULT (2) -#define DEFRATE (48000.0) -#define DEFSIZE (2048) -#define DEFMODE (SAM) - -#ifndef MAXPATHLEN -#define MAXPATHLEN 2048 -#endif extern struct _loc { char name[MAXPATHLEN]; @@ -64,14 +56,15 @@ extern struct _loc { char rcfile[MAXPATHLEN], parm[MAXPATHLEN], meter[MAXPATHLEN], + spec[MAXPATHLEN], wisdom[MAXPATHLEN]; } path; struct { REAL rate; - int size, nrx; + int size, nrx, spec; SDRMODE mode; } def; - struct { int ring, meter; } mult; + struct { int ring; } mult; } loc; #endif diff --git a/jDttSP/main.c b/jDttSP/main.c index b74e9df..7575afb 100644 --- a/jDttSP/main.c +++ b/jDttSP/main.c @@ -2,7 +2,7 @@ This file is part of a program that implements a Software-Defined Radio. -Copyright (C) 2004 by Frank Brickle, AB2KT and Bob McGwier, N4HY +Copyright (C) 2004-5 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 @@ -42,18 +42,69 @@ struct _loc loc; // most of what little we know here about the inner loop, // functionally speaking +extern void reset_meters(void); +extern void reset_spectrum(void); +extern void reset_counters(void); extern void process_samples(float *, float *, float *, float *, int); extern void setup_workspace(void); extern void destroy_workspace(void); //======================================================================== -void -clear_jack_ringbuffer(jack_ringbuffer_t *rb, int nbytes) { - int i; - char zero = 0; - for (i = 0; i < nbytes; i++) - jack_ringbuffer_write(rb, &zero, 1); +PRIVATE void +spectrum_thread(void) { + + while (top.running) { + sem_wait(&top.sync.pws.sem); + + compute_spectrum(&uni.spec); + + if (fwrite((char *) &uni.spec.label, sizeof(int), 1, top.meas.spec.fp) + != 1) { + fprintf(stderr, "error writing spectrum label\n"); + exit(1); + } + + if (fwrite((char *) uni.spec.output, sizeof(float), uni.spec.size, top.meas.spec.fp) + != uni.spec.size) { + fprintf(stderr, "error writing spectrum\n"); + exit(1); + } + + fflush(top.meas.spec.fp); + } + + pthread_exit(0); +} + +PRIVATE void +meter_thread(void) { + + while (top.running) { + sem_wait(&top.sync.mtr.sem); + + if (fwrite((char *) &uni.meter.label, sizeof(int), 1, top.meas.mtr.fp) + != 1) { + fprintf(stderr, "error writing meter label\n"); + exit(1); + } + + if (fwrite((char *) uni.meter.snap.rx, sizeof(REAL), MAXRX * RXMETERPTS, top.meas.mtr.fp) + != MAXRX * RXMETERPTS) { + fprintf(stderr, "error writing rx meter\n"); + exit(1); + } + + if (fwrite((char *) uni.meter.snap.tx, sizeof(REAL), TXMETERPTS, top.meas.mtr.fp) + != TXMETERPTS) { + fprintf(stderr, "error writing tx meter\n"); + exit(1); + } + + fflush(top.meas.mtr.fp); + } + + pthread_exit(0); } //======================================================================== @@ -86,6 +137,8 @@ process_updates_thread(void) { pthread_exit(0); } +//======================================================================== + PRIVATE void gethold(void) { if (jack_ringbuffer_write_space(top.jack.ring.o.l) @@ -136,6 +189,8 @@ canhold(void) { >= top.hold.size.bytes; } +//------------------------------------------------------------------------ + PRIVATE void run_mute(void) { memset((char *) top.hold.buf.l, 0, top.hold.size.bytes); @@ -186,19 +241,15 @@ run_swch(void) { } uni.mode.trx = top.swch.trx.next; - // move this out of main! ----------------------------- - { - int k; - for (k = 0; k < uni.multirx.nrx; k++) rx[k].tick = 0; - } - tx.tick = 0; - //----------------------------------------------------- - top.state = top.swch.run.last; top.swch.bfct.want = top.swch.bfct.have = 0; jack_ringbuffer_reset(top.jack.ring.o.l); jack_ringbuffer_reset(top.jack.ring.o.r); + + reset_meters(); + reset_spectrum(); + reset_counters(); } process_samples(top.hold.buf.l, top.hold.buf.r, @@ -208,6 +259,13 @@ run_swch(void) { //======================================================================== +void +clear_jack_ringbuffer(jack_ringbuffer_t *rb, int nbytes) { + int i; + char zero = 0; + for (i = 0; i < nbytes; i++) + jack_ringbuffer_write(rb, &zero, 1); +} PRIVATE void audio_callback(jack_nframes_t nframes, void *arg) { @@ -276,6 +334,8 @@ audio_callback(jack_nframes_t nframes, void *arg) { sem_post(&top.sync.mon.sem); } +//======================================================================== + PRIVATE void process_samples_thread(void) { while (top.running) { @@ -320,6 +380,10 @@ execute(void) { pthread_join(top.thrd.trx.id, 0); pthread_join(top.thrd.upd.id, 0); pthread_join(top.thrd.mon.id, 0); + if (uni.meter.flag) + pthread_join(top.thrd.mtr.id, 0); + if (uni.spec.flag) + pthread_join(top.thrd.pws.id, 0); // stop audio processing jack_client_close(top.jack.client); @@ -339,6 +403,13 @@ closeup(void) { safefree((char *) top.hold.aux.r); safefree((char *) top.hold.aux.l); + fclose(top.parm.fp); + + if (uni.meter.flag) + fclose(top.meas.mtr.fp); + if (uni.spec.flag) + fclose(top.meas.spec.fp); + destroy_workspace(); exit(0); @@ -351,15 +422,8 @@ usage(void) { fprintf(stderr, "flags:\n"); fprintf(stderr, " -v verbose commentary\n"); fprintf(stderr, " -m do metering\n"); + fprintf(stderr, " -s do spectrum\n"); fprintf(stderr, " -l file execute update commands in file at startup\n"); - fprintf(stderr, " -P cmdpath path to command/update pipe\n"); - fprintf(stderr, " -S s-mtrpath path to S-meter output channel\n"); - fprintf(stderr, " -W wispath path to FFTW wisdom file\n"); - fprintf(stderr, " -R rate sampling rate\n"); - fprintf(stderr, " -B bufsize internal DSP buffer size\n"); - fprintf(stderr, " -M mode start up in mode (SAM, USB, LCW, etc.)\n"); - fprintf(stderr, " -G num use num as ringbuffer mult\n"); - fprintf(stderr, " -E num use num as meter chan mult\n"); fprintf(stderr, "'file' arg unused, but available\n"); exit(1); } @@ -405,6 +469,16 @@ setup_updates(void) { fprintf(stderr, "can't fdopen parm pipe %s\n", loc.path.parm); exit(1); } + + // do this here 'cuz the update thread is controlling the action + if (uni.meter.flag) { + top.meas.mtr.path = loc.path.meter; + top.meas.mtr.fp = efopen(top.meas.mtr.path, "r+"); + } + if (uni.spec.flag) { + top.meas.spec.path = loc.path.spec; + top.meas.spec.fp = efopen(top.meas.spec.path, "r+"); + } } PRIVATE void @@ -477,6 +551,14 @@ setup_threading(void) { pthread_create(&top.thrd.trx.id, NULL, (void *) process_samples_thread, NULL); sem_init(&top.sync.mon.sem, 0, 0); pthread_create(&top.thrd.mon.id, NULL, (void *) monitor_thread, NULL); + if (uni.meter.flag) { + sem_init(&top.sync.mtr.sem, 0, 0); + pthread_create(&top.thrd.mtr.id, NULL, (void *) meter_thread, NULL); + } + if (uni.spec.flag) { + sem_init(&top.sync.pws.sem, 0, 0); + pthread_create(&top.thrd.pws.id, NULL, (void *) spectrum_thread, NULL); + } } //======================================================================== @@ -488,13 +570,14 @@ setup_defaults(void) { strcpy(loc.path.rcfile, RCBASE); strcpy(loc.path.parm, PARMPATH); strcpy(loc.path.meter, METERPATH); + strcpy(loc.path.spec, SPECPATH); strcpy(loc.path.wisdom, WISDOMPATH); loc.def.rate = DEFRATE; loc.def.size = DEFSIZE; loc.def.mode = DEFMODE; + loc.def.spec = DEFSPEC; loc.def.nrx = MAXRX; loc.mult.ring = RINGMULT; - loc.mult.meter = METERMULT; { char *ep; @@ -502,9 +585,9 @@ setup_defaults(void) { if ((ep = getenv("SDR_RCBASE"))) strcpy(loc.path.rcfile, ep); if ((ep = getenv("SDR_PARMPATH"))) strcpy(loc.path.parm, ep); if ((ep = getenv("SDR_METERPATH"))) strcpy(loc.path.meter, ep); + if ((ep = getenv("SDR_SPECPATH"))) strcpy(loc.path.spec, ep); if ((ep = getenv("SDR_WISDOMPATH"))) strcpy(loc.path.wisdom, ep); if ((ep = getenv("SDR_RINGMULT"))) loc.mult.ring = atoi(ep); - if ((ep = getenv("SDR_METERMULT"))) loc.mult.meter = atoi(ep); if ((ep = getenv("SDR_DEFRATE"))) loc.def.rate = atof(ep); if ((ep = getenv("SDR_DEFSIZE"))) loc.def.size = atoi(ep); if ((ep = getenv("SDR_DEFMODE"))) loc.def.mode = atoi(ep); @@ -531,35 +614,14 @@ setup(int argc, char **argv) { case 'v': top.verbose = TRUE; break; - case 'l': - strcpy(loc.path.rcfile, argv[++i]); - break; case 'm': uni.meter.flag = TRUE; break; - case 'P': - strcpy(loc.path.parm, argv[++i]); + case 's': + uni.spec.flag = TRUE; break; - case 'S': - strcpy(loc.path.meter, argv[++i]); - break; - case 'W': - strcpy(loc.path.wisdom, argv[++i]); - break; - case 'R': - loc.def.rate = atof(argv[++i]); - break; - case 'B': - loc.def.size = atoi(argv[++i]); - break; - case 'M': - loc.def.mode = atoi(argv[++i]); - break; - case 'G': - loc.mult.ring = atoi(argv[++i]); - break; - case 'E': - loc.mult.meter = atoi(argv[++i]); + case 'l': + strcpy(loc.path.rcfile, argv[++i]); break; default: usage(); diff --git a/jDttSP/meter.h b/jDttSP/meter.h index 57e7b71..3deb654 100644 --- a/jDttSP/meter.h +++ b/jDttSP/meter.h @@ -1,12 +1,98 @@ +/* meter.h */ +/* +This file is part of a program that implements a Software-Defined Radio. + +Copyright (C) 2004-5 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 _meter_h #define _meter_h +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + typedef enum { SIGNAL_STRENGTH, AVG_SIGNAL_STRENGTH, ADC_REAL, - ADC_IMAG, - AGC_GAIN + ADC_IMAG } METERTYPE; +#define RXMETERPTS (3) +#define RXMETER_PRE_CONV (0) +#define RXMETER_PRE_FILT (1) +#define RXMETER_POST_FILT (2) + +#define TXMETERPTS (1) +#define TXMETER_POST_MOD (0) + +typedef +struct _meter_block { + BOOLEAN flag; + int label; + struct { + METERTYPE type; + REAL val[MAXRX][RXMETERPTS], + avg[MAXRX][RXMETERPTS]; + } rx; + struct { + METERTYPE type; + REAL val[TXMETERPTS], + avg[TXMETERPTS]; + } tx; + struct { + REAL rx[MAXRX * RXMETERPTS], + tx[TXMETERPTS]; + } snap; +} MeterBlock; + +extern void snap_meter(MeterBlock *mb, int label); + #endif diff --git a/jDttSP/metermon.c b/jDttSP/metermon.c index 1bd875b..09a6b6e 100644 --- a/jDttSP/metermon.c +++ b/jDttSP/metermon.c @@ -1,44 +1,62 @@ /* metermon.c */ -#include +#include -#define METERPATH "./IPC/SDR-1000-0-meter.chan" -#define METERMULT (24) #define SLEEP (500000) -jmp_buf here; +char *cmdsink = "./IPC/SDR-1000-0-commands.fifo", + *mtrsrc = "./IPC/SDR-1000-0-meter.fifo"; -void -onsig(int sig) { - signal(SIGHUP, SIG_IGN); - signal(SIGINT, SIG_IGN); - signal(SIGQUIT, SIG_IGN); - longjmp(here, TRUE); -} +FILE *cmdfp, *mtrfp; + +int label; +REAL rxm[MAXRX][RXMETERPTS]; +REAL txm[TXMETERPTS]; int main(int argc, char **argv) { - Chan ch = 0; - int i = 0; - REAL val = 0.0; - - signal(SIGHUP, onsig); - signal(SIGINT, onsig); - signal(SIGQUIT, onsig); - - if (!(ch = openChan(METERPATH, METERMULT * sizeof(REAL)))) - perror("openChan"), exit(1); - - while (!setjmp(here)) { - if (getChan_nowait(ch, (char *) &val, sizeof(REAL))) { - printf("(%d)", i++); - do - printf(" %f", val); - while (getChan_nowait(ch, (char *) &val, sizeof(REAL))); + int i = 0, j, k, lab = getpid(); + + if (!(cmdfp = fopen(cmdsink, "r+"))) + perror(cmdsink), exit(1); + if (!(mtrfp = fopen(mtrsrc, "r+"))) + perror(mtrsrc), exit(1); + + fprintf(stderr, "metermon OK\n"); + + for (;;) { + + usleep(SLEEP); + + fprintf(cmdfp, "reqMeter %d\n", lab); + fflush(cmdfp); + + if (fread((char *) &label, sizeof(int), 1, mtrfp) != 1) + perror("fread meter label"), exit(1); + + if (fread((char *) rxm, sizeof(REAL), MAXRX * RXMETERPTS, mtrfp) + != MAXRX * RXMETERPTS) + perror("fread meter"), exit(1); + + printf("%d <%d>", i++, label); + for (j = 0; j < MAXRX; j++) { + for (k = 0; k < RXMETERPTS; k++) + printf(" %8.3f", rxm[j][k]); putchar('\n'); } - usleep(SLEEP); + + if (fread((char *) txm, sizeof(REAL), TXMETERPTS, mtrfp) + != TXMETERPTS) + perror("fread meter"), exit(1); + + printf("%d\n", i++); + for (k = 0; k < TXMETERPTS; k++) + printf(" %8.3f", txm[k]); + putchar('\n'); } - closeChan(ch); + fclose(cmdfp); + fclose(mtrfp); + + exit(0); } diff --git a/jDttSP/sdr.c b/jDttSP/sdr.c index ead39f0..aad64d3 100644 --- a/jDttSP/sdr.c +++ b/jDttSP/sdr.c @@ -36,25 +36,45 @@ Bridgewater, NJ 08807 //======================================================================== /* 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; { @@ -72,13 +92,29 @@ setup_all(void) { 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; } @@ -86,7 +122,7 @@ setup_all(void) { PRIVATE void setup_rx(int k) { - + /* conditioning */ rx[k].iqfix = newCorrectIQ(0.0, 1.0); rx[k].filt.coef = newFIR_Bandpass_COMPLEX(-4800.0, @@ -297,7 +333,7 @@ setup_workspace(void) { } uni.multirx.act[0] = TRUE; uni.multirx.nac = 1; - + setup_tx(); } @@ -336,8 +372,7 @@ destroy_workspace(void) { } /* all */ - if (uni.meter.flag) - closeChan(uni.meter.chan.c); + finish_spectrum(&uni.spec); } ////////////////////////////////////////////////////////////////////////// @@ -359,43 +394,99 @@ CXBnorm(CXB buff) { //======================================================================== /* 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; } //======================================================================== @@ -448,10 +539,6 @@ PRIVATE void 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), @@ -460,6 +547,10 @@ do_rx_pre(int k) { 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 */ @@ -471,33 +562,39 @@ do_rx_pre(int k) { 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 @@ -509,17 +606,17 @@ do_rx_post(int k) { 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)); @@ -585,8 +682,8 @@ 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); } @@ -604,12 +701,20 @@ do_tx_post(void) { 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); @@ -697,11 +802,11 @@ process_samples(float *bufl, float *bufr, 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]) { @@ -720,11 +825,12 @@ 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), + 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, @@ -734,6 +840,7 @@ process_samples(float *bufl, float *bufr, 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, diff --git a/jDttSP/sdrexport.h b/jDttSP/sdrexport.h index 9900339..6303a65 100644 --- a/jDttSP/sdrexport.h +++ b/jDttSP/sdrexport.h @@ -34,29 +34,39 @@ Bridgewater, NJ 08807 #ifndef _sdrexport_h #define _sdrexport_h -#include - +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include //------------------------------------------------------------------------ // max no. simultaneous receivers +#ifndef MAXRX #define MAXRX (4) +#endif //------------------------------------------------------------------------ /* modulation types, modes */ -typedef enum _sdrmode { - LSB, // 0 - USB, // 1 - DSB, // 2 - CWL, // 3 - CWU, // 4 - FMN, // 5 - AM, // 6 - PSK, // 7 - SPEC, // 8 - RTTY, // 9 - SAM, // 10 - DRM // 11 -} SDRMODE; - -typedef enum _trxmode { RX, TX } TRXMODE; //======================================================================== /* RX/TX both */ @@ -70,16 +80,8 @@ extern struct _uni { TRXMODE trx; } mode; - struct { - BOOLEAN flag; - struct { - char *path; - size_t size; - Chan c; - } chan; - REAL val, avgval; - METERTYPE type; - } meter; + MeterBlock meter; + SpecBlock spec; struct { BOOLEAN flag; @@ -238,12 +240,20 @@ extern struct _top { unsigned int frames, bytes; } size; } hold; + struct { char *path; int fd; FILE *fp; char buff[4096]; } parm; + + struct { + struct { + char *path; + FILE *fp; + } mtr, spec; + } meas; struct { char name[256]; @@ -288,12 +298,13 @@ extern struct _top { struct { struct { pthread_t id; - } trx, upd, mon; + } trx, upd, mon, pws, mtr; } thrd; + struct { struct { sem_t sem; - } buf, upd, mon; + } buf, upd, mon, pws, mtr; } sync; // TRX switching diff --git a/jDttSP/setup-ipc b/jDttSP/setup-ipc index 3a58d31..dfea683 100755 --- a/jDttSP/setup-ipc +++ b/jDttSP/setup-ipc @@ -7,9 +7,12 @@ if [ ! -d ./IPC ]; then mkdir ./IPC; fi mkfifo SDR-1000-0-commands.fifo fi - # 192 = METERMULT * sizeof(REAL) - if [ ! -f SDR-1000-0-meter.chan ]; then - ../mkchan SDR-1000-0-meter.chan 192 + if [ ! -f SDR-1000-0-rx-meter.fifo ]; then + mkfifo SDR-1000-0-meter.fifo + fi + + if [ ! -f SDR-1000-0-spec.fifo ]; then + mkfifo SDR-1000-0-spec.fifo fi) ls -ld IPC diff --git a/jDttSP/specmon.c b/jDttSP/specmon.c new file mode 100644 index 0000000..632fee6 --- /dev/null +++ b/jDttSP/specmon.c @@ -0,0 +1,51 @@ +/* specmon.c */ + +#include + +#define SLEEP (500000) + +char *cmdsink = "./IPC/SDR-1000-0-commands.fifo", + *specsrc = "./IPC/SDR-1000-0-spec.fifo"; + +FILE *cmdfp, *spcfp; + +int label; +float spec[DEFSPEC]; + +int +main(int argc, char **argv) { + int i = 0, j, k, lab = getpid(); + + if (!(cmdfp = fopen(cmdsink, "r+"))) + perror(cmdsink), exit(1); + if (!(spcfp = fopen(specsrc, "r+"))) + perror(specsrc), exit(1); + + printf("spec OK\n"); + + for (;;) { + + usleep(SLEEP); + + fprintf(cmdfp, "reqSpectrum %d\n", lab); + fflush(cmdfp); + + if (fread((char *) &label, sizeof(int), 1, spcfp) != 1) + perror("fread spectrum label"), exit(1); + + if (fread((char *) spec, sizeof(float), DEFSPEC, spcfp) != DEFSPEC) + perror("fread spec"), exit(1); + + printf("%d <%d>", i++, label); + + j = 0; + for (k = 1; k < DEFSPEC; k++) + if (spec[k] > spec[j]) j = k; + printf(" [%d %g]\n", j, spec[j]); + } + + fclose(cmdfp); + fclose(spcfp); + + exit(0); +} diff --git a/jDttSP/spectrum.c b/jDttSP/spectrum.c new file mode 100644 index 0000000..441f92e --- /dev/null +++ b/jDttSP/spectrum.c @@ -0,0 +1,107 @@ +/* spectrum.c */ +/* +This file is part of a program that implements a Software-Defined Radio. + +Copyright (C) 2004 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 + +// snapshot of current signal +void +snap_spectrum(SpecBlock *sb, int label) { + int i, j; + + // where most recent signal started + j = (sb->fill - sb->buflen + sb->size) % sb->size; + + // 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]); + j = ++j % sb->size; + } + + sb->label = label; +} + +// snapshot -> frequency domain +void +compute_spectrum(SpecBlock *sb) { + int i, half = sb->size / 2; + + // assume timebuf has windowed current snapshot + + fftw_one(sb->plan, + (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); + } +} + +void +init_spectrum(SpecBlock *sb) { + sb->fill = sb->size - sb->buflen; + sb->accum = newCXB(sb->size, 0, "spectrum accum"); + sb->timebuf = newCXB(sb->size, 0, "spectrum timebuf"); + 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->plan = fftw_create_plan(sb->size, FFTW_FORWARD, sb->planbits); +} + +void +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)); +} + +void +finish_spectrum(SpecBlock *sb) { + if (sb) { + delCXB(sb->accum); + delCXB(sb->timebuf); + delCXB(sb->freqbuf); + delvec_REAL(sb->window); + safefree((char *) sb->output); + fftw_destroy_plan(sb->plan); + } +} diff --git a/jDttSP/spectrum.h b/jDttSP/spectrum.h new file mode 100644 index 0000000..adef3dc --- /dev/null +++ b/jDttSP/spectrum.h @@ -0,0 +1,86 @@ +/* spectrum.h */ +/* +This file is part of a program that implements a Software-Defined Radio. + +Copyright (C) 2004 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 _spectrum_h +#define _spectrum_h + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define SPEC_MAG (0) +#define SPEC_PWR (1) + +#define SPEC_SEMI_RAW (0) +#define SPEC_PRE_FILT (1) +#define SPEC_POST_FILT (2) + +typedef +struct _spec_block { + BOOLEAN flag; + int label; + CXB accum, timebuf, freqbuf; + int fill, buflen, rxk, scale, size, type; + REAL *window; + float *output; + int planbits; + fftw_plan plan; +} SpecBlock; + +extern void init_spectrum(SpecBlock *sb); +extern void reinit_spectrum(SpecBlock *sb); +extern void snap_spectrum(SpecBlock *sb, int label); +extern void compute_spectrum(SpecBlock *sb); +extern void finish_spectrum(SpecBlock *sb); + +#endif diff --git a/jDttSP/update.c b/jDttSP/update.c index cb6ae7a..833366b 100644 --- a/jDttSP/update.c +++ b/jDttSP/update.c @@ -4,7 +4,7 @@ common defs and code for parm update This file is part of a program that implements a Software-Defined Radio. -Copyright (C) 2004 by Frank Brickle, AB2KT and Bob McGwier, N4HY +Copyright (C) 2004-5 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 @@ -141,7 +141,6 @@ setFilter(int n, char **p) { } // setMode [TRX] - PRIVATE int setMode(int n, char **p) { int mode = atoi(p[0]); @@ -382,6 +381,8 @@ setTXSpeechCompressionGain(int n, char **p) { } //============================================================ +// some changes have been made to a transfer function in vec; +// apply time-domain window to counter possible artifacts PRIVATE void re_window(COMPLEX *vec, int len) { @@ -440,6 +441,7 @@ apply_txeq_band(REAL lof, REAL dB, REAL hif) { // 0 dB1 75 dB2 150 dB3 300 dB4 600 dB5 1200 dB6 2000 dB7 2800 dB8 3600 // approximates W2IHY bandcenters. // no args, revert to no EQ. +// NB these are shelves, not linear or other splines PRIVATE int setTXEQ(int n, char **p) { @@ -655,8 +657,10 @@ PRIVATE int setFinished(int n, char **p) { top.running = FALSE; pthread_cancel(top.thrd.trx.id); - pthread_cancel(top.thrd.upd.id); pthread_cancel(top.thrd.mon.id); + pthread_cancel(top.thrd.pws.id); + pthread_cancel(top.thrd.mtr.id); + pthread_cancel(top.thrd.upd.id); return 0; } @@ -755,6 +759,7 @@ setRXOff(int n, char **p) { } } +// [pos] 0.0 <= pos <= 1.0 PRIVATE int setRXPan(int n, char **p) { REAL pos, theta; @@ -791,6 +796,7 @@ setAuxMixSt(int n, char **p) { } } +// [dB] NB both channels PRIVATE int setAuxMixGain(int n, char **p) { if (n < 1) { @@ -810,11 +816,104 @@ setAuxMixGain(int n, char **p) { } } +//------------------------------------------------------------------------ + +// [type] +PRIVATE int +setMeterType(int n, char **p) { + if (n < 1) + uni.meter.rx.type = SIGNAL_STRENGTH; + else { + METERTYPE type = (METERTYPE) atoi(p[0]); + if (n > 1) { + int trx = atoi(p[1]); + switch (trx) { + case TX: uni.meter.tx.type = type; break; + case RX: + default: uni.meter.rx.type = type; break; + } + } else + uni.meter.rx.type = type; + } + return 0; +} + +// setSpectrumType [type [scale [rx]]] +PRIVATE int +setSpectrumType(int n, char **p) { + uni.spec.type = SPEC_POST_FILT; + uni.spec.scale = SPEC_PWR; + uni.spec.rxk = RL; + switch (n) { + case 3: + uni.spec.rxk = atoi(p[2]); + case 2: + uni.spec.scale = atoi(p[1]); + case 1: + uni.spec.type = atoi(p[0]); + break; + case 0: + return 0; + default: + return -1; + } +} + +#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: + return -1; + } + return 0; +} +#endif + +//======================================================================== + +// save current state while guarded by upd sem +PRIVATE int +reqMeter(int n, char **p) { + snap_meter(&uni.meter, n > 0 ? atoi(p[0]) : 0); + sem_post(&top.sync.mtr.sem); + return 0; +} + +// simile modo +PRIVATE int +reqSpectrum(int n, char **p) { + snap_spectrum(&uni.spec, n > 0 ? atoi(p[0]) : 0); + sem_post(&top.sync.pws.sem); + return 0; +} + //======================================================================== #include CTE update_cmds[] = { + {"reqMeter", reqMeter}, + {"reqSpectrum", reqSpectrum}, {"setANF", setANF}, {"setANFvals", setANFvals}, {"setBIN", setBIN}, @@ -869,6 +968,8 @@ CTE update_cmds[] = { {"setRXPan", setRXPan}, {"setAuxMixSt", setAuxMixSt}, {"setAuxMixGain", setAuxMixGain}, + {"setMeterType", setMeterType}, + {"setSpectrumType", setSpectrumType}, { 0, 0 } }; -- 2.37.2