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 #define YBO 8
25 #define YWF 4
26 
27 #include <unistd.h>
28 #include <fcntl.h>
29 #include "globdef.h"
30 #include "uidef.h"
31 #include "fft1def.h"
32 #include "fft2def.h"
33 #include "screendef.h"
34 #include "seldef.h"
35 #include "graphcal.h"
36 #include "vernr.h"
37 #include "sigdef.h"
38 #include "rusage.h"
39 #include "thrdef.h"
40 
41 int wide_graph_scro;
42 int wg_old_y1;
43 int wg_old_y2;
44 int wg_old_x1;
45 int wg_old_x2;
46 
make_wg_fqlimits(void)47 void make_wg_fqlimits(void)
48 {
49 wg_lowest_freq=0.000001*wg_first_frequency+0.1*frequency_scale_offset;
50 wg_highest_freq=wg_lowest_freq+0.000001*wg.xpoints*fft1_hz_per_point;
51 }
52 
wg_check_mix1(int i0)53 float wg_check_mix1(int i0)
54 {
55 int i,k;
56 float t1;
57 i=mouse_x;
58 if(i<wg_first_xpixel)i=wg_first_xpixel;
59 if(i>wg_last_xpixel)i=wg_last_xpixel;
60 t1=wg_first_frequency+(float)(i-wg_first_xpixel)*wg_hz_per_pixel;
61 if(t1 <  mix1_lowest_fq)t1=mix1_lowest_fq;
62 if(t1 > mix1_highest_fq)t1=mix1_highest_fq;
63 k=0;
64 for(i=i0; i<genparm[MIX1_NO_OF_CHANNELS]; i++)
65   {
66   if( fabs(t1-mix1_selfreq[i]) < 3*wg_hz_per_pixel)
67     {
68     new_mix1_curx[i]=-1;
69     k++;
70     mix1_selfreq[i]=-1;
71     mix1_point[i]=-1;
72     }
73   }
74 if(k>0 && i0==0)return -(float)BIG;
75 return t1;
76 }
77 
78 
wide_graph_selfreq(void)79 void wide_graph_selfreq(void)
80 {
81 int post;
82 float t1;
83 new_mix1_curx[0]=-1;
84 t1=wg_check_mix1(1);
85 post=make_new_signal(0, t1);
86 if(post)
87   {
88   sc[SC_FREQ_READOUT]++;
89   if(genparm[SECOND_FFT_ENABLE] != 0)sc[SC_HG_FQ_SCALE]++;
90   if(genparm[AFC_ENABLE]==0)sc[SC_BG_FQ_SCALE]++;
91   }
92 if(leftpressed != BUTTON_RELEASED)
93   {
94   if(post)lir_set_event(EVENT_SCREEN);
95   return;
96   }
97 if(post)
98   {
99   if(genparm[AFC_ENABLE]!=0)sc[SC_BG_FQ_SCALE]++;
100   lir_set_event(EVENT_SCREEN);
101   }
102 leftpressed=BUTTON_IDLE;
103 baseb_reset_counter++;
104 mouse_active_flag=0;
105 }
106 
add_mix1_cursor(int num)107 void add_mix1_cursor(int num)
108 {
109 if(mix1_selfreq[num]<wg_first_frequency)
110   {
111   new_mix1_curx[num]=(int)wg_first_frequency;
112   return;
113   }
114 new_mix1_curx[num]=(int)(0.5F+(float)wg_first_xpixel+
115                     (mix1_selfreq[num]-wg_first_frequency)/wg_hz_per_pixel);
116 if(new_mix1_curx[num] > wg_last_xpixel)
117   {
118   new_mix1_curx[num]=wg_last_xpixel;
119   }
120 }
121 
make_new_signal(int i,float t1)122 int make_new_signal(int i,float t1)
123 {
124 int retcod;
125 if(mix1_selfreq[i]==t1)
126   {
127   retcod=FALSE;
128   }
129 else
130   {
131   retcod=TRUE;
132   mix1_selfreq[i]=t1;
133   }
134 mix1_point[i]=-1;
135 add_mix1_cursor(i);
136 return retcod;
137 }
138 
step_rx_frequency(int direction)139 void step_rx_frequency(int direction)
140 {
141 float t1, t2;
142 int m;
143 if(mix1_selfreq[0] < 0 || ag.mode_control != 0)return;
144 if(genparm[AFC_ENABLE]==0 || rx_mode >= MODE_SSB)
145   {
146   m=1<<bg.wheel_stepn;
147   t1=mix1_selfreq[0];
148   t2=(float)direction*((float)m/fftx_points_per_hz)/256;
149   t1+=t2;
150   if(t1<=mix1_lowest_fq)return;
151   if(t1>=mix1_highest_fq)return;
152   unconditional_hide_mouse();
153   switch (bg.horiz_arrow_mode)
154     {
155     case 0:
156     mix1_selfreq[0]=t1;
157     add_mix1_cursor(0);
158     sc[SC_SHOW_CENTER_FQ]++;
159     break;
160 
161     case 1:
162     mix1_selfreq[0]=t1;
163     add_mix1_cursor(0);
164     sc[SC_SHOW_CENTER_FQ]++;
165     clear_bfo();
166     bg.bfo_freq-=t2;
167     make_bfo();
168     break;
169 
170     case 2:
171     clear_bfo();
172     bg.bfo_freq-=t2;
173     make_bfo();
174     break;
175     }
176   }
177 }
178 
179 
mouse_continue_wide_graph_rightpressed(void)180 void mouse_continue_wide_graph_rightpressed(void)
181 {
182 int iymax;
183 int jw, iy, i, ix,color;
184 int maxpos, maxval, total;
185 float t1;
186 #define MAX_OCCURANCES 3*MAX_COLOR_SCALE
187 int occurances[MAX_OCCURANCES];
188 int last_valid;
189 last_valid=0;
190 if(rightpressed != BUTTON_RELEASED)return;
191 switch (mouse_active_flag-1)
192   {
193   case WG_WATERF_ZERO:
194   if(recent_time-wg_waterf_zero_time > 1)
195     {
196     for(i=0; i<MAX_OCCURANCES; i++)occurances[i]=0;
197     wg_waterf_zero_time=current_time();
198     iy=wg_waterf_y;
199     iymax=wg_waterf_y+wg_waterf_lines-wg_waterf_yinc;
200     jw=wg_waterf_ptr2;
201     while(iy < iymax)
202       {
203       i=wg_first_xpixel;
204       ix=0;
205       while(ix<wg_xpixels && i<screen_width)
206         {
207         color=(int)(MAX_COLOR_SCALE+wg_waterf_cfac*
208                                   ((float)wg_waterf[jw+ix]-(float)wg_waterf_czer));
209         ix++;
210         if(color<0)
211           {
212           color=0;
213           }
214         else
215           {
216           if(color >= MAX_OCCURANCES)color=MAX_OCCURANCES-1;
217           }
218         occurances[color]++;
219         if(color != 0)last_valid=occurances[0];
220         i++;
221         }
222       iy++;
223       jw+=wg_xpixels;
224       if(jw > wg_waterf_size-wg_xpixels-1)jw=0;
225       }
226     if(last_valid == 0)last_valid=1;
227     occurances[0]=last_valid;
228     maxpos=-1;
229     maxval=0;
230     total=0;
231     for(i=0; i<MAX_OCCURANCES-2; i++)
232       {
233       if(occurances[i]>maxval)
234         {
235         maxval=occurances[i];
236         maxpos=i;
237         }
238       total+=occurances[i];
239       }
240     if(maxpos==-1 || maxpos== 3)break;
241     if(occurances[MAX_OCCURANCES-1] > 1.5*total)
242       {
243       maxpos=MAX_COLOR_SCALE-1;
244       }
245     if(maxpos == 0)
246       {
247 // The waterfall is black.
248      wg.waterfall_db_zero-=0.01F*(float)MAX_COLOR_SCALE/wg_waterf_cfac;
249       }
250     else
251       {
252       if(maxpos == MAX_COLOR_SCALE-1)
253         {
254 // The waterfall is white.
255         wg.waterfall_db_zero+=0.01F*(float)MAX_COLOR_SCALE/wg_waterf_cfac;
256         }
257       else
258         {
259         wg.waterfall_db_zero+=.01F*(float)(maxpos-MAX_COLOR_SCALE-3)/
260                                           wg_waterf_cfac;
261         }
262       }
263     make_modepar_file(GRAPHTYPE_WG);
264     sc[SC_WG_WATERF_REDRAW]++;
265     }
266   break;
267 
268   case WG_FREQ_ADJUSTMENT_MODE:
269   t1=0.000001F*(float)
270                (mouse_x-(wg_last_xpixel+wg_first_xpixel)/2)*wg_hz_per_pixel;
271   make_wg_fqlimits();
272   wg_lowest_freq+=t1;
273   wg_highest_freq+=t1;
274   t1=0.1F*(float)frequency_scale_offset;
275   if(wg_lowest_freq < t1)
276     {
277     wg_highest_freq+=t1-wg_lowest_freq;
278     wg_lowest_freq+=t1-wg_lowest_freq;;
279     }
280   t1+=(float)(0.000001F*(float)(fft1_size-1)*(float)fft1_hz_per_point);
281   if(wg_highest_freq > t1)
282     {
283     wg_lowest_freq+=wg_highest_freq-t1;
284     wg_highest_freq+=wg_highest_freq-t1;
285     }
286   wg_freq_adjustment_mode=2;
287   wg_old_y1=wg.ytop;
288   wg_old_y2=wg.ybottom;
289   wg_old_x1=wg.xleft;
290   wg_old_x2=wg.xright;
291   make_wide_graph(TRUE);
292   sc[SC_WG_WATERF_REDRAW]++;
293   break;
294 
295   default:
296   break;
297   }
298 rightpressed=BUTTON_IDLE;
299 mouse_task=-1;
300 wg_waterf_zero_time=0;
301 mouse_active_flag=0;
302 }
303 
wide_graph_add_signal(void)304 void wide_graph_add_signal(void)
305 {
306 float t1;
307 int i;
308 int event_no;
309 // The user made a click on the right mouse button.
310 for(event_no=0; event_no<MAX_WGBUTT; event_no++)
311   {
312   if( wgbutt[event_no].x1 <= mouse_x &&
313       wgbutt[event_no].x2 >= mouse_x &&
314       wgbutt[event_no].y1 <= mouse_y &&
315       wgbutt[event_no].y2 >= mouse_y)
316     {
317     wg_old_y1=wg.ytop;
318     wg_old_y2=wg.ybottom;
319     wg_old_x1=wg.xleft;
320     wg_old_x2=wg.xright;
321     mouse_active_flag=1+event_no;
322     current_mouse_activity=mouse_continue_wide_graph_rightpressed;
323     return;
324     }
325   }
326 // If the mouse is on the frequency scale, shift the
327 // range of frequencies that we display.
328 // Add or remove a receive signal.
329 // We arrive here when the mouse right button is pressed.
330 // mix1_selfreq[0] is the frequency we process and send to the loudspeaker.
331 // The other frequencies are translated from CW to ASCII and placed on
332 // the screen (hopefully, some time...).
333 // If we are within +/- 3 pixels from a frequency that is already selected
334 // we deselect it.
335 if(rightpressed==BUTTON_RELEASED)
336   {
337   t1=wg_check_mix1(0);
338   if(t1 <0)
339     {
340     sc[SC_FREQ_READOUT]++;
341     baseb_reset_counter++;
342     if( ((unsigned int)ui.network_flag & NET_RX_INPUT) != 0)
343       {
344       net_send_slaves_freq();
345       }
346     goto addx;
347     }
348   for(i=1; i<genparm[MIX1_NO_OF_CHANNELS]; i++)
349     {
350     if(mix1_selfreq[i]<0)
351       {
352       make_new_signal(i,t1);
353       goto addx;
354       }
355     }
356 addx:;
357   if(rightpressed==BUTTON_RELEASED)
358     {
359     sc[SC_SHOW_FFT1]++;
360     rightpressed=BUTTON_IDLE;
361     mouse_task=-1;
362     }
363   }
364 }
365 
make_wg_waterf_cfac(void)366 void make_wg_waterf_cfac(void)
367 {
368 wg_waterf_cfac=wg.waterfall_db_gain*0.01F;
369 wg_waterf_czer=100*(wg.waterfall_db_zero+WATERFALL_SCALE_ZERO);
370 }
371 
372 
check_wg_fft_avgnum(void)373 void check_wg_fft_avgnum(void)
374 {
375 // fft1 average power spectra are used to display the full dynamic
376 // range spectrum.
377 // In case fft2 is not enabled they are also used for the waterfall graph
378 // and for AFC (if enabled)
379 // Average power spectra are time consuming to calculate so several
380 // different ways are used depending on the needs.
381 // wg.fft_avg1num 1 to MAX_FFT1_AVG1
382 // fft1_sumsq=sum over avg1num spectra.
383 // wg.spek_avgnum = number of spectra for main spectrum
384 // wg.spek_avgnum=wg.fft_avg1num*wg_fft_avg2num;
385 // On entry here wg.fft_avg1num is determined by the user.
386 // change wg.spek_avgnum if necessary
387 // calculate the new avg2num
388 // In case neither AFC nor fft2 is enabled, make sure the averaging
389 // selected for the waterfall graph is a multiple of wg.fft_avg1num.
390 if(wg.fft_avg1num<1)wg.fft_avg1num=1;
391 if(wg.fft_avg1num>MAX_FFT1_AVG1)wg.fft_avg1num=MAX_FFT1_AVG1;
392 if(wg.spek_avgnum<wg.fft_avg1num)wg.spek_avgnum=wg.fft_avg1num;
393 wg_fft_avg2num=(wg.spek_avgnum+wg.fft_avg1num/2)/wg.fft_avg1num;
394 if(wg_fft_avg2num >= max_fft1_sumsq)wg_fft_avg2num=max_fft1_sumsq-1;
395 wg.spek_avgnum=wg.fft_avg1num*wg_fft_avg2num;
396 while(wg.spek_avgnum >= 99999)
397   {
398   wg_fft_avg2num--;
399   wg.spek_avgnum=wg.fft_avg1num*wg_fft_avg2num;
400   }
401 if( genparm[SECOND_FFT_ENABLE] == 0 )
402   {
403   if(wg.waterfall_avgnum<wg.fft_avg1num)wg.waterfall_avgnum=wg.fft_avg1num;
404   wg.waterfall_avgnum=(wg.waterfall_avgnum+wg.fft_avg1num/2)/wg.fft_avg1num;
405   wg.waterfall_avgnum*=wg.fft_avg1num;
406   }
407 }
408 
wg_error(char * txt,int line)409 void wg_error(char *txt,int line)
410 {
411 int i;
412 i=0;
413 while(txt[i]!=0)i++;
414 settextcolor(15);
415 i=wg.xright/text_width-4-i;
416 if(i<=wg.xleft/text_width)i=wg.xleft/text_width+1;
417 lir_text(i,wg.ybottom/text_height-2-line,txt);
418 settextcolor(7);
419 }
420 
421 
decrease_wg_pixels_per_points(void)422 void decrease_wg_pixels_per_points(void)
423 {
424 if(wg_xpixels < 128)return;
425 if(wg.pixels_per_xpoint != 0)
426   {
427   wg.pixels_per_xpoint/=2;
428   if(wg.pixels_per_xpoint > 0)
429     {
430     wg.xpoints=wg_xpixels/wg.pixels_per_xpoint;
431     }
432   else
433     {
434     wg.pixels_per_xpoint=0;
435     wg.xpoints_per_pixel=2;
436     wg.xpoints=wg_xpixels*2;
437     }
438   }
439 else
440   {
441   if(genparm[SECOND_FFT_ENABLE] == 0)
442     {
443     wg.xpoints_per_pixel++;
444     wg.xpoints=wg_xpixels*wg.xpoints_per_pixel;
445     }
446   else
447     {
448     wg.xpoints_per_pixel*=2;
449     wg.xpoints=wg_xpixels*wg.xpoints_per_pixel;
450     }
451   }
452 }
453 
help_on_wide_graph(void)454 void help_on_wide_graph(void)
455 {
456 int msg_no;
457 int event_no;
458 // Set msg to select a frequency in case it is not button or border
459 msg_no=340;
460 // First find out is we are on a button or border line.
461 for(event_no=0; event_no<MAX_WGBUTT; event_no++)
462   {
463   if( wgbutt[event_no].x1 <= mouse_x &&
464       wgbutt[event_no].x2 >= mouse_x &&
465       wgbutt[event_no].y1 <= mouse_y &&
466       wgbutt[event_no].y2 >= mouse_y)
467     {
468     switch (event_no)
469       {
470       case WG_TOP:
471       case WG_BORDER:
472       case WG_BOTTOM:
473       case WG_LEFT:
474       case WG_RIGHT:
475       msg_no=100;
476       break;
477 
478       case WG_YSCALE_EXPAND:
479       msg_no=3;
480       break;
481 
482       case WG_YSCALE_CONTRACT:
483       msg_no=4;
484       break;
485 
486       case WG_YZERO_DECREASE:
487       msg_no=5;
488       break;
489 
490       case WG_YZERO_INCREASE:
491       msg_no=6;
492       break;
493 
494       case WG_FQMIN_DECREASE:
495       msg_no=7;
496       break;
497 
498       case WG_FQMIN_INCREASE:
499       msg_no=8;
500       break;
501 
502       case WG_FQMAX_DECREASE:
503       msg_no=9;
504       break;
505 
506       case WG_FQMAX_INCREASE:
507       msg_no=10;
508       break;
509 
510       case WG_SPUR_TOGGLE:
511       msg_no=316;
512       break;
513 
514       case WG_AVG1NUM:
515       if(genparm[SECOND_FFT_ENABLE]==0)
516         {
517         msg_no=11;
518         }
519       else
520         {
521         msg_no=12;
522         }
523       break;
524 
525       case WG_FFT1_AVGNUM:
526       if(genparm[SECOND_FFT_ENABLE] == 0)
527         {
528         msg_no=58;
529         }
530       else
531         {
532         msg_no=59;
533         }
534       break;
535 
536       case WG_WATERF_AVGNUM:
537       if(genparm[SECOND_FFT_ENABLE] == 0)
538         {
539         msg_no=60;
540         }
541       else
542         {
543         msg_no=61;
544         }
545       break;
546 
547       case WG_WATERF_ZERO:
548       if(genparm[SECOND_FFT_ENABLE] == 0)
549         {
550         msg_no=64;
551         }
552       else
553         {
554         msg_no=65;
555         }
556       break;
557 
558       case WG_WATERF_GAIN:
559       if(genparm[SECOND_FFT_ENABLE] == 0)
560         {
561         msg_no=66;
562         }
563       else
564         {
565         msg_no=67;
566         }
567       break;
568 
569       case WG_FREQ_ADJUSTMENT_MODE:
570       msg_no=323;
571       break;
572 
573       case WG_LOWEST_FREQ:
574       msg_no=324;
575       break;
576 
577       case WG_HIGHEST_FREQ:
578       msg_no=325;
579       break;
580       }
581     }
582   }
583 help_message(msg_no);
584 }
585 
change_fft1avgnum(void)586 void change_fft1avgnum(void)
587 {
588 wg.spek_avgnum=numinput_int_data;
589 check_wg_fft_avgnum();
590 change_fft1_flag=TRUE;
591 make_wg_yfac();
592 make_modepar_file(GRAPHTYPE_WG);
593 sc[SC_WG_BUTTONS]++;
594 }
595 
change_waterfall_avgnum(void)596 void change_waterfall_avgnum(void)
597 {
598 wg.waterfall_avgnum=numinput_int_data;
599 if(wg.waterfall_avgnum < 1)
600   {
601   wg.waterfall_avgnum=1;
602   }
603 if(genparm[SECOND_FFT_ENABLE] == 0) check_wg_fft_avgnum();
604 make_wg_yfac();
605 make_modepar_file(GRAPHTYPE_WG);
606 sc[SC_WG_BUTTONS]++;
607 }
608 
change_wg_waterfall_zero(void)609 void change_wg_waterfall_zero(void)
610 {
611 wg.waterfall_db_zero=numinput_float_data;
612 make_modepar_file(GRAPHTYPE_WG);
613 sc[SC_WG_WATERF_REDRAW]++;
614 }
615 
change_wg_waterfall_gain(void)616 void change_wg_waterfall_gain(void)
617 {
618 wg.waterfall_db_gain=numinput_float_data;
619 if(wg.waterfall_db_gain <0.01F)wg.waterfall_db_gain=0.01F;
620 make_modepar_file(GRAPHTYPE_WG);
621 sc[SC_WG_WATERF_REDRAW]++;
622 }
623 
624 
change_wg_lowest_freq(void)625 void change_wg_lowest_freq(void)
626 {
627 float t1, t2;
628 t1=(float)(0.1*frequency_scale_offset);
629 t2=t1+(float)(0.000001*(fft1_size-4)*fft1_hz_per_point);
630 wg_lowest_freq=numinput_float_data;
631 if(wg_lowest_freq > t2)wg_lowest_freq=t2;
632 if(wg_lowest_freq < t1)wg_lowest_freq=t1;
633 make_modepar_file(GRAPHTYPE_WG);
634 sc[SC_WG_WATERF_REDRAW]++;
635 }
636 
change_wg_highest_freq(void)637 void change_wg_highest_freq(void)
638 {
639 float t1, t2;
640 t1=(float)(0.1*frequency_scale_offset+0.000004*fft1_hz_per_point);
641 t2=t1+0.000001F*(float)(fft1_size-4)*fft1_hz_per_point;
642 wg_highest_freq=numinput_float_data;
643 if(wg_highest_freq > t2)wg_highest_freq=t2;
644 if(wg_highest_freq < t1)wg_highest_freq=t1;
645 make_modepar_file(GRAPHTYPE_WG);
646 sc[SC_WG_WATERF_REDRAW]++;
647 }
648 
mouse_continue_wide_graph(void)649 void mouse_continue_wide_graph(void)
650 {
651 int j, old_xpoints;
652 switch (mouse_active_flag-1)
653   {
654   case WG_TOP:
655   if(wg.ytop!=mouse_y)
656     {
657     pause_screen_and_hide_mouse();
658     dual_graph_borders((void*)&wg,0);
659     wg.ytop=mouse_y;
660     j=wg.yborder-text_height-YBO;
661     if(wg.ytop > j)wg.ytop=j;
662     if(wg_old_y1 > wg.ytop)wg_old_y1=wg.ytop;
663     dual_graph_borders((void*)&wg,15);
664     resume_thread(THREAD_SCREEN);
665     }
666   break;
667 
668   case WG_BORDER:
669   if(wg.yborder!=mouse_y)
670     {
671     pause_screen_and_hide_mouse();
672     dual_graph_borders((void*)&wg,0);
673     wg.yborder=mouse_y;
674     j=wg.ytop+text_height+YBO;
675     if(wg.yborder < j)wg.yborder=j;
676     j=wg.ybottom-2*text_height;
677     if(wg.yborder > j)wg.yborder=j;
678     dual_graph_borders((void*)&wg,15);
679     resume_thread(THREAD_SCREEN);
680     }
681   break;
682 
683   case WG_BOTTOM:
684   if(wg.ybottom!=mouse_y)
685     {
686     pause_screen_and_hide_mouse();
687     dual_graph_borders((void*)&wg,0);
688     wg.ybottom=mouse_y;
689     j=wg.yborder+2*text_height;
690     if(wg.ybottom < j)wg.ybottom=j;
691     if(wg_old_y2 < wg.ybottom)wg_old_y2=wg.ybottom;
692     dual_graph_borders((void*)&wg,15);
693     resume_thread(THREAD_SCREEN);
694     }
695   break;
696 
697   case WG_LEFT:
698   if(wg.xleft!=mouse_x)
699     {
700     pause_screen_and_hide_mouse();
701     dual_graph_borders((void*)&wg,0);
702     wg.xleft=mouse_x;
703     j=wg.xright-32-6*text_width;
704     if(wg.xleft > j)wg.xleft=j;
705     if(wg_old_x1 > wg.xleft)wg_old_x1=wg.xleft;
706     dual_graph_borders((void*)&wg,15);
707     resume_thread(THREAD_SCREEN);
708     }
709   break;
710 
711   case WG_RIGHT:
712   if(wg.xright!=mouse_x)
713     {
714     pause_screen_and_hide_mouse();
715     dual_graph_borders((void*)&wg,0);
716     wg.xright=mouse_x;
717     j=wg.xleft+32+6*text_width;
718     if(wg.xright < j)wg.xright=j;
719     if(wg_old_x2 < wg.xright)wg_old_x2=wg.xright;
720     dual_graph_borders((void*)&wg,15);
721     resume_thread(THREAD_SCREEN);
722     }
723   break;
724 
725   default:
726   goto await_release;
727   }
728 if(leftpressed == BUTTON_RELEASED)goto finish;
729 return;
730 await_release:;
731 if(leftpressed != BUTTON_RELEASED) return;
732 switch (mouse_active_flag-1)
733   {
734   case WG_YSCALE_EXPAND:
735   wg.yrange=wg.yrange/(float)pow(wg.yrange,.2);
736   break;
737 
738   case WG_YSCALE_CONTRACT:
739   wg.yrange=wg.yrange*(float)pow(wg.yrange,.18);
740   break;
741 
742   case WG_YZERO_DECREASE:
743   wg.yzero=wg.yzero/(float)pow(wg.yrange,.2);
744   break;
745 
746   case WG_YZERO_INCREASE:
747   wg.yzero=(float)(wg.yzero*pow(wg.yrange,.18));
748   break;
749 
750   case WG_FQMIN_DECREASE:
751   old_xpoints=wg.xpoints;
752   decrease_wg_pixels_per_points();
753   wg.first_xpoint-=wg.xpoints-old_xpoints;
754   break;
755 
756   case WG_FQMIN_INCREASE:
757   old_xpoints=wg.xpoints;
758   increase_wg_pixels_per_points();
759   wg.first_xpoint-=wg.xpoints-old_xpoints;
760   break;
761 
762   case WG_FQMAX_DECREASE:
763   old_xpoints=wg.xpoints;
764   increase_wg_pixels_per_points();
765   break;
766 
767   case WG_FQMAX_INCREASE:
768   old_xpoints=wg.xpoints;
769   decrease_wg_pixels_per_points();
770   break;
771 
772   case WG_AVG1NUM:
773   wg.fft_avg1num++;
774   if(wg.fft_avg1num > MAX_FFT1_AVG1)wg.fft_avg1num=1;
775   check_wg_fft_avgnum();
776   sc[SC_WG_BUTTONS]++;
777   break;
778 
779   case WG_FFT1_AVGNUM:
780   mouse_active_flag=1;
781   numinput_xpix=wgbutt[WG_FFT1_AVGNUM].x1+text_width/2-1;
782   numinput_ypix=wgbutt[WG_FFT1_AVGNUM].y1+2;
783   numinput_chars=5;
784   erase_numinput_txt();
785   numinput_flag=FIXED_INT_PARM;
786   par_from_keyboard_routine=change_fft1avgnum;
787   return;
788 
789   case WG_WATERF_AVGNUM:
790   mouse_active_flag=1;
791   numinput_xpix=wgbutt[WG_WATERF_AVGNUM].x1+text_width/2-1;
792   numinput_ypix=wgbutt[WG_WATERF_AVGNUM].y1+2;
793   numinput_chars=4;
794   erase_numinput_txt();
795   numinput_flag=FIXED_INT_PARM;
796   par_from_keyboard_routine=change_waterfall_avgnum;
797   return;
798 
799   case WG_WATERF_ZERO:
800   mouse_active_flag=1;
801   numinput_xpix=wgbutt[WG_WATERF_ZERO].x1+text_width/2-1;
802   numinput_ypix=wgbutt[WG_WATERF_ZERO].y1+2;
803   numinput_chars=5;
804   erase_numinput_txt();
805   numinput_flag=FIXED_FLOAT_PARM;
806   par_from_keyboard_routine=change_wg_waterfall_zero;
807   return;
808 
809   case WG_WATERF_GAIN:
810   mouse_active_flag=1;
811   numinput_xpix=wgbutt[WG_WATERF_GAIN].x1+text_width/2-1;
812   numinput_ypix=wgbutt[WG_WATERF_GAIN].y1+2;
813   numinput_chars=4;
814   erase_numinput_txt();
815   numinput_flag=FIXED_FLOAT_PARM;
816   par_from_keyboard_routine=change_wg_waterfall_gain;
817   return;
818 
819   case WG_SPUR_TOGGLE:
820   wg.spur_inhibit^=1;
821   wg.spur_inhibit&=1;
822   if(wg.spur_inhibit == 1)spurcancel_flag++;
823   leftpressed=BUTTON_IDLE;
824   mouse_active_flag=0;
825   make_modepar_file(GRAPHTYPE_WG);
826   sc[SC_WG_WATERF_REDRAW]++;
827   return;
828 
829   case WG_FREQ_ADJUSTMENT_MODE:
830   wg_freq_adjustment_mode++;
831   if(wg_freq_adjustment_mode < 2)
832     {
833     make_wg_fqlimits();
834     }
835   break;
836 
837   case WG_LOWEST_FREQ:
838   mouse_active_flag=1;
839   numinput_xpix=wgbutt[WG_LOWEST_FREQ].x1+text_width/2-1;
840   numinput_ypix=wgbutt[WG_LOWEST_FREQ].y1+2;
841   numinput_chars=(wgbutt[WG_LOWEST_FREQ].x2 -
842                                    wgbutt[WG_LOWEST_FREQ].x1)/text_width-1;
843   erase_numinput_txt();
844   numinput_flag=FIXED_FLOAT_PARM;
845   par_from_keyboard_routine=change_wg_lowest_freq;
846   return;
847 
848   case WG_HIGHEST_FREQ:
849   mouse_active_flag=1;
850   numinput_xpix=wgbutt[WG_HIGHEST_FREQ].x1+text_width/2-1;
851   numinput_ypix=wgbutt[WG_HIGHEST_FREQ].y1+2;
852   numinput_chars=(wgbutt[WG_HIGHEST_FREQ].x2 -
853                                    wgbutt[WG_HIGHEST_FREQ].x1)/text_width-1;
854   erase_numinput_txt();
855   numinput_flag=FIXED_FLOAT_PARM;
856   par_from_keyboard_routine=change_wg_highest_freq;
857   return;
858   }
859 finish:;
860 leftpressed=BUTTON_IDLE;
861 mouse_active_flag=0;
862 make_wide_graph(TRUE);
863 }
864 
mouse_on_wide_graph(void)865 void mouse_on_wide_graph(void)
866 {
867 int event_no;
868 // First find out if we are on a button or border line.
869 for(event_no=0; event_no<MAX_WGBUTT; event_no++)
870   {
871   if( wgbutt[event_no].x1 <= mouse_x &&
872       wgbutt[event_no].x2 >= mouse_x &&
873       wgbutt[event_no].y1 <= mouse_y &&
874       wgbutt[event_no].y2 >= mouse_y)
875     {
876     wg_old_y1=wg.ytop;
877     wg_old_y2=wg.ybottom;
878     wg_old_x1=wg.xleft;
879     wg_old_x2=wg.xright;
880     mouse_active_flag=1+event_no;
881     current_mouse_activity=mouse_continue_wide_graph;
882     return;
883     }
884   }
885 if(rx_mode != MODE_TXTEST && rx_mode != MODE_RADAR)
886   {
887 // Not button or border.
888 // Select a frequency.
889   current_mouse_activity=wide_graph_selfreq;
890   }
891 else
892   {
893   current_mouse_activity=mouse_nothing;
894   }
895 mouse_active_flag=1;
896 }
897 
898 
make_wg_yfac(void)899 void make_wg_yfac(void)
900 {
901 float t1;
902 int i;
903 wg_yfac_power=1/(4*(float)wg.spek_avgnum*wg.yzero*wg.yzero);
904 // If waterfall is generated from fft1 we set the zero point here.
905 t1=(float)FFT1_WATERFALL_ZERO/(float)wg.waterfall_avgnum;
906 if(wg.xpoints_per_pixel > 1)
907   {
908   wg_yfac_power/=(float)wg.xpoints_per_pixel*(float)wg.xpoints_per_pixel;
909   t1*=(float)ui.rx_rf_channels;
910   }
911 if(genparm[SECOND_FFT_ENABLE] != 0)
912   {
913 // The constant here sets the zero point for the waterfall graph
914 // generated by fft2.
915   t1=(float)(FFT2_WATERFALL_ZERO)/((float)fft2_size*(float)fft1_size);
916   t1/=(float)sqrt((float)(wg.waterfall_avgnum));
917   if(fft_cntrl[FFT2_CURMODE].mmx != 0)
918     {
919     t1*=(float)(2<<(2*(genparm[SECOND_FFT_ATT_N])));
920     }
921   t1*=(float)(1<<(2*genparm[FIRST_BCKFFT_ATT_N]));
922   t1*=(float)(1 + 1/(0.5+genparm[FIRST_FFT_SINPOW]));
923   t1*=(float)(ui.rx_rf_channels*ui.rx_rf_channels);
924   }
925 // Straighten out the waterfall graph until the -10dB point is reached
926 for(i=0; i<fft1_size; i++)
927   {
928   if(fft1_desired[i] > 0.3162278)
929     {
930     wg_waterf_yfac[i]=t1/(float)pow(fft1_desired[i],2.0);
931     }
932   else
933     {
934     wg_waterf_yfac[i]=t1*10;
935     }
936   }
937 wg_waterf_yfac[0]=t1;
938 wg_waterf_yfac[fft1_size-1]=t1;
939 wg_yfac_log=10/wg_db_per_pixel;
940 }
941 
new_fft1_averages(int ptr,int ia,int ib)942 void new_fft1_averages(int ptr, int ia, int ib)
943 {
944 int i,m,p0;
945 change_fft1_flag=FALSE;
946 if(lir_status==LIR_POWTIM)return;
947 // Make fft1_slowsum from scratch over the specified interval
948 // We have power spectra in fft1_sumsq and we want to take
949 // the sum over the latest wg.fft_avg2num of them.
950 if(ia<0)lirerr(521233);
951 if(ib<ia)lirerr(521234);
952 if(ib>=fft1_size)lirerr(521235);
953 p0=(ptr-(wg_fft_avg2num-1)*fft1_size+fft1_sumsq_bufsize)
954                                                           &fft1_sumsq_mask;
955 for(i=ia; i<=ib; i++)
956   {
957   fft1_slowsum[i]=fft1_sumsq[p0+i]+0.0000001F;
958   }
959 p0=(p0+fft1_size)&fft1_sumsq_mask;
960 for(m=1; m<wg_fft_avg2num; m++)
961   {
962   for(i=ia; i<=ib; i++)fft1_slowsum[i]+=fft1_sumsq[p0+i];
963   p0=(p0+fft1_size)&fft1_sumsq_mask;
964   }
965 if(fft1_correlation_flag)
966   {
967   p0=(ptr-(wg_fft_avg2num-1)*fft1_size+fft1_sumsq_bufsize)
968                                                           &fft1_sumsq_mask;
969   for(i=ia; i<=ib; i++)
970     {
971     fft1_slowcorr[2*i  ]=fft1_corrsum[2*(p0+i)  ];
972     fft1_slowcorr[2*i+1]=fft1_corrsum[2*(p0+i)+1];
973     }
974   p0=(p0+fft1_size)&fft1_sumsq_mask;
975   for(m=1; m<wg_fft_avg2num; m++)
976     {
977     for(i=ia; i<=ib; i++)
978       {
979       fft1_slowcorr[2*i  ]+=fft1_corrsum[2*(p0+i)  ];
980       fft1_slowcorr[2*i+1]+=fft1_corrsum[2*(p0+i)+1];
981       }
982     p0=(p0+fft1_size)&fft1_sumsq_mask;
983     }
984   }
985 }
986 
increase_wg_pixels_per_points(void)987 void increase_wg_pixels_per_points(void)
988 {
989 if(wg.pixels_per_xpoint != 0)
990   {
991   wg.pixels_per_xpoint*=2;
992   wg.xpoints=wg_xpixels/wg.pixels_per_xpoint;
993   wg.xpoints_per_pixel=0;
994   }
995 else
996   {
997   wg.xpoints_per_pixel--;
998   wg.xpoints=wg_xpixels*wg.xpoints_per_pixel;
999   if(wg.xpoints_per_pixel == 1)
1000     {
1001     wg.pixels_per_xpoint=1;
1002     wg.xpoints=wg_xpixels;
1003     }
1004   else
1005     {
1006     wg.pixels_per_xpoint=0;
1007     }
1008   }
1009 }
1010 
make_wide_graph(int clear_old)1011 void make_wide_graph(int clear_old)
1012 {
1013 char s[80];
1014 int i, j, k;
1015 int old_xpix;
1016 int hgwat_xpoints;
1017 float t2;
1018 int ypixels;
1019 float t1;
1020 double db_scalestep, scale_value;
1021 float scale_y;
1022 int scale_decimals;
1023 float scale_rnd;
1024 pause_thread(THREAD_SCREEN);
1025 if(clear_old)
1026   {
1027   hide_mouse(wg_old_x1,wg_old_x2,wg_old_y1,wg_old_y2);
1028   lir_fillbox(wg_old_x1,wg_old_y1,wg_old_x2-wg_old_x1+1,
1029                                                     wg_old_y2-wg_old_y1+1,0);
1030   }
1031 // If there is another window open, make sure we stay away from it
1032 current_graph_minh=YBO+3*text_height;
1033 current_graph_minw=32+6*text_width;
1034 check_graph_placement(&wg);
1035 clear_button(wgbutt, MAX_WGBUTT);
1036 hide_mouse(wg.xleft,wg.xright,wg.ytop,wg.ybottom);
1037 if(wg.ybottom-wg.ytop<3*text_height+YBO)
1038   {
1039   wg.yborder=(wg.ybottom+wg.ytop)/2;
1040   }
1041 else
1042   {
1043   if(wg.yborder < wg.ytop+text_height+YBO)wg.yborder=wg.ytop+text_height+YBO;
1044   if(wg.yborder > wg.ybottom-2*text_height)wg.yborder=wg.ybottom-2*text_height;
1045   }
1046 wg_waterf_lines=wg.yborder-wg.ytop-text_height-YWF;
1047 wg_waterf_y1=wg.ytop+text_height+YWF+1;
1048 wg_waterf_y2=wg_waterf_y1+2+wg_waterf_lines/16;
1049 if(wg_waterf_y2 > wg_waterf_y1+wg_waterf_lines-1)
1050                            wg_waterf_y2=wg_waterf_y1+wg_waterf_lines-1;
1051 wg_waterf_y=wg_waterf_y2;
1052 if(wg_waterf_y2 > wg.yborder-1)wg_waterf_y2=wg.yborder-1;
1053 wg_waterf_yinc=wg_waterf_y2-wg_waterf_y1+1;
1054 if(wg_freq_adjustment_mode >= 2)
1055   {
1056   wg_freq_adjustment_mode=0;
1057 // Find out whether we can expand our window.
1058   k=wg.xright-wg.xleft;
1059   i=0;
1060   while(i!=k)
1061     {
1062     i=k;
1063     wg.xleft=wg.xleft-k/2;
1064     wg.xright=wg.xright+k/2;
1065     if(wg.xleft<0)wg.xleft=0;
1066     if(wg.xright >= screen_width)wg.xright=screen_width-1;
1067     check_graph_placement(&wg);
1068     k=wg.xright-wg.xleft;
1069     }
1070   wg.xpoints=(int)(1000000*(wg_highest_freq-wg_lowest_freq)/fft1_hz_per_point);
1071   if(wg.xpoints < 4)wg.xpoints=4;
1072   if(wg.xpoints > fft1_size)wg.xpoints=fft1_size;
1073   wg_first_frequency=(float)(1000000*wg_lowest_freq
1074                                -100000*frequency_scale_offset);
1075   wg.first_xpoint=(int)(wg_first_frequency/fft1_hz_per_point);
1076   wg_xpixels=wg.xright-wg.xleft-6*text_width+1;
1077   wg.pixels_per_xpoint=wg_xpixels/wg.xpoints;
1078   if(wg.pixels_per_xpoint > 0)
1079     {
1080     if(wg.pixels_per_xpoint == 1)
1081       {
1082       wg.xpoints_per_pixel=1;
1083       }
1084     else
1085       {
1086       wg.xpoints_per_pixel=0;
1087       }
1088     wg_xpixels=wg.xpoints*wg.pixels_per_xpoint;
1089     }
1090   else
1091     {
1092     wg.xpoints_per_pixel=wg.xpoints/wg_xpixels;
1093     wg.xpoints=wg_xpixels*wg.xpoints_per_pixel;
1094     }
1095   wg.xright=wg_xpixels+wg.xleft+6*text_width-1;
1096   }
1097 if(wg.first_xpoint<0)wg.first_xpoint=0;
1098 // Check if the desired spectrum fits within the frame and
1099 // make changes as required if not.
1100 wg_first_xpixel=wg.xleft+4*text_width;
1101 wg_last_xpixel=wg.xright-2*text_width;
1102 wg_xpixels = wg_last_xpixel-wg_first_xpixel+1;
1103 old_xpix=wg_xpixels;
1104 if(wg.pixels_per_xpoint != 0)
1105   {
1106   wg.xpoints=wg_xpixels/wg.pixels_per_xpoint;
1107   }
1108 else
1109   {
1110   wg.xpoints=wg_xpixels*wg.xpoints_per_pixel;
1111   }
1112 if(wg.xpoints < 4)
1113   {
1114   wg.xpoints=4;
1115   wg.pixels_per_xpoint=wg_xpixels/wg.xpoints;
1116   wg.xpoints_per_pixel=0;
1117   }
1118 if(rx_mode == MODE_TXTEST)
1119   {
1120   if(wg.xpoints_per_pixel != 0)
1121     {
1122     if( fft1_hz_per_point*wg.xpoints_per_pixel > 600)
1123       {
1124       wg.xpoints_per_pixel=595/fft1_hz_per_point;
1125       wg.xpoints=wg_xpixels*wg.xpoints_per_pixel;
1126       }
1127     }
1128   else
1129     {
1130     if(wg.pixels_per_xpoint*fft1_hz_per_point > 400)
1131       {
1132       wg.pixels_per_xpoint= 400/fft1_hz_per_point;
1133       wg.xpoints=wg_xpixels/wg.pixels_per_xpoint;
1134       wg_xpixels=wg.xpoints*wg.pixels_per_xpoint;
1135       }
1136     }
1137   txtest_no_of_segs=wg.xpoints*fft1_hz_per_point/600;
1138   if(txtest_no_of_segs > screen_width-4*text_width)
1139     {
1140     wg.xpoints=600*(screen_width-4*text_width)/fft1_hz_per_point;
1141     if(wg.pixels_per_xpoint != 0)
1142       {
1143       wg_xpixels=wg.xpoints*wg.pixels_per_xpoint;
1144       }
1145     else
1146       {
1147       wg_xpixels=wg.xpoints/wg.xpoints_per_pixel;
1148       wg.xpoints=wg_xpixels*wg.xpoints_per_pixel;
1149       }
1150     }
1151   if(wg_xpixels > wg.xright-wg.xleft-6*text_width+1)
1152     {
1153     wg_xpixels=wg.xright-wg.xleft-6*text_width+1;
1154     if(wg.pixels_per_xpoint != 0)
1155       {
1156       wg.xpoints=wg_xpixels/wg.pixels_per_xpoint;
1157       wg_xpixels=wg.xpoints*wg.pixels_per_xpoint;
1158       }
1159     else
1160       {
1161       wg.xpoints=wg_xpixels*wg.xpoints_per_pixel;
1162       }
1163     }
1164   }
1165 if(wg.xpoints>fft1_size)
1166   {
1167   wg.xpoints=fft1_size;
1168   if(wg.pixels_per_xpoint != 0)
1169     {
1170     wg_xpixels=wg.xpoints*wg.pixels_per_xpoint;
1171     }
1172   else
1173     {
1174     wg_xpixels=wg.xpoints/wg.xpoints_per_pixel;
1175     }
1176   }
1177 if(wg.first_xpoint+wg.xpoints>=fft1_size)wg.first_xpoint=fft1_size-wg.xpoints;
1178 // Now that we know that fft1 fits in the window, set the number of
1179 // pixels per data point.
1180 if(genparm[SECOND_FFT_ENABLE] != 0)
1181   {
1182   hgwat_xpoints=wg.xpoints*fft2_to_fft1_ratio;
1183   if(hgwat_xpoints > wg_xpixels)
1184     {
1185     hgwat_xpoints_per_pixel=hgwat_xpoints/wg_xpixels;
1186     hgwat_pixels_per_xpoint=0;
1187     wg.xpoints_per_pixel=hgwat_xpoints_per_pixel/fft2_to_fft1_ratio;
1188     if(wg.xpoints_per_pixel > 0)
1189       {
1190       hgwat_xpoints_per_pixel=wg.xpoints_per_pixel*fft2_to_fft1_ratio;
1191       wg_xpixels=hgwat_xpoints/hgwat_xpoints_per_pixel;
1192       wg.xpoints=wg_xpixels*wg.xpoints_per_pixel;
1193       if(wg.xpoints_per_pixel == 1)
1194         {
1195         wg.pixels_per_xpoint=1;
1196         }
1197       else
1198         {
1199         wg.pixels_per_xpoint=0;
1200         }
1201       wg_hz_per_pixel=fft1_hz_per_point*(float)wg.xpoints_per_pixel;
1202       }
1203     else
1204       {
1205       wg.pixels_per_xpoint=fft2_to_fft1_ratio/hgwat_xpoints_per_pixel;
1206       wg_xpixels=wg.xpoints*wg.pixels_per_xpoint;
1207       while(wg_xpixels > old_xpix)
1208         {
1209         wg.xpoints--;
1210         wg_xpixels-=wg.pixels_per_xpoint;
1211         }
1212       wg.xpoints=wg_xpixels/wg.pixels_per_xpoint;
1213       wg_hz_per_pixel=fft1_hz_per_point/(float)wg.pixels_per_xpoint;
1214       make_power_of_two(&wg.pixels_per_xpoint);
1215       hgwat_xpoints_per_pixel=fft2_to_fft1_ratio/wg.pixels_per_xpoint;
1216       }
1217     }
1218   else
1219     {
1220     hgwat_xpoints_per_pixel=0;
1221     hgwat_pixels_per_xpoint=wg_xpixels/hgwat_xpoints;
1222     wg.pixels_per_xpoint=fft2_to_fft1_ratio*hgwat_pixels_per_xpoint;
1223     wg_xpixels=wg.xpoints*wg.pixels_per_xpoint;
1224     wg.xpoints=wg_xpixels/wg.pixels_per_xpoint;
1225     wg_hz_per_pixel=fft1_hz_per_point/(float)wg.pixels_per_xpoint;
1226     if(wg.pixels_per_xpoint == 1)
1227       {
1228       wg.xpoints_per_pixel=1;
1229       }
1230     else
1231       {
1232       wg.xpoints_per_pixel=0;
1233       }
1234     }
1235   hgwat_first_xpoint=wg.first_xpoint*fft2_to_fft1_ratio;
1236   }
1237 else
1238   {
1239   if(wg.pixels_per_xpoint != 0)
1240     {
1241     wg_xpixels=wg.xpoints*wg.pixels_per_xpoint;
1242     wg_hz_per_pixel=fft1_hz_per_point/(float)wg.pixels_per_xpoint;
1243     }
1244   else
1245     {
1246     wg_xpixels=wg.xpoints/wg.xpoints_per_pixel;
1247     wg_hz_per_pixel=fft1_hz_per_point*(float)wg.xpoints_per_pixel;
1248     }
1249   }
1250 wg_last_xpixel=wg_first_xpixel+wg_xpixels-1;
1251 if(genparm[WG_WATERF_BLANKED_PERCENT] == 0)
1252   {
1253   wg_waterfall_blank_points=0;
1254   }
1255 else
1256   {
1257   wg_waterfall_blank_points=1+(genparm[WG_WATERF_BLANKED_PERCENT]*wg_xpixels)/100;
1258   }
1259 wg.xright=wg_last_xpixel+2*text_width;
1260 wg_first_frequency=fft1_hz_per_point*(float)wg.first_xpoint;
1261 set_fft1_endpoints();
1262 mix1_lowest_fq=(float)(fft1_first_point+1)*fft1_hz_per_point;
1263 t2=(float)wg.first_xpoint*fft1_hz_per_point;
1264 if(mix1_lowest_fq<t2) mix1_lowest_fq=t2;
1265 mix1_highest_fq=(float)(fft1_last_point-1)*fft1_hz_per_point;
1266 t2=(float)((float)wg_last_point*fft1_hz_per_point);
1267 if(mix1_highest_fq > t2)mix1_highest_fq=t2;
1268 if(wg.ybottom >= screen_height)wg.ybottom=screen_height-1;
1269 scro[wide_graph_scro].no=WIDE_GRAPH;
1270 scro[wide_graph_scro].x1=wg.xleft;
1271 scro[wide_graph_scro].x2=wg.xright;
1272 scro[wide_graph_scro].y1=wg.ytop;
1273 scro[wide_graph_scro].y2=wg.ybottom;
1274 wgbutt[WG_LEFT].x1=wg.xleft;
1275 wgbutt[WG_LEFT].x2=wg.xleft+2;
1276 wgbutt[WG_LEFT].y1=wg.ytop;
1277 wgbutt[WG_LEFT].y2=wg.ybottom;
1278 wgbutt[WG_RIGHT].x1=wg.xright-2;
1279 wgbutt[WG_RIGHT].x2=wg.xright;
1280 wgbutt[WG_RIGHT].y1=wg.ytop;
1281 wgbutt[WG_RIGHT].y2=wg.ybottom;
1282 wgbutt[WG_TOP].x1=wg.xleft;
1283 wgbutt[WG_TOP].x2=wg.xright;
1284 wgbutt[WG_TOP].y1=wg.ytop;
1285 wgbutt[WG_TOP].y2=wg.ytop+2;
1286 wgbutt[WG_BORDER].x1=wg.xleft;
1287 wgbutt[WG_BORDER].x2=wg.xright;
1288 wgbutt[WG_BORDER].y1=wg.yborder-1;
1289 wgbutt[WG_BORDER].y2=wg.yborder+1;
1290 wgbutt[WG_BOTTOM].x1=wg.xleft;
1291 wgbutt[WG_BOTTOM].x2=wg.xright;
1292 wgbutt[WG_BOTTOM].y1=wg.ybottom-2;
1293 wgbutt[WG_BOTTOM].y2=wg.ybottom;
1294 // Draw the border lines
1295 dual_graph_borders((void*)&wg,7);
1296 // Free the waterfall buffer in case there is already one allocated
1297 // Then allocate the number of bytes we actually need for the current screen.
1298 wg_waterf=chk_free(wg_waterf);
1299 // ************************************
1300 wg_waterf_size=wg_xpixels*wg_waterf_lines;
1301 max_wg_waterf_times=2+(int)(0.5F*(float)wg_waterf_lines/(float)text_height);
1302 wg_waterf_ptr=0;
1303 wg_waterf=malloc((unsigned int)max_wg_waterf_times*sizeof(WATERF_TIMES)+
1304                  (unsigned int)wg_waterf_size*sizeof(short int)+
1305                  (unsigned int)screen_height*sizeof(char));
1306 if(wg_waterf == NULL)
1307   {
1308   lirerr(1036);
1309   return;
1310   }
1311 wg_background=(void*)(wg_waterf)+
1312                               (unsigned int)wg_waterf_size*sizeof(short int);
1313 wg_waterf_times=(WATERF_TIMES*)((void*)(wg_background)+
1314                                    (unsigned int)screen_height*sizeof(char));
1315 for(i=0;i<wg_waterf_size;i++)wg_waterf[i]=(short int)0x8000;
1316 for(i=0;i<max_wg_waterf_times; i++)wg_waterf_times[i].line=10000;
1317 // Write out the y scale for logarithmic spectrum graph.
1318 // We want a point with amplitude 1<<(fft1_n/2) to be placed at the
1319 // zero point of the dB scale.
1320 for(i=0; i<screen_height; i++)wg_background[i]=0;
1321 ypixels=wg.ybottom-wg.yborder-1;
1322 wg_db_per_pixel=(float)(20*log10(wg.yrange)/ypixels);
1323 db_scalestep=1.3*wg_db_per_pixel*text_height;
1324 adjust_scale(&db_scalestep);
1325 t1=(float)(20*log10(wg.yzero));
1326 i=(int)(t1/db_scalestep);
1327 scale_value=i*(1.00000*db_scalestep);
1328 scale_y=(float)(wg.ybottom+(t1-scale_value)/wg_db_per_pixel);
1329 scale_decimals=0;
1330 scale_rnd=.01F;
1331 if(db_scalestep < 1)
1332   {
1333   sprintf(s,"%f",db_scalestep);
1334   while(s[scale_decimals] != '.')scale_decimals++;
1335   scale_decimals++;
1336   while(s[scale_decimals] == '0' && s[scale_decimals] != 0)
1337     {
1338     scale_decimals++;
1339     scale_rnd/=10;
1340     }
1341   }
1342 while( scale_y-(float)(text_height/2-2) > wg.yborder+1.5*text_height)
1343   {
1344   i=0;
1345   if(scale_y+(float)(text_height+2) < wg.ybottom)
1346     {
1347     if(scale_value < 0)
1348       {
1349       t1=(float)(scale_value-scale_rnd);
1350       }
1351     else
1352       {
1353       t1=(float)(scale_value+scale_rnd);
1354       }
1355     sprintf(s,"%f",t1);
1356     while(s[i] != '.')i++;
1357     if(scale_decimals != 0)
1358       {
1359       i+=scale_decimals;
1360       }
1361     s[i]=0;
1362     lir_pixwrite(wg.xleft+text_width/2,(int)scale_y-text_height/2+2,s);
1363     }
1364   if(scale_y+2 < wg.ybottom)
1365     {
1366     k=(int)scale_y;
1367     wg_background[k]=WG_DBSCALE_COLOR;
1368     lir_hline(wg_first_xpixel+scale_decimals*text_width,
1369                                         k,wg_last_xpixel,WG_DBSCALE_COLOR);
1370     if(kill_all_flag) return;
1371     }
1372   scale_y-=(float)(db_scalestep/wg_db_per_pixel);
1373   scale_value+=db_scalestep;
1374   }
1375 // Init fft1_spectrum as the base line and place it on the screen.
1376 for(i=wg_first_xpixel; i<=wg_last_xpixel; i++)
1377   {
1378   fft1_spectrum[i]=(short int)(wg.ybottom-1);
1379   }
1380 lir_hline(wg_first_xpixel,wg.ybottom-1,wg_last_xpixel,15);
1381 new_fft1_averages(fft1_sumsq_pa, fft1_first_point, fft1_last_point);
1382 make_button(wg.xleft+text_width,wg.ybottom-text_height/2-2,
1383                                          wgbutt,WG_YSCALE_EXPAND,24);
1384 make_button(wg.xleft+3*text_width,wg.ybottom-text_height/2-2,
1385                                          wgbutt,WG_YSCALE_CONTRACT,25);
1386 i=(wg.ybottom+wg.yborder)/2;
1387 make_button(wg.xright-text_width,i-text_height/2-2,
1388                                          wgbutt,WG_YZERO_DECREASE,24);
1389 make_button(wg.xright-text_width,i+text_height/2+2,
1390                                          wgbutt,WG_YZERO_INCREASE,25);
1391 make_button(wg.xright-text_width,wg.ybottom-text_height/2-2,
1392                                wgbutt,WG_AVG1NUM,(char)(wg.fft_avg1num+48));
1393 if(wg_freq_adjustment_mode == 0)
1394   {
1395   make_button(wg.xleft+text_width,wg.ytop+text_height/2+3,
1396                                          wgbutt,WG_FQMIN_DECREASE,26);
1397   make_button(wg.xleft+3*text_width,wg.ytop+text_height/2+3,
1398                                          wgbutt,WG_FQMIN_INCREASE,27);
1399   make_button(wg.xright-3*text_width,wg.ytop+text_height/2+3,
1400                                          wgbutt,WG_FQMAX_DECREASE,26);
1401   make_button(wg.xright-text_width,wg.ytop+text_height/2+3,
1402                                          wgbutt,WG_FQMAX_INCREASE,27);
1403   wgbutt[WG_FREQ_ADJUSTMENT_MODE].x1=wgbutt[WG_FQMIN_INCREASE].x2+2;
1404   wgbutt[WG_FREQ_ADJUSTMENT_MODE].x2=wgbutt[WG_FQMAX_DECREASE].x1-2;
1405   wgbutt[WG_FREQ_ADJUSTMENT_MODE].y1=wgbutt[WG_FQMAX_DECREASE].y1;
1406   wgbutt[WG_FREQ_ADJUSTMENT_MODE].y2=wgbutt[WG_FQMAX_DECREASE].y2;
1407   wg_freq_x1=wgbutt[WG_FQMIN_INCREASE].x2;
1408   wg_freq_x2=wgbutt[WG_FQMAX_DECREASE].x1;
1409   }
1410 else
1411   {
1412   wgbutt[WG_LOWEST_FREQ].x1=wg.xleft+2;
1413   wgbutt[WG_LOWEST_FREQ].x2=wgbutt[WG_LOWEST_FREQ].x1+15*text_width;
1414   wgbutt[WG_LOWEST_FREQ].y1=wg.ytop+2;
1415   wgbutt[WG_LOWEST_FREQ].y2=wgbutt[WG_LOWEST_FREQ].y1+text_height+2;
1416   wgbutt[WG_HIGHEST_FREQ].x2=wg.xright-2;
1417   wgbutt[WG_HIGHEST_FREQ].x1=wgbutt[WG_HIGHEST_FREQ].x2-15*text_width;
1418   wgbutt[WG_HIGHEST_FREQ].y1=wgbutt[WG_LOWEST_FREQ].y1;
1419   wgbutt[WG_HIGHEST_FREQ].y2=wgbutt[WG_LOWEST_FREQ].y2;
1420   if(wgbutt[WG_LOWEST_FREQ].x2+17 >= wgbutt[WG_HIGHEST_FREQ].x1)
1421     {
1422     i=(wgbutt[WG_LOWEST_FREQ].x2+wgbutt[WG_HIGHEST_FREQ].x1-1)/2;
1423     wgbutt[WG_LOWEST_FREQ].x2=i+8;
1424     wgbutt[WG_HIGHEST_FREQ].x1=i-8;
1425     }
1426   wgbutt[WG_FREQ_ADJUSTMENT_MODE].x1=wgbutt[WG_LOWEST_FREQ].x2+2;
1427   wgbutt[WG_FREQ_ADJUSTMENT_MODE].x2=wgbutt[WG_HIGHEST_FREQ].x1-2;
1428   wgbutt[WG_FREQ_ADJUSTMENT_MODE].y1=wgbutt[WG_LOWEST_FREQ].y1;
1429   wgbutt[WG_FREQ_ADJUSTMENT_MODE].y2=wgbutt[WG_LOWEST_FREQ].y2;
1430   wg_freq_x1=-1;
1431   }
1432 if(genparm[AFC_ENABLE] == 2)
1433   {
1434   if(wg.spur_inhibit == 0)
1435     {
1436     button_color=14;
1437     }
1438   else
1439     {
1440     button_color=3;
1441     }
1442   settextcolor(button_color);
1443   make_button(wg.xright-text_width,wg.ytop+3*text_height+3,
1444                                          wgbutt,WG_SPUR_TOGGLE,'c');
1445   show_button(&wgbutt[WG_SPUR_TOGGLE],"c");
1446   button_color=7;
1447   settextcolor(7);
1448   }
1449 spur_search_first_point=wg_first_point;
1450 spur_search_last_point=wg_last_point;
1451 if(genparm[SECOND_FFT_ENABLE] != 0)
1452   {
1453   spur_search_first_point*=fft2_to_fft1_ratio;
1454   spur_search_last_point*=fft2_to_fft1_ratio;
1455   }
1456 autospur_point=spur_search_last_point;
1457 // ***********  fft1 averaging number button ******************
1458 wgbutt[WG_FFT1_AVGNUM].x1=2+wg.xleft;
1459 wgbutt[WG_FFT1_AVGNUM].x2=2+wg.xleft+(11*text_width)/2;
1460 wgbutt[WG_FFT1_AVGNUM].y1=2+wg.yborder;
1461 wgbutt[WG_FFT1_AVGNUM].y2=2+wg.yborder+text_height;
1462 wgbutt[WG_WATERF_AVGNUM].x1=2+wg.xleft;
1463 wgbutt[WG_WATERF_AVGNUM].x2=2+wg.xleft+(9*text_width)/2;
1464 wgbutt[WG_WATERF_AVGNUM].y1=wg.yborder-text_height-2;
1465 wgbutt[WG_WATERF_AVGNUM].y2=wg.yborder-2;
1466 wgbutt[WG_WATERF_GAIN].x1=wg.xright-(9*text_width)/2-2;
1467 wgbutt[WG_WATERF_GAIN].x2=wg.xright-2;
1468 wgbutt[WG_WATERF_GAIN].y1=wg.yborder-2*text_height-4;
1469 wgbutt[WG_WATERF_GAIN].y2=wg.yborder-text_height-4;
1470 wgbutt[WG_WATERF_ZERO].x1=wg.xright-(11*text_width)/2-2;
1471 wgbutt[WG_WATERF_ZERO].x2=wg.xright-2;
1472 wgbutt[WG_WATERF_ZERO].y1=wg.yborder-text_height-2;
1473 wgbutt[WG_WATERF_ZERO].y2=wg.yborder-2;
1474 make_wg_yfac();
1475 make_modepar_file(GRAPHTYPE_WG);
1476 wg_flag=1;
1477 wg_waterf_block=(wg_waterf_y2-wg_waterf_y1+1)*wg_xpixels;
1478 make_wg_waterf_cfac();
1479 // Check if there are selected frequencies that are still
1480 // within the permitted range.
1481 // Place their cursors on screen and remove other selected frequencies.
1482 if(rx_mode != MODE_TXTEST && rx_mode != MODE_RADAR)
1483   {
1484   for(i=0; i<genparm[MIX1_NO_OF_CHANNELS]; i++)
1485     {
1486     mix1_curx[i]=-1;
1487     if( mix1_selfreq[i] > mix1_lowest_fq  && mix1_selfreq[i]<mix1_highest_fq)
1488       {
1489       add_mix1_cursor(i);
1490       if(genparm[AFC_ENABLE] != 0)
1491         {
1492         for(j=0; j<max_fftxn; j++)
1493           {
1494           k=i*max_fftxn+j;
1495           if(mix1_fq_mid[k]<mix1_lowest_fq)mix1_fq_mid[k]=mix1_lowest_fq;
1496           if(mix1_fq_mid[k]>mix1_highest_fq)mix1_fq_mid[k]=mix1_highest_fq;
1497           }
1498         }
1499       }
1500     else
1501       {
1502       mix1_selfreq[i]=-1;
1503       new_mix1_curx[i]=-1;
1504       mix1_point[i]=-1;
1505       }
1506     }
1507   }
1508 if( (ui.network_flag&NET_RX_OUTPUT) != 0)
1509   {
1510   for(i=0; i<MAX_FREQLIST; i++)
1511     {
1512     netfreq_curx[i]=-1;
1513     }
1514   }
1515 wg_timestamp_counter=0;
1516 baseb_reset_counter++;
1517 if(rx_mode == MODE_TXTEST)txtest_init();
1518 //update_indicator();
1519 resume_thread(THREAD_SCREEN);
1520 sc[SC_WG_WATERF_INIT]++;
1521 sc[SC_WG_BUTTONS]++;
1522 sc[SC_WG_FQ_SCALE]++;
1523 }
1524 
1525 
wg_default(void)1526 void wg_default(void)
1527 {
1528 wg.check=WG_VERNR;
1529 wg.yrange=32768;
1530 wg.yzero=1;
1531 wg.waterfall_db_gain=.25;
1532 wg.waterfall_db_zero=20;
1533 wg.spek_avgnum=1+(int)(0.2/fft1_blocktime);
1534 if(wg.spek_avgnum > 800)wg.spek_avgnum=800;
1535 wg.fft_avg1num=wg.spek_avgnum/3;
1536 if(genparm[SECOND_FFT_ENABLE] == 0)
1537   {
1538   wg.waterfall_avgnum=2*wg.spek_avgnum;
1539   }
1540 else
1541   {
1542   wg.waterfall_avgnum=1+(int)(5/fft2_blocktime);
1543   }
1544 check_wg_fft_avgnum();
1545 }
1546 
1547 
wg_default_x(void)1548 void wg_default_x(void)
1549 {
1550 int i;
1551 float t1;
1552 // Make the default window for the wide graphs (spectrum and waterfall)
1553 wg.xleft=0;
1554 i=fft1_size+6*text_width-1;
1555 if(i > screen_width-1)i=screen_width-1;
1556 wg.xright=i;
1557 // Decide what range in fft1 points we want to place on the x-axis
1558 // Default is to show approximately half the spectrum.
1559 wg_first_xpixel=wg.xleft+4*text_width;
1560 wg_last_xpixel=wg.xright-2*text_width;
1561 wg_xpixels=wg_last_xpixel-wg_first_xpixel+1;
1562 t1=(0.5F*(float)fft1_size)/(float)wg_xpixels;
1563 if(t1 > 1)
1564   {
1565   wg.xpoints_per_pixel=(int)(t1+0.5F);
1566   wg.xpoints=wg.xpoints_per_pixel*wg_xpixels;
1567   wg.pixels_per_xpoint=0;
1568   }
1569 else
1570   {
1571   wg.pixels_per_xpoint=(int)(1.01F/t1);
1572   wg.xpoints=wg_xpixels/wg.pixels_per_xpoint;
1573   if(wg.pixels_per_xpoint == 1)
1574     {
1575     wg.xpoints_per_pixel=1;
1576     }
1577   else
1578     {
1579     wg.xpoints_per_pixel=0;
1580     }
1581   }
1582 wg.first_xpoint=(fft1_size-wg.xpoints)/3;
1583 if(wg.first_xpoint<0)lirerr(314);
1584 }
1585 
wg_default_y(void)1586 void wg_default_y(void)
1587 {
1588 wg.ytop=0;
1589 wg.yborder=(int)(0.2F*(float)screen_height);
1590 wg.ybottom=(int)(0.35F*(float)screen_height);
1591 }
1592 
1593 
init_wide_graph()1594 void init_wide_graph()
1595 {
1596 if (read_modepar_file(GRAPHTYPE_WG) == 0)
1597   {
1598   wg_default();
1599   }
1600 if(wg.check!=WG_VERNR)wg_default();
1601 if(wg.xpoints_per_pixel*wg.pixels_per_xpoint > 1)wg_default_x();
1602 if(wg.first_xpoint < 0)wg_default_x();
1603 if(wg.first_xpoint+wg.xpoints > fft1_size)wg_default_x();
1604 if(wg.xleft<0 || wg.xleft > wg.xright-32-6*text_width)wg_default_x();
1605 if(wg.xright>=screen_width)wg_default_x();
1606 if(wg.ytop < 0 || wg.ytop >wg.ybottom-50)wg_default_y();
1607 if(wg.ybottom>=screen_height)wg_default_y();
1608 if(wg.yborder < wg.ytop+text_height+YBO ||
1609                 wg.yborder > wg.ybottom-2*text_height)wg_default_y();
1610 wg.spur_inhibit &= 1;
1611 if(genparm[SECOND_FFT_ENABLE] != 0 && wg.pixels_per_xpoint>2)
1612                                    make_power_of_two(&wg.pixels_per_xpoint);
1613 check_wg_fft_avgnum();
1614 wide_graph_scro=no_of_scro;
1615 if(fft1_size < 32)
1616   {
1617   lir_status=LIR_PARERR;
1618   return;
1619   }
1620 wg_freq_adjustment_mode=0;
1621 make_wide_graph(FALSE);
1622 no_of_scro++;
1623 if(no_of_scro >= MAX_SCRO)lirerr(89);
1624 }
1625