1 // ----------------------------------------------------------------------------
2 // rtty.cxx  --  RTTY modem
3 //
4 // Copyright (C) 2012
5 //		Dave Freese, W1HKJ
6 //		Stefan Fendt, DL1SMF
7 //
8 // This file is part of fldigi.
9 //
10 // This code bears some resemblance to code contained in gmfsk from which
11 // it originated.  Much has been changed, but credit should still be
12 // given to Tomi Manninen (oh2bns@sral.fi), who so graciously distributed
13 // his gmfsk modem under the GPL.
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 #include <config.h>
30 #include <iostream>
31 #include <fstream>
32 
33 using namespace std;
34 
35 //#include "rtty.h"
36 #include "view_rtty.h"
37 #include "fl_digi.h"
38 #include "digiscope.h"
39 #include "misc.h"
40 #include "waterfall.h"
41 #include "confdialog.h"
42 #include "configuration.h"
43 #include "status.h"
44 #include "digiscope.h"
45 #include "trx.h"
46 #include "debug.h"
47 #include "synop.h"
48 #include "main.h"
49 #include "modem.h"
50 
51 #include "threads.h"
52 
53 #include "rtty.h"
54 
55 #define FILTER_DEBUG 0
56 
57 #define SHAPER_BAUD 150
58 
59 //void start_fsk_thread();
60 //void stop_fsk_thread();
61 
62 //=====================================================================
63 // Baudot support
64 //=====================================================================
65 
66 static char letters[32] = {
67 	'\0',	'E',	'\n',	'A',	' ',	'S',	'I',	'U',
68 	'\r',	'D',	'R',	'J',	'N',	'F',	'C',	'K',
69 	'T',	'Z',	'L',	'W',	'H',	'Y',	'P',	'Q',
70 	'O',	'B',	'G',	' ',	'M',	'X',	'V',	' '
71 };
72 
73 /*
74  * U.S. version of the figures case.
75  */
76 static char figures[32] = {
77 	'\0',	'3',	'\n',	'-',	' ',	'\a',	'8',	'7',
78 	'\r',	'$',	'4',	'\'',	',',	'!',	':',	'(',
79 	'5',	'"',	')',	'2',	'#',	'6',	'0',	'1',
80 	'9',	'?',	'&',	' ',	'.',	'/',	';',	' '
81 };
82 
83 int dspcnt = 0;
84 
85 static char msg1[20];
86 
87 const double	rtty::SHIFT[] = {23, 85, 160, 170, 182, 200, 240, 350, 425, 850};
88 // FILTLEN must be same size as BAUD
89 const double	rtty::BAUD[]  = {45, 45.45, 50, 56, 75, 100, 110, 150, 200, 300};
90 const int		rtty::FILTLEN[] = { 512, 512, 512, 512, 512, 512, 512, 256, 128, 64};
91 const int		rtty::BITS[]  = {5, 7, 8};
92 const int		rtty::numshifts = (int)(sizeof(SHIFT) / sizeof(*SHIFT));
93 const int		rtty::numbauds = (int)(sizeof(BAUD) / sizeof(*BAUD));
94 
tx_init()95 void rtty::tx_init()
96 {
97 	phaseacc = 0;
98 	preamble = true;
99 	videoText();
100 
101 	symbols = 0;
102 	acc_symbols = 0;
103 	ovhd_symbols = 0;
104 }
105 
106 // Customizes output of Synop decoded data.
107 struct rtty_callback : public synop_callback {
108 	// Callback for writing decoded synop messages.
printrtty_callback109 	void print(const char * str, size_t nb, bool bold ) const {
110 		// Could choose: FTextBase::CTRL,XMIT,RECV
111 		int style = bold ? FTextBase::XMIT : FTextBase::RECV;
112 		for( size_t i = 0; i < nb; ++i ) {
113 			unsigned char c = str[i];
114 			put_rx_char(progdefaults.rx_lowercase ? tolower(c) : c, style );
115 		}
116 	}
117 	// Should we log new Synop messages to the current Adif log file ?
log_adifrtty_callback118 	bool log_adif(void) const { return progdefaults.SynopAdifDecoding ;}
119 	// Should we log new Synop messages to KML file ?
log_kmlrtty_callback120 	bool log_kml(void) const { return progdefaults.SynopKmlDecoding ;}
121 
interleavedrtty_callback122 	bool interleaved(void) const { return progdefaults.SynopInterleaved ;}
123 };
124 
rx_init()125 void rtty::rx_init()
126 {
127 	rxstate = RTTY_RX_STATE_IDLE;
128 	rxmode = LETTERS;
129 	phaseacc = 0;
130 	FSKphaseacc = 0;
131 
132 	for (int i = 0; i < MAXBITS; i++ ) bit_buf[i] = 0.0;
133 
134 	mark_phase = 0;
135 	space_phase = 0;
136 	xy_phase = 0.0;
137 
138 	mark_mag = 0;
139 	space_mag = 0;
140 	mark_env = 0;
141 	space_env = 0;
142 
143 	inp_ptr = 0;
144 
145 	lastchar = 0;
146 
147 	// Synop file is reloaded each time we enter this modem. Ideally do that when the file is changed.
148 	static bool wmo_loaded = false ;
149 	if( wmo_loaded == false ) {
150 		wmo_loaded = true ;
151 		SynopDB::Init(PKGDATADIR);
152 	}
153 	/// Used by weather reports decoding.
154 	synop::setup<rtty_callback>();
155 	synop::instance()->init();
156 }
157 
init()158 void rtty::init()
159 {
160 	bool wfrev = wf->Reverse();
161 	bool wfsb = wf->USB();
162 	// Probably not necessary because similar to modem::set_reverse
163 	reverse = wfrev ^ !wfsb;
164 	stopflag = false;
165 
166 	if (progdefaults.StartAtSweetSpot)
167 		set_freq(progdefaults.RTTYsweetspot);
168 	else if (progStatus.carrier != 0) {
169 		set_freq(progStatus.carrier);
170 #if !BENCHMARK_MODE
171 		progStatus.carrier = 0;
172 #endif
173 	} else
174 		set_freq(wf->Carrier());
175 
176 	rx_init();
177 	put_MODEstatus(mode);
178 	if ((rtty_baud - (int)rtty_baud) == 0)
179 		snprintf(msg1, sizeof(msg1), "%-3.0f/%-4.0f", rtty_baud, rtty_shift);
180 	else
181 		snprintf(msg1, sizeof(msg1), "%-4.2f/%-4.0f", rtty_baud, rtty_shift);
182 	put_Status1(msg1);
183 	if (progdefaults.PreferXhairScope)
184 		set_scope_mode(Digiscope::XHAIRS);
185 	else
186 		set_scope_mode(Digiscope::RTTY);
187 	for (int i = 0; i < MAXPIPE; i++) mark_history[i] = space_history[i] = cmplx(0,0);
188 
189 	lastchar = 0;
190 }
191 
~rtty()192 rtty::~rtty()
193 {
194 	if (rttyviewer) delete rttyviewer;
195 
196 	if (mark_filt) delete mark_filt;
197 	if (space_filt) delete space_filt;
198 	if (pipe) delete [] pipe;
199 	if (dsppipe) delete [] dsppipe;
200 	if (bits) delete bits;
201 	delete m_Osc1;
202 	delete m_Osc2;
203 	delete m_SymShaper1;
204 	delete m_SymShaper2;
205 
206 // EXPERIMENTAL FSK DTR/RTS
207 //	stop_fsk_thread();
208 }
209 
reset_filters()210 void rtty::reset_filters()
211 {
212 	delete mark_filt;
213 	mark_filt = new fftfilt(rtty_baud/samplerate, filter_length);
214 	mark_filt->rtty_filter(rtty_baud/samplerate);
215 	delete space_filt;
216 	space_filt = new fftfilt(rtty_baud/samplerate, filter_length);
217 	space_filt->rtty_filter(rtty_baud/samplerate);
218 }
219 
restart()220 void rtty::restart()
221 {
222 	double stl;
223 
224 	rtty_shift = shift = (progdefaults.rtty_shift < numshifts ?
225 				  SHIFT[progdefaults.rtty_shift] : progdefaults.rtty_custom_shift);
226 	if (progdefaults.rtty_baud > numbauds - 1) progdefaults.rtty_baud = numbauds - 1;
227 	rtty_baud = BAUD[progdefaults.rtty_baud];
228 	filter_length = FILTLEN[progdefaults.rtty_baud];
229 
230 	nbits = rtty_bits = BITS[progdefaults.rtty_bits];
231 	if (rtty_bits == 5)
232 		rtty_parity = RTTY_PARITY_NONE;
233 	else
234 		switch (progdefaults.rtty_parity) {
235 			case 0 : rtty_parity = RTTY_PARITY_NONE; break;
236 			case 1 : rtty_parity = RTTY_PARITY_EVEN; break;
237 			case 2 : rtty_parity = RTTY_PARITY_ODD; break;
238 			case 3 : rtty_parity = RTTY_PARITY_ZERO; break;
239 			case 4 : rtty_parity = RTTY_PARITY_ONE; break;
240 			default : rtty_parity = RTTY_PARITY_NONE; break;
241 		}
242 	// (exists below already)  rtty_stop = progdefaults.rtty_stop;
243 
244 	txmode = LETTERS;
245 	rxmode = LETTERS;
246 	symbollen = (int) (samplerate / rtty_baud + 0.5);
247 // part of an EXPERIMENTAL FSK implementation
248 //	bitlen = 1000.0 / rtty_baud;  // bit length in milliseconds
249 	set_bandwidth(shift);
250 
251 	rtty_BW = progdefaults.RTTY_BW = rtty_baud * 2;
252 
253 	wf->redraw_marker();
254 
255 	reset_filters();
256 
257 	if (bits)
258 		bits->setLength(symbollen / 8);//2);
259 	else
260 		bits = new Cmovavg(symbollen / 8);//2);
261 	mark_noise = space_noise = 0;
262 	bit = nubit = true;
263 
264 // stop length = 1, 1.5 or 2 bits
265 	rtty_stop = progdefaults.rtty_stop;
266 	if (rtty_stop == 0) stl = 1.0;
267 	else if (rtty_stop == 1) stl = 1.5;
268 	else stl = 2.0;
269 	stoplen = (int) (stl * samplerate / rtty_baud + 0.5);
270 	freqerr = 0.0;
271 	pipeptr = 0;
272 
273 	for (int i = 0; i < MAXBITS; i++ ) bit_buf[i] = 0.0;
274 
275 	metric = 0.0;
276 
277 	if ((rtty_baud - (int)rtty_baud) == 0)
278 		snprintf(msg1, sizeof(msg1), "%-3.0f/%-4.0f", rtty_baud, rtty_shift);
279 	else
280 		snprintf(msg1, sizeof(msg1), "%-4.2f/%-4.0f", rtty_baud, rtty_shift);
281 	put_Status1(msg1);
282 	put_MODEstatus(mode);
283 	for (int i = 0; i < MAXPIPE; i++)
284 		QI[i] = cmplx(0.0, 0.0);
285 	sigpwr = 0.0;
286 	noisepwr = 0.0;
287 	sigsearch = 0;
288 	dspcnt = 2*(nbits + 2);
289 
290 	clear_zdata = true;
291 
292 	// restart symbol-rtty_shaper
293 	m_SymShaper1->Preset(rtty_baud, samplerate);
294 	m_SymShaper2->Preset(rtty_baud, samplerate);
295 
296 	mark_phase = 0;
297 	space_phase = 0;
298 	xy_phase = 0.0;
299 
300 	mark_mag = 0;
301 	space_mag = 0;
302 	mark_env = 0;
303 	space_env = 0;
304 
305 	inp_ptr = 0;
306 
307 	for (int i = 0; i < MAXPIPE; i++) mark_history[i] = space_history[i] = cmplx(0,0);
308 
309 //	if (::rttyviewer) ::rttyviewer->restart();
310 	if (rttyviewer) rttyviewer->restart();
311 
312 	progStatus.rtty_filter_changed = false;
313 
314 }
315 
rtty(trx_mode tty_mode)316 rtty::rtty(trx_mode tty_mode)
317 {
318 	cap |= CAP_AFC | CAP_REV;
319 
320 	mode = tty_mode;
321 
322 	samplerate = RTTY_SampleRate;
323 
324 	mark_filt = (fftfilt *)0;
325 	space_filt = (fftfilt *)0;
326 
327 	bits = (Cmovavg *)0;
328 
329 	pipe = new double[MAXPIPE];
330 	dsppipe = new double [MAXPIPE];
331 
332 //	if (::rttyviewer == 0) ::rttyviewer = new view_rtty(mode);
333 
334 	rttyviewer = new view_rtty(mode);
335 
336 	m_Osc1 = new Oscillator( samplerate );
337 	m_Osc2 = new Oscillator( samplerate );
338 
339 	m_SymShaper1 = new SymbolShaper( 45, samplerate );
340 	m_SymShaper2 = new SymbolShaper( 45, samplerate );
341 
342 	restart();
343 
344 // EXPERIMENT FSK on DTR/RTS
345 //	start_fsk_thread();
346 }
347 
Update_syncscope()348 void rtty::Update_syncscope()
349 {
350 	int j;
351 	for (int i = 0; i < symbollen; i++) {
352 		j = pipeptr - i;
353 		if (j < 0) j += symbollen;
354 		dsppipe[i] = pipe[j];
355 	}
356 	set_scope(dsppipe, symbollen, false);
357 }
358 
Clear_syncscope()359 void rtty::Clear_syncscope()
360 {
361 	set_scope(0, 0, false);
362 }
363 
mixer(double & phase,double f,cmplx in)364 cmplx rtty::mixer(double &phase, double f, cmplx in)
365 {
366 	cmplx z = cmplx( cos(phase), sin(phase)) * in;
367 
368 	phase -= TWOPI * f / samplerate;
369 	if (phase < -TWOPI) phase += TWOPI;
370 
371 	return z;
372 }
373 
Bit_reverse(unsigned char in,int n)374 unsigned char rtty::Bit_reverse(unsigned char in, int n)
375 {
376 	unsigned char out = 0;
377 
378 	for (int i = 0; i < n; i++)
379 		out = (out << 1) | ((in >> i) & 1);
380 
381 	return out;
382 }
383 
rparity(int c)384 static int rparity(int c)
385 {
386 	int w = c;
387 	int p = 0;
388 	while (w) {
389 		p += (w & 1);
390 		w >>= 1;
391 	}
392 	return p & 1;
393 }
394 
rttyparity(unsigned int c,int nbits)395 int rttyparity(unsigned int c, int nbits)
396 {
397 	c &= (1 << nbits) - 1;
398 
399 	switch (progdefaults.rtty_parity) {
400 	default:
401 	case rtty::RTTY_PARITY_NONE:
402 		return 0;
403 
404 	case rtty::RTTY_PARITY_ODD:
405 		return rparity(c);
406 
407 	case rtty::RTTY_PARITY_EVEN:
408 		return !rparity(c);
409 
410 	case rtty::RTTY_PARITY_ZERO:
411 		return 0;
412 
413 	case rtty::RTTY_PARITY_ONE:
414 		return 1;
415 	}
416 }
417 
decode_char()418 int rtty::decode_char()
419 {
420 	unsigned int parbit, par, data;
421 
422 	parbit = (rxdata >> nbits) & 1;
423 	par = rttyparity(rxdata, nbits);
424 
425 	if (rtty_parity != RTTY_PARITY_NONE && parbit != par)
426 		return 0;
427 
428 	data = rxdata & ((1 << nbits) - 1);
429 
430 	if (nbits == 5)
431 		return baudot_dec(data);
432 
433 	return data;
434 }
435 
is_mark_space(int & correction)436 bool rtty::is_mark_space( int &correction)
437 {
438 	correction = 0;
439 // test for rough bit position
440 	if (bit_buf[0] && !bit_buf[symbollen-1]) {
441 // test for mark/space straddle point
442 		for (int i = 0; i < symbollen; i++)
443 			correction += bit_buf[i];
444 		if (abs(symbollen/2 - correction) < 6) // too small & bad signals are not decoded
445 			return true;
446 	}
447 	return false;
448 }
449 
is_mark()450 bool rtty::is_mark()
451 {
452 	return bit_buf[symbollen / 2];
453 }
454 
rx(bool bit)455 bool rtty::rx(bool bit) // original modified for probability test
456 {
457 	bool flag = false;
458 	unsigned char c = 0;
459 	int correction;
460 
461 	for (int i = 1; i < symbollen; i++) bit_buf[i-1] = bit_buf[i];
462 	bit_buf[symbollen - 1] = bit;
463 
464 	switch (rxstate) {
465 	case RTTY_RX_STATE_IDLE:
466 		if ( is_mark_space(correction)) {
467 			rxstate = RTTY_RX_STATE_START;
468 			counter = correction;
469 		}
470 		break;
471 	case RTTY_RX_STATE_START:
472 		if (--counter == 0) {
473 			if (!is_mark()) {
474 				rxstate = RTTY_RX_STATE_DATA;
475 				counter = symbollen;
476 				bitcntr = 0;
477 				rxdata = 0;
478 			} else {
479 				rxstate = RTTY_RX_STATE_IDLE;
480 			}
481 		}
482 		break;
483 	case RTTY_RX_STATE_DATA:
484 		if (--counter == 0) {
485 			rxdata |= is_mark() << bitcntr++;
486 			counter = symbollen;
487 		}
488 		if (bitcntr == nbits + (rtty_parity != RTTY_PARITY_NONE ? 1 : 0))
489 			rxstate = RTTY_RX_STATE_STOP;
490 		break;
491 	case RTTY_RX_STATE_STOP:
492 		if (--counter == 0) {
493 			if (is_mark()) {
494 				if ((metric >= progStatus.sldrSquelchValue && progStatus.sqlonoff) || !progStatus.sqlonoff) {
495 					c = decode_char();
496 					if( progdefaults.SynopAdifDecoding || progdefaults.SynopKmlDecoding ) {
497 						if (c != 0 && c != '\r')  {
498 							synop::instance()->add(c);
499 						} else {
500 							if( synop::instance()->enabled() )
501 								synop::instance()->flush(false);
502 							put_rx_char(c);
503 						}
504 					} else if ( c != 0 ) {
505 // supress <CR><CR> and <LF><LF> sequences
506 // these were observed during the RTTY contest 2/9/2013
507 						if (c == '\r' && lastchar == '\r');
508 						else if (c == '\n' && lastchar == '\n');
509 						else
510 							put_rx_char(progdefaults.rx_lowercase ? tolower(c) : c);
511 						lastchar = c;
512 					}
513 					flag = true;
514 				}
515 			}
516 			rxstate = RTTY_RX_STATE_IDLE;
517 		}
518 		break;
519 	default : break;
520 	}
521 
522 	return flag;
523 }
524 
525 char snrmsg[80];
Metric()526 void rtty::Metric()
527 {
528 	double delta = rtty_baud/8.0;
529 	double np = wf->powerDensity(frequency, delta) * 3000 / delta;
530 	double sp =
531 		wf->powerDensity(frequency - shift/2, delta) +
532 		wf->powerDensity(frequency + shift/2, delta) + 1e-10;
533 	double snr = 0;
534 
535 	sigpwr = decayavg( sigpwr, sp, sp > sigpwr ? 2 : 8);
536 	noisepwr = decayavg( noisepwr, np, 16 );
537 	snr = 10*log10(sigpwr / noisepwr);
538 
539 	snprintf(snrmsg, sizeof(snrmsg), "s/n %-3.0f dB", snr);
540 	put_Status2(snrmsg);
541 	metric = CLAMP((3000 / delta) * (sigpwr/noisepwr), 0.0, 100.0);
542 	display_metric(metric);
543 }
544 
searchDown()545 void rtty::searchDown()
546 {
547 	double srchfreq = frequency - shift -100;
548 	double minfreq = shift * 2 + 100;
549 	double spwrlo, spwrhi, npwr;
550 	while (srchfreq > minfreq) {
551 		spwrlo = wf->powerDensity(srchfreq - shift/2, 2*rtty_baud);
552 		spwrhi = wf->powerDensity(srchfreq + shift/2, 2*rtty_baud);
553 		npwr = wf->powerDensity(srchfreq + shift, 2*rtty_baud) + 1e-10;
554 		if ((spwrlo / npwr > 10.0) && (spwrhi / npwr > 10.0)) {
555 			frequency = srchfreq;
556 			set_freq(frequency);
557 			sigsearch = SIGSEARCH;
558 			break;
559 		}
560 		srchfreq -= 5.0;
561 	}
562 }
563 
searchUp()564 void rtty::searchUp()
565 {
566 	double srchfreq = frequency + shift +100;
567 	double maxfreq = IMAGE_WIDTH - shift * 2 - 100;
568 	double spwrhi, spwrlo, npwr;
569 	while (srchfreq < maxfreq) {
570 		spwrlo = wf->powerDensity(srchfreq - shift/2, 2*rtty_baud);
571 		spwrhi = wf->powerDensity(srchfreq + shift/2, 2*rtty_baud);
572 		npwr = wf->powerDensity(srchfreq - shift, 2*rtty_baud) + 1e-10;
573 		if ((spwrlo / npwr > 10.0) && (spwrhi / npwr > 10.0)) {
574 			frequency = srchfreq;
575 			set_freq(frequency);
576 			sigsearch = SIGSEARCH;
577 			break;
578 		}
579 		srchfreq += 5.0;
580 	}
581 }
582 
583 #if FILTER_DEBUG == 1
584 int snum = 0;
585 int mnum = 0;
586 #define ook(sp) \
587 { \
588 	value = sin(2.0*M_PI*( \
589 		(((sp / symbollen) % 2 == 0) ? (frequency + shift/2.0) : (frequency - shift/2.0))\
590 		/samplerate)*sp); \
591 }
592 
593 std::fstream ook_signal("ook_signal.csv", std::ios::out );
594 #endif
595 
rx_process(const double * buf,int len)596 int rtty::rx_process(const double *buf, int len)
597 {
598 	const double *buffer = buf;
599 	int length = len;
600 	static int showxy = symbollen;
601 
602 	cmplx z, zmark, zspace, *zp_mark, *zp_space;
603 
604 	int n_out = 0;
605 	static int bitcount = 5 * nbits * symbollen;
606 
607 	if ( !progdefaults.report_when_visible ||
608 		 dlgViewer->visible() || progStatus.show_channels )
609 		if (!bHistory && rttyviewer) rttyviewer->rx_process(buf, len);
610 
611 	if (progStatus.rtty_filter_changed) {
612 		progStatus.rtty_filter_changed = false;
613 		reset_filters();
614 	}
615 {
616 	reverse = wf->Reverse() ^ !wf->USB();
617 }
618 
619 	Metric();
620 #if FILTER_DEBUG == 1
621 double value;
622 #endif
623 	while (length-- > 0) {
624 
625 // Create analytic signal from sound card input samples
626 
627 #if FILTER_DEBUG == 1
628 if (snum < 2 * filter_length) {
629 	frequency = 1000.0;
630 	ook(snum);
631 	z = cmplx(value, value);
632 	ook_signal << snum << "," << z.real() << ",";
633 //	snum++;
634 } else {
635 	z = cmplx(*buffer, *buffer);
636 }
637 #else
638 	z = cmplx(*buffer, *buffer);
639 #endif
640 	buffer++;
641 
642 // Mix it with the audio carrier frequency to create two baseband signals
643 // mark and space are separated and processed independently
644 // lowpass Windowed Sinc - Overlap-Add convolution filters.
645 // The two fftfilt's are the same size and processed in sync
646 // therefore the mark and space filters will concurrently have the
647 // same size outputs available for further processing
648 
649 		zmark = mixer(mark_phase, frequency + shift/2.0, z);
650 		mark_filt->run(zmark, &zp_mark);
651 
652 		zspace = mixer(space_phase, frequency - shift/2.0, z);
653 		n_out = space_filt->run(zspace, &zp_space);
654 #if FILTER_DEBUG == 1
655 if (snum < 2 * filter_length) {
656 	ook_signal << abs(zmark) <<"\n";
657 	snum++;
658 }
659 #endif
660 		for (int i = 0; i < n_out; i++) {
661 
662 			mark_mag = abs(zp_mark[i]);
663 			mark_env = decayavg (mark_env, mark_mag,
664 						(mark_mag > mark_env) ? symbollen / 4 : symbollen * 16);
665 			mark_noise = decayavg (mark_noise, mark_mag,
666 						(mark_mag < mark_noise) ? symbollen / 4 : symbollen * 48);
667 			space_mag = abs(zp_space[i]);
668 			space_env = decayavg (space_env, space_mag,
669 						(space_mag > space_env) ? symbollen / 4 : symbollen * 16);
670 			space_noise = decayavg (space_noise, space_mag,
671 						(space_mag < space_noise) ? symbollen / 4 : symbollen * 48);
672 #if FILTER_DEBUG == 1
673 if (mnum < 2 * filter_length)
674 	ook_signal << ",,," << mnum++ + filter_length / 2 << "," << mark_mag << "," << space_mag << "\n";
675 #endif
676 			noise_floor = min(space_noise, mark_noise);
677 
678 // clipped if clipped decoder selected
679 			double mclipped = 0, sclipped = 0;
680 			mclipped = mark_mag > mark_env ? mark_env : mark_mag;
681 			sclipped = space_mag > space_env ? space_env : space_mag;
682 			if (mclipped < noise_floor) mclipped = noise_floor;
683 			if (sclipped < noise_floor) sclipped = noise_floor;
684 
685 			switch (progdefaults.rtty_cwi) {
686 				case 1 : // mark only decode
687 					space_env = sclipped = noise_floor;
688 					break;
689 				case 2: // space only decode
690 					mark_env = mclipped = noise_floor;
691 				default : ;
692 			}
693 
694 //			double v0, v1, v2, v3, v4, v5;
695 			double v3;
696 
697 // no ATC
698 //			v0 = mark_mag - space_mag;
699 // Linear ATC
700 //			v1 = mark_mag - space_mag - 0.5 * (mark_env - space_env);
701 // Clipped ATC
702 //			v2  = (mclipped - noise_floor) - (sclipped - noise_floor) - 0.5 * (
703 //					(mark_env - noise_floor) - (space_env - noise_floor));
704 // Optimal ATC
705 			v3  = (mclipped - noise_floor) * (mark_env - noise_floor) -
706 					(sclipped - noise_floor) * (space_env - noise_floor) - 0.25 * (
707 					(mark_env - noise_floor) * (mark_env - noise_floor) -
708 					(space_env - noise_floor) * (space_env - noise_floor));
709 // Kahn Squarer with Linear ATC
710 //			v4 =  (mark_mag - noise_floor) * (mark_mag - noise_floor) -
711 //					(space_mag - noise_floor) * (space_mag - noise_floor) - 0.25 * (
712 //					(mark_env - noise_floor) * (mark_env - noise_floor) -
713 //					(space_env - noise_floor) * (space_env - noise_floor));
714 // Kahn Squarer with Clipped ATC
715 //			v5 =  (mclipped - noise_floor) * (mclipped - noise_floor) -
716 //					(sclipped - noise_floor) * (sclipped - noise_floor) - 0.25 * (
717 //					(mark_env - noise_floor) * (mark_env - noise_floor) -
718 //					(space_env - noise_floor) * (space_env - noise_floor));
719 //				switch (progdefaults.rtty_demodulator) {
720 //			switch (2) { // Optimal ATC
721 //			case 0: // linear ATC
722 //				bit = v1 > 0;
723 //				break;
724 //			case 1: // clipped ATC
725 //				bit = v2 > 0;
726 //				break;
727 //			case 2: // optimal ATC
728 				bit = v3 > 0;
729 //				break;
730 //			case 3: // Kahn linear ATC
731 //				bit = v4 > 0;
732 //				break;
733 //			case 4: // Kahn clipped
734 //				bit = v5 > 0;
735 //				break;
736 //			case 5: // No ATC
737 //			default :
738 //				bit = v0 > 0;
739 //			}
740 
741 // XY scope signal generation
742 
743 			if (progdefaults.true_scope) {
744 //----------------------------------------------------------------------
745 // "true" scope implementation------------------------------------------
746 //----------------------------------------------------------------------
747 
748 // get the baseband-signal and...
749 				xy = cmplx(
750 						zp_mark[i].real() * cos(xy_phase) + zp_mark[i].imag() * sin(xy_phase),
751 						zp_space[i].real() * cos(xy_phase) + zp_space[i].imag() * sin(xy_phase) );
752 
753 // if mark-tone has a higher magnitude than the space-tone,
754 // further reduce the scope's space-amplitude and vice versa
755 // this makes the scope looking a little bit nicer, too...
756 // aka: less noisy...
757 				if( abs(zp_mark[i]) > abs(zp_space[i]) ) {
758 // note ox x complex lib does not support xy.real(double) or xy.imag(double)
759 					xy = cmplx( xy.real(),
760 								xy.imag() * abs(zp_space[i])/abs(zp_mark[i]) );
761 //					xy.imag() *= abs(zp_space[i])/abs(zp_mark[i]);
762 				} else {
763 					xy = cmplx( xy.real() / ( abs(zp_space[i])/abs(zp_mark[i]) ),
764 								xy.imag() );
765 //					xy.real() /= abs(zp_space[i])/abs(zp_mark[i]);
766 				}
767 
768 // now normalize the scope
769 				double const norm = 1.3*(abs(zp_mark [i]) + abs(zp_space[i]));
770 				xy /= norm;
771 
772 			} else {
773 //----------------------------------------------------------------------
774 // "ortho" scope implementation-----------------------------------------
775 //----------------------------------------------------------------------
776 // get magnitude of the baseband-signal
777 				if (bit)
778 					xy = cmplx( mark_mag * cos(xy_phase), space_noise * sin(xy_phase) / 2.0);
779 				else
780 					xy = cmplx( mark_noise * cos(xy_phase) / 2.0, space_mag * sin(xy_phase));
781 // now normalize the scope
782 				double const norm = (mark_env + space_env);
783 				xy /= norm;
784 			}
785 
786 // Rotate the scope x-y iaw frequency error.  Old scopes were not capable
787 // of this, but it should be very handy, so... who cares of realism anyways?
788 			double const rotate = 8 * TWOPI * freqerr / rtty_shift;
789 			xy = xy * cmplx(cos(rotate), sin(rotate));
790 
791 			QI[inp_ptr] = xy;
792 
793 // shift it to 128Hz(!) and not to it's original position.
794 // this makes it more pretty and does not remove it's other
795 // qualities. Reason is that this is a fraction of the used
796 // block-size.
797 			xy_phase += (TWOPI * (128.0 / samplerate));
798 // end XY signal generation
799 
800 			mark_history[inp_ptr] = zp_mark[i];
801 			space_history[inp_ptr] = zp_space[i];
802 
803 			inp_ptr = (inp_ptr + 1) % MAXPIPE;
804 
805 			if (dspcnt && (--dspcnt % (nbits + 2) == 0)) {
806 				pipe[pipeptr] = bit - 0.5; //testbit - 0.5;
807 				pipeptr = (pipeptr + 1) % symbollen;
808 			}
809 
810 // detect TTY signal transitions
811 // rx(...) returns true if valid TTY bit stream detected
812 // either character or idle signal
813 			if ( rx( reverse ? !bit : bit ) ) {
814 				dspcnt = symbollen * (nbits + 2);
815 				if (!bHighSpeed) Update_syncscope();
816 				clear_zdata = true;
817 				bitcount = 5 * nbits * symbollen;
818 				if (sigsearch) sigsearch--;
819 					int mp0 = inp_ptr - 2;
820 				int mp1 = mp0 + 1;
821 				if (mp0 < 0) mp0 += MAXPIPE;
822 				if (mp1 < 0) mp1 += MAXPIPE;
823 				double ferr = (TWOPI * samplerate / rtty_baud) *
824 						(!reverse ?
825 							arg(conj(mark_history[mp1]) * mark_history[mp0]) :
826 							arg(conj(space_history[mp1]) * space_history[mp0]));
827 				if (fabs(ferr) > rtty_baud / 2) ferr = 0;
828 				freqerr = decayavg ( freqerr, ferr / 8,
829 					progdefaults.rtty_afcspeed == 0 ? 8 :
830 					progdefaults.rtty_afcspeed == 1 ? 4 : 1 );
831 				if (progStatus.afconoff &&
832 					(metric > progStatus.sldrSquelchValue || !progStatus.sqlonoff))
833 					set_freq(frequency - freqerr);
834 			} else
835 				if (bitcount) --bitcount;
836 		}
837 		if (!bHighSpeed) {
838 			if (!bitcount) {
839 				if (clear_zdata) {
840 					clear_zdata = false;
841 					Clear_syncscope();
842 					for (int i = 0; i < MAXPIPE; i++)
843 						QI[i] = cmplx(0.0, 0.0);
844 				}
845 			}
846 			if (!--showxy) {
847 				set_zdata(QI, MAXPIPE);
848 				showxy = symbollen;
849 			}
850 		}
851 	}
852 	return 0;
853 }
854 
855 //=====================================================================
856 // RTTY transmit
857 //=====================================================================
858 //double freq1;
859 double maxamp = 0;
860 
nco(double freq)861 double rtty::nco(double freq)
862 {
863 	phaseacc += TWOPI * freq / samplerate;
864 
865 	if (phaseacc > TWOPI) phaseacc -= TWOPI;
866 
867 	return cos(phaseacc);
868 }
869 
FSKnco()870 double rtty::FSKnco()
871 {
872 	FSKphaseacc += TWOPI * 1000 / samplerate;
873 
874 	if (FSKphaseacc > TWOPI) FSKphaseacc -= TWOPI;
875 
876 	return sin(FSKphaseacc);
877 
878 }
879 
880 extern Cserial CW_KEYLINE_serial;
881 extern bool CW_KEYLINE_isopen;
882 
send_symbol(int symbol,int len)883 void rtty::send_symbol(int symbol, int len)
884 {
885 	if (reverse) symbol = !symbol;
886 
887 	acc_symbols += len;
888 
889 	if (!progStatus.shaped_rtty) {
890 		double freq;
891 
892 		if (symbol)
893 			freq = get_txfreq_woffset() + shift / 2.0;
894 		else
895 			freq = get_txfreq_woffset() - shift / 2.0;
896 
897 		for (int i = 0; i < len; i++) {
898 			outbuf[i] = nco(freq);
899 			if (symbol)
900 				FSKbuf[i] = FSKnco();
901 			else
902 				FSKbuf[i] = 0.0;
903 		}
904 	} else {
905 		double const freq1 = get_txfreq_woffset() + shift / 2.0;
906 		double const freq2 = get_txfreq_woffset() - shift / 2.0;
907 		double mark = 0, space = 0;
908 		double signal = 0;
909 
910 		if (maxamp == 0) {
911 			int sym = 0;
912 			for (int j = 0; j < 100; j++) {
913 				if (sym) sym = 0;
914 				else sym = 1;
915 				for( int i = 0; i < 3*len; ++i ) {
916 					mark  = m_SymShaper1->Update( sym) * m_Osc1->Update( freq1 );
917 					space = m_SymShaper2->Update(!sym) * m_Osc2->Update( freq2 );
918 					signal = mark + space;
919 
920 					if (maxamp < fabs(signal)) maxamp = fabs(signal);
921 				}
922 			}
923 		}
924 
925 		for( int i = 0; i < len; ++i ) {
926 			mark  = m_SymShaper1->Update( symbol) * m_Osc1->Update( freq1 );
927 			space = m_SymShaper2->Update(!symbol) * m_Osc2->Update( freq2 );
928 			signal = mark + space;
929 
930 			if (maxamp < fabs(signal)) {
931 				maxamp = fabs(signal);
932 			}
933 
934 			outbuf[i] = maxamp ? (signal / maxamp) : 0.0;
935 
936 			if (symbol)
937 				FSKbuf[i] = FSKnco();
938 			else
939 				FSKbuf[i] = 0.0 * FSKnco();
940 		}
941 	}
942 
943 	if (progdefaults.PseudoFSK)
944 		ModulateStereo(outbuf, FSKbuf, symbollen);
945 	else
946 		ModulateXmtr(outbuf, symbollen);
947 
948 }
949 
send_stop()950 void rtty::send_stop()
951 {
952 	if (!progStatus.shaped_rtty) {
953 		double freq;
954 		bool invert = reverse;
955 
956 		if (invert)
957 			freq = get_txfreq_woffset() - shift / 2.0;
958 		else
959 			freq = get_txfreq_woffset() + shift / 2.0;
960 
961 		for (int i = 0; i < stoplen; i++) {
962 			outbuf[i] = nco(freq);
963 			if (invert)
964 				FSKbuf[i] = 0.0;
965 			else
966 				FSKbuf[i] = FSKnco();
967 		}
968 	} else {
969 		double const freq1 = get_txfreq_woffset() + shift / 2.0;
970 		double const freq2 = get_txfreq_woffset() - shift / 2.0;
971 		double mark = 0, space = 0, signal = 0;
972 		bool symbol = true;
973 
974 		if (reverse)
975 			symbol = !symbol;
976 
977 		for( int i = 0; i < stoplen; ++i ) {
978 			mark  = m_SymShaper1->Update( symbol)*m_Osc1->Update( freq1 );
979 			space = m_SymShaper2->Update(!symbol)*m_Osc2->Update( freq2 );
980 			signal = mark + space;
981 
982 			if (maxamp < fabs(signal))
983 				maxamp = fabs(signal);
984 			outbuf[i] = maxamp ? (signal / maxamp) : 0.0;
985 
986 			if (reverse)
987 				FSKbuf[i] = 0.0;
988 			else
989 				FSKbuf[i] = FSKnco();
990 		}
991 	}
992 
993 	if (progdefaults.PseudoFSK)
994 		ModulateStereo(outbuf, FSKbuf, stoplen);
995 	else
996 		ModulateXmtr(outbuf, stoplen);
997 
998 }
999 
flush_stream()1000 void rtty::flush_stream()
1001 {
1002 	double const freq1 = get_txfreq_woffset() + shift / 2.0;
1003 	double const freq2 = get_txfreq_woffset() - shift / 2.0;
1004 	double mark = 0, space = 0, signal = 0;
1005 
1006 	for( int i = 0; i < symbollen * 6; ++i ) {
1007 		mark  = m_SymShaper1->Update(0)*m_Osc1->Update( freq1 );
1008 		space = m_SymShaper2->Update(0)*m_Osc2->Update( freq2 );
1009 		signal = mark + space;
1010 
1011 		if (maxamp < fabs(signal)) maxamp = fabs(signal);
1012 
1013 		outbuf[i] = maxamp ? (signal / maxamp) : 0.0;
1014 
1015 		FSKbuf[i] = 0.0;
1016 	}
1017 
1018 	sig_stop = true;
1019 	if (progdefaults.PseudoFSK)
1020 		ModulateStereo(outbuf, FSKbuf, symbollen * 6);
1021 	else
1022 		ModulateXmtr(outbuf, symbollen * 6);
1023 
1024 }
1025 
send_char(int c)1026 void rtty::send_char(int c)
1027 {
1028 // experimental code that fails to perform well on Windows, poorly on OS-X
1029 // and perfectly on Linux!
1030 //	if (progdefaults.useFSK && (CW_KEYLINE_isopen || progdefaults.CW_KEYLINE_on_cat_port)) {
1031 //		send_FSK(c);
1032 //	}
1033 
1034 	int i;
1035 	if (nbits == 5) {
1036 		if (c == LETTERS)
1037 			c = 0x1F;
1038 		if (c == FIGURES)
1039 			c = 0x1B;
1040 	}
1041 
1042 // start bit
1043 	send_symbol(0, symbollen);
1044 // data bits
1045 	for (i = 0; i < nbits; i++) {
1046 		send_symbol((c >> i) & 1, symbollen);
1047 	}
1048 // parity bit
1049 	if (rtty_parity != RTTY_PARITY_NONE)
1050 		send_symbol(rttyparity(c, nbits), symbollen);
1051 // stop bit(s)
1052 	send_stop();
1053 
1054 	if (nbits == 5) {
1055 		if (c == 0x1F || c == 0x1B)
1056 			return;
1057 		if (txmode == LETTERS)
1058 			c = letters[c];
1059 		else
1060 			c = figures[c];
1061 		if (c)
1062 			put_echo_char(progdefaults.rx_lowercase ? tolower(c) : c);
1063 	}
1064 	else
1065 		put_echo_char(c);
1066 
1067 }
1068 
send_idle()1069 void rtty::send_idle()
1070 {
1071 	if (nbits == 5) {
1072 		send_char(LETTERS);
1073 		txmode = LETTERS;
1074 	} else
1075 		send_char(0);
1076 }
1077 
1078 static int line_char_count = 0;
1079 // 1 start, 5 data, 1.5/2.0 stopbits
1080 #define wait_one_byte(baud, stopbits) \
1081 MilliSleep( (int)((6 + (stopbits))*1000.0 / (baud)));
1082 
tx_process()1083 int rtty::tx_process()
1084 {
1085 	modem::tx_process();
1086 
1087 	int c = get_tx_char();
1088 
1089 	if (progStatus.nanoFSK_online) {
1090 		if (preamble) {
1091 			start_deadman();
1092 			sig_start = true;
1093 			for (int i = 0; i < progdefaults.TTY_LTRS; i++)
1094 				nano_send_char(-1);
1095 			preamble = false;
1096 			nano_send_char(-1);
1097 			nano_send_char(-1);
1098 		}
1099 
1100 		if (c == GET_TX_CHAR_ETX || stopflag) {
1101 			stopflag = false;
1102 			stop_deadman();
1103 			return -1;
1104 		}
1105 // send idle character if c == -1
1106 // nanoIO does not return an idle character in it's buffer so fldigi
1107 // must insert a suitable time delay to account for the idle
1108 		if (c == GET_TX_CHAR_NODATA) {
1109 			wait_one_byte(
1110 				progdefaults.nanoIO_baud,
1111 				1.5);
1112 			return 0;
1113 		}
1114 		nano_send_char(c);
1115 		put_echo_char(c);
1116 		return 0;
1117 	}
1118 
1119 	if (use_Nav) {
1120 		if (preamble) {
1121 			start_deadman();
1122 			for (int i = 0; i < progdefaults.TTY_LTRS; i++)
1123 				Nav_send_char(-1);
1124 			preamble = false;
1125 		}
1126 
1127 		if (c == GET_TX_CHAR_ETX || stopflag) {
1128 			stopflag = false;
1129 			stop_deadman();
1130 			return -1;
1131 		}
1132 		if (c == GET_TX_CHAR_NODATA) {
1133 			Nav_send_char(-1);
1134 			return 0;
1135 		}
1136 		Nav_send_char(c);
1137 		put_echo_char(c);
1138 		return 0;
1139 	}
1140 
1141 	if (progStatus.WK_online && progStatus.WKFSK_mode) {
1142 		if (preamble) {
1143 			start_deadman();
1144 			WKFSK_send_char('[');
1145 			preamble = false;
1146 		}
1147 
1148 		if (c == GET_TX_CHAR_ETX || stopflag) {
1149 			if (stopflag) WKFSK_send_char('\\');
1150 			WKFSK_send_char(']');
1151 			stop_deadman();
1152 			stopflag = false;
1153 			return -1;
1154 		}
1155 // send idle character if c == -1
1156 // must insert a suitable time delay to account for the idle
1157 		if (c == GET_TX_CHAR_NODATA) {
1158 			wait_one_byte(
1159 				(progStatus.WKFSK_baud == 0 ? 45.45 :
1160 				 progStatus.WKFSK_baud == 1 ? 50.0 :
1161 				 progStatus.WKFSK_baud == 2 ? 75.0 : 100.0),
1162 				 (progStatus.WKFSK_stopbits == 0 ? 2.0 : 1.5));
1163 			return 0;
1164 		}
1165 		else {
1166 		WKFSK_send_char(c);
1167 		put_echo_char(c);
1168 		wait_one_byte(
1169 			(progStatus.WKFSK_baud == 0 ? 45.45 :
1170 			 progStatus.WKFSK_baud == 1 ? 50.0 :
1171 			 progStatus.WKFSK_baud == 2 ? 75.0 : 100.0),
1172 			 (progStatus.WKFSK_stopbits == 0 ? 2.0 : 1.5));
1173 		}
1174 		return 0;
1175 	}
1176 
1177 	if (preamble) {
1178 		sig_start = true;
1179 		for (int i = 0; i < progdefaults.TTY_LTRS; i++)
1180 			send_char(LETTERS);
1181 		preamble = false;
1182 	}
1183 
1184 // TX buffer empty
1185 	if (c == GET_TX_CHAR_ETX || stopflag) {
1186 		stopflag = false;
1187 		line_char_count = 0;
1188 		if (nbits != 5) {
1189 			if (progdefaults.rtty_crcrlf) send_char('\r');
1190 			send_char('\r');
1191 			send_char('\n');
1192 		} else {
1193 			if (progdefaults.rtty_crcrlf) send_char(0x08);
1194 			send_char(0x08);
1195 			send_char(0x02);
1196 		}
1197 		flush_stream();
1198 		return -1;
1199 	}
1200 // send idle character if c == -1
1201 	if (c == GET_TX_CHAR_NODATA) {
1202 		send_idle();
1203 		return 0;
1204 	}
1205 
1206 // if NOT Baudot
1207 	if (nbits != 5) {
1208 		acc_symbols = 0;
1209 		send_char(c);
1210 		xmt_samples = char_samples = acc_symbols;
1211 		return 0;
1212 	}
1213 
1214 	if (isalpha(c) || isdigit(c) || isblank(c) || ispunct(c)) {
1215 		++line_char_count;
1216 	}
1217 
1218 	if (progdefaults.rtty_autocrlf && (c != '\n' && c != '\r') &&
1219 		(line_char_count == progdefaults.rtty_autocount ||
1220 		 (line_char_count > progdefaults.rtty_autocount - 5 && c == ' '))) {
1221 		line_char_count = 0;
1222 		if (progdefaults.rtty_crcrlf)
1223 			send_char(0x08); // CR-CR-LF triplet
1224 		send_char(0x08);
1225 		send_char(0x02);
1226 		if (c == ' ')
1227 			return 0;
1228 	}
1229 	if (c == '\r') {
1230 		line_char_count = 0;
1231 		send_char(0x08);
1232 		return 0;
1233 	}
1234 	if (c == '\n') {
1235 		line_char_count = 0;
1236 		if (progdefaults.rtty_crcrlf)
1237 			send_char(0x08); // CR-CR-LF triplet
1238 		send_char(0x02);
1239 		return 0;
1240 	}
1241 
1242 
1243 /* unshift-on-space */
1244 	if (c == ' ') {
1245 		if (progdefaults.UOStx) {
1246 			send_char(LETTERS);
1247 			send_char(0x04); // coded value for a space
1248 			txmode = LETTERS;
1249 		} else
1250 			send_char(0x04);
1251 		return 0;
1252 	}
1253 
1254 	if ((c = baudot_enc(c)) < 0)
1255 		return 0;
1256 
1257 // switch case if necessary
1258 
1259 	if ((c & 0x300) != txmode) {
1260 		if (txmode == FIGURES) {
1261 			send_char(LETTERS);
1262 			txmode = LETTERS;
1263 		} else {
1264 			send_char(FIGURES);
1265 			txmode = FIGURES;
1266 		}
1267 	}
1268 ///
1269 	acc_symbols = 0;
1270 	send_char(c & 0x1F);
1271 	xmt_samples = char_samples = acc_symbols;
1272 
1273 	return 0;
1274 }
1275 
baudot_enc(unsigned char data)1276 int rtty::baudot_enc(unsigned char data)
1277 {
1278 	int i, c, mode;
1279 
1280 	mode = 0;
1281 	c = -1;
1282 
1283 	if (islower(data))
1284 		data = toupper(data);
1285 
1286 	for (i = 0; i < 32; i++) {
1287 		if (data == letters[i]) {
1288 			mode |= LETTERS;
1289 			c = i;
1290 		}
1291 		if (data == figures[i]) {
1292 			mode |= FIGURES;
1293 			c = i;
1294 		}
1295 		if (c != -1)
1296 			return (mode | c);
1297 	}
1298 
1299 	return -1;
1300 }
1301 
baudot_dec(unsigned char data)1302 char rtty::baudot_dec(unsigned char data)
1303 {
1304 	int out = 0;
1305 
1306 	switch (data) {
1307 	case 0x1F:		/* letters */
1308 		rxmode = LETTERS;
1309 		break;
1310 	case 0x1B:		/* figures */
1311 		rxmode = FIGURES;
1312 		break;
1313 	case 0x04:		/* unshift-on-space */
1314 		if (progdefaults.UOSrx)
1315 			rxmode = LETTERS;
1316 		return ' ';
1317 		break;
1318 	default:
1319 		if (rxmode == LETTERS)
1320 			out = letters[data];
1321 		else
1322 			out = figures[data];
1323 		break;
1324 	}
1325 
1326 	return out;
1327 }
1328 
1329 // ---------------------------------------------------------------------
1330 // TTY output on DTR/RTS signal lines
1331 //----------------------------------------------------------------------
1332 // experimental code that performs perfect on Linux, OK on OS-X and
1333 // fails on Windows-10 !!!
1334 /*
1335 static pthread_t       fsk_pthread;
1336 static pthread_cond_t  fsk_cond;
1337 static pthread_mutex_t fsk_mutex = PTHREAD_MUTEX_INITIALIZER;
1338 
1339 static bool fsk_thread_running   = false;
1340 static bool fsk_terminate_flag   = false;
1341 
1342 #define fskbit(bit, len) {if (progdefaults.FSK_keyline == 2) ser->SetDTR(bit);\
1343 else ser->SetRTS(bit);\
1344 MilliSleep((len));}
1345 
1346 static int fsk_ch;
1347 static int fsk_nbits;
1348 static int fsk_parity;
1349 static bool fsk_sending = false;
1350 
1351 void send_fsk(int c)
1352 {
1353 	fsk_sending = true;
1354 	int bitlen = 1000.0 / rtty::BAUD[progdefaults.rtty_baud];
1355 	int stoplen = bitlen * (progdefaults.rtty_stop == 0 ? 1.0 : progdefaults.rtty_stop == 1 ? 1.5 : 2.0);
1356 
1357 	Cserial *ser = &CW_KEYLINE_serial;
1358 	if (progdefaults.CW_KEYLINE_on_cat_port)
1359 		ser = &rigio;
1360 
1361 	if (fsk_nbits == 5) {
1362 		if (c == LETTERS) c = 0x1F;
1363 		else if (c == FIGURES) c = 0x1B;
1364 	}
1365 
1366 // start bit
1367 	fskbit(1, bitlen);
1368 // data bits
1369 	for (int i = 0; i < fsk_nbits; i++)
1370 		fskbit(!((c >> i) & 1), bitlen);
1371 
1372 // parity bit
1373 	if (fsk_parity != rtty::RTTY_PARITY_NONE)
1374 		fskbit(!rttyparity(c, fsk_nbits), bitlen);
1375 
1376 // stop bits
1377 	fskbit(0, stoplen);
1378 	fsk_sending = false;
1379 }
1380 
1381 static void * fsk_loop(void *args)
1382 {
1383 //	SET_THREAD_ID(AUDIO_ALERT_TID);
1384 
1385 	fsk_thread_running   = true;
1386 	fsk_terminate_flag   = false;
1387 
1388 	while(1) {
1389 		pthread_mutex_lock(&fsk_mutex);
1390 		pthread_cond_wait(&fsk_cond, &fsk_mutex);
1391 		pthread_mutex_unlock(&fsk_mutex);
1392 
1393 		if (fsk_terminate_flag)
1394 			break;
1395 		send_fsk(fsk_ch);
1396 	}
1397 	return (void *)0;
1398 }
1399 
1400 void stop_fsk_thread(void)
1401 {
1402 	if(!fsk_thread_running) return;
1403 
1404 	fsk_terminate_flag = true;
1405 	pthread_cond_signal(&fsk_cond);
1406 
1407 	MilliSleep(10);
1408 
1409 	pthread_join(fsk_pthread, NULL);
1410 
1411 	pthread_mutex_destroy(&fsk_mutex);
1412 	pthread_cond_destroy(&fsk_cond);
1413 
1414 	memset((void *) &fsk_pthread, 0, sizeof(fsk_pthread));
1415 	memset((void *) &fsk_mutex,   0, sizeof(fsk_mutex));
1416 
1417 	fsk_thread_running   = false;
1418 	fsk_terminate_flag   = false;
1419 }
1420 
1421 void start_fsk_thread(void)
1422 {
1423 	if (fsk_thread_running) return;
1424 
1425 	memset((void *) &fsk_pthread, 0, sizeof(fsk_pthread));
1426 	memset((void *) &fsk_mutex,   0, sizeof(fsk_mutex));
1427 	memset((void *) &fsk_cond,    0, sizeof(fsk_cond));
1428 
1429 	if(pthread_cond_init(&fsk_cond, NULL)) {
1430 		LOG_ERROR("Alert thread create fail (pthread_cond_init)");
1431 		return;
1432 	}
1433 
1434 	if(pthread_mutex_init(&fsk_mutex, NULL)) {
1435 		LOG_ERROR("AUDIO_ALERT thread create fail (pthread_mutex_init)");
1436 		return;
1437 	}
1438 
1439 	if (pthread_create(&fsk_pthread, NULL, fsk_loop, NULL) < 0) {
1440 		pthread_mutex_destroy(&fsk_mutex);
1441 		LOG_ERROR("AUDIO_ALERT thread create fail (pthread_create)");
1442 	}
1443 
1444 	LOG_VERBOSE("started audio fsk thread");
1445 
1446 	MilliSleep(10); // Give the CPU time to set 'fsk_thread_running'
1447 }
1448 
1449 void rtty::send_FSK(int c)
1450 {
1451 	if (!fsk_thread_running)
1452 		start_fsk_thread();
1453 
1454 	int count = 100;
1455 	while (fsk_sending) {
1456 		MilliSleep(1);
1457 		if (--count <= 0) return;
1458 	}
1459 	fsk_ch = c;
1460 	fsk_nbits = nbits;
1461 	fsk_parity = rtty_parity;
1462 
1463 	pthread_cond_signal(&fsk_cond);
1464 }
1465 */
1466 //======================================================================
1467 // methods for class Oscillator and class SymbolShaper
1468 //======================================================================
1469 
Oscillator(double samplerate)1470 Oscillator::Oscillator( double samplerate )
1471 {
1472 	m_phase = 0;
1473 	m_samplerate = samplerate;
1474 //	std::cerr << "samplerate for Oscillator:"<<m_samplerate<<"\n";
1475 }
1476 
Update(double frequency)1477 double Oscillator::Update( double frequency )
1478 {
1479 	m_phase += frequency/m_samplerate * TWOPI;
1480 	if ( m_phase > TWOPI ) m_phase -= TWOPI;
1481 
1482 	return ( sin( m_phase ) );
1483 }
1484 
SymbolShaper(double baud,double sr)1485 SymbolShaper::SymbolShaper(double baud, double sr)
1486 {
1487 	m_sinc_table = 0;
1488 	Preset( baud, sr );
1489 }
1490 
~SymbolShaper()1491 SymbolShaper::~SymbolShaper()
1492 {
1493 	delete [] m_sinc_table;
1494 }
1495 
reset()1496 void SymbolShaper::reset()
1497 {
1498 	m_State = false;
1499 	m_Accumulator = 0.0;
1500 	m_Counter0 = 1024;
1501 	m_Counter1 = 1024;
1502 	m_Counter2 = 1024;
1503 	m_Counter3 = 1024;
1504 	m_Counter4 = 1024;
1505 	m_Counter5 = 1024;
1506 	m_Factor0 = 0.0;
1507 	m_Factor1 = 0.0;
1508 	m_Factor2 = 0.0;
1509 	m_Factor3 = 0.0;
1510 	m_Factor4 = 0.0;
1511 	m_Factor5 = 0.0;
1512 }
1513 
Preset(double baud,double sr)1514 void SymbolShaper::Preset(double baud, double sr)
1515 {
1516     double baud_rate = baud;
1517     double sample_rate = sr;
1518 
1519     LOG_INFO("Shaper::reset( %f, %f )",  baud_rate, sample_rate);
1520 
1521 // calculate new table-size for six integrators ----------------------
1522 
1523     m_table_size = sample_rate / baud_rate * 5.49;
1524     LOG_INFO("Shaper::m_table_size = %d", m_table_size);
1525 
1526 // kill old sinc-table and get memory for the new one -----------------
1527 
1528 	if (m_sinc_table)
1529 		delete [] m_sinc_table;
1530     m_sinc_table = new double[m_table_size];
1531 
1532 // set up the new sinc-table based on the new parameters --------------
1533 
1534     long double sum = 0.0;
1535 
1536     for( int x=0; x<m_table_size; ++x ) {
1537         int const offset = m_table_size/2;
1538         double wfactor = 1.0 / 1.568; // optimal
1539 // symbol-length in samples if wmultiple = 1.0
1540         double const T = wfactor * sample_rate / (baud_rate*2.0);
1541 // symbol-time relative to zero
1542         double const t = (x-offset);
1543 
1544         m_sinc_table[x] = rcos( t, T, 1.0 );
1545 
1546 // calculate integral
1547         sum += m_sinc_table[x];
1548     }
1549 
1550 // scale the values in the table so that the integral over it is as
1551 // exactly 1.0000000 as we can do this...
1552 
1553     for( int x=0; x<m_table_size; ++x ) {
1554         m_sinc_table[x] *= 1.0 / sum;
1555     }
1556 
1557 // reset internal states
1558     reset();
1559     maxamp = 0;
1560 }
1561 
Update(bool state)1562 double SymbolShaper::Update( bool state )
1563 {
1564 	if( m_State != state ) {
1565 		m_State = state;
1566 		if( m_Counter0 >= m_table_size ) {
1567 			m_Counter0 = 0;
1568 			m_Factor0 = (state)? +1.0 : -1.0;
1569 		} else if( m_Counter1 >= m_table_size ) {
1570 			m_Counter1 = 0;
1571 			m_Factor1 = (state)? +1.0 : -1.0;
1572 		} else if( m_Counter2 >= m_table_size ) {
1573 			m_Counter2 = 0;
1574 			m_Factor2 = (state)? +1.0 : -1.0;
1575 		} else if( m_Counter3 >= m_table_size ) {
1576 			m_Counter3 = 0;
1577 			m_Factor3 = (state)? +1.0 : -1.0;
1578 		} else if( m_Counter4 >= m_table_size ) {
1579 			m_Counter4 = 0;
1580 			m_Factor4 = (state)? +1.0 : -1.0;
1581 		} else  if( m_Counter5 >= m_table_size ) {
1582 			m_Counter5 = 0;
1583 			m_Factor5 = (state)? +1.0 : -1.0;
1584 		}
1585 	}
1586 
1587 	if( m_Counter0 < m_table_size )
1588 		m_Accumulator += m_Factor0 * m_sinc_table[m_Counter0++];
1589 
1590 	if( m_Counter1 < m_table_size )
1591 		m_Accumulator += m_Factor1 * m_sinc_table[m_Counter1++];
1592 
1593 	if( m_Counter2 < m_table_size )
1594 		m_Accumulator += m_Factor2 * m_sinc_table[m_Counter2++];
1595 
1596 	if( m_Counter3 < m_table_size )
1597 		m_Accumulator += m_Factor3 * m_sinc_table[m_Counter3++];
1598 
1599 	if( m_Counter4 < m_table_size )
1600 		m_Accumulator += m_Factor4 * m_sinc_table[m_Counter4++];
1601 
1602 	if( m_Counter5 < m_table_size )
1603 		m_Accumulator += m_Factor5 * m_sinc_table[m_Counter5++];
1604 
1605 	return ( m_Accumulator / sqrt(2) );
1606 }
1607 
print_sinc_table()1608 void SymbolShaper::print_sinc_table()
1609 {
1610 	for (int i = 0; i < 1024; i++) printf("%f\n", m_SincTable[i]);
1611 }
1612 
1613