]> git.rkrishnan.org Git - dttsp.git/blob - jDttSP/update.c
Minor fix to keyb, added hash function to banal.h, added aux input ports with settabl...
[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 int
387 f2x(REAL f) {
388   REAL fix = tx.filt.ovsv->fftlen * f / uni.samplerate;
389   return (int) (fix + 0.5);
390 }
391
392 //------------------------------------------------------------
393
394 PRIVATE void
395 apply_txeq_band(REAL lof, REAL dB, REAL hif) {
396   int i,
397       lox = f2x(lof),
398       hix = f2x(hif),
399       l = tx.filt.ovsv->fftlen;
400   REAL g = dB2lin(dB);
401   COMPLEX *src = tx.filt.save,
402           *trg = tx.filt.ovsv->zfvec;
403   for (i = lox; i < hix; i++) {
404     trg[i] = Cscl(src[i], g);
405     if (i) {
406       int j = l - i;
407       trg[j] = Cscl(src[j], g);
408     }
409   }
410 }
411
412 // typical:
413 // 0 dB1 75 dB2 150 dB3 300 dB4 600 dB5 1200 dB6 2000 dB7 2800 dB8 3600
414 // approximates W2IHY bandcenters.
415 // no args, revert to no EQ.
416
417 PRIVATE int
418 setTXEQ(int n, char **p) {
419   if (n < 3) {
420     // revert to no EQ
421     memcpy((char *) tx.filt.ovsv->zfvec,
422            (char *) tx.filt.save,
423            tx.filt.ovsv->fftlen * sizeof(COMPLEX));
424     return 0;
425   } else {
426     int i;
427     REAL lof = atof(p[0]);
428     for (i = 0; i < n - 2; i += 2) {
429       REAL dB = atof(p[i + 1]),
430            hif = atof(p[i + 2]);
431       if (lof < 0.0 || hif <= lof) return -1;
432       apply_txeq_band(lof, dB, hif);
433       lof = hif;
434     }
435     return 0;
436   }
437 }
438
439 //------------------------------------------------------------
440
441 PRIVATE void
442 apply_rxeq_band(REAL lof, REAL dB, REAL hif) {
443   int i,
444       lox = f2x(lof),
445       hix = f2x(hif),
446       l = rx[RL].filt.ovsv->fftlen;
447   REAL g = dB2lin(dB);
448   COMPLEX *src = rx[RL].filt.save,
449           *trg = rx[RL].filt.ovsv->zfvec;
450   for (i = lox; i < hix; i++) {
451     trg[i] = Cscl(src[i], g);
452     if (i) {
453       int j = l - i;
454       trg[j] = Cscl(src[j], g);
455     }
456   }
457 }
458
459 PRIVATE int
460 setRXEQ(int n, char **p) {
461   if (n < 3) {
462     // revert to no EQ
463     memcpy((char *) rx[RL].filt.ovsv->zfvec,
464            (char *) rx[RL].filt.save,
465            rx[RL].filt.ovsv->fftlen * sizeof(COMPLEX));
466     return 0;
467   } else {
468     int i;
469     REAL lof = atof(p[0]);
470     for (i = 0; i < n - 2; i += 2) {
471       REAL dB = atof(p[i + 1]),
472            hif = atof(p[i + 2]);
473       if (lof < 0.0 || hif <= lof) return -1;
474       apply_rxeq_band(lof, dB, hif);
475       lof = hif;
476     }
477     return 0;
478   }
479 }
480
481 //============================================================
482
483 PRIVATE int
484 setANFvals(int n, char **p) {
485   int taps  = atoi(p[0]),
486       delay = atoi(p[1]);
487   REAL gain = atof(p[2]),
488        leak = atof(p[3]);
489   rx[RL].anf.gen->adaptive_filter_size = taps;
490   rx[RL].anf.gen->delay = delay;
491   rx[RL].anf.gen->adaptation_rate = gain;
492   rx[RL].anf.gen->leakage = leak;
493   return 0;
494 }
495
496 PRIVATE int
497 setNRvals(int n, char **p) {
498   int taps  = atoi(p[0]),
499       delay = atoi(p[1]);
500   REAL gain = atof(p[2]),
501        leak = atof(p[3]);
502   rx[RL].anr.gen->adaptive_filter_size = taps;
503   rx[RL].anr.gen->delay = delay;
504   rx[RL].anr.gen->adaptation_rate = gain;
505   rx[RL].anr.gen->leakage = leak;
506   return 0;
507 }
508
509 PRIVATE int
510 setcorrectIQ(int n, char **p) {
511   int phaseadjustment = atoi(p[0]),
512       gainadjustment  = atoi(p[1]);
513   rx[RL].iqfix->phase = 0.001 * (REAL) phaseadjustment;
514   rx[RL].iqfix->gain  = 1.0+ 0.001 * (REAL) gainadjustment;
515   return 0;
516 }
517
518 PRIVATE int
519 setcorrectIQphase(int n, char **p) {
520   int phaseadjustment = atoi(p[0]);
521   rx[RL].iqfix->phase = 0.001 * (REAL) phaseadjustment;
522   return 0;
523 }
524
525 PRIVATE int
526 setcorrectIQgain(int n, char **p) {
527   int gainadjustment = atoi(p[0]);
528   rx[RL].iqfix->gain = 1.0 + 0.001 * (REAL) gainadjustment;
529   return 0;
530 }
531
532 PRIVATE int
533 setSquelch(int n, char **p) {
534   rx[RL].squelch.thresh = -atof(p[0]);
535   return 0;
536 }
537
538 PRIVATE int
539 setSquelchSt(int n, char **p) {
540   rx[RL].squelch.flag = atoi(p[0]);
541   return 0;
542 }
543
544 PRIVATE int
545 setTRX(int n, char **p) {
546   uni.mode.trx = atoi(p[0]);
547   return 0;
548 }
549
550 PRIVATE int
551 setRunState(int n, char **p) {
552   RUNMODE rs = (RUNMODE) atoi(p[0]);
553   top.state = rs;
554   return 0;
555 }
556
557 PRIVATE int
558 setSpotToneVals(int n, char **p) {
559   REAL gain = atof(p[0]),
560        freq = atof(p[1]),
561        rise = atof(p[2]),
562        fall = atof(p[3]);
563   setSpotToneGenVals(rx[RL].spot.gen, gain, freq, rise, fall);
564   return 0;
565 }
566
567 PRIVATE int
568 setSpotTone(int n, char **p) {
569   if (atoi(p[0])) {
570     SpotToneOn(rx[RL].spot.gen);
571     rx[RL].spot.flag = TRUE;
572   } else
573     SpotToneOff(rx[RL].spot.gen);
574   return 0;
575 }
576
577 PRIVATE int
578 setRXPreScl(int n, char **p) {
579   rx[RL].scl.pre.flag = atoi(p[0]);
580   return 0;
581 }
582
583 PRIVATE int
584 setRXPreSclVal(int n, char **p) {
585   rx[RL].scl.pre.val = dB2lin(atof(p[0]));
586   return 0;
587 }
588
589 PRIVATE int
590 setTXPreScl(int n, char **p) {
591   tx.scl.pre.flag = atoi(p[0]);
592   return 0;
593 }
594
595 PRIVATE int
596 setTXPreSclVal(int n, char **p) {
597   tx.scl.pre.val = dB2lin(atof(p[0]));
598   return 0;
599 }
600
601 PRIVATE int
602 setRXPostScl(int n, char **p) {
603   rx[RL].scl.post.flag = atoi(p[0]);
604   return 0;
605 }
606
607 PRIVATE int
608 setRXPostSclVal(int n, char **p) {
609   rx[RL].scl.post.val = dB2lin(atof(p[0]));
610   return 0;
611 }
612
613 PRIVATE int
614 setTXPostScl(int n, char **p) {
615   tx.scl.post.flag = atoi(p[0]);
616   return 0;
617 }
618
619 PRIVATE int
620 setTXPostSclVal(int n, char **p) {
621   tx.scl.post.val = dB2lin(atof(p[0]));
622   return 0;
623 }
624
625 PRIVATE int
626 setFinished(int n, char **p) {
627   top.running = FALSE;
628   pthread_cancel(top.thrd.trx.id);
629   pthread_cancel(top.thrd.upd.id);
630   pthread_cancel(top.thrd.mon.id);
631   return 0;
632 }
633
634 // next-trx-mode [nbufs-to-zap]
635 PRIVATE int
636 setSWCH(int n, char **p) {
637   top.swch.trx.next = atoi(p[0]);
638   if (n > 1) top.swch.bfct.want = atoi(p[1]);
639   else top.swch.bfct.want = 0;
640   top.swch.bfct.have = 0;
641   top.swch.run.last = top.state;
642   top.state = RUN_SWCH;
643   return 0;
644 }
645
646 PRIVATE int
647 setMonDump(int n, char **p) {
648   sem_post(&top.sync.mon.sem);
649   return 0;
650 }
651
652 PRIVATE int
653 setRingBufferReset(int n, char **p) {
654   extern void clear_jack_ringbuffer(jack_ringbuffer_t *rb, int nbytes);
655   jack_ringbuffer_reset(top.jack.ring.i.l);
656   jack_ringbuffer_reset(top.jack.ring.i.r);
657   jack_ringbuffer_reset(top.jack.ring.o.l);
658   jack_ringbuffer_reset(top.jack.ring.o.r);
659   clear_jack_ringbuffer(top.jack.ring.o.l, top.hold.size.bytes);
660   clear_jack_ringbuffer(top.jack.ring.o.r, top.hold.size.bytes);
661   return 0;
662 }
663
664 PRIVATE int
665 setRXListen(int n, char **p) {
666   int lis = atoi(p[0]);
667   if (lis < 0 || lis >= uni.multirx.nrx)
668     return -1;
669   else {
670     uni.multirx.lis = lis;
671     return 0;
672   }
673 }
674
675 PRIVATE int
676 setRXOn(int n, char **p) {
677   if (n < 1) {
678     if (uni.multirx.act[RL])
679       return -1;
680     else {
681       uni.multirx.act[RL] = TRUE;
682       uni.multirx.nac++;
683       rx[RL].tick = 0;
684       return 0;
685     }
686   } else {
687     int k = atoi(p[0]);
688     if (k < 0 || k >= uni.multirx.nrx)
689       return -1;
690     else {
691       if (uni.multirx.act[k])
692         return -1;
693       else {
694         uni.multirx.act[k] = TRUE;
695         uni.multirx.nac++;
696         rx[k].tick = 0;
697         return 0;
698       }
699     }
700   }
701 }
702
703 PRIVATE int
704 setRXOff(int n, char **p) {
705   if (n < 1) {
706     if (!uni.multirx.act[RL])
707       return -1;
708     else {
709       uni.multirx.act[RL] = FALSE;
710       --uni.multirx.nac;
711       return 0;
712     }
713   } else {
714     int k = atoi(p[0]);
715     if (k < 0 || k >= uni.multirx.nrx)
716       return -1;
717     else {
718       if (!uni.multirx.act[k])
719         return -1;
720       else {
721         uni.multirx.act[k] = FALSE;
722         --uni.multirx.nac;
723         return 0;
724       }
725     }
726   }
727 }
728
729 PRIVATE int
730 setRXPan(int n, char **p) {
731   REAL pos, theta;
732   if (n < 1) {
733     pos = 0.5;
734     theta = (1.0 - pos) * M_PI / 2.0;
735     rx[RL].azim = Cmplx(cos(theta), sin(theta));
736     return 0;
737   } else {
738     if ((pos = atof(p[0])) < 0.0 || pos > 1.0)
739       return -1;
740     theta = (1.0 - pos) * M_PI / 2.0;
741     rx[RL].azim = Cmplx(cos(theta), sin(theta));
742     return 0;
743   }
744 }
745
746 PRIVATE int
747 setAuxMix(int n, char **p) {
748   if (n < 1) {
749     uni.mix.rx = uni.mix.tx = 1.0;
750     return 0;
751   } else {
752     REAL gain = dB2lin(atof(p[0]));
753     if (n > 1) {
754       switch (atoi(p[1])) {
755       case TX: uni.mix.tx = gain; break;
756       case RX:
757       default: uni.mix.rx = gain; break;
758       }
759     } else
760       uni.mix.rx = uni.mix.tx = gain;
761     return 0;
762   }
763 }
764
765 //========================================================================
766
767 #include <thunk.h>
768
769 CTE update_cmds[] = {
770   {"setANF", setANF},
771   {"setANFvals", setANFvals},
772   {"setBIN", setBIN},
773   {"setFilter", setFilter},
774   {"setFinished", setFinished},
775   {"setMode", setMode},
776   {"setNB", setNB},
777   {"setNBvals", setNBvals},
778   {"setNR", setNR},
779   {"setNRvals", setNRvals},
780   {"setOsc", setOsc},
781   {"setRXAGC", setRXAGC},
782   {"setRXAGCCompression", setRXAGCCompression},
783   {"setRXAGCHang", setRXAGCHang},
784   {"setRXAGCLimit", setRXAGCLimit},
785   {"setRXEQ", setRXEQ},
786   {"setRXPostScl", setRXPostScl},
787   {"setRXPostSclVal", setRXPostSclVal},
788   {"setRXPreScl", setRXPreScl},
789   {"setRXPreSclVal", setRXPreSclVal},
790   {"setRunState", setRunState},
791   {"setSDROM", setSDROM},
792   {"setSDROMvals",setSDROMvals},
793   {"setSWCH", setSWCH},
794   {"setSampleRate", setSampleRate},
795   {"setSpotTone", setSpotTone},
796   {"setSpotToneVals", setSpotToneVals},
797   {"setSquelch", setSquelch},
798   {"setSquelchSt", setSquelchSt},
799   {"setTRX", setTRX},
800   {"setTXAGC", setTXAGC},
801   {"setTXAGCCompression", setTXAGCCompression},
802   {"setTXAGCFFCompression",setTXAGCFFCompression},
803   {"setTXAGCHang", setTXAGCHang},
804   {"setTXAGCLimit", setTXAGCLimit},
805   {"setTXEQ", setTXEQ},
806   {"setTXPostScl", setTXPostScl},
807   {"setTXPostSclVal", setTXPostSclVal},
808   {"setTXPreScl", setTXPreScl},
809   {"setTXPreSclVal", setTXPreSclVal},
810   {"setTXSpeechCompression", setTXSpeechCompression},
811   {"setTXSpeechCompressionGain", setTXSpeechCompressionGain},
812   {"setcorrectIQ", setcorrectIQ},
813   {"setcorrectIQgain", setcorrectIQgain},
814   {"setcorrectIQphase", setcorrectIQphase},
815   {"setfixedAGC", setfixedAGC},
816   {"setMonDump", setMonDump},
817   {"setRingBufferReset", setRingBufferReset},
818   {"setRXListen", setRXListen},
819   {"setRXOn", setRXOn},
820   {"setRXOff", setRXOff},
821   {"setRXPan", setRXPan},
822   {"setAuxMix", setAuxMix},
823   { 0, 0 }
824 };
825
826 //........................................................................
827
828 int
829 do_update(char *str, FILE *log) {
830   SPLIT splt = &uni.update.splt;
831
832   split(splt, str);
833
834   if (NF(splt) < 1) return -1;
835
836   else {
837     Thunk thk = Thunk_lookup(update_cmds, F(splt, 0));
838     if (!thk) return -1;
839     else {
840       int val;
841
842       sem_wait(&top.sync.upd.sem);
843       val = (*thk)(NF(splt) - 1, Fptr(splt, 1));
844       sem_post(&top.sync.upd.sem);
845
846       if (log) {
847         int i;
848         char *s = since(&top.start_tv);
849         fprintf(log, "update[%s]: returned %d from", s, val);
850         for (i = 0; i < NF(splt); i++)
851           fprintf(log, " %s", F(splt, i));
852         putc('\n', log);
853         fflush(log);
854       }
855
856       return val;
857     }
858   }
859 }