]> git.rkrishnan.org Git - dttsp.git/blob - jDttSP/update.c
Initial revision
[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
40 PRIVATE REAL
41 dB2lin(REAL dB) { return pow(10.0, dB / 20.0); }
42
43 PRIVATE int
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;
49   fftw_plan ptmp;
50   COMPLEX *zcvec;
51
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);
56
57   rx.filt.coef = newFIR_Bandpass_COMPLEX(low_frequency,
58                                          high_frequency,
59                                          uni.samplerate,
60                                          ncoef);
61
62   zcvec = newvec_COMPLEX(fftlen, "filter z vec in setFilter");
63   ptmp = fftw_create_plan(fftlen, FFTW_FORWARD, uni.wisdom.bits);
64 #ifdef LHS
65   for (i = 0; i < ncoef; i++) zcvec[i] = rx.filt.coef->coef[i];
66 #else
67   for (i = 0; i < ncoef; i++) zcvec[fftlen - ncoef + i] = rx.filt.coef->coef[i];
68 #endif
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));
77
78   return 0;
79 }
80
81
82 PRIVATE int
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;
88   fftw_plan ptmp;
89   COMPLEX *zcvec;
90
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,
96                                          high_frequency,
97                                          uni.samplerate,
98                                          ncoef);
99   
100   zcvec = newvec_COMPLEX(fftlen, "filter z vec in setFilter");
101   ptmp = fftw_create_plan(fftlen, FFTW_FORWARD, uni.wisdom.bits);
102 #ifdef LHS
103   for (i = 0; i < ncoef; i++) zcvec[i] = tx.filt.coef->coef[i];
104 #else
105   for (i = 0; i < ncoef; i++) zcvec[fftlen - ncoef + i] = tx.filt.coef->coef[i];
106 #endif
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));
115
116   return 0;
117 }
118
119 PRIVATE int
120 setFilter(int n, char **p) {
121   if (n == 2) return setRXFilter(n, p);
122   else {
123     int trx = atoi(p[2]);
124     if      (trx == RX) return setRXFilter(n, p);
125     else if (trx == TX) return setTXFilter(n, p);
126     else                return -1;
127   }
128 }
129
130 // setMode <mode> [TRX]
131
132 PRIVATE int
133 setMode(int n, char **p) {
134   int mode = atoi(p[0]);
135   if (n > 1) {
136     int trx = atoi(p[1]);
137     switch (trx) {
138     case TX: tx.mode = mode; break;
139     case RX: 
140     default: rx.mode = mode; break;
141     }
142   } else
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;
146   return 0;
147 }
148
149 // setOsc <freq> [TRX]
150 PRIVATE int
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;
155   if (n > 1) {
156     int trx = atoi(p[1]);
157     switch (trx) {
158     case TX: tx.osc.gen->Frequency = newfreq; break;
159     case RX:
160     default: rx.osc.gen->Frequency = newfreq; break;
161     }
162   } else
163     tx.osc.gen->Frequency = rx.osc.gen->Frequency = newfreq;
164   return 0;
165 }
166
167 PRIVATE int
168 setSampleRate(int n, char **p) {
169   REAL samplerate = atof(p[0]);
170   uni.samplerate = samplerate;
171   return 0;
172 }
173
174 PRIVATE int
175 setNR(int n, char **p) {
176   rx.anr.flag = atoi(p[0]);
177   return 0;
178 }
179
180 PRIVATE int
181 setANF(int n, char **p) {
182   rx.anf.flag = atoi(p[0]);
183   return 0;
184 }
185
186 PRIVATE int
187 setNB(int n, char **p) {
188   rx.nb.flag = atoi(p[0]);
189   return 0;
190 }
191
192 PRIVATE int
193 setNBvals(int n, char **p) {
194  REAL threshold = atof(p[0]);
195   rx.nb.gen->threshold = rx.nb.thresh = threshold;
196   return 0;
197 }
198
199 PRIVATE int
200 setSDROM(int n, char **p) {
201   rx.nb_sdrom.flag = atoi(p[0]);
202   return 0;
203 }
204
205 PRIVATE int
206 setSDROMvals(int n, char **p) {
207  REAL threshold = atof(p[0]);
208   rx.nb_sdrom.gen->threshold = rx.nb_sdrom.thresh = threshold;
209   return 0;
210 }
211
212 PRIVATE int
213 setBIN(int n, char **p) {
214   rx.bin.flag = atoi(p[0]);
215   return 0;
216 }
217
218 // setfixedAGC <gain> [TRX]
219 PRIVATE int
220 setfixedAGC(int n, char **p) {
221   REAL gain = atof(p[0]);
222   if (n > 1) {
223     int trx = atoi(p[1]);
224     switch(trx) {
225     case TX: tx.agc.gen->gain.now = gain; break;
226     case RX:
227     default: rx.agc.gen->gain.now = gain; break;
228     }
229   } else
230     tx.agc.gen->gain.now = rx.agc.gen->gain.now = gain;
231   return 0;
232 }
233
234 PRIVATE int
235 setRXAGC(int n, char **p) {
236   int setit = atoi(p[0]);
237   switch (setit) {
238   case agcOFF:
239     rx.agc.gen->mode = agcOFF;
240     rx.agc.flag = TRUE;
241     break;
242   case agcSLOW:
243     rx.agc.gen->mode = agcSLOW;
244     rx.agc.gen->hang = 10;
245     rx.agc.flag = TRUE;
246     break;
247   case agcMED:
248     rx.agc.gen->mode = agcMED;
249     rx.agc.gen->hang = 6;
250     rx.agc.flag = TRUE;
251     break;
252   case agcFAST:
253     rx.agc.gen->mode = agcFAST;
254     rx.agc.gen->hang = 3;
255     rx.agc.flag = TRUE;
256     break;
257   case agcLONG:
258     rx.agc.gen->mode = agcLONG;
259     rx.agc.gen->hang = 23;
260     rx.agc.flag = TRUE;
261     break;
262   }
263   return 0;
264 }
265
266 PRIVATE int
267 setRXAGCCompression(int n, char **p) {
268   REAL rxcompression = atof(p[0]);
269   rx.agc.gen->gain.top = pow(10.0 , rxcompression * 0.05);
270   return 0;
271 }
272
273 PRIVATE int
274 setRXAGCHang(int n, char **p) {
275   int hang = atoi(p[0]);
276   rx.agc.gen->hang =
277     max(1,
278         min(23,
279             hang * uni.samplerate / (1e3 * uni.buflen)));
280   return 0;
281 }
282
283 PRIVATE int
284 setRXAGCLimit(int n, char **p) {
285   REAL limit = atof(p[0]);
286   rx.agc.gen->gain.lim = 0.001 * limit;
287   return 0;
288 }
289
290 PRIVATE int
291 setTXAGC(int n, char **p) {
292   int setit = atoi(p[0]);
293   switch (setit) {
294   case agcOFF:
295     tx.agc.gen->mode = agcOFF;
296     tx.agc.flag = FALSE;
297     break;
298   case agcSLOW:
299     tx.agc.gen->mode = agcSLOW;
300     tx.agc.gen->hang = 10;
301     tx.agc.flag = TRUE;
302     break;
303   case agcMED:
304     tx.agc.gen->mode = agcMED;
305     tx.agc.gen->hang = 6;
306     tx.agc.flag = TRUE;
307     break;
308   case agcFAST:
309     tx.agc.gen->mode = agcFAST;
310     tx.agc.gen->hang = 3;
311     tx.agc.flag = TRUE;
312     break;
313   case agcLONG:
314     tx.agc.gen->mode = agcLONG;
315     tx.agc.gen->hang = 23;
316     tx.agc.flag = TRUE;
317     break;
318   }
319   return 0;
320 }
321
322 PRIVATE int
323 setTXAGCCompression(int n, char **p) {
324   REAL txcompression = atof(p[0]);
325   tx.agc.gen->gain.top = pow(10.0 , txcompression * 0.05);
326   return 0;
327 }
328
329 PRIVATE int
330 setTXAGCFF(int n, char **p) {
331   tx.spr.flag = atoi(p[0]);
332   return 0;
333 }
334
335 PRIVATE int
336 setTXAGCFFCompression(int n, char **p) {
337   REAL txcompression = atof(p[0]);
338   tx.spr.gen->MaxGain = pow(10.0 , txcompression * 0.05);
339   return 0;
340 }
341
342 PRIVATE int
343 setTXAGCHang(int n, char **p) {
344   int hang = atoi(p[0]);
345   tx.agc.gen->hang =
346     max(1,
347         min(23,
348             hang * uni.samplerate / (1e3 * uni.buflen)));
349   return 0;
350 }
351
352 PRIVATE int
353 setTXAGCLimit(int n, char **p) {
354   REAL limit = atof(p[0]);
355   tx.agc.gen->gain.lim = 0.001 * limit;
356   return 0;
357 }
358
359 PRIVATE int
360 setTXSpeechCompression(int n, char **p) {
361   tx.spr.flag = atoi(p[0]);
362   return 0;
363 }
364
365 PRIVATE int
366 setTXSpeechCompressionGain(int n, char **p) {
367   tx.spr.gen->MaxGain = dB2lin(atof(p[0]));
368   return 0;
369 }
370
371 //============================================================
372
373 PRIVATE int
374 f2x(REAL f) {
375   REAL fix = tx.filt.ovsv->fftlen * f / uni.samplerate;
376   return (int) (fix + 0.5);
377 }
378
379 //------------------------------------------------------------
380
381 PRIVATE void
382 apply_txeq_band(REAL lof, REAL dB, REAL hif) {
383   int i,
384       lox = f2x(lof),
385       hix = f2x(hif),
386       l = tx.filt.ovsv->fftlen;
387   REAL g = dB2lin(dB);
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);
392     if (i) {
393       int j = l - i;
394       trg[j] = Cscl(src[j], g);
395     }
396   }
397 }
398
399 // typical:
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.
403 PRIVATE int
404 setTXEQ(int n, char **p) {
405   if (n < 3) {
406     // revert to no EQ
407     memcpy((char *) tx.filt.ovsv->zfvec,
408            (char *) tx.filt.save,
409            tx.filt.ovsv->fftlen * sizeof(COMPLEX));
410     return 0;
411   } else {
412     int i;
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);
419       lof = hif;
420     }
421     return 0;
422   }
423 }
424
425 //------------------------------------------------------------
426
427 PRIVATE void
428 apply_rxeq_band(REAL lof, REAL dB, REAL hif) {
429   int i,
430       lox = f2x(lof),
431       hix = f2x(hif),
432       l = rx.filt.ovsv->fftlen;
433   REAL g = dB2lin(dB);
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);
438     if (i) {
439       int j = l - i;
440       trg[j] = Cscl(src[j], g);
441     }
442   }
443 }
444
445 PRIVATE int
446 setRXEQ(int n, char **p) {
447   if (n < 3) {
448     // revert to no EQ
449     memcpy((char *) rx.filt.ovsv->zfvec,
450            (char *) rx.filt.save,
451            rx.filt.ovsv->fftlen * sizeof(COMPLEX));
452     return 0;
453   } else {
454     int i;
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);
461       lof = hif;
462     }
463     return 0;
464   }
465 }
466
467 //============================================================
468
469 PRIVATE int
470 setANFvals(int n, char **p) {
471   int taps  = atoi(p[0]),
472       delay = atoi(p[1]);
473   REAL gain = atof(p[2]),
474        leak = atof(p[3]);
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;
479   return 0;
480 }
481
482 PRIVATE int
483 setNRvals(int n, char **p) {
484   int taps  = atoi(p[0]),
485       delay = atoi(p[1]);
486   REAL gain = atof(p[2]),
487        leak = atof(p[3]);
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;
492   return 0;
493 }
494
495 PRIVATE int
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;
501   return 0;
502 }
503
504 PRIVATE int
505 setcorrectIQphase(int n, char **p) {
506   int phaseadjustment = atoi(p[0]);
507   rx.iqfix->phase = 0.001 * (REAL) phaseadjustment;
508   return 0;
509 }
510
511 PRIVATE int
512 setcorrectIQgain(int n, char **p) {
513   int gainadjustment = atoi(p[0]);
514   rx.iqfix->gain = 1.0 + 0.001 * (REAL) gainadjustment;
515   return 0;
516 }
517
518 PRIVATE int
519 setSquelch(int n, char **p) {
520   rx.squelch.thresh = -atof(p[0]);
521   return 0;
522 }
523
524 PRIVATE int
525 setMeterOffset(int n, char **p) {
526   rx.squelch.offset.meter = atof(p[0]);
527   return 0;
528 }
529
530 PRIVATE int
531 setATTOffset(int n, char **p) {
532   rx.squelch.offset.att = atof(p[0]);
533   return 0;
534 }
535
536 PRIVATE int
537 setGainOffset(int n, char **p) {
538   rx.squelch.offset.gain = atof(p[0]);
539   return 0;
540 }
541
542 PRIVATE int
543 setSquelchSt(int n, char **p) {
544   rx.squelch.flag = atoi(p[0]);
545   return 0;
546 }
547
548 PRIVATE int
549 setTRX(int n, char **p) {
550   uni.mode.trx = atoi(p[0]);
551   return 0;
552 }
553
554 PRIVATE int
555 setRunState(int n, char **p) {
556   RUNMODE rs = (RUNMODE) atoi(p[0]);
557   top.state = rs;
558   return 0;
559 }
560
561 PRIVATE int
562 setSpotToneVals(int n, char **p) {
563   REAL gain = atof(p[0]),
564        freq = atof(p[1]),
565        rise = atof(p[2]),
566        fall = atof(p[3]);
567   setSpotToneGenVals(rx.spot.gen, gain, freq, rise, fall);
568   return 0;
569 }
570
571 PRIVATE int
572 setSpotTone(int n, char **p) {
573   if (atoi(p[0])) {
574     SpotToneOn(rx.spot.gen);
575     rx.spot.flag = TRUE;
576   } else
577     SpotToneOff(rx.spot.gen);
578   return 0;
579 }
580
581 PRIVATE int
582 setRXPreScl(int n, char **p) {
583   rx.scl.pre.flag = atoi(p[0]);
584   return 0;
585 }
586
587 PRIVATE int
588 setRXPreSclVal(int n, char **p) {
589   rx.scl.pre.val = dB2lin(atof(p[0]));
590   return 0;
591 }
592
593 PRIVATE int
594 setTXPreScl(int n, char **p) {
595   tx.scl.pre.flag = atoi(p[0]);
596   return 0;
597 }
598
599 PRIVATE int
600 setTXPreSclVal(int n, char **p) {
601   tx.scl.pre.val = dB2lin(atof(p[0]));
602   return 0;
603 }
604
605 PRIVATE int
606 setRXPostScl(int n, char **p) {
607   rx.scl.post.flag = atoi(p[0]);
608   return 0;
609 }
610
611 PRIVATE int
612 setRXPostSclVal(int n, char **p) {
613   rx.scl.post.val = dB2lin(atof(p[0]));
614   return 0;
615 }
616
617 PRIVATE int
618 setTXPostScl(int n, char **p) {
619   tx.scl.post.flag = atoi(p[0]);
620   return 0;
621 }
622
623 PRIVATE int
624 setTXPostSclVal(int n, char **p) {
625   tx.scl.post.val = dB2lin(atof(p[0]));
626   return 0;
627 }
628
629 PRIVATE int
630 setFinished(int n, char **p) {
631   top.running = FALSE;
632   pthread_cancel(top.thrd.trx.id);
633   pthread_cancel(top.thrd.upd.id);
634   pthread_cancel(top.thrd.mon.id);
635   return 0;
636 }
637
638 // next-trx-mode [nbufs-to-zap]
639 PRIVATE int
640 setSWCH(int n, char **p) {
641   top.swch.trx.next = atoi(p[0]);
642   if (n > 1) top.swch.bfct.want = atoi(p[1]);
643   else top.swch.bfct.want = 0;
644   top.swch.bfct.have = 0;
645   top.swch.run.last = top.state;
646   top.state = RUN_SWCH;
647   return 0;
648 }
649
650 PRIVATE int
651 setMonDump(int n, char **p) {
652   sem_post(&top.sync.mon.sem);
653   return 0;
654 }
655
656 PRIVATE int
657 setRingBufferReset(int n, char **p) {
658   extern void clear_jack_ringbuffer(jack_ringbuffer_t *rb, int nbytes);
659   jack_ringbuffer_reset(top.jack.ring.i.l);
660   jack_ringbuffer_reset(top.jack.ring.i.r);
661   jack_ringbuffer_reset(top.jack.ring.o.l);
662   jack_ringbuffer_reset(top.jack.ring.o.r);
663   clear_jack_ringbuffer(top.jack.ring.o.l, top.hold.size.bytes);
664   clear_jack_ringbuffer(top.jack.ring.o.r, top.hold.size.bytes);
665   return 0;
666 }
667
668 //========================================================================
669
670 #include <thunk.h>
671
672 CTE update_cmds[] = {
673   {"setANF", setANF},
674   {"setANFvals", setANFvals},
675   {"setATTOffset", setATTOffset},
676   {"setBIN", setBIN},
677   {"setFilter", setFilter},
678   {"setFinished", setFinished},
679   {"setGainOffset", setGainOffset},
680   {"setMeterOffset", setMeterOffset},
681   {"setMode", setMode},
682   {"setNB", setNB},
683   {"setNBvals", setNBvals},
684   {"setNR", setNR},
685   {"setNRvals", setNRvals},
686   {"setOsc", setOsc},
687   {"setRXAGC", setRXAGC},
688   {"setRXAGCCompression", setRXAGCCompression},
689   {"setRXAGCHang", setRXAGCHang},
690   {"setRXAGCLimit", setRXAGCLimit},
691   {"setRXEQ", setRXEQ},
692   {"setRXPostScl", setRXPostScl},
693   {"setRXPostSclVal", setRXPostSclVal},
694   {"setRXPreScl", setRXPreScl},
695   {"setRXPreSclVal", setRXPreSclVal},
696   {"setRunState", setRunState},
697   {"setSDROM", setSDROM},
698   {"setSDROMvals",setSDROMvals},
699   {"setSWCH", setSWCH},
700   {"setSampleRate", setSampleRate},
701   {"setSpotTone", setSpotTone},
702   {"setSpotToneVals", setSpotToneVals},
703   {"setSquelch", setSquelch},
704   {"setSquelchSt", setSquelchSt},
705   {"setTRX", setTRX},
706   {"setTXAGC", setTXAGC},
707   {"setTXAGCCompression", setTXAGCCompression},
708   {"setTXAGCFFCompression",setTXAGCFFCompression},
709   {"setTXAGCHang", setTXAGCHang},
710   {"setTXAGCLimit", setTXAGCLimit},
711   {"setTXEQ", setTXEQ},
712   {"setTXPostScl", setTXPostScl},
713   {"setTXPostSclVal", setTXPostSclVal},
714   {"setTXPreScl", setTXPreScl},
715   {"setTXPreSclVal", setTXPreSclVal},
716   {"setTXSpeechCompression", setTXSpeechCompression},
717   {"setTXSpeechCompressionGain", setTXSpeechCompressionGain},
718   {"setcorrectIQ", setcorrectIQ},
719   {"setcorrectIQgain", setcorrectIQgain},
720   {"setcorrectIQphase", setcorrectIQphase},
721   {"setfixedAGC", setfixedAGC},
722   {"setMonDump", setMonDump},
723   {"setRingBufferReset", setRingBufferReset},
724   { 0, 0 }
725 };
726
727 //........................................................................
728
729 int
730 do_update(char *str, FILE *log) {
731   SPLIT splt = &uni.update.splt;
732
733   split(splt, str);
734
735   if (NF(splt) < 1) return -1;
736
737   else {
738     Thunk thk = Thunk_lookup(update_cmds, F(splt, 0));
739     if (!thk) return -1;
740     else {
741       int val;
742
743       sem_wait(&top.sync.upd.sem);
744       val = (*thk)(NF(splt) - 1, Fptr(splt, 1));
745       sem_post(&top.sync.upd.sem);
746
747       if (log) {
748         int i;
749         char *s = since(&top.start_tv);
750         fprintf(log, "update[%s]: returned %d from", s, val);
751         for (i = 0; i < NF(splt); i++)
752           fprintf(log, " %s", F(splt, i));
753         putc('\n', log);
754         fflush(log);
755       }
756
757       return val;
758     }
759   }
760 }