mirror of
https://github.com/f4exb/sdrangel.git
synced 2024-11-08 09:36:02 -05:00
1676 lines
51 KiB
C++
1676 lines
51 KiB
C++
///////////////////////////////////////////////////////////////////////////////////
|
|
// Copyright (C) 2016 Edouard Griffiths, F4EXB. //
|
|
// //
|
|
// This program 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 as version 3 of the License, or //
|
|
// //
|
|
// This program 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 V3 for more details. //
|
|
// //
|
|
// You should have received a copy of the GNU General Public License //
|
|
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
|
|
///////////////////////////////////////////////////////////////////////////////////
|
|
|
|
#include <stdlib.h>
|
|
#include "dsd_decoder.h"
|
|
|
|
namespace DSDplus
|
|
{
|
|
|
|
DSDDecoder::DSDDecoder() :
|
|
m_symbol(0),
|
|
m_fsmState(DSDLookForSync),
|
|
m_hasSync(0),
|
|
m_mbeDecoder(this),
|
|
m_dsdDMRVoice(this)
|
|
{
|
|
resetSymbol();
|
|
resetFrameSync();
|
|
noCarrier();
|
|
m_state.logfile = fdopen(fileno(stderr), (const char *) 'w');
|
|
}
|
|
|
|
DSDDecoder::~DSDDecoder()
|
|
{
|
|
fclose(m_state.logfile);
|
|
}
|
|
|
|
void DSDDecoder::run(short sample)
|
|
{
|
|
if (pushSample(sample, 0)) // a symbol is retrieved
|
|
{
|
|
switch (m_fsmState)
|
|
{
|
|
case DSDLookForSync:
|
|
m_hasSync = 0;
|
|
m_state.synctype = getFrameSync(); // -> -2: still looking, -1 not found, 0 and above: sync found
|
|
|
|
if (m_state.synctype > -2) // -1 and above means syncing has been processed (sync found or not but not searching)
|
|
{
|
|
// recalibrate center/umid/lmid
|
|
m_state.center = ((m_state.max) + (m_state.min)) / 2;
|
|
m_state.umid = (((m_state.max) - m_state.center) * 5 / 8) + m_state.center;
|
|
m_state.lmid = (((m_state.min) - m_state.center) * 5 / 8) + m_state.center;
|
|
|
|
if (m_state.synctype > -1) // 0 and above means a sync has been found
|
|
{
|
|
m_hasSync = 1;
|
|
processFrame(); // process the frame which sync has been found. This will change FSM state
|
|
}
|
|
else // no sync has been found after searching -> call noCarrier() and go back searching (same FSM state)
|
|
{
|
|
noCarrier();
|
|
}
|
|
}
|
|
// still searching -> no change in FSM state
|
|
break;
|
|
case DSDprocessDMRvoice:
|
|
m_dsdDMRVoice.process();
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void DSDDecoder::resetSymbol()
|
|
{
|
|
m_sampleIndex = 0;
|
|
m_sum = 0;
|
|
m_count = 0;
|
|
}
|
|
|
|
bool DSDDecoder::pushSample(short sample, int have_sync)
|
|
{
|
|
// timing control
|
|
if ((m_sampleIndex == 0) && (have_sync == 0))
|
|
{
|
|
if (m_state.samplesPerSymbol == 20)
|
|
{
|
|
if ((m_state.jitter >= 7) && (m_state.jitter <= 10))
|
|
{
|
|
m_sampleIndex--;
|
|
}
|
|
else if ((m_state.jitter >= 11) && (m_state.jitter <= 14))
|
|
{
|
|
m_sampleIndex++;
|
|
}
|
|
}
|
|
else if (m_state.rf_mod == 1)
|
|
{
|
|
if ((m_state.jitter >= 0)
|
|
&& (m_state.jitter < m_state.symbolCenter))
|
|
{
|
|
m_sampleIndex++; // fall back
|
|
}
|
|
else if ((m_state.jitter > m_state.symbolCenter)
|
|
&& (m_state.jitter < 10))
|
|
{
|
|
m_sampleIndex--; // catch up
|
|
}
|
|
}
|
|
else if (m_state.rf_mod == 2)
|
|
{
|
|
if ((m_state.jitter >= m_state.symbolCenter - 1)
|
|
&& (m_state.jitter <= m_state.symbolCenter))
|
|
{
|
|
m_sampleIndex--;
|
|
}
|
|
else if ((m_state.jitter >= m_state.symbolCenter + 1)
|
|
&& (m_state.jitter <= m_state.symbolCenter + 2))
|
|
{
|
|
m_sampleIndex++;
|
|
}
|
|
}
|
|
else if (m_state.rf_mod == 0)
|
|
{
|
|
if ((m_state.jitter > 0)
|
|
&& (m_state.jitter <= m_state.symbolCenter))
|
|
{
|
|
m_sampleIndex--; // catch up
|
|
}
|
|
else if ((m_state.jitter > m_state.symbolCenter)
|
|
&& (m_state.jitter < m_state.samplesPerSymbol))
|
|
{
|
|
m_sampleIndex++; // fall back
|
|
}
|
|
}
|
|
|
|
m_state.jitter = -1;
|
|
}
|
|
|
|
// process sample
|
|
if (m_opts.use_cosine_filter)
|
|
{
|
|
if (m_state.lastsynctype >= 10 && m_state.lastsynctype <= 13)
|
|
{
|
|
sample = m_dsdFilters.dmr_filter(sample);
|
|
}
|
|
else if (m_state.lastsynctype == 8 || m_state.lastsynctype == 9
|
|
|| m_state.lastsynctype == 16 || m_state.lastsynctype == 17)
|
|
{
|
|
sample = m_dsdFilters.nxdn_filter(sample);
|
|
}
|
|
}
|
|
|
|
if ((sample > m_state.max) && (have_sync == 1) && (m_state.rf_mod == 0))
|
|
{
|
|
sample = m_state.max;
|
|
}
|
|
else if ((sample < m_state.min) && (have_sync == 1)
|
|
&& (m_state.rf_mod == 0))
|
|
{
|
|
sample = m_state.min;
|
|
}
|
|
|
|
if (sample > m_state.center)
|
|
{
|
|
if (m_state.lastsample < m_state.center)
|
|
{
|
|
m_state.numflips += 1;
|
|
}
|
|
if (sample > (m_state.maxref * 1.25))
|
|
{
|
|
if (m_state.lastsample < (m_state.maxref * 1.25))
|
|
{
|
|
m_state.numflips += 1;
|
|
}
|
|
if ((m_state.jitter < 0) && (m_state.rf_mod == 1))
|
|
{ // first spike out of place
|
|
m_state.jitter = m_sampleIndex;
|
|
}
|
|
if ((m_opts.symboltiming == 1) && (have_sync == 0)
|
|
&& (m_state.lastsynctype != -1))
|
|
{
|
|
fprintf(m_state.logfile, "O");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ((m_opts.symboltiming == 1) && (have_sync == 0)
|
|
&& (m_state.lastsynctype != -1))
|
|
{
|
|
fprintf(m_state.logfile, "+");
|
|
}
|
|
if ((m_state.jitter < 0)
|
|
&& (m_state.lastsample < m_state.center)
|
|
&& (m_state.rf_mod != 1))
|
|
{ // first transition edge
|
|
m_state.jitter = m_sampleIndex;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{ // sample < 0
|
|
if (m_state.lastsample > m_state.center)
|
|
{
|
|
m_state.numflips += 1;
|
|
}
|
|
if (sample < (m_state.minref * 1.25))
|
|
{
|
|
if (m_state.lastsample > (m_state.minref * 1.25))
|
|
{
|
|
m_state.numflips += 1;
|
|
}
|
|
if ((m_state.jitter < 0) && (m_state.rf_mod == 1))
|
|
{ // first spike out of place
|
|
m_state.jitter = m_sampleIndex;
|
|
}
|
|
if ((m_opts.symboltiming == 1) && (have_sync == 0)
|
|
&& (m_state.lastsynctype != -1))
|
|
{
|
|
fprintf(m_state.logfile, "X");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ((m_opts.symboltiming == 1) && (have_sync == 0)
|
|
&& (m_state.lastsynctype != -1))
|
|
{
|
|
fprintf(m_state.logfile, "-");
|
|
}
|
|
if ((m_state.jitter < 0)
|
|
&& (m_state.lastsample > m_state.center)
|
|
&& (m_state.rf_mod != 1))
|
|
{ // first transition edge
|
|
m_state.jitter = m_sampleIndex;
|
|
}
|
|
}
|
|
}
|
|
if (m_state.samplesPerSymbol == 20)
|
|
{
|
|
if ((m_sampleIndex >= 9) && (m_sampleIndex <= 11))
|
|
{
|
|
m_sum += sample;
|
|
m_count++;
|
|
}
|
|
}
|
|
if (m_state.samplesPerSymbol == 5)
|
|
{
|
|
if (m_sampleIndex == 2)
|
|
{
|
|
m_sum += sample;
|
|
m_count++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (((m_sampleIndex >= m_state.symbolCenter - 1)
|
|
&& (m_sampleIndex <= m_state.symbolCenter + 2)
|
|
&& (m_state.rf_mod == 0))
|
|
|| (((m_sampleIndex == m_state.symbolCenter)
|
|
|| (m_sampleIndex == m_state.symbolCenter + 1))
|
|
&& (m_state.rf_mod != 0)))
|
|
{
|
|
m_sum += sample;
|
|
m_count++;
|
|
}
|
|
}
|
|
|
|
m_state.lastsample = sample;
|
|
|
|
if (m_sampleIndex == m_state.samplesPerSymbol - 1) // conclusion
|
|
{
|
|
m_symbol = m_sum / m_count;
|
|
if ((m_opts.symboltiming == 1) && (have_sync == 0)
|
|
&& (m_state.lastsynctype != -1))
|
|
{
|
|
if (m_state.jitter >= 0)
|
|
{
|
|
fprintf(m_state.logfile, " %i\n", m_state.jitter);
|
|
}
|
|
else
|
|
{
|
|
fprintf(m_state.logfile, "\n");
|
|
}
|
|
}
|
|
|
|
m_state.symbolcnt++;
|
|
resetSymbol();
|
|
return true; // new symbol available
|
|
}
|
|
else
|
|
{
|
|
m_sampleIndex++; // wait for next sample
|
|
return false;
|
|
}
|
|
}
|
|
|
|
int DSDDecoder::getDibit()
|
|
{
|
|
// returns one dibit value
|
|
int i, j, o, symbol;
|
|
int sbuf2[128];
|
|
int spectrum[64];
|
|
char modulation[8];
|
|
int lmin, lmax, lsum;
|
|
|
|
m_state.numflips = 0;
|
|
|
|
symbol = m_symbol;
|
|
m_state.sbuf[m_state.sidx] = m_symbol;
|
|
|
|
for (i = 0; i < m_opts.ssize; i++)
|
|
{
|
|
sbuf2[i] = m_state.sbuf[i];
|
|
}
|
|
|
|
qsort(sbuf2, m_opts.ssize, sizeof(int), comp);
|
|
// continuous update of min/max in rf_mod=1 (QPSK) mode
|
|
// in c4fm min/max must only be updated during sync
|
|
if (m_state.rf_mod == 1)
|
|
{
|
|
lmin = (sbuf2[0] + sbuf2[1]) / 2;
|
|
lmax = (sbuf2[(m_opts.ssize - 1)] + sbuf2[(m_opts.ssize - 2)]) / 2;
|
|
m_state.minbuf[m_state.midx] = lmin;
|
|
m_state.maxbuf[m_state.midx] = lmax;
|
|
|
|
if (m_state.midx == (m_opts.msize - 1))
|
|
{
|
|
m_state.midx = 0;
|
|
}
|
|
else
|
|
{
|
|
m_state.midx++;
|
|
}
|
|
|
|
lsum = 0;
|
|
|
|
for (i = 0; i < m_opts.msize; i++)
|
|
{
|
|
lsum += m_state.minbuf[i];
|
|
}
|
|
|
|
m_state.min = lsum / m_opts.msize;
|
|
lsum = 0;
|
|
|
|
for (i = 0; i < m_opts.msize; i++)
|
|
{
|
|
lsum += m_state.maxbuf[i];
|
|
}
|
|
|
|
m_state.max = lsum / m_opts.msize;
|
|
m_state.center = ((m_state.max) + (m_state.min)) / 2;
|
|
m_state.umid = (((m_state.max) - m_state.center) * 5 / 8) + m_state.center;
|
|
m_state.lmid = (((m_state.min) - m_state.center) * 5 / 8) + m_state.center;
|
|
m_state.maxref = ((m_state.max) * 0.80);
|
|
m_state.minref = ((m_state.min) * 0.80);
|
|
}
|
|
else
|
|
{
|
|
m_state.maxref = m_state.max;
|
|
m_state.minref = m_state.min;
|
|
}
|
|
|
|
if (m_state.sidx == (m_opts.ssize - 1))
|
|
{
|
|
m_state.sidx = 0;
|
|
|
|
if (m_opts.datascope == 1)
|
|
{
|
|
if (m_state.rf_mod == 0)
|
|
{
|
|
sprintf(modulation, "C4FM");
|
|
}
|
|
else if (m_state.rf_mod == 1)
|
|
{
|
|
sprintf(modulation, "QPSK");
|
|
}
|
|
else if (m_state.rf_mod == 2)
|
|
{
|
|
sprintf(modulation, "GFSK");
|
|
}
|
|
|
|
for (i = 0; i < 64; i++)
|
|
{
|
|
spectrum[i] = 0;
|
|
}
|
|
for (i = 0; i < m_opts.ssize; i++)
|
|
{
|
|
o = (sbuf2[i] + 32768) / 1024;
|
|
spectrum[o]++;
|
|
}
|
|
if (m_state.symbolcnt > (4800 / m_opts.scoperate))
|
|
{
|
|
m_state.symbolcnt = 0;
|
|
fprintf(m_state.logfile, "\n");
|
|
fprintf(m_state.logfile,
|
|
"Demod mode: %s Nac: %4X\n",
|
|
modulation, m_state.nac);
|
|
fprintf(m_state.logfile,
|
|
"Frame Type: %s Talkgroup: %7i\n",
|
|
m_state.ftype, m_state.lasttg);
|
|
fprintf(m_state.logfile,
|
|
"Frame Subtype: %s Source: %12i\n",
|
|
m_state.fsubtype, m_state.lastsrc);
|
|
fprintf(m_state.logfile,
|
|
"TDMA activity: %s %s Voice errors: %s\n",
|
|
m_state.slot0light, m_state.slot1light, m_state.err_str);
|
|
fprintf(m_state.logfile,
|
|
"+----------------------------------------------------------------+\n");
|
|
|
|
for (i = 0; i < 10; i++)
|
|
{
|
|
fprintf(m_state.logfile, "|");
|
|
|
|
for (j = 0; j < 64; j++)
|
|
{
|
|
if (i == 0)
|
|
{
|
|
if ((j == ((m_state.min) + 32768) / 1024)
|
|
|| (j == ((m_state.max) + 32768) / 1024))
|
|
{
|
|
fprintf(m_state.logfile, "#");
|
|
}
|
|
else if ((j == ((m_state.lmid) + 32768) / 1024)
|
|
|| (j == ((m_state.umid) + 32768) / 1024))
|
|
{
|
|
fprintf(m_state.logfile, "^");
|
|
}
|
|
else if (j == (m_state.center + 32768) / 1024)
|
|
{
|
|
fprintf(m_state.logfile, "!");
|
|
}
|
|
else
|
|
{
|
|
if (j == 32)
|
|
{
|
|
fprintf(m_state.logfile, "|");
|
|
}
|
|
else
|
|
{
|
|
fprintf(m_state.logfile, " ");
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (spectrum[j] > 9 - i)
|
|
{
|
|
fprintf(m_state.logfile, "*");
|
|
}
|
|
else
|
|
{
|
|
if (j == 32)
|
|
{
|
|
fprintf(m_state.logfile, "|");
|
|
}
|
|
else
|
|
{
|
|
fprintf(m_state.logfile, " ");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
fprintf(m_state.logfile, "|\n");
|
|
}
|
|
fprintf(m_state.logfile,
|
|
"+----------------------------------------------------------------+\n");
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_state.sidx++;
|
|
}
|
|
|
|
if (m_state.dibit_buf_p > m_state.dibit_buf + 900000)
|
|
{
|
|
m_state.dibit_buf_p = m_state.dibit_buf + 200;
|
|
}
|
|
|
|
// determine dibit state
|
|
if ((m_state.synctype == 6) || (m_state.synctype == 14)
|
|
|| (m_state.synctype == 18))
|
|
{
|
|
if (m_symbol > m_state.center)
|
|
{
|
|
*m_state.dibit_buf_p = 1;
|
|
m_state.dibit_buf_p++;
|
|
return (0);
|
|
}
|
|
else
|
|
{
|
|
*m_state.dibit_buf_p = 3;
|
|
m_state.dibit_buf_p++;
|
|
return (1);
|
|
}
|
|
}
|
|
else if ((m_state.synctype == 7) || (m_state.synctype == 15)
|
|
|| (m_state.synctype == 19))
|
|
{
|
|
if (m_symbol > m_state.center)
|
|
{
|
|
*m_state.dibit_buf_p = 1;
|
|
m_state.dibit_buf_p++;
|
|
return (1);
|
|
}
|
|
else
|
|
{
|
|
*m_state.dibit_buf_p = 3;
|
|
m_state.dibit_buf_p++;
|
|
return (0);
|
|
}
|
|
}
|
|
else if ((m_state.synctype == 1) || (m_state.synctype == 3)
|
|
|| (m_state.synctype == 5) || (m_state.synctype == 9)
|
|
|| (m_state.synctype == 11) || (m_state.synctype == 13))
|
|
{
|
|
if (m_symbol > m_state.center)
|
|
{
|
|
if (m_symbol > m_state.umid)
|
|
{
|
|
*m_state.dibit_buf_p = 1; // store non-inverted values in dibit_buf
|
|
m_state.dibit_buf_p++;
|
|
return (3);
|
|
}
|
|
else
|
|
{
|
|
*m_state.dibit_buf_p = 0;
|
|
m_state.dibit_buf_p++;
|
|
return (2);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (m_symbol < m_state.lmid)
|
|
{
|
|
*m_state.dibit_buf_p = 3;
|
|
m_state.dibit_buf_p++;
|
|
return (1);
|
|
}
|
|
else
|
|
{
|
|
*m_state.dibit_buf_p = 2;
|
|
m_state.dibit_buf_p++;
|
|
return (0);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (m_symbol > m_state.center)
|
|
{
|
|
if (m_symbol > m_state.umid)
|
|
{
|
|
*m_state.dibit_buf_p = 1;
|
|
m_state.dibit_buf_p++;
|
|
return (1);
|
|
}
|
|
else
|
|
{
|
|
*m_state.dibit_buf_p = 0;
|
|
m_state.dibit_buf_p++;
|
|
return (0);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (m_symbol < m_state.lmid)
|
|
{
|
|
*m_state.dibit_buf_p = 3;
|
|
m_state.dibit_buf_p++;
|
|
return (3);
|
|
}
|
|
else
|
|
{
|
|
*m_state.dibit_buf_p = 2;
|
|
m_state.dibit_buf_p++;
|
|
return (2);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void DSDDecoder::resetFrameSync()
|
|
{
|
|
for (int i = 18; i < 24; i++)
|
|
{
|
|
m_lbuf[i] = 0;
|
|
m_lbuf2[i] = 0;
|
|
}
|
|
|
|
// reset detect frame sync engine
|
|
m_t = 0;
|
|
m_synctest[24] = 0;
|
|
m_synctest18[18] = 0;
|
|
m_synctest32[32] = 0;
|
|
m_synctest_pos = 0;
|
|
m_synctest_p = m_synctest_buf + 10;
|
|
m_lmin = 0;
|
|
m_lmax = 0;
|
|
m_lidx = 0;
|
|
m_lastt = 0;
|
|
m_state.numflips = 0;
|
|
m_sync = -2; // make in progress
|
|
|
|
if ((m_opts.symboltiming == 1) && (m_state.carrier == 1))
|
|
{
|
|
fprintf(m_state.logfile, "\nSymbol Timing:\n");
|
|
}
|
|
|
|
m_fsmState = DSDLookForSync;
|
|
}
|
|
|
|
void DSDDecoder::printFrameSync(const char *frametype, int offset, char *modulation)
|
|
{
|
|
if (m_opts.verbose > 0)
|
|
{
|
|
fprintf(m_state.logfile, "Sync: %s ", frametype);
|
|
}
|
|
if (m_opts.verbose > 2)
|
|
{
|
|
fprintf(m_state.logfile, "o: %4i ", offset);
|
|
}
|
|
if (m_opts.verbose > 1)
|
|
{
|
|
fprintf(m_state.logfile, "mod: %s ", modulation);
|
|
}
|
|
if (m_opts.verbose > 2)
|
|
{
|
|
fprintf(m_state.logfile, "g: %f ", m_state.aout_gain);
|
|
}
|
|
}
|
|
|
|
int DSDDecoder::getFrameSync()
|
|
{
|
|
/* detects frame sync and returns frame type
|
|
* -2 = in progress
|
|
* -1 = no sync
|
|
* 0 = +P25p1
|
|
* 1 = -P25p1
|
|
* 2 = +X2-TDMA (non inverted signal data frame)
|
|
* 3 = +X2-TDMA (inverted signal voice frame)
|
|
* 4 = -X2-TDMA (non inverted signal voice frame)
|
|
* 5 = -X2-TDMA (inverted signal data frame)
|
|
* 6 = +D-STAR
|
|
* 7 = -D-STAR
|
|
* 8 = +NXDN (non inverted voice frame)
|
|
* 9 = -NXDN (inverted voice frame)
|
|
* 10 = +DMR (non inverted singlan data frame)
|
|
* 11 = -DMR (inverted signal voice frame)
|
|
* 12 = +DMR (non inverted signal voice frame)
|
|
* 13 = -DMR (inverted signal data frame)
|
|
* 14 = +ProVoice
|
|
* 15 = -ProVoice
|
|
* 16 = +NXDN (non inverted data frame)
|
|
* 17 = -NXDN (inverted data frame)
|
|
* 18 = +D-STAR_HD
|
|
* 19 = -D-STAR_HD
|
|
*/
|
|
|
|
// smelly while was starting here
|
|
//symbol = getSymbol(opts, state, 0);
|
|
m_t++;
|
|
m_lbuf[m_lidx] = m_symbol;
|
|
m_state.sbuf[m_state.sidx] = m_symbol;
|
|
|
|
if (m_lidx == 23)
|
|
{
|
|
m_lidx = 0;
|
|
}
|
|
else
|
|
{
|
|
m_lidx++;
|
|
}
|
|
|
|
if (m_state.sidx == (m_opts.ssize - 1))
|
|
{
|
|
m_state.sidx = 0;
|
|
}
|
|
else
|
|
{
|
|
m_state.sidx++;
|
|
}
|
|
|
|
if (m_lastt == 23)
|
|
{
|
|
m_lastt = 0;
|
|
|
|
if (m_state.numflips > m_opts.mod_threshold)
|
|
{
|
|
if (m_opts.mod_qpsk == 1)
|
|
{
|
|
m_state.rf_mod = 1;
|
|
}
|
|
}
|
|
else if (m_state.numflips > 18)
|
|
{
|
|
if (m_opts.mod_gfsk == 1)
|
|
{
|
|
m_state.rf_mod = 2;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (m_opts.mod_c4fm == 1)
|
|
{
|
|
m_state.rf_mod = 0;
|
|
}
|
|
}
|
|
|
|
m_state.numflips = 0;
|
|
}
|
|
else
|
|
{
|
|
m_lastt++;
|
|
}
|
|
|
|
if (m_state.dibit_buf_p > m_state.dibit_buf + 900000)
|
|
{
|
|
m_state.dibit_buf_p = m_state.dibit_buf + 200;
|
|
}
|
|
|
|
//determine dibit state
|
|
if (m_symbol > 0)
|
|
{
|
|
*m_state.dibit_buf_p = 1;
|
|
m_state.dibit_buf_p++;
|
|
m_dibit = 49;
|
|
}
|
|
else
|
|
{
|
|
*m_state.dibit_buf_p = 3;
|
|
m_state.dibit_buf_p++;
|
|
m_dibit = 51;
|
|
}
|
|
|
|
*m_synctest_p = m_dibit;
|
|
|
|
if (m_t >= 18)
|
|
{
|
|
for (int i = 0; i < 24; i++)
|
|
{
|
|
m_lbuf2[i] = m_lbuf[i];
|
|
}
|
|
|
|
qsort(m_lbuf2, 24, sizeof(int), comp);
|
|
|
|
m_lmin = (m_lbuf2[2] + m_lbuf2[3] + m_lbuf2[4]) / 3;
|
|
m_lmax = (m_lbuf2[21] + m_lbuf2[20] + m_lbuf2[19]) / 3;
|
|
|
|
if (m_state.rf_mod == 1)
|
|
{
|
|
m_state.minbuf[m_state.midx] = m_lmin;
|
|
m_state.maxbuf[m_state.midx] = m_lmax;
|
|
|
|
if (m_state.midx == (m_opts.msize - 1))
|
|
{
|
|
m_state.midx = 0;
|
|
}
|
|
else
|
|
{
|
|
m_state.midx++;
|
|
}
|
|
|
|
m_lsum = 0;
|
|
|
|
for (int i = 0; i < m_opts.msize; i++)
|
|
{
|
|
m_lsum += m_state.minbuf[i];
|
|
}
|
|
|
|
m_state.min = m_lsum / m_opts.msize;
|
|
m_lsum = 0;
|
|
|
|
for (int i = 0; i < m_opts.msize; i++)
|
|
{
|
|
m_lsum += m_state.maxbuf[i];
|
|
}
|
|
|
|
m_state.max = m_lsum / m_opts.msize;
|
|
m_state.center = ((m_state.max) + (m_state.min)) / 2;
|
|
m_state.maxref = ((m_state.max) * 0.80);
|
|
m_state.minref = ((m_state.min) * 0.80);
|
|
}
|
|
else
|
|
{
|
|
m_state.maxref = m_state.max;
|
|
m_state.minref = m_state.min;
|
|
}
|
|
|
|
if (m_state.rf_mod == 0)
|
|
{
|
|
sprintf(m_modulation, "C4FM");
|
|
}
|
|
else if (m_state.rf_mod == 1)
|
|
{
|
|
sprintf(m_modulation, "QPSK");
|
|
}
|
|
else if (m_state.rf_mod == 2)
|
|
{
|
|
sprintf(m_modulation, "GFSK");
|
|
}
|
|
|
|
if (m_opts.datascope == 1)
|
|
{
|
|
if (m_lidx == 0)
|
|
{
|
|
for (int i = 0; i < 64; i++)
|
|
{
|
|
m_spectrum[i] = 0;
|
|
}
|
|
|
|
for (int i = 0; i < 24; i++)
|
|
{
|
|
int o = (m_lbuf2[i] + 32768) / 1024;
|
|
m_spectrum[o]++;
|
|
}
|
|
if (m_state.symbolcnt > (4800 / m_opts.scoperate))
|
|
{
|
|
m_state.symbolcnt = 0;
|
|
|
|
fprintf(m_state.logfile, "\n");
|
|
fprintf(m_state.logfile,
|
|
"Demod mode: %s Nac: %4X\n",
|
|
m_modulation, m_state.nac);
|
|
fprintf(m_state.logfile,
|
|
"Frame Type: %s Talkgroup: %7i\n",
|
|
m_state.ftype, m_state.lasttg);
|
|
fprintf(m_state.logfile,
|
|
"Frame Subtype: %s Source: %12i\n",
|
|
m_state.fsubtype, m_state.lastsrc);
|
|
fprintf(m_state.logfile,
|
|
"TDMA activity: %s %s Voice errors: %s\n",
|
|
m_state.slot0light, m_state.slot1light,
|
|
m_state.err_str);
|
|
fprintf(m_state.logfile,
|
|
"+----------------------------------------------------------------+\n");
|
|
|
|
for (int i = 0; i < 10; i++)
|
|
{
|
|
fprintf(m_state.logfile, "|");
|
|
|
|
for (int j = 0; j < 64; j++)
|
|
{
|
|
if (i == 0)
|
|
{
|
|
if ((j == ((m_state.min) + 32768) / 1024) || (j == ((m_state.max) + 32768) / 1024))
|
|
{
|
|
fprintf(m_state.logfile, "#");
|
|
}
|
|
else if (j == (m_state.center + 32768) / 1024)
|
|
{
|
|
fprintf(m_state.logfile, "!");
|
|
}
|
|
else
|
|
{
|
|
if (j == 32)
|
|
{
|
|
fprintf(m_state.logfile, "|");
|
|
}
|
|
else
|
|
{
|
|
fprintf(m_state.logfile, " ");
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (m_spectrum[j] > 9 - i)
|
|
{
|
|
fprintf(m_state.logfile, "*");
|
|
}
|
|
else
|
|
{
|
|
if (j == 32)
|
|
{
|
|
fprintf(m_state.logfile, "|");
|
|
}
|
|
else
|
|
{
|
|
fprintf(m_state.logfile, " ");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
fprintf(m_state.logfile, "|\n");
|
|
}
|
|
|
|
fprintf(m_state.logfile,
|
|
"+----------------------------------------------------------------+\n");
|
|
}
|
|
}
|
|
} // m_opts.datascope == 1
|
|
|
|
strncpy(m_synctest, (m_synctest_p - 23), 24);
|
|
|
|
if (m_opts.frame_p25p1 == 1)
|
|
{
|
|
if (strcmp(m_synctest, P25P1_SYNC) == 0)
|
|
{
|
|
m_state.carrier = 1;
|
|
m_state.offset = m_synctest_pos;
|
|
m_state.max = ((m_state.max) + m_lmax) / 2;
|
|
m_state.min = ((m_state.min) + m_lmin) / 2;
|
|
|
|
sprintf(m_state.ftype, " P25 Phase 1 ");
|
|
|
|
if (m_opts.errorbars == 1)
|
|
{
|
|
printFrameSync(" +P25p1 ", m_synctest_pos + 1, m_modulation);
|
|
}
|
|
|
|
m_state.lastsynctype = 0;
|
|
return(0);
|
|
}
|
|
if (strcmp(m_synctest, INV_P25P1_SYNC) == 0)
|
|
{
|
|
m_state.carrier = 1;
|
|
m_state.offset = m_synctest_pos;
|
|
m_state.max = ((m_state.max) + m_lmax) / 2;
|
|
m_state.min = ((m_state.min) + m_lmin) / 2;
|
|
|
|
sprintf(m_state.ftype, " P25 Phase 1 ");
|
|
|
|
if (m_opts.errorbars == 1)
|
|
{
|
|
printFrameSync(" -P25p1 ", m_synctest_pos + 1, m_modulation);
|
|
}
|
|
|
|
m_state.lastsynctype = 1;
|
|
return(1);
|
|
}
|
|
}
|
|
if (m_opts.frame_x2tdma == 1)
|
|
{
|
|
if ((strcmp(m_synctest, X2TDMA_BS_DATA_SYNC) == 0)
|
|
|| (strcmp(m_synctest, X2TDMA_MS_DATA_SYNC) == 0))
|
|
{
|
|
m_state.carrier = 1;
|
|
m_state.offset = m_synctest_pos;
|
|
m_state.max = ((m_state.max) + (m_lmax)) / 2;
|
|
m_state.min = ((m_state.min) + (m_lmin)) / 2;
|
|
|
|
if (m_opts.inverted_x2tdma == 0)
|
|
{
|
|
// data frame
|
|
sprintf(m_state.ftype, " X2-TDMA ");
|
|
|
|
if (m_opts.errorbars == 1)
|
|
{
|
|
printFrameSync(" +X2-TDMA ", m_synctest_pos + 1, m_modulation);
|
|
}
|
|
|
|
m_state.lastsynctype = 2;
|
|
return(2); // done
|
|
}
|
|
else
|
|
{
|
|
// inverted voice frame
|
|
sprintf(m_state.ftype, " X2-TDMA ");
|
|
|
|
if (m_opts.errorbars == 1)
|
|
{
|
|
printFrameSync(" -X2-TDMA ", m_synctest_pos + 1, m_modulation);
|
|
}
|
|
|
|
if (m_state.lastsynctype != 3)
|
|
{
|
|
m_state.firstframe = 1;
|
|
}
|
|
|
|
m_state.lastsynctype = 3;
|
|
return(3); // done
|
|
}
|
|
}
|
|
if ((strcmp(m_synctest, X2TDMA_BS_VOICE_SYNC) == 0)
|
|
|| (strcmp(m_synctest, X2TDMA_MS_VOICE_SYNC) == 0))
|
|
{
|
|
m_state.carrier = 1;
|
|
m_state.offset = m_synctest_pos;
|
|
m_state.max = ((m_state.max) + m_lmax) / 2;
|
|
m_state.min = ((m_state.min) + m_lmin) / 2;
|
|
|
|
if (m_opts.inverted_x2tdma == 0)
|
|
{
|
|
// voice frame
|
|
sprintf(m_state.ftype, " X2-TDMA ");
|
|
|
|
if (m_opts.errorbars == 1)
|
|
{
|
|
printFrameSync(" +X2-TDMA ", m_synctest_pos + 1, m_modulation);
|
|
}
|
|
|
|
if (m_state.lastsynctype != 4)
|
|
{
|
|
m_state.firstframe = 1;
|
|
}
|
|
|
|
m_state.lastsynctype = 4;
|
|
return(4); // done
|
|
}
|
|
else
|
|
{
|
|
// inverted data frame
|
|
sprintf(m_state.ftype, " X2-TDMA ");
|
|
|
|
if (m_opts.errorbars == 1)
|
|
{
|
|
printFrameSync(" -X2-TDMA ", m_synctest_pos + 1, m_modulation);
|
|
}
|
|
|
|
m_state.lastsynctype = 5;
|
|
return(5); // done
|
|
}
|
|
}
|
|
}
|
|
if (m_opts.frame_dmr == 1)
|
|
{
|
|
if ((strcmp(m_synctest, DMR_MS_DATA_SYNC) == 0)
|
|
|| (strcmp(m_synctest, DMR_BS_DATA_SYNC) == 0))
|
|
{
|
|
m_state.carrier = 1;
|
|
m_state.offset = m_synctest_pos;
|
|
m_state.max = ((m_state.max) + (m_lmax)) / 2;
|
|
m_state.min = ((m_state.min) + (m_lmin)) / 2;
|
|
|
|
if (m_opts.inverted_dmr == 0)
|
|
{
|
|
// data frame
|
|
sprintf(m_state.ftype, " DMR ");
|
|
|
|
if (m_opts.errorbars == 1)
|
|
{
|
|
printFrameSync(" +DMR ", m_synctest_pos + 1, m_modulation);
|
|
}
|
|
|
|
m_state.lastsynctype = 10;
|
|
return(10); // done
|
|
}
|
|
else
|
|
{
|
|
// inverted voice frame
|
|
sprintf(m_state.ftype, " DMR ");
|
|
|
|
if (m_opts.errorbars == 1)
|
|
{
|
|
printFrameSync(" -DMR ", m_synctest_pos + 1, m_modulation);
|
|
}
|
|
|
|
if (m_state.lastsynctype != 11)
|
|
{
|
|
m_state.firstframe = 1;
|
|
}
|
|
|
|
m_state.lastsynctype = 11;
|
|
return(11); // done
|
|
}
|
|
}
|
|
if ((strcmp(m_synctest, DMR_MS_VOICE_SYNC) == 0)
|
|
|| (strcmp(m_synctest, DMR_BS_VOICE_SYNC) == 0))
|
|
{
|
|
m_state.carrier = 1;
|
|
m_state.offset = m_synctest_pos;
|
|
m_state.max = ((m_state.max) + m_lmax) / 2;
|
|
m_state.min = ((m_state.min) + m_lmin) / 2;
|
|
|
|
if (m_opts.inverted_dmr == 0)
|
|
{
|
|
// voice frame
|
|
sprintf(m_state.ftype, " DMR ");
|
|
|
|
if (m_opts.errorbars == 1)
|
|
{
|
|
printFrameSync(" +DMR ", m_synctest_pos + 1, m_modulation);
|
|
}
|
|
|
|
if (m_state.lastsynctype != 12)
|
|
{
|
|
m_state.firstframe = 1;
|
|
}
|
|
|
|
m_state.lastsynctype = 12;
|
|
return(12); // done
|
|
}
|
|
else
|
|
{
|
|
// inverted data frame
|
|
sprintf(m_state.ftype, " DMR ");
|
|
|
|
if (m_opts.errorbars == 1)
|
|
{
|
|
printFrameSync(" -DMR ", m_synctest_pos + 1, m_modulation);
|
|
}
|
|
|
|
m_state.lastsynctype = 13;
|
|
return(13); // done
|
|
}
|
|
}
|
|
}
|
|
if (m_opts.frame_provoice == 1)
|
|
{
|
|
strncpy(m_synctest32, (m_synctest_p - 31), 32);
|
|
|
|
if ((strcmp(m_synctest32, PROVOICE_SYNC) == 0)
|
|
|| (strcmp(m_synctest32, PROVOICE_EA_SYNC) == 0))
|
|
{
|
|
m_state.carrier = 1;
|
|
m_state.offset = m_synctest_pos;
|
|
m_state.max = ((m_state.max) + m_lmax) / 2;
|
|
m_state.min = ((m_state.min) + m_lmin) / 2;
|
|
|
|
sprintf(m_state.ftype, " ProVoice ");
|
|
|
|
if (m_opts.errorbars == 1)
|
|
{
|
|
printFrameSync(" -ProVoice ", m_synctest_pos + 1, m_modulation);
|
|
}
|
|
|
|
m_state.lastsynctype = 14;
|
|
return(14); // done
|
|
}
|
|
else if ((strcmp(m_synctest32, INV_PROVOICE_SYNC) == 0)
|
|
|| (strcmp(m_synctest32, INV_PROVOICE_EA_SYNC) == 0))
|
|
{
|
|
m_state.carrier = 1;
|
|
m_state.offset = m_synctest_pos;
|
|
m_state.max = ((m_state.max) + m_lmax) / 2;
|
|
m_state.min = ((m_state.min) + m_lmin) / 2;
|
|
|
|
sprintf(m_state.ftype, " ProVoice ");
|
|
|
|
if (m_opts.errorbars == 1)
|
|
{
|
|
printFrameSync(" -ProVoice ", m_synctest_pos + 1, m_modulation);
|
|
}
|
|
|
|
m_state.lastsynctype = 15;
|
|
return(15); // done
|
|
}
|
|
|
|
}
|
|
if ((m_opts.frame_nxdn96 == 1) || (m_opts.frame_nxdn48 == 1))
|
|
{
|
|
strncpy(m_synctest18, (m_synctest_p - 17), 18);
|
|
|
|
if ((strcmp(m_synctest18, NXDN_BS_VOICE_SYNC) == 0)
|
|
|| (strcmp(m_synctest18, NXDN_MS_VOICE_SYNC) == 0))
|
|
{
|
|
if ((m_state.lastsynctype == 8)
|
|
|| (m_state.lastsynctype == 16))
|
|
{
|
|
m_state.carrier = 1;
|
|
m_state.offset = m_synctest_pos;
|
|
m_state.max = ((m_state.max) + m_lmax) / 2;
|
|
m_state.min = ((m_state.min) + m_lmin) / 2;
|
|
|
|
if (m_state.samplesPerSymbol == 20)
|
|
{
|
|
sprintf(m_state.ftype, " NXDN48 ");
|
|
|
|
if (m_opts.errorbars == 1)
|
|
{
|
|
printFrameSync(" +NXDN48 ", m_synctest_pos + 1, m_modulation);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
sprintf(m_state.ftype, " NXDN96 ");
|
|
|
|
if (m_opts.errorbars == 1)
|
|
{
|
|
printFrameSync(" +NXDN96 ", m_synctest_pos + 1, m_modulation);
|
|
}
|
|
}
|
|
|
|
m_state.lastsynctype = 8;
|
|
return(8); // done
|
|
}
|
|
else
|
|
{
|
|
m_state.lastsynctype = 8;
|
|
}
|
|
}
|
|
else if ((strcmp(m_synctest18, INV_NXDN_BS_VOICE_SYNC) == 0)
|
|
|| (strcmp(m_synctest18, INV_NXDN_MS_VOICE_SYNC) == 0))
|
|
{
|
|
if ((m_state.lastsynctype == 9)
|
|
|| (m_state.lastsynctype == 17))
|
|
{
|
|
m_state.carrier = 1;
|
|
m_state.offset = m_synctest_pos;
|
|
m_state.max = ((m_state.max) + m_lmax) / 2;
|
|
m_state.min = ((m_state.min) + m_lmin) / 2;
|
|
|
|
if (m_state.samplesPerSymbol == 20)
|
|
{
|
|
sprintf(m_state.ftype, " NXDN48 ");
|
|
|
|
if (m_opts.errorbars == 1)
|
|
{
|
|
printFrameSync(" -NXDN48 ", m_synctest_pos + 1, m_modulation);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
sprintf(m_state.ftype, " NXDN96 ");
|
|
|
|
if (m_opts.errorbars == 1)
|
|
{
|
|
printFrameSync(" -NXDN96 ", m_synctest_pos + 1, m_modulation);
|
|
}
|
|
}
|
|
|
|
m_state.lastsynctype = 9;
|
|
return(9); // done
|
|
}
|
|
else
|
|
{
|
|
m_state.lastsynctype = 9;
|
|
}
|
|
}
|
|
else if ((strcmp(m_synctest18, NXDN_BS_DATA_SYNC) == 0)
|
|
|| (strcmp(m_synctest18, NXDN_MS_DATA_SYNC) == 0))
|
|
{
|
|
if ((m_state.lastsynctype == 8)
|
|
|| (m_state.lastsynctype == 16))
|
|
{
|
|
m_state.carrier = 1;
|
|
m_state.offset = m_synctest_pos;
|
|
m_state.max = ((m_state.max) + m_lmax) / 2;
|
|
m_state.min = ((m_state.min) + m_lmin) / 2;
|
|
|
|
if (m_state.samplesPerSymbol == 20)
|
|
{
|
|
sprintf(m_state.ftype, " NXDN48 ");
|
|
|
|
if (m_opts.errorbars == 1)
|
|
{
|
|
printFrameSync(" +NXDN48 ", m_synctest_pos + 1, m_modulation);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
sprintf(m_state.ftype, " NXDN96 ");
|
|
|
|
if (m_opts.errorbars == 1)
|
|
{
|
|
printFrameSync(" +NXDN96 ", m_synctest_pos + 1, m_modulation);
|
|
}
|
|
}
|
|
|
|
m_state.lastsynctype = 16;
|
|
return(16); // done
|
|
}
|
|
else
|
|
{
|
|
m_state.lastsynctype = 16;
|
|
}
|
|
}
|
|
else if ((strcmp(m_synctest18, INV_NXDN_BS_DATA_SYNC) == 0)
|
|
|| (strcmp(m_synctest18, INV_NXDN_MS_DATA_SYNC) == 0))
|
|
{
|
|
if ((m_state.lastsynctype == 9)
|
|
|| (m_state.lastsynctype == 17))
|
|
{
|
|
m_state.carrier = 1;
|
|
m_state.offset = m_synctest_pos;
|
|
m_state.max = ((m_state.max) + m_lmax) / 2;
|
|
m_state.min = ((m_state.min) + m_lmin) / 2;
|
|
|
|
sprintf(m_state.ftype, " NXDN ");
|
|
|
|
if (m_state.samplesPerSymbol == 20)
|
|
{
|
|
sprintf(m_state.ftype, " NXDN48 ");
|
|
|
|
if (m_opts.errorbars == 1)
|
|
{
|
|
printFrameSync(" -NXDN48 ", m_synctest_pos + 1, m_modulation);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
sprintf(m_state.ftype, " NXDN96 ");
|
|
|
|
if (m_opts.errorbars == 1)
|
|
{
|
|
printFrameSync(" -NXDN96 ", m_synctest_pos + 1, m_modulation);
|
|
}
|
|
}
|
|
|
|
m_state.lastsynctype = 17;
|
|
return(17); // done
|
|
}
|
|
else
|
|
{
|
|
m_state.lastsynctype = 17;
|
|
}
|
|
}
|
|
}
|
|
if (m_opts.frame_dstar == 1)
|
|
{
|
|
if (strcmp(m_synctest, DSTAR_SYNC) == 0)
|
|
{
|
|
m_state.carrier = 1;
|
|
m_state.offset = m_synctest_pos;
|
|
m_state.max = ((m_state.max) + m_lmax) / 2;
|
|
m_state.min = ((m_state.min) + m_lmin) / 2;
|
|
|
|
sprintf(m_state.ftype, " D-STAR ");
|
|
|
|
if (m_opts.errorbars == 1)
|
|
{
|
|
printFrameSync(" +D-STAR ", m_synctest_pos + 1, m_modulation);
|
|
}
|
|
|
|
m_state.lastsynctype = 6;
|
|
return(6);
|
|
}
|
|
if (strcmp(m_synctest, INV_DSTAR_SYNC) == 0)
|
|
{
|
|
m_state.carrier = 1;
|
|
m_state.offset = m_synctest_pos;
|
|
m_state.max = ((m_state.max) + m_lmax) / 2;
|
|
m_state.min = ((m_state.min) + m_lmin) / 2;
|
|
|
|
sprintf(m_state.ftype, " D-STAR ");
|
|
|
|
if (m_opts.errorbars == 1)
|
|
{
|
|
printFrameSync(" -D-STAR ", m_synctest_pos + 1, m_modulation);
|
|
}
|
|
|
|
m_state.lastsynctype = 7;
|
|
return(7); // done
|
|
}
|
|
if (strcmp(m_synctest, DSTAR_HD) == 0)
|
|
{
|
|
m_state.carrier = 1;
|
|
m_state.offset = m_synctest_pos;
|
|
m_state.max = ((m_state.max) + m_lmax) / 2;
|
|
m_state.min = ((m_state.min) + m_lmin) / 2;
|
|
|
|
sprintf(m_state.ftype, " D-STAR_HD ");
|
|
|
|
if (m_opts.errorbars == 1)
|
|
{
|
|
printFrameSync(" +D-STAR_HD ", m_synctest_pos + 1, m_modulation);
|
|
}
|
|
|
|
m_state.lastsynctype = 18;
|
|
return(18); // done
|
|
}
|
|
if (strcmp(m_synctest, INV_DSTAR_HD) == 0)
|
|
{
|
|
m_state.carrier = 1;
|
|
m_state.offset = m_synctest_pos;
|
|
m_state.max = ((m_state.max) + m_lmax) / 2;
|
|
m_state.min = ((m_state.min) + m_lmin) / 2;
|
|
|
|
sprintf(m_state.ftype, " D-STAR_HD ");
|
|
|
|
if (m_opts.errorbars == 1)
|
|
{
|
|
printFrameSync(" -D-STAR_HD ", m_synctest_pos + 1, m_modulation);
|
|
}
|
|
|
|
m_state.lastsynctype = 19;
|
|
return(19);
|
|
}
|
|
}
|
|
|
|
if ((m_t == 24) && (m_state.lastsynctype != -1))
|
|
{
|
|
if ((m_state.lastsynctype == 0)
|
|
&& ((m_state.lastp25type == 1)
|
|
|| (m_state.lastp25type == 2)))
|
|
{
|
|
m_state.carrier = 1;
|
|
m_state.offset = m_synctest_pos;
|
|
m_state.max = ((m_state.max) + (m_lmax)) / 2;
|
|
m_state.min = ((m_state.min) + (m_lmin)) / 2;
|
|
|
|
sprintf(m_state.ftype, "(P25 Phase 1)");
|
|
|
|
if (m_opts.errorbars == 1)
|
|
{
|
|
printFrameSync("(+P25p1) ", m_synctest_pos + 1, m_modulation);
|
|
}
|
|
|
|
m_state.lastsynctype = -1;
|
|
return(0); // done
|
|
}
|
|
else if ((m_state.lastsynctype == 1) && ((m_state.lastp25type == 1) || (m_state.lastp25type == 2)))
|
|
{
|
|
m_state.carrier = 1;
|
|
m_state.offset = m_synctest_pos;
|
|
m_state.max = ((m_state.max) + m_lmax) / 2;
|
|
m_state.min = ((m_state.min) + m_lmin) / 2;
|
|
sprintf(m_state.ftype, "(P25 Phase 1)");
|
|
if (m_opts.errorbars == 1)
|
|
{
|
|
printFrameSync("(-P25p1) ", m_synctest_pos + 1, m_modulation);
|
|
}
|
|
|
|
m_state.lastsynctype = -1;
|
|
return(1); // done
|
|
}
|
|
else if ((m_state.lastsynctype == 3) && ((strcmp(m_synctest, X2TDMA_BS_VOICE_SYNC) != 0) || (strcmp(m_synctest, X2TDMA_MS_VOICE_SYNC) != 0)))
|
|
{
|
|
m_state.carrier = 1;
|
|
m_state.offset = m_synctest_pos;
|
|
m_state.max = ((m_state.max) + m_lmax) / 2;
|
|
m_state.min = ((m_state.min) + m_lmin) / 2;
|
|
|
|
sprintf(m_state.ftype, "(X2-TDMA) ");
|
|
|
|
if (m_opts.errorbars == 1)
|
|
{
|
|
printFrameSync("(-X2-TDMA) ", m_synctest_pos + 1, m_modulation);
|
|
}
|
|
|
|
m_state.lastsynctype = -1;
|
|
return(3);
|
|
}
|
|
else if ((m_state.lastsynctype == 4) && ((strcmp(m_synctest, X2TDMA_BS_DATA_SYNC) != 0) || (strcmp(m_synctest, X2TDMA_MS_DATA_SYNC) != 0)))
|
|
{
|
|
m_state.carrier = 1;
|
|
m_state.offset = m_synctest_pos;
|
|
m_state.max = ((m_state.max) + m_lmax) / 2;
|
|
m_state.min = ((m_state.min) + m_lmin) / 2;
|
|
|
|
sprintf(m_state.ftype, "(X2-TDMA) ");
|
|
|
|
if (m_opts.errorbars == 1)
|
|
{
|
|
printFrameSync("(+X2-TDMA) ", m_synctest_pos + 1, m_modulation);
|
|
}
|
|
|
|
m_state.lastsynctype = -1;
|
|
return(4);
|
|
}
|
|
else if ((m_state.lastsynctype == 11) && ((strcmp(m_synctest, DMR_BS_VOICE_SYNC) != 0) || (strcmp(m_synctest, DMR_MS_VOICE_SYNC) != 0)))
|
|
{
|
|
m_state.carrier = 1;
|
|
m_state.offset = m_synctest_pos;
|
|
m_state.max = ((m_state.max) + m_lmax) / 2;
|
|
m_state.min = ((m_state.min) + m_lmin) / 2;
|
|
|
|
sprintf(m_state.ftype, "(DMR) ");
|
|
|
|
if (m_opts.errorbars == 1)
|
|
{
|
|
printFrameSync("(-DMR) ", m_synctest_pos + 1, m_modulation);
|
|
}
|
|
|
|
m_state.lastsynctype = -1;
|
|
return(11); // done
|
|
}
|
|
else if ((m_state.lastsynctype == 12) && ((strcmp(m_synctest, DMR_BS_DATA_SYNC) != 0) || (strcmp(m_synctest, DMR_MS_DATA_SYNC) != 0)))
|
|
{
|
|
m_state.carrier = 1;
|
|
m_state.offset = m_synctest_pos;
|
|
m_state.max = ((m_state.max) + m_lmax) / 2;
|
|
m_state.min = ((m_state.min) + m_lmin) / 2;
|
|
|
|
sprintf(m_state.ftype, "(DMR) ");
|
|
|
|
if (m_opts.errorbars == 1)
|
|
{
|
|
printFrameSync("(+DMR) ", m_synctest_pos + 1, m_modulation);
|
|
}
|
|
|
|
m_state.lastsynctype = -1;
|
|
return(12); // done
|
|
}
|
|
}
|
|
}
|
|
|
|
if (m_synctest_pos < 10200)
|
|
{
|
|
m_synctest_pos++;
|
|
m_synctest_p++;
|
|
}
|
|
else
|
|
{
|
|
// buffer reset
|
|
m_synctest_pos = 0;
|
|
m_synctest_p = m_synctest_buf;
|
|
noCarrier();
|
|
}
|
|
|
|
if (m_state.lastsynctype != 1)
|
|
{
|
|
if (m_synctest_pos >= 1800)
|
|
{
|
|
if ((m_opts.errorbars == 1) && (m_opts.verbose > 1)
|
|
&& (m_state.carrier == 1))
|
|
{
|
|
printf("Sync: no sync\n");
|
|
}
|
|
|
|
noCarrier();
|
|
return(-1); // done
|
|
}
|
|
}
|
|
|
|
return(-2); // still searching
|
|
}
|
|
|
|
void DSDDecoder::noCarrier()
|
|
{
|
|
m_state.dibit_buf_p = m_state.dibit_buf + 200;
|
|
memset(m_state.dibit_buf, 0, sizeof(int) * 200);
|
|
m_state.jitter = -1;
|
|
m_state.lastsynctype = -1;
|
|
m_state.carrier = 0;
|
|
m_state.max = 15000;
|
|
m_state.min = -15000;
|
|
m_state.center = 0;
|
|
m_state.err_str[0] = 0;
|
|
|
|
sprintf(m_state.fsubtype, " ");
|
|
sprintf(m_state.ftype, " ");
|
|
|
|
m_state.errs = 0;
|
|
m_state.errs2 = 0;
|
|
m_state.lasttg = 0;
|
|
m_state.lastsrc = 0;
|
|
m_state.lastp25type = 0;
|
|
m_state.repeat = 0;
|
|
m_state.nac = 0;
|
|
m_state.numtdulc = 0;
|
|
|
|
sprintf(m_state.slot0light, " slot0 ");
|
|
sprintf(m_state.slot1light, " slot1 ");
|
|
|
|
m_state.firstframe = 0;
|
|
|
|
if (m_opts.audio_gain == (float) 0)
|
|
{
|
|
m_state.aout_gain = 25;
|
|
}
|
|
|
|
memset(m_state.aout_max_buf, 0, sizeof(float) * 200);
|
|
m_state.aout_max_buf_p = m_state.aout_max_buf;
|
|
m_state.aout_max_buf_idx = 0;
|
|
sprintf(m_state.algid, "________");
|
|
sprintf(m_state.keyid, "________________");
|
|
mbe_initMbeParms(m_state.cur_mp, m_state.prev_mp, m_state.prev_mp_enhanced);
|
|
}
|
|
|
|
void DSDDecoder::printFrameInfo()
|
|
{
|
|
|
|
int level = (int) m_state.max / 164;
|
|
|
|
if (m_opts.verbose > 0)
|
|
{
|
|
fprintf(m_state.logfile, "inlvl: %2i%% ", level);
|
|
}
|
|
if (m_state.nac != 0)
|
|
{
|
|
fprintf(m_state.logfile, "nac: %4X ", m_state.nac);
|
|
}
|
|
|
|
if (m_opts.verbose > 1)
|
|
{
|
|
fprintf(m_state.logfile, "src: %8i ", m_state.lastsrc);
|
|
}
|
|
|
|
fprintf(m_state.logfile, "tg: %5i ", m_state.lasttg);
|
|
}
|
|
|
|
int DSDDecoder::comp(const void *a, const void *b)
|
|
{
|
|
if (*((const int *) a) == *((const int *) b))
|
|
return 0;
|
|
else if (*((const int *) a) < *((const int *) b))
|
|
return -1;
|
|
else
|
|
return 1;
|
|
}
|
|
|
|
void DSDDecoder::processFrame()
|
|
{
|
|
if (m_state.rf_mod == 1)
|
|
{
|
|
m_state.maxref = (m_state.max * 0.80);
|
|
m_state.minref = (m_state.min * 0.80);
|
|
}
|
|
else
|
|
{
|
|
m_state.maxref = m_state.max;
|
|
m_state.minref = m_state.min;
|
|
}
|
|
|
|
if ((m_state.synctype >= 10) && (m_state.synctype <= 13))
|
|
{
|
|
m_state.nac = 0;
|
|
m_state.lastsrc = 0;
|
|
m_state.lasttg = 0;
|
|
|
|
if (m_opts.errorbars == 1)
|
|
{
|
|
if (m_opts.verbose > 0)
|
|
{
|
|
int level = (int) m_state.max / 164;
|
|
fprintf(m_state.logfile, "inlvl: %2i%% ", level);
|
|
}
|
|
}
|
|
|
|
if ((m_state.synctype == 11) || (m_state.synctype == 12))
|
|
{
|
|
sprintf(m_state.fsubtype, " VOICE ");
|
|
m_dsdDMRVoice.init();
|
|
m_fsmState = DSDprocessDMRvoice;
|
|
}
|
|
else
|
|
{
|
|
m_state.err_str[0] = 0;
|
|
m_fsmState = DSDprocessDMRdata;
|
|
}
|
|
}
|
|
else if ((m_state.synctype == 6) || (m_state.synctype == 7))
|
|
{
|
|
m_state.nac = 0;
|
|
m_state.lastsrc = 0;
|
|
m_state.lasttg = 0;
|
|
|
|
if (m_opts.errorbars == 1)
|
|
{
|
|
if (m_opts.verbose > 0)
|
|
{
|
|
int level = (int) m_state.max / 164;
|
|
printf("inlvl: %2i%% ", level);
|
|
}
|
|
}
|
|
|
|
m_state.nac = 0;
|
|
sprintf(m_state.fsubtype, " VOICE ");
|
|
m_fsmState = DSDprocessDSTAR;
|
|
}
|
|
else if ((m_state.synctype == 18) || (m_state.synctype == 19))
|
|
{
|
|
m_state.nac = 0;
|
|
m_state.lastsrc = 0;
|
|
m_state.lasttg = 0;
|
|
|
|
if (m_opts.errorbars == 1)
|
|
{
|
|
if (m_opts.verbose > 0)
|
|
{
|
|
int level = (int) m_state.max / 164;
|
|
fprintf(m_state.logfile, "inlvl: %2i%% ", level);
|
|
}
|
|
}
|
|
|
|
m_state.nac = 0;
|
|
sprintf(m_state.fsubtype, " DATA ");
|
|
m_fsmState = DSDprocessDSTAR_HD;
|
|
}
|
|
else
|
|
{
|
|
noCarrier();
|
|
m_fsmState = DSDLookForSync;
|
|
}
|
|
}
|
|
|
|
} // namespace dsdplus
|