]> git.rkrishnan.org Git - dttsp.git/blob - jDttSP/update.c
cb6ae7a54c6f90df5dfe9097fd37497948c832d2
[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 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
145 PRIVATE int
146 setMode(int n, char **p) {
147   int mode = atoi(p[0]);
148   if (n > 1) {
149     int trx = atoi(p[1]);
150     switch (trx) {
151     case TX: tx.mode = mode; break;
152     case RX: 
153     default: rx[RL].mode = mode; break;
154     }
155   } else
156     tx.mode = rx[RL].mode = uni.mode.sdr = mode;
157   if (rx[RL].mode == AM) rx[RL].am.gen->mode = AMdet;
158   if (rx[RL].mode == SAM) rx[RL].am.gen->mode = SAMdet;
159   return 0;
160 }
161
162 // setOsc <freq> [TRX]
163 PRIVATE int
164 setOsc(int n, char **p) {
165   REAL newfreq = atof(p[0]);
166   if (fabs(newfreq) >= 0.5 * uni.samplerate) return -1;
167   newfreq *= 2.0 * M_PI / uni.samplerate;
168   if (n > 1) {
169     int trx = atoi(p[1]);
170     switch (trx) {
171     case TX: tx.osc.gen->Frequency = newfreq; break;
172     case RX:
173     default: rx[RL].osc.gen->Frequency = newfreq; break;
174     }
175   } else
176     tx.osc.gen->Frequency = rx[RL].osc.gen->Frequency = newfreq;
177   return 0;
178 }
179
180 PRIVATE int
181 setSampleRate(int n, char **p) {
182   REAL samplerate = atof(p[0]);
183   uni.samplerate = samplerate;
184   return 0;
185 }
186
187 PRIVATE int
188 setNR(int n, char **p) {
189   rx[RL].anr.flag = atoi(p[0]);
190   return 0;
191 }
192
193 PRIVATE int
194 setANF(int n, char **p) {
195   rx[RL].anf.flag = atoi(p[0]);
196   return 0;
197 }
198
199 PRIVATE int
200 setNB(int n, char **p) {
201   rx[RL].nb.flag = atoi(p[0]);
202   return 0;
203 }
204
205 PRIVATE int
206 setNBvals(int n, char **p) {
207   REAL threshold = atof(p[0]);
208   rx[RL].nb.gen->threshold = rx[RL].nb.thresh = threshold;
209   return 0;
210 }
211
212 PRIVATE int
213 setSDROM(int n, char **p) {
214   rx[RL].nb_sdrom.flag = atoi(p[0]);
215   return 0;
216 }
217
218 PRIVATE int
219 setSDROMvals(int n, char **p) {
220  REAL threshold = atof(p[0]);
221   rx[RL].nb_sdrom.gen->threshold = rx[RL].nb_sdrom.thresh = threshold;
222   return 0;
223 }
224
225 PRIVATE int
226 setBIN(int n, char **p) {
227   rx[RL].bin.flag = atoi(p[0]);
228   return 0;
229 }
230
231 // setfixedAGC <gain> [TRX]
232 PRIVATE int
233 setfixedAGC(int n, char **p) {
234   REAL gain = atof(p[0]);
235   if (n > 1) {
236     int trx = atoi(p[1]);
237     switch(trx) {
238     case TX: tx.agc.gen->gain.now = gain; break;
239     case RX:
240     default: rx[RL].agc.gen->gain.now = gain; break;
241     }
242   } else
243     tx.agc.gen->gain.now = rx[RL].agc.gen->gain.now = gain;
244   return 0;
245 }
246
247 PRIVATE int
248 setRXAGC(int n, char **p) {
249   int setit = atoi(p[0]);
250   switch (setit) {
251   case agcOFF:
252     rx[RL].agc.gen->mode = agcOFF;
253     rx[RL].agc.flag = TRUE;
254     break;
255   case agcSLOW:
256     rx[RL].agc.gen->mode = agcSLOW;
257     rx[RL].agc.gen->hang = 10;
258     rx[RL].agc.flag = TRUE;
259     break;
260   case agcMED:
261     rx[RL].agc.gen->mode = agcMED;
262     rx[RL].agc.gen->hang = 6;
263     rx[RL].agc.flag = TRUE;
264     break;
265   case agcFAST:
266     rx[RL].agc.gen->mode = agcFAST;
267     rx[RL].agc.gen->hang = 3;
268     rx[RL].agc.flag = TRUE;
269     break;
270   case agcLONG:
271     rx[RL].agc.gen->mode = agcLONG;
272     rx[RL].agc.gen->hang = 23;
273     rx[RL].agc.flag = TRUE;
274     break;
275   }
276   return 0;
277 }
278
279 PRIVATE int
280 setRXAGCCompression(int n, char **p) {
281   REAL rxcompression = atof(p[0]);
282   rx[RL].agc.gen->gain.top = pow(10.0 , rxcompression * 0.05);
283   return 0;
284 }
285
286 PRIVATE int
287 setRXAGCHang(int n, char **p) {
288   int hang = atoi(p[0]);
289   rx[RL].agc.gen->hang =
290     max(1,
291         min(23,
292             hang * uni.samplerate / (1e3 * uni.buflen)));
293   return 0;
294 }
295
296 PRIVATE int
297 setRXAGCLimit(int n, char **p) {
298   REAL limit = atof(p[0]);
299   rx[RL].agc.gen->gain.lim = 0.001 * limit;
300   return 0;
301 }
302
303 PRIVATE int
304 setTXAGC(int n, char **p) {
305   int setit = atoi(p[0]);
306   switch (setit) {
307   case agcOFF:
308     tx.agc.gen->mode = agcOFF;
309     tx.agc.flag = FALSE;
310     break;
311   case agcSLOW:
312     tx.agc.gen->mode = agcSLOW;
313     tx.agc.gen->hang = 10;
314     tx.agc.flag = TRUE;
315     break;
316   case agcMED:
317     tx.agc.gen->mode = agcMED;
318     tx.agc.gen->hang = 6;
319     tx.agc.flag = TRUE;
320     break;
321   case agcFAST:
322     tx.agc.gen->mode = agcFAST;
323     tx.agc.gen->hang = 3;
324     tx.agc.flag = TRUE;
325     break;
326   case agcLONG:
327     tx.agc.gen->mode = agcLONG;
328     tx.agc.gen->hang = 23;
329     tx.agc.flag = TRUE;
330     break;
331   }
332   return 0;
333 }
334
335 PRIVATE int
336 setTXAGCCompression(int n, char **p) {
337   REAL txcompression = atof(p[0]);
338   tx.agc.gen->gain.top = pow(10.0 , txcompression * 0.05);
339   return 0;
340 }
341
342 PRIVATE int
343 setTXAGCFF(int n, char **p) {
344   tx.spr.flag = atoi(p[0]);
345   return 0;
346 }
347
348 PRIVATE int
349 setTXAGCFFCompression(int n, char **p) {
350   REAL txcompression = atof(p[0]);
351   tx.spr.gen->MaxGain = pow(10.0 , txcompression * 0.05);
352   return 0;
353 }
354
355 PRIVATE int
356 setTXAGCHang(int n, char **p) {
357   int hang = atoi(p[0]);
358   tx.agc.gen->hang =
359     max(1,
360         min(23,
361             hang * uni.samplerate / (1e3 * uni.buflen)));
362   return 0;
363 }
364
365 PRIVATE int
366 setTXAGCLimit(int n, char **p) {
367   REAL limit = atof(p[0]);
368   tx.agc.gen->gain.lim = 0.001 * limit;
369   return 0;
370 }
371
372 PRIVATE int
373 setTXSpeechCompression(int n, char **p) {
374   tx.spr.flag = atoi(p[0]);
375   return 0;
376 }
377
378 PRIVATE int
379 setTXSpeechCompressionGain(int n, char **p) {
380   tx.spr.gen->MaxGain = dB2lin(atof(p[0]));
381   return 0;
382 }
383
384 //============================================================
385
386 PRIVATE void
387 re_window(COMPLEX *vec, int len) {
388   int i;
389   REAL *win = newvec_REAL(len, "re_window win vec");
390   COMPLEX *ztmp = newvec_COMPLEX(len, "re_window z buf");
391
392   fftw_plan ptmp = fftw_create_plan(len, FFTW_BACKWARD, uni.wisdom.bits);
393   fftw_one(ptmp, (fftw_complex *) vec, (fftw_complex *) ztmp);
394   fftw_destroy_plan(ptmp);
395
396   (void) makewindow(BLACKMANHARRIS_WINDOW, len, win);
397
398   for (i = 0; i < len; i++)
399     ztmp[i] = Cscl(ztmp[i], win[i]);
400
401   ptmp = fftw_create_plan(len, FFTW_FORWARD, uni.wisdom.bits);
402   fftw_one(ptmp, (fftw_complex *) ztmp, (fftw_complex *) vec);
403   fftw_destroy_plan(ptmp);
404
405   delvec_COMPLEX(ztmp);
406   delvec_REAL(win);
407   
408   normalize_vec_COMPLEX(vec, len);
409 }
410
411 //============================================================
412
413 PRIVATE int
414 f2x(REAL f) {
415   REAL fix = tx.filt.ovsv->fftlen * f / uni.samplerate;
416   return (int) (fix + 0.5);
417 }
418
419 //------------------------------------------------------------
420
421 PRIVATE void
422 apply_txeq_band(REAL lof, REAL dB, REAL hif) {
423   int i,
424       lox = f2x(lof),
425       hix = f2x(hif),
426       l = tx.filt.ovsv->fftlen;
427   REAL g = dB2lin(dB);
428   COMPLEX *src = tx.filt.save,
429           *trg = tx.filt.ovsv->zfvec;
430   for (i = lox; i < hix; i++) {
431     trg[i] = Cscl(src[i], g);
432     if (i) {
433       int j = l - i;
434       trg[j] = Cscl(src[j], g);
435     }
436   }
437 }
438
439 // typical:
440 // 0 dB1 75 dB2 150 dB3 300 dB4 600 dB5 1200 dB6 2000 dB7 2800 dB8 3600
441 // approximates W2IHY bandcenters.
442 // no args, revert to no EQ.
443
444 PRIVATE int
445 setTXEQ(int n, char **p) {
446   if (n < 3) {
447     // revert to no EQ
448     memcpy((char *) tx.filt.ovsv->zfvec,
449            (char *) tx.filt.save,
450            tx.filt.ovsv->fftlen * sizeof(COMPLEX));
451     return 0;
452   } else {
453     int i;
454     REAL lof = atof(p[0]);
455     for (i = 0; i < n - 2; i += 2) {
456       REAL dB = atof(p[i + 1]),
457            hif = atof(p[i + 2]);
458       if (lof < 0.0 || hif <= lof) return -1;
459       apply_txeq_band(lof, dB, hif);
460       lof = hif;
461     }
462     re_window(rx[RL].filt.ovsv->zfvec, rx[RL].filt.ovsv->fftlen);
463     return 0;
464   }
465 }
466
467 //------------------------------------------------------------
468
469 PRIVATE void
470 apply_rxeq_band(REAL lof, REAL dB, REAL hif) {
471   int i,
472       lox = f2x(lof),
473       hix = f2x(hif),
474       l = rx[RL].filt.ovsv->fftlen;
475   REAL g = dB2lin(dB);
476   COMPLEX *src = rx[RL].filt.save,
477           *trg = rx[RL].filt.ovsv->zfvec;
478   for (i = lox; i < hix; i++) {
479     trg[i] = Cscl(src[i], g);
480     if (i) {
481       int j = l - i;
482       trg[j] = Cscl(src[j], g);
483     }
484   }
485 }
486
487 PRIVATE int
488 setRXEQ(int n, char **p) {
489   if (n < 3) {
490     // revert to no EQ
491     memcpy((char *) rx[RL].filt.ovsv->zfvec,
492            (char *) rx[RL].filt.save,
493            rx[RL].filt.ovsv->fftlen * sizeof(COMPLEX));
494     return 0;
495   } else {
496     int i;
497     REAL lof = atof(p[0]);
498     for (i = 0; i < n - 2; i += 2) {
499       REAL dB = atof(p[i + 1]),
500            hif = atof(p[i + 2]);
501       if (lof < 0.0 || hif <= lof) return -1;
502       apply_rxeq_band(lof, dB, hif);
503       lof = hif;
504     }
505     re_window(rx[RL].filt.ovsv->zfvec, rx[RL].filt.ovsv->fftlen);
506     return 0;
507   }
508 }
509
510 //============================================================
511
512 PRIVATE int
513 setANFvals(int n, char **p) {
514   int taps  = atoi(p[0]),
515       delay = atoi(p[1]);
516   REAL gain = atof(p[2]),
517        leak = atof(p[3]);
518   rx[RL].anf.gen->adaptive_filter_size = taps;
519   rx[RL].anf.gen->delay = delay;
520   rx[RL].anf.gen->adaptation_rate = gain;
521   rx[RL].anf.gen->leakage = leak;
522   return 0;
523 }
524
525 PRIVATE int
526 setNRvals(int n, char **p) {
527   int taps  = atoi(p[0]),
528       delay = atoi(p[1]);
529   REAL gain = atof(p[2]),
530        leak = atof(p[3]);
531   rx[RL].anr.gen->adaptive_filter_size = taps;
532   rx[RL].anr.gen->delay = delay;
533   rx[RL].anr.gen->adaptation_rate = gain;
534   rx[RL].anr.gen->leakage = leak;
535   return 0;
536 }
537
538 PRIVATE int
539 setcorrectIQ(int n, char **p) {
540   int phaseadjustment = atoi(p[0]),
541       gainadjustment  = atoi(p[1]);
542   rx[RL].iqfix->phase = 0.001 * (REAL) phaseadjustment;
543   rx[RL].iqfix->gain  = 1.0+ 0.001 * (REAL) gainadjustment;
544   return 0;
545 }
546
547 PRIVATE int
548 setcorrectIQphase(int n, char **p) {
549   int phaseadjustment = atoi(p[0]);
550   rx[RL].iqfix->phase = 0.001 * (REAL) phaseadjustment;
551   return 0;
552 }
553
554 PRIVATE int
555 setcorrectIQgain(int n, char **p) {
556   int gainadjustment = atoi(p[0]);
557   rx[RL].iqfix->gain = 1.0 + 0.001 * (REAL) gainadjustment;
558   return 0;
559 }
560
561 PRIVATE int
562 setSquelch(int n, char **p) {
563   rx[RL].squelch.thresh = -atof(p[0]);
564   return 0;
565 }
566
567 PRIVATE int
568 setSquelchSt(int n, char **p) {
569   rx[RL].squelch.flag = atoi(p[0]);
570   return 0;
571 }
572
573 PRIVATE int
574 setTRX(int n, char **p) {
575   uni.mode.trx = atoi(p[0]);
576   return 0;
577 }
578
579 PRIVATE int
580 setRunState(int n, char **p) {
581   RUNMODE rs = (RUNMODE) atoi(p[0]);
582   top.state = rs;
583   return 0;
584 }
585
586 PRIVATE int
587 setSpotToneVals(int n, char **p) {
588   REAL gain = atof(p[0]),
589        freq = atof(p[1]),
590        rise = atof(p[2]),
591        fall = atof(p[3]);
592   setSpotToneGenVals(rx[RL].spot.gen, gain, freq, rise, fall);
593   return 0;
594 }
595
596 PRIVATE int
597 setSpotTone(int n, char **p) {
598   if (atoi(p[0])) {
599     SpotToneOn(rx[RL].spot.gen);
600     rx[RL].spot.flag = TRUE;
601   } else
602     SpotToneOff(rx[RL].spot.gen);
603   return 0;
604 }
605
606 PRIVATE int
607 setRXPreScl(int n, char **p) {
608   rx[RL].scl.pre.flag = atoi(p[0]);
609   return 0;
610 }
611
612 PRIVATE int
613 setRXPreSclVal(int n, char **p) {
614   rx[RL].scl.pre.val = dB2lin(atof(p[0]));
615   return 0;
616 }
617
618 PRIVATE int
619 setTXPreScl(int n, char **p) {
620   tx.scl.pre.flag = atoi(p[0]);
621   return 0;
622 }
623
624 PRIVATE int
625 setTXPreSclVal(int n, char **p) {
626   tx.scl.pre.val = dB2lin(atof(p[0]));
627   return 0;
628 }
629
630 PRIVATE int
631 setRXPostScl(int n, char **p) {
632   rx[RL].scl.post.flag = atoi(p[0]);
633   return 0;
634 }
635
636 PRIVATE int
637 setRXPostSclVal(int n, char **p) {
638   rx[RL].scl.post.val = dB2lin(atof(p[0]));
639   return 0;
640 }
641
642 PRIVATE int
643 setTXPostScl(int n, char **p) {
644   tx.scl.post.flag = atoi(p[0]);
645   return 0;
646 }
647
648 PRIVATE int
649 setTXPostSclVal(int n, char **p) {
650   tx.scl.post.val = dB2lin(atof(p[0]));
651   return 0;
652 }
653
654 PRIVATE int
655 setFinished(int n, char **p) {
656   top.running = FALSE;
657   pthread_cancel(top.thrd.trx.id);
658   pthread_cancel(top.thrd.upd.id);
659   pthread_cancel(top.thrd.mon.id);
660   return 0;
661 }
662
663 // next-trx-mode [nbufs-to-zap]
664 PRIVATE int
665 setSWCH(int n, char **p) {
666   top.swch.trx.next = atoi(p[0]);
667   if (n > 1) top.swch.bfct.want = atoi(p[1]);
668   else top.swch.bfct.want = 0;
669   top.swch.bfct.have = 0;
670   top.swch.run.last = top.state;
671   top.state = RUN_SWCH;
672   return 0;
673 }
674
675 PRIVATE int
676 setMonDump(int n, char **p) {
677   sem_post(&top.sync.mon.sem);
678   return 0;
679 }
680
681 PRIVATE int
682 setRingBufferReset(int n, char **p) {
683   extern void clear_jack_ringbuffer(jack_ringbuffer_t *rb, int nbytes);
684   jack_ringbuffer_reset(top.jack.ring.i.l);
685   jack_ringbuffer_reset(top.jack.ring.i.r);
686   jack_ringbuffer_reset(top.jack.ring.o.l);
687   jack_ringbuffer_reset(top.jack.ring.o.r);
688   clear_jack_ringbuffer(top.jack.ring.o.l, top.hold.size.bytes);
689   clear_jack_ringbuffer(top.jack.ring.o.r, top.hold.size.bytes);
690   return 0;
691 }
692
693 PRIVATE int
694 setRXListen(int n, char **p) {
695   int lis = atoi(p[0]);
696   if (lis < 0 || lis >= uni.multirx.nrx)
697     return -1;
698   else {
699     uni.multirx.lis = lis;
700     return 0;
701   }
702 }
703
704 PRIVATE int
705 setRXOn(int n, char **p) {
706   if (n < 1) {
707     if (uni.multirx.act[RL])
708       return -1;
709     else {
710       uni.multirx.act[RL] = TRUE;
711       uni.multirx.nac++;
712       rx[RL].tick = 0;
713       return 0;
714     }
715   } else {
716     int k = atoi(p[0]);
717     if (k < 0 || k >= uni.multirx.nrx)
718       return -1;
719     else {
720       if (uni.multirx.act[k])
721         return -1;
722       else {
723         uni.multirx.act[k] = TRUE;
724         uni.multirx.nac++;
725         rx[k].tick = 0;
726         return 0;
727       }
728     }
729   }
730 }
731
732 PRIVATE int
733 setRXOff(int n, char **p) {
734   if (n < 1) {
735     if (!uni.multirx.act[RL])
736       return -1;
737     else {
738       uni.multirx.act[RL] = FALSE;
739       --uni.multirx.nac;
740       return 0;
741     }
742   } else {
743     int k = atoi(p[0]);
744     if (k < 0 || k >= uni.multirx.nrx)
745       return -1;
746     else {
747       if (!uni.multirx.act[k])
748         return -1;
749       else {
750         uni.multirx.act[k] = FALSE;
751         --uni.multirx.nac;
752         return 0;
753       }
754     }
755   }
756 }
757
758 PRIVATE int
759 setRXPan(int n, char **p) {
760   REAL pos, theta;
761   if (n < 1) {
762     pos = 0.5;
763     theta = (1.0 - pos) * M_PI / 2.0;
764     rx[RL].azim = Cmplx(cos(theta), sin(theta));
765     return 0;
766   } else {
767     if ((pos = atof(p[0])) < 0.0 || pos > 1.0)
768       return -1;
769     theta = (1.0 - pos) * M_PI / 2.0;
770     rx[RL].azim = Cmplx(cos(theta), sin(theta));
771     return 0;
772   }
773 }
774
775 PRIVATE int
776 setAuxMixSt(int n, char **p) {
777   if (n < 1) {
778     uni.mix.rx.flag = uni.mix.tx.flag = FALSE;
779     return 0;
780   } else {
781     BOOLEAN flag = atoi(p[0]);
782     if (n > 1) {
783       switch (atoi(p[1])) {
784       case TX: uni.mix.tx.flag = flag; break;
785       case RX:
786       default: uni.mix.rx.flag = flag; break;
787       }
788     } else
789       uni.mix.rx.flag = uni.mix.tx.flag = flag;
790     return 0;
791   }
792 }
793
794 PRIVATE int
795 setAuxMixGain(int n, char **p) {
796   if (n < 1) {
797     uni.mix.rx.gain = uni.mix.tx.gain = 1.0;
798     return 0;
799   } else {
800     REAL gain = dB2lin(atof(p[0]));
801     if (n > 1) {
802       switch (atoi(p[1])) {
803       case TX: uni.mix.tx.gain = gain; break;
804       case RX:
805       default: uni.mix.rx.gain = gain; break;
806       }
807     } else
808       uni.mix.rx.gain = uni.mix.tx.gain = gain;
809     return 0;
810   }
811 }
812
813 //========================================================================
814
815 #include <thunk.h>
816
817 CTE update_cmds[] = {
818   {"setANF", setANF},
819   {"setANFvals", setANFvals},
820   {"setBIN", setBIN},
821   {"setFilter", setFilter},
822   {"setFinished", setFinished},
823   {"setMode", setMode},
824   {"setNB", setNB},
825   {"setNBvals", setNBvals},
826   {"setNR", setNR},
827   {"setNRvals", setNRvals},
828   {"setOsc", setOsc},
829   {"setRXAGC", setRXAGC},
830   {"setRXAGCCompression", setRXAGCCompression},
831   {"setRXAGCHang", setRXAGCHang},
832   {"setRXAGCLimit", setRXAGCLimit},
833   {"setRXEQ", setRXEQ},
834   {"setRXPostScl", setRXPostScl},
835   {"setRXPostSclVal", setRXPostSclVal},
836   {"setRXPreScl", setRXPreScl},
837   {"setRXPreSclVal", setRXPreSclVal},
838   {"setRunState", setRunState},
839   {"setSDROM", setSDROM},
840   {"setSDROMvals",setSDROMvals},
841   {"setSWCH", setSWCH},
842   {"setSampleRate", setSampleRate},
843   {"setSpotTone", setSpotTone},
844   {"setSpotToneVals", setSpotToneVals},
845   {"setSquelch", setSquelch},
846   {"setSquelchSt", setSquelchSt},
847   {"setTRX", setTRX},
848   {"setTXAGC", setTXAGC},
849   {"setTXAGCCompression", setTXAGCCompression},
850   {"setTXAGCFFCompression",setTXAGCFFCompression},
851   {"setTXAGCHang", setTXAGCHang},
852   {"setTXAGCLimit", setTXAGCLimit},
853   {"setTXEQ", setTXEQ},
854   {"setTXPostScl", setTXPostScl},
855   {"setTXPostSclVal", setTXPostSclVal},
856   {"setTXPreScl", setTXPreScl},
857   {"setTXPreSclVal", setTXPreSclVal},
858   {"setTXSpeechCompression", setTXSpeechCompression},
859   {"setTXSpeechCompressionGain", setTXSpeechCompressionGain},
860   {"setcorrectIQ", setcorrectIQ},
861   {"setcorrectIQgain", setcorrectIQgain},
862   {"setcorrectIQphase", setcorrectIQphase},
863   {"setfixedAGC", setfixedAGC},
864   {"setMonDump", setMonDump},
865   {"setRingBufferReset", setRingBufferReset},
866   {"setRXListen", setRXListen},
867   {"setRXOn", setRXOn},
868   {"setRXOff", setRXOff},
869   {"setRXPan", setRXPan},
870   {"setAuxMixSt", setAuxMixSt},
871   {"setAuxMixGain", setAuxMixGain},
872   { 0, 0 }
873 };
874
875 //........................................................................
876
877 int
878 do_update(char *str, FILE *log) {
879   SPLIT splt = &uni.update.splt;
880
881   split(splt, str);
882
883   if (NF(splt) < 1) return -1;
884
885   else {
886     Thunk thk = Thunk_lookup(update_cmds, F(splt, 0));
887     if (!thk) return -1;
888     else {
889       int val;
890
891       sem_wait(&top.sync.upd.sem);
892       val = (*thk)(NF(splt) - 1, Fptr(splt, 1));
893       sem_post(&top.sync.upd.sem);
894
895       if (log) {
896         int i;
897         char *s = since(&top.start_tv);
898         fprintf(log, "update[%s]: returned %d from", s, val);
899         for (i = 0; i < NF(splt); i++)
900           fprintf(log, " %s", F(splt, i));
901         putc('\n', log);
902         fflush(log);
903       }
904
905       return val;
906     }
907   }
908 }