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 #include <unistd.h>
25 
26 #include "globdef.h"
27 #include "uidef.h"
28 #include "fft1def.h"
29 #include "fft2def.h"
30 #include "fft3def.h"
31 #include "sigdef.h"
32 #include "screendef.h"
33 #include "seldef.h"
34 #include "rusage.h"
35 #include "thrdef.h"
36 
37 extern int wg_old_y1;
38 extern int wg_old_y2;
39 extern int wg_old_x1;
40 extern int wg_old_x2;
41 
42 
43 
txtest_init(void)44 void txtest_init(void)
45 {
46 int i, j, k;
47 float t1;
48 int pnts_per_seg;
49 txtest_decayfac1=fft1_blocktime;
50 txtest_decayfac2=1-txtest_decayfac1;
51 txtest_no_of_segs=(int)((fft1_last_point-fft1_first_point)*
52                                                    fft1_hz_per_point/600);
53 if(txtest_no_of_segs >= screen_width)
54   {
55   lirerr(1159);
56   return;
57   }
58 for(i=0; i<screen_width; i++)
59   {
60   txtest_ypeak[i]=wg.ybottom-1;
61   txtest_ypeak_decay[i]=wg.ybottom-1;
62   txtest_yavg[i]=wg.ybottom-1;
63   fft1_spectrum[i]=wg.ybottom-1;
64   }
65 mix1_selfreq[0]=2400;
66 // Set up a rectangular filter with 2400Hz bandwidth
67 pnts_per_seg=2400/fft1_hz_per_point;
68 j=(mix1.size-pnts_per_seg)/2;
69 k=mix1.size/2;
70 i=0;
71 for(i=0; i<j; i++)
72   {
73   mix1_fqwin[i]=0;
74   }
75 for(i=j; i<=(int)mix1.size/2; i++)
76   {
77   mix1_fqwin[i]=1;
78   }
79 j=(mix1.size-mix1.new_points)/2;
80 k=j;
81 for(i=0; i<(int)mix1.crossover_points; i++)
82   {
83   mix1.cos2win[i]=mix1.window[k];
84   mix1.sin2win[i]=mix1.window[j];
85   k--;
86   j++;
87   }
88 if(txtest_no_of_segs <=0)txtest_no_of_segs=1;
89 txtest_pntinc=(fft1_last_point-fft1_first_point)/txtest_no_of_segs;
90 t1=pnts_per_seg/2+1;
91 txtest_first_point=fft1_first_point+t1;
92 txtest_pixinc=txtest_pntinc;
93 if(wg.xpoints_per_pixel == 0)
94   {
95   txtest_pixinc=txtest_pntinc*wg.pixels_per_xpoint;
96   t1*=wg.pixels_per_xpoint;
97   }
98 else
99   {
100   txtest_pixinc=(float)(txtest_pntinc)/wg.xpoints_per_pixel;
101   t1/=wg.xpoints_per_pixel;
102   if(txtest_pixinc < 1)
103     {
104     lirerr(1160);
105     return;
106     }
107   }
108 t1+=wg_first_xpixel;
109 txtest_spek_no=0;
110 txtest_spek_p0=0;
111 while(txtest_first_point-(int)mix1.size/2 < fft1_first_point)
112   {
113   txtest_first_point+=txtest_pntinc;
114   t1+=txtest_pixinc;
115   }
116 txtest_first_xpix=t1+0.5;
117 while(txtest_no_of_segs*txtest_pntinc+(int)mix1.size/2+
118                txtest_first_point > fft1_last_point) txtest_no_of_segs--;
119 if(txtest_no_of_segs < 0)
120   {
121   txtest_no_of_segs=0;
122   }
123 else
124   {
125   if( txtest_first_xpix+(txtest_no_of_segs-1)*txtest_pixinc >= wg.xright)
126     {
127     txtest_no_of_segs=0;
128     }
129   }
130 txtest_yfac=wg_yfac_power*wg.spek_avgnum;
131 if(genparm[FIRST_FFT_SINPOW] != 0)
132   {
133   t1=0;
134   for(i=0; i<fft1_size/2; i++)t1+=fft1_window[i];
135   t1/=fft1_size;
136   txtest_yfac/=t1*t1;
137   }
138 txtest_peak_redraw=0;
139 txtest_saturated=(float)BIG;
140 }
141 
make_txtest_wide_spectra(void)142 void make_txtest_wide_spectra(void)
143 {
144 int i, j, k;
145 float t1;
146 // Make the average spectrum.
147 for(i=0; i<txtest_no_of_segs; i++)
148   {
149   t1=0;
150   k=0;
151   for(j=0; j<wg.spek_avgnum; j++)
152     {
153     t1+=txtest_power[k+i];
154     k+=txtest_no_of_segs;
155     }
156   txtest_powersum[i]=t1/wg.spek_avgnum;
157   }
158 }
159 
160 
txtest(void)161 void txtest(void)
162 {
163 int i, j, k;
164 int ia, ib;
165 int mix1_flag;
166 int local_workload_reset;
167 int old_fft1_nx, old_fft1_px;
168 float pwr1, pwr2;
169 float t1;
170 restart:;
171 local_workload_reset=workload_reset_flag;
172 for(i=0; i<txtest_no_of_segs*wg.spek_avgnum; i++)txtest_power[i]=0;
173 mix1_flag=0;
174 if(thread_command_flag[THREAD_SCREEN]!=THRFLAG_NOT_ACTIVE)
175   {
176   while(thread_status_flag[THREAD_SCREEN]!=THRFLAG_ACTIVE &&
177         thread_status_flag[THREAD_SCREEN]!=THRFLAG_IDLE &&
178         thread_status_flag[THREAD_SCREEN]!=THRFLAG_SEM_WAIT)
179     {
180     if(thread_command_flag[THREAD_TXTEST] == THRFLAG_KILL)goto txtest_exit;
181     lir_sleep(10000);
182     }
183   }
184 thread_status_flag[THREAD_TXTEST]=THRFLAG_ACTIVE;
185 while(thread_command_flag[THREAD_TXTEST] == THRFLAG_ACTIVE)
186   {
187   if(local_workload_reset!=workload_reset_flag)
188     {
189     local_workload_reset=workload_reset_flag;
190     if(txtest_saturated < 0.1)
191       {
192       txtest_saturated=BIG;
193       }
194     for(i=0; i<txtest_no_of_segs; i++)
195       {
196       txtest_peak_power_decay[i]=txtest_peak_power[i];
197       txtest_peak_power[i]=0;
198       }
199     for(i=wg_first_xpixel; i<wg_last_xpixel; i++)
200       {
201       txtest_ypeak[i]=wg.ybottom-1;
202       }
203 // Just clear the entire window and make a new graph.
204 // Quick fix when going from single-threaded to multi-threaded structure.
205     wg_old_x1=wg.xleft;
206     wg_old_x2=wg.xright;
207     wg_old_y1=wg.ytop;
208     wg_old_y2=wg.ybottom;
209     make_wide_graph(TRUE);
210     memcheck(197,fft1mem,&fft1_handle);
211     if(kill_all_flag) goto txtest_exit;
212     }
213 // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
214 // mix1_flag signals to us that there is work to do on previous
215 // transforms so do not wait for a new fft1/fft2 if it is nonzero.
216   if(mix1_flag == 0) lir_await_event(EVENT_FFT1_READY);
217   if(txtest_no_of_segs < 1)fft1_px=(fft1_px+1)&fft1_mask;
218   mix1_flag=0;
219 // ###########################################################
220 // Third processing block.
221 // evaluate peak voltage in 2.4kHz bandwidth.
222 // ###########################################################
223   i=(fft1_pb-fft1_px+fft1_mask+1)&fft1_mask;
224   if(i>2*(int)mix1.size)
225     {
226     mix1_flag=1;
227     old_fft1_nx=fft1_nx;
228     old_fft1_px=fft1_px;
229     mix1_point[0]=txtest_first_point;
230     for(i=0; i<txtest_no_of_segs; i++)
231       {
232       fft1_nx=old_fft1_nx;
233       fft1_px=old_fft1_px;
234       for(j=0; j<2*timf3_block; j++)
235         {
236         timf3_float[j]=0;
237         }
238       timf3_pa=0;
239       fft1_mix1_fixed();
240 // In case the window is sine squared, we have to divide by it.
241 // because the standard routine we use does not divide for us.
242       ia=(mix1.interleave_points+mix1.crossover_points)/2;
243       if(mix1.interleave_points == mix1.new_points)
244         {
245         ia=mix1.size/4;
246         ib=3*mix1.size/4;
247         j=mix1.size/2+1;
248         k=mix1.size/2-1;
249         while(k >= (int)mix1.size/5)
250           {
251           timf3_float[2*k]*=mix1.window[k];
252           timf3_float[2*k+1]*=mix1.window[k];
253           timf3_float[2*j]*=mix1.window[k];
254           timf3_float[2*j+1]*=mix1.window[k];
255           j++;
256           k--;
257           }
258         }
259       else
260         {
261         if(mix1.interleave_points == 0)
262           {
263           ia=0;
264           ib=mix1.size;
265           }
266         else
267           {
268           ia=0;
269           ib=mix1.new_points+1;
270           }
271         }
272       pwr2=0;
273       pwr1=0;
274       for(j=ia; j<ib; j++)
275         {
276         t1=timf3_float[2*j  ]*timf3_float[2*j  ]+
277            timf3_float[2*j+1]*timf3_float[2*j+1];
278         pwr1+=t1;
279         if(pwr2 < t1)pwr2=t1;
280         }
281       pwr1*=txtest_yfac;
282       pwr2*=txtest_yfac;
283       txtest_power[txtest_spek_p0+i]=pwr1/(ib-ia);
284       txtest_peak_power[i]=pwr2;
285       txtest_peak_power_decay[i]=txtest_peak_power_decay[i]*txtest_decayfac2+
286                                         txtest_peak_power[i]*txtest_decayfac1;
287       mix1_point[0]+=txtest_pntinc;
288       lir_sched_yield();
289       }
290     txtest_show_p0=txtest_spek_p0;
291     txtest_spek_no++;
292     txtest_spek_p0+=txtest_no_of_segs;
293     if(txtest_spek_no >=wg.spek_avgnum)
294       {
295       txtest_spek_no=0;
296       txtest_spek_p0=0;
297       }
298     make_txtest_wide_spectra();
299     }
300 // Here we do the mouse actions that affect the wide graph.
301 // Currently only the waterfall memory area may become re-allocated
302   if(mouse_task!=-1)
303     {
304     k=mouse_task&GRAPH_MASK;
305     if( k > MAX_WIDEBAND_GRAPHS)
306       {
307       set_button_states();
308       if(mouse_active_flag == 0)
309         {
310         switch (k)
311           {
312           case FREQ_GRAPH:
313           mouse_on_freq_graph();
314           break;
315           }
316         if(mouse_active_flag == 0)lirerr(18877);
317         }
318       if(numinput_flag==0)current_mouse_activity();
319       if( (numinput_flag&DATA_READY_PARM) != 0)
320         {
321         par_from_keyboard_routine();
322         par_from_keyboard_routine=NULL;
323         mouse_active_flag=0;
324         numinput_flag=0;
325         leftpressed=BUTTON_IDLE;
326         }
327       if(mouse_active_flag == 0)
328         {
329         mouse_task=-1;
330         }
331       }
332     }
333   }
334 if(thread_command_flag[THREAD_TXTEST]==THRFLAG_IDLE)
335   {
336 // The wideband dsp thread is running and it puts out
337 // the waterfall graph. Stop it now.
338   thread_command_flag[THREAD_WIDEBAND_DSP]=THRFLAG_IDLE;
339   while(thread_status_flag[THREAD_WIDEBAND_DSP]!=THRFLAG_IDLE)
340     {
341     lir_sleep(25000);
342     }
343   thread_status_flag[THREAD_TXTEST]=THRFLAG_IDLE;
344   while(thread_command_flag[THREAD_TXTEST] == THRFLAG_IDLE)
345     {
346     lir_sleep(10000);
347     fft1_px = fft1_pb;
348     }
349   thread_command_flag[THREAD_WIDEBAND_DSP]=THRFLAG_ACTIVE;
350   lir_sleep(1000);
351   wg_old_x1=wg.xleft;
352   wg_old_x2=wg.xright;
353   wg_old_y1=wg.ytop;
354   wg_old_y2=wg.ybottom;
355   make_wide_graph(TRUE);
356   if(kill_all_flag) goto txtest_exit;
357   goto restart;
358   }
359 txtest_exit:;
360 lir_sleep(10000);
361 thread_status_flag[THREAD_TXTEST]=THRFLAG_RETURNED;
362 while(thread_command_flag[THREAD_TXTEST] != THRFLAG_NOT_ACTIVE)
363   {
364   lir_sleep(1000);
365   }
366 }
367