]> git.rkrishnan.org Git - dttsp.git/blob - jDttSP/update.c
Added leading '-' to command strings to prevent echo to log
[dttsp.git] / jDttSP / update.c
1 /* update.c
2
3 common defs and code for parm update 
4    
5 This file is part of a program that implements a Software-Defined Radio.
6
7 Copyright (C) 2004-5 by Frank Brickle, AB2KT and Bob McGwier, N4HY
8
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.
13
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.
18
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
22
23 The authors can be reached by email at
24
25 ab2kt@arrl.net
26 or
27 rwmcgwier@comcast.net
28
29 or by paper mail at
30
31 The DTTS Microwave Society
32 6 Kathleen Place
33 Bridgewater, NJ 08807
34 */
35
36 #include <common.h>
37
38 ////////////////////////////////////////////////////////////////////////////
39 // for commands affecting RX, which RX is Listening
40
41 #define RL (uni.multirx.lis)
42
43 ////////////////////////////////////////////////////////////////////////////
44
45 PRIVATE REAL
46 dB2lin(REAL dB) { return pow(10.0, dB / 20.0); }
47
48 PRIVATE int
49 setRXFilter(int n, char **p) {
50   REAL low_frequency  = atof(p[0]),
51        high_frequency = atof(p[1]);
52   int ncoef = uni.buflen + 1;
53   int i, fftlen = 2 * uni.buflen;
54   fftw_plan ptmp;
55   COMPLEX *zcvec;
56
57   if (fabs(low_frequency) >= 0.5 * uni.samplerate) return -1;
58   if (fabs(high_frequency) >= 0.5 * uni.samplerate) return -2;
59   if ((low_frequency + 10) >= high_frequency) return -3;
60   delFIR_COMPLEX(rx[RL].filt.coef);
61
62   rx[RL].filt.coef = newFIR_Bandpass_COMPLEX(low_frequency,
63                                              high_frequency,
64                                              uni.samplerate,
65                                              ncoef);
66
67   zcvec = newvec_COMPLEX(fftlen, "filter z vec in setFilter");
68   ptmp = fftw_create_plan(fftlen, FFTW_FORWARD, uni.wisdom.bits);
69 #ifdef LHS
70   for (i = 0; i < ncoef; i++)
71     zcvec[i] = rx[RL].filt.coef->coef[i];
72 #else
73   for (i = 0; i < ncoef; i++)
74     zcvec[fftlen - ncoef + i] = rx[RL].filt.coef->coef[i];
75 #endif
76   fftw_one(ptmp,
77            (fftw_complex *) zcvec,
78            (fftw_complex *) rx[RL].filt.ovsv->zfvec);
79   fftw_destroy_plan(ptmp);
80   delvec_COMPLEX(zcvec);
81   normalize_vec_COMPLEX(rx[RL].filt.ovsv->zfvec,
82                         rx[RL].filt.ovsv->fftlen);
83   memcpy((char *) rx[RL].filt.save,
84          (char *) rx[RL].filt.ovsv->zfvec,
85          rx[RL].filt.ovsv->fftlen * sizeof(COMPLEX));
86
87   return 0;
88 }
89
90
91 PRIVATE int
92 setTXFilter(int n, char **p) {
93   REAL low_frequency  = atof(p[0]),
94        high_frequency = atof(p[1]);
95   int ncoef = uni.buflen + 1;
96   int i, fftlen = 2 * uni.buflen;
97   fftw_plan ptmp;
98   COMPLEX *zcvec;
99
100   if (fabs(low_frequency) >= 0.5 * uni.samplerate) return -1;
101   if (fabs(high_frequency) >= 0.5 * uni.samplerate) return -2;
102   if ((low_frequency + 10) >= high_frequency) return -3;
103   delFIR_COMPLEX(tx.filt.coef);
104   tx.filt.coef = newFIR_Bandpass_COMPLEX(low_frequency,
105                                          high_frequency,
106                                          uni.samplerate,
107                                          ncoef);
108   
109   zcvec = newvec_COMPLEX(fftlen, "filter z vec in setFilter");
110   ptmp = fftw_create_plan(fftlen, FFTW_FORWARD, uni.wisdom.bits);
111 #ifdef LHS
112   for (i = 0; i < ncoef; i++)
113     zcvec[i] = tx.filt.coef->coef[i];
114 #else
115   for (i = 0; i < ncoef; i++)
116     zcvec[fftlen - ncoef + i] = tx.filt.coef->coef[i];
117 #endif
118   fftw_one(ptmp,
119            (fftw_complex *) zcvec,
120            (fftw_complex *) tx.filt.ovsv->zfvec);
121   fftw_destroy_plan(ptmp);
122   delvec_COMPLEX(zcvec);
123   normalize_vec_COMPLEX(tx.filt.ovsv->zfvec,
124                         tx.filt.ovsv->fftlen);
125   memcpy((char *) tx.filt.save,
126          (char *) tx.filt.ovsv->zfvec,
127          tx.filt.ovsv->fftlen * sizeof(COMPLEX));
128
129   return 0;
130 }
131
132 PRIVATE int
133 setFilter(int n, char **p) {
134   if (n == 2) return setRXFilter(n, p);
135   else {
136     int trx = atoi(p[2]);
137     if      (trx == RX) return setRXFilter(n, p);
138     else if (trx == TX) return setTXFilter(n, p);
139     else                return -1;
140   }
141 }
142
143 // setMode <mode> [TRX]
144 PRIVATE int
145 setMode(int n, char **p) {
146   int mode = atoi(p[0]);
147   if (n > 1) {
148     int trx = atoi(p[1]);
149     switch (trx) {
150     case TX: tx.mode = mode; break;
151     case RX: 
152     default: rx[RL].mode = mode; break;
153     }
154   } else
155     tx.mode = rx[RL].mode = uni.mode.sdr = mode;
156   if (rx[RL].mode == AM) rx[RL].am.gen->mode = AMdet;
157   if (rx[RL].mode == SAM) rx[RL].am.gen->mode = SAMdet;
158   return 0;
159 }
160
161 // setOsc <freq> [TRX]
162 PRIVATE int
163 setOsc(int n, char **p) {
164   REAL newfreq = atof(p[0]);
165   if (fabs(newfreq) >= 0.5 * uni.samplerate) return -1;
166   newfreq *= 2.0 * M_PI / uni.samplerate;
167   if (n > 1) {
168     int trx = atoi(p[1]);
169     switch (trx) {
170     case TX: tx.osc.gen->Frequency = newfreq; break;
171     case RX:
172     default: rx[RL].osc.gen->Frequency = newfreq; break;
173     }
174   } else
175     tx.osc.gen->Frequency = rx[RL].osc.gen->Frequency = newfreq;
176   return 0;
177 }
178
179 PRIVATE int
180 setSampleRate(int n, char **p) {
181   REAL samplerate = atof(p[0]);
182   uni.samplerate = samplerate;
183   return 0;
184 }
185
186 PRIVATE int
187 setNR(int n, char **p) {
188   rx[RL].anr.flag = atoi(p[0]);
189   return 0;
190 }
191
192 PRIVATE int
193 setANF(int n, char **p) {
194   rx[RL].anf.flag = atoi(p[0]);
195   return 0;
196 }
197
198 PRIVATE int
199 setNB(int n, char **p) {
200   rx[RL].nb.flag = atoi(p[0]);
201   return 0;
202 }
203
204 PRIVATE int
205 setNBvals(int n, char **p) {
206   REAL threshold = atof(p[0]);
207   rx[RL].nb.gen->threshold = rx[RL].nb.thresh = threshold;
208   return 0;
209 }
210
211 PRIVATE int
212 setSDROM(int n, char **p) {
213   rx[RL].nb_sdrom.flag = atoi(p[0]);
214   return 0;
215 }
216
217 PRIVATE int
218 setSDROMvals(int n, char **p) {
219  REAL threshold = atof(p[0]);
220   rx[RL].nb_sdrom.gen->threshold = rx[RL].nb_sdrom.thresh = threshold;
221   return 0;
222 }
223
224 PRIVATE int
225 setBIN(int n, char **p) {
226   rx[RL].bin.flag = atoi(p[0]);
227   return 0;
228 }
229
230 // setfixedAGC <gain> [TRX]
231 PRIVATE int
232 setfixedAGC(int n, char **p) {
233   REAL gain = atof(p[0]);
234   if (n > 1) {
235     int trx = atoi(p[1]);
236     switch(trx) {
237     case TX: tx.agc.gen->gain.now = gain; break;
238     case RX:
239     default: rx[RL].agc.gen->gain.now = gain; break;
240     }
241   } else
242     tx.agc.gen->gain.now = rx[RL].agc.gen->gain.now = gain;
243   return 0;
244 }
245
246 PRIVATE int
247 setRXAGC(int n, char **p) {
248   int setit = atoi(p[0]);
249   switch (setit) {
250   case agcOFF:
251     rx[RL].agc.gen->mode = agcOFF;
252     rx[RL].agc.flag = TRUE;
253     break;
254   case agcSLOW:
255     rx[RL].agc.gen->mode = agcSLOW;
256     rx[RL].agc.gen->hang = 10;
257     rx[RL].agc.flag = TRUE;
258     break;
259   case agcMED:
260     rx[RL].agc.gen->mode = agcMED;
261     rx[RL].agc.gen->hang = 6;
262     rx[RL].agc.flag = TRUE;
263     break;
264   case agcFAST:
265     rx[RL].agc.gen->mode = agcFAST;
266     rx[RL].agc.gen->hang = 3;
267     rx[RL].agc.flag = TRUE;
268     break;
269   case agcLONG:
270     rx[RL].agc.gen->mode = agcLONG;
271     rx[RL].agc.gen->hang = 23;
272     rx[RL].agc.flag = TRUE;
273     break;
274   }
275   return 0;
276 }
277
278 PRIVATE int
279 setRXAGCCompression(int n, char **p) {
280   REAL rxcompression = atof(p[0]);
281   rx[RL].agc.gen->gain.top = pow(10.0 , rxcompression * 0.05);
282   return 0;
283 }
284
285 PRIVATE int
286 setRXAGCHang(int n, char **p) {
287   int hang = atoi(p[0]);
288   rx[RL].agc.gen->hang =
289     max(1,
290         min(23,
291             hang * uni.samplerate / (1e3 * uni.buflen)));
292   return 0;
293 }
294
295 PRIVATE int
296 setRXAGCLimit(int n, char **p) {
297   REAL limit = atof(p[0]);
298   rx[RL].agc.gen->gain.lim = 0.001 * limit;
299   return 0;
300 }
301
302 PRIVATE int
303 setTXAGC(int n, char **p) {
304   int setit = atoi(p[0]);
305   switch (setit) {
306   case agcOFF:
307     tx.agc.gen->mode = agcOFF;
308     tx.agc.flag = FALSE;
309     break;
310   case agcSLOW:
311     tx.agc.gen->mode = agcSLOW;
312     tx.agc.gen->hang = 10;
313     tx.agc.flag = TRUE;
314     break;
315   case agcMED:
316     tx.agc.gen->mode = agcMED;
317     tx.agc.gen->hang = 6;
318     tx.agc.flag = TRUE;
319     break;
320   case agcFAST:
321     tx.agc.gen->mode = agcFAST;
322     tx.agc.gen->hang = 3;
323     tx.agc.flag = TRUE;
324     break;
325   case agcLONG:
326     tx.agc.gen->mode = agcLONG;
327     tx.agc.gen->hang = 23;
328     tx.agc.flag = TRUE;
329     break;
330   }
331   return 0;
332 }
333
334 PRIVATE int
335 setTXAGCCompression(int n, char **p) {
336   REAL txcompression = atof(p[0]);
337   tx.agc.gen->gain.top = pow(10.0 , txcompression * 0.05);
338   return 0;
339 }
340
341 PRIVATE int
342 setTXAGCFF(int n, char **p) {
343   tx.spr.flag = atoi(p[0]);
344   return 0;
345 }
346
347 PRIVATE int
348 setTXAGCFFCompression(int n, char **p) {
349   REAL txcompression = atof(p[0]);
350   tx.spr.gen->MaxGain = pow(10.0 , txcompression * 0.05);
351   return 0;
352 }
353
354 PRIVATE int
355 setTXAGCHang(int n, char **p) {
356   int hang = atoi(p[0]);
357   tx.agc.gen->hang =
358     max(1,
359         min(23,
360             hang * uni.samplerate / (1e3 * uni.buflen)));
361   return 0;
362 }
363
364 PRIVATE int
365 setTXAGCLimit(int n, char **p) {
366   REAL limit = atof(p[0]);
367   tx.agc.gen->gain.lim = 0.001 * limit;
368   return 0;
369 }
370
371 PRIVATE int
372 setTXSpeechCompression(int n, char **p) {
373   tx.spr.flag = atoi(p[0]);
374   return 0;
375 }
376
377 PRIVATE int
378 setTXSpeechCompressionGain(int n, char **p) {
379   tx.spr.gen->MaxGain = dB2lin(atof(p[0]));
380   return 0;
381 }
382
383 //============================================================
384 // some changes have been made to a transfer function in vec;
385 // apply time-domain window to counter possible artifacts
386
387 PRIVATE void
388 re_window(COMPLEX *vec, int len) {
389   int i;
390   REAL *win = newvec_REAL(len, "re_window win vec");
391   COMPLEX *ztmp = newvec_COMPLEX(len, "re_window z buf");
392
393   fftw_plan ptmp = fftw_create_plan(len, FFTW_BACKWARD, uni.wisdom.bits);
394   fftw_one(ptmp, (fftw_complex *) vec, (fftw_complex *) ztmp);
395   fftw_destroy_plan(ptmp);
396
397   (void) makewindow(BLACKMANHARRIS_WINDOW, len, win);
398
399   for (i = 0; i < len; i++)
400     ztmp[i] = Cscl(ztmp[i], win[i]);
401
402   ptmp = fftw_create_plan(len, FFTW_FORWARD, uni.wisdom.bits);
403   fftw_one(ptmp, (fftw_complex *) ztmp, (fftw_complex *) vec);
404   fftw_destroy_plan(ptmp);
405
406   delvec_COMPLEX(ztmp);
407   delvec_REAL(win);
408   
409   normalize_vec_COMPLEX(vec, len);
410 }
411
412 //============================================================
413
414 PRIVATE int
415 f2x(REAL f) {
416   REAL fix = tx.filt.ovsv->fftlen * f / uni.samplerate;
417   return (int) (fix + 0.5);
418 }
419
420 //------------------------------------------------------------
421
422 PRIVATE void
423 apply_txeq_band(REAL lof, REAL dB, REAL hif) {
424   int i,
425       lox = f2x(lof),
426       hix = f2x(hif),
427       l = tx.filt.ovsv->fftlen;
428   REAL g = dB2lin(dB);
429   COMPLEX *src = tx.filt.save,
430           *trg = tx.filt.ovsv->zfvec;
431   for (i = lox; i < hix; i++) {
432     trg[i] = Cscl(src[i], g);
433     if (i) {
434       int j = l - i;
435       trg[j] = Cscl(src[j], g);
436     }
437   }
438 }
439
440 // typical:
441 // 0 dB1 75 dB2 150 dB3 300 dB4 600 dB5 1200 dB6 2000 dB7 2800 dB8 3600
442 // approximates W2IHY bandcenters.
443 // no args, revert to no EQ.
444 // NB these are shelves, not linear or other splines
445
446 PRIVATE int
447 setTXEQ(int n, char **p) {
448   if (n < 3) {
449     // revert to no EQ
450     memcpy((char *) tx.filt.ovsv->zfvec,
451            (char *) tx.filt.save,
452            tx.filt.ovsv->fftlen * sizeof(COMPLEX));
453     return 0;
454   } else {
455     int i;
456     REAL lof = atof(p[0]);
457     for (i = 0; i < n - 2; i += 2) {
458       REAL dB = atof(p[i + 1]),
459            hif = atof(p[i + 2]);
460       if (lof < 0.0 || hif <= lof) return -1;
461       apply_txeq_band(lof, dB, hif);
462       lof = hif;
463     }
464     re_window(rx[RL].filt.ovsv->zfvec, rx[RL].filt.ovsv->fftlen);
465     return 0;
466   }
467 }
468
469 //------------------------------------------------------------
470
471 PRIVATE void
472 apply_rxeq_band(REAL lof, REAL dB, REAL hif) {
473   int i,
474       lox = f2x(lof),
475       hix = f2x(hif),
476       l = rx[RL].filt.ovsv->fftlen;
477   REAL g = dB2lin(dB);
478   COMPLEX *src = rx[RL].filt.save,
479           *trg = rx[RL].filt.ovsv->zfvec;
480   for (i = lox; i < hix; i++) {
481     trg[i] = Cscl(src[i], g);
482     if (i) {
483       int j = l - i;
484       trg[j] = Cscl(src[j], g);
485     }
486   }
487 }
488
489 PRIVATE int
490 setRXEQ(int n, char **p) {
491   if (n < 3) {
492     // revert to no EQ
493     memcpy((char *) rx[RL].filt.ovsv->zfvec,
494            (char *) rx[RL].filt.save,
495            rx[RL].filt.ovsv->fftlen * sizeof(COMPLEX));
496     return 0;
497   } else {
498     int i;
499     REAL lof = atof(p[0]);
500     for (i = 0; i < n - 2; i += 2) {
501       REAL dB = atof(p[i + 1]),
502            hif = atof(p[i + 2]);
503       if (lof < 0.0 || hif <= lof) return -1;
504       apply_rxeq_band(lof, dB, hif);
505       lof = hif;
506     }
507     re_window(rx[RL].filt.ovsv->zfvec, rx[RL].filt.ovsv->fftlen);
508     return 0;
509   }
510 }
511
512 //============================================================
513
514 PRIVATE int
515 setANFvals(int n, char **p) {
516   int taps  = atoi(p[0]),
517       delay = atoi(p[1]);
518   REAL gain = atof(p[2]),
519        leak = atof(p[3]);
520   rx[RL].anf.gen->adaptive_filter_size = taps;
521   rx[RL].anf.gen->delay = delay;
522   rx[RL].anf.gen->adaptation_rate = gain;
523   rx[RL].anf.gen->leakage = leak;
524   return 0;
525 }
526
527 PRIVATE int
528 setNRvals(int n, char **p) {
529   int taps  = atoi(p[0]),
530       delay = atoi(p[1]);
531   REAL gain = atof(p[2]),
532        leak = atof(p[3]);
533   rx[RL].anr.gen->adaptive_filter_size = taps;
534   rx[RL].anr.gen->delay = delay;
535   rx[RL].anr.gen->adaptation_rate = gain;
536   rx[RL].anr.gen->leakage = leak;
537   return 0;
538 }
539
540 PRIVATE int
541 setcorrectIQ(int n, char **p) {
542   int phaseadjustment = atoi(p[0]),
543       gainadjustment  = atoi(p[1]);
544   rx[RL].iqfix->phase = 0.001 * (REAL) phaseadjustment;
545   rx[RL].iqfix->gain  = 1.0+ 0.001 * (REAL) gainadjustment;
546   return 0;
547 }
548
549 PRIVATE int
550 setcorrectIQphase(int n, char **p) {
551   int phaseadjustment = atoi(p[0]);
552   rx[RL].iqfix->phase = 0.001 * (REAL) phaseadjustment;
553   return 0;
554 }
555
556 PRIVATE int
557 setcorrectIQgain(int n, char **p) {
558   int gainadjustment = atoi(p[0]);
559   rx[RL].iqfix->gain = 1.0 + 0.001 * (REAL) gainadjustment;
560   return 0;
561 }
562
563 PRIVATE int
564 setSquelch(int n, char **p) {
565   rx[RL].squelch.thresh = -atof(p[0]);
566   return 0;
567 }
568
569 PRIVATE int
570 setSquelchSt(int n, char **p) {
571   rx[RL].squelch.flag = atoi(p[0]);
572   return 0;
573 }
574
575 PRIVATE int
576 setTRX(int n, char **p) {
577   uni.mode.trx = atoi(p[0]);
578   return 0;
579 }
580
581 PRIVATE int
582 setRunState(int n, char **p) {
583   RUNMODE rs = (RUNMODE) atoi(p[0]);
584   top.state = rs;
585   return 0;
586 }
587
588 PRIVATE int
589 setSpotToneVals(int n, char **p) {
590   REAL gain = atof(p[0]),
591        freq = atof(p[1]),
592        rise = atof(p[2]),
593        fall = atof(p[3]);
594   setSpotToneGenVals(rx[RL].spot.gen, gain, freq, rise, fall);
595   return 0;
596 }
597
598 PRIVATE int
599 setSpotTone(int n, char **p) {
600   if (atoi(p[0])) {
601     SpotToneOn(rx[RL].spot.gen);
602     rx[RL].spot.flag = TRUE;
603   } else
604     SpotToneOff(rx[RL].spot.gen);
605   return 0;
606 }
607
608 PRIVATE int
609 setRXPreScl(int n, char **p) {
610   rx[RL].scl.pre.flag = atoi(p[0]);
611   return 0;
612 }
613
614 PRIVATE int
615 setRXPreSclVal(int n, char **p) {
616   rx[RL].scl.pre.val = dB2lin(atof(p[0]));
617   return 0;
618 }
619
620 PRIVATE int
621 setTXPreScl(int n, char **p) {
622   tx.scl.pre.flag = atoi(p[0]);
623   return 0;
624 }
625
626 PRIVATE int
627 setTXPreSclVal(int n, char **p) {
628   tx.scl.pre.val = dB2lin(atof(p[0]));
629   return 0;
630 }
631
632 PRIVATE int
633 setRXPostScl(int n, char **p) {
634   rx[RL].scl.post.flag = atoi(p[0]);
635   return 0;
636 }
637
638 PRIVATE int
639 setRXPostSclVal(int n, char **p) {
640   rx[RL].scl.post.val = dB2lin(atof(p[0]));
641   return 0;
642 }
643
644 PRIVATE int
645 setTXPostScl(int n, char **p) {
646   tx.scl.post.flag = atoi(p[0]);
647   return 0;
648 }
649
650 PRIVATE int
651 setTXPostSclVal(int n, char **p) {
652   tx.scl.post.val = dB2lin(atof(p[0]));
653   return 0;
654 }
655
656 PRIVATE int
657 setFinished(int n, char **p) {
658   top.running = FALSE;
659   pthread_cancel(top.thrd.trx.id);
660   pthread_cancel(top.thrd.mon.id);
661   pthread_cancel(top.thrd.pws.id);
662   pthread_cancel(top.thrd.mtr.id);
663   pthread_cancel(top.thrd.upd.id);
664   return 0;
665 }
666
667 // next-trx-mode [nbufs-to-zap]
668 PRIVATE int
669 setSWCH(int n, char **p) {
670   top.swch.trx.next = atoi(p[0]);
671   if (n > 1) top.swch.bfct.want = atoi(p[1]);
672   else top.swch.bfct.want = 0;
673   top.swch.bfct.have = 0;
674   top.swch.run.last = top.state;
675   top.state = RUN_SWCH;
676   return 0;
677 }
678
679 PRIVATE int
680 setMonDump(int n, char **p) {
681   sem_post(&top.sync.mon.sem);
682   return 0;
683 }
684
685 PRIVATE int
686 setRingBufferReset(int n, char **p) {
687   extern void clear_jack_ringbuffer(jack_ringbuffer_t *rb, int nbytes);
688   jack_ringbuffer_reset(top.jack.ring.i.l);
689   jack_ringbuffer_reset(top.jack.ring.i.r);
690   jack_ringbuffer_reset(top.jack.ring.o.l);
691   jack_ringbuffer_reset(top.jack.ring.o.r);
692   clear_jack_ringbuffer(top.jack.ring.o.l, top.hold.size.bytes);
693   clear_jack_ringbuffer(top.jack.ring.o.r, top.hold.size.bytes);
694   return 0;
695 }
696
697 PRIVATE int
698 setRXListen(int n, char **p) {
699   int lis = atoi(p[0]);
700   if (lis < 0 || lis >= uni.multirx.nrx)
701     return -1;
702   else {
703     uni.multirx.lis = lis;
704     return 0;
705   }
706 }
707
708 PRIVATE int
709 setRXOn(int n, char **p) {
710   if (n < 1) {
711     if (uni.multirx.act[RL])
712       return -1;
713     else {
714       uni.multirx.act[RL] = TRUE;
715       uni.multirx.nac++;
716       rx[RL].tick = 0;
717       return 0;
718     }
719   } else {
720     int k = atoi(p[0]);
721     if (k < 0 || k >= uni.multirx.nrx)
722       return -1;
723     else {
724       if (uni.multirx.act[k])
725         return -1;
726       else {
727         uni.multirx.act[k] = TRUE;
728         uni.multirx.nac++;
729         rx[k].tick = 0;
730         return 0;
731       }
732     }
733   }
734 }
735
736 PRIVATE int
737 setRXOff(int n, char **p) {
738   if (n < 1) {
739     if (!uni.multirx.act[RL])
740       return -1;
741     else {
742       uni.multirx.act[RL] = FALSE;
743       --uni.multirx.nac;
744       return 0;
745     }
746   } else {
747     int k = atoi(p[0]);
748     if (k < 0 || k >= uni.multirx.nrx)
749       return -1;
750     else {
751       if (!uni.multirx.act[k])
752         return -1;
753       else {
754         uni.multirx.act[k] = FALSE;
755         --uni.multirx.nac;
756         return 0;
757       }
758     }
759   }
760 }
761
762 // [pos]  0.0 <= pos <= 1.0
763 PRIVATE int
764 setRXPan(int n, char **p) {
765   REAL pos, theta;
766   if (n < 1) {
767     pos = 0.5;
768     theta = (1.0 - pos) * M_PI / 2.0;
769     rx[RL].azim = Cmplx(cos(theta), sin(theta));
770     return 0;
771   } else {
772     if ((pos = atof(p[0])) < 0.0 || pos > 1.0)
773       return -1;
774     theta = (1.0 - pos) * M_PI / 2.0;
775     rx[RL].azim = Cmplx(cos(theta), sin(theta));
776     return 0;
777   }
778 }
779
780 PRIVATE int
781 setAuxMixSt(int n, char **p) {
782   if (n < 1) {
783     uni.mix.rx.flag = uni.mix.tx.flag = FALSE;
784     return 0;
785   } else {
786     BOOLEAN flag = atoi(p[0]);
787     if (n > 1) {
788       switch (atoi(p[1])) {
789       case TX: uni.mix.tx.flag = flag; break;
790       case RX:
791       default: uni.mix.rx.flag = flag; break;
792       }
793     } else
794       uni.mix.rx.flag = uni.mix.tx.flag = flag;
795     return 0;
796   }
797 }
798
799 // [dB] NB both channels
800 PRIVATE int
801 setAuxMixGain(int n, char **p) {
802   if (n < 1) {
803     uni.mix.rx.gain = uni.mix.tx.gain = 1.0;
804     return 0;
805   } else {
806     REAL gain = dB2lin(atof(p[0]));
807     if (n > 1) {
808       switch (atoi(p[1])) {
809       case TX: uni.mix.tx.gain = gain; break;
810       case RX:
811       default: uni.mix.rx.gain = gain; break;
812       }
813     } else
814       uni.mix.rx.gain = uni.mix.tx.gain = gain;
815     return 0;
816   }
817 }
818
819 //------------------------------------------------------------------------
820
821 // [type]
822 PRIVATE int
823 setMeterType(int n, char **p) {
824   if (n < 1)
825     uni.meter.rx.type = SIGNAL_STRENGTH;
826   else {
827     METERTYPE type = (METERTYPE) atoi(p[0]);
828     if (n > 1) {
829       int trx = atoi(p[1]);
830       switch (trx) {
831       case TX: uni.meter.tx.type = type; break;
832       case RX:
833       default: uni.meter.rx.type = type; break;
834       }
835     } else
836        uni.meter.rx.type = type;
837   }
838   return 0;
839 }
840
841 // setSpectrumType [type [scale [rx]]]
842 PRIVATE int
843 setSpectrumType(int n, char **p) {
844   uni.spec.type  = SPEC_POST_FILT;
845   uni.spec.scale = SPEC_PWR;
846   uni.spec.rxk   = RL;
847   switch (n) {
848   case 3:
849     uni.spec.rxk   = atoi(p[2]);
850   case 2:
851     uni.spec.scale = atoi(p[1]);
852   case 1:
853     uni.spec.type  = atoi(p[0]);
854     break;
855   case 0:
856     return 0;
857   default:
858     return -1;
859   }
860 }
861
862 #if 0
863 PRIVATE int
864 setSpectrumType(int n, char **p) {
865   switch (n) {
866   case 3:
867     uni.spec.type = atoi(p[0]);
868     uni.spec.scale = atoi(p[1]);
869     uni.spec.rxk = atoi(p[2]);
870   case 2:
871     uni.spec.type = atoi(p[0]);
872     uni.spec.scale = atoi(p[1]);
873     uni.spec.rxk = RL;
874     break;
875   case 1:
876     uni.spec.type = atoi(p[0]);
877     uni.spec.scale = SPEC_PWR;
878     uni.spec.rxk = RL;
879     break;
880   case 0:
881     uni.spec.type = SPEC_POST_FILT;
882     uni.spec.scale = SPEC_PWR;
883     uni.spec.rxk = RL;
884     break;
885   default:
886     return -1;
887   }
888   return 0;
889 }
890 #endif
891
892 //========================================================================
893
894 // save current state while guarded by upd sem
895 PRIVATE int
896 reqMeter(int n, char **p) {
897   snap_meter(&uni.meter, n > 0 ? atoi(p[0]) : 0);
898   sem_post(&top.sync.mtr.sem);
899   return 0;
900 }
901
902 // simile modo
903 PRIVATE int
904 reqSpectrum(int n, char **p) {
905   snap_spectrum(&uni.spec, n > 0 ? atoi(p[0]) : 0);
906   sem_post(&top.sync.pws.sem);
907   return 0;
908 }
909
910 //========================================================================
911
912 #include <thunk.h>
913
914 CTE update_cmds[] = {
915   {"reqMeter", reqMeter},
916   {"reqSpectrum", reqSpectrum},
917   {"setANF", setANF},
918   {"setANFvals", setANFvals},
919   {"setBIN", setBIN},
920   {"setFilter", setFilter},
921   {"setFinished", setFinished},
922   {"setMode", setMode},
923   {"setNB", setNB},
924   {"setNBvals", setNBvals},
925   {"setNR", setNR},
926   {"setNRvals", setNRvals},
927   {"setOsc", setOsc},
928   {"setRXAGC", setRXAGC},
929   {"setRXAGCCompression", setRXAGCCompression},
930   {"setRXAGCHang", setRXAGCHang},
931   {"setRXAGCLimit", setRXAGCLimit},
932   {"setRXEQ", setRXEQ},
933   {"setRXPostScl", setRXPostScl},
934   {"setRXPostSclVal", setRXPostSclVal},
935   {"setRXPreScl", setRXPreScl},
936   {"setRXPreSclVal", setRXPreSclVal},
937   {"setRunState", setRunState},
938   {"setSDROM", setSDROM},
939   {"setSDROMvals",setSDROMvals},
940   {"setSWCH", setSWCH},
941   {"setSampleRate", setSampleRate},
942   {"setSpotTone", setSpotTone},
943   {"setSpotToneVals", setSpotToneVals},
944   {"setSquelch", setSquelch},
945   {"setSquelchSt", setSquelchSt},
946   {"setTRX", setTRX},
947   {"setTXAGC", setTXAGC},
948   {"setTXAGCCompression", setTXAGCCompression},
949   {"setTXAGCFFCompression",setTXAGCFFCompression},
950   {"setTXAGCHang", setTXAGCHang},
951   {"setTXAGCLimit", setTXAGCLimit},
952   {"setTXEQ", setTXEQ},
953   {"setTXPostScl", setTXPostScl},
954   {"setTXPostSclVal", setTXPostSclVal},
955   {"setTXPreScl", setTXPreScl},
956   {"setTXPreSclVal", setTXPreSclVal},
957   {"setTXSpeechCompression", setTXSpeechCompression},
958   {"setTXSpeechCompressionGain", setTXSpeechCompressionGain},
959   {"setcorrectIQ", setcorrectIQ},
960   {"setcorrectIQgain", setcorrectIQgain},
961   {"setcorrectIQphase", setcorrectIQphase},
962   {"setfixedAGC", setfixedAGC},
963   {"setMonDump", setMonDump},
964   {"setRingBufferReset", setRingBufferReset},
965   {"setRXListen", setRXListen},
966   {"setRXOn", setRXOn},
967   {"setRXOff", setRXOff},
968   {"setRXPan", setRXPan},
969   {"setAuxMixSt", setAuxMixSt},
970   {"setAuxMixGain", setAuxMixGain},
971   {"setMeterType", setMeterType},
972   {"setSpectrumType", setSpectrumType},
973   { 0, 0 }
974 };
975
976 //........................................................................
977
978 int
979 do_update(char *str, FILE *log) {
980   BOOLEAN quiet = FALSE;
981   SPLIT splt = &uni.update.splt;
982
983   if (*str == '-') {
984     quiet = TRUE;
985     str++;
986   }
987
988   split(splt, str);
989
990   if (NF(splt) < 1) return -1;
991
992   else {
993     Thunk thk = Thunk_lookup(update_cmds, F(splt, 0));
994     if (!thk) return -1;
995     else {
996       int val;
997
998       sem_wait(&top.sync.upd.sem);
999       val = (*thk)(NF(splt) - 1, Fptr(splt, 1));
1000       sem_post(&top.sync.upd.sem);
1001
1002       if (log && !quiet) {
1003         int i;
1004         char *s = since(&top.start_tv);
1005         fprintf(log, "update[%s]: returned %d from", s, val);
1006         for (i = 0; i < NF(splt); i++)
1007           fprintf(log, " %s", F(splt, i));
1008         putc('\n', log);
1009         fflush(log);
1010       }
1011
1012       return val;
1013     }
1014   }
1015 }