// ---------------------------------------------------------------------------- // // rsid.cxx // // Copyright (C) 2008-2012 // Dave Freese, W1HKJ // Copyright (C) 2009-2012 // Stelios Bounanos, M0GLD // Copyright (C) 2012 // John Douyere, VK2ETA // // This file is part of fldigi. // // Fldigi is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Fldigi is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with fldigi. If not, see . // ---------------------------------------------------------------------------- #include #include #include #include #include #include #include "rsid.h" #include "filters.h" /* #include "misc.h" #include "trx.h" #include "fl_digi.h" #include "configuration.h" #include "confdialog.h" #include "qrunner.h" #include "notify.h" #include "debug.h" #include "main.h" #include "arq_io.h" #include "data_io.h" #include "audio_alert.h" */ struct RSIDs { unsigned short rs; trx_mode mode; const char* name; }; #include "rsid_defs.cxx" #define RSWINDOW 1 const int cRsId::Squares[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15, 0, 2, 4, 6, 8,10,12,14, 9,11,13,15, 1, 3, 5, 7, 0, 3, 6, 5,12,15,10, 9, 1, 2, 7, 4,13,14,11, 8, 0, 4, 8,12, 9,13, 1, 5,11,15, 3, 7, 2, 6,10,14, 0, 5,10,15,13, 8, 7, 2, 3, 6, 9,12,14,11, 4, 1, 0, 6,12,10, 1, 7,13,11, 2, 4,14, 8, 3, 5,15, 9, 0, 7,14, 9, 5, 2,11,12,10,13, 4, 3,15, 8, 1, 6, 0, 8, 9, 1,11, 3, 2,10,15, 7, 6,14, 4,12,13, 5, 0, 9,11, 2,15, 6, 4,13, 7,14,12, 5, 8, 1, 3,10, 0,10,13, 7, 3, 9,14, 4, 6,12,11, 1, 5,15, 8, 2, 0,11,15, 4, 7,12, 8, 3,14, 5, 1,10, 9, 2, 6,13, 0,12, 1,13, 2,14, 3,15, 4, 8, 5, 9, 6,10, 7,11, 0,13, 3,14, 6,11, 5, 8,12, 1,15, 2,10, 7, 9, 4, 0,14, 5,11,10, 4,15, 1,13, 3, 8, 6, 7, 9, 2,12, 0,15, 7, 8,14, 1, 9, 6, 5,10, 2,13,11, 4,12, 3 }; const int cRsId::indices[] = { 2, 4, 8, 9, 11, 15, 7, 14, 5, 10, 13, 3 }; cRsId::cRsId() { int error; src_state = src_new(progdefaults.sample_converter, 1, &error); if (error) { LOG_ERROR("src_new error %d: %s", error, src_strerror(error)); abort(); } src_data.end_of_input = 0; reset(); rsfft = new g_fft(RSID_ARRAY_SIZE); memset(fftwindow, 0, sizeof(fftwindow)); if (RSWINDOW) { for (int i = 0; i < RSID_ARRAY_SIZE; i++) // fftwindow[i] = blackman ( 1.0 * i / RSID_ARRAY_SIZE ); fftwindow[i] = hamming ( 1.0 * i / RSID_ARRAY_SIZE ); // fftwindow[i] = hanning ( 1.0 * i / RSID_ARRAY_SIZE ); // fftwindow[i] = 1.0; } pCodes1 = new unsigned char[rsid_ids_size1 * RSID_NSYMBOLS]; memset(pCodes1, 0, sizeof(pCodes1) * sizeof(unsigned char)); pCodes2 = new unsigned char[rsid_ids_size2 * RSID_NSYMBOLS]; memset(pCodes2, 0, sizeof(pCodes2) * sizeof(unsigned char)); // Initialization of assigned mode/submode IDs. unsigned char* c; for (int i = 0; i < rsid_ids_size1; i++) { c = pCodes1 + i * RSID_NSYMBOLS; Encode(rsid_ids_1[i].rs, c); } for (int i = 0; i < rsid_ids_size2; i++) { c = pCodes2 + i * RSID_NSYMBOLS; Encode(rsid_ids_2[i].rs, c); } #if 0 printf("pcode 1\n"); printf(",rs, name, mode,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14\n"); for (int i = 0; i < rsid_ids_size1; i++) { printf("%d,%d,%s,%d", i, rsid_ids_1[i].rs, rsid_ids_1[i].name, rsid_ids_1[i].mode); for (int j = 0; j < RSID_NSYMBOLS + 1; j++) printf(",%d", pCodes1[i*(RSID_NSYMBOLS + 1) + j]); printf("\n"); } printf("\npcode 2\n"); printf(", rs, name, mode,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14\n"); for (int i = 0; i < rsid_ids_size2; i++) { printf("%d,%d,%s,%d", i, rsid_ids_2[i].rs, rsid_ids_2[i].name, rsid_ids_2[i].mode); for (int j = 0; j < RSID_NSYMBOLS + 1; j++) printf(",%d", pCodes2[i*(RSID_NSYMBOLS+ 1) + j]); printf("\n"); } #endif nBinLow = 3; nBinHigh = RSID_FFT_SIZE - 32; // - RSID_NTIMES - 2 outbuf = 0; symlen = 0; reset(); } cRsId::~cRsId() { delete [] pCodes1; delete [] pCodes2; delete [] outbuf; delete rsfft; src_delete(src_state); } void cRsId::reset() { iPrevDistance = iPrevDistance2 = 99; bPrevTimeSliceValid = bPrevTimeSliceValid2 = false; found1 = found2 = false; rsid_secondary_time_out = 0; memset(aInputSamples, 0, (RSID_ARRAY_SIZE * 2) * sizeof(float)); memset(aFFTAmpl, 0, RSID_FFT_SIZE * sizeof(rs_fft_type)); memset(fft_buckets, 0, RSID_NTIMES * RSID_FFT_SIZE * sizeof(int)); for (int n = 0; n < RSID_ARRAY_SIZE; n++) aFFTcmplx[n] = cmplx(0,0); int error = src_reset(src_state); if (error) LOG_ERROR("src_reset error %d: %s", error, src_strerror(error)); src_data.src_ratio = 0.0; inptr = RSID_FFT_SIZE; hamming_resolution = progdefaults.RsID_label_type; } void cRsId::Encode(int code, unsigned char *rsid) { rsid[0] = code >> 8; rsid[1] = (code >> 4) & 0x0f; rsid[2] = code & 0x0f; for (int i = 3; i < RSID_NSYMBOLS; i++) rsid[i] = 0; for (int i = 0; i < 12; i++) { for (int j = RSID_NSYMBOLS - 1; j > 0; j--) rsid[j] = rsid[j - 1] ^ Squares[(rsid[j] << 4) + indices[i]]; rsid[0] = Squares[(rsid[0] << 4) + indices[i]]; } } void cRsId::CalculateBuckets(const rs_fft_type *pSpectrum, int iBegin, int iEnd) { rs_fft_type Amp = 0.0, AmpMax = 0.0; int iBucketMax = iBegin - 2; int j; for (int i = iBegin; i < iEnd; i += 2) { if (iBucketMax == i - 2) { AmpMax = pSpectrum[i]; iBucketMax = i; for (j = i + 2; j < i + RSID_NTIMES + 2; j += 2) { Amp = pSpectrum[j]; if (Amp > AmpMax) { AmpMax = Amp; iBucketMax = j; } } } else { j = i + RSID_NTIMES; Amp = pSpectrum[j]; if (Amp > AmpMax) { AmpMax = Amp; iBucketMax = j; } } fft_buckets[RSID_NTIMES - 1][i] = (iBucketMax - i) >> 1; } } void cRsId::receive(const float* buf, size_t len) { if (len == 0) return; int srclen = static_cast(len); double src_ratio = RSID_SAMPLE_RATE / active_modem->get_samplerate(); if (rsid_secondary_time_out > 0) { rsid_secondary_time_out -= 1.0 * len / active_modem->get_samplerate(); if (rsid_secondary_time_out <= 0) { LOG_INFO("%s", "Secondary RsID timed out"); reset(); } } if (src_data.src_ratio != src_ratio) { src_data.src_ratio = src_ratio; src_set_ratio(src_state, src_data.src_ratio); } while (srclen > 0) { src_data.data_in = const_cast(buf); src_data.input_frames = srclen; src_data.data_out = &aInputSamples[inptr]; src_data.output_frames = RSID_ARRAY_SIZE * 2 - inptr; src_data.input_frames_used = 0; int error = src_process(src_state, &src_data); if (unlikely(error)) { LOG_ERROR("src_process error %d: %s", error, src_strerror(error)); return; } size_t gend = src_data.output_frames_gen; size_t used = src_data.input_frames_used; inptr += gend; buf += used; srclen -= used; while (inptr >= RSID_ARRAY_SIZE) { search(); memmove(&aInputSamples[0], &aInputSamples[RSID_FFT_SAMPLES], (RSID_BUFFER_SIZE - RSID_FFT_SAMPLES)*sizeof(float)); inptr -= RSID_FFT_SAMPLES; } } } void cRsId::search(void) { if (progdefaults.rsidWideSearch) { nBinLow = 3; nBinHigh = RSID_FFT_SIZE - 32; } else { float centerfreq = active_modem->get_freq(); float bpf = 1.0 * RSID_ARRAY_SIZE / RSID_SAMPLE_RATE; nBinLow = (int)((centerfreq - 100.0 * 2) * bpf); nBinHigh = (int)((centerfreq + 100.0 * 2) * bpf); } if (nBinLow < 3) nBinLow = 3; if (nBinHigh > RSID_FFT_SIZE - 32) nBinHigh = RSID_FFT_SIZE - 32; bool bReverse = !(wf->Reverse() ^ wf->USB()); if (bReverse) { nBinLow = RSID_FFT_SIZE - nBinHigh; nBinHigh = RSID_FFT_SIZE - nBinLow; } if (RSWINDOW) { for (int i = 0; i < RSID_ARRAY_SIZE; i++) aFFTcmplx[i] = cmplx(aInputSamples[i] * fftwindow[i], 0); } else { for (int i = 0; i < RSID_ARRAY_SIZE; i++) aFFTcmplx[i] = cmplx(aInputSamples[i], 0); } rsfft->ComplexFFT(aFFTcmplx); memset(aFFTAmpl, 0, sizeof(aFFTAmpl)); static const double pscale = 4.0 / (RSID_FFT_SIZE * RSID_FFT_SIZE); if (unlikely(bReverse)) { for (int i = 0; i < RSID_FFT_SIZE; i++) aFFTAmpl[RSID_FFT_SIZE - 1 - i] = norm(aFFTcmplx[i]) * pscale; } else { for (int i = 0; i < RSID_FFT_SIZE; i++) aFFTAmpl[i] = norm(aFFTcmplx[i]) * pscale; } int bucket_low = 3; int bucket_high = RSID_FFT_SIZE - 32; if (bReverse) { bucket_low = RSID_FFT_SIZE - bucket_high; bucket_high = RSID_FFT_SIZE - bucket_low; } memmove(fft_buckets, &(fft_buckets[1][0]), (RSID_NTIMES - 1) * RSID_FFT_SIZE * sizeof(int)); memset(&(fft_buckets[RSID_NTIMES - 1][0]), 0, RSID_FFT_SIZE * sizeof(int)); CalculateBuckets ( aFFTAmpl, bucket_low, bucket_high - RSID_NTIMES); CalculateBuckets ( aFFTAmpl, bucket_low + 1, bucket_high - RSID_NTIMES); int symbol_out_1 = -1; int bin_out_1 = -1; int symbol_out_2 = -1; int bin_out_2 = -1; if (rsid_secondary_time_out <= 0) { found1 = search_amp(bin_out_1, symbol_out_1, pCodes1); if (found1) { if (symbol_out_1 != RSID_ESCAPE) { if (bReverse) bin_out_1 = 1024 - bin_out_1 - 31; apply(bin_out_1, symbol_out_1, 0); reset(); return; } else { // 10 rsid_gap + 15 symbols + 2 for timing errors rsid_secondary_time_out = 27 * RSID_SYMLEN; return; } } else return; } found2 = search_amp(bin_out_2, symbol_out_2, pCodes2); if (found2) { if (symbol_out_2 != RSID_NONE2) { if (bReverse) bin_out_2 = 1024 - bin_out_2 - 31; apply(bin_out_2, symbol_out_2, 1); } reset(); } } void cRsId::setup_mode(int iSymbol) { switch (iSymbol) { case RSID_RTTY_ASCII_7: progdefaults.rtty_baud = 5; progdefaults.rtty_bits = 1; progdefaults.rtty_shift = 9; REQ(&set_rtty_tab_widgets); break; case RSID_RTTY_ASCII_8: progdefaults.rtty_baud = 5; progdefaults.rtty_bits = 2; progdefaults.rtty_shift = 9; REQ(&set_rtty_tab_widgets); break; case RSID_RTTY_45: progdefaults.rtty_baud = 1; progdefaults.rtty_bits = 0; progdefaults.rtty_shift = 3; REQ(&set_rtty_tab_widgets); break; case RSID_RTTY_50: progdefaults.rtty_baud = 2; progdefaults.rtty_bits = 0; progdefaults.rtty_shift = 3; REQ(&set_rtty_tab_widgets); break; case RSID_RTTY_75: progdefaults.rtty_baud = 4; progdefaults.rtty_bits = 0; progdefaults.rtty_shift = 9; REQ(&set_rtty_tab_widgets); break; // DominoEX / FEC case RSID_DOMINOEX_4: case RSID_DOMINOEX_5: case RSID_DOMINOEX_8: case RSID_DOMINOEX_11: case RSID_DOMINOEX_16: case RSID_DOMINOEX_22: progdefaults.DOMINOEX_FEC = false; REQ(&set_dominoex_tab_widgets); break; case RSID_DOMINOEX_4_FEC: case RSID_DOMINOEX_5_FEC: case RSID_DOMINOEX_8_FEC: case RSID_DOMINOEX_11_FEC: case RSID_DOMINOEX_16_FEC: case RSID_DOMINOEX_22_FEC: progdefaults.DOMINOEX_FEC = true; REQ(&set_dominoex_tab_widgets); break; // olivia parameters case RSID_OLIVIA_4_125: progdefaults.oliviatones = 1; progdefaults.oliviabw = 0; REQ(&set_olivia_tab_widgets); break; case RSID_OLIVIA_4_250: progdefaults.oliviatones = 1; progdefaults.oliviabw = 1; REQ(&set_olivia_tab_widgets); break; case RSID_OLIVIA_4_500: progdefaults.oliviatones = 1; progdefaults.oliviabw = 2; REQ(&set_olivia_tab_widgets); break; case RSID_OLIVIA_4_1000: progdefaults.oliviatones = 1; progdefaults.oliviabw = 3; REQ(&set_olivia_tab_widgets); break; case RSID_OLIVIA_4_2000: progdefaults.oliviatones = 1; progdefaults.oliviabw = 4; REQ(&set_olivia_tab_widgets); break; case RSID_OLIVIA_8_125: progdefaults.oliviatones = 2; progdefaults.oliviabw = 0; REQ(&set_olivia_tab_widgets); break; case RSID_OLIVIA_8_250: progdefaults.oliviatones = 2; progdefaults.oliviabw = 1; REQ(&set_olivia_tab_widgets); break; case RSID_OLIVIA_8_500: progdefaults.oliviatones = 2; progdefaults.oliviabw = 2; REQ(&set_olivia_tab_widgets); break; case RSID_OLIVIA_8_1000: progdefaults.oliviatones = 2; progdefaults.oliviabw = 3; REQ(&set_olivia_tab_widgets); break; case RSID_OLIVIA_8_2000: progdefaults.oliviatones = 2; progdefaults.oliviabw = 4; REQ(&set_olivia_tab_widgets); break; case RSID_OLIVIA_16_500: progdefaults.oliviatones = 3; progdefaults.oliviabw = 2; REQ(&set_olivia_tab_widgets); break; case RSID_OLIVIA_16_1000: progdefaults.oliviatones = 3; progdefaults.oliviabw = 3; REQ(&set_olivia_tab_widgets); break; case RSID_OLIVIA_16_2000: progdefaults.oliviatones = 3; progdefaults.oliviabw = 4; REQ(&set_olivia_tab_widgets); break; case RSID_OLIVIA_32_1000: progdefaults.oliviatones = 4; progdefaults.oliviabw = 3; REQ(&set_olivia_tab_widgets); break; case RSID_OLIVIA_32_2000: progdefaults.oliviatones = 4; progdefaults.oliviabw = 4; REQ(&set_olivia_tab_widgets); break; case RSID_OLIVIA_64_2000: progdefaults.oliviatones = 5; progdefaults.oliviabw = 4; REQ(&set_olivia_tab_widgets); break; // contestia parameters case RSID_CONTESTIA_4_125: progdefaults.contestiatones = 1; progdefaults.contestiabw = 0; REQ(&set_contestia_tab_widgets); break; case RSID_CONTESTIA_4_250: progdefaults.contestiatones = 1; progdefaults.contestiabw = 1; REQ(&set_contestia_tab_widgets); break; case RSID_CONTESTIA_4_500: progdefaults.contestiatones = 1; progdefaults.contestiabw = 2; REQ(&set_contestia_tab_widgets); break; case RSID_CONTESTIA_4_1000: progdefaults.contestiatones = 1; progdefaults.contestiabw = 3; REQ(&set_contestia_tab_widgets); break; case RSID_CONTESTIA_4_2000: progdefaults.contestiatones = 1; progdefaults.contestiabw = 4; REQ(&set_contestia_tab_widgets); break; case RSID_CONTESTIA_8_125: progdefaults.contestiatones = 2; progdefaults.contestiabw = 0; REQ(&set_contestia_tab_widgets); break; case RSID_CONTESTIA_8_250: progdefaults.contestiatones = 2; progdefaults.contestiabw = 1; REQ(&set_contestia_tab_widgets); break; case RSID_CONTESTIA_8_500: progdefaults.contestiatones = 2; progdefaults.contestiabw = 2; REQ(&set_contestia_tab_widgets); break; case RSID_CONTESTIA_8_1000: progdefaults.contestiatones = 2; progdefaults.contestiabw = 3; REQ(&set_contestia_tab_widgets); break; case RSID_CONTESTIA_8_2000: progdefaults.contestiatones = 2; progdefaults.contestiabw = 4; REQ(&set_contestia_tab_widgets); break; case RSID_CONTESTIA_16_500: progdefaults.contestiatones = 3; progdefaults.contestiabw = 2; REQ(&set_contestia_tab_widgets); break; case RSID_CONTESTIA_16_1000: progdefaults.contestiatones = 3; progdefaults.contestiabw = 3; REQ(&set_contestia_tab_widgets); break; case RSID_CONTESTIA_16_2000: progdefaults.contestiatones = 3; progdefaults.contestiabw = 4; REQ(&set_contestia_tab_widgets); break; case RSID_CONTESTIA_32_1000: progdefaults.contestiatones = 4; progdefaults.contestiabw = 3; REQ(&set_contestia_tab_widgets); break; case RSID_CONTESTIA_32_2000: progdefaults.contestiatones = 4; progdefaults.contestiabw = 4; REQ(&set_contestia_tab_widgets); break; case RSID_CONTESTIA_64_500: progdefaults.contestiatones = 5; progdefaults.contestiabw = 2; REQ(&set_contestia_tab_widgets); break; case RSID_CONTESTIA_64_1000: progdefaults.contestiatones = 5; progdefaults.contestiabw = 3; REQ(&set_contestia_tab_widgets); break; case RSID_CONTESTIA_64_2000: progdefaults.contestiatones = 5; progdefaults.contestiabw = 4; REQ(&set_contestia_tab_widgets); break; default: break; } // switch (iSymbol) } void cRsId::apply(int iBin, int iSymbol, int extended) { ENSURE_THREAD(TRX_TID); double rsidfreq = 0, currfreq = 0; int n, mbin = NUM_MODES; int tblsize; const RSIDs *p_rsid; if (extended) { tblsize = rsid_ids_size2; p_rsid = rsid_ids_2; } else { tblsize = rsid_ids_size1; p_rsid = rsid_ids_1; } currfreq = active_modem->get_freq(); rsidfreq = (iBin + RSID_NSYMBOLS - 0.5) * RSID_SAMPLE_RATE / 2048.0; for (n = 0; n < tblsize; n++) { if (p_rsid[n].rs == iSymbol) { mbin = p_rsid[n].mode; break; } } if (mbin == NUM_MODES) { char msg[50]; if (n < tblsize) // RSID known but unimplemented snprintf(msg, sizeof(msg), "RSID: %s unimplemented", p_rsid[n].name); else // RSID unknown; shouldn't happen snprintf(msg, sizeof(msg), "RSID: code %d unknown", iSymbol); put_status(msg, 4.0); LOG_VERBOSE("%s", msg); return; } if (progdefaults.rsid_rx_modes.test(mbin)) { char msg[50]; snprintf(msg, sizeof(msg), "RSID: %s @ %0.1f Hz", p_rsid[n].name, rsidfreq); LOG_VERBOSE("%s", msg); } else { char msg[50]; snprintf(msg, sizeof(msg), "Ignoring RSID: %s @ %0.1f Hz", p_rsid[n].name, rsidfreq); LOG_DEBUG("%s", msg); return; } if (progdefaults.ENABLE_RSID_MATCH) audio_alert->alert(progdefaults.RSID_MATCH); if (mailclient || mailserver) REQ(pskmail_notify_rsid, mbin); if (progdefaults.rsid_auto_disable) REQ(toggleRSID); if (iSymbol == RSID_EOT) { if (progdefaults.rsid_eot_squelch) { REQ(rsid_eot_squelch); if (!progdefaults.disable_rsid_warning_dialog_box) REQ(notify_rsid_eot, mbin, rsidfreq); } return; } if (!progdefaults.disable_rsid_warning_dialog_box) REQ(notify_rsid, mbin, rsidfreq); if (progdefaults.rsid_notify_only) { if (data_io_enabled == KISS_IO) { bcast_rsid_kiss_frame(rsidfreq, mbin, (int) active_modem->get_txfreq_woffset(), active_modem->get_mode(), RSID_KISS_NOTIFY); } return; } if (progdefaults.rsid_mark) // mark current modem & freq REQ(note_qrg, false, "\nBefore RSID: ", "\n\n", active_modem->get_mode(), 0LL, currfreq); if(active_modem) // Currently only effects Olivia, Contestia and MT63. active_modem->rx_flush(); setup_mode(iSymbol); if (progdefaults.rsid_squelch) REQ(init_modem_squelch, mbin, progdefaults.disable_rsid_freq_change ? currfreq : rsidfreq); else REQ(init_modem, mbin, progdefaults.disable_rsid_freq_change ? currfreq : rsidfreq); } inline int cRsId::HammingDistance(int iBucket, unsigned char *p2) { int dist = 0; for (int i = 0, j = 1; i < RSID_NSYMBOLS; i++, j += 2) { if (fft_buckets[j][iBucket] != p2[i]) { ++dist; if (dist > hamming_resolution) break; } } return dist; } bool cRsId::search_amp( int &bin_out, int &symbol_out, unsigned char *pcode) { int i, j; int iDistanceMin = 1000; // infinity int iDistance = 1000; int iBin = -1; int iSymbol = -1; int tblsize; const RSIDs *prsid; if (pcode == pCodes1) { tblsize = rsid_ids_size1; prsid = rsid_ids_1; } else { tblsize = rsid_ids_size2; prsid = rsid_ids_2; } unsigned char *pc = 0; for (i = 0; i < tblsize; i++) { pc = pcode + i * RSID_NSYMBOLS; for (j = nBinLow; j < nBinHigh - RSID_NTIMES; j++) { iDistance = HammingDistance(j, pc); if (iDistance < iDistanceMin) { iDistanceMin = iDistance; iSymbol = prsid[i].rs; iBin = j; if (iDistanceMin == 0) break; } } } if (iDistanceMin <= hamming_resolution) { symbol_out = iSymbol; bin_out = iBin; return true; } return false; } //============================================================================= // transmit rsid code for current mode //============================================================================= bool cRsId::assigned(trx_mode mode) { rmode = RSID_NONE; rmode2 = RSID_NONE2; switch (mode) { case MODE_EOT : rmode = RSID_EOT; std::cout << "send RSID_EOT" << std::endl; return true; case MODE_RTTY : if (progdefaults.rtty_baud == 5 && progdefaults.rtty_bits == 1 && progdefaults.rtty_shift == 9) rmode = RSID_RTTY_ASCII_7; else if (progdefaults.rtty_baud == 5 && progdefaults.rtty_bits == 1 && progdefaults.rtty_shift == 9) rmode = RSID_RTTY_ASCII_8; else if (progdefaults.rtty_baud == 1 && progdefaults.rtty_bits == 0 && progdefaults.rtty_shift == 3) rmode = RSID_RTTY_45; else if (progdefaults.rtty_baud == 2 && progdefaults.rtty_bits == 0 && progdefaults.rtty_shift == 3) rmode = RSID_RTTY_50; else if (progdefaults.rtty_baud == 4 && progdefaults.rtty_bits == 0 && progdefaults.rtty_shift == 9) rmode = RSID_RTTY_75; else return false; return true; break; case MODE_OLIVIA: case MODE_OLIVIA_4_250: case MODE_OLIVIA_8_250: case MODE_OLIVIA_4_500: case MODE_OLIVIA_8_500: case MODE_OLIVIA_16_500: case MODE_OLIVIA_8_1000: case MODE_OLIVIA_16_1000: case MODE_OLIVIA_32_1000: case MODE_OLIVIA_64_2000: if (progdefaults.oliviatones == 1 && progdefaults.oliviabw == 0) rmode = RSID_OLIVIA_4_125; else if (progdefaults.oliviatones == 1 && progdefaults.oliviabw == 1) rmode = RSID_OLIVIA_4_250; else if (progdefaults.oliviatones == 1 && progdefaults.oliviabw == 2) rmode = RSID_OLIVIA_4_500; else if (progdefaults.oliviatones == 1 && progdefaults.oliviabw == 3) rmode = RSID_OLIVIA_4_1000; else if (progdefaults.oliviatones == 1 && progdefaults.oliviabw == 4) rmode = RSID_OLIVIA_4_2000; else if (progdefaults.oliviatones == 2 && progdefaults.oliviabw == 0) rmode = RSID_OLIVIA_8_125; else if (progdefaults.oliviatones == 2 && progdefaults.oliviabw == 1) rmode = RSID_OLIVIA_8_250; else if (progdefaults.oliviatones == 2 && progdefaults.oliviabw == 2) rmode = RSID_OLIVIA_8_500; else if (progdefaults.oliviatones == 2 && progdefaults.oliviabw == 3) rmode = RSID_OLIVIA_8_1000; else if (progdefaults.oliviatones == 2 && progdefaults.oliviabw == 4) rmode = RSID_OLIVIA_8_2000; else if (progdefaults.oliviatones == 3 && progdefaults.oliviabw == 2) rmode = RSID_OLIVIA_16_500; else if (progdefaults.oliviatones == 3 && progdefaults.oliviabw == 3) rmode = RSID_OLIVIA_16_1000; else if (progdefaults.oliviatones == 3 && progdefaults.oliviabw == 4) rmode = RSID_OLIVIA_16_2000; else if (progdefaults.oliviatones == 4 && progdefaults.oliviabw == 3) rmode = RSID_OLIVIA_32_1000; else if (progdefaults.oliviatones == 4 && progdefaults.oliviabw == 4) rmode = RSID_OLIVIA_32_2000; else if (progdefaults.oliviatones == 5 && progdefaults.oliviabw == 4) rmode = RSID_OLIVIA_64_2000; else return false; return true; break; case MODE_CONTESTIA: case MODE_CONTESTIA_4_125: case MODE_CONTESTIA_4_250: case MODE_CONTESTIA_8_250: case MODE_CONTESTIA_4_500: case MODE_CONTESTIA_8_500: case MODE_CONTESTIA_16_500: case MODE_CONTESTIA_8_1000: case MODE_CONTESTIA_16_1000: case MODE_CONTESTIA_32_1000: case MODE_CONTESTIA_64_2000: if (progdefaults.contestiatones == 1 && progdefaults.contestiabw == 0) rmode = RSID_CONTESTIA_4_125; else if (progdefaults.contestiatones == 1 && progdefaults.contestiabw == 1) rmode = RSID_CONTESTIA_4_250; else if (progdefaults.contestiatones == 1 && progdefaults.contestiabw == 2) rmode = RSID_CONTESTIA_4_500; else if (progdefaults.contestiatones == 1 && progdefaults.contestiabw == 3) rmode = RSID_CONTESTIA_4_1000; else if (progdefaults.contestiatones == 1 && progdefaults.contestiabw == 4) rmode = RSID_CONTESTIA_4_2000; else if (progdefaults.contestiatones == 2 && progdefaults.contestiabw == 0) rmode = RSID_CONTESTIA_8_125; else if (progdefaults.contestiatones == 2 && progdefaults.contestiabw == 1) rmode = RSID_CONTESTIA_8_250; else if (progdefaults.contestiatones == 2 && progdefaults.contestiabw == 2) rmode = RSID_CONTESTIA_8_500; else if (progdefaults.contestiatones == 2 && progdefaults.contestiabw == 3) rmode = RSID_CONTESTIA_8_1000; else if (progdefaults.contestiatones == 2 && progdefaults.contestiabw == 4) rmode = RSID_CONTESTIA_8_2000; else if (progdefaults.contestiatones == 3 && progdefaults.contestiabw == 2) rmode = RSID_CONTESTIA_16_500; else if (progdefaults.contestiatones == 3 && progdefaults.contestiabw == 3) rmode = RSID_CONTESTIA_16_1000; else if (progdefaults.contestiatones == 3 && progdefaults.contestiabw == 4) rmode = RSID_CONTESTIA_16_2000; else if (progdefaults.contestiatones == 4 && progdefaults.contestiabw == 3) rmode = RSID_CONTESTIA_32_1000; else if (progdefaults.contestiatones == 4 && progdefaults.contestiabw == 4) rmode = RSID_CONTESTIA_32_2000; else if (progdefaults.contestiatones == 5 && progdefaults.contestiabw == 2) rmode = RSID_CONTESTIA_64_500; else if (progdefaults.contestiatones == 5 && progdefaults.contestiabw == 3) rmode = RSID_CONTESTIA_64_1000; else if (progdefaults.contestiatones == 5 && progdefaults.contestiabw == 4) rmode = RSID_CONTESTIA_64_2000; else return false; return true; break; case MODE_DOMINOEX4: if (progdefaults.DOMINOEX_FEC) rmode = RSID_DOMINOEX_4_FEC; break; case MODE_DOMINOEX5: if (progdefaults.DOMINOEX_FEC) rmode = RSID_DOMINOEX_5_FEC; break; case MODE_DOMINOEX8: if (progdefaults.DOMINOEX_FEC) rmode = RSID_DOMINOEX_8_FEC; break; case MODE_DOMINOEX11: if (progdefaults.DOMINOEX_FEC) rmode = RSID_DOMINOEX_11_FEC; break; case MODE_DOMINOEX16: if (progdefaults.DOMINOEX_FEC) rmode = RSID_DOMINOEX_16_FEC; break; case MODE_DOMINOEX22: if (progdefaults.DOMINOEX_FEC) rmode = RSID_DOMINOEX_22_FEC; break; case MODE_MT63_500S: rmode = RSID_MT63_500_ST; break; case MODE_MT63_500L: rmode = RSID_MT63_500_LG; break; case MODE_MT63_1000S: rmode = RSID_MT63_1000_ST; break; case MODE_MT63_1000L: rmode = RSID_MT63_1000_LG; break; case MODE_MT63_2000S: rmode = RSID_MT63_2000_ST; break; case MODE_MT63_2000L: rmode = RSID_MT63_2000_LG; break; } // if rmode is still unset, look it up // Try secondary table first if (rmode == RSID_NONE) { for (size_t i = 0; i < sizeof(rsid_ids_2)/sizeof(*rsid_ids_2); i++) { if (mode == rsid_ids_2[i].mode) { rmode = RSID_ESCAPE; rmode2 = rsid_ids_2[i].rs; break; } } if (rmode2 == RSID_NONE2) { for (size_t i = 0; i < sizeof(rsid_ids_1)/sizeof(*rsid_ids_1); i++) { if (mode == rsid_ids_1[i].mode) { rmode = rsid_ids_1[i].rs; break; } } } } if (rmode == RSID_NONE) { LOG_DEBUG("%s mode is not assigned an RSID", mode_info[mode].sname); return false; } return true; } void cRsId::send_eot() { unsigned char rsid[RSID_NSYMBOLS]; double sr; size_t len; int iTone; double freq, phaseincr; double fr; double phase; Encode(RSID_EOT, rsid); sr = active_modem->get_samplerate(); len = (size_t)floor(RSID_SYMLEN * sr); if (unlikely(len != symlen)) { symlen = len; delete [] outbuf; outbuf = new double[symlen]; } // transmit 5 symbol periods of silence at beginning of rsid memset(outbuf, 0, symlen * sizeof(*outbuf)); for (int i = 0; i < 5; i++) active_modem->ModulateXmtr(outbuf, symlen); // transmit sequence of 15 symbols (tones) fr = 1.0 * active_modem->get_txfreq_woffset() - (RSID_SAMPLE_RATE * 7 / 1024); phase = 0.0; for (int i = 0; i < 15; i++) { iTone = rsid[i]; if (active_modem->get_reverse()) iTone = 15 - iTone; freq = fr + iTone * RSID_SAMPLE_RATE / 1024; phaseincr = 2.0 * M_PI * freq / sr; for (size_t j = 0; j < symlen; j++) { phase += phaseincr; if (phase > 2.0 * M_PI) phase -= 2.0 * M_PI; outbuf[j] = sin(phase); } active_modem->ModulateXmtr(outbuf, symlen); } } void cRsId::send(bool preRSID) { trx_mode mode = active_modem->get_mode(); if (!progdefaults.rsid_tx_modes.test(mode)) { LOG_DEBUG("Mode %s excluded, not sending RSID", mode_info[mode].sname); return; } if (!progdefaults.rsid_post && !preRSID) return; if (!assigned(mode)) return; unsigned char rsid[RSID_NSYMBOLS]; double sr; size_t len; int iTone; double freq, phaseincr; double fr; double phase; Encode(rmode, rsid); sr = active_modem->get_samplerate(); len = (size_t)floor(RSID_SYMLEN * sr); if (unlikely(len != symlen)) { symlen = len; delete [] outbuf; outbuf = new double[symlen]; } // transmit 5 symbol periods of silence at beginning of rsid memset(outbuf, 0, symlen * sizeof(*outbuf)); for (int i = 0; i < 5; i++) active_modem->ModulateXmtr(outbuf, symlen); // transmit sequence of 15 symbols (tones) fr = 1.0 * active_modem->get_txfreq_woffset() - (RSID_SAMPLE_RATE * 7 / 1024); phase = 0.0; for (int i = 0; i < 15; i++) { iTone = rsid[i]; if (active_modem->get_reverse()) iTone = 15 - iTone; freq = fr + iTone * RSID_SAMPLE_RATE / 1024; phaseincr = 2.0 * M_PI * freq / sr; for (size_t j = 0; j < symlen; j++) { phase += phaseincr; if (phase > 2.0 * M_PI) phase -= 2.0 * M_PI; outbuf[j] = sin(phase); } active_modem->ModulateXmtr(outbuf, symlen); } if (rmode == RSID_ESCAPE && rmode2 != RSID_NONE2) { // transmit 10 symbol periods of silence between rsid sequences memset(outbuf, 0, symlen * sizeof(*outbuf)); for (int i = 0; i < 10; i++) active_modem->ModulateXmtr(outbuf, symlen); Encode(rmode2, rsid); sr = active_modem->get_samplerate(); len = (size_t)floor(RSID_SYMLEN * sr); if (unlikely(len != symlen)) { symlen = len; delete [] outbuf; outbuf = new double[symlen]; } // transmit sequence of 15 symbols (tones) fr = 1.0 * active_modem->get_txfreq_woffset() - (RSID_SAMPLE_RATE * 7 / 1024); phase = 0.0; for (int i = 0; i < 15; i++) { iTone = rsid[i]; if (active_modem->get_reverse()) iTone = 15 - iTone; freq = fr + iTone * RSID_SAMPLE_RATE / 1024; phaseincr = 2.0 * M_PI * freq / sr; for (size_t j = 0; j < symlen; j++) { phase += phaseincr; if (phase > 2.0 * M_PI) phase -= 2.0 * M_PI; outbuf[j] = sin(phase); } active_modem->ModulateXmtr(outbuf, symlen); } } // 5 symbol periods of silence at end of transmission // and between RsID and the data signal int nperiods = 5; memset(outbuf, 0, symlen * sizeof(*outbuf)); for (int i = 0; i < nperiods; i++) active_modem->ModulateXmtr(outbuf, symlen); }