-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
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\
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)
$(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
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
} 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) {
} 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");
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);
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
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
+
*/
#ifndef _common_h
-
#define _common_h
#include <fromsys.h>
+#include <defs.h>
#include <banal.h>
#include <splitfields.h>
#include <datatypes.h>
#include <spottone.h>
#include <update.h>
#include <meter.h>
+#include <spectrum.h>
#include <sdrexport.h>
#include <local.h>
--- /dev/null
+/* 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
//------------------------------------------------------------------------
// update keyer parameters via text input from stdin
-// <wpm xxx> -> set keyer speed to xxx
+// <wpm xxx> -> set keyer speed to xxx
// <gain xxx> -> set gain to xxx (dB)
// <freq xxx> -> set freq to xxx
// <ramp xxx> -> set attack/decay times to xxx ms
#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];
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
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
// 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);
}
//========================================================================
pthread_exit(0);
}
+//========================================================================
+
PRIVATE void
gethold(void) {
if (jack_ringbuffer_write_space(top.jack.ring.o.l)
>= top.hold.size.bytes;
}
+//------------------------------------------------------------------------
+
PRIVATE void
run_mute(void) {
memset((char *) top.hold.buf.l, 0, top.hold.size.bytes);
}
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,
//========================================================================
+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) {
sem_post(&top.sync.mon.sem);
}
+//========================================================================
+
PRIVATE void
process_samples_thread(void) {
while (top.running) {
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);
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);
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);
}
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
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);
+ }
}
//========================================================================
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;
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);
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();
+/* 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 <fromsys.h>
+#include <defs.h>
+#include <banal.h>
+#include <splitfields.h>
+#include <datatypes.h>
+#include <bufvec.h>
+#include <cxops.h>
+#include <ringb.h>
+#include <chan.h>
+#include <lmadf.h>
+#include <fftw.h>
+#include <ovsv.h>
+#include <filter.h>
+#include <oscillator.h>
+#include <digitalagc.h>
+#include <am_demod.h>
+#include <fm_demod.h>
+#include <noiseblanker.h>
+#include <correctIQ.h>
+#include <crc16.h>
+#include <speechproc.h>
+#include <spottone.h>
+#include <update.h>
+
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
/* metermon.c */
-#include <chan.h>
+#include <common.h>
-#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);
}
//========================================================================
/* initialization and termination */
+void
+reset_meters(void) {
+ if (uni.meter.flag) { // reset metering completely
+ int i, k;
+ for (i = 0; i < RXMETERPTS; i++)
+ for (k = 0; k < MAXRX; k++)
+ uni.meter.rx.val[k][i] = uni.meter.rx.avg[k][i] = -200.0;
+ for (i = 0; i < TXMETERPTS; i++)
+ uni.meter.tx.val[i] = uni.meter.tx.avg[i] = -200.0;
+ }
+}
+
+void
+reset_spectrum(void) {
+ if (uni.spec.flag)
+ reinit_spectrum(&uni.spec);
+}
+
+void
+reset_counters(void) {
+ int k;
+ for (k = 0; k < uni.multirx.nrx; k++) rx[k].tick = 0;
+ tx.tick = 0;
+}
+
+//========================================================================
+
/* global and general info,
not specifically attached to
tx, rx, or scheduling */
PRIVATE void
setup_all(void) {
-
+
uni.samplerate = loc.def.rate;
uni.buflen = loc.def.size;
uni.mode.sdr = loc.def.mode;
uni.mode.trx = RX;
-
- if (uni.meter.flag) {
- uni.meter.chan.path = loc.path.meter;
- uni.meter.chan.size = loc.mult.ring * sizeof(REAL);
- uni.meter.val = -200.0;
- uni.meter.chan.c = openChan(uni.meter.chan.path, uni.meter.chan.size);
- }
-
+
uni.wisdom.path = loc.path.wisdom;
uni.wisdom.bits = FFTW_OUT_OF_PLACE | FFTW_ESTIMATE;
{
fclose(f);
}
}
-
+
+ if (uni.meter.flag) {
+ uni.meter.rx.type = SIGNAL_STRENGTH;
+ uni.meter.tx.type = SIGNAL_STRENGTH;
+ reset_meters();
+ }
+
+ uni.spec.rxk = 0;
+ uni.spec.buflen = uni.buflen;
+ uni.spec.scale = SPEC_PWR;
+ uni.spec.type = SPEC_POST_FILT;
+ uni.spec.size = loc.def.spec;
+ uni.spec.planbits = uni.wisdom.bits;
+ init_spectrum(&uni.spec);
+
+ // set which receiver is listening to commands
uni.multirx.lis = 0;
uni.multirx.nrx = loc.def.nrx;
-
+
+ // set mixing of input from aux ports
uni.mix.rx.flag = uni.mix.tx.flag = FALSE;
uni.mix.rx.gain = uni.mix.tx.gain = 1.0;
-
+
uni.tick = 0;
}
PRIVATE void
setup_rx(int k) {
-
+
/* conditioning */
rx[k].iqfix = newCorrectIQ(0.0, 1.0);
rx[k].filt.coef = newFIR_Bandpass_COMPLEX(-4800.0,
}
uni.multirx.act[0] = TRUE;
uni.multirx.nac = 1;
-
+
setup_tx();
}
}
/* all */
- if (uni.meter.flag)
- closeChan(uni.meter.chan.c);
+ finish_spectrum(&uni.spec);
}
//////////////////////////////////////////////////////////////////////////
//========================================================================
/* all */
-/* tap off S-meter from some buf */
+// unfortunate duplication here, due to
+// multirx vs monotx
PRIVATE void
-do_meter(COMPLEX *vec, int len) {
- int i;
+do_rx_meter(int k, CXB buf, int tap) {
+ COMPLEX *vec = CXBbase(buf);
+ int i, len = CXBhave(buf);
+
+ uni.meter.rx.val[k][tap] = 0;
+
+ switch (uni.meter.rx.type) {
+ case AVG_SIGNAL_STRENGTH:
+ for (i = 0; i < len; i++)
+ uni.meter.rx.val[k][tap] += Csqrmag(vec[i]);
+ uni.meter.rx.val[k][tap] =
+ uni.meter.rx.avg[k][tap] =
+ 0.9 * uni.meter.rx.avg[k][tap] + log10(uni.meter.rx.val[k][tap] + 1e-20);
+ break;
+ case SIGNAL_STRENGTH:
+ for (i = 0; i < len; i++)
+ uni.meter.rx.val[k][tap] += Csqrmag(vec[i]);
+ uni.meter.rx.avg[k][tap] =
+ uni.meter.rx.val[k][tap] =
+ 10.0 * log10(uni.meter.rx.val[k][tap] + 1e-20);
+ break;
+ case ADC_REAL:
+ for(i = 0; i < len; i++)
+ uni.meter.rx.val[k][tap] = max(fabs(vec[i].re), uni.meter.rx.val[k][tap]);
+ uni.meter.rx.val[k][tap] = 20.0 * log10(uni.meter.rx.val[k][tap] + 1e-10);
+ break;
+ case ADC_IMAG:
+ for(i = 0; i < len; i++)
+ uni.meter.rx.val[k][tap] = max(fabs(vec[i].im), uni.meter.rx.val[k][tap]);
+ uni.meter.rx.val[k][tap] = 20.0 * log10(uni.meter.rx.val[k][tap] + 1e-10);
+ break;
+ default:
+ break;
+ }
+}
+
+PRIVATE void
+do_tx_meter(CXB buf, int tap) {
+ COMPLEX *vec = CXBbase(buf);
+ int i, len = CXBhave(buf);
- uni.meter.val = 0;
+ uni.meter.tx.val[tap] = 0;
- switch (uni.meter.type) {
+ switch (uni.meter.tx.type) {
case AVG_SIGNAL_STRENGTH:
for (i = 0; i < len; i++)
- uni.meter.val += Csqrmag(vec[i]);
- uni.meter.val =
- uni.meter.avgval = 0.9 * uni.meter.avgval + log10(uni.meter.val + 1e-20);
+ uni.meter.tx.val[tap] += Csqrmag(vec[i]);
+ uni.meter.tx.val[tap] =
+ uni.meter.tx.avg[tap] =
+ 0.9 * uni.meter.tx.avg[tap] + log10(uni.meter.tx.val[tap] + 1e-20);
break;
case SIGNAL_STRENGTH:
for (i = 0; i < len; i++)
- uni.meter.val += Csqrmag(vec[i]);
- uni.meter.avgval = uni.meter.val = 10.0 * log10(uni.meter.val + 1e-20);
+ uni.meter.tx.val[tap] += Csqrmag(vec[i]);
+ uni.meter.tx.avg[tap] =
+ uni.meter.tx.val[tap] =
+ 10.0 * log10(uni.meter.tx.val[tap] + 1e-20);
break;
case ADC_REAL:
for(i = 0; i < len; i++)
- uni.meter.val = max(fabs(vec[i].re), uni.meter.val);
- uni.meter.val = 20.0 * log10(uni.meter.val + 1e-10);
+ uni.meter.tx.val[tap] = max(fabs(vec[i].re), uni.meter.tx.val[tap]);
+ uni.meter.tx.val[tap] = 20.0 * log10(uni.meter.tx.val[tap] + 1e-10);
break;
case ADC_IMAG:
for(i = 0; i < len; i++)
- uni.meter.val = max(fabs(vec[i].im), uni.meter.val);
- uni.meter.val = 20.0 * log10(uni.meter.val + 1e-10);
+ uni.meter.tx.val[tap] = max(fabs(vec[i].im), uni.meter.tx.val[tap]);
+ uni.meter.tx.val[tap] = 20.0 * log10(uni.meter.tx.val[tap] + 1e-10);
break;
default:
break;
}
+}
- putChan_nowait(uni.meter.chan.c,
- (char *) &uni.meter.val,
- sizeof(uni.meter.val));
+PRIVATE BOOLEAN
+do_rx_spectrum(int k, CXB buf, int type) {
+ if (uni.spec.flag && k == uni.spec.rxk && type == uni.spec.type) {
+ memcpy((char *) &CXBdata(uni.spec.accum, uni.spec.fill),
+ (char *) CXBbase(buf),
+ CXBhave(buf));
+ uni.spec.fill = (uni.spec.fill + uni.spec.buflen) % uni.spec.size;
+ }
+}
+
+PRIVATE void
+do_tx_spectrum(CXB buf) {
+ memcpy((char *) &CXBdata(uni.spec.accum, uni.spec.fill),
+ (char *) CXBbase(buf),
+ CXBhave(buf));
+ uni.spec.fill = (uni.spec.fill + uni.spec.buflen) % uni.spec.size;
}
//========================================================================
do_rx_pre(int k) {
int i, n = min(CXBhave(rx[k].buf.i), uni.buflen);
- //
- // do shrinkage here?
- //
-
if (rx[k].scl.pre.flag)
for (i = 0; i < n; i++)
CXBdata(rx[k].buf.i, i) = Cscl(CXBdata(rx[k].buf.i, i),
if (rx[k].nb.flag) noiseblanker(rx[k].nb.gen);
if (rx[k].nb_sdrom.flag) SDROMnoiseblanker(rx[k].nb_sdrom.gen);
+ // metering for uncorrected values here
+
+ do_rx_meter(k, rx[k].buf.i, RXMETER_PRE_CONV);
+
correctIQ(rx[k].buf.i, rx[k].iqfix);
/* 2nd IF conversion happens here */
OSCCdata(rx[k].osc.gen, i));
}
- /* filtering, metering, squelch, & AGC */
-
- if (rx[k].mode != SPEC) {
-
+ /* filtering, metering, spectrum, squelch, & AGC */
+
+ if (rx[k].mode == SPEC)
+
+ do_rx_spectrum(k, rx[k].buf.i, SPEC_SEMI_RAW);
+
+ else {
+
+ do_rx_meter(k, rx[k].buf.i, RXMETER_PRE_FILT);
+ do_rx_spectrum(k, rx[k].buf.i, SPEC_PRE_FILT);
+
if (rx[k].tick == 0)
reset_OvSv(rx[k].filt.ovsv);
filter_OvSv(rx[k].filt.ovsv);
CXBhave(rx[k].buf.o) = CXBhave(rx[k].buf.i);
-
- if (uni.meter.flag)
- do_meter(CXBbase(rx[k].buf.o), uni.buflen);
-
+
+ do_rx_meter(k, rx[k].buf.o, RXMETER_POST_FILT);
+ do_rx_spectrum(k, rx[k].buf.o, SPEC_POST_FILT);
+
if (should_do_rx_squelch(k))
do_squelch(k);
-
+
else if (rx[k].agc.flag)
DigitalAgc(rx[k].agc.gen, rx[k].tick);
-
- } else if (uni.meter.flag)
- do_meter(CXBbase(rx[k].buf.o), uni.buflen);
+
+ }
}
PRIVATE void
do_rx_post(int k) {
int i, n = CXBhave(rx[k].buf.o);
-
+
if (!rx[k].squelch.set) {
no_squelch(k);
// spotting tone
CXBdata(rx[k].spot.gen->buf, i));
}
}
-
+
// final scaling
-
+
if (rx[k].scl.post.flag)
for (i = 0; i < n; i++)
CXBdata(rx[k].buf.o, i) = Cscl(CXBdata(rx[k].buf.o, i),
rx[k].scl.post.val);
-
+
// not binaural?
// position in stereo field
-
+
if (!rx[k].bin.flag)
for (i = 0; i < n; i++)
CXBdata(rx[k].buf.o, i) = Cscl(rx[k].azim, CXBreal(rx[k].buf.o, i));
PRIVATE void
do_tx_pre(void) {
- if (tx.scl.pre.flag) {
- int i, n = CXBhave(tx.buf.i);
+if (tx.scl.pre.flag) {
+int i, n = CXBhave(tx.buf.i);
for (i = 0; i < n; i++)
CXBdata(tx.buf.i, i) = Cmplx(CXBreal(tx.buf.i, i) * tx.scl.pre.val, 0.0);
}
CXBhave(tx.buf.o) = CXBhave(tx.buf.i);
if (tx.agc.flag) DigitalAgc(tx.agc.gen, tx.tick);
+
+ // meter modulated signal
+
+ do_tx_meter(tx.buf.o, TXMETER_POST_MOD);
+
if (tx.scl.post.flag) {
int i, n = CXBhave(tx.buf.o);
for (i = 0; i < n; i++)
CXBdata(tx.buf.o, i) = Cscl(CXBdata(tx.buf.o, i), tx.scl.post.val);
}
- if (uni.meter.flag) do_meter(CXBbase(tx.buf.o), uni.buflen);
+
+ if (uni.spec.flag)
+ do_tx_spectrum(tx.buf.o);
+
if (tx.osc.gen->Frequency != 0.0) {
int i;
ComplexOSC(tx.osc.gen);
float *auxl, float *auxr,
int n) {
int i, k;
-
+
switch (uni.mode.trx) {
-
+
case RX:
-
+
// make copies of the input for all receivers
for (k = 0; k < uni.multirx.nrx; k++)
if (uni.multirx.act[k]) {
do_rx(k), rx[k].tick++;
// mix
for (i = 0; i < n; i++)
- bufl[i] += CXBimag(rx[k].buf.o, i),
+ bufl[i] += CXBimag(rx[k].buf.o, i),
bufr[i] += CXBreal(rx[k].buf.o, i);
CXBhave(rx[k].buf.o) = n;
}
+ // late mixing of aux buffers
if (uni.mix.rx.flag)
for (i = 0; i < n; i++)
bufl[i] += auxl[i] * uni.mix.rx.gain,
case TX:
+ // early mixing of aux buffers
if (uni.mix.tx.flag)
for (i = 0; i < n; i++)
bufl[i] += auxl[i] * uni.mix.tx.gain,
#ifndef _sdrexport_h
#define _sdrexport_h
-#include <common.h>
-
+#include <fromsys.h>
+#include <defs.h>
+#include <banal.h>
+#include <splitfields.h>
+#include <datatypes.h>
+#include <bufvec.h>
+#include <cxops.h>
+#include <ringb.h>
+#include <chan.h>
+#include <lmadf.h>
+#include <fftw.h>
+#include <ovsv.h>
+#include <filter.h>
+#include <oscillator.h>
+#include <digitalagc.h>
+#include <am_demod.h>
+#include <fm_demod.h>
+#include <noiseblanker.h>
+#include <correctIQ.h>
+#include <crc16.h>
+#include <speechproc.h>
+#include <spottone.h>
+#include <update.h>
+#include <local.h>
+#include <meter.h>
+#include <spectrum.h>
//------------------------------------------------------------------------
// 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 */
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;
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];
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
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
--- /dev/null
+/* specmon.c */
+
+#include <common.h>
+
+#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);
+}
--- /dev/null
+/* 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 <spectrum.h>
+
+// 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);
+ }
+}
--- /dev/null
+/* 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 <fromsys.h>
+#include <defs.h>
+#include <banal.h>
+#include <splitfields.h>
+#include <datatypes.h>
+#include <bufvec.h>
+#include <cxops.h>
+#include <ringb.h>
+#include <chan.h>
+#include <lmadf.h>
+#include <fftw.h>
+#include <ovsv.h>
+#include <filter.h>
+#include <oscillator.h>
+#include <digitalagc.h>
+#include <am_demod.h>
+#include <fm_demod.h>
+#include <noiseblanker.h>
+#include <correctIQ.h>
+#include <crc16.h>
+#include <speechproc.h>
+#include <spottone.h>
+#include <update.h>
+
+#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
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
}
// setMode <mode> [TRX]
-
PRIVATE int
setMode(int n, char **p) {
int mode = atoi(p[0]);
}
//============================================================
+// 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) {
// 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) {
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;
}
}
}
+// [pos] 0.0 <= pos <= 1.0
PRIVATE int
setRXPan(int n, char **p) {
REAL pos, theta;
}
}
+// [dB] NB both channels
PRIVATE int
setAuxMixGain(int n, char **p) {
if (n < 1) {
}
}
+//------------------------------------------------------------------------
+
+// [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 <thunk.h>
CTE update_cmds[] = {
+ {"reqMeter", reqMeter},
+ {"reqSpectrum", reqSpectrum},
{"setANF", setANF},
{"setANFvals", setANFvals},
{"setBIN", setBIN},
{"setRXPan", setRXPan},
{"setAuxMixSt", setAuxMixSt},
{"setAuxMixGain", setAuxMixGain},
+ {"setMeterType", setMeterType},
+ {"setSpectrumType", setSpectrumType},
{ 0, 0 }
};