1 // ----------------------------------------------------------------------------
2 //
3 //	rsid.cxx
4 //
5 // Copyright (C) 2008-2012
6 //		Dave Freese, W1HKJ
7 // Copyright (C) 2009-2012
8 //		Stelios Bounanos, M0GLD
9 // Copyright (C) 2012
10 //		John Douyere, VK2ETA
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 <string>
31 #include <cmath>
32 #include <cstring>
33 #include <float.h>
34 #include <samplerate.h>
35 
36 #include "rsid.h"
37 #include "filters.h"
38 #include "misc.h"
39 #include "trx.h"
40 #include "fl_digi.h"
41 #include "configuration.h"
42 #include "confdialog.h"
43 #include "qrunner.h"
44 #include "notify.h"
45 #include "debug.h"
46 
47 #include "main.h"
48 #include "arq_io.h"
49 #include "data_io.h"
50 #include "audio_alert.h"
51 
52 LOG_FILE_SOURCE(debug::LOG_MODEM);
53 
54 #include "rsid_defs.cxx"
55 
56 #define RSWINDOW 1
57 
58 const int cRsId::Squares[] = {
59 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
60 	0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,
61 	0, 2, 4, 6, 8,10,12,14, 9,11,13,15, 1, 3, 5, 7,
62 	0, 3, 6, 5,12,15,10, 9, 1, 2, 7, 4,13,14,11, 8,
63 	0, 4, 8,12, 9,13, 1, 5,11,15, 3, 7, 2, 6,10,14,
64 	0, 5,10,15,13, 8, 7, 2, 3, 6, 9,12,14,11, 4, 1,
65 	0, 6,12,10, 1, 7,13,11, 2, 4,14, 8, 3, 5,15, 9,
66 	0, 7,14, 9, 5, 2,11,12,10,13, 4, 3,15, 8, 1, 6,
67 	0, 8, 9, 1,11, 3, 2,10,15, 7, 6,14, 4,12,13, 5,
68 	0, 9,11, 2,15, 6, 4,13, 7,14,12, 5, 8, 1, 3,10,
69 	0,10,13, 7, 3, 9,14, 4, 6,12,11, 1, 5,15, 8, 2,
70 	0,11,15, 4, 7,12, 8, 3,14, 5, 1,10, 9, 2, 6,13,
71 	0,12, 1,13, 2,14, 3,15, 4, 8, 5, 9, 6,10, 7,11,
72 	0,13, 3,14, 6,11, 5, 8,12, 1,15, 2,10, 7, 9, 4,
73 	0,14, 5,11,10, 4,15, 1,13, 3, 8, 6, 7, 9, 2,12,
74 	0,15, 7, 8,14, 1, 9, 6, 5,10, 2,13,11, 4,12, 3
75 };
76 
77 const int cRsId::indices[] = {
78 	2, 4, 8, 9, 11, 15, 7, 14, 5, 10, 13, 3
79 };
80 
cRsId()81 cRsId::cRsId()
82 {
83 	int error;
84 	src_state = src_new(progdefaults.sample_converter, 1, &error);
85 	if (error) {
86 		LOG_ERROR("src_new error %d: %s", error, src_strerror(error));
87 		abort();
88 	}
89 	src_data.end_of_input = 0;
90 
91 	reset();
92 
93 	rsfft = new g_fft<rs_fft_type>(RSID_ARRAY_SIZE);
94 
95 	memset(fftwindow, 0, sizeof(fftwindow));
96 
97 	if (RSWINDOW) {
98 		for (int i = 0; i < RSID_ARRAY_SIZE; i++)
99 //		fftwindow[i] = blackman ( 1.0 * i / RSID_ARRAY_SIZE );
100 		fftwindow[i] = hamming ( 1.0 * i / RSID_ARRAY_SIZE );
101 //		fftwindow[i] = hanning ( 1.0 * i / RSID_ARRAY_SIZE );
102 //		fftwindow[i] = 1.0;
103 	}
104 
105 	pCodes1 = new unsigned char[rsid_ids_size1 * RSID_NSYMBOLS];
106 	memset(pCodes1, 0, sizeof(pCodes1) * sizeof(unsigned char));
107 
108 	pCodes2 = new unsigned char[rsid_ids_size2 * RSID_NSYMBOLS];
109 	memset(pCodes2, 0, sizeof(pCodes2) * sizeof(unsigned char));
110 
111 	// Initialization  of assigned mode/submode IDs.
112 	unsigned char* c;
113 	for (int i = 0; i < rsid_ids_size1; i++) {
114 		c = pCodes1 + i * RSID_NSYMBOLS;
115 		Encode(rsid_ids_1[i].rs, c);
116 	}
117 
118 	for (int i = 0; i < rsid_ids_size2; i++) {
119 		c = pCodes2 + i * RSID_NSYMBOLS;
120 		Encode(rsid_ids_2[i].rs, c);
121 	}
122 
123 #if 0
124 	printf("pcode 1\n");
125 	printf(",rs, name, mode,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14\n");
126 	for (int i = 0; i < rsid_ids_size1; i++) {
127 		printf("%d,%d,%s,%d", i, rsid_ids_1[i].rs, rsid_ids_1[i].name, rsid_ids_1[i].mode);
128 		for (int j = 0; j < RSID_NSYMBOLS + 1; j++)
129 			printf(",%d", pCodes1[i*(RSID_NSYMBOLS + 1) + j]);
130 		printf("\n");
131 	}
132 	printf("\npcode 2\n");
133 	printf(", rs, name, mode,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14\n");
134 	for (int i = 0; i < rsid_ids_size2; i++) {
135 		printf("%d,%d,%s,%d", i, rsid_ids_2[i].rs, rsid_ids_2[i].name, rsid_ids_2[i].mode);
136 		for (int j = 0; j < RSID_NSYMBOLS + 1; j++)
137 			printf(",%d", pCodes2[i*(RSID_NSYMBOLS+ 1) + j]);
138 		printf("\n");
139 	}
140 #endif
141 
142 	nBinLow = 3;
143 	nBinHigh = RSID_FFT_SIZE - 32; // - RSID_NTIMES - 2
144 
145 	outbuf = 0;
146 	symlen = 0;
147 
148 	reset();
149 
150 }
151 
~cRsId()152 cRsId::~cRsId()
153 {
154 	delete [] pCodes1;
155 	delete [] pCodes2;
156 
157 	delete [] outbuf;
158 	delete rsfft;
159 	src_delete(src_state);
160 }
161 
reset()162 void cRsId::reset()
163 {
164 	iPrevDistance = iPrevDistance2 = 99;
165 	bPrevTimeSliceValid = bPrevTimeSliceValid2 = false;
166 	found1 = found2 = false;
167 	rsid_secondary_time_out = 0;
168 
169 	memset(aInputSamples, 0, (RSID_ARRAY_SIZE * 2) * sizeof(float));
170 	memset(aFFTAmpl, 0, RSID_FFT_SIZE * sizeof(rs_fft_type));
171 	memset(fft_buckets, 0, RSID_NTIMES * RSID_FFT_SIZE * sizeof(int));
172 
173 	for (int n = 0; n < RSID_ARRAY_SIZE; n++)
174 		aFFTcmplx[n] = cmplx(0,0);
175 
176 	int error = src_reset(src_state);
177 	if (error)
178 		LOG_ERROR("src_reset error %d: %s", error, src_strerror(error));
179 	src_data.src_ratio = 0.0;
180 	inptr = RSID_FFT_SIZE;
181 	hamming_resolution = progdefaults.RsID_label_type;
182 }
183 
Encode(int code,unsigned char * rsid)184 void cRsId::Encode(int code, unsigned char *rsid)
185 {
186 	rsid[0] = code >> 8;
187 	rsid[1] = (code >> 4) & 0x0f;
188 	rsid[2] = code & 0x0f;
189 	for (int i = 3; i < RSID_NSYMBOLS; i++)
190 		rsid[i] = 0;
191 	for (int i = 0; i < 12; i++) {
192 		for (int j = RSID_NSYMBOLS - 1; j > 0; j--)
193 			rsid[j] = rsid[j - 1] ^ Squares[(rsid[j] << 4) + indices[i]];
194 		rsid[0] = Squares[(rsid[0] << 4) + indices[i]];
195 	}
196 }
197 
CalculateBuckets(const rs_fft_type * pSpectrum,int iBegin,int iEnd)198 void cRsId::CalculateBuckets(const rs_fft_type *pSpectrum, int iBegin, int iEnd)
199 {
200 	rs_fft_type Amp = 0.0, AmpMax = 0.0;
201 	int iBucketMax = iBegin - 2;
202 	int j;
203 
204 	for (int i = iBegin; i < iEnd; i += 2) {
205 		if (iBucketMax == i - 2) {
206 			AmpMax = pSpectrum[i];
207 			iBucketMax = i;
208 			for (j = i + 2; j < i + RSID_NTIMES + 2; j += 2) {
209 				Amp = pSpectrum[j];
210 				if (Amp > AmpMax) {
211 					AmpMax = Amp;
212 					iBucketMax = j;
213 				}
214 			}
215 		}
216 		else {
217 			j = i + RSID_NTIMES;
218 			Amp = pSpectrum[j];
219 			if (Amp > AmpMax) {
220 				AmpMax    = Amp;
221 				iBucketMax = j;
222 			}
223 		}
224 		fft_buckets[RSID_NTIMES - 1][i] = (iBucketMax - i) >> 1;
225 	}
226 }
227 
receive(const float * buf,size_t len)228 void cRsId::receive(const float* buf, size_t len)
229 {
230 
231 	if (len == 0) return;
232 
233 	int srclen = static_cast<int>(len);
234 	double src_ratio = RSID_SAMPLE_RATE / active_modem->get_samplerate();
235 
236 	if (rsid_secondary_time_out > 0) {
237 		rsid_secondary_time_out -= 1.0 * len / active_modem->get_samplerate();
238 		if (rsid_secondary_time_out <= 0) {
239 			LOG_INFO("%s", "Secondary RsID timed out");
240 			reset();
241 		}
242 	}
243 
244 	if (src_data.src_ratio != src_ratio) {
245 		src_data.src_ratio = src_ratio;
246 		src_set_ratio(src_state, src_data.src_ratio);
247 	}
248 
249 	while (srclen > 0) {
250 		src_data.data_in = const_cast<float*>(buf);
251 		src_data.input_frames = srclen;
252 		src_data.data_out = &aInputSamples[inptr];
253 		src_data.output_frames = RSID_ARRAY_SIZE * 2 - inptr;
254 		src_data.input_frames_used = 0;
255 		int error = src_process(src_state, &src_data);
256 		if (unlikely(error)) {
257 			LOG_ERROR("src_process error %d: %s", error, src_strerror(error));
258 			return;
259 		}
260 		size_t gend = src_data.output_frames_gen;
261 		size_t used = src_data.input_frames_used;
262 		inptr += gend;
263 		buf += used;
264 		srclen -= used;
265 
266 		while (inptr >= RSID_ARRAY_SIZE) {
267 			search();
268 			memmove(&aInputSamples[0], &aInputSamples[RSID_FFT_SAMPLES],
269 					(RSID_BUFFER_SIZE - RSID_FFT_SAMPLES)*sizeof(float));
270 			inptr -= RSID_FFT_SAMPLES;
271 		}
272 	}
273 }
274 
search(void)275 void cRsId::search(void)
276 {
277 	if (progdefaults.rsidWideSearch) {
278 		nBinLow = 3;
279 		nBinHigh = RSID_FFT_SIZE - 32;
280 	}
281 	else {
282 		float centerfreq = active_modem->get_freq();
283 		float bpf = 1.0 * RSID_ARRAY_SIZE / RSID_SAMPLE_RATE;
284 		nBinLow = (int)((centerfreq  - 100.0 * 2) * bpf);
285 		nBinHigh = (int)((centerfreq  + 100.0 * 2) * bpf);
286 	}
287 	if (nBinLow < 3) nBinLow = 3;
288 	if (nBinHigh > RSID_FFT_SIZE - 32) nBinHigh = RSID_FFT_SIZE - 32;
289 
290 	bool bReverse = !(wf->Reverse() ^ wf->USB());
291 	if (bReverse) {
292 		nBinLow  = RSID_FFT_SIZE - nBinHigh;
293 		nBinHigh = RSID_FFT_SIZE - nBinLow;
294 	}
295 
296 	if (RSWINDOW) {
297 		for (int i = 0; i < RSID_ARRAY_SIZE; i++)
298 			aFFTcmplx[i] = cmplx(aInputSamples[i] * fftwindow[i], 0);
299 	} else {
300 		for (int i = 0; i < RSID_ARRAY_SIZE; i++)
301 			aFFTcmplx[i] = cmplx(aInputSamples[i], 0);
302 	}
303 
304 	rsfft->ComplexFFT(aFFTcmplx);
305 
306 	memset(aFFTAmpl, 0, sizeof(aFFTAmpl));
307 
308 	static const double pscale = 4.0 / (RSID_FFT_SIZE * RSID_FFT_SIZE);
309 
310 	if (unlikely(bReverse)) {
311 		for (int i = 0; i < RSID_FFT_SIZE; i++)
312 			aFFTAmpl[RSID_FFT_SIZE - 1 - i] = norm(aFFTcmplx[i]) * pscale;
313 	} else {
314 		for (int i = 0; i < RSID_FFT_SIZE; i++)
315 			aFFTAmpl[i] = norm(aFFTcmplx[i]) * pscale;
316 	}
317 
318 	int bucket_low = 3;
319 	int bucket_high = RSID_FFT_SIZE - 32;
320 	if (bReverse) {
321 		bucket_low  = RSID_FFT_SIZE - bucket_high;
322 		bucket_high = RSID_FFT_SIZE - bucket_low;
323 	}
324 
325 	memmove(fft_buckets,
326 			&(fft_buckets[1][0]),
327 			(RSID_NTIMES - 1) * RSID_FFT_SIZE * sizeof(int));
328 	memset(&(fft_buckets[RSID_NTIMES - 1][0]), 0, RSID_FFT_SIZE * sizeof(int));
329 
330 	CalculateBuckets ( aFFTAmpl, bucket_low,  bucket_high - RSID_NTIMES);
331 	CalculateBuckets ( aFFTAmpl, bucket_low + 1, bucket_high - RSID_NTIMES);
332 
333 	int symbol_out_1 = -1;
334 	int bin_out_1    = -1;
335 	int symbol_out_2 = -1;
336 	int bin_out_2    = -1;
337 
338 	if (rsid_secondary_time_out <= 0) {
339 		found1 = search_amp(bin_out_1, symbol_out_1, pCodes1);
340 		if (found1) {
341 			if (symbol_out_1 != RSID_ESCAPE) {
342 				if (bReverse)
343 					bin_out_1 = 1024 - bin_out_1 - 31;
344 				apply(bin_out_1, symbol_out_1, 0);
345 				reset();
346 				return;
347 			} else {
348 				// 10 rsid_gap + 15 symbols + 2 for timing errors
349 				rsid_secondary_time_out = 27 * RSID_SYMLEN;
350 				return;
351 			}
352 		} else
353 			return;
354 	}
355 
356 	found2 = search_amp(bin_out_2, symbol_out_2, pCodes2);
357 	if (found2) {
358 		if (symbol_out_2 != RSID_NONE2) {
359 			if (bReverse)
360 				bin_out_2 = 1024 - bin_out_2 - 31;
361 			apply(bin_out_2, symbol_out_2, 1);
362 		}
363 		reset();
364 	}
365 
366 }
367 
setup_mode(int iSymbol)368 void cRsId::setup_mode(int iSymbol)
369 {
370 	switch (iSymbol) {
371 	case RSID_RTTY_ASCII_7:
372 		progdefaults.rtty_baud = 5;
373 		progdefaults.rtty_bits = 1;
374 		progdefaults.rtty_shift = 9;
375 		REQ(&set_rtty_tab_widgets);
376 		break;
377 	case RSID_RTTY_ASCII_8:
378 		progdefaults.rtty_baud = 5;
379 		progdefaults.rtty_bits = 2;
380 		progdefaults.rtty_shift = 9;
381 		REQ(&set_rtty_tab_widgets);
382 		break;
383 	case RSID_RTTY_45:
384 		progdefaults.rtty_baud = 1;
385 		progdefaults.rtty_bits = 0;
386 		progdefaults.rtty_shift = 3;
387 		REQ(&set_rtty_tab_widgets);
388 		break;
389 	case RSID_RTTY_50:
390 		progdefaults.rtty_baud = 2;
391 		progdefaults.rtty_bits = 0;
392 		progdefaults.rtty_shift = 3;
393 		REQ(&set_rtty_tab_widgets);
394 		break;
395 	case RSID_RTTY_75:
396 		progdefaults.rtty_baud = 4;
397 		progdefaults.rtty_bits = 0;
398 		progdefaults.rtty_shift = 9;
399 		REQ(&set_rtty_tab_widgets);
400 		break;
401 // DominoEX / FEC
402 	case RSID_DOMINOEX_4: case RSID_DOMINOEX_5: case RSID_DOMINOEX_8:
403 	case RSID_DOMINOEX_11: case RSID_DOMINOEX_16: case RSID_DOMINOEX_22:
404 		progdefaults.DOMINOEX_FEC = false;
405 		REQ(&set_dominoex_tab_widgets);
406 		break;
407 	case RSID_DOMINOEX_4_FEC: case RSID_DOMINOEX_5_FEC: case RSID_DOMINOEX_8_FEC:
408 	case RSID_DOMINOEX_11_FEC: case RSID_DOMINOEX_16_FEC: case RSID_DOMINOEX_22_FEC:
409 		progdefaults.DOMINOEX_FEC = true;
410 		REQ(&set_dominoex_tab_widgets);
411 		break;
412 // olivia parameters
413 	case RSID_OLIVIA_4_125:
414 		progdefaults.oliviatones = 1;
415 		progdefaults.oliviabw = 0;
416 		REQ(&set_olivia_tab_widgets);
417 		break;
418 	case RSID_OLIVIA_4_250:
419 		progdefaults.oliviatones = 1;
420 		progdefaults.oliviabw = 1;
421 		REQ(&set_olivia_tab_widgets);
422 		break;
423 	case RSID_OLIVIA_4_500:
424 		progdefaults.oliviatones = 1;
425 		progdefaults.oliviabw = 2;
426 		REQ(&set_olivia_tab_widgets);
427 		break;
428 	case RSID_OLIVIA_4_1000:
429 		progdefaults.oliviatones = 1;
430 		progdefaults.oliviabw = 3;
431 		REQ(&set_olivia_tab_widgets);
432 		break;
433 	case RSID_OLIVIA_4_2000:
434 		progdefaults.oliviatones = 1;
435 		progdefaults.oliviabw = 4;
436 		REQ(&set_olivia_tab_widgets);
437 		break;
438 	case RSID_OLIVIA_8_125:
439 		progdefaults.oliviatones = 2;
440 		progdefaults.oliviabw = 0;
441 		REQ(&set_olivia_tab_widgets);
442 		break;
443 	case RSID_OLIVIA_8_250:
444 		progdefaults.oliviatones = 2;
445 		progdefaults.oliviabw = 1;
446 		REQ(&set_olivia_tab_widgets);
447 		break;
448 	case RSID_OLIVIA_8_500:
449 		progdefaults.oliviatones = 2;
450 		progdefaults.oliviabw = 2;
451 		REQ(&set_olivia_tab_widgets);
452 		break;
453 	case RSID_OLIVIA_8_1000:
454 		progdefaults.oliviatones = 2;
455 		progdefaults.oliviabw = 3;
456 		REQ(&set_olivia_tab_widgets);
457 		break;
458 	case RSID_OLIVIA_8_2000:
459 		progdefaults.oliviatones = 2;
460 		progdefaults.oliviabw = 4;
461 		REQ(&set_olivia_tab_widgets);
462 		break;
463 	case RSID_OLIVIA_16_500:
464 		progdefaults.oliviatones = 3;
465 		progdefaults.oliviabw = 2;
466 		REQ(&set_olivia_tab_widgets);
467 		break;
468 	case RSID_OLIVIA_16_1000:
469 		progdefaults.oliviatones = 3;
470 		progdefaults.oliviabw = 3;
471 		REQ(&set_olivia_tab_widgets);
472 		break;
473 	case RSID_OLIVIA_16_2000:
474 		progdefaults.oliviatones = 3;
475 		progdefaults.oliviabw = 4;
476 		REQ(&set_olivia_tab_widgets);
477 		break;
478 	case RSID_OLIVIA_32_1000:
479 		progdefaults.oliviatones = 4;
480 		progdefaults.oliviabw = 3;
481 		REQ(&set_olivia_tab_widgets);
482 		break;
483 	case RSID_OLIVIA_32_2000:
484 		progdefaults.oliviatones = 4;
485 		progdefaults.oliviabw = 4;
486 		REQ(&set_olivia_tab_widgets);
487 		break;
488 	case RSID_OLIVIA_64_2000:
489 		progdefaults.oliviatones = 5;
490 		progdefaults.oliviabw = 4;
491 		REQ(&set_olivia_tab_widgets);
492 		break;
493 // contestia parameters
494 	case RSID_CONTESTIA_4_125:
495 		progdefaults.contestiatones = 1;
496 		progdefaults.contestiabw = 0;
497 		REQ(&set_contestia_tab_widgets);
498 		break;
499 	case RSID_CONTESTIA_4_250:
500 		progdefaults.contestiatones = 1;
501 		progdefaults.contestiabw = 1;
502 		REQ(&set_contestia_tab_widgets);
503 		break;
504 	case RSID_CONTESTIA_4_500:
505 		progdefaults.contestiatones = 1;
506 		progdefaults.contestiabw = 2;
507 		REQ(&set_contestia_tab_widgets);
508 		break;
509 	case RSID_CONTESTIA_4_1000:
510 		progdefaults.contestiatones = 1;
511 		progdefaults.contestiabw = 3;
512 		REQ(&set_contestia_tab_widgets);
513 		break;
514 	case RSID_CONTESTIA_4_2000:
515 		progdefaults.contestiatones = 1;
516 		progdefaults.contestiabw = 4;
517 		REQ(&set_contestia_tab_widgets);
518 		break;
519 	case RSID_CONTESTIA_8_125:
520 		progdefaults.contestiatones = 2;
521 		progdefaults.contestiabw = 0;
522 		REQ(&set_contestia_tab_widgets);
523 		break;
524 	case RSID_CONTESTIA_8_250:
525 		progdefaults.contestiatones = 2;
526 		progdefaults.contestiabw = 1;
527 		REQ(&set_contestia_tab_widgets);
528 		break;
529 	case RSID_CONTESTIA_8_500:
530 		progdefaults.contestiatones = 2;
531 		progdefaults.contestiabw = 2;
532 		REQ(&set_contestia_tab_widgets);
533 		break;
534 	case RSID_CONTESTIA_8_1000:
535 		progdefaults.contestiatones = 2;
536 		progdefaults.contestiabw = 3;
537 		REQ(&set_contestia_tab_widgets);
538 		break;
539 	case RSID_CONTESTIA_8_2000:
540 		progdefaults.contestiatones = 2;
541 		progdefaults.contestiabw = 4;
542 		REQ(&set_contestia_tab_widgets);
543 		break;
544 	case RSID_CONTESTIA_16_500:
545 		progdefaults.contestiatones = 3;
546 		progdefaults.contestiabw = 2;
547 		REQ(&set_contestia_tab_widgets);
548 		break;
549 	case RSID_CONTESTIA_16_1000:
550 		progdefaults.contestiatones = 3;
551 		progdefaults.contestiabw = 3;
552 		REQ(&set_contestia_tab_widgets);
553 		break;
554 	case RSID_CONTESTIA_16_2000:
555 		progdefaults.contestiatones = 3;
556 		progdefaults.contestiabw = 4;
557 		REQ(&set_contestia_tab_widgets);
558 		break;
559 	case RSID_CONTESTIA_32_1000:
560 		progdefaults.contestiatones = 4;
561 		progdefaults.contestiabw = 3;
562 		REQ(&set_contestia_tab_widgets);
563 		break;
564 	case RSID_CONTESTIA_32_2000:
565 		progdefaults.contestiatones = 4;
566 		progdefaults.contestiabw = 4;
567 		REQ(&set_contestia_tab_widgets);
568 		break;
569 	case RSID_CONTESTIA_64_500:
570 		progdefaults.contestiatones = 5;
571 		progdefaults.contestiabw = 2;
572 		REQ(&set_contestia_tab_widgets);
573 		break;
574 	case RSID_CONTESTIA_64_1000:
575 		progdefaults.contestiatones = 5;
576 		progdefaults.contestiabw = 3;
577 		REQ(&set_contestia_tab_widgets);
578 		break;
579 	case RSID_CONTESTIA_64_2000:
580 		progdefaults.contestiatones = 5;
581 		progdefaults.contestiabw = 4;
582 		REQ(&set_contestia_tab_widgets);
583 		break;
584 	default:
585 		break;
586 	} // switch (iSymbol)
587 }
588 
apply(int iBin,int iSymbol,int extended)589 void cRsId::apply(int iBin, int iSymbol, int extended)
590 {
591 	ENSURE_THREAD(TRX_TID);
592 
593 	double rsidfreq = 0, currfreq = 0;
594 	int n, mbin = NUM_MODES;
595 
596 	int tblsize;
597 	const RSIDs *p_rsid;
598 
599 	if (extended) {
600 		tblsize = rsid_ids_size2;
601 		p_rsid = rsid_ids_2;
602 	}
603 	else {
604 		tblsize = rsid_ids_size1;
605 		p_rsid = rsid_ids_1;
606 	}
607 
608 	currfreq = active_modem->get_freq();
609 	rsidfreq = (iBin + RSID_NSYMBOLS - 0.5) * RSID_SAMPLE_RATE / 2048.0;
610 
611 	for (n = 0; n < tblsize; n++) {
612 		if (p_rsid[n].rs == iSymbol) {
613 			mbin = p_rsid[n].mode;
614 			break;
615 		}
616 	}
617 
618 	if (mbin == NUM_MODES) {
619 		char msg[50];
620 		if (n < tblsize) // RSID known but unimplemented
621 			snprintf(msg, sizeof(msg), "RSID: %s unimplemented",
622 				p_rsid[n].name);
623 		else // RSID unknown; shouldn't  happen
624 			snprintf(msg, sizeof(msg), "RSID: code %d unknown", iSymbol);
625 		put_status(msg, 4.0);
626 		LOG_VERBOSE("%s", msg);
627 		return;
628 	}
629 
630 	if (progdefaults.rsid_rx_modes.test(mbin)) {
631 		LOG_VERBOSE("RSID: %s @ %0.1f Hz",
632 			p_rsid[n].name, rsidfreq);
633 	}
634 	else {
635 		LOG_DEBUG("Ignoring RSID: %s @ %0.1f Hz",
636 			p_rsid[n].name, rsidfreq);
637 		return;
638 	}
639 
640 	if (progdefaults.ENABLE_RSID_MATCH)
641 		audio_alert->alert(progdefaults.RSID_MATCH);
642 
643 	if (mailclient || mailserver)
644 		REQ(pskmail_notify_rsid, mbin);
645 
646 	if (progdefaults.rsid_auto_disable)
647 		REQ(toggleRSID);
648 
649 	if (!progdefaults.disable_rsid_warning_dialog_box)
650 		REQ(notify_rsid, mbin, rsidfreq);
651 
652 	if (progdefaults.rsid_notify_only) {
653 		if (data_io_enabled == KISS_IO) {
654 			bcast_rsid_kiss_frame(rsidfreq, mbin, (int) active_modem->get_txfreq_woffset(),
655 								  active_modem->get_mode(), RSID_KISS_NOTIFY);
656 		}
657 		return;
658 	}
659 
660 	if (progdefaults.rsid_mark) // mark current modem & freq
661 		REQ(note_qrg, false, "\nBefore RSID: ", "\n",
662 			active_modem->get_mode(), 0LL, currfreq);
663 
664 	if(active_modem) // Currently only effects Olivia, Contestia and MT63.
665 		active_modem->rx_flush();
666 
667 	setup_mode(iSymbol);
668 
669 	if (progdefaults.rsid_squelch)
670 		REQ(init_modem_squelch, mbin, progdefaults.disable_rsid_freq_change ? currfreq : rsidfreq);
671 	else
672 		REQ(init_modem, mbin, progdefaults.disable_rsid_freq_change ? currfreq : rsidfreq);
673 
674 }
675 
HammingDistance(int iBucket,unsigned char * p2)676 inline int cRsId::HammingDistance(int iBucket, unsigned char *p2)
677 {
678 	int dist = 0;
679 	for (int i = 0, j = 1; i < RSID_NSYMBOLS; i++, j += 2) {
680 		if (fft_buckets[j][iBucket] != p2[i]) {
681 			++dist;
682 			if (dist > hamming_resolution)
683 				break;
684 		}
685 	}
686 	return dist;
687 }
688 
search_amp(int & bin_out,int & symbol_out,unsigned char * pcode)689 bool cRsId::search_amp( int &bin_out, int &symbol_out, unsigned char *pcode)
690 {
691 	int i, j;
692 	int iDistanceMin = 1000;  // infinity
693 	int iDistance    = 1000;
694 	int iBin         = -1;
695 	int iSymbol      = -1;
696 
697 	int tblsize;
698 	const RSIDs *prsid;
699 
700 	if (pcode == pCodes1) {
701 		tblsize = rsid_ids_size1;
702 		prsid = rsid_ids_1;
703 	} else {
704 		tblsize = rsid_ids_size2;
705 		prsid = rsid_ids_2;
706 	}
707 
708 	unsigned char *pc = 0;
709 	for (i = 0; i < tblsize; i++) {
710 		pc = pcode + i * RSID_NSYMBOLS;
711 		for (j = nBinLow; j < nBinHigh - RSID_NTIMES; j++) {
712 			iDistance = HammingDistance(j, pc);
713 			if (iDistance < iDistanceMin) {
714 				iDistanceMin = iDistance;
715 				iSymbol  	 = prsid[i].rs;
716 				iBin		 = j;
717 				if (iDistanceMin == 0) break;
718 			}
719 		}
720 	}
721 
722 	if (iDistanceMin <= hamming_resolution) {
723 		symbol_out	= iSymbol;
724 		bin_out		= iBin;
725 		return true;
726 	}
727 
728 	return false;
729 }
730 
731 //=============================================================================
732 // transmit rsid code for current mode
733 //=============================================================================
734 
assigned(trx_mode mode)735 bool cRsId::assigned(trx_mode mode) {
736 
737 	rmode = RSID_NONE;
738 	rmode2 = RSID_NONE2;
739 
740 	switch (mode) {
741 	case MODE_RTTY :
742 		if (progdefaults.rtty_baud == 5 && progdefaults.rtty_bits == 1 && progdefaults.rtty_shift == 9)
743 			rmode = RSID_RTTY_ASCII_7;
744 		else if (progdefaults.rtty_baud == 5 && progdefaults.rtty_bits == 1 && progdefaults.rtty_shift == 9)
745 			rmode = RSID_RTTY_ASCII_8;
746 		else if (progdefaults.rtty_baud == 1 && progdefaults.rtty_bits == 0 && progdefaults.rtty_shift == 3)
747 			rmode = RSID_RTTY_45;
748 		else if (progdefaults.rtty_baud == 2 && progdefaults.rtty_bits == 0 && progdefaults.rtty_shift == 3)
749 			rmode = RSID_RTTY_50;
750 		else if (progdefaults.rtty_baud == 4 && progdefaults.rtty_bits == 0 && progdefaults.rtty_shift == 9)
751 			rmode = RSID_RTTY_75;
752 		else
753 			return false;
754 		return true;
755 		break;
756 
757 	case MODE_OLIVIA:
758 	case MODE_OLIVIA_4_250:
759 	case MODE_OLIVIA_8_250:
760 	case MODE_OLIVIA_4_500:
761 	case MODE_OLIVIA_8_500:
762 	case MODE_OLIVIA_16_500:
763 	case MODE_OLIVIA_8_1000:
764 	case MODE_OLIVIA_16_1000:
765 	case MODE_OLIVIA_32_1000:
766 	case MODE_OLIVIA_64_2000:
767 		if (progdefaults.oliviatones == 1 && progdefaults.oliviabw == 0)
768 			rmode = RSID_OLIVIA_4_125;
769 		else if (progdefaults.oliviatones == 1 && progdefaults.oliviabw == 1)
770 			rmode = RSID_OLIVIA_4_250;
771 		else if (progdefaults.oliviatones == 1 && progdefaults.oliviabw == 2)
772 			rmode = RSID_OLIVIA_4_500;
773 		else if (progdefaults.oliviatones == 1 && progdefaults.oliviabw == 3)
774 			rmode = RSID_OLIVIA_4_1000;
775 		else if (progdefaults.oliviatones == 1 && progdefaults.oliviabw == 4)
776 			rmode = RSID_OLIVIA_4_2000;
777 
778 		else if (progdefaults.oliviatones == 2 && progdefaults.oliviabw == 0)
779 			rmode = RSID_OLIVIA_8_125;
780 		else if (progdefaults.oliviatones == 2 && progdefaults.oliviabw == 1)
781 			rmode = RSID_OLIVIA_8_250;
782 		else if (progdefaults.oliviatones == 2 && progdefaults.oliviabw == 2)
783 			rmode = RSID_OLIVIA_8_500;
784 		else if (progdefaults.oliviatones == 2 && progdefaults.oliviabw == 3)
785 			rmode = RSID_OLIVIA_8_1000;
786 		else if (progdefaults.oliviatones == 2 && progdefaults.oliviabw == 4)
787 			rmode = RSID_OLIVIA_8_2000;
788 
789 		else if (progdefaults.oliviatones == 3 && progdefaults.oliviabw == 2)
790 			rmode = RSID_OLIVIA_16_500;
791 		else if (progdefaults.oliviatones == 3 && progdefaults.oliviabw == 3)
792 			rmode = RSID_OLIVIA_16_1000;
793 		else if (progdefaults.oliviatones == 3 && progdefaults.oliviabw == 4)
794 			rmode = RSID_OLIVIA_16_2000;
795 
796 		else if (progdefaults.oliviatones == 4 && progdefaults.oliviabw == 3)
797 			rmode = RSID_OLIVIA_32_1000;
798 		else if (progdefaults.oliviatones == 4 && progdefaults.oliviabw == 4)
799 			rmode = RSID_OLIVIA_32_2000;
800 
801 		else if (progdefaults.oliviatones == 5 && progdefaults.oliviabw == 4)
802 			rmode = RSID_OLIVIA_64_2000;
803 
804 		else
805 			return false;
806 		return true;
807 		break;
808 
809 	case MODE_CONTESTIA:
810 	case MODE_CONTESTIA_4_125:
811 	case MODE_CONTESTIA_4_250:
812 	case MODE_CONTESTIA_8_250:
813 	case MODE_CONTESTIA_4_500:
814 	case MODE_CONTESTIA_8_500:
815 	case MODE_CONTESTIA_16_500:
816 	case MODE_CONTESTIA_8_1000:
817 	case MODE_CONTESTIA_16_1000:
818 	case MODE_CONTESTIA_32_1000:
819 	case MODE_CONTESTIA_64_2000:
820 		if (progdefaults.contestiatones == 1 && progdefaults.contestiabw == 0)
821 			rmode = RSID_CONTESTIA_4_125;
822 		else if (progdefaults.contestiatones == 1 && progdefaults.contestiabw == 1)
823 			rmode = RSID_CONTESTIA_4_250;
824 		else if (progdefaults.contestiatones == 1 && progdefaults.contestiabw == 2)
825 			rmode = RSID_CONTESTIA_4_500;
826 		else if (progdefaults.contestiatones == 1 && progdefaults.contestiabw == 3)
827 			rmode = RSID_CONTESTIA_4_1000;
828 		else if (progdefaults.contestiatones == 1 && progdefaults.contestiabw == 4)
829 			rmode = RSID_CONTESTIA_4_2000;
830 
831 		else if (progdefaults.contestiatones == 2 && progdefaults.contestiabw == 0)
832 			rmode = RSID_CONTESTIA_8_125;
833 		else if (progdefaults.contestiatones == 2 && progdefaults.contestiabw == 1)
834 			rmode = RSID_CONTESTIA_8_250;
835 		else if (progdefaults.contestiatones == 2 && progdefaults.contestiabw == 2)
836 			rmode = RSID_CONTESTIA_8_500;
837 		else if (progdefaults.contestiatones == 2 && progdefaults.contestiabw == 3)
838 			rmode = RSID_CONTESTIA_8_1000;
839 		else if (progdefaults.contestiatones == 2 && progdefaults.contestiabw == 4)
840 			rmode = RSID_CONTESTIA_8_2000;
841 
842 		else if (progdefaults.contestiatones == 3 && progdefaults.contestiabw == 2)
843 			rmode = RSID_CONTESTIA_16_500;
844 		else if (progdefaults.contestiatones == 3 && progdefaults.contestiabw == 3)
845 			rmode = RSID_CONTESTIA_16_1000;
846 		else if (progdefaults.contestiatones == 3 && progdefaults.contestiabw == 4)
847 			rmode = RSID_CONTESTIA_16_2000;
848 
849 		else if (progdefaults.contestiatones == 4 && progdefaults.contestiabw == 3)
850 			rmode = RSID_CONTESTIA_32_1000;
851 		else if (progdefaults.contestiatones == 4 && progdefaults.contestiabw == 4)
852 			rmode = RSID_CONTESTIA_32_2000;
853 
854 		else if (progdefaults.contestiatones == 5 && progdefaults.contestiabw == 2)
855 			rmode = RSID_CONTESTIA_64_500;
856 		else if (progdefaults.contestiatones == 5 && progdefaults.contestiabw == 3)
857 			rmode = RSID_CONTESTIA_64_1000;
858 		else if (progdefaults.contestiatones == 5 && progdefaults.contestiabw == 4)
859 			rmode = RSID_CONTESTIA_64_2000;
860 
861 		else
862 			return false;
863 		return true;
864 		break;
865 
866 	case MODE_DOMINOEX4:
867 		if (progdefaults.DOMINOEX_FEC)
868 			rmode = RSID_DOMINOEX_4_FEC;
869 		break;
870 	case MODE_DOMINOEX5:
871 		if (progdefaults.DOMINOEX_FEC)
872 			rmode = RSID_DOMINOEX_5_FEC;
873 		break;
874 	case MODE_DOMINOEX8:
875 		if (progdefaults.DOMINOEX_FEC)
876 			rmode = RSID_DOMINOEX_8_FEC;
877 		break;
878 	case MODE_DOMINOEX11:
879 		if (progdefaults.DOMINOEX_FEC)
880 			rmode = RSID_DOMINOEX_11_FEC;
881 		break;
882 	case MODE_DOMINOEX16:
883 		if (progdefaults.DOMINOEX_FEC)
884 			rmode = RSID_DOMINOEX_16_FEC;
885 		break;
886 	case MODE_DOMINOEX22:
887 		if (progdefaults.DOMINOEX_FEC)
888 			rmode = RSID_DOMINOEX_22_FEC;
889 		break;
890 
891 	case MODE_MT63_500S:
892 		rmode = RSID_MT63_500_ST;
893 		break;
894 	case MODE_MT63_500L:
895 		rmode = RSID_MT63_500_LG;
896 		break;
897 	case MODE_MT63_1000S:
898 		rmode = RSID_MT63_1000_ST;
899 		break;
900 	case MODE_MT63_1000L:
901 		rmode = RSID_MT63_1000_LG;
902 		break;
903 	case MODE_MT63_2000S:
904 		rmode = RSID_MT63_2000_ST;
905 		break;
906 	case MODE_MT63_2000L:
907 		rmode = RSID_MT63_2000_LG;
908 		break;
909 	}
910 
911 // if rmode is still unset, look it up
912 // Try secondary table first
913 	if (rmode == RSID_NONE) {
914 		for (size_t i = 0; i < sizeof(rsid_ids_2)/sizeof(*rsid_ids_2); i++) {
915 			if (mode == rsid_ids_2[i].mode) {
916 				rmode = RSID_ESCAPE;
917 				rmode2 = rsid_ids_2[i].rs;
918 				break;
919 			}
920 		}
921 		if (rmode2 == RSID_NONE2) {
922 			for (size_t i = 0; i < sizeof(rsid_ids_1)/sizeof(*rsid_ids_1); i++) {
923 				if (mode == rsid_ids_1[i].mode) {
924 					rmode = rsid_ids_1[i].rs;
925 					break;
926 				}
927 			}
928 		}
929 	}
930 	if (rmode == RSID_NONE) {
931 		LOG_DEBUG("%s mode is not assigned an RSID", mode_info[mode].sname);
932 		return false;
933 	}
934 	return true;
935 }
936 
send(bool preRSID)937 void cRsId::send(bool preRSID)
938 {
939 	trx_mode mode = active_modem->get_mode();
940 
941 	if (!progdefaults.rsid_tx_modes.test(mode)) {
942 		LOG_DEBUG("Mode %s excluded, not sending RSID", mode_info[mode].sname);
943 		return;
944 	}
945 
946 	if (!progdefaults.rsid_post && !preRSID)
947 		return;
948 
949 	if (!assigned(mode)) return;
950 
951 	unsigned char rsid[RSID_NSYMBOLS];
952 	double sr;
953 	size_t len;
954 	int iTone;
955 	double freq, phaseincr;
956 	double fr;
957 	double phase;
958 
959 	Encode(rmode, rsid);
960 	sr = active_modem->get_samplerate();
961 	len = (size_t)floor(RSID_SYMLEN * sr);
962 	if (unlikely(len != symlen)) {
963 		symlen = len;
964 		delete [] outbuf;
965 		outbuf = new double[symlen];
966 	}
967 
968 // transmit 5 symbol periods of silence at beginning of rsid
969 	memset(outbuf, 0, symlen * sizeof(*outbuf));
970 	for (int i = 0; i < 5; i++)
971 		active_modem->ModulateXmtr(outbuf, symlen);
972 
973 // transmit sequence of 15 symbols (tones)
974 	fr = 1.0 * active_modem->get_txfreq_woffset() - (RSID_SAMPLE_RATE * 7 / 1024);
975 	phase = 0.0;
976 
977 	for (int i = 0; i < 15; i++) {
978 		iTone = rsid[i];
979 		if (active_modem->get_reverse())
980 		iTone = 15 - iTone;
981 		freq = fr + iTone * RSID_SAMPLE_RATE / 1024;
982 		phaseincr = 2.0 * M_PI * freq / sr;
983 
984 		for (size_t j = 0; j < symlen; j++) {
985 			phase += phaseincr;
986 			if (phase > 2.0 * M_PI) phase -= 2.0 * M_PI;
987 			outbuf[j] = sin(phase);
988 		}
989 		active_modem->ModulateXmtr(outbuf, symlen);
990 	}
991 
992 	if (rmode == RSID_ESCAPE && rmode2 != RSID_NONE2) {
993 // transmit 10 symbol periods of silence between rsid sequences
994 		memset(outbuf, 0, symlen * sizeof(*outbuf));
995 		for (int i = 0; i < 10; i++)
996 			active_modem->ModulateXmtr(outbuf, symlen);
997 
998 		Encode(rmode2, rsid);
999 		sr = active_modem->get_samplerate();
1000 		len = (size_t)floor(RSID_SYMLEN * sr);
1001 		if (unlikely(len != symlen)) {
1002 			symlen = len;
1003 			delete [] outbuf;
1004 			outbuf = new double[symlen];
1005 		}
1006 // transmit sequence of 15 symbols (tones)
1007 		fr = 1.0 * active_modem->get_txfreq_woffset() - (RSID_SAMPLE_RATE * 7 / 1024);
1008 		phase = 0.0;
1009 
1010 		for (int i = 0; i < 15; i++) {
1011 			iTone = rsid[i];
1012 			if (active_modem->get_reverse())
1013 			iTone = 15 - iTone;
1014 			freq = fr + iTone * RSID_SAMPLE_RATE / 1024;
1015 			phaseincr = 2.0 * M_PI * freq / sr;
1016 
1017 			for (size_t j = 0; j < symlen; j++) {
1018 				phase += phaseincr;
1019 				if (phase > 2.0 * M_PI) phase -= 2.0 * M_PI;
1020 				outbuf[j] = sin(phase);
1021 			}
1022 			active_modem->ModulateXmtr(outbuf, symlen);
1023 		}
1024 	}
1025 
1026 	// 5 symbol periods of silence at end of transmission
1027 	// and between RsID and the data signal
1028 	int nperiods = 5;
1029 	memset(outbuf, 0, symlen * sizeof(*outbuf));
1030 	for (int i = 0; i < nperiods; i++)
1031 		active_modem->ModulateXmtr(outbuf, symlen);
1032 
1033 }
1034 
1035