1 // ----------------------------------------------------------------------------
2 // olivia.cxx  --  OLIVIA modem
3 //
4 // Copyright (C) 2006-2010
5 //		Dave Freese, W1HKJ
6 //
7 // This file is part of fldigi.  Adapted from code contained in gmfsk source code
8 // distribution.
9 //	Copyright (C) 2005
10 //	Tomi Manninen (oh2bns@sral.fi)
11 //
12 // This file is part of fldigi.
13 //
14 // Fldigi is free software: you can redistribute it and/or modify
15 // it under the terms of the GNU General Public License as published by
16 // the Free Software Foundation, either version 3 of the License, or
17 // (at your option) any later version.
18 //
19 // Fldigi is distributed in the hope that it will be useful,
20 // but WITHOUT ANY WARRANTY; without even the implied warranty of
21 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22 // GNU General Public License for more details.
23 //
24 // You should have received a copy of the GNU General Public License
25 // along with fldigi.  If not, see <http://www.gnu.org/licenses/>.
26 // ----------------------------------------------------------------------------
27 
28 #include <config.h>
29 
30 #include <sstream>
31 
32 #include <FL/Fl.H>
33 
34 #include "olivia.h"
35 #include "modem.h"
36 #include "fl_digi.h"
37 
38 #include "misc.h"
39 #include "confdialog.h"
40 #include "status.h"
41 #include "debug.h"
42 #include "qrunner.h"
43 
44 //------------------------------------------------------------------------------
45 #include "threads.h"
46 
47 static pthread_mutex_t olivia_mutex = PTHREAD_MUTEX_INITIALIZER;
48 //------------------------------------------------------------------------------
49 
50 LOG_FILE_SOURCE(debug::LOG_MODEM);
51 
52 using namespace std;
53 
nco(double freq)54 double olivia::nco(double freq)
55 {
56     preamblephase += 2.0 * M_PI * freq / samplerate;
57 
58 	if (preamblephase > M_PI)
59 		preamblephase -= 2.0 * M_PI;
60 
61 	return cos(preamblephase);
62 }
63 
tx_init()64 void olivia::tx_init()
65 {
66 	phaseacc = 0;
67 	prevsymbol = cmplx (1.0, 0.0);
68 	preamble = 32;
69 	shreg = 0;
70 
71 	preamblesent = 0;
72 	postamblesent = 0;
73 	txbasefreq = get_txfreq_woffset();
74 
75 	rx_flush();
76 
77 { // critical section
78 	guard_lock dsp_lock(&olivia_mutex);
79 
80 	double fc_offset = Tx->Bandwidth*(1.0 - 0.5/Tx->Tones)/2.0;
81 	if (reverse) {
82 		Tx->FirstCarrierMultiplier = (txbasefreq + fc_offset)/500.0;
83 		Tx->Reverse = 1;
84 	} else {
85 		Tx->FirstCarrierMultiplier = (txbasefreq - fc_offset)/500.0;
86 		Tx->Reverse = 0;
87 	}
88 	Tx->Preset();
89 	Tx->Start();
90 } // end critical section
91 
92 	videoText();
93 
94 	escape = 0;
95 }
96 
rx_flush()97 void olivia::rx_flush()
98 {
99 	guard_lock dsp_lock(&olivia_mutex);
100 
101 	unsigned char c;
102 	Rx->Flush();
103 	while (Rx->GetChar(c) > 0)
104 		put_rx_char(c);
105 }
106 
send_tones()107 void olivia::send_tones()
108 {
109 	if (!progdefaults.olivia_start_tones) return;
110 
111 	double freqa, freqb;
112 	tone_bw = bandwidth;
113 	tone_midfreq = txbasefreq;
114 
115 	if (reverse) {
116 		freqa = tone_midfreq + (tone_bw / 2.0);
117 		freqb = tone_midfreq - (tone_bw / 2.0);
118 	} else {
119 		freqa = tone_midfreq - (tone_bw / 2.0);
120 		freqb = tone_midfreq + (tone_bw / 2.0);
121 	}
122 
123 	preamblephase = 0;
124 	for (int i = 0; i < SR4; i++)
125 		tonebuff[2*SR4 + i] = tonebuff[i] = nco(freqa) * ampshape[i];
126 
127 	preamblephase = 0;
128 	for (int i = 0; i < SR4; i++)
129 		tonebuff[3*SR4 + i] = tonebuff[SR4 + i] = nco(freqb) * ampshape[i];
130 
131 	for (int j = 0; j < TONE_DURATION; j += SCBLOCKSIZE)
132 		ModulateXmtr(&tonebuff[j], SCBLOCKSIZE);
133 
134 }
135 
rx_init()136 void olivia::rx_init()
137 {
138 	guard_lock dsp_lock(&olivia_mutex);
139 
140 	Rx->Reset();
141 	escape = 0;
142 }
143 
unescape(int c)144 int olivia::unescape(int c)
145 {
146 	if (progdefaults.olivia8bit == 0)
147 		return c;
148 
149 	if (escape) {
150 		escape = 0;
151 		return c + 128;
152 	}
153 
154 	if (c == 127) {
155 		escape = 1;
156 		return -1;
157 	}
158 
159 	return c;
160 }
161 
tx_process()162 int olivia::tx_process()
163 {
164 	modem::tx_process();
165 
166 	int c = 0, len = 0;
167 
168 	if ((mode == MODE_OLIVIA &&
169 		(tones	!= progdefaults.oliviatones ||
170 		bw 		!= progdefaults.oliviabw)) ||
171 		smargin != progdefaults.oliviasmargin ||
172 		sinteg	!= progdefaults.oliviasinteg )
173 			restart();
174 
175 { // critical section
176 	guard_lock dsp_lock(&olivia_mutex);
177 
178 	if (preamblesent != 1) {
179 		send_tones();
180 		preamblesent = 1;
181 		// Olivia Transmitter class requires at least character
182 		Tx->PutChar(0);
183 	}
184 
185 // The encoder works with BitsPerSymbol length blocks. If the
186 // modem already has that many characters buffered, don't try
187 // to read any more. If stopflag is set, we will always read
188 // whatever there is.
189 	if (stopflag || (Tx->GetReadReady() < Tx->BitsPerSymbol)) {
190 		if (!stopflag && (c = get_tx_char()) == GET_TX_CHAR_ETX)
191 			stopflag = true;
192 		if (stopflag)
193 			Tx->Stop();
194 		else {
195 			if (c == GET_TX_CHAR_NODATA)
196 		                c = 0;
197 			if (c > 127) {
198 				if (progdefaults.olivia8bit && c <= 255) {
199 					Tx->PutChar(127);
200 					Tx->PutChar(c & 127);
201 				}
202 				else {
203 					c = '.';
204 					Tx->PutChar(c);
205 				}
206 			}
207 			else
208 				Tx->PutChar(c);
209 		}
210 	}
211 
212 	if (c > 0)
213 		put_echo_char(c);
214 
215 	if ((len = Tx->Output(txfbuffer)) > 0)
216 		ModulateXmtr(txfbuffer, len);
217 
218 	if (stopflag && Tx->DoPostambleYet() == 1 && postamblesent != 1) {
219 		postamblesent = 1;
220 		send_tones();
221 		memset(tonebuff, 0, sizeof(*tonebuff) * SCBLOCKSIZE);
222 		ModulateXmtr(tonebuff, SCBLOCKSIZE);
223 	}
224 
225 	if (!Tx->Running()) {
226 		stopflag = false;
227 		return -1;
228 	}
229 } // end critical section
230 	return 0;
231 }
232 
233 
rx_process(const double * buf,int len)234 int olivia::rx_process(const double *buf, int len)
235 {
236 	int c;
237 	unsigned char ch = 0;
238 	static double snr = 1e-3;
239 	static char msg1[20];
240 	static char msg2[20];
241 	double rxf_offset = 0;
242 	double rx_bw = 0;
243 	double rx_tones = 0;
244 	double rx_snr = 0;
245 	int fc_offset = 0;
246 	bool gotchar = false;
247 
248 	if ((mode == MODE_OLIVIA &&
249 		(tones	!= progdefaults.oliviatones ||
250 		bw 		!= progdefaults.oliviabw)) ||
251 		smargin != progdefaults.oliviasmargin ||
252 		sinteg	!= progdefaults.oliviasinteg )
253 			restart();
254 
255 { // critical section
256 	guard_lock dsp_lock(&olivia_mutex);
257 
258 	fc_offset = Tx->Bandwidth*(1.0 - 0.5/Tx->Tones)/2.0;
259 
260 	if ((lastfreq != frequency || Rx->Reverse) && !reverse) {
261 		Rx->FirstCarrierMultiplier = (frequency - fc_offset)/500.0;
262 		Rx->Reverse = 0;
263 		lastfreq = frequency;
264 		Rx->Preset();
265 	}
266 	else if ((lastfreq != frequency || !Rx->Reverse) && reverse) {
267 		Rx->FirstCarrierMultiplier = (frequency + fc_offset)/500.0;
268 		Rx->Reverse = 1;
269 		lastfreq = frequency;
270 		Rx->Preset();
271 	}
272 
273 	Rx->SyncThreshold = progStatus.sqlonoff ?
274 		clamp(progStatus.sldrSquelchValue / 5.0 + 3.0, 0, 90.0) : 0.0;
275 
276 	Rx->Process(buf, len);
277 
278 	while (Rx->GetChar(ch) > 0) {
279 		if ((c = unescape(ch)) != -1 && c > 7) {
280 			put_rx_char(c);
281 			gotchar = true;
282 		}
283     }
284 
285 	rxf_offset = Rx->FrequencyOffset();
286 	rx_bw = Rx->Bandwidth;
287 	rx_tones = Rx->Tones;
288 	rx_snr = Rx->SignalToNoiseRatio();
289 } // end critical section
290 
291 	sp = 0;
292 	for (int i = frequency - fc_offset; i < frequency + fc_offset; i++)
293 		if (wf->Pwr(i) > sp)
294 			sp = wf->Pwr(i);
295 
296 	np = wf->Pwr(static_cast<int>(frequency + rx_bw/2 + 2*rx_bw/rx_tones));
297 
298 	if (np == 0) np = sp + 1e-8;
299 
300 	sigpwr = decayavg( sigpwr, sp, 10);
301 	noisepwr = decayavg( noisepwr, np, 50);
302 	snr = CLAMP(sigpwr / noisepwr, 0.001, 100000);
303 
304 	metric = clamp( 5.0 * (rx_snr - 3.0), 0, 100);
305 	display_metric(metric);
306 
307 	if (gotchar) {
308 		snprintf(msg1, sizeof(msg1), "s/n: %4.1f dB", 10*log10(snr) - 20);
309 		put_Status1(msg1, 5, STATUS_CLEAR);
310 		snprintf(msg2, sizeof(msg2), "f/o %+4.1f Hz", rxf_offset);
311 		put_Status2(msg2, 5, STATUS_CLEAR);
312 	}
313 
314 	return 0;
315 }
316 
restart()317 void olivia::restart()
318 {
319 	if (mode == MODE_OLIVIA) {
320 		tones	= progdefaults.oliviatones;
321 		bw 		= progdefaults.oliviabw;
322 	}
323 	smargin = progdefaults.oliviasmargin;
324 	sinteg	= progdefaults.oliviasinteg;
325 
326 	samplerate = 8000;
327 	bandwidth = 125 * (1 << bw);
328 
329 	Tx->Tones = 2 * (1 << tones);
330 	Tx->Bandwidth = bandwidth;
331 	Tx->SampleRate = samplerate;
332 	Tx->OutputSampleRate = samplerate;
333 	txbasefreq = get_txfreq_woffset();
334 
335 { // critical section
336 	guard_lock dsp_lock(&olivia_mutex);
337 
338 	int fc_offset = Tx->Bandwidth * (1.0 - 0.5/Tx->Tones) / 2.0;
339 	if (reverse) {
340 		Tx->FirstCarrierMultiplier = (txbasefreq + fc_offset)/500.0;
341 		Tx->Reverse = 1;
342 	} else {
343 		Tx->FirstCarrierMultiplier = (txbasefreq - fc_offset)/500.0;
344 		Tx->Reverse = 0;
345 	}
346 
347 	if (Tx->Preset() < 0) {
348 		LOG_ERROR("olivia: transmitter preset failed!");
349 		return;
350 	}
351 
352 	txbufferlen = Tx->MaxOutputLen;
353 
354 	if (txfbuffer) delete [] txfbuffer;
355 	txfbuffer = new double[txbufferlen];
356 
357 	Rx->Tones = Tx->Tones;
358 	Rx->Bandwidth = bandwidth;
359 	Rx->SyncMargin = smargin;
360 	Rx->SyncIntegLen = sinteg;
361 	Rx->SyncThreshold = progStatus.sqlonoff ?
362 		clamp(progStatus.sldrSquelchValue / 5.0 + 3.0, 0, 90.0) : 0.0;
363 
364 	Rx->SampleRate = samplerate;
365 	Rx->InputSampleRate = samplerate;
366 
367 	fc_offset = Rx->Bandwidth * (1.0 - 0.5/Rx->Tones) / 2.0;
368 	if (reverse) {
369 		Rx->FirstCarrierMultiplier = (frequency + fc_offset)/500.0;
370 		Rx->Reverse = 1;
371 	} else {
372 		Rx->FirstCarrierMultiplier = (frequency - fc_offset)/500.0;
373 		Rx->Reverse = 0;
374 	}
375 
376 	if (Rx->Preset() < 0) {
377 		LOG_ERROR("olivia: receiver preset failed!");
378 		return;
379 	}
380 	fragmentsize = 1024;
381 	set_bandwidth(Tx->Bandwidth - Tx->Bandwidth / Tx->Tones);
382 
383 	stringstream info;
384 	info << mode_info[mode].sname;
385 	put_MODEstatus("%s", info.str().c_str());
386 
387 	metric = 0;
388 
389 	sigpwr = 1e-10; noisepwr = 1e-8;
390 	LOG_DEBUG("\nOlivia Rx parameters:\n%s", Rx->PrintParameters());
391 } // end critical section
392 }
393 
init()394 void olivia::init()
395 {
396 	restart();
397 	modem::init();
398 	set_scope_mode(Digiscope::BLANK);
399 
400 	if (progdefaults.StartAtSweetSpot)
401 		set_freq(progdefaults.PSKsweetspot);
402 	else if (progStatus.carrier != 0) {
403 		set_freq(progStatus.carrier);
404 #if !BENCHMARK_MODE
405 		progStatus.carrier = 0;
406 #endif
407 	} else
408 		set_freq(wf->Carrier());
409 
410 }
411 
olivia(trx_mode omode)412 olivia::olivia(trx_mode omode)
413 {
414 	mode = omode;
415 	cap |= CAP_REV;
416 
417 	txfbuffer = 0;
418 	samplerate = 8000;
419 
420 	switch (mode) {
421 		case MODE_OLIVIA_4_125:
422 			progdefaults.oliviatones = tones = 1;
423 			progdefaults.oliviabw = bw = 0;
424 			REQ(set_olivia_tab_widgets);
425 			break;
426 		case MODE_OLIVIA_4_250:
427 			progdefaults.oliviatones = tones = 1;
428 			progdefaults.oliviabw = bw = 1;
429 			REQ(set_olivia_tab_widgets);
430 			break;
431 		case MODE_OLIVIA_4_500:
432 			progdefaults.oliviatones = tones = 1;
433 			progdefaults.oliviabw = bw = 2;
434 			REQ(set_olivia_tab_widgets);
435 			break;
436 		case MODE_OLIVIA_4_1000:
437 			progdefaults.oliviatones = tones = 1;
438 			progdefaults.oliviabw = bw = 3;
439 			REQ(set_olivia_tab_widgets);
440 			break;
441 		case MODE_OLIVIA_4_2000:
442 			progdefaults.oliviatones = tones = 1;
443 			progdefaults.oliviabw = bw = 4;
444 			REQ(set_olivia_tab_widgets);
445 			break;
446 		case MODE_OLIVIA_8_125:
447 			progdefaults.oliviatones = tones = 2;
448 			progdefaults.oliviabw = bw = 0;
449 			REQ(set_olivia_tab_widgets);
450 			break;
451 		case MODE_OLIVIA_8_250:
452 			progdefaults.oliviatones = tones = 2;
453 			progdefaults.oliviabw = bw = 1;
454 			REQ(set_olivia_tab_widgets);
455 			break;
456 		case MODE_OLIVIA_8_500:
457 			progdefaults.oliviatones = tones = 2;
458 			progdefaults.oliviabw = bw = 2;
459 			REQ(set_olivia_tab_widgets);
460 			break;
461 		case MODE_OLIVIA_8_1000:
462 			progdefaults.oliviatones = tones = 2;
463 			progdefaults.oliviabw = bw = 3;
464 			REQ(set_olivia_tab_widgets);
465 			break;
466 		case MODE_OLIVIA_8_2000:
467 			progdefaults.oliviatones = tones = 2;
468 			progdefaults.oliviabw = bw = 4;
469 			REQ(set_olivia_tab_widgets);
470 			break;
471 		case MODE_OLIVIA_16_500:
472 			progdefaults.oliviatones = tones = 3;
473 			progdefaults.oliviabw = bw = 2;
474 			REQ(set_olivia_tab_widgets);
475 			break;
476 		case MODE_OLIVIA_16_1000:
477 			progdefaults.oliviatones = tones = 3;
478 			progdefaults.oliviabw = bw = 3;
479 			REQ(set_olivia_tab_widgets);
480 			break;
481 		case MODE_OLIVIA_16_2000:
482 			progdefaults.oliviatones = tones = 3;
483 			progdefaults.oliviabw = bw = 4;
484 			REQ(set_olivia_tab_widgets);
485 			break;
486 		case MODE_OLIVIA_32_1000:
487 			progdefaults.oliviatones = tones = 4;
488 			progdefaults.oliviabw = bw = 3;
489 			REQ(set_olivia_tab_widgets);
490 			break;
491 		case MODE_OLIVIA_32_2000:
492 			progdefaults.oliviatones = tones = 4;
493 			progdefaults.oliviabw = bw = 4;
494 			REQ(set_olivia_tab_widgets);
495 			break;
496 		case MODE_OLIVIA_64_500:
497 			progdefaults.oliviatones = tones = 5;
498 			progdefaults.oliviabw = bw = 2;
499 			REQ(set_olivia_tab_widgets);
500 			break;
501 		case MODE_OLIVIA_64_1000:
502 			progdefaults.oliviatones = tones = 5;
503 			progdefaults.oliviabw = bw = 3;
504 			REQ(set_olivia_tab_widgets);
505 			break;
506 		case MODE_OLIVIA_64_2000:
507 			progdefaults.oliviatones = tones = 5;
508 			progdefaults.oliviabw = bw = 4;
509 			REQ(set_olivia_tab_widgets);
510 			break;
511 		case MODE_OLIVIA:
512 		default:
513 			tones = progdefaults.oliviatones;
514 			bw    = progdefaults.oliviabw;
515 			REQ(set_olivia_tab_widgets);
516 			break;
517 	}
518 
519 	Tx = new MFSK_Transmitter< double >;
520 	Rx = new MFSK_Receiver< double >;
521 
522 	lastfreq = 0;
523 
524 	for (int i = 0; i < SR4; i++) ampshape[i] = 1.0;
525 	for (int i = 0; i < SR4 / 8; i++)
526 		ampshape[i] = ampshape[SR4 - 1 - i] = 0.5 * (1.0 - cos(M_PI * i / (SR4/8)));
527 
528 	for (int i = 0; i < TONE_DURATION; i++) tonebuff[i] = 0;
529 
530 	tone_bw = -1;
531 	tone_midfreq = -1;
532 }
533 
~olivia()534 olivia::~olivia()
535 {
536 	guard_lock dsp_lock(&olivia_mutex);
537 
538 	if (Tx) delete Tx;
539 	if (Rx) delete Rx;
540 	if (txfbuffer) delete [] txfbuffer;
541 }
542 
543