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 "globdef.h"
25 #include "uidef.h"
26 #include "sigdef.h"
27 #include "screendef.h"
28 #include "fft1def.h"
29 #include "fft3def.h"
30 #include "options.h"
31 #include "rusage.h"
32 #include "thrdef.h"
33
34 void show_cw(char *s);
35 void check_cw(int num,int type);
36 void make_coherent_graph(int clear_old);
37 void manage_meter_graph(void);
38 int coherent_graph_scro;
39
40 extern int meter_graph_scro;
41
42 // float[2] baseb_out=data to send to loudspeaker
43 // float[2] baseb=complex amplitude of first level coherent data.
44 // float[2] baseb_raw=complex amplitude of baseband signal. Raw data, pol. adapted.
45 // float[2] baseb_raw_orthog=complex amplitude of pol. orthog signal. Raw data.
46 // float[2] baseb_carrier=phase of carrier. Complex data, cosines and sines.
47 // float[1] baseb_carrier_ampl=amplitude of carrier
48 // float[1] baseb_totpwr=total power of baseb_raw
49 // float[2] baseb_envelope=complex amplitude from fitted dots and dashes.
50 // float[1] baseb_upthreshold=forward peak detector for power
51 // float[1] baseb_threshold=combined forward and backward peak detector at -6dB
52 // float[2] baseb_fit=fitted dots and dashes.
53 // float[2] baseb_tmp=array for intermediate data in complex format
54 // float[1] baseb_agc_level=used only when AGC is enabled.
55 // short int[1] baseb_ramp=indicator for time of power above/below threshold.
56 // short_int[1] baseb_clock=CW code clock
57 // float[2] baseb_tmp=for debug during development
58
59 // baseb_pa baseb exists up to baseb_pa-1.
60 // baseb_pb The point up to which thresholds exist.
61 // baseb_pc The point up to which ramp is collected.
62 // baseb_pd A key up region close before baseb_pc
63 // baseb_pe The point up to which we have run first detect.
64 // baseb_pf
65 // baseb_px The oldest point that contains valid data.
66
67 #define COH_GRAPH_ACTIVE -1000
68 #define X_SIZE 5
69
evaluate_keying_spectrum(void)70 float evaluate_keying_spectrum(void)
71 {
72 int ia, ib, ic, kk, nn;
73 float t1, t2;
74 // keying_spectrum contains the modulation of the Morse-coded signal
75 // computed in mix2.c as the power spectrum of the real part of
76 // baseb_wb.
77 // One of the strong components should be the frequency of
78 // a string of Morse code dots, the "clock frequency" of the
79 // Morse code.
80 // The user has to set the baseband filter to allow this frequency
81 // within the baseband filter but the filter must not be set
82 // more than 2.5 times wider than optimum because we do not search
83 // for the "Morse clock" lower than this.
84 // keying_spectrum is computed over twice the bandwidth compared to
85 // the bandwidth of the user selected filter.
86 // The full baseband bandwidth, bw, corresponds to half the
87 // keying_spectrum width. (keying_spectrum_size/2)
88 // Start at bw/3 and step upwards until a minimum is reached.
89 // Look for signal power in pairs of points.
90 ia=3+keying_spectrum_size/6;
91 t1=keying_spectrum[ia]+keying_spectrum[ia-1];
92 t2=keying_spectrum[ia]+keying_spectrum[ia+1];
93 while(t2<t1 && ia<keying_spectrum_size/2)
94 {
95 t1=t2;
96 ia++;
97 t2=keying_spectrum[ia]+keying_spectrum[ia+1];
98 }
99 // Now we should have stepped away from the peak associated
100 // with the "Morse clock" divided by three.
101 // Look for the strongest peak above ia.
102 ib=ia;
103 t1=keying_spectrum[ib];
104 kk=ib;
105 while(ib<keying_spectrum_size/2)
106 {
107 if(t1<keying_spectrum[ib])
108 {
109 t1=keying_spectrum[ib];
110 kk=ib;
111 }
112 ib++;
113 }
114 // kk may be the Morse code clock, but it could also be
115 // half the frequency. Search 1.5 to 2.5 times kk for another
116 // maximum. If it has at least 50% of the power, attribute the
117 // higher peak to the Morse clock.
118 ib=1.5*kk;
119 ic=2.5*kk+1;
120 if(ic > keying_spectrum_size/2)ic=keying_spectrum_size/2;
121 nn=0;
122 t2=0;
123 while(ib < ic)
124 {
125 if(t2<keying_spectrum[ib])
126 {
127 t2=keying_spectrum[ib];
128 nn=ib;
129 }
130 ib++;
131 }
132 if(2*t2 > t1)kk=nn;
133 // Get the peak posuition with some decimals. Not very accurate,
134 // but the first decimal should be close to correct.
135 if(kk < keying_spectrum_size-1)
136 {
137 parabolic_fit(&t2, &t1, sqrt(keying_spectrum[kk-1]),
138 sqrt(keying_spectrum[kk]),sqrt(keying_spectrum[kk+1]));
139 t1+=kk;
140 }
141 else
142 {
143 t1=kk;
144 t2=sqrt(keying_spectrum[kk]);
145 }
146 return t1;
147 }
148
collect_ramp(void)149 void collect_ramp(void)
150 {
151 int ia, ib;
152 // Make a first decision key up/key down based on signal power.
153 // This is the conventional approach, a matched filter (the operator
154 // has to select the optimum bandwidth) followed by a squarelaw detector.
155 // The threshold is conventionally kept at a fixed level but here it is
156 // very close to the noise when no signal is present. while it is at
157 // half the peak amplitude for strong signals.
158 // Store the result in baseb_ramp as ramps.
159 // Positive values indicate key down while negative values
160 // indicate key up (or signal too weak)
161 ib=(baseb_pc+baseband_mask)&baseband_mask;
162 ia=baseb_pc;
163 while( ia != baseb_pb )
164 {
165 if(baseb_totpwr[ia] > baseb_threshold[ia])
166 {
167 if(baseb_ramp[ib]>0)
168 {
169 baseb_ramp[ia]=baseb_ramp[ib]+1;
170 }
171 else
172 {
173 baseb_ramp[ia]=1;
174 }
175 }
176 else
177 {
178 if(baseb_ramp[ib]<0)
179 {
180 baseb_ramp[ia]=baseb_ramp[ib]-1;
181 }
182 else
183 {
184 baseb_ramp[ia]=-1;
185 }
186 }
187 ib=ia;
188 ia=(ia+1)&baseband_mask;
189 }
190 baseb_pc=ib;
191 // Step baseb_pc backwards until a long key up region is found.
192 ib=2.5*cwbit_pts;
193 while(abs(baseb_ramp[baseb_pc]) < ib || baseb_ramp[baseb_pc] > 0)
194 {
195 baseb_pc=(baseb_pc-abs(baseb_ramp[baseb_pc])+baseband_size)&baseband_mask;
196 if( ((baseb_pc-baseb_pe+baseband_size)&baseband_mask)>baseband_neg)
197 {
198 baseb_pc=baseb_pe;
199 }
200 }
201 // Now we know that baseb_pc points to the start of a long negative ramp.
202 }
203
204
make_ideal_waveform(void)205 void make_ideal_waveform(void)
206 {
207 unsigned int i, j, k, m, ia;
208 float t1;
209 // Set the size we use for averaging the waveform around dashes.
210 // Make it an even number.
211 cw_avg_points=15*cwbit_pts+1;
212 cw_avg_points&=0xfffffffe;
213 if(cw_avg_points >= (fftn_tmp_bytes/(2*sizeof(float))))
214 {
215 lirerr(853021);
216 return;
217 }
218 // Assuming the modulation spectrum has been correctly evaluated
219 // the length of a Morse code bit should be about cwbit_pts points.
220 // Construct a dash of the appropriate lengths, make it symmetric
221 // around mix2.size/2 and run it through the baseband filter.
222 // Store the result as the first guess for our CW waveforms.
223 for(i=0; i<2*mix2.size; i++) mix2_tmp[i]=0;
224 j=mix2.size;
225 t1=cwbit_pts*3.0;
226 k=t1;
227 m=k/2;
228 k=2*m;
229 mix2_tmp[j]=1;
230 for(i=0; i<m; i++)
231 {
232 mix2_tmp[j+2*i]=1;
233 mix2_tmp[j-2-2*i]=1;
234 }
235 t1=0.5*(t1-k);
236 // t1 is the amount by which the dash is longer than the
237 // amount we set to 1 (on both sides).
238 // With full level for a fractional (=t1) sample period,
239 // the power within the interval is t1.
240 // The amplitude we should set is therefore sqrt(t1)
241 mix2_tmp[j+2*m]=sqrt(t1);
242 mix2_tmp[j-2-2*m]=sqrt(t1);
243 fftforward(mix2.size, mix2.n, mix2_tmp,
244 mix2.table, mix2.permute, yieldflag_ndsp_mix2);
245 i=1;
246 j=fft3_size/2;
247 while(bg_filterfunc[j] != 0)
248 {
249 mix2_tmp[2*i ]*=bg_filterfunc[j];
250 mix2_tmp[2*i+1]*=bg_filterfunc[j];
251 mix2_tmp[2*(mix2.size-i) ]*=bg_filterfunc[j];
252 mix2_tmp[2*(mix2.size-i)+1]*=bg_filterfunc[j];
253 i++;
254 j++;
255 }
256 while(i <= mix2.size/2)
257 {
258 mix2_tmp[2*i ]=0;
259 mix2_tmp[2*i+1]=0;
260 mix2_tmp[2*(mix2.size-i) ]=0;
261 mix2_tmp[2*(mix2.size-i)+1]=0;
262 i++;
263 }
264 fftback(mix2.size, mix2.n, mix2_tmp,
265 mix2.table, mix2.permute, yieldflag_ndsp_mix2);
266 ia=mix2.size-cw_avg_points;
267 for(j=0; j<cw_avg_points; j++)
268 {
269 fftn_tmp[2*j ]=mix2_tmp[ia];
270 fftn_tmp[2*j+1]=0;
271 ia+=2;
272 }
273 store_symmetry_adapted_dash(TRUE);
274 }
275
coherent_cw_detect(void)276 void coherent_cw_detect(void)
277 {
278 int i, j;
279 float t1, t2, t3;
280 switch (cw_detect_flag)
281 {
282 case CWDETECT_CLEARED:
283 if(keying_spectrum_cnt < keying_spectrum_max)return;
284 keying_spectrum_cnt=0;
285 // Initiate a new search for Morse code.
286 // We will glook for the "Morse code clock" in keying_spectrum.
287 keying_spectrum_pos[0]=evaluate_keying_spectrum();
288 keying_spectrum_ampl[0]=keying_spectrum[0];
289 cwbit_pts=0.5*mix2.size/keying_spectrum_pos[0];
290 collect_ramp();
291 return;//öööööööööö
292 make_ideal_waveform();
293 keying_spectrum_ptr=1;
294 detect_cw_speed();
295 if(cw_detect_flag == CWDETECT_ERROR)
296 {
297 cw_detect_flag=CWDETECT_SEARCH_SPEED;
298 }
299 break;
300
301 case CWDETECT_SEARCH_SPEED:
302 if(keying_spectrum_cnt < keying_spectrum_max)return;
303 keying_spectrum_cnt=0;
304 // Collect more data from keying_spectrum.
305 keying_spectrum_pos[keying_spectrum_ptr]=evaluate_keying_spectrum();
306 keying_spectrum_ampl[keying_spectrum_ptr]=keying_spectrum[0];
307 cwbit_pts=0.5*mix2.size/keying_spectrum_pos[keying_spectrum_ptr];
308 collect_ramp();
309 make_ideal_waveform();
310 detect_cw_speed();
311 if(cw_detect_flag == CWDETECT_ERROR)
312 {
313 cw_detect_flag=CWDETECT_SEARCH_SPEED;
314 keying_spectrum_ptr++;
315 // When KEYING_SPECTRUM_MAX spectra are evaluated, skip initial
316 // ones until the carrier power of the first one is above
317 // one third of the average carrier power.
318 if(keying_spectrum_ptr >= KEYING_SPECTRUM_MAX)
319 {
320 t1=keying_spectrum_ampl[0];
321 for(i=1; i<KEYING_SPECTRUM_MAX; i++)
322 {
323 t1+=keying_spectrum_ampl[i];
324 }
325 t1/=3*KEYING_SPECTRUM_MAX;
326 i=0;
327 while(keying_spectrum_ampl[i] < t1)i++;
328 if(i != 0)
329 {
330 j=0;
331 while(i<KEYING_SPECTRUM_MAX)
332 {
333 keying_spectrum_ampl[j]=keying_spectrum_ampl[i];
334 keying_spectrum_pos[j]=keying_spectrum_pos[i];
335 i++;
336 j++;
337 }
338 keying_spectrum_ptr=j;
339 }
340 else
341 {
342 // We have KEYING_SPECTRUM_MAX peaks in keying_spectrum.
343 // Check if they are close together.
344 t1=0;
345 t2=0;
346 for(i=0; i<KEYING_SPECTRUM_MAX; i++)
347 {
348 t1+=keying_spectrum_ampl[i];
349 t2+=keying_spectrum_ampl[i]*keying_spectrum_pos[i];
350 }
351 t3=t2/t1;
352 t1=0;
353 t2=0;
354 for(i=0; i<KEYING_SPECTRUM_MAX; i++)
355 {
356 if(fabs(t3-keying_spectrum_pos[i]) < 0.1*keying_spectrum_size)
357 {
358 t1+=keying_spectrum_ampl[i];
359 t2+=keying_spectrum_ampl[i]*keying_spectrum_pos[i];
360 }
361 }
362 if(t1 == 0)goto fail;
363 t2/=t1;
364 if(fabs(t3-t2) > 0.1*keying_spectrum_size)goto fail;
365 // The most probable frequency for the fundamental of the
366 // "Morse code clock" seems to be t2.
367 // Convert from frequency to time (samples)
368 cwbit_pts=0.5*mix2.size/t2;
369 make_ideal_waveform();
370 detect_cw_speed();
371 if(cw_detect_flag == CWDETECT_ERROR)goto fail;
372 }
373 }
374 }
375 break;
376
377 case CWDETECT_WAVEFORM_ESTABLISHED:
378 collect_ramp();
379 first_find_parts();
380 break;
381
382 case CWDETECT_SOME_PARTS_FITTED:
383 collect_ramp();
384 second_find_parts();
385 break;
386
387 case CWDETECT_LIMITS_FOUND:
388 collect_ramp();
389 init_cw_decode_region();
390 break;
391
392 case CWDETECT_REGION_INITIATED:
393 collect_ramp();
394 cw_decode_region();
395 break;
396
397 case CWDETECT_REGION_WAVEFORM_OK:
398 collect_ramp();
399 init_cw_decode();
400 break;
401
402 case CWDETECT_SOME_ASCII_FITTED:
403 collect_ramp();
404 cw_decode();
405 break;
406
407 case CWDETECT_DEBUG_STOP:
408 lir_fillbox(screen_width/2,0,50,screen_height-1,3);
409 DEB"\nno more!!");
410 cw_detect_flag=CWDETECT_DEBUG_IDLE;
411 break;
412
413 case CWDETECT_DEBUG_IDLE:
414 break;
415
416 case CWDETECT_ERROR:
417 // Detect failed. Remove old data so buffers will not overflow.
418 fail:;
419 cw_detect_flag=CWDETECT_CLEARED;
420 // Do not store more than 2 minutes of bad data
421 // and make sure we leave some space in the buffer.
422 i=(baseb_pa-baseb_px+baseband_size)&baseband_mask;
423 j=i;
424 if(i>baseband_neg)i=baseband_neg;
425 if(i>120*baseband_sampling_speed)i=120*baseband_sampling_speed;
426 if(i != j)
427 {
428 baseb_px=(baseb_pa-i+baseband_size)&baseband_mask;
429 }
430 no_of_cwdat=0;
431 baseb_pf=baseb_px;
432 baseb_pe=baseb_px;
433 baseb_pd=baseb_px;
434 baseb_pc=baseb_px;
435 XZ("\n\nERROR error fail!! ");
436 break;
437 }
438 }
439
check_cg_borders(void)440 void check_cg_borders(void)
441 {
442 int xsiz, ysiz;
443 xsiz=3*cg_size+2;
444 ysiz=xsiz+5*text_height+4;
445 current_graph_minh=ysiz;
446 current_graph_minw=xsiz;
447 check_graph_placement((void*)(&cg));
448 set_graph_minwidth((void*)(&cg));
449 }
450
451
help_on_coherent_graph(void)452 void help_on_coherent_graph(void)
453 {
454 int msg_no;
455 int event_no;
456 msg_no=68;
457 for(event_no=0; event_no<MAX_CGBUTT; event_no++)
458 {
459 if( cgbutt[event_no].x1 <= mouse_x &&
460 cgbutt[event_no].x2 >= mouse_x &&
461 cgbutt[event_no].y1 <= mouse_y &&
462 cgbutt[event_no].y2 >= mouse_y)
463 {
464 switch (event_no)
465 {
466 case CG_TOP:
467 case CG_BOTTOM:
468 case CG_LEFT:
469 case CG_RIGHT:
470 msg_no=101;
471 break;
472
473 case CG_OSCILLOSCOPE:
474 msg_no=69;
475 break;
476
477 case CG_METER_GRAPH:
478 msg_no=99;
479 break;
480 }
481 }
482 }
483 help_message(msg_no);
484 }
485
486
487
488
mouse_continue_coh_graph(void)489 void mouse_continue_coh_graph(void)
490 {
491 int i, j;
492 switch (mouse_active_flag-1)
493 {
494 case CG_TOP:
495 if(cg.ytop!=mouse_y)goto cgm;
496 break;
497
498 case CG_BOTTOM:
499 if(cg.ybottom!=mouse_y)goto cgm;
500 break;
501
502 case CG_LEFT:
503 if(cg.xleft!=mouse_x)goto cgm;
504 break;
505
506 case CG_RIGHT:
507 if(cg.xright==mouse_x)break;
508 cgm:;
509 pause_screen_and_hide_mouse();
510 graph_borders((void*)&cg,0);
511 if(cg_oldx==COH_GRAPH_ACTIVE)
512 {
513 cg_oldx=mouse_x;
514 cg_oldy=mouse_y;
515 }
516 else
517 {
518 i=mouse_x-cg_oldx;
519 j=mouse_y-cg_oldy;
520 cg_oldx=mouse_x;
521 cg_oldy=mouse_y;
522 cg.ytop+=j;
523 cg.ybottom+=j;
524 cg.xleft+=i;
525 cg.xright+=i;
526 check_cg_borders();
527 }
528 graph_borders((void*)&cg,15);
529 resume_thread(THREAD_SCREEN);
530 break;
531
532 default:
533 goto await_release;
534 }
535 if(leftpressed == BUTTON_RELEASED)goto finish;
536 return;
537 await_release:;
538 if(leftpressed != BUTTON_RELEASED)return;
539 switch (mouse_active_flag-1)
540 {
541 case CG_OSCILLOSCOPE:
542 if(ui.operator_skil == OPERATOR_SKIL_EXPERT)
543 {
544 pause_thread(THREAD_SCREEN);
545 hide_mouse(0,screen_width>>1,0,screen_height);
546 clear_cg_traces();
547 resume_thread(THREAD_SCREEN);
548 cg.oscill_on^=1;
549 cg.oscill_on&=1;
550 cg_max_trlevel=0;
551 }
552 break;
553
554 case CG_METER_GRAPH:
555 pause_thread(THREAD_SCREEN);
556 hide_mouse(0,screen_width>>1,0,screen_height);
557 cg.meter_graph_on^=1;
558 manage_meter_graph();
559 resume_thread(THREAD_SCREEN);
560 break;
561
562 default:
563 lirerr(872);
564 break;
565 }
566 finish:;
567 leftpressed=BUTTON_IDLE;
568 mouse_active_flag=0;
569 make_coherent_graph(TRUE);
570 cg_oldx=COH_GRAPH_ACTIVE;
571 }
572
573
mouse_on_coh_graph(void)574 void mouse_on_coh_graph(void)
575 {
576 int event_no;
577 // First find out is we are on a button or border line.
578 for(event_no=0; event_no<MAX_CGBUTT; event_no++)
579 {
580 if( cgbutt[event_no].x1 <= mouse_x &&
581 cgbutt[event_no].x2 >= mouse_x &&
582 cgbutt[event_no].y1 <= mouse_y &&
583 cgbutt[event_no].y2 >= mouse_y)
584 {
585 mouse_active_flag=1+event_no;
586 current_mouse_activity=mouse_continue_coh_graph;
587 return;
588 }
589 }
590 // Not button or border.
591 // Do nothing.
592 current_mouse_activity=mouse_nothing;
593 mouse_active_flag=1;
594 }
595
make_coherent_graph(int clear_old)596 void make_coherent_graph(int clear_old)
597 {
598 int len;
599 pause_thread(THREAD_SCREEN);
600 hide_mouse(0,screen_width>>1,0,screen_height);
601 clear_cg_traces();
602 if(clear_old)
603 {
604 hide_mouse(cg_old_x1,cg_old_x2,cg_old_y1,cg_old_y2);
605 lir_fillbox(cg_old_x1,cg_old_y1,cg_old_x2-cg_old_x1+1,
606 cg_old_y2-cg_old_y1+1,0);
607 }
608 check_cg_borders();
609 clear_button(cgbutt, MAX_CGBUTT);
610 hide_mouse(cg.xleft,cg.xright,cg.ytop,cg.ybottom);
611 scro[coherent_graph_scro].no=COH_GRAPH;
612 scro[coherent_graph_scro].x1=cg.xleft;
613 scro[coherent_graph_scro].x2=cg.xright;
614 scro[coherent_graph_scro].y1=cg.ytop;
615 scro[coherent_graph_scro].y2=cg.ybottom;
616 cgbutt[CG_LEFT].x1=cg.xleft;
617 cgbutt[CG_LEFT].x2=cg.xleft+2;
618 cgbutt[CG_LEFT].y1=cg.ytop;
619 cgbutt[CG_LEFT].y2=cg.ybottom;
620 cgbutt[CG_RIGHT].x1=cg.xright-2;
621 cgbutt[CG_RIGHT].x2=cg.xright;
622 cgbutt[CG_RIGHT].y1=cg.ytop;
623 cgbutt[CG_RIGHT].y2=cg.ybottom;
624 cgbutt[CG_TOP].x1=cg.xleft;
625 cgbutt[CG_TOP].x2=cg.xright;
626 cgbutt[CG_TOP].y1=cg.ytop;
627 cgbutt[CG_TOP].y2=cg.ytop+2;
628 cgbutt[CG_BOTTOM].x1=cg.xleft;
629 cgbutt[CG_BOTTOM].x2=cg.xright;
630 cgbutt[CG_BOTTOM].y1=cg.ybottom-2;
631 cgbutt[CG_BOTTOM].y2=cg.ybottom;
632 // Draw the border lines
633 graph_borders((void*)&cg,7);
634 if(ui.operator_skil == OPERATOR_SKIL_EXPERT)
635 {
636 make_button(cg.xleft+text_width-1,cg.ybottom-text_height/2-1,
637 cgbutt,CG_OSCILLOSCOPE,'o');
638 }
639 make_button(cg.xleft+text_width-1,cg.ybottom-5*(text_height/2-1),
640 cgbutt,CG_METER_GRAPH,'s');
641 cg_oldx=COH_GRAPH_ACTIVE;
642 settextcolor(7);
643 cg_x0=(cg.xleft+cg.xright)>>1;
644 len=((cg.xright-cg.xleft)>>1);
645 cg_y0=cg.ytop+len+1;
646 cg_y1=cg_y0+len;
647 lir_hline(cg.xleft+1,cg_y1,cg.xright-1,7);
648 if(kill_all_flag) return;
649 if(clear_old)
650 {
651 clear_coherent();
652 }
653 cg_old_y1=cg.ytop;
654 cg_old_y2=cg.ybottom;
655 cg_old_x1=cg.xleft;
656 cg_old_x2=cg.xright;
657 manage_meter_graph();
658 resume_thread(THREAD_SCREEN);
659 make_modepar_file(GRAPHTYPE_CG);
660 update_meter_time=current_time();
661 }
662
init_coherent_graph(void)663 void init_coherent_graph(void)
664 {
665 int xsiz, ysiz;
666 xsiz=3*cg_size+2;
667 ysiz=xsiz+5*text_height+4;
668 if (read_modepar_file(GRAPHTYPE_CG) == 0)
669 {
670 reinit:;
671 cg.xright=screen_width-1;
672 cg.xleft=cg.xright-xsiz;
673 cg.ybottom=bg.ybottom;
674 cg.ytop=cg.ybottom-ysiz;
675 cg.meter_graph_on=1;
676 cg.oscill_on=0;
677 }
678 if(cg.ybottom-cg.ytop != ysiz ||
679 cg.xright-cg.xleft != xsiz)goto reinit;
680 cg_flag=1;
681 mg_flag=0;
682 cg_osc_shift_flag=0;
683 cg_max_trlevel=0;
684 coherent_graph_scro=no_of_scro;
685 // We have to reserve space for the meter graph here.
686 // The meter graph can be enabled or disabled from the coherent
687 // window at run time.
688 meter_graph_scro=no_of_scro+1;
689 cg.oscill_on&=1;
690 if(no_of_scro+2 >= MAX_SCRO)lirerr(89);
691 if(ui.operator_skil != OPERATOR_SKIL_EXPERT)cg.oscill_on=0;
692 make_coherent_graph(FALSE);
693 no_of_scro+=2;
694 }
695
696