1 // ----------------------------------------------------------------------------
2 // cw.cxx  --  morse code modem
3 //
4 // Copyright (C) 2006-2010
5 //		Dave Freese, W1HKJ
6 //		   (C) Mauri Niininen, AG1LE
7 //
8 // This file is part of fldigi.  Adapted from code contained in gmfsk source code
9 // distribution.
10 //  gmfsk Copyright (C) 2001, 2002, 2003
11 //  Tomi Manninen (oh2bns@sral.fi)
12 //  Copyright (C) 2004
13 //  Lawrence Glaister (ve7it@shaw.ca)
14 //
15 // Fldigi is free software: you can redistribute it and/or modify
16 // it under the terms of the GNU General Public License as published by
17 // the Free Software Foundation, either version 3 of the License, or
18 // (at your option) any later version.
19 //
20 // Fldigi is distributed in the hope that it will be useful,
21 // but WITHOUT ANY WARRANTY; without even the implied warranty of
22 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23 // GNU General Public License for more details.
24 //
25 // You should have received a copy of the GNU General Public License
26 // along with fldigi.  If not, see <http://www.gnu.org/licenses/>.
27 // ----------------------------------------------------------------------------
28 
29 
30 #include <config.h>
31 
32 #include <cstring>
33 #include <string>
34 #include <stdio.h>
35 #include <iostream>
36 #include <fstream>
37 #include <cstdlib>
38 
39 #include "digiscope.h"
40 #include "waterfall.h"
41 #include "fl_digi.h"
42 #include "fftfilt.h"
43 #include "serial.h"
44 #include "ptt.h"
45 #include "main.h"
46 
47 #include "cw.h"
48 #include "misc.h"
49 #include "configuration.h"
50 #include "confdialog.h"
51 #include "status.h"
52 #include "debug.h"
53 #include "FTextRXTX.h"
54 #include "modem.h"
55 
56 #include "qrunner.h"
57 
58 #include "winkeyer.h"
59 #include "nanoIO.h"
60 #include "KYkeying.h"
61 #include "ICOMkeying.h"
62 #include "YAESUkeying.h"
63 
64 #include "audio_alert.h"
65 
66 using namespace std;
67 
68 void start_cwio_thread();
69 void stop_cwio_thread();
70 
71 #define XMT_FILT_LEN 256
72 #define QSK_DELAY_LEN 4*XMT_FILT_LEN
73 #define CW_FFT_SIZE 2048 // must be a factor of 2
74 
75 static double nano_d2d = 0;
76 static int nano_wpm = 0;
77 
78 const cw::SOM_TABLE cw::som_table[] = {
79 	/* Prosigns */
80 	{"-...-",	{1.0,  0.33,  0.33,  0.33, 1.0,   0, 0} },
81 	{".-.-",	{ 0.33, 1.0,  0.33, 1.0,   0,   0, 0} },
82 	{".-...",	{ 0.33, 1.0,  0.33,  0.33,  0.33,   0, 0} },
83 	{".-.-.",	{ 0.33, 1.0,  0.33, 1.0,  0.33,   0, 0} },
84 	{"...-.-",	{ 0.33,  0.33,  0.33, 1.0,  0.33, 1.0, 0} },
85 	{"-.--.",	{1.0,  0.33, 1.0, 1.0,  0.33,   0, 0} },
86 	{"..-.-",	{ 0.33,  0.33, 1.0,  0.33, 1.0,   0, 0} },
87 	{"....--",	{ 0.33,  0.33,  0.33,  0.33, 1.0, 1.0, 0} },
88 	{"...-.",	{ 0.33,  0.33,  0.33, 1.0,  0.33,   0, 0} },
89 	/* ASCII 7bit letters */
90 	{".-",		{ 0.33, 1.0,   0,   0,   0,   0, 0}	},
91 	{"-...",	{1.0,  0.33,  0.33,  0.33,   0,   0, 0}	},
92 	{"-.-.",	{1.0,  0.33, 1.0,  0.33,   0,   0, 0}	},
93 	{"-..",		{1.0,  0.33,  0.33,   0,   0,   0, 0} 	},
94 	{".",		{ 0.33,   0,   0,   0,   0,   0, 0}	},
95 	{"..-.",	{ 0.33,  0.33, 1.0,  0.33,   0,   0, 0}	},
96 	{"--.",		{1.0, 1.0,  0.33,   0,   0,   0, 0}	},
97 	{"....",	{ 0.33,  0.33,  0.33,  0.33,   0,   0, 0}	},
98 	{"..",		{ 0.33,  0.33,   0,   0,   0,   0, 0}	},
99 	{".---",	{ 0.33, 1.0, 1.0, 1.0,   0,   0, 0}	},
100 	{"-.-",		{1.0,  0.33, 1.0,   0,   0,   0, 0}	},
101 	{".-..",	{ 0.33, 1.0,  0.33,  0.33,   0,   0, 0}	},
102 	{"--",		{1.0, 1.0,   0,   0,   0,   0, 0}	},
103 	{"-.",		{1.0,  0.33,   0,   0,   0,   0, 0}	},
104 	{"---",		{1.0, 1.0, 1.0,   0,   0,   0, 0}	},
105 	{".--.",	{ 0.33, 1.0, 1.0,  0.33,   0,   0, 0}	},
106 	{"--.-",	{1.0, 1.0,  0.33, 1.0,   0,   0, 0}	},
107 	{".-.",		{ 0.33, 1.0,  0.33,   0,   0,   0, 0}	},
108 	{"...",		{ 0.33,  0.33,  0.33,   0,   0,   0, 0}	},
109 	{"-",		{1.0,   0,   0,   0,   0,   0, 0}	},
110 	{"..-",		{ 0.33,  0.33, 1.0,   0,   0,   0, 0}	},
111 	{"...-",	{ 0.33,  0.33,  0.33, 1.0,   0,   0, 0}	},
112 	{".--",		{ 0.33, 1.0, 1.0,   0,   0,   0, 0}	},
113 	{"-..-",	{1.0,  0.33,  0.33, 1.0,   0,   0, 0}	},
114 	{"-.--",	{1.0,  0.33, 1.0, 1.0,   0,   0, 0}	},
115 	{"--..",	{1.0, 1.0,  0.33,  0.33,   0,   0, 0}	},
116 	/* Numerals */
117 	{"-----",	{1.0, 1.0, 1.0, 1.0, 1.0,   0, 0}	},
118 	{".----",	{ 0.33, 1.0, 1.0, 1.0, 1.0,   0, 0}	},
119 	{"..---",	{ 0.33,  0.33, 1.0, 1.0, 1.0,   0, 0}	},
120 	{"...--",	{ 0.33,  0.33,  0.33, 1.0, 1.0,   0, 0}	},
121 	{"....-",	{ 0.33,  0.33,  0.33,  0.33, 1.0,   0, 0}	},
122 	{".....",	{ 0.33,  0.33,  0.33,  0.33,  0.33,   0, 0}	},
123 	{"-....",	{1.0,  0.33,  0.33,  0.33,  0.33,   0, 0}	},
124 	{"--...",	{1.0, 1.0,  0.33,  0.33,  0.33,   0, 0}	},
125 	{"---..",	{1.0, 1.0, 1.0,  0.33,  0.33,   0, 0}	},
126 	{"----.",	{1.0, 1.0, 1.0, 1.0,  0.33,   0, 0}	},
127 	/* Punctuation */
128 	{".-..-.",	{ 0.33, 1.0,  0.33,  0.33, 1.0,  0.33, 0}	},
129 	{".----.",	{ 0.33, 1.0, 1.0, 1.0, 1.0,  0.33, 0}	},
130 	{"...-..-",	{ 0.33,  0.33,  0.33, 1.0,  0.33,  0.33, 1.0}	},
131 	{"-.---.",	{1.0,  0.33, 1.0, 1.0,  0.33,   0, 0}	},
132 	{"-.--.-",	{1.0,  0.33, 1.0, 1.0,  0.33, 1.0, 0}	},
133 	{"--..--",	{1.0, 1.0,  0.33,  0.33, 1.0, 1.0, 0}	},
134 	{"-....-",	{1.0,  0.33,  0.33,  0.33,  0.33, 1.0, 0}	},
135 	{".-.-.-",	{ 0.33, 1.0,  0.33, 1.0,  0.33, 1.0, 0}	},
136 	{"-..-.",	{1.0,  0.33,  0.33, 1.0,  0.33,   0, 0}	},
137 	{"---...",	{1.0, 1.0, 1.0,  0.33,  0.33,  0.33, 0}	},
138 	{"-.-.-.",	{1.0,  0.33, 1.0,  0.33, 1.0,  0.33, 0}	},
139 	{"..--..",	{ 0.33,  0.33, 1.0, 1.0,  0.33,  0.33, 0}	},
140 	{"..--.-",	{ 0.33,  0.33, 1.0, 1.0,  0.33, 1.0, 0}	},
141 	{".--.-.",	{ 0.33, 1.0, 1.0,  0.33, 1.0,  0.33, 0}	},
142 	{"-.-.--",	{1.0,  0.33, 1.0,  0.33, 1.0, 1.0, 0}	},
143 
144 	{".-.-",	{0.33, 1.0, 0.33, 1.0, 0, 0 , 0}  },	// A umlaut, A aelig
145 	{".--.-",	{0.33, 1.0, 1.0, 0.33, 1.0, 0, 0 }  },	// A ring
146 	{"-.-..",	{1.0, 0.33, 1.0, 0.33, 0.33, 0, 0} },	// C cedilla
147 	{".-..-",	{0.33, 1.0, 0.33, 0.33, 1.0, 0, 0} },	// E grave
148 	{"..-..",	{0.33, 0.33, 1.0, 0.33, 0.33, 0, 0} },	// E acute
149 	{"---.",	{1.0, 1.0, 1.0, 0.33, 0, 0, 0} },		// O acute, O umlat, O slash
150 	{"--.--",	{1.0, 1.0, 0.33, 1.0, 1.0, 0, 0} },		// N tilde
151 	{"..--",	{0.33, 0.33, 1.0, 1.0, 0, 0, 0} },		// U umlaut, U circ
152 
153 	{"", {0.0}}
154 };
155 
normalize(float * v,int n,int twodots)156 int cw::normalize(float *v, int n, int twodots)
157 {
158 	if( n == 0 ) return 0 ;
159 
160 	float max = v[0];
161 	float min = v[0];
162 	int j;
163 
164 	/* find max and min values */
165 	for (j=1; j<n; j++) {
166 		float vj = v[j];
167 		if (vj > max)	max = vj;
168 		else if (vj < min)	min = vj;
169 	}
170 	/* all values 0 - no need to normalize or decode */
171 	if (max == 0.0) return 0;
172 
173 	/* scale values between  [0,1] -- if Max longer than 2 dots it was "dah" and should be 1.0, otherwise it was "dit" and should be 0.33 */
174 	float ratio = (max > twodots) ? 1.0 : 0.33 ;
175 	ratio /= max ;
176 	for (j=0; j<n; j++) v[j] *= ratio;
177 	return (1);
178 }
179 
180 
find_winner(float * inbuf,int twodots)181 std::string cw::find_winner (float *inbuf, int twodots)
182 {
183 	float diffsf = 999999999999.0;
184 
185 	if ( normalize (inbuf, WGT_SIZE, twodots) == 0) return " ";
186 
187 	int winner = -1;
188 	for ( int n = 0; som_table[n].rpr.length(); n++) {
189 		 /* Compute the distance between codebook and input entry */
190 		float difference = 0.0;
191 	   	for (int i = 0; i < WGT_SIZE; i++) {
192 			float diff = (inbuf[i] - som_table[n].wgt[i]);
193 					difference += diff * diff;
194 					if (difference > diffsf) break;
195 	  		}
196 
197 	 /* If distance is smaller than previous distances */
198 			if (difference < diffsf) {
199 	  			winner = n;
200 	  			diffsf = difference;
201 			}
202 	}
203 
204 	std::string sc;
205 	if (!som_table[winner].rpr.empty()) {
206 		sc = morse.rx_lookup(som_table[winner].rpr);
207 		if (sc.empty())
208 			sc = (progdefaults.CW_noise == '*' ? "*" :
209 				  progdefaults.CW_noise == '_' ? "_" :
210 				  progdefaults.CW_noise == ' ' ? " " : "");
211 	} else
212 		sc = (progdefaults.CW_noise == '*' ? "*" :
213 			  progdefaults.CW_noise == '_' ? "_" :
214 			  progdefaults.CW_noise == ' ' ? " " : "");
215 	return sc;
216 }
217 
tx_init()218 void cw::tx_init()
219 {
220 	phaseacc = 0;
221 	lastsym = 0;
222 	qskphase = 0;
223 	if (progdefaults.pretone) pretone();
224 
225 	symbols = 0;
226 	acc_symbols = 0;
227 	ovhd_symbols = 0;
228 
229 	maxval = 0.0;
230 }
231 
rx_init()232 void cw::rx_init()
233 {
234 	cw_receive_state = RS_IDLE;
235 	smpl_ctr = 0;
236 	cw_rr_current = 0;
237 	cw_ptr = 0;
238 	agc_peak = 0;
239 	set_scope_mode(Digiscope::SCOPE);
240 
241 	update_Status();
242 	usedefaultWPM = false;
243 	scope_clear = true;
244 
245 	viewcw.restart();
246 }
247 
init()248 void cw::init()
249 {
250 	bool wfrev = wf->Reverse();
251 	bool wfsb = wf->USB();
252 	reverse = wfrev ^ !wfsb;
253 
254 	if (progdefaults.StartAtSweetSpot)
255 		set_freq(progdefaults.CWsweetspot);
256 	else if (progStatus.carrier != 0) {
257 		set_freq(progStatus.carrier);
258 #if !BENCHMARK_MODE
259 		progStatus.carrier = 0;
260 #endif
261 	} else
262 		set_freq(wf->Carrier());
263 
264 	trackingfilter->reset();
265 	two_dots = (long int)trackingfilter->run(2 * cw_send_dot_length);
266 	put_cwRcvWPM(cw_send_speed);
267 
268 	memset(outbuf, 0, OUTBUFSIZE*sizeof(*outbuf));
269 	memset(qskbuf, 0, OUTBUFSIZE*sizeof(*qskbuf));
270 
271 	morse.init();
272 	use_paren = progdefaults.CW_use_paren;
273 	prosigns = progdefaults.CW_prosigns;
274 
275 	rx_init();
276 
277 	stopflag = false;
278 	maxval = 0;
279 
280 	if (use_nanoIO) set_nanoCW();
281 
282 }
283 
~cw()284 cw::~cw() {
285 	if (cw_FFT_filter) delete cw_FFT_filter;
286 	if (bitfilter) delete bitfilter;
287 	if (trackingfilter) delete trackingfilter;
288 	stop_cwio_thread();
289 }
290 
cw()291 cw::cw() : modem()
292 {
293 	cap |= CAP_BW;
294 
295 	mode = MODE_CW;
296 	freqlock = false;
297 	usedefaultWPM = false;
298 	frequency = progdefaults.CWsweetspot;
299 	tx_frequency = get_txfreq_woffset();
300 	risetime = progdefaults.CWrisetime;
301 	QSKshape = progdefaults.QSKshape;
302 
303 	cw_ptr = 0;
304 	clrcount = CLRCOUNT;
305 
306 	samplerate = CW_SAMPLERATE;
307 	fragmentsize = CWMaxSymLen;
308 
309 	wpm = cw_speed  = progdefaults.CWspeed;
310 	bandwidth = progdefaults.CWbandwidth;
311 
312 	cw_send_speed = cw_speed;
313 	cw_receive_speed = cw_speed;
314 	two_dots = 2 * KWPM / cw_speed;
315 	cw_noise_spike_threshold = two_dots / 4;
316 	cw_send_dot_length = KWPM / cw_send_speed;
317 	cw_send_dash_length = 3 * cw_send_dot_length;
318 	symbollen = (int)round(samplerate * 1.2 / progdefaults.CWspeed);  // transmit char rate
319 	fsymlen = (int)round(samplerate * 1.2 / progdefaults.CWfarnsworth); // transmit word rate
320 
321 	rx_rep_buf.clear();
322 
323 // block of variables that get updated each time speed changes
324 	pipesize = (22 * samplerate * 12) / (progdefaults.CWspeed * 160);
325 	if (pipesize < 0) pipesize = 512;
326 	if (pipesize > MAX_PIPE_SIZE) pipesize = MAX_PIPE_SIZE;
327 
328 	cwTrack = true;
329 	phaseacc = 0.0;
330 	FFTphase = 0.0;
331 	FFTvalue = 0.0;
332 	pipeptr = 0;
333 	clrcount = 0;
334 
335 	upper_threshold = progdefaults.CWupper;
336 	lower_threshold = progdefaults.CWlower;
337 	for (int i = 0; i < MAX_PIPE_SIZE; clearpipe[i++] = 0.0);
338 
339 	agc_peak = 1.0;
340 	in_replay = 0;
341 
342 	use_matched_filter = progdefaults.CWmfilt;
343 
344 	bandwidth = progdefaults.CWbandwidth;
345 	if (use_matched_filter)
346 		progdefaults.CWbandwidth = bandwidth = 5.0 * progdefaults.CWspeed / 1.2;
347 
348 	cw_FFT_filter = new fftfilt(1.0 * progdefaults.CWbandwidth / samplerate, CW_FFT_SIZE);
349 
350 	int bfv = symbollen / ( 2 * DEC_RATIO);
351 	if (bfv < 1) bfv = 1;
352 
353 	bitfilter = new Cmovavg(bfv);
354 
355 	trackingfilter = new Cmovavg(TRACKING_FILTER_SIZE);
356 
357 	create_edges();
358 
359 	nano_wpm = progdefaults.CWspeed;
360 	nano_d2d = progdefaults.CWdash2dot;
361 
362 	sync_parameters();
363 	REQ(static_cast<void (waterfall::*)(int)>(&waterfall::Bandwidth), wf, (int)bandwidth);
364 	REQ(static_cast<int (Fl_Value_Slider2::*)(double)>(&Fl_Value_Slider2::value), sldrCWbandwidth, (int)bandwidth);
365 	update_Status();
366 
367 	synchscope = 50;
368 	noise_floor = 1.0;
369 	sig_avg = 0.0;
370 
371 	start_cwio_thread();
372 
373 }
374 
375 // SHOULD ONLY BE CALLED FROM THE rx_processing loop
reset_rx_filter()376 void cw::reset_rx_filter()
377 {
378 	if (use_matched_filter != progdefaults.CWmfilt ||
379 		cw_speed != progdefaults.CWspeed ||
380 		(bandwidth != progdefaults.CWbandwidth && !use_matched_filter)) {
381 
382 		use_matched_filter = progdefaults.CWmfilt;
383 		cw_send_speed = cw_speed = progdefaults.CWspeed;
384 
385 		if (use_matched_filter)
386 			progdefaults.CWbandwidth = bandwidth = 5.0 * progdefaults.CWspeed / 1.2;
387 		else
388 			bandwidth = progdefaults.CWbandwidth;
389 
390 		cw_FFT_filter->create_lpf(1.0 * bandwidth / samplerate);
391 		FFTphase = 0;
392 
393 		REQ(static_cast<void (waterfall::*)(int)>(&waterfall::Bandwidth),
394 			wf, (int)bandwidth);
395 		REQ(static_cast<int (Fl_Value_Slider2::*)(double)>(&Fl_Value_Slider2::value),
396 			sldrCWbandwidth, (int)bandwidth);
397 
398 		pipesize = (22 * samplerate * 12) / (progdefaults.CWspeed * 160);
399 		if (pipesize < 0) pipesize = 512;
400 		if (pipesize > MAX_PIPE_SIZE) pipesize = MAX_PIPE_SIZE;
401 
402 		two_dots = 2 * KWPM / cw_speed;
403 		cw_noise_spike_threshold = two_dots / 4;
404 		cw_send_dot_length = KWPM / cw_send_speed;
405 		cw_send_dash_length = 3 * cw_send_dot_length;
406 		symbollen = (int)round(samplerate * 1.2 / progdefaults.CWspeed);
407 		fsymlen = (int)round(samplerate * 1.2 / progdefaults.CWfarnsworth);
408 
409 		phaseacc = 0.0;
410 		FFTphase = 0.0;
411 		FFTvalue = 0.0;
412 		pipeptr = 0;
413 		clrcount = 0;
414 		smpl_ctr = 0;
415 
416 		rx_rep_buf.clear();
417 
418 	int bfv = symbollen / ( 2 * DEC_RATIO);
419 	if (bfv < 1) bfv = 1;
420 
421 	bitfilter->setLength(bfv);
422 
423 	siglevel = 0;
424 
425 	}
426 
427 }
428 
429 // sync_parameters()
430 // Synchronize the dot, dash, end of element, end of character, and end
431 // of word timings and ranges to new values of Morse speed, or receive tolerance.
432 
sync_transmit_parameters()433 void cw::sync_transmit_parameters()
434 {
435 //	wpm = usedefaultWPM ? progdefaults.defCWspeed : progdefaults.CWspeed;
436 	fwpm = progdefaults.CWfarnsworth;
437 
438 	cw_send_dot_length = KWPM / progdefaults.CWspeed;
439 	cw_send_dash_length = 3 * cw_send_dot_length;
440 
441 	nusymbollen = (int)round(samplerate * 1.2 / progdefaults.CWspeed);
442 	nufsymlen = (int)round(samplerate * 1.2 / fwpm);
443 
444 	if (symbollen != nusymbollen ||
445 		nufsymlen != fsymlen ||
446 		risetime  != progdefaults.CWrisetime ||
447 		QSKshape  != progdefaults.QSKshape) {
448 		risetime = progdefaults.CWrisetime;
449 		QSKshape = progdefaults.QSKshape;
450 		symbollen = nusymbollen;
451 		fsymlen = nufsymlen;
452 		create_edges();
453 	}
454 }
455 
sync_parameters()456 void cw::sync_parameters()
457 {
458 	sync_transmit_parameters();
459 
460 	if (use_nanoIO) {
461 		if (nano_wpm != progdefaults.CWspeed) {
462 			nano_wpm = progdefaults.CWspeed;
463 			set_nanoWPM(progdefaults.CWspeed);
464 		}
465 		if (nano_d2d != progdefaults.CWdash2dot) {
466 			nano_d2d = progdefaults.CWdash2dot;
467 			set_nano_dash2dot(progdefaults.CWdash2dot);
468 		}
469 	}
470 
471 // check if user changed the tracking or the cw default speed
472 	if ((cwTrack != progdefaults.CWtrack) ||
473 		(cw_send_speed != progdefaults.CWspeed)) {
474 		trackingfilter->reset();
475 		two_dots = 2 * cw_send_dot_length;
476 		put_cwRcvWPM(cw_send_speed);
477 	}
478 	cwTrack = progdefaults.CWtrack;
479 	cw_send_speed = progdefaults.CWspeed;
480 
481 // Receive parameters:
482 	lowerwpm = cw_send_speed - progdefaults.CWrange;
483 	upperwpm = cw_send_speed + progdefaults.CWrange;
484 	if (lowerwpm < progdefaults.CWlowerlimit)
485 		lowerwpm = progdefaults.CWlowerlimit;
486 	if (upperwpm > progdefaults.CWupperlimit)
487 		upperwpm = progdefaults.CWupperlimit;
488 	cw_lower_limit = 2 * KWPM / upperwpm;
489 	cw_upper_limit = 2 * KWPM / lowerwpm;
490 
491 	if (cwTrack)
492 		cw_receive_speed = KWPM / (two_dots / 2);
493 	else {
494 		cw_receive_speed = cw_send_speed;
495 		two_dots = 2 * cw_send_dot_length;
496 	}
497 
498 	if (cw_receive_speed > 0)
499 		cw_receive_dot_length = KWPM / cw_receive_speed;
500 	else
501 		cw_receive_dot_length = KWPM / 5;
502 
503 	cw_receive_dash_length = 3 * cw_receive_dot_length;
504 
505 	cw_noise_spike_threshold = cw_receive_dot_length / 2;
506 
507 }
508 
509 
510 //=======================================================================
511 // cw_update_tracking()
512 //=======================================================================
513 
update_tracking(int dur_1,int dur_2)514 inline void cw::update_tracking(int dur_1, int dur_2)
515 {
516 static int min_dot = KWPM / 200;
517 static int max_dash = 3 * KWPM / 5;
518 	if ((dur_1 > dur_2) && (dur_1 > 4 * dur_2)) return;
519 	if ((dur_2 > dur_1) && (dur_2 > 4 * dur_1)) return;
520 	if (dur_1 < min_dot || dur_2 < min_dot) return;
521 	if (dur_2 > max_dash || dur_2 > max_dash) return;
522 
523 	two_dots = trackingfilter->run((dur_1 + dur_2) / 2);
524 
525 	sync_parameters();
526 }
527 
update_Status()528 void cw::update_Status()
529 {
530 	put_MODEstatus("CW %s Rx %d", usedefaultWPM ? "*" : " ", cw_receive_speed);
531 	REQ(set_CWwpm);
532 }
533 
534 //=======================================================================
535 //update_syncscope()
536 //Routine called to update the display on the sync scope display.
537 //For CW this is an o scope pattern that shows the cw data stream.
538 //=======================================================================
539 //
540 
update_syncscope()541 void cw::update_syncscope()
542 {
543 	if (pipesize < 0 || pipesize > MAX_PIPE_SIZE)
544 		return;
545 
546 	for (int i = 0; i < pipesize; i++)
547 		scopedata[i] = 0.96*pipe[i]+0.02;
548 
549 	set_scope_xaxis_1(siglevel);
550 
551 	set_scope(scopedata, pipesize, true);
552 	scopedata.next(); // change buffers
553 
554 	clrcount = CLRCOUNT;
555 	put_cwRcvWPM(cw_receive_speed);
556 	update_Status();
557 }
558 
clear_syncscope()559 void cw::clear_syncscope()
560 {
561 	set_scope_xaxis_1(siglevel);
562 
563 	set_scope(clearpipe, pipesize, false);
564 	clrcount = CLRCOUNT;
565 }
566 
mixer(cmplx in)567 cmplx cw::mixer(cmplx in)
568 {
569 	cmplx z (cos(phaseacc), sin(phaseacc));
570 	z = z * in;
571 
572 	phaseacc += TWOPI * frequency / samplerate;
573 	if (phaseacc > TWOPI) phaseacc -= TWOPI;
574 
575 	return z;
576 }
577 
578 //=====================================================================
579 // cw_rxprocess()
580 // Called with a block (size SCBLOCKSIZE samples) of audio.
581 //
582 //======================================================================
583 
decode_stream(double value)584 void cw::decode_stream(double value)
585 {
586 	std::string sc;
587 	std::string somc;
588 	int attack = 0;
589 	int decay = 0;
590 	switch (progdefaults.cwrx_attack) {
591 		case 0: attack = 400; break;//100; break;
592 		case 1: default: attack = 200; break;//50; break;
593 		case 2: attack = 100;//25;
594 	}
595 	switch (progdefaults.cwrx_decay) {
596 		case 0: decay = 2000; break;//1000; break;
597 		case 1: default : decay = 1000; break;//500; break;
598 		case 2: decay = 500;//250;
599 	}
600 
601 	sig_avg = decayavg(sig_avg, value, decay);
602 
603 	if (value < sig_avg) {
604 		if (value < noise_floor)
605 			noise_floor = decayavg(noise_floor, value, attack);
606 		else
607 			noise_floor = decayavg(noise_floor, value, decay);
608 	}
609 	if (value > sig_avg)  {
610 		if (value > agc_peak)
611 			agc_peak = decayavg(agc_peak, value, attack);
612 		else
613 			agc_peak = decayavg(agc_peak, value, decay);
614 	}
615 
616 	float norm_noise  = noise_floor / agc_peak;
617 	float norm_sig    = sig_avg / agc_peak;
618 	siglevel = norm_sig;
619 
620 	if (agc_peak)
621 		value /= agc_peak;
622 	else
623 		value = 0;
624 
625 	metric = 0.8 * metric;
626 	if ((noise_floor > 1e-4) && (noise_floor < sig_avg))
627 		metric += 0.2 * clamp(2.5 * (20*log10(sig_avg / noise_floor)) , 0, 100);
628 
629 	float diff = (norm_sig - norm_noise);
630 
631 	progdefaults.CWupper = norm_sig - 0.2 * diff;
632 	progdefaults.CWlower = norm_noise + 0.7 * diff;
633 
634 	pipe[pipeptr] = value;
635 	if (++pipeptr == pipesize) pipeptr = 0;
636 
637 	if (!progStatus.sqlonoff || metric > progStatus.sldrSquelchValue ) {
638 // Power detection using hysterisis detector
639 // upward trend means tone starting
640 		if ((value > progdefaults.CWupper) && (cw_receive_state != RS_IN_TONE)) {
641 			handle_event(CW_KEYDOWN_EVENT, sc);
642 		}
643 // downward trend means tone stopping
644 		if ((value < progdefaults.CWlower) && (cw_receive_state == RS_IN_TONE)) {
645 			handle_event(CW_KEYUP_EVENT, sc);
646 		}
647 	}
648 
649 	if (handle_event(CW_QUERY_EVENT, sc) == CW_SUCCESS) {
650 		update_syncscope();
651 		synchscope = 100;
652 		if (progdefaults.CWuseSOMdecoding) {
653 			somc = find_winner(cw_buffer, two_dots);
654 			if (!somc.empty())
655 				for (size_t n = 0; n < somc.length(); n++)
656 					put_rx_char(
657 						somc[n],
658 						somc[0] == '<' ? FTextBase::CTRL : FTextBase::RECV);
659 			cw_ptr = 0;
660 			memset(cw_buffer, 0, sizeof(cw_buffer));
661 		} else {
662 			for (size_t n = 0; n < sc.length(); n++)
663 				put_rx_char(
664 					sc[n],
665 					sc[0] == '<' ? FTextBase::CTRL : FTextBase::RECV);
666 		}
667 	} else if (--synchscope == 0) {
668 		synchscope = 25;
669 	update_syncscope();
670 	}
671 
672 }
673 
rx_FFTprocess(const double * buf,int len)674 void cw::rx_FFTprocess(const double *buf, int len)
675 {
676 	cmplx z, *zp;
677 	int n;
678 
679 	while (len-- > 0) {
680 
681 		z = cmplx ( *buf * cos(FFTphase), *buf * sin(FFTphase) );
682 		FFTphase += TWOPI * frequency / samplerate;
683 		if (FFTphase > TWOPI) FFTphase -= TWOPI;
684 
685 		buf++;
686 
687 		n = cw_FFT_filter->run(z, &zp); // n = 0 or filterlen/2
688 
689 		if (!n) continue;
690 
691 		for (int i = 0; i < n; i++) {
692 // update the basic sample counter used for morse timing
693 			++smpl_ctr;
694 
695 			if (smpl_ctr % DEC_RATIO) continue; // decimate by DEC_RATIO
696 
697 // demodulate
698 			FFTvalue = abs(zp[i]);
699 			FFTvalue = bitfilter->run(FFTvalue);
700 
701 			decode_stream(FFTvalue);
702 
703 		} // for (i =0; i < n ...
704 
705 	} //while (len-- > 0)
706 }
707 
708 static bool cwprocessing = false;
709 
rx_process(const double * buf,int len)710 int cw::rx_process(const double *buf, int len)
711 {
712 	if (use_paren != progdefaults.CW_use_paren ||
713 		prosigns != progdefaults.CW_prosigns) {
714 		use_paren = progdefaults.CW_use_paren;
715 		prosigns = progdefaults.CW_prosigns;
716 		morse.init();
717 	}
718 
719 	if (cwprocessing)
720 		return 0;
721 
722 	cwprocessing = true;
723 
724 	reset_rx_filter();
725 
726 	rx_FFTprocess(buf, len);
727 
728 	if (!clrcount--) clear_syncscope();
729 
730 	display_metric(metric);
731 
732 	if ( (dlgViewer->visible() || progStatus.show_channels )
733 		&& !bHighSpeed && !bHistory )
734 		viewcw.rx_process(buf, len);
735 
736 	cwprocessing = false;
737 
738 	return 0;
739 }
740 
741 // ----------------------------------------------------------------------
742 
743 // Compare two timestamps, and return the difference between them in usecs.
744 
usec_diff(unsigned int earlier,unsigned int later)745 inline int cw::usec_diff(unsigned int earlier, unsigned int later)
746 {
747 	return (earlier >= later) ? 0 : (later - earlier);
748 }
749 
750 
751 //=======================================================================
752 // handle_event()
753 //	high level cw decoder... gets called with keyup, keydown, reset and
754 //	query commands.
755 //   Keyup/down influences decoding logic.
756 //	Reset starts everything out fresh.
757 //	The query command returns CW_SUCCESS and the character that has
758 //	been decoded (may be '*',' ' or [a-z,0-9] or a few others)
759 //	If there is no data ready, CW_ERROR is returned.
760 //=======================================================================
761 
handle_event(int cw_event,string & sc)762 int cw::handle_event(int cw_event, string &sc)
763 {
764 	static int space_sent = true;	// for word space logic
765 	static int last_element = 0;	// length of last dot/dash
766 	int element_usec;		// Time difference in usecs
767 
768 	switch (cw_event) {
769 	case CW_RESET_EVENT:
770 		sync_parameters();
771 		cw_receive_state = RS_IDLE;
772 		cw_rr_current = 0;			// reset decoding pointer
773 		cw_ptr = 0;
774 		memset(cw_buffer, 0, sizeof(cw_buffer));
775 		smpl_ctr = 0;					// reset audio sample counter
776 		rx_rep_buf.clear();
777 		break;
778 	case CW_KEYDOWN_EVENT:
779 // A receive tone start can only happen while we
780 // are idle, or in the middle of a character.
781 		if (cw_receive_state == RS_IN_TONE)
782 			return CW_ERROR;
783 // first tone in idle state reset audio sample counter
784 		if (cw_receive_state == RS_IDLE) {
785 			smpl_ctr = 0;
786 			rx_rep_buf.clear();
787 			cw_rr_current = 0;
788 			cw_ptr = 0;
789 		}
790 // save the timestamp
791 		cw_rr_start_timestamp = smpl_ctr;
792 // Set state to indicate we are inside a tone.
793 		old_cw_receive_state = cw_receive_state;
794 		cw_receive_state = RS_IN_TONE;
795 		return CW_ERROR;
796 		break;
797 	case CW_KEYUP_EVENT:
798 // The receive state is expected to be inside a tone.
799 		if (cw_receive_state != RS_IN_TONE)
800 			return CW_ERROR;
801 // Save the current timestamp
802 		cw_rr_end_timestamp = smpl_ctr;
803 		element_usec = usec_diff(cw_rr_start_timestamp, cw_rr_end_timestamp);
804 
805 // make sure our timing values are up to date
806 		sync_parameters();
807 // If the tone length is shorter than any noise cancelling
808 // threshold that has been set, then ignore this tone.
809 		if (cw_noise_spike_threshold > 0
810 			&& element_usec < cw_noise_spike_threshold) {
811 			cw_receive_state = RS_IDLE;
812  			return CW_ERROR;
813 		}
814 
815 // Set up to track speed on dot-dash or dash-dot pairs for this test to work, we need a dot dash pair or a
816 // dash dot pair to validate timing from and force the speed tracking in the right direction. This method
817 // is fundamentally different than the method in the unix cw project. Great ideas come from staring at the
818 // screen long enough!. Its kind of simple really ... when you have no idea how fast or slow the cw is...
819 // the only way to get a threshold is by having both code elements and setting the threshold between them
820 // knowing that one is supposed to be 3 times longer than the other. with straight key code... this gets
821 // quite variable, but with most faster cw sent with electronic keyers, this is one relationship that is
822 // quite reliable. Lawrence Glaister (ve7it@shaw.ca)
823 		if (last_element > 0) {
824 // check for dot dash sequence (current should be 3 x last)
825 			if ((element_usec > 2 * last_element) &&
826 				(element_usec < 4 * last_element)) {
827 				update_tracking(last_element, element_usec);
828 			}
829 // check for dash dot sequence (last should be 3 x current)
830 			if ((last_element > 2 * element_usec) &&
831 				(last_element < 4 * element_usec)) {
832 				update_tracking(element_usec, last_element);
833 			}
834 		}
835 		last_element = element_usec;
836 // ok... do we have a dit or a dah?
837 // a dot is anything shorter than 2 dot times
838 		if (element_usec <= two_dots) {
839 			rx_rep_buf += CW_DOT_REPRESENTATION;
840 	//		printf("%d dit ", last_element/1000);  // print dot length
841 			cw_buffer[cw_ptr++] = (float)last_element;
842 		} else {
843 // a dash is anything longer than 2 dot times
844 			rx_rep_buf += CW_DASH_REPRESENTATION;
845 			cw_buffer[cw_ptr++] = (float)last_element;
846 		}
847 // We just added a representation to the receive buffer.
848 // If it's full, then reset everything as it probably noise
849 		if (rx_rep_buf.length() > MAX_MORSE_ELEMENTS) {
850 			cw_receive_state = RS_IDLE;
851 			cw_rr_current = 0;	// reset decoding pointer
852 			cw_ptr = 0;
853 			smpl_ctr = 0;		// reset audio sample counter
854 			return CW_ERROR;
855 		} else {
856 // zero terminate representation
857 //			rx_rep_buf.clear();
858 			cw_buffer[cw_ptr] = 0.0;
859 		}
860 // All is well.  Move to the more normal after-tone state.
861 		cw_receive_state = RS_AFTER_TONE;
862 		return CW_ERROR;
863 		break;
864 	case CW_QUERY_EVENT:
865 // this should be called quite often (faster than inter-character gap) It looks after timing
866 // key up intervals and determining when a character, a word space, or an error char '*' should be returned.
867 // CW_SUCCESS is returned when there is a printable character. Nothing to do if we are in a tone
868 		if (cw_receive_state == RS_IN_TONE)
869 			return CW_ERROR;
870 // compute length of silence so far
871 		sync_parameters();
872 		element_usec = usec_diff(cw_rr_end_timestamp, smpl_ctr);
873 // SHORT time since keyup... nothing to do yet
874 		if (element_usec < (2 * cw_receive_dot_length))
875 			return CW_ERROR;
876 // MEDIUM time since keyup... check for character space
877 // one shot through this code via receive state logic
878 // FARNSWOTH MOD HERE -->
879 		if (element_usec >= (2 * cw_receive_dot_length) &&
880 			element_usec <= (4 * cw_receive_dot_length) &&
881 			cw_receive_state == RS_AFTER_TONE) {
882 // Look up the representation
883 			sc = morse.rx_lookup(rx_rep_buf);
884 			if (sc.empty()) {
885 // invalid decode... let user see error
886 			sc = (progdefaults.CW_noise == '*' ? "*" :
887 				  progdefaults.CW_noise == '_' ? "_" :
888 				  progdefaults.CW_noise == ' ' ? " " : "");
889 
890 			}
891 			rx_rep_buf.clear();
892 			cw_receive_state = RS_IDLE;
893 			cw_rr_current = 0;	// reset decoding pointer
894 			space_sent = false;
895 			cw_ptr = 0;
896 
897 			return CW_SUCCESS;
898 		}
899 // LONG time since keyup... check for a word space
900 // FARNSWOTH MOD HERE -->
901 		if ((element_usec > (4 * cw_receive_dot_length)) && !space_sent) {
902 			sc = " ";
903 			space_sent = true;
904 			return CW_SUCCESS;
905 		}
906 // should never get here... catch all
907 		return CW_ERROR;
908 		break;
909 	}
910 // should never get here... catch all
911 	return CW_ERROR;
912 }
913 
914 //===========================================================================
915 // cw transmit routines
916 // Define the amplitude envelop for key down events (32 samples long)
917 // this is 1/2 cycle of a raised cosine
918 //===========================================================================
919 
920 double keyshape[CWKNUM];
921 double QSKkeyshape[CWKNUM];
922 
create_edges()923 void cw::create_edges()
924 {
925 	for (int i = 0; i < CWKNUM; i++) keyshape[i] = 1.0;
926 
927 	switch (QSKshape) {
928 		case 1: // blackman
929 			knum = (int)(risetime * CW_SAMPLERATE / 1000);
930 			if (knum >= symbollen) knum = symbollen;
931 			for (int i = 0; i < knum; i++)
932 				keyshape[i] = (0.42 - 0.50 * cos(M_PI * i/ knum) + 0.08 * cos(2 * M_PI * i / knum));
933 			break;
934 		case 0: // hanning
935 		default:
936 			knum = (int)(risetime * CW_SAMPLERATE / 1000);
937 			if (knum >= symbollen) knum = symbollen;
938 			for (int i = 0; i < knum; i++)
939 				keyshape[i] = 0.5 * (1.0 - cos (M_PI * i / knum));
940 	}
941 
942 	for (int i = 0; i < CWKNUM; i++) QSKkeyshape[i] = 1.0;
943 
944 	switch (QSKshape) {
945 		case 1: // blackman
946 			qnum = (int)(progdefaults.QSKrisetime * CW_SAMPLERATE / 1000);
947 			if (qnum >= symbollen) qnum = symbollen;
948 			for (int i = 0; i < qnum; i++)
949 				QSKkeyshape[i] = (0.42 - 0.50 * cos(M_PI * i/ qnum) + 0.08 * cos(2 * M_PI * i / qnum));
950 			break;
951 		case 0: // hanning
952 		default:
953 			qnum = (int)(progdefaults.QSKrisetime * CW_SAMPLERATE / 1000);
954 			if (qnum >= symbollen) qnum = symbollen;
955 			for (int i = 0; i < qnum; i++)
956 				QSKkeyshape[i] = 0.5 * (1.0 - cos (M_PI * i / qnum));
957 	}
958 }
959 
nco(double freq)960 inline double cw::nco(double freq)
961 {
962 	phaseacc += 2.0 * M_PI * freq / samplerate;
963 	if (phaseacc > TWOPI) phaseacc -= TWOPI;
964 	return sin(phaseacc);
965 }
966 
qsknco()967 inline double cw::qsknco()
968 {
969 	double amp;
970 	amp = sin(qskphase);
971 	qskphase += TWOPI * progdefaults.QSKfrequency / samplerate;
972 	if (qskphase > TWOPI) qskphase -= TWOPI;
973 	return amp;
974 }
975 
976 //=====================================================================
977 // send_symbol()
978 // Sends a part of a morse character (one dot duration) of either
979 // sound at the correct freq or silence. Rise and fall time is controlled
980 // with a raised cosine shape.
981 //
982 // Left channel contains the shaped A2 CW waveform
983 // Right channel contains a square wave signal that is used
984 // to trigger a qsk switch.  Right channel has pre and post timings for
985 // proper switching of the qsk switch before and after the A2 element.
986 // If the Pre + Post timing exceeds the interelement spacing then the
987 // Pre and / or Post is only applied at the beginning and end of the
988 // character.
989 //=======================================================================
990 
991 bool first_char = true;
992 
993 enum {START, FIRST, MID, LAST, SPACE};
994 
send_symbol(int bit,int len,int state)995 void cw::send_symbol(int bit, int len, int state)
996 {
997 	double qsk_amp = progdefaults.QSK ? progdefaults.QSKamp : 0.0;
998 
999 	sync_transmit_parameters();
1000 	acc_symbols += len;
1001 
1002 	memset(outbuf, 0, OUTBUFSIZE*sizeof(*outbuf));
1003 	memset(qskbuf, 0, OUTBUFSIZE*sizeof(*qskbuf));
1004 
1005 	if (bit == 1) { // keydown
1006 		tx_frequency = get_txfreq_woffset();
1007 		if (CW_KEYLINE_isopen ||
1008 			progdefaults.CW_KEYLINE_on_cat_port ||
1009 			progdefaults.CW_KEYLINE_on_ptt_port)
1010 			tx_frequency = progdefaults.CWsweetspot;
1011 		for (int n = 0; n < len; n++) {
1012 			outbuf[n] = nco(tx_frequency);
1013 			if (n < knum) outbuf[n] *= keyshape[n];
1014 			if (len - n < knum) outbuf[n] *= keyshape[len - n];
1015 			qskbuf[n] = qsk_amp * qsknco();
1016 		}
1017 	} else { // keyup
1018 		for (int n = 0; n < len; n++) {
1019 			outbuf[n] = 0;
1020 			if (progdefaults.QSK) {
1021 				qskbuf[n] = 0;
1022 				if (state == START || state == FIRST) {
1023 					qskbuf[n] = 0;
1024 					if (n > len - kpre) {
1025 						qskbuf[n] = qsk_amp * qsknco();
1026 						if (n < len - kpre + qnum)
1027 							qskbuf[n] *= QSKkeyshape[n - (len - kpre)];
1028 					}
1029 				} else if (state == MID) {
1030 					qskbuf[n] = qsk_amp * qsknco();
1031 					if (len > kpre + kpost) {
1032 						if (n < kpost)
1033 							qskbuf[n] *= QSKkeyshape[kpost - n];
1034 						else if (n > len - kpre)
1035 							qskbuf[n] *= QSKkeyshape[n - (len - kpre)];
1036 						else qskbuf[n] = 0;
1037 					}
1038 				} else if (state == LAST) {
1039 					qskbuf[n] = qsk_amp * qsknco();
1040 					if (n > kpost - qnum)
1041 						qskbuf[n] *= QSKkeyshape[kpost - n];
1042 					if (n >= kpost) qskbuf[n] = 0;
1043 				} else { // state == SPACE
1044 					qskbuf[n] = 0;
1045 				}
1046 			}
1047 		}
1048 	}
1049 
1050 	if (progdefaults.QSK)
1051 		ModulateStereo(outbuf, qskbuf, len);
1052 	else
1053 		ModulateXmtr(outbuf, len);
1054 
1055 }
1056 
1057 //=====================================================================
1058 // send_ch()
1059 // sends a morse character and the space afterwards
1060 //=======================================================================
1061 
send_ch(int ch)1062 void cw::send_ch(int ch)
1063 {
1064 	string code;
1065 
1066 	float kfactor = CW_SAMPLERATE / 1000.0;
1067 	float tc = 1200.0 / progdefaults.CWspeed;
1068 	float ta = 0.0;
1069 	float tch = 3 * tc, twd = 4 * tc;
1070 
1071 	if (progdefaults.CWusefarnsworth && (progdefaults.CWspeed > progdefaults.CWfarnsworth)) {
1072 		ta = 60000.0 / progdefaults.CWfarnsworth - 37200.0 / progdefaults.CWspeed;
1073 		tch = 3 * ta / 19;
1074 		twd = 4 * ta / 19;
1075 	}
1076 	tc *= kfactor;
1077 	tch *= kfactor;
1078 	twd *= kfactor;
1079 
1080 	sync_parameters();
1081 
1082 	if (progdefaults.CWpre < progdefaults.QSKrisetime)
1083 		kpre = progdefaults.QSKrisetime * kfactor;
1084 	else
1085 		kpre = progdefaults.CWpre * kfactor;
1086 
1087 	if (progdefaults.CWpost < progdefaults.QSKrisetime)
1088 		kpost = progdefaults.QSKrisetime * kfactor;
1089 	else
1090 		kpost = progdefaults.CWpost * kfactor;
1091 
1092 	if ((ch == ' ') || (ch == '\n')) {
1093 		send_symbol(0,
1094 			twd,
1095 			SPACE);
1096 		put_echo_char(progdefaults.rx_lowercase ? tolower(ch) : ch);
1097 		return;
1098 	}
1099 
1100 	code = morse.tx_lookup(ch);
1101 	if (!code.length()) {
1102 		return;
1103 	}
1104 
1105 	float w = (progdefaults.CWdash2dot + 1) / (progdefaults.CWdash2dot -1);
1106 
1107 	int elements = code.length();
1108 
1109 	if (kpre)
1110 		send_symbol(
1111 			0,
1112 			(first_char ? kpre :
1113 				(kpre < 3 * tc - kpost) ? kpre :
1114 					3 * tc ),
1115 			(first_char ? START : FIRST));
1116 
1117 	for (int n = 0; n < elements; n++) {
1118 		send_symbol(1,
1119 					(code[n] == '-' ? (w + 1) : (w - 1)) * symbollen,
1120 					MID);
1121 		send_symbol(0,
1122 					((n < elements - 1) ? tc :
1123 						(kpost + kpre < 3 * tc) ? tch - kpre:
1124 							tch),
1125 					(n < elements - 1 ? MID : LAST) );
1126 	}
1127 
1128 	if (ch != -1) {
1129 		string prtstr = morse.tx_print();
1130 		for (size_t n = 0; n < prtstr.length(); n++)
1131 			put_echo_char(
1132 				prtstr[n],
1133 				prtstr[0] == '<' ? FTextBase::CTRL : FTextBase::XMIT);
1134 	}
1135 }
1136 
1137 //=====================================================================
1138 // cw_txprocess()
1139 // Read characters from screen and send them out the sound card.
1140 // This is called repeatedly from a thread during tx.
1141 //=======================================================================
tx_process()1142 int cw::tx_process()
1143 {
1144 	int c = get_tx_char();
1145 
1146 	if (c == GET_TX_CHAR_NODATA) {
1147 		if (stopflag) {
1148 			stopflag = false;
1149 			put_echo_char('\n');
1150 			first_char = true;
1151 			return -1;
1152 		}
1153 		Fl::awake();
1154 		MilliSleep(50);
1155 		return 0;
1156 	}
1157 
1158 	if (progdefaults.use_FLRIGkeying) {
1159 		if (c == GET_TX_CHAR_ETX || stopflag) {
1160 			stopflag = false;
1161 			put_echo_char('\n');
1162 			return -1;
1163 		}
1164 		flrig_cwio_send(c);
1165 		put_echo_char(c);
1166 		return 0;
1167 	}
1168 
1169 	if (progStatus.WK_online) {
1170 		if (c == GET_TX_CHAR_ETX || stopflag) {
1171 			stopflag = false;
1172 			put_echo_char('\n');
1173 			return -1;
1174 		}
1175 		if (WK_send_char(c)){
1176 			put_echo_char('\n');
1177 			return -1; // WinKeyer problem
1178 		}
1179 		return 0;
1180 	}
1181 
1182 	if (use_nanoIO) {
1183 		if (c == GET_TX_CHAR_ETX || stopflag) {
1184 			stopflag = false;
1185 			put_echo_char('\n');
1186 			return -1;
1187 		}
1188 		nano_send_char(c);
1189 		put_echo_char(c);
1190 		return 0;
1191 	}
1192 
1193 	if (progdefaults.use_ELCTkeying || progdefaults.use_KNWDkeying) {
1194 		if (c == GET_TX_CHAR_ETX || stopflag) {
1195 			stopflag = false;
1196 			put_echo_char('\n');
1197 			return -1;
1198 		}
1199 		KYkeyer_send_char(c);
1200 		put_echo_char(c);
1201 		return 0;
1202 	}
1203 
1204 	if (progdefaults.use_ICOMkeying) {
1205 		if (c == GET_TX_CHAR_ETX || stopflag) {
1206 			stopflag = false;
1207 			put_echo_char('\n');
1208 			return -1;
1209 		}
1210 		ICOMkeyer_send_char(c);
1211 		put_echo_char(c);
1212 		return 0;
1213 	}
1214 
1215 	if (progdefaults.use_YAESUkeying) {
1216 		if (c == GET_TX_CHAR_ETX || stopflag) {
1217 			stopflag = false;
1218 			put_echo_char('\n');
1219 			return -1;
1220 		}
1221 		FTkeyer_send_char(c);
1222 		put_echo_char(c);
1223 		return 0;
1224 	}
1225 
1226 	if (c == GET_TX_CHAR_ETX || stopflag) {
1227 		stopflag = false;
1228 		put_echo_char('\n');
1229 		first_char = true;
1230 		return -1;
1231 	}
1232 
1233 	acc_symbols = 0;
1234 
1235 	if (CW_KEYLINE_isopen ||
1236 		progdefaults.CW_KEYLINE_on_cat_port ||
1237 		progdefaults.CW_KEYLINE_on_ptt_port)
1238 		send_CW(c);
1239 //	else {
1240 	send_ch(c);
1241 	first_char = false;
1242 //	}
1243 	char_samples = acc_symbols;
1244 
1245 	return 0;
1246 }
1247 
incWPM()1248 void cw::incWPM()
1249 {
1250 
1251 	if (usedefaultWPM) return;
1252 	if (progdefaults.CWspeed < progdefaults.CWupperlimit) {
1253 		progdefaults.CWspeed++;
1254 		sync_parameters();
1255 		set_CWwpm();
1256 		update_Status();
1257 	}
1258 }
1259 
decWPM()1260 void cw::decWPM()
1261 {
1262 
1263 	if (usedefaultWPM) return;
1264 	if (progdefaults.CWspeed > progdefaults.CWlowerlimit) {
1265 		progdefaults.CWspeed--;
1266 		set_CWwpm();
1267 		sync_parameters();
1268 		update_Status();
1269 	}
1270 }
1271 
toggleWPM()1272 void cw::toggleWPM()
1273 {
1274 	usedefaultWPM = !usedefaultWPM;
1275 	if (usedefaultWPM) {
1276 		wpm = progdefaults.CWspeed;
1277 		progdefaults.CWspeed = progdefaults.defCWspeed;
1278 	} else {
1279 		progdefaults.CWspeed = wpm;
1280 	}
1281 	sync_parameters();
1282 	update_Status();
1283 }
1284 
1285 // ---------------------------------------------------------------------
1286 // CW output on DTR/RTS signal lines
1287 //----------------------------------------------------------------------
1288 
1289 Cserial CW_KEYLINE_serial;
1290 bool CW_KEYLINE_isopen = false;
1291 
open_CW_KEYLINE()1292 int open_CW_KEYLINE()
1293 {
1294 	CW_KEYLINE_serial.Device(progdefaults.CW_KEYLINE_serial_port_name);
1295 	CW_KEYLINE_serial.Baud(progdefaults.BaudRate(9));
1296 	CW_KEYLINE_serial.RTS(false);
1297 	CW_KEYLINE_serial.DTR(false);
1298 	CW_KEYLINE_serial.RTSptt(false);
1299 	CW_KEYLINE_serial.DTRptt(false);
1300 	CW_KEYLINE_serial.RestoreTIO(true);
1301 	CW_KEYLINE_serial.RTSCTS(false);
1302 	CW_KEYLINE_serial.Stopbits(1);
1303 
1304 	LOG_VERBOSE("\n\
1305 CW Keyline Serial port parameters:\n\
1306 device	 : %s\n\
1307 baudrate   : %d\n\
1308 stopbits   : %d\n\
1309 initial rts: %+d\n\
1310 initial dtr: %+d\n\
1311 restore tio: %c\n\
1312 flowcontrol: %c\n",
1313 		CW_KEYLINE_serial.Device().c_str(),
1314 		CW_KEYLINE_serial.Baud(),
1315 		CW_KEYLINE_serial.Stopbits(),
1316 		(CW_KEYLINE_serial.RTS() ? +12 : -12),
1317 		(CW_KEYLINE_serial.DTR() ? +12 : -12),
1318 		(CW_KEYLINE_serial.RestoreTIO() ? 'T' : 'F'),
1319 		(CW_KEYLINE_serial.RTSCTS() ? 'T' : 'F')
1320 	);
1321 
1322 	if (CW_KEYLINE_serial.OpenPort() == false) {
1323 		LOG_ERROR("Cannot open serial port %s", CW_KEYLINE_serial.Device().c_str());
1324 		CW_KEYLINE_isopen = false;
1325 		return 0;
1326 	}
1327 	CW_KEYLINE_isopen = true;
1328 	return 1;
1329 }
1330 
close_CW_KEYLINE()1331 void close_CW_KEYLINE()
1332 {
1333 	CW_KEYLINE_serial.ClosePort();
1334 	CW_KEYLINE_isopen = false;
1335 }
1336 
1337 //----------------------------------------------------------------------
1338 #include <queue>
1339 
1340 static pthread_t       cwio_pthread;
1341 static pthread_cond_t  cwio_cond;
1342 static pthread_mutex_t cwio_mutex = PTHREAD_MUTEX_INITIALIZER;
1343 static pthread_mutex_t fifo_mutex = PTHREAD_MUTEX_INITIALIZER;
1344 pthread_mutex_t        cwio_ptt_mutex = PTHREAD_MUTEX_INITIALIZER;
1345 
1346 static bool cwio_thread_running   = false;
1347 static bool cwio_terminate_flag   = false;
1348 static bool cwio_calibrate_flag   = false;
1349 
1350 //----------------------------------------------------------------------
1351 
1352 static int cwio_ch;
1353 static cMorse *cwio_morse = 0;
1354 static queue<int> fifo;
1355 static std::string cwio_prosigns;
1356 
1357 //----------------------------------------------------------------------
1358 // CW output using flrig cwio calls
1359 //----------------------------------------------------------------------
1360 static char lastcwiochar = 0;
flrig_cwio_send(char c)1361 void flrig_cwio_send(char c)
1362 {
1363 	if (cwio_morse == 0) {
1364 		cwio_morse = new cMorse;
1365 		cwio_morse->init();
1366 	}
1367 
1368 	if (c == '[') {
1369 		flrig_cwio_ptt(1);
1370 		return;
1371 	}
1372 	if (c == ']') {
1373 		flrig_cwio_ptt(0);
1374 		return;
1375 	}
1376 	std::string s = " ";
1377 	s[0] = c;
1378 	flrig_cwio_send_text(s);
1379 
1380 	int tc = 1200 / progdefaults.CWspeed;
1381 	if (progdefaults.CWusefarnsworth && (progdefaults.CWspeed > progdefaults.CWfarnsworth))
1382 		tc = 1200 / progdefaults.CWfarnsworth;
1383 
1384 	if (c == ' ') {
1385 		if (lastcwiochar == ' ')
1386 			tc *= 7;
1387 		else
1388 		tc *= 5;
1389 	} else
1390 		tc *= (cwio_morse->tx_length(c));
1391 	lastcwiochar = c;
1392 	MilliSleep(tc);
1393 }
1394 
1395 //----------------------------------------------------------------------
1396 
cwio_key(int on)1397 void cwio_key(int on)
1398 {
1399 	if (CW_KEYLINE_isopen ||
1400 		progdefaults.CW_KEYLINE_on_cat_port ||
1401 		progdefaults.CW_KEYLINE_on_ptt_port) {
1402 		Cserial *ser = &CW_KEYLINE_serial;
1403 		if (progdefaults.CW_KEYLINE_on_cat_port)
1404 			ser = &rigio;
1405 		else if (progdefaults.CW_KEYLINE_on_ptt_port)
1406 			ser = &push2talk->serPort;
1407 		switch (progdefaults.CW_KEYLINE) {
1408 			case 0: break;
1409 			case 1: ser->SetRTS(on); break;
1410 			case 2: ser->SetDTR(on); break;
1411 		}
1412 	}
1413 }
1414 
cwio_ptt(int on)1415 void cwio_ptt(int on)
1416 {
1417 	if (CW_KEYLINE_isopen ||
1418 		progdefaults.CW_KEYLINE_on_cat_port ||
1419 		progdefaults.CW_KEYLINE_on_ptt_port) {
1420 		Cserial *ser = &CW_KEYLINE_serial;
1421 		if (progdefaults.CW_KEYLINE_on_cat_port)
1422 			ser = &rigio;
1423 		else if (progdefaults.CW_KEYLINE_on_ptt_port)
1424 			ser = &push2talk->serPort;
1425 		switch (progdefaults.PTT_KEYLINE) {
1426 			case 0: break;
1427 			case 1: ser->SetRTS(on); break;
1428 			case 2: ser->SetDTR(on); break;
1429 		}
1430 	}
1431 }
1432 
1433 #define cwio_bit(bit, len) {\
1434 switch (progdefaults.CW_KEYLINE) {\
1435 case 0: break;\
1436 case 1: ser->SetRTS(bit); break;\
1437 case 2: ser->SetDTR(bit); break;\
1438 }\
1439 MilliSleep(len);}
1440 
send_cwio(int c)1441 void send_cwio(int c)
1442 {
1443 	if (c == GET_TX_CHAR_NODATA || c == 0x0d) {
1444 		return;
1445 	}
1446 
1447 	float tc = 1200.0 / progdefaults.CWspeed;
1448 	if (tc <= 0) tc = 1;
1449 	float ta = 0.0;
1450 	float tch = 3 * tc, twd = 4 * tc;
1451 
1452 	Cserial *ser = &CW_KEYLINE_serial;
1453 	if (progdefaults.CW_KEYLINE_on_cat_port)
1454 		ser = &rigio;
1455 	else if (progdefaults.CW_KEYLINE_on_ptt_port)
1456 		ser = &push2talk->serPort;
1457 
1458 	if (progdefaults.CWusefarnsworth && (progdefaults.CWspeed > progdefaults.CWfarnsworth)) {
1459 		ta = 60000.0 / progdefaults.CWfarnsworth - 37200 / progdefaults.CWspeed;
1460 		tch = 3 * ta / 19;
1461 		twd = 4 * ta / 19;
1462 	}
1463 
1464 	if (progdefaults.cwio_comp && progdefaults.cwio_comp < tc) {
1465 		tc -= progdefaults.cwio_comp;
1466 		tch -= progdefaults.cwio_comp;
1467 		twd -= progdefaults.cwio_comp;
1468 	}
1469 
1470 	if (c == 0x0a) c = ' ';
1471 
1472 	if (c == ' ') {
1473 		cwio_bit(0, twd);
1474 		return;
1475 	}
1476 
1477 	string code;
1478 	code = cwio_morse->tx_lookup(c);
1479 	if (!code.length()) {
1480 		return;
1481 	}
1482 
1483 	guard_lock lk(&cwio_ptt_mutex);
1484 
1485 	for (size_t n = 0; n < code.length(); n++) {
1486 		if (code[n] == '.') {
1487 			cwio_bit(1, tc);
1488 		} else {
1489 			cwio_bit(1, 3*tc);
1490 		}
1491 		if (n < code.length() -1) {
1492 			cwio_bit(0, tc);
1493 		} else {
1494 			cwio_bit(0, tch);
1495 		}
1496 	}
1497 
1498 }
1499 
1500 unsigned long start_time = 0L;
1501 unsigned long end_time = 0L;
1502 int testwpm = 20;
1503 int testwords = 10;
1504 
cwio_calibrate_finished(void *)1505 void cwio_calibrate_finished(void *)
1506 {
1507 	double ratio = (1200.0 * 50.0 * testwords / progdefaults.CWspeed) / (end_time - start_time);
1508 	int comp = round(testwpm * (1.0 - ratio));
1509 	progdefaults.cwio_comp = comp;
1510 	cnt_cwio_comp->value(comp);
1511 	btn_cw_dtr_calibrate->value(0);
1512 
1513 	LOG_INFO("\n\
1514 xmt %d words at %.0f wpm : %0.3f secs\n\
1515 compensation ratio:  %f\n\
1516 compensation (msec): %d",
1517 		testwords,
1518 		progdefaults.CWspeed,
1519 		(end_time - start_time) / 1000.0,
1520 		ratio,
1521 		comp);
1522 }
1523 
cwio_calibrate()1524 void cwio_calibrate()
1525 {
1526 	std::string paris = "PARIS ";
1527 	bool farnsworth = progdefaults.CWusefarnsworth;
1528 	progdefaults.CWusefarnsworth = false;
1529 	int comp = progdefaults.cwio_comp;
1530 	progdefaults.cwio_comp = 0;
1531 
1532 	guard_lock lk(&fifo_mutex);
1533 
1534 	start_time = zmsec();
1535 	for (int i = 0; i < testwords; i++)
1536 		for (size_t n = 0; n < paris.length(); n++)
1537 			send_cwio(paris[n]);
1538 	end_time = zmsec();
1539 
1540 	progdefaults.CWusefarnsworth = farnsworth;
1541 	progdefaults.cwio_comp = comp;
1542 
1543 	Fl::awake(cwio_calibrate_finished);
1544 }
1545 
cwio_loop(void * args)1546 static void * cwio_loop(void *args)
1547 {
1548 	SET_THREAD_ID(CWIO_TID);
1549 
1550 	cwio_thread_running   = true;
1551 	cwio_terminate_flag   = false;
1552 
1553 	while(1) {
1554 		pthread_mutex_lock(&cwio_mutex);
1555 		pthread_cond_wait(&cwio_cond, &cwio_mutex);
1556 		pthread_mutex_unlock(&cwio_mutex);
1557 
1558 		if (cwio_terminate_flag)
1559 			break;
1560 		if (cwio_calibrate_flag) {
1561 			cwio_calibrate();
1562 			cwio_calibrate_flag = false;
1563 		}
1564 		while (!fifo.empty()) {
1565 			{
1566 				guard_lock lk(&fifo_mutex);
1567 				cwio_ch = fifo.front();
1568 				fifo.pop();
1569 			}
1570 			send_cwio(cwio_ch);
1571 		}
1572 	}
1573 	return (void *)0;
1574 }
1575 
calibrate_cwio()1576 void calibrate_cwio()
1577 {
1578 	if (!cwio_thread_running)
1579 		start_cwio_thread();
1580 
1581 	if (cwio_morse == 0) {
1582 		cwio_morse = new cMorse;
1583 		cwio_morse->init();
1584 	}
1585 
1586 	cwio_calibrate_flag = true;
1587 	pthread_cond_signal(&cwio_cond);
1588 }
1589 
stop_cwio_thread(void)1590 void stop_cwio_thread(void)
1591 {
1592 	if(!cwio_thread_running) return;
1593 
1594 	cwio_terminate_flag = true;
1595 	pthread_cond_signal(&cwio_cond);
1596 
1597 	MilliSleep(10);
1598 
1599 	pthread_join(cwio_pthread, NULL);
1600 
1601 	pthread_mutex_destroy(&cwio_mutex);
1602 	pthread_cond_destroy(&cwio_cond);
1603 
1604 	memset((void *) &cwio_pthread, 0, sizeof(cwio_pthread));
1605 	memset((void *) &cwio_mutex,   0, sizeof(cwio_mutex));
1606 
1607 	cwio_thread_running   = false;
1608 	cwio_terminate_flag   = false;
1609 
1610 	delete cwio_morse;
1611 	cwio_morse = 0;
1612 }
1613 
start_cwio_thread(void)1614 void start_cwio_thread(void)
1615 {
1616 	if (cwio_thread_running) return;
1617 
1618 	memset((void *) &cwio_pthread, 0, sizeof(cwio_pthread));
1619 	memset((void *) &cwio_mutex,   0, sizeof(cwio_mutex));
1620 	memset((void *) &cwio_cond,    0, sizeof(cwio_cond));
1621 
1622 	if(pthread_cond_init(&cwio_cond, NULL)) {
1623 		LOG_ERROR("Alert thread create fail (pthread_cond_init)");
1624 		return;
1625 	}
1626 
1627 	if(pthread_mutex_init(&cwio_mutex, NULL)) {
1628 		LOG_ERROR("AUDIO_ALERT thread create fail (pthread_mutex_init)");
1629 		return;
1630 	}
1631 
1632 	if (pthread_create(&cwio_pthread, NULL, cwio_loop, NULL) < 0) {
1633 		pthread_mutex_destroy(&cwio_mutex);
1634 		LOG_ERROR("AUDIO_ALERT thread create fail (pthread_create)");
1635 	}
1636 
1637 	LOG_VERBOSE("started audio cwio thread");
1638 
1639 	MilliSleep(10); // Give the CPU time to set 'cwio_thread_running'
1640 }
1641 
send_CW(int c)1642 void cw::send_CW(int c)
1643 {
1644 	if (!cwio_thread_running)
1645 		start_cwio_thread();
1646 
1647 	if (cwio_morse == 0) {
1648 		cwio_morse = new cMorse;
1649 		cwio_morse->init();
1650 	}
1651 
1652 	if (cwio_prosigns != progdefaults.CW_prosigns) {
1653 		cwio_prosigns = progdefaults.CW_prosigns;
1654 		cwio_morse->init();
1655 	}
1656 
1657 	guard_lock lk(&fifo_mutex);
1658 	fifo.push(c);
1659 
1660 	pthread_cond_signal(&cwio_cond);
1661 
1662 }
1663 
1664 unsigned long CAT_start_time = 0L;
1665 unsigned long CAT_end_time = 0L;
1666 
CAT_keying_calibrate_finished(void *)1667 void CAT_keying_calibrate_finished(void *)
1668 {
1669 	int comp = (CAT_end_time - CAT_start_time - 60000);
1670 
1671 	progdefaults.CATkeying_compensation = comp;
1672 
1673 	out_CATkeying_compensation->value(comp / 1000.0);
1674 
1675 	char info[1000];
1676 	snprintf(info, sizeof(info),
1677 		"Speed test: %.0f wpm : %0.2f secs",
1678 		progdefaults.CWspeed,
1679 		(CAT_end_time - CAT_start_time) / 1000.0);
1680 	LOG_INFO("\n%s", info);
1681 
1682 }
1683 
1684 static pthread_t       CW_keying_pthread;
1685 bool   CW_CAT_thread_running = false;
1686 
do_CAT_keying_calibrate(void * args)1687 void *do_CAT_keying_calibrate(void *args)
1688 {
1689 	CW_CAT_thread_running = true;
1690 
1691 	if (progdefaults.use_KNWDkeying || progdefaults.use_ELCTkeying)
1692 		set_KYkeyer();
1693 	else if (progdefaults.use_ICOMkeying)
1694 		set_ICOMkeyer();
1695 	else if (progdefaults.use_YAESUkeying)
1696 		set_FTkeyer();
1697 
1698 	std::string paris = "PARIS ";
1699 	bool farnsworth = progdefaults.CWusefarnsworth;
1700 	progdefaults.CWusefarnsworth = false;
1701 	progdefaults.CATkeying_compensation = 0;
1702 
1703 	CAT_start_time = zmsec();
1704 	for (int i = 0; i < progdefaults.CWspeed; i++) {
1705 		for (size_t n = 0; n < paris.length(); n++) {
1706 			if (progdefaults.use_KNWDkeying || progdefaults.use_ELCTkeying)
1707 				KYkeyer_send_char(paris[n]);
1708 			else if (progdefaults.use_ICOMkeying)
1709 				ICOMkeyer_send_char(paris[n]);
1710 			else if (progdefaults.use_YAESUkeying)
1711 				FTkeyer_send_char(paris[n]);
1712 		}
1713 	}
1714 	CAT_end_time = zmsec();
1715 
1716 	progdefaults.CWusefarnsworth = farnsworth;
1717 
1718 	Fl::awake(CAT_keying_calibrate_finished);
1719 	CW_CAT_thread_running = false;
1720 	return NULL;
1721 }
1722 
CAT_keying_calibrate()1723 void CAT_keying_calibrate()
1724 {
1725 	if (CW_CAT_thread_running) return;
1726 
1727 	if (pthread_create(&CW_keying_pthread, NULL, do_CAT_keying_calibrate, NULL) < 0) {
1728 		LOG_ERROR("CW CAT calibration thread create failed");
1729 		return;
1730 	}
1731 
1732 	LOG_VERBOSE("started CW CAT calibration thread");
1733 
1734 	MilliSleep(10);
1735 
1736 }
1737 
CAT_keying_test_finished(void *)1738 void CAT_keying_test_finished(void *)
1739 {
1740 	int comp = (CAT_end_time - CAT_start_time - 60000);
1741 	out_CATkeying_test_result->value(comp / 1000.0);
1742 }
1743 
do_CAT_keying_test(void * args)1744 void *do_CAT_keying_test(void *args)
1745 {
1746 	CW_CAT_thread_running = true;
1747 
1748 	if (progdefaults.use_KNWDkeying || progdefaults.use_ELCTkeying)
1749 		set_KYkeyer();
1750 	else if (progdefaults.use_ICOMkeying)
1751 		set_ICOMkeyer();
1752 	else if (progdefaults.use_YAESUkeying)
1753 		set_FTkeyer();
1754 
1755 	std::string paris = "PARIS ";
1756 	bool farnsworth = progdefaults.CWusefarnsworth;
1757 	progdefaults.CWusefarnsworth = false;
1758 
1759 	CAT_start_time = zmsec();
1760 	for (int i = 0; i < progdefaults.CWspeed; i++) {
1761 		for (size_t n = 0; n < paris.length(); n++) {
1762 			if (progdefaults.use_KNWDkeying || progdefaults.use_ELCTkeying)
1763 				KYkeyer_send_char(paris[n]);
1764 			else if (progdefaults.use_ICOMkeying)
1765 				ICOMkeyer_send_char(paris[n]);
1766 			else if (progdefaults.use_YAESUkeying)
1767 				FTkeyer_send_char(paris[n]);
1768 		}
1769 	}
1770 	CAT_end_time = zmsec();
1771 
1772 	progdefaults.CWusefarnsworth = farnsworth;
1773 
1774 	Fl::awake(CAT_keying_test_finished);
1775 	CW_CAT_thread_running = false;
1776 	return NULL;
1777 }
1778 
CAT_keying_test()1779 void CAT_keying_test()
1780 {
1781 	if (CW_CAT_thread_running) return;
1782 
1783 	if (pthread_create(&CW_keying_pthread, NULL, do_CAT_keying_test, NULL) < 0) {
1784 		LOG_ERROR("CW CAT calibration thread create failed");
1785 		return;
1786 	}
1787 
1788 	LOG_VERBOSE("started CW CAT calibration thread");
1789 
1790 	MilliSleep(10);
1791 
1792 }
1793