3 common defs and code for parm update
5 This file is part of a program that implements a Software-Defined Radio.
7 Copyright (C) 2004 by Frank Brickle, AB2KT and Bob McGwier, N4HY
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 The authors can be reached by email at
31 The DTTS Microwave Society
38 ////////////////////////////////////////////////////////////////////////////
41 dB2lin(REAL dB) { return pow(10.0, dB / 20.0); }
44 setRXFilter(int n, char **p) {
45 REAL low_frequency = atof(p[0]),
46 high_frequency = atof(p[1]);
47 int ncoef = uni.buflen + 1;
48 int i, fftlen = 2 * uni.buflen;
52 if (fabs(low_frequency) >= 0.5 * uni.samplerate) return -1;
53 if (fabs(high_frequency) >= 0.5 * uni.samplerate) return -2;
54 if ((low_frequency + 10) >= high_frequency) return -3;
55 delFIR_COMPLEX(rx.filt.coef);
57 rx.filt.coef = newFIR_Bandpass_COMPLEX(low_frequency,
62 zcvec = newvec_COMPLEX(fftlen, "filter z vec in setFilter");
63 ptmp = fftw_create_plan(fftlen, FFTW_FORWARD, uni.wisdom.bits);
65 for (i = 0; i < ncoef; i++) zcvec[i] = rx.filt.coef->coef[i];
67 for (i = 0; i < ncoef; i++) zcvec[fftlen - ncoef + i] = rx.filt.coef->coef[i];
69 fftw_one(ptmp, (fftw_complex *) zcvec, (fftw_complex *) rx.filt.ovsv->zfvec);
70 fftw_destroy_plan(ptmp);
71 delvec_COMPLEX(zcvec);
72 normalize_vec_COMPLEX(rx.filt.ovsv->zfvec,
73 rx.filt.ovsv->fftlen);
74 memcpy((char *) rx.filt.save,
75 (char *) rx.filt.ovsv->zfvec,
76 rx.filt.ovsv->fftlen * sizeof(COMPLEX));
83 setTXFilter(int n, char **p) {
84 REAL low_frequency = atof(p[0]),
85 high_frequency = atof(p[1]);
86 int ncoef = uni.buflen + 1;
87 int i, fftlen = 2 * uni.buflen;
91 if (fabs(low_frequency) >= 0.5 * uni.samplerate) return -1;
92 if (fabs(high_frequency) >= 0.5 * uni.samplerate) return -2;
93 if ((low_frequency + 10) >= high_frequency) return -3;
94 delFIR_COMPLEX(tx.filt.coef);
95 tx.filt.coef = newFIR_Bandpass_COMPLEX(low_frequency,
100 zcvec = newvec_COMPLEX(fftlen, "filter z vec in setFilter");
101 ptmp = fftw_create_plan(fftlen, FFTW_FORWARD, uni.wisdom.bits);
103 for (i = 0; i < ncoef; i++) zcvec[i] = tx.filt.coef->coef[i];
105 for (i = 0; i < ncoef; i++) zcvec[fftlen - ncoef + i] = tx.filt.coef->coef[i];
107 fftw_one(ptmp, (fftw_complex *) zcvec, (fftw_complex *) tx.filt.ovsv->zfvec);
108 fftw_destroy_plan(ptmp);
109 delvec_COMPLEX(zcvec);
110 normalize_vec_COMPLEX(tx.filt.ovsv->zfvec,
111 tx.filt.ovsv->fftlen);
112 memcpy((char *) tx.filt.save,
113 (char *) tx.filt.ovsv->zfvec,
114 tx.filt.ovsv->fftlen * sizeof(COMPLEX));
120 setFilter(int n, char **p) {
121 if (n == 2) return setRXFilter(n, p);
123 int trx = atoi(p[2]);
124 if (trx == RX) return setRXFilter(n, p);
125 else if (trx == TX) return setTXFilter(n, p);
130 // setMode <mode> [TRX]
133 setMode(int n, char **p) {
134 int mode = atoi(p[0]);
136 int trx = atoi(p[1]);
138 case TX: tx.mode = mode; break;
140 default: rx.mode = mode; break;
143 tx.mode = rx.mode = uni.mode.sdr = mode;
144 if (rx.mode == AM) rx.am.gen->mode = AMdet;
145 if (rx.mode == SAM) rx.am.gen->mode = SAMdet;
149 // setOsc <freq> [TRX]
151 setOsc(int n, char **p) {
152 REAL newfreq = atof(p[0]);
153 if (fabs(newfreq) >= 0.5 * uni.samplerate) return -1;
154 newfreq *= 2.0 * M_PI / uni.samplerate;
156 int trx = atoi(p[1]);
158 case TX: tx.osc.gen->Frequency = newfreq; break;
160 default: rx.osc.gen->Frequency = newfreq; break;
163 tx.osc.gen->Frequency = rx.osc.gen->Frequency = newfreq;
168 setSampleRate(int n, char **p) {
169 REAL samplerate = atof(p[0]);
170 uni.samplerate = samplerate;
175 setNR(int n, char **p) {
176 rx.anr.flag = atoi(p[0]);
181 setANF(int n, char **p) {
182 rx.anf.flag = atoi(p[0]);
187 setNB(int n, char **p) {
188 rx.nb.flag = atoi(p[0]);
193 setNBvals(int n, char **p) {
194 REAL threshold = atof(p[0]);
195 rx.nb.gen->threshold = rx.nb.thresh = threshold;
200 setSDROM(int n, char **p) {
201 rx.nb_sdrom.flag = atoi(p[0]);
206 setSDROMvals(int n, char **p) {
207 REAL threshold = atof(p[0]);
208 rx.nb_sdrom.gen->threshold = rx.nb_sdrom.thresh = threshold;
213 setBIN(int n, char **p) {
214 rx.bin.flag = atoi(p[0]);
218 // setfixedAGC <gain> [TRX]
220 setfixedAGC(int n, char **p) {
221 REAL gain = atof(p[0]);
223 int trx = atoi(p[1]);
225 case TX: tx.agc.gen->gain.now = gain; break;
227 default: rx.agc.gen->gain.now = gain; break;
230 tx.agc.gen->gain.now = rx.agc.gen->gain.now = gain;
235 setRXAGC(int n, char **p) {
236 int setit = atoi(p[0]);
239 rx.agc.gen->mode = agcOFF;
243 rx.agc.gen->mode = agcSLOW;
244 rx.agc.gen->hang = 10;
248 rx.agc.gen->mode = agcMED;
249 rx.agc.gen->hang = 6;
253 rx.agc.gen->mode = agcFAST;
254 rx.agc.gen->hang = 3;
258 rx.agc.gen->mode = agcLONG;
259 rx.agc.gen->hang = 23;
267 setRXAGCCompression(int n, char **p) {
268 REAL rxcompression = atof(p[0]);
269 rx.agc.gen->gain.top = pow(10.0 , rxcompression * 0.05);
274 setRXAGCHang(int n, char **p) {
275 int hang = atoi(p[0]);
279 hang * uni.samplerate / (1e3 * uni.buflen)));
284 setRXAGCLimit(int n, char **p) {
285 REAL limit = atof(p[0]);
286 rx.agc.gen->gain.lim = 0.001 * limit;
291 setTXAGC(int n, char **p) {
292 int setit = atoi(p[0]);
295 tx.agc.gen->mode = agcOFF;
299 tx.agc.gen->mode = agcSLOW;
300 tx.agc.gen->hang = 10;
304 tx.agc.gen->mode = agcMED;
305 tx.agc.gen->hang = 6;
309 tx.agc.gen->mode = agcFAST;
310 tx.agc.gen->hang = 3;
314 tx.agc.gen->mode = agcLONG;
315 tx.agc.gen->hang = 23;
323 setTXAGCCompression(int n, char **p) {
324 REAL txcompression = atof(p[0]);
325 tx.agc.gen->gain.top = pow(10.0 , txcompression * 0.05);
330 setTXAGCFF(int n, char **p) {
331 tx.spr.flag = atoi(p[0]);
336 setTXAGCFFCompression(int n, char **p) {
337 REAL txcompression = atof(p[0]);
338 tx.spr.gen->MaxGain = pow(10.0 , txcompression * 0.05);
343 setTXAGCHang(int n, char **p) {
344 int hang = atoi(p[0]);
348 hang * uni.samplerate / (1e3 * uni.buflen)));
353 setTXAGCLimit(int n, char **p) {
354 REAL limit = atof(p[0]);
355 tx.agc.gen->gain.lim = 0.001 * limit;
360 setTXSpeechCompression(int n, char **p) {
361 tx.spr.flag = atoi(p[0]);
366 setTXSpeechCompressionGain(int n, char **p) {
367 tx.spr.gen->MaxGain = dB2lin(atof(p[0]));
371 //============================================================
375 REAL fix = tx.filt.ovsv->fftlen * f / uni.samplerate;
376 return (int) (fix + 0.5);
379 //------------------------------------------------------------
382 apply_txeq_band(REAL lof, REAL dB, REAL hif) {
386 l = tx.filt.ovsv->fftlen;
388 COMPLEX *src = tx.filt.save,
389 *trg = tx.filt.ovsv->zfvec;
390 for (i = lox; i < hix; i++) {
391 trg[i] = Cscl(src[i], g);
394 trg[j] = Cscl(src[j], g);
400 // 0 dB1 75 dB2 150 dB3 300 dB4 600 dB5 1200 dB6 2000 dB7 2800 dB8 3600
401 // approximates W2IHY bandcenters.
402 // no args, revert to no EQ.
404 setTXEQ(int n, char **p) {
407 memcpy((char *) tx.filt.ovsv->zfvec,
408 (char *) tx.filt.save,
409 tx.filt.ovsv->fftlen * sizeof(COMPLEX));
413 REAL lof = atof(p[0]);
414 for (i = 0; i < n - 2; i += 2) {
415 REAL dB = atof(p[i + 1]),
416 hif = atof(p[i + 2]);
417 if (lof < 0.0 || hif <= lof) return -1;
418 apply_txeq_band(lof, dB, hif);
425 //------------------------------------------------------------
428 apply_rxeq_band(REAL lof, REAL dB, REAL hif) {
432 l = rx.filt.ovsv->fftlen;
434 COMPLEX *src = rx.filt.save,
435 *trg = rx.filt.ovsv->zfvec;
436 for (i = lox; i < hix; i++) {
437 trg[i] = Cscl(src[i], g);
440 trg[j] = Cscl(src[j], g);
446 setRXEQ(int n, char **p) {
449 memcpy((char *) rx.filt.ovsv->zfvec,
450 (char *) rx.filt.save,
451 rx.filt.ovsv->fftlen * sizeof(COMPLEX));
455 REAL lof = atof(p[0]);
456 for (i = 0; i < n - 2; i += 2) {
457 REAL dB = atof(p[i + 1]),
458 hif = atof(p[i + 2]);
459 if (lof < 0.0 || hif <= lof) return -1;
460 apply_rxeq_band(lof, dB, hif);
467 //============================================================
470 setANFvals(int n, char **p) {
471 int taps = atoi(p[0]),
473 REAL gain = atof(p[2]),
475 rx.anf.gen->adaptive_filter_size = taps;
476 rx.anf.gen->delay = delay;
477 rx.anf.gen->adaptation_rate = gain;
478 rx.anf.gen->leakage = leak;
483 setNRvals(int n, char **p) {
484 int taps = atoi(p[0]),
486 REAL gain = atof(p[2]),
488 rx.anr.gen->adaptive_filter_size = taps;
489 rx.anr.gen->delay = delay;
490 rx.anr.gen->adaptation_rate = gain;
491 rx.anr.gen->leakage = leak;
496 setcorrectIQ(int n, char **p) {
497 int phaseadjustment = atoi(p[0]),
498 gainadjustment = atoi(p[1]);
499 rx.iqfix->phase = 0.001 * (REAL) phaseadjustment;
500 rx.iqfix->gain = 1.0+ 0.001 * (REAL) gainadjustment;
505 setcorrectIQphase(int n, char **p) {
506 int phaseadjustment = atoi(p[0]);
507 rx.iqfix->phase = 0.001 * (REAL) phaseadjustment;
512 setcorrectIQgain(int n, char **p) {
513 int gainadjustment = atoi(p[0]);
514 rx.iqfix->gain = 1.0 + 0.001 * (REAL) gainadjustment;
519 setSquelch(int n, char **p) {
520 rx.squelch.thresh = -atof(p[0]);
525 setSquelchSt(int n, char **p) {
526 rx.squelch.flag = atoi(p[0]);
531 setTRX(int n, char **p) {
532 uni.mode.trx = atoi(p[0]);
537 setRunState(int n, char **p) {
538 RUNMODE rs = (RUNMODE) atoi(p[0]);
544 setSpotToneVals(int n, char **p) {
545 REAL gain = atof(p[0]),
549 setSpotToneGenVals(rx.spot.gen, gain, freq, rise, fall);
554 setSpotTone(int n, char **p) {
556 SpotToneOn(rx.spot.gen);
559 SpotToneOff(rx.spot.gen);
564 setRXPreScl(int n, char **p) {
565 rx.scl.pre.flag = atoi(p[0]);
570 setRXPreSclVal(int n, char **p) {
571 rx.scl.pre.val = dB2lin(atof(p[0]));
576 setTXPreScl(int n, char **p) {
577 tx.scl.pre.flag = atoi(p[0]);
582 setTXPreSclVal(int n, char **p) {
583 tx.scl.pre.val = dB2lin(atof(p[0]));
588 setRXPostScl(int n, char **p) {
589 rx.scl.post.flag = atoi(p[0]);
594 setRXPostSclVal(int n, char **p) {
595 rx.scl.post.val = dB2lin(atof(p[0]));
600 setTXPostScl(int n, char **p) {
601 tx.scl.post.flag = atoi(p[0]);
606 setTXPostSclVal(int n, char **p) {
607 tx.scl.post.val = dB2lin(atof(p[0]));
612 setFinished(int n, char **p) {
614 pthread_cancel(top.thrd.trx.id);
615 pthread_cancel(top.thrd.upd.id);
616 pthread_cancel(top.thrd.mon.id);
620 // next-trx-mode [nbufs-to-zap]
622 setSWCH(int n, char **p) {
623 top.swch.trx.next = atoi(p[0]);
624 if (n > 1) top.swch.bfct.want = atoi(p[1]);
625 else top.swch.bfct.want = 0;
626 top.swch.bfct.have = 0;
627 top.swch.run.last = top.state;
628 top.state = RUN_SWCH;
633 setMonDump(int n, char **p) {
634 sem_post(&top.sync.mon.sem);
639 setRingBufferReset(int n, char **p) {
640 extern void clear_jack_ringbuffer(jack_ringbuffer_t *rb, int nbytes);
641 jack_ringbuffer_reset(top.jack.ring.i.l);
642 jack_ringbuffer_reset(top.jack.ring.i.r);
643 jack_ringbuffer_reset(top.jack.ring.o.l);
644 jack_ringbuffer_reset(top.jack.ring.o.r);
645 clear_jack_ringbuffer(top.jack.ring.o.l, top.hold.size.bytes);
646 clear_jack_ringbuffer(top.jack.ring.o.r, top.hold.size.bytes);
650 //========================================================================
654 CTE update_cmds[] = {
656 {"setANFvals", setANFvals},
658 {"setFilter", setFilter},
659 {"setFinished", setFinished},
660 {"setMode", setMode},
662 {"setNBvals", setNBvals},
664 {"setNRvals", setNRvals},
666 {"setRXAGC", setRXAGC},
667 {"setRXAGCCompression", setRXAGCCompression},
668 {"setRXAGCHang", setRXAGCHang},
669 {"setRXAGCLimit", setRXAGCLimit},
670 {"setRXEQ", setRXEQ},
671 {"setRXPostScl", setRXPostScl},
672 {"setRXPostSclVal", setRXPostSclVal},
673 {"setRXPreScl", setRXPreScl},
674 {"setRXPreSclVal", setRXPreSclVal},
675 {"setRunState", setRunState},
676 {"setSDROM", setSDROM},
677 {"setSDROMvals",setSDROMvals},
678 {"setSWCH", setSWCH},
679 {"setSampleRate", setSampleRate},
680 {"setSpotTone", setSpotTone},
681 {"setSpotToneVals", setSpotToneVals},
682 {"setSquelch", setSquelch},
683 {"setSquelchSt", setSquelchSt},
685 {"setTXAGC", setTXAGC},
686 {"setTXAGCCompression", setTXAGCCompression},
687 {"setTXAGCFFCompression",setTXAGCFFCompression},
688 {"setTXAGCHang", setTXAGCHang},
689 {"setTXAGCLimit", setTXAGCLimit},
690 {"setTXEQ", setTXEQ},
691 {"setTXPostScl", setTXPostScl},
692 {"setTXPostSclVal", setTXPostSclVal},
693 {"setTXPreScl", setTXPreScl},
694 {"setTXPreSclVal", setTXPreSclVal},
695 {"setTXSpeechCompression", setTXSpeechCompression},
696 {"setTXSpeechCompressionGain", setTXSpeechCompressionGain},
697 {"setcorrectIQ", setcorrectIQ},
698 {"setcorrectIQgain", setcorrectIQgain},
699 {"setcorrectIQphase", setcorrectIQphase},
700 {"setfixedAGC", setfixedAGC},
701 {"setMonDump", setMonDump},
702 {"setRingBufferReset", setRingBufferReset},
706 //........................................................................
709 do_update(char *str, FILE *log) {
710 SPLIT splt = &uni.update.splt;
714 if (NF(splt) < 1) return -1;
717 Thunk thk = Thunk_lookup(update_cmds, F(splt, 0));
722 sem_wait(&top.sync.upd.sem);
723 val = (*thk)(NF(splt) - 1, Fptr(splt, 1));
724 sem_post(&top.sync.upd.sem);
728 char *s = since(&top.start_tv);
729 fprintf(log, "update[%s]: returned %d from", s, val);
730 for (i = 0; i < NF(splt); i++)
731 fprintf(log, " %s", F(splt, i));