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