1 // Copyright (c) <2012> <Leif Asbrink>
2 //
3 // Permission is hereby granted, free of charge, to any person
4 // obtaining a copy of this software and associated documentation
5 // files (the "Software"), to deal in the Software without restriction,
6 // including without limitation the rights to use, copy, modify,
7 // merge, publish, distribute, sublicense, and/or sell copies of
8 // the Software, and to permit persons to whom the Software is
9 // furnished to do so, subject to the following conditions:
10 //
11 // The above copyright notice and this permission notice shall be
12 // included in all copies or substantial portions of the Software.
13 //
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
16 // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
18 // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
19 // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
21 // OR OTHER DEALINGS IN THE SOFTWARE.
22 
23 
24 
25 #include <ctype.h>
26 #include <unistd.h>
27 #include "globdef.h"
28 #include "uidef.h"
29 #include "fft1def.h"
30 #include "fft2def.h"
31 #include "caldef.h"
32 #include "rusage.h"
33 #include "thrdef.h"
34 
35 #define INFOLINE 3
36 
cal_initscreen(void)37 void cal_initscreen(void)
38 {
39 int i;
40 char s[256];
41 clear_screen();
42 sprintf(s,"%s for %s. Press F1 or '!' for info.",cal_type_text[cal_type],
43                                                      rxmodes[rx_mode]);
44 for(i=0; i<screen_width*(2*MAX_ADCHAN); i++)cal_graph[i]=screen_height-1;
45 settextcolor(14);
46 lir_text(10,0,s);
47 settextcolor(7);
48 lir_refresh_screen();
49 }
50 
normalise_fft1_filtercorr(float * out)51 void normalise_fft1_filtercorr(float *out)
52 {
53 int i, j, k;
54 int mm;
55 float t1, t2, sum[2];
56 mm=2*ui.rx_rf_channels;
57 for(i=0; i<mm*fft1_size; i++)out[i]=1000000000*fft1_filtercorr[i];
58 //Make the average gain equal to one (weighted by desired spectrum)
59 t1=0;
60 sum[0]=0;
61 sum[1]=0;
62 for(i=0; i<fft1_size; i++)
63   {
64   t2=pow(fft1_desired[i],2.0);
65   t1+=t2;
66   k=0;
67   for(j=0; j<mm; j+=2)
68     {
69     sum[k]+=t2*(pow(out[mm*i+j  ],2.0)+
70                 pow(out[mm*i+j+1],2.0));
71     k++;
72     }
73   }
74 sum[0]=sqrt(sum[0]/t1);
75 sum[1]=sqrt(sum[1]/t1);
76 for(i=0; i<fft1_size; i++)
77   {
78   k=0;
79   for(j=0; j<mm; j+=2)
80     {
81     out[mm*i+j  ]/=sum[k];
82     out[mm*i+j+1]/=sum[k];
83     k++;
84     }
85   }
86 }
87 
write_filcorr(int siz)88 void write_filcorr(int siz)
89 {
90 FILE *file;
91 int i;
92 int wrbuf[10];
93 char s[80];
94 make_filfunc_filename(s);
95 file = fopen(s, "wb");
96 if (file == NULL)
97   {
98   DEB"\nCould not open file %s\n",s);
99   lirerr(1144);
100   return;
101   }
102 wrbuf[2]=rx_mode;
103 wrbuf[3]=ui.rx_input_mode;
104 wrbuf[4]=genparm[FIRST_FFT_VERNR];
105 wrbuf[5]=ui.rx_ad_speed;
106 wrbuf[6]=ui.rx_rf_channels;
107 if(siz >= 0)
108   {
109   wrbuf[0]=fft1_n;
110   wrbuf[1]=fft1_size;
111   wrbuf[7]=siz;
112   }
113 else
114   {
115   wrbuf[0]=fft2_n;
116   wrbuf[1]=fft2_size;
117   wrbuf[7]=0;
118   }
119 for(i=8; i<10; i++)wrbuf[i]=0;
120 i=fwrite(wrbuf, sizeof(int),10,file);
121 if(i != 10)
122   {
123 errx:
124   fclose(file);
125   lirerr(1145);
126   return;
127   }
128 if(siz < 0)
129   {
130   i=fwrite(cal_fft1_filtercorr, 2*ui.rx_rf_channels*sizeof(float),fft2_size, file);
131   if(i != fft2_size)goto errx;
132   i=fwrite(cal_fft1_desired,sizeof(float),fft2_size,file);
133   if(i != fft2_size)goto errx;
134   }
135 else
136   {
137   if(siz == 0)
138     {
139     normalise_fft1_filtercorr(cal_tmp);
140     i=fwrite(cal_tmp, twice_rxchan*sizeof(float),fft1_size, file);
141     if(i != fft1_size)goto errx;
142     i=fwrite(fft1_desired,sizeof(float),fft1_size,file);
143     if(i != fft1_size)goto errx;
144     }
145   else
146     {
147     i=fwrite(cal_buf, 2*ui.rx_rf_channels*sizeof(float),siz, file);
148     if(i != siz)goto errx;
149 // Store fft1_desired in siz points in cal_buf2
150     resize_fft1_desired(fft1_size, fft1_desired, siz, cal_buf2);
151     i=fwrite(cal_buf2,sizeof(float),siz,file);
152     if(i != siz)goto errx;
153     }
154   }
155 i=fwrite(wrbuf, sizeof(int),10,file);
156 if(i != 10)goto errx;
157 fclose(file);
158 }
159 
160 
do_cal_interval(void)161 void do_cal_interval(void)
162 {
163 int i, j, k, l, m, n, color,wid,first_pulse;
164 int p0, ia, ib, ic, ja, jb;
165 int imode,  lim;
166 int rawbytes;
167 int maxval[MAX_ADCHAN],minval[MAX_ADCHAN];
168 int old_end;
169 int points, mask;
170 int textend,ysiz,ytop;
171 char s[80];
172 float *filpwr;
173 float pwr_l, pwr_h;
174 float old_trig_power,trig_power,dc[MAX_ADCHAN],ampmax;
175 float noise_floor;
176 float t1,t2,t3;
177 // Collect 0.5 seconds of raw data.
178 rawbytes=ui.rx_ad_speed*snd[RXAD].framesize;
179 if(rawbytes > timf1_bytes-3*timf1_blockbytes)
180                                       rawbytes=timf1_bytes-3*timf1_blockbytes;
181 if(rawbytes < 0.25*ui.rx_ad_speed*snd[RXAD].framesize && fft1_size < 32768)
182   {
183   lirerr(1241);
184   goto calint_error_exit;
185   }
186 points=rawbytes/snd[RXAD].framesize;
187 make_power_of_two(&points);
188 points >>= 1;
189 rawbytes=points*snd[RXAD].framesize;
190 if(rawbytes > fft1_bytes/2)
191   {
192   rawbytes=fft1_bytes/2;
193   points=rawbytes/snd[RXAD].framesize;
194   }
195 filpwr=&fft1_float[points];
196 old_trig_power=1;
197 old_end=-1;
198 cal_ygain=1;
199 cal_xgain=1;
200 cal_interval=0;
201 imode=ui.rx_input_mode&(DWORD_INPUT+TWO_CHANNELS+IQ_DATA);
202 restart:;
203 cal_signal_level=0;
204 cal_type=CAL_TYPE_PULSE_INTERVAL;
205 cal_initscreen();
206 lir_text(3, 1,"Connect pulse generator to all antenna inputs");
207 lir_text(3, 2,"Press ENTER when OK.    (+),(-) for y-scale     E,C for x-scale");
208 lir_text(0,INFOLINE,"DC offset");
209 lir_text(5,INFOLINE+1,"Min");
210 lir_text(5,INFOLINE+2,"Max");
211 lir_text(3,INFOLINE+3,"Level");
212 lir_refresh_screen();
213 timf1p_px=timf1p_pa;
214 thread_status_flag[THREAD_CAL_INTERVAL]=THRFLAG_ACTIVE;
215 while(thread_command_flag[THREAD_CAL_INTERVAL] == THRFLAG_ACTIVE)
216   {
217 // Get power as a function of time.
218 // The A/D converters are AC coupled so we remove DC components.
219   for(i=0; i<MAX_ADCHAN; i++)
220     {
221     maxval[i]=0x80000000;
222     minval[i]=0x7fffffff;
223     dc[i]=0;
224     }
225   while( ((timf1p_pa-timf1p_px+timf1_bytes)&timf1_bytemask) < rawbytes &&
226                   thread_command_flag[THREAD_CAL_INTERVAL] == THRFLAG_ACTIVE)
227     {
228     lir_await_event(EVENT_TIMF1);
229     }
230   timf1p_px=(timf1p_pa-rawbytes+timf1_bytes)&timf1_bytemask;
231   if( (ui.rx_input_mode & DWORD_INPUT) == 0)
232     {
233     p0=timf1p_px/sizeof(short int);
234     mask=timf1_bytemask/sizeof(short int);
235     }
236   else
237     {
238     p0=timf1p_px/sizeof(int);
239     mask=timf1_bytemask/sizeof(int);
240     }
241   switch ( imode )
242     {
243     case 0:
244 // One channel 16 bit real data
245     for(i=0; i<points; i++)
246       {
247       k=(p0+i)&mask;
248       dc[0]+=timf1_short_int[k];
249       if(minval[0]>timf1_short_int[k])minval[0]=timf1_short_int[k];
250       if(maxval[0]<timf1_short_int[k])maxval[0]=timf1_short_int[k];
251       }
252     dc[0]/=points;
253     for(i=0; i<points; i++)
254       {
255       k=(p0+i)&mask;
256       fft1_float[i]=pow( 65536.0*(timf1_short_int[k]-dc[0]), 2.);
257       }
258     break;
259 
260     case 1:
261 // One channel 32 bit real data.
262     for(i=0; i<points; i++)
263       {
264       k=(p0+i)&mask;
265       dc[0]+=timf1_int[k];
266       if(minval[0]>timf1_int[k])minval[0]=timf1_int[k];
267       if(maxval[0]<timf1_int[k])maxval[0]=timf1_int[k];
268       }
269     dc[0]/=points;
270     for(i=0; i<points; i++)
271       {
272       k=(p0+i)&mask;
273       fft1_float[i]=pow( timf1_int[k]-dc[0], 2.);
274       }
275     break;
276 
277     case 2:
278 // Two channels 16 bit real data
279     for(i=0; i<points; i++)
280       {
281       k=(p0+2*i)&mask;
282       for(j=0; j<2; j++)
283         {
284         dc[j]+=timf1_short_int[k+j];
285         if(minval[j]>timf1_short_int[k+j])minval[j]=timf1_short_int[k+j];
286         if(maxval[j]<timf1_short_int[k+j])maxval[j]=timf1_short_int[k+j];
287         }
288       }
289     for(j=0; j<2; j++)dc[j]/=points;
290     for(i=0; i<points; i++)
291       {
292       t1=0;
293       k=(p0+2*i)&mask;
294       for(j=0; j<2; j++)
295         {
296         t2=timf1_short_int[k+j]-dc[j];
297         t1+=t2*t2;
298         }
299       fft1_float[i]=t1*65536.0*65536.0;
300       }
301     break;
302 
303     case 3:
304 // Two channels 32 bit real data
305     for(i=0; i<points; i++)
306       {
307       k=(p0+2*i)&mask;
308       for(j=0; j<2; j++)
309         {
310         dc[j]+=timf1_int[k+j];
311         if(minval[j]>timf1_int[k+j])minval[j]=timf1_int[k+j];
312         if(maxval[j]<timf1_int[k+j])maxval[j]=timf1_int[k+j];
313         }
314       }
315     for(j=0; j<2; j++)dc[j]/=points;
316     for(i=0; i<points; i++)
317       {
318       k=(p0+2*i)&mask;
319       t1=0;
320       for(j=0; j<2; j++)
321         {
322         t2=timf1_int[k+j]-dc[j];
323         t1+=t2*t2;
324         }
325       fft1_float[i]=t1;
326       }
327     break;
328 
329 
330     case 4:
331 // One channel 16 bit IQ data
332     for(i=0; i<points; i++)
333       {
334       k=(p0+2*i)&mask;
335       for(j=0; j<2; j++)
336         {
337         dc[j]+=timf1_short_int[k+j];
338         if(minval[j]>timf1_short_int[k+j])minval[j]=timf1_short_int[k+j];
339         if(maxval[j]<timf1_short_int[k+j])maxval[j]=timf1_short_int[k+j];
340         }
341       }
342     for(j=0; j<2; j++)dc[j]/=points;
343     for(i=0; i<points; i++)
344       {
345       k=(p0+2*i)&mask;
346       t1=0;
347       for(j=0; j<2; j++)
348         {
349         t2=timf1_short_int[k+j]-dc[j];
350         t1+=t2*t2;
351         }
352       fft1_float[i]=t1*65536.0*65536.0;
353       }
354     break;
355 
356     case 5:
357 // One channel 32 bit IQ data
358     for(i=0; i<points; i++)
359       {
360       k=(p0+2*i)&mask;
361       for(j=0; j<2; j++)
362         {
363         dc[j]+=timf1_int[k+j];
364         if(minval[j]>timf1_int[k+j])minval[j]=timf1_int[k+j];
365         if(maxval[j]<timf1_int[k+j])maxval[j]=timf1_int[k+j];
366         }
367       }
368     for(j=0; j<2; j++)dc[j]/=points;
369     for(i=0; i<points; i++)
370       {
371       k=(p0+2*i)&mask;
372       t1=0;
373       for(j=0; j<2; j++)
374         {
375         t2=timf1_int[k+j]-dc[j];
376         t1+=t2*t2;
377         }
378       fft1_float[i]=t1;
379       }
380     break;
381 
382     case 6:
383 // Two channels 16 bit IQ data
384     for(i=0; i<points; i++)
385       {
386       k=(p0+4*i)&mask;
387       for(j=0; j<4; j++)
388         {
389         dc[j]+=timf1_short_int[k+j];
390         if(minval[j]>timf1_short_int[k+j])minval[j]=timf1_short_int[k+j];
391         if(maxval[j]<timf1_short_int[k+j])maxval[j]=timf1_short_int[k+j];
392         }
393       }
394     for(j=0; j<4; j++)dc[j]/=points;
395     for(i=0; i<points; i++)
396       {
397       k=(p0+4*i)&mask;
398       t1=0;
399       for(j=0; j<4; j++)
400         {
401         t2=timf1_short_int[k+j]-dc[j];
402         t1+=t2*t2;
403         }
404       fft1_float[i]=t1*65536.0*65536.0;
405       }
406     break;
407 
408     case 7:
409 // Two channels 32 bit IQ data
410     for(i=0; i<points; i++)
411       {
412       k=(p0+4*i)&mask;
413       for(j=0; j<4; j++)
414         {
415         dc[j]+=timf1_int[k+j];
416         if(minval[j]>timf1_int[k+j])minval[j]=timf1_int[k+j];
417         if(maxval[j]<timf1_int[k+j])maxval[j]=timf1_int[k+j];
418         }
419       }
420     for(j=0; j<4; j++)dc[j]/=points;
421     for(i=0; i<points; i++)
422       {
423       k=(p0+4*i)&mask;
424       t1=0;
425       for(j=0; j<4; j++)
426         {
427         t2=timf1_int[k+j]-dc[j];
428         t1+=t2*t2;
429         }
430       fft1_float[i]=t1;
431       }
432     break;
433     }
434   lir_sched_yield();
435   cal_signal_level=BIG;
436   if( (ui.rx_input_mode&(DWORD_INPUT)) == 0)lim=0x7ff0; else lim=0x7ff00000;
437   for(j=0; j<ui.rx_ad_channels; j++)
438     {
439     sprintf(s," %4.2f ",dc[j]);
440     lir_text(10+15*j,INFOLINE,s);
441     sprintf(s," %d ",minval[j]);
442     lir_text(10+15*j,INFOLINE+1,s);
443     sprintf(s," %d ",maxval[j]);
444     lir_text(10+15*j,INFOLINE+2,s);
445     t1=-minval[j];
446     if(t1<maxval[j])t1=maxval[j];
447     if(t1 < cal_signal_level)cal_signal_level=t1;
448     if(minval[j] <= -lim || maxval[j] >= lim)
449       {
450       lir_text(10+15*j,INFOLINE+3,"OVERFLOW");
451       t1=1;
452       }
453     else
454       {
455       t1/=lim;
456       sprintf(s," %1.6f%% ",100*t1);
457       lir_text(10+15*j,INFOLINE+3,s);
458       }
459     }
460   cal_signal_level/=lim;
461 // Find the largest power value and point wid to it.
462   trig_power=0;
463   wid=0;
464   for(i=0; i<points; i++)
465     {
466     if(trig_power < fft1_float[i])
467       {
468       trig_power=fft1_float[i];
469       wid=i;
470       }
471     }
472   lir_sched_yield();
473 // Get an approximate width of the pulse (remember it may have a
474 // very ugly shape!)
475   i=wid;
476   while( i<points-3 && (fft1_float[i] >= trig_power/20 ||
477                         fft1_float[i+1] >= trig_power/20 ||
478                         fft1_float[i+2] >= trig_power/20 ||
479                         fft1_float[i+3] >= trig_power/20 ))
480     {
481     i++;
482     if(i-wid >100)goto skip;
483     }
484   while( wid>2 && (fft1_float[wid] >= trig_power/20 ||
485                  fft1_float[wid-1] >= trig_power/20 ||
486                  fft1_float[wid-2] >= trig_power/20 ||
487                  fft1_float[wid-3] >= trig_power/20 ))
488     {
489     wid--;
490     if(i-wid > 100)goto skip;
491     }
492   wid=(i-wid);
493   wid=wid/2+1;
494 // Low pass filter the power function and store in filpwr
495   for(i=wid; i<points; i++)
496     {
497     t1=0;
498     for(j=i-wid; j<=i; j++)
499       {
500       t1+=fft1_float[j];
501       }
502     filpwr[i-wid/2]=t1/wid;
503     }
504 // Save the maximum amplitude and make trig power 31.6 times smaller
505 // than the maximum value (-15dB)
506   ampmax=sqrt(trig_power);
507   if(trig_power > old_trig_power)old_trig_power=trig_power;
508   trig_power=old_trig_power/31.6;
509 // Remember trig_power for the next set of data.
510   old_trig_power/=2;
511   ia=0;
512   i=wid;
513   if(wid < points/16)
514     {
515 // find the position of the first pulse
516 interval_init:;
517     while( i<points-3*wid && filpwr[i] <= trig_power)i++;
518     ja=i;
519     while( i<points-wid && filpwr[i] >= trig_power/20)i++;
520     if(ja==wid)goto interval_init;
521     jb=i;
522     t1=0;
523     for(k=ja; k<jb; k++)
524       {
525       if(fft1_float[k] > t1)
526         {
527         t1=fft1_float[k];
528         ia=k;
529         }
530       }
531     first_pulse=ia;
532 // Find sucessive pulses and store the intervals in cal_tmp
533     k=0;
534     cal_interval=0;
535     j=0;
536 find_interval:;
537     while( i<points-wid && filpwr[i] <= trig_power)i++;
538     ja=i;
539     while( i<points-wid && filpwr[i] >= trig_power/20)i++;
540     jb=i;
541     t1=0;
542     ib=i;
543     for(k=ja; k<jb; k++)
544       {
545       if(fft1_float[k] > t1)
546         {
547         t1=fft1_float[k];
548         ib=k;
549         }
550       }
551     if(i<points-wid)
552       {
553       if(ib-ia<4*wid)goto find_interval;
554       cal_tmp[j]=ib-ia;
555       j++;
556       ia=ib;
557       if(j<fft1_size)goto find_interval;
558       }
559 // Since the pulses may vary in amplitude by more than we allow for in
560 // the setting of the trigger level we sort the intervals in ascending order
561 // and take desicions if the interval is 1,2 or 3 pulses.
562     if(j>0)
563       {
564       for(i=0; i<j-1; i++)
565         {
566         for(k=i+1; k<j; k++)
567           {
568           if(cal_tmp[k]<cal_tmp[i])
569             {
570             t1=cal_tmp[k];
571             cal_tmp[k]=cal_tmp[i];
572             cal_tmp[i]=t1;
573             }
574           }
575         }
576       i=j/4+1;
577       t1=0;
578       while(i<j && cal_tmp[i-1]>0.7*cal_tmp[i])
579         {
580         t1+=cal_tmp[i];
581         i++;
582         }
583       i-=(j/4+1);
584       if(i != 0)
585         {
586         t1/=i;
587         k=0;
588         for(i=0; i<j; i++)
589           {
590           if(cal_tmp[i]>0.8*t1 && cal_tmp[i]<1.2*t1)
591             {
592             cal_interval+=cal_tmp[i];
593             k++;
594             }
595           else
596             {
597             if(cal_tmp[i]>1.8*t1 && cal_tmp[i]<2.2*t1)
598               {
599               cal_interval+=cal_tmp[i];
600               k+=2;
601               }
602             else
603               {
604               if(cal_tmp[i]>2.7*t1 && cal_tmp[i]<3.3*t1)
605                 {
606                 cal_interval+=cal_tmp[i];
607                 k+=3;
608                 }
609               }
610             }
611           }
612         cal_interval/=k;
613 // Get the noise floor.
614 // First locate the smallest power value in the filtered power vs time curve.
615         pwr_l=BIG;
616         pwr_h=0;
617         for(i=wid; i<points-wid; i++)
618           {
619           if(pwr_l>filpwr[i])pwr_l=filpwr[i];
620           if(pwr_h<filpwr[i])pwr_h=filpwr[i];
621           }
622 // Assume the noise floor is 10dB above this level
623         pwr_l*=10;
624 // Limit our guess to the range -10dB to -60 dB
625         if(pwr_l < 0.000001*pwr_h)pwr_l=0.000001*pwr_h;
626         if(pwr_l > 0.1*pwr_h)pwr_l=0.1*pwr_h;
627 // Count the number of points above the noise floor and
628 // get the average value of the points below the noise floor.
629         j=0;
630 get_floor:;
631         t2=0;
632         k=0;
633         j++;
634         if(j < 10)
635           {
636           for(i=wid; i<points-wid; i++)
637             {
638             if(filpwr[i]<pwr_l)
639               {
640               k++;
641               t2+=fft1_float[i];
642               }
643             }
644           t2/=k;
645           if(k < 0.4*(points-2*wid))
646             {
647             pwr_l*=3.333;
648             goto get_floor;
649             }
650           if(k > 0.6*(points-2*wid))
651             {
652             if(pwr_l > 4*t2)
653               {
654               pwr_l=3*t2;
655               goto get_floor;
656               }
657             else
658               {
659               if(pwr_l < 2*t2)
660                 {
661                 pwr_l/=2;
662                 goto get_floor;
663                 }
664               }
665             }
666           }
667         else
668           {
669           t2=pwr_h;
670           }
671         noise_floor=pwr_h/t2;
672 // Show one of the pulses.
673         while(first_pulse+7*(screen_width>>3) > points)
674                                                 first_pulse -= cal_interval;
675         while(first_pulse < (screen_width>>3))
676                                                 first_pulse += cal_interval;
677         if(first_pulse+7*(screen_width>>3) <= points)
678           {
679           ic=first_pulse+7*(screen_width>>3);
680           ia=first_pulse-(screen_width>>3);
681           for(j=0; j<=ui.rx_ad_channels; j++)
682             {
683             m=screen_width*j;
684             n=screen_width*(ui.rx_ad_channels+1);
685             for(i=1; i<=old_end; i++)
686               {
687               lir_line(cal_graph[n+i-1], cal_graph[m+i-1],
688                       cal_graph[n+i  ], cal_graph[m+i  ],0);
689               if(kill_all_flag) goto calint_error_exit;
690               }
691             }
692           textend=(INFOLINE+4)*text_height;
693           ytop=textend+screen_height*0.3;
694           ysiz=screen_height-ytop;
695           n=-1;
696           for(j=ia; j<ic; j++)
697             {
698             i=(screen_width>>3)+cal_xgain*(j-first_pulse);
699             if(i>=0 && i<screen_width)
700               {
701               n++;
702               if( (n&0x7f)==0) lir_sched_yield();
703               old_end=n;
704               cal_graph[screen_width*(ui.rx_ad_channels+1)+n]=i;
705               cal_graph[n]=textend+screen_height*(0.4-0.008*log(fft1_float[j]));
706               switch ( imode )
707                 {
708 // One channel 16 bit
709                 case 0:
710                 k=(p0+j)&mask;
711                 t2=4*6553.6*cal_ygain*timf1_short_int[k]/ampmax;
712                 if(t2 <-0.45)t2=-0.45;
713                 if(t2 >0.45)t2=0.45;
714                 cal_graph[screen_width+n]=ytop+ysiz*(0.5-t2);
715                 m=1;
716                 break;
717 
718 // One channel 32 bit
719                 case 1:
720                 k=(p0+j)&mask;
721                 t2=0.4*cal_ygain*timf1_int[k]/ampmax;
722                 if(t2 <-0.45)t2=-0.45;
723                 if(t2 >0.45)t2=0.45;
724                 cal_graph[screen_width+n]=ytop+ysiz*(0.5-t2);
725                 m=1;
726                 break;
727 
728 // Two channels 16 bit real data
729                 case 2:
730                 k=(p0+2*j)&mask;
731                 for(m=0; m<2; m++)
732                   {
733                   t2=2*6553.6*cal_ygain*timf1_short_int[k+m]/ampmax;
734                   if(t2 <-0.22)t2=-0.22;
735                   if(t2 >0.22)t2=0.22;
736                   if(m == 1)t2-=0.5;
737                   cal_graph[screen_width*(m+1)+n]=ytop+ysiz*(0.25-t2);
738                   }
739                 m=2;
740                 break;
741 
742 // Two channels 32 bit real data
743                 case 3:
744                 k=(p0+2*j)&mask;
745                 for(m=0; m<2; m++)
746                   {
747                   t2=0.4*cal_ygain*timf1_int[k+m]/ampmax;
748                   if(t2 <-0.22)t2=-0.22;
749                   if(t2 >0.22)t2=0.22;
750                   if(m == 1)t2-=0.5;
751                   cal_graph[screen_width*(m+1)+n]=ytop+ysiz*(0.25-t2);
752                   }
753                 m=2;
754                 break;
755 
756 // One channel 16 bit IQ data
757                 case 4:
758                 k=(p0+2*j)&mask;
759                 for(m=0; m<2; m++)
760                   {
761                   t2=4*6553.6*cal_ygain*timf1_short_int[k+m]/ampmax;
762                   if(t2 <-0.45)t2=-0.45;
763                   if(t2 >0.45)t2=0.45;
764                   cal_graph[screen_width*(m+1)+n]=ytop+ysiz*(0.5-t2);
765                   }
766                 m=2;
767                 break;
768 
769 // One channel 32 bit IQ data
770                 case 5:
771                 k=(p0+2*j)&mask;
772                 for(m=0; m<2; m++)
773                   {
774                   t2=0.4*cal_ygain*timf1_int[k+m]/ampmax;
775                   if(t2 <-0.45)t2=-0.45;
776                   if(t2 >0.45)t2=0.45;
777                   cal_graph[screen_width*(m+1)+n]=ytop+ysiz*(0.5-t2);
778                   }
779                 m=2;
780                 break;
781 
782 // Two channels 16 bit IQ data
783                 case 6:
784                 k=(p0+4*j)&mask;
785                 t3=4*6553.6*cal_ygain/ampmax;
786                 for(m=0; m<4; m++)
787                   {
788                   t2=t3*timf1_short_int[k+m];
789                   if(t2 <-0.22)t2=-0.22;
790                   if(t2 >0.22)t2=0.22;
791                   if(m > 1)t2-=0.5;
792                   cal_graph[screen_width*(m+1)+n]=ytop+ysiz*(0.25-t2);
793                   }
794                 m=4;
795                 break;
796 
797 // Two channels 32 bit IQ data
798                 case 7:
799                 k=(p0+4*j)&mask;
800                 for(m=0; m<4; m++)
801                   {
802                   t2=0.4*cal_ygain*timf1_int[k+m]/ampmax;
803                   if(t2 <-0.22)t2=-0.22;
804                   if(t2 >0.22)t2=0.22;
805                   if(m > 1)t2-=0.5;
806                   cal_graph[screen_width*(m+1)+n]=ytop+ysiz*(0.25-t2);
807                   }
808                 m=4;
809                 break;
810 
811                 default:
812                 m=0;
813                 }
814               if(n>0)
815                 {
816                 lir_line(cal_graph[screen_width*(ui.rx_ad_channels+1)+n-1],
817                                         cal_graph[n-1],i,cal_graph[n],15);
818                 if(kill_all_flag) goto calint_error_exit;
819                 for(l=0; l<m; l++)
820                   {
821                   color=10+3*(l&1);
822                   if( (ui.rx_input_mode&IQ_DATA) == 0)color=14;
823                   lir_line(cal_graph[screen_width*(ui.rx_ad_channels                  +1)+n-1],
824                                 cal_graph[(l+1)*screen_width+n-1],
825                                    i,cal_graph[(l+1)*screen_width+n],color);
826                   if(kill_all_flag) goto calint_error_exit;
827                   }
828                 }
829               }
830             sprintf(s,"Scale x=%f  y=%f      S/N=%f dB      PRF %.1f Hz    ",
831                           cal_xgain,cal_ygain,10*log10(noise_floor),
832                                              ui.rx_ad_speed/cal_interval);
833             lir_text(1,INFOLINE+4,s);
834             }
835           }
836         }
837       }
838     }
839 skip:;
840   timf1p_px=(timf1p_px+rawbytes)&timf1_bytemask;
841   lir_refresh_screen();
842   }
843 if(thread_command_flag[THREAD_CAL_INTERVAL]==THRFLAG_IDLE)
844   {
845   thread_status_flag[THREAD_CAL_INTERVAL]=THRFLAG_IDLE;
846   while(thread_command_flag[THREAD_CAL_INTERVAL]==THRFLAG_IDLE)
847     {
848     lir_await_event(EVENT_TIMF1);
849     timf1p_px=(timf1p_px+rawbytes)&timf1_bytemask;
850     }
851   if(thread_command_flag[THREAD_CAL_INTERVAL]==THRFLAG_ACTIVE)goto restart;
852   }
853 calint_error_exit:;
854 thread_status_flag[THREAD_CAL_INTERVAL]=THRFLAG_RETURNED;
855 while(thread_command_flag[THREAD_CAL_INTERVAL] != THRFLAG_NOT_ACTIVE)
856   {
857   lir_sleep(1000);
858   }
859 }
860 
861