mirror of
https://github.com/f4exb/sdrangel.git
synced 2024-12-23 01:55:48 -05:00
NFM demod: DCS squelch (1)
This commit is contained in:
parent
2562d42385
commit
c901ba5c63
@ -1,6 +1,7 @@
|
||||
project(nfm)
|
||||
|
||||
set(nfm_SOURCES
|
||||
dcsdetector.cpp
|
||||
nfmdemod.cpp
|
||||
nfmdemodsettings.cpp
|
||||
nfmdemodwebapiadapter.cpp
|
||||
@ -11,6 +12,7 @@ set(nfm_SOURCES
|
||||
)
|
||||
|
||||
set(nfm_HEADERS
|
||||
dcsdetector.h
|
||||
nfmdemod.h
|
||||
nfmdemodsettings.h
|
||||
nfmdemodwebapiadapter.h
|
||||
|
124
plugins/channelrx/demodnfm/dcsdetector.cpp
Normal file
124
plugins/channelrx/demodnfm/dcsdetector.cpp
Normal file
@ -0,0 +1,124 @@
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (C) 2021 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 //
|
||||
// (at your option) any later version. //
|
||||
// //
|
||||
// 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 <algorithm>
|
||||
#include <QMutexLocker>
|
||||
|
||||
#include "dcsdetector.h"
|
||||
|
||||
DCSDetector::DCSDetector() :
|
||||
m_bitIndex(0.0),
|
||||
m_sampleRate(48000),
|
||||
m_eqSamples(nullptr),
|
||||
m_high(0.0f),
|
||||
m_low(0.0f),
|
||||
m_mid(0.0f),
|
||||
m_prevSample(0.0f),
|
||||
m_dcsWord(0),
|
||||
m_mutex(QMutex::Recursive)
|
||||
{
|
||||
setBitrate(134.3);
|
||||
setEqWindow(23);
|
||||
}
|
||||
|
||||
bool DCSDetector::analyze(Real *sample, unsigned int& dcsCode)
|
||||
{
|
||||
QMutexLocker mlock(&m_mutex);
|
||||
bool codeAvailable = false;
|
||||
|
||||
if (!m_eqSamples) {
|
||||
return false;
|
||||
}
|
||||
// Equalizer
|
||||
m_eqSamples[m_eqIndex++] = *sample;
|
||||
|
||||
if (m_eqIndex == m_eqSize)
|
||||
{
|
||||
m_high = *std::max_element(m_eqSamples, m_eqSamples + m_eqSize);
|
||||
m_low = *std::min_element(m_eqSamples, m_eqSamples + m_eqSize);
|
||||
m_mid = (m_high + m_low) / 2.0f;
|
||||
// qDebug("DCSDetector::analyze: %f %f %f", m_low, m_mid, m_high);
|
||||
m_eqIndex = 0;
|
||||
}
|
||||
|
||||
// Edge detection
|
||||
if (((m_prevSample < m_mid) && (*sample >= m_mid)) || ((m_prevSample > m_mid) && (*sample <= m_mid))) {
|
||||
m_bitIndex = 0.0;
|
||||
}
|
||||
|
||||
// Symbol detection
|
||||
m_prevSample = *sample;
|
||||
float fprev = m_bitIndex;
|
||||
m_bitIndex += m_bitsPerSample;
|
||||
|
||||
if ((fprev < 0.5f) && (m_bitIndex >= 0.5f)) // mid point detection
|
||||
{
|
||||
unsigned int bit = *sample > m_mid ? 1 : 0; // always work in positive mode
|
||||
m_dcsWord = (bit << 23) + (m_dcsWord >> 1);
|
||||
|
||||
if (((m_dcsWord >> 9) & 0x07) == 4) // magic signature
|
||||
{
|
||||
codeAvailable = m_golay2312.decodeParityFirst(&m_dcsWord);
|
||||
|
||||
if (codeAvailable) {
|
||||
dcsCode = m_dcsWord & 0x1FF;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (m_bitIndex > 1.0f) {
|
||||
m_bitIndex -= 1.0f;
|
||||
}
|
||||
|
||||
return codeAvailable;
|
||||
}
|
||||
|
||||
void DCSDetector::setBitrate(float bitrate)
|
||||
{
|
||||
m_bitrate = bitrate;
|
||||
m_bitsPerSample = m_bitrate / m_sampleRate;
|
||||
m_samplesPerBit = m_sampleRate / m_bitrate;
|
||||
}
|
||||
|
||||
void DCSDetector::setSampleRate(int sampleRate)
|
||||
{
|
||||
m_sampleRate = sampleRate;
|
||||
m_bitsPerSample = m_bitrate / m_sampleRate;
|
||||
m_samplesPerBit = m_sampleRate / m_bitrate;
|
||||
}
|
||||
|
||||
void DCSDetector::setEqWindow(int nbBits)
|
||||
{
|
||||
QMutexLocker mlock(&m_mutex);
|
||||
|
||||
m_eqBits = nbBits;
|
||||
m_eqSize = (int) m_samplesPerBit * m_eqBits;
|
||||
|
||||
if (m_eqSamples) {
|
||||
delete[] m_eqSamples;
|
||||
}
|
||||
|
||||
m_eqSamples = new float[m_eqSize];
|
||||
m_eqIndex = 0;
|
||||
}
|
||||
|
||||
DCSDetector::~DCSDetector()
|
||||
{
|
||||
if (m_eqSamples) {
|
||||
delete[] m_eqSamples;
|
||||
}
|
||||
}
|
55
plugins/channelrx/demodnfm/dcsdetector.h
Normal file
55
plugins/channelrx/demodnfm/dcsdetector.h
Normal file
@ -0,0 +1,55 @@
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (C) 2021 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 //
|
||||
// (at your option) any later version. //
|
||||
// //
|
||||
// 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/>. //
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef INCLUDE_DSP_DCSDETECTOR_H_
|
||||
#define INCLUDE_DSP_DCSDETECTOR_H_
|
||||
|
||||
#include <QMutex>
|
||||
|
||||
#include "dsp/dsptypes.h"
|
||||
#include "util/golay2312.h"
|
||||
|
||||
class DCSDetector {
|
||||
public:
|
||||
DCSDetector();
|
||||
~DCSDetector();
|
||||
|
||||
bool analyze(Real *sample, unsigned int& dcsCode); //!< input signal sample
|
||||
void setBitrate(float bitrate);
|
||||
void setSampleRate(int sampleRate);
|
||||
void setEqWindow(int nbBits);
|
||||
|
||||
private:
|
||||
float m_bitsPerSample;
|
||||
float m_samplesPerBit;
|
||||
float m_bitIndex;
|
||||
float m_bitrate;
|
||||
float m_sampleRate;
|
||||
float *m_eqSamples;
|
||||
int m_eqBits;
|
||||
int m_eqSize;
|
||||
int m_eqIndex;
|
||||
float m_high;
|
||||
float m_low;
|
||||
float m_mid;
|
||||
float m_prevSample;
|
||||
unsigned int m_dcsWord; //!< 23 bit DCS code word
|
||||
Golay2312 m_golay2312;
|
||||
QMutex m_mutex;
|
||||
};
|
||||
|
||||
#endif // INCLUDE_DSP_DCSDETECTOR_H_
|
@ -151,6 +151,9 @@ void NFMDemod::applySettings(const NFMDemodSettings& settings, bool force)
|
||||
<< " m_squelch: " << settings.m_squelch
|
||||
<< " m_ctcssIndex: " << settings.m_ctcssIndex
|
||||
<< " m_ctcssOn: " << settings.m_ctcssOn
|
||||
<< " m_dcsOn: " << settings.m_dcsOn
|
||||
<< " m_dcsCode: " << oct << settings.m_dcsCode << dec
|
||||
<< " m_dcsPositive: " << settings.m_dcsPositive
|
||||
<< " m_highPass: " << settings.m_highPass
|
||||
<< " m_audioMute: " << settings.m_audioMute
|
||||
<< " m_audioDeviceName: " << settings.m_audioDeviceName
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include "gui/crightclickenabler.h"
|
||||
#include "gui/audioselectdialog.h"
|
||||
#include "dsp/dspengine.h"
|
||||
#include "dsp/dcscodes.h"
|
||||
#include "maincore.h"
|
||||
|
||||
#include "nfmdemodreport.h"
|
||||
@ -61,6 +62,12 @@ bool NFMDemodGUI::handleMessage(const Message& message)
|
||||
setCtcssFreq(report.getFrequency());
|
||||
return true;
|
||||
}
|
||||
else if (NFMDemodReport::MsgReportDCSCode::match(message))
|
||||
{
|
||||
NFMDemodReport::MsgReportDCSCode& report = (NFMDemodReport::MsgReportDCSCode&) message;
|
||||
setDcsCode(report.getCode());
|
||||
return true;
|
||||
}
|
||||
else if (NFMDemod::MsgConfigureNFMDemod::match(message))
|
||||
{
|
||||
qDebug("NFMDemodGUI::handleMessage: NFMDemod::MsgConfigureNFMDemod");
|
||||
@ -214,6 +221,42 @@ void NFMDemodGUI::on_ctcssOn_toggled(bool checked)
|
||||
applySettings();
|
||||
}
|
||||
|
||||
void NFMDemodGUI::on_dcsOn_toggled(bool checked)
|
||||
{
|
||||
m_settings.m_dcsOn = checked;
|
||||
applySettings();
|
||||
}
|
||||
|
||||
void NFMDemodGUI::on_dcsPositive_toggled(bool checked)
|
||||
{
|
||||
m_dcsShowPositive = checked;
|
||||
setDcsCode(m_reportedDcsCode);
|
||||
}
|
||||
|
||||
void NFMDemodGUI::on_dcsCode_currentIndexChanged(int index)
|
||||
{
|
||||
if (index == 0)
|
||||
{
|
||||
m_settings.m_dcsCode = 0;
|
||||
applySettings();
|
||||
}
|
||||
else
|
||||
{
|
||||
QString dcsText = ui->dcsCode->currentText();
|
||||
bool positive = (dcsText[3] == 'P');
|
||||
dcsText.chop(1);
|
||||
bool ok;
|
||||
int dcsCode = dcsText.toInt(&ok, 8);
|
||||
|
||||
if (ok)
|
||||
{
|
||||
m_settings.m_dcsCode = dcsCode;
|
||||
m_settings.m_dcsPositive = positive;
|
||||
applySettings();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void NFMDemodGUI::on_highPassFilter_toggled(bool checked)
|
||||
{
|
||||
m_settings.m_highPass = checked;
|
||||
@ -297,6 +340,7 @@ NFMDemodGUI::NFMDemodGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, Baseban
|
||||
m_doApplySettings(true),
|
||||
m_squelchOpen(false),
|
||||
m_audioSampleRate(-1),
|
||||
m_reportedDcsCode(0),
|
||||
m_tickCount(0)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
@ -328,11 +372,22 @@ NFMDemodGUI::NFMDemodGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, Baseban
|
||||
|
||||
ui->ctcss->addItem("--");
|
||||
|
||||
for (int i=0; i<ctcss_nbTones; i++)
|
||||
{
|
||||
for (int i=0; i<ctcss_nbTones; i++) {
|
||||
ui->ctcss->addItem(QString("%1").arg(ctcss_tones[i]));
|
||||
}
|
||||
|
||||
ui->dcsOn->setChecked(m_settings.m_dcsOn);
|
||||
ui->dscPositive->setChecked(m_settings.m_dcsPositive);
|
||||
QList<unsigned int> dcsCodes;
|
||||
DCSCodes::getCanonicalCodes(dcsCodes);
|
||||
ui->dcsCode->addItem("--");
|
||||
|
||||
for (auto dcsCode : dcsCodes)
|
||||
{
|
||||
ui->dcsCode->addItem(QString("%1P").arg(dcsCode, 3, 8, QLatin1Char('0')));
|
||||
ui->dcsCode->addItem(QString("%1N").arg(dcsCode, 3, 8, QLatin1Char('0')));
|
||||
}
|
||||
|
||||
blockApplySettings(false);
|
||||
|
||||
ui->audioMute->setStyleSheet("QToolButton { background:rgb(79,79,79); }"); // squelch closed
|
||||
@ -440,6 +495,16 @@ void NFMDemodGUI::displaySettings()
|
||||
|
||||
ui->ctcss->setCurrentIndex(m_settings.m_ctcssIndex);
|
||||
|
||||
if (m_settings.m_dcsCode == 0) {
|
||||
ui->dcsCode->setCurrentText(tr("--"));
|
||||
} else {
|
||||
ui->dcsCode->setCurrentText(tr("%1%2")
|
||||
.arg(m_settings.m_dcsCode, 3, 8, QLatin1Char('0'))
|
||||
.arg(m_settings.m_dcsPositive ? "P" : "N")
|
||||
);
|
||||
}
|
||||
|
||||
setDcsCode(m_reportedDcsCode);
|
||||
displayStreamIndex();
|
||||
|
||||
blockApplySettings(false);
|
||||
@ -466,16 +531,28 @@ void NFMDemodGUI::enterEvent(QEvent*)
|
||||
|
||||
void NFMDemodGUI::setCtcssFreq(Real ctcssFreq)
|
||||
{
|
||||
if (ctcssFreq == 0)
|
||||
{
|
||||
if (ctcssFreq == 0) {
|
||||
ui->ctcssText->setText("--");
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
ui->ctcssText->setText(QString("%1").arg(ctcssFreq));
|
||||
}
|
||||
}
|
||||
|
||||
void NFMDemodGUI::setDcsCode(unsigned int dcsCode)
|
||||
{
|
||||
if (dcsCode == 0)
|
||||
{
|
||||
ui->dcsText->setText("--");
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned int normalizedCode;
|
||||
normalizedCode = DCSCodes::m_toCanonicalCode[dcsCode];
|
||||
normalizedCode = m_dcsShowPositive ? normalizedCode : DCSCodes::m_signFlip[normalizedCode];
|
||||
ui->dcsText->setText(tr("%1").arg(normalizedCode, 3, 8, QLatin1Char('0')));
|
||||
}
|
||||
}
|
||||
|
||||
void NFMDemodGUI::blockApplySettings(bool block)
|
||||
{
|
||||
m_doApplySettings = !block;
|
||||
|
@ -29,7 +29,6 @@ public:
|
||||
QByteArray serialize() const;
|
||||
bool deserialize(const QByteArray& data);
|
||||
virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; }
|
||||
void setCtcssFreq(Real ctcssFreq);
|
||||
|
||||
public slots:
|
||||
void channelMarkerChangedByCursor();
|
||||
@ -47,6 +46,8 @@ private:
|
||||
NFMDemod* m_nfmDemod;
|
||||
bool m_squelchOpen;
|
||||
int m_audioSampleRate;
|
||||
bool m_reportedDcsCode;
|
||||
bool m_dcsShowPositive;
|
||||
uint32_t m_tickCount;
|
||||
MessageQueue m_inputMessageQueue;
|
||||
|
||||
@ -57,6 +58,8 @@ private:
|
||||
void applySettings(bool force = false);
|
||||
void displaySettings();
|
||||
void displayStreamIndex();
|
||||
void setCtcssFreq(Real ctcssFreq);
|
||||
void setDcsCode(unsigned int dcsCode);
|
||||
bool handleMessage(const Message& message);
|
||||
|
||||
void leaveEvent(QEvent*);
|
||||
@ -74,6 +77,9 @@ private slots:
|
||||
void on_squelch_valueChanged(int value);
|
||||
void on_ctcss_currentIndexChanged(int index);
|
||||
void on_ctcssOn_toggled(bool checked);
|
||||
void on_dcsOn_toggled(bool checked);
|
||||
void on_dcsPositive_toggled(bool checked);
|
||||
void on_dcsCode_currentIndexChanged(int index);
|
||||
void on_highPassFilter_toggled(bool checked);
|
||||
void on_audioMute_toggled(bool checked);
|
||||
void onWidgetRolled(QWidget* widget, bool rollDown);
|
||||
|
@ -6,8 +6,8 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>302</width>
|
||||
<height>182</height>
|
||||
<width>364</width>
|
||||
<height>200</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
@ -18,8 +18,8 @@
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>302</width>
|
||||
<height>0</height>
|
||||
<width>364</width>
|
||||
<height>200</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="font">
|
||||
@ -36,13 +36,13 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>300</width>
|
||||
<height>141</height>
|
||||
<width>362</width>
|
||||
<height>191</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>300</width>
|
||||
<width>362</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
@ -537,41 +537,39 @@
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="ctcssLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="ctcssLabel">
|
||||
<widget class="QCheckBox" name="ctcssOn">
|
||||
<property name="toolTip">
|
||||
<string>Activate CTCSS</string>
|
||||
</property>
|
||||
<property name="layoutDirection">
|
||||
<enum>Qt::RightToLeft</enum>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>CTCSS</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="CTCSSblock">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="ctcssOn">
|
||||
<property name="toolTip">
|
||||
<string>Activate CTCSS</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="ctcss">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Set CTCSS Frequency</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
<widget class="QComboBox" name="ctcss">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>60</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Set CTCSS Frequency</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="ctcssText">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>30</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>CTCSS detected</string>
|
||||
</property>
|
||||
@ -583,6 +581,61 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="dcsOn">
|
||||
<property name="toolTip">
|
||||
<string>Activate DCS</string>
|
||||
</property>
|
||||
<property name="layoutDirection">
|
||||
<enum>Qt::RightToLeft</enum>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>DCS</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="dcsCode">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>60</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Set DCS code</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="ButtonSwitch" name="dscPositive">
|
||||
<property name="toolTip">
|
||||
<string>Display DCS code as postive</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>+</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="dcsText">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>30</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>DCS detected</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>--</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_2">
|
||||
<property name="orientation">
|
||||
@ -596,6 +649,29 @@
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="audioLayout">
|
||||
<property name="topMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_3">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="volumeLabel">
|
||||
<property name="text">
|
||||
@ -697,12 +773,6 @@
|
||||
<header>gui/rollupwidget.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>LevelMeterSignalDB</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>gui/levelmeter.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>ButtonSwitch</class>
|
||||
<extends>QToolButton</extends>
|
||||
@ -714,6 +784,12 @@
|
||||
<header>gui/valuedialz.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>LevelMeterSignalDB</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>gui/levelmeter.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources>
|
||||
<include location="../../../sdrgui/resources/res.qrc"/>
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include "nfmdemodreport.h"
|
||||
|
||||
MESSAGE_CLASS_DEFINITION(NFMDemodReport::MsgReportCTCSSFreq, Message)
|
||||
MESSAGE_CLASS_DEFINITION(NFMDemodReport::MsgReportDCSCode, Message)
|
||||
|
||||
NFMDemodReport::NFMDemodReport()
|
||||
{ }
|
||||
|
@ -47,6 +47,26 @@ public:
|
||||
{ }
|
||||
};
|
||||
|
||||
class MsgReportDCSCode : public Message {
|
||||
MESSAGE_CLASS_DECLARATION
|
||||
|
||||
public:
|
||||
unsigned int getCode() const { return m_code; }
|
||||
|
||||
static MsgReportDCSCode* create(unsigned int code)
|
||||
{
|
||||
return new MsgReportDCSCode(code);
|
||||
}
|
||||
|
||||
private:
|
||||
unsigned int m_code;
|
||||
|
||||
MsgReportDCSCode(unsigned int code) :
|
||||
Message(),
|
||||
m_code(code)
|
||||
{ }
|
||||
};
|
||||
|
||||
public:
|
||||
NFMDemodReport();
|
||||
~NFMDemodReport();
|
||||
|
@ -60,6 +60,9 @@ void NFMDemodSettings::resetToDefaults()
|
||||
m_ctcssOn = false;
|
||||
m_audioMute = false;
|
||||
m_ctcssIndex = 0;
|
||||
m_dcsOn = false;
|
||||
m_dcsCode = 0023;
|
||||
m_dcsPositive = false;
|
||||
m_rgbColor = QColor(255, 0, 0).rgb();
|
||||
m_title = "NFM Demodulator";
|
||||
m_audioDeviceName = AudioDeviceManager::m_defaultDeviceName;
|
||||
@ -101,6 +104,9 @@ QByteArray NFMDemodSettings::serialize() const
|
||||
s.writeU32(20, m_reverseAPIChannelIndex);
|
||||
s.writeS32(21, m_streamIndex);
|
||||
s.writeReal(22, m_fmDeviation);
|
||||
s.writeBool(23, m_dcsOn);
|
||||
s.writeU32(24, m_dcsCode);
|
||||
s.writeBool(25, m_dcsPositive);
|
||||
|
||||
return s.final();
|
||||
}
|
||||
@ -160,6 +166,10 @@ bool NFMDemodSettings::deserialize(const QByteArray& data)
|
||||
m_reverseAPIChannelIndex = utmp > 99 ? 99 : utmp;
|
||||
d.readS32(21, &m_streamIndex, 0);
|
||||
d.readReal(22, &m_fmDeviation, 5000.0);
|
||||
d.readBool(23, &m_dcsOn, false);
|
||||
d.readU32(24, &utmp, 0023);
|
||||
m_dcsCode = utmp < 511 ? utmp : 511;
|
||||
d.readBool(26, &m_dcsPositive, false);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -41,6 +41,9 @@ struct NFMDemodSettings
|
||||
bool m_ctcssOn;
|
||||
bool m_audioMute;
|
||||
int m_ctcssIndex;
|
||||
bool m_dcsOn;
|
||||
unsigned int m_dcsCode;
|
||||
bool m_dcsPositive;
|
||||
quint32 m_rgbColor;
|
||||
QString m_title;
|
||||
QString m_audioDeviceName;
|
||||
|
@ -30,6 +30,7 @@
|
||||
#include "dsp/devicesamplemimo.h"
|
||||
#include "dsp/misc.h"
|
||||
#include "dsp/datafifo.h"
|
||||
#include "dsp/dcscodes.h"
|
||||
#include "device/deviceapi.h"
|
||||
#include "maincore.h"
|
||||
|
||||
@ -49,6 +50,7 @@ NFMDemodSink::NFMDemodSink() :
|
||||
m_audioFifo(48000),
|
||||
m_rfFilter(FFT_FILTER_LENGTH),
|
||||
m_ctcssIndex(0),
|
||||
m_dcsCode(0),
|
||||
m_sampleCount(0),
|
||||
m_squelchCount(0),
|
||||
m_squelchGate(4800),
|
||||
@ -68,6 +70,9 @@ NFMDemodSink::NFMDemodSink() :
|
||||
m_demodBuffer.resize(1<<12);
|
||||
m_demodBufferFill = 0;
|
||||
|
||||
m_dcsDetector.setSampleRate(CTCSS_DETECTOR_RATE);
|
||||
m_dcsDetector.setEqWindow(23);
|
||||
|
||||
applySettings(m_settings, true);
|
||||
applyChannelSettings(m_channelSampleRate, m_channelFrequencyOffset, true);
|
||||
}
|
||||
@ -171,14 +176,18 @@ void NFMDemodSink::processOneSample(Complex &ci)
|
||||
|
||||
m_squelchOpen = m_squelchCount > m_squelchGate;
|
||||
int ctcssIndex = m_squelchOpen && m_settings.m_ctcssOn ? m_ctcssIndex : 0;
|
||||
unsigned int dcsCode = m_squelchOpen && m_settings.m_dcsOn ? m_dcsCode : 0;
|
||||
|
||||
if (m_squelchOpen)
|
||||
{
|
||||
if (m_settings.m_ctcssOn)
|
||||
{
|
||||
int factor = (m_audioSampleRate / CTCSS_DETECTOR_RATE) - 1; // decimate -> 6k
|
||||
|
||||
if ((m_sampleCount & factor) == factor)
|
||||
{
|
||||
Real ctcssSample = m_ctcssLowpass.filter(demod);
|
||||
|
||||
if (m_ctcssDetector.analyze(&ctcssSample))
|
||||
{
|
||||
int maxToneIndex;
|
||||
@ -186,8 +195,29 @@ void NFMDemodSink::processOneSample(Complex &ci)
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (m_settings.m_dcsOn)
|
||||
{
|
||||
int factor = (m_audioSampleRate / CTCSS_DETECTOR_RATE) - 1; // decimate -> 6k (same decimation as for CTCSS)
|
||||
|
||||
if (!m_settings.m_audioMute && (!m_settings.m_ctcssOn || m_ctcssIndexSelected == ctcssIndex || m_ctcssIndexSelected == 0))
|
||||
if ((m_sampleCount & factor) == factor)
|
||||
{
|
||||
Real dcsSample = m_ctcssLowpass.filter(demod);
|
||||
unsigned int dcsCodeDetected;
|
||||
|
||||
if (m_dcsDetector.analyze(&dcsSample, dcsCodeDetected))
|
||||
{
|
||||
dcsCode = DCSCodes::m_toCanonicalCode.value(dcsCodeDetected, 0);
|
||||
|
||||
if (dcsCode != 0) {
|
||||
dcsCode = m_settings.m_dcsPositive ? dcsCode : DCSCodes::m_signFlip[dcsCode];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!m_settings.m_audioMute &&
|
||||
(!m_settings.m_ctcssOn || m_ctcssIndexSelected == ctcssIndex || m_ctcssIndexSelected == 0) &&
|
||||
(!m_settings.m_dcsOn || m_dcsCodeSeleted == dcsCode || m_dcsCodeSeleted == 0))
|
||||
{
|
||||
Real audioSample = m_squelchDelayLine.readBack(m_squelchGate);
|
||||
audioSample = m_settings.m_highPass ? m_bandpass.filter(audioSample) : m_lowpass.filter(audioSample);
|
||||
@ -200,14 +230,27 @@ void NFMDemodSink::processOneSample(Complex &ci)
|
||||
if (ctcssIndex != m_ctcssIndex)
|
||||
{
|
||||
auto *guiQueue = getMessageQueueToGUI();
|
||||
|
||||
if (guiQueue)
|
||||
{
|
||||
guiQueue->push(NFMDemodReport::MsgReportCTCSSFreq::create(
|
||||
ctcssIndex ? m_ctcssDetector.getToneSet()[ctcssIndex - 1] : 0));
|
||||
}
|
||||
|
||||
m_ctcssIndex = ctcssIndex;
|
||||
}
|
||||
|
||||
if (dcsCode != m_dcsCode)
|
||||
{
|
||||
auto *guiQueue = getMessageQueueToGUI();
|
||||
|
||||
if (guiQueue) {
|
||||
guiQueue->push(NFMDemodReport::MsgReportDCSCode::create(dcsCode));
|
||||
}
|
||||
|
||||
m_dcsCode = dcsCode;
|
||||
}
|
||||
|
||||
m_audioBuffer[m_audioBufferFill].l = sample;
|
||||
m_audioBuffer[m_audioBufferFill].r = sample;
|
||||
++m_audioBufferFill;
|
||||
@ -286,6 +329,9 @@ void NFMDemodSink::applySettings(const NFMDemodSettings& settings, bool force)
|
||||
<< " m_squelch: " << settings.m_squelch
|
||||
<< " m_ctcssIndex: " << settings.m_ctcssIndex
|
||||
<< " m_ctcssOn: " << settings.m_ctcssOn
|
||||
<< " m_dcsOn: " << settings.m_dcsOn
|
||||
<< " m_dcsCode: " << settings.m_dcsCode
|
||||
<< " m_dcsPositive: " << settings.m_dcsPositive
|
||||
<< " m_highPass: " << settings.m_highPass
|
||||
<< " m_audioMute: " << settings.m_audioMute
|
||||
<< " m_audioDeviceName: " << settings.m_audioDeviceName
|
||||
@ -339,6 +385,10 @@ void NFMDemodSink::applySettings(const NFMDemodSettings& settings, bool force)
|
||||
setSelectedCtcssIndex(settings.m_ctcssIndex);
|
||||
}
|
||||
|
||||
if ((settings.m_dcsCode != m_settings.m_dcsCode) || force) {
|
||||
setSelectedDcsCode(settings.m_dcsCode);
|
||||
}
|
||||
|
||||
m_settings = settings;
|
||||
}
|
||||
|
||||
@ -359,8 +409,8 @@ void NFMDemodSink::applyAudioSampleRate(unsigned int sampleRate)
|
||||
} else {
|
||||
m_afSquelch.setCoefficients(sampleRate/2000, 600, sampleRate, 200, 0, afSqTones); // 0.5ms test period, 300ms average span, audio SR, 100ms attack, no decay
|
||||
}
|
||||
m_afSquelch.setThreshold(m_squelchLevel);
|
||||
|
||||
m_afSquelch.setThreshold(m_squelchLevel);
|
||||
m_phaseDiscri.setFMScaling(Real(sampleRate) / (2.0f * m_settings.m_fmDeviation));
|
||||
m_audioFifo.setSize(sampleRate);
|
||||
m_squelchDelayLine.resize(sampleRate/2);
|
||||
|
@ -33,6 +33,7 @@
|
||||
#include "util/doublebufferfifo.h"
|
||||
#include "audio/audiofifo.h"
|
||||
|
||||
#include "dcsdetector.h"
|
||||
#include "nfmdemodsettings.h"
|
||||
|
||||
class ChannelAPI;
|
||||
@ -52,6 +53,10 @@ public:
|
||||
m_ctcssIndexSelected = selectedCtcssIndex;
|
||||
}
|
||||
|
||||
void setSelectedDcsCode(unsigned int selectedDcsCode) {
|
||||
m_dcsCodeSeleted = selectedDcsCode;
|
||||
}
|
||||
|
||||
bool getSquelchOpen() const { return m_squelchOpen; }
|
||||
|
||||
void getMagSqLevels(double& avg, double& peak, int& nbSamples)
|
||||
@ -120,6 +125,9 @@ private:
|
||||
CTCSSDetector m_ctcssDetector;
|
||||
int m_ctcssIndex; // 0 for nothing detected
|
||||
int m_ctcssIndexSelected;
|
||||
DCSDetector m_dcsDetector;
|
||||
unsigned int m_dcsCode;
|
||||
unsigned int m_dcsCodeSeleted;
|
||||
int m_sampleCount;
|
||||
int m_squelchCount;
|
||||
int m_squelchGate;
|
||||
|
@ -101,6 +101,7 @@ set(sdrbase_SOURCES
|
||||
dsp/cwkeyer.cpp
|
||||
dsp/cwkeyersettings.cpp
|
||||
dsp/datafifo.cpp
|
||||
dsp/dcscodes.cpp
|
||||
dsp/decimatorsff.cpp
|
||||
dsp/decimatorsfi.cpp
|
||||
dsp/decimatorc.cpp
|
||||
@ -186,6 +187,7 @@ set(sdrbase_SOURCES
|
||||
util/db.cpp
|
||||
util/fixedtraits.cpp
|
||||
util/fits.cpp
|
||||
util/golay2312.cpp
|
||||
util/httpdownloadmanager.cpp
|
||||
util/lfsr.cpp
|
||||
util/maidenhead.cpp
|
||||
@ -262,6 +264,7 @@ set(sdrbase_HEADERS
|
||||
dsp/cwkeyer.h
|
||||
dsp/cwkeyersettings.h
|
||||
dsp/datafifo.h
|
||||
dsp/dcscodes.h
|
||||
dsp/decimators.h
|
||||
dsp/decimatorsif.h
|
||||
dsp/decimatorsff.h
|
||||
@ -382,6 +385,7 @@ set(sdrbase_HEADERS
|
||||
util/doublebufferfifo.h
|
||||
util/fixedtraits.h
|
||||
util/fits.h
|
||||
util/golay2312.h
|
||||
util/httpdownloadmanager.h
|
||||
util/incrementalarray.h
|
||||
util/incrementalvector.h
|
||||
|
465
sdrbase/dsp/dcscodes.cpp
Normal file
465
sdrbase/dsp/dcscodes.cpp
Normal file
@ -0,0 +1,465 @@
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (C) 2021 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 //
|
||||
// (at your option) any later version. //
|
||||
// //
|
||||
// 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/>. //
|
||||
// //
|
||||
// Source: http://onfreq.com/syntorx/dcs.html //
|
||||
// //
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "dcscodes.h"
|
||||
|
||||
const QMap<unsigned int, unsigned int> DCSCodes::m_toCanonicalCode {
|
||||
{0023, 0023},
|
||||
{0340, 0023},
|
||||
{0766, 0023},
|
||||
{0025, 0025},
|
||||
{0026, 0026},
|
||||
{0566, 0026},
|
||||
{0031, 0031},
|
||||
{0374, 0031},
|
||||
{0643, 0031},
|
||||
{0032, 0032},
|
||||
{0036, 0036},
|
||||
{0137, 0036},
|
||||
{0043, 0043},
|
||||
{0355, 0043},
|
||||
{0047, 0047},
|
||||
{0375, 0047},
|
||||
{0707, 0047},
|
||||
{0051, 0051},
|
||||
{0771, 0051},
|
||||
{0520, 0051},
|
||||
{0053, 0053},
|
||||
{0054, 0054},
|
||||
{0405, 0054},
|
||||
{0675, 0054},
|
||||
{0065, 0065},
|
||||
{0301, 0065},
|
||||
{0071, 0071},
|
||||
{0603, 0071},
|
||||
{0717, 0071},
|
||||
{0746, 0071},
|
||||
{0072, 0072},
|
||||
{0470, 0072},
|
||||
{0701, 0072},
|
||||
{0073, 0073},
|
||||
{0640, 0073},
|
||||
{0074, 0074},
|
||||
{0360, 0074},
|
||||
{0721, 0074},
|
||||
{0112, 0112},
|
||||
{0250, 0112},
|
||||
{0505, 0112},
|
||||
{0512, 0112},
|
||||
{0114, 0114},
|
||||
{0327, 0114},
|
||||
{0615, 0114},
|
||||
{0115, 0115},
|
||||
{0534, 0115},
|
||||
{0674, 0115},
|
||||
{0116, 0116},
|
||||
{0060, 0116},
|
||||
{0737, 0116},
|
||||
{0122, 0122},
|
||||
{0535, 0125},
|
||||
{0125, 0125},
|
||||
{0173, 0125},
|
||||
{0131, 0131},
|
||||
{0572, 0131},
|
||||
{0702, 0131},
|
||||
{0132, 0132},
|
||||
{0605, 0132},
|
||||
{0634, 0132},
|
||||
{0714, 0132},
|
||||
{0134, 0134},
|
||||
{0273, 0134},
|
||||
{0143, 0143},
|
||||
{0333, 0143},
|
||||
{0145, 0145},
|
||||
{0525, 0145},
|
||||
{0152, 0152},
|
||||
{0366, 0152},
|
||||
{0415, 0152},
|
||||
{0155, 0155},
|
||||
{0233, 0155},
|
||||
{0660, 0155},
|
||||
{0156, 0156},
|
||||
{0517, 0156},
|
||||
{0741, 0156},
|
||||
{0162, 0162},
|
||||
{0416, 0162},
|
||||
{0553, 0162},
|
||||
{0165, 0165},
|
||||
{0354, 0165},
|
||||
{0172, 0172},
|
||||
{0057, 0172},
|
||||
{0174, 0174},
|
||||
{0142, 0174},
|
||||
{0270, 0174},
|
||||
{0205, 0205},
|
||||
{0135, 0205},
|
||||
{0610, 0205},
|
||||
{0212, 0212},
|
||||
{0253, 0212},
|
||||
{0223, 0223},
|
||||
{0350, 0223},
|
||||
{0475, 0223},
|
||||
{0750, 0223},
|
||||
{0225, 0225},
|
||||
{0536, 0225},
|
||||
{0226, 0226},
|
||||
{0104, 0226},
|
||||
{0557, 0226},
|
||||
{0243, 0243},
|
||||
{0267, 0243},
|
||||
{0342, 0243},
|
||||
{0244, 0244},
|
||||
{0176, 0244},
|
||||
{0417, 0244},
|
||||
{0245, 0245},
|
||||
{0370, 0245},
|
||||
{0246, 0246},
|
||||
{0542, 0246},
|
||||
{0653, 0246},
|
||||
{0554, 0245},
|
||||
{0251, 0251},
|
||||
{0236, 0251},
|
||||
{0704, 0251},
|
||||
{0742, 0251},
|
||||
{0252, 0252},
|
||||
{0661, 0252},
|
||||
{0255, 0255},
|
||||
{0425, 0255},
|
||||
{0261, 0261},
|
||||
{0227, 0261},
|
||||
{0567, 0261},
|
||||
{0263, 0263},
|
||||
{0213, 0263},
|
||||
{0736, 0263},
|
||||
{0265, 0265},
|
||||
{0171, 0265},
|
||||
{0426, 0265},
|
||||
{0266, 0266},
|
||||
{0655, 0266},
|
||||
{0271, 0271},
|
||||
{0427, 0271},
|
||||
{0510, 0271},
|
||||
{0762, 0271},
|
||||
{0274, 0274},
|
||||
{0652, 0274},
|
||||
{0306, 0306},
|
||||
{0147, 0306},
|
||||
{0303, 0306},
|
||||
{0761, 0306},
|
||||
{0311, 0311},
|
||||
{0330, 0311},
|
||||
{0456, 0311},
|
||||
{0561, 0311},
|
||||
{0315, 0315},
|
||||
{0321, 0315},
|
||||
{0673, 0315},
|
||||
{0325, 0325},
|
||||
{0550, 0325},
|
||||
{0626, 0325},
|
||||
{0331, 0331},
|
||||
{0372, 0331},
|
||||
{0507, 0331},
|
||||
{0332, 0332},
|
||||
{0433, 0332},
|
||||
{0552, 0332},
|
||||
{0343, 0343},
|
||||
{0324, 0343},
|
||||
{0570, 0343},
|
||||
{0346, 0346},
|
||||
{0616, 0346},
|
||||
{0635, 0346},
|
||||
{0724, 0346},
|
||||
{0351, 0351},
|
||||
{0353, 0351},
|
||||
{0435, 0351},
|
||||
{0356, 0356},
|
||||
{0521, 0356},
|
||||
{0364, 0364},
|
||||
{0130, 0364},
|
||||
{0641, 0364},
|
||||
{0365, 0365},
|
||||
{0107, 0365},
|
||||
{0371, 0371},
|
||||
{0217, 0371},
|
||||
{0453, 0371},
|
||||
{0530, 0371},
|
||||
{0411, 0411},
|
||||
{0117, 0411},
|
||||
{0756, 0411},
|
||||
{0412, 0412},
|
||||
{0127, 0412},
|
||||
{0441, 0412},
|
||||
{0711, 0412},
|
||||
{0413, 0413},
|
||||
{0133, 0413},
|
||||
{0620, 0413},
|
||||
{0423, 0423},
|
||||
{0234, 0423},
|
||||
{0563, 0423},
|
||||
{0621, 0423},
|
||||
{0713, 0423},
|
||||
{0431, 0431},
|
||||
{0262, 0431},
|
||||
{0316, 0431},
|
||||
{0730, 0431},
|
||||
{0432, 0432},
|
||||
{0432, 0432},
|
||||
{0276, 0432},
|
||||
{0326, 0432},
|
||||
{0445, 0445},
|
||||
{0222, 0445},
|
||||
{0457, 0445},
|
||||
{0575, 0445},
|
||||
{0446, 0446},
|
||||
{0467, 0446},
|
||||
{0511, 0446},
|
||||
{0672, 0446},
|
||||
{0452, 0452},
|
||||
{0524, 0452},
|
||||
{0765, 0452},
|
||||
{0454, 0454},
|
||||
{0545, 0454},
|
||||
{0513, 0454},
|
||||
{0564, 0454},
|
||||
{0455, 0455},
|
||||
{0533, 0455},
|
||||
{0551, 0455},
|
||||
{0462, 0462},
|
||||
{0462, 0462},
|
||||
{0472, 0462},
|
||||
{0623, 0462},
|
||||
{0725, 0462},
|
||||
{0464, 0464},
|
||||
{0237, 0464},
|
||||
{0642, 0464},
|
||||
{0772, 0464},
|
||||
{0465, 0465},
|
||||
{0056, 0465},
|
||||
{0656, 0465},
|
||||
{0466, 0466},
|
||||
{0144, 0466},
|
||||
{0666, 0466},
|
||||
{0503, 0503},
|
||||
{0157, 0503},
|
||||
{0322, 0503},
|
||||
{0506, 0506},
|
||||
{0224, 0506},
|
||||
{0313, 0506},
|
||||
{0574, 0506},
|
||||
{0516, 0516},
|
||||
{0067, 0516},
|
||||
{0720, 0516},
|
||||
{0523, 0523},
|
||||
{0647, 0523},
|
||||
{0726, 0523},
|
||||
{0526, 0526},
|
||||
{0562, 0526},
|
||||
{0645, 0526},
|
||||
{0532, 0532},
|
||||
{0161, 0532},
|
||||
{0345, 0532},
|
||||
{0546, 0546},
|
||||
{0317, 0546},
|
||||
{0614, 0546},
|
||||
{0751, 0546},
|
||||
{0565, 0565},
|
||||
{0307, 0565},
|
||||
{0362, 0565},
|
||||
{0606, 0606},
|
||||
{0153, 0606},
|
||||
{0630, 0606},
|
||||
{0612, 0612},
|
||||
{0254, 0612},
|
||||
{0314, 0612},
|
||||
{0706, 0612},
|
||||
{0624, 0624},
|
||||
{0075, 0624},
|
||||
{0501, 0624},
|
||||
{0627, 0627},
|
||||
{0037, 0627},
|
||||
{0560, 0627},
|
||||
{0631, 0631},
|
||||
{0231, 0631},
|
||||
{0504, 0631},
|
||||
{0636, 0631},
|
||||
{0745, 0631},
|
||||
{0632, 0632},
|
||||
{0123, 0632},
|
||||
{0657, 0632},
|
||||
{0654, 0654},
|
||||
{0163, 0654},
|
||||
{0460, 0654},
|
||||
{0607, 0654},
|
||||
{0662, 0662},
|
||||
{0363, 0662},
|
||||
{0436, 0662},
|
||||
{0443, 0662},
|
||||
{0444, 0662},
|
||||
{0664, 0664},
|
||||
{0344, 0664},
|
||||
{0471, 0664},
|
||||
{0715, 0664},
|
||||
{0703, 0703},
|
||||
{0150, 0703},
|
||||
{0256, 0703},
|
||||
{0712, 0712},
|
||||
{0136, 0712},
|
||||
{0502, 0712},
|
||||
{0723, 0723},
|
||||
{0235, 0723},
|
||||
{0671, 0723},
|
||||
{0611, 0723},
|
||||
{0731, 0731},
|
||||
{0447, 0731},
|
||||
{0473, 0731},
|
||||
{0474, 0731},
|
||||
{0744, 0731},
|
||||
{0732, 0732},
|
||||
{0164, 0732},
|
||||
{0207, 0732},
|
||||
{0734, 0734},
|
||||
{0066, 0734},
|
||||
{0743, 0743},
|
||||
{0312, 0743},
|
||||
{0515, 0743},
|
||||
{0663, 0743},
|
||||
{0754, 0754},
|
||||
{0076, 0754},
|
||||
{0203, 0754},
|
||||
};
|
||||
|
||||
const QMap<unsigned int, unsigned int> DCSCodes::m_signFlip = {
|
||||
{0023, 0047},
|
||||
{0025, 0244},
|
||||
{0026, 0464},
|
||||
{0031, 0627},
|
||||
{0032, 0051},
|
||||
{0043, 0445},
|
||||
{0047, 0023},
|
||||
{0051, 0032},
|
||||
{0053, 0452},
|
||||
{0054, 0413},
|
||||
{0065, 0271},
|
||||
{0071, 0306},
|
||||
{0072, 0245},
|
||||
{0073, 0506},
|
||||
{0074, 0174},
|
||||
{0114, 0712},
|
||||
{0115, 0152},
|
||||
{0116, 0754},
|
||||
{0122, 0225},
|
||||
{0125, 0365},
|
||||
{0131, 0364},
|
||||
{0132, 0546},
|
||||
{0134, 0223},
|
||||
{0143, 0412},
|
||||
{0145, 0274},
|
||||
{0152, 0115},
|
||||
{0155, 0731},
|
||||
{0156, 0265},
|
||||
{0162, 0503},
|
||||
{0165, 0251},
|
||||
{0172, 0036},
|
||||
{0174, 0074},
|
||||
{0205, 0263},
|
||||
{0212, 0356},
|
||||
{0223, 0134},
|
||||
{0225, 0122},
|
||||
{0226, 0411},
|
||||
{0243, 0351},
|
||||
{0244, 0025},
|
||||
{0245, 0072},
|
||||
{0246, 0523},
|
||||
{0251, 0165},
|
||||
{0252, 0462},
|
||||
{0255, 0511},
|
||||
{0261, 0732},
|
||||
{0263, 0205},
|
||||
{0265, 0156},
|
||||
{0266, 0454},
|
||||
{0271, 0065},
|
||||
{0274, 0145},
|
||||
{0306, 0071},
|
||||
{0311, 0664},
|
||||
{0315, 0423},
|
||||
{0325, 0526},
|
||||
{0331, 0465},
|
||||
{0332, 0455},
|
||||
{0343, 0532},
|
||||
{0346, 0612},
|
||||
{0351, 0243},
|
||||
{0356, 0212},
|
||||
{0364, 0131},
|
||||
{0365, 0125},
|
||||
{0371, 0734},
|
||||
{0411, 0226},
|
||||
{0412, 0143},
|
||||
{0413, 0054},
|
||||
{0423, 0315},
|
||||
{0431, 0723},
|
||||
{0432, 0516},
|
||||
{0445, 0043},
|
||||
{0446, 0255},
|
||||
{0452, 0053},
|
||||
{0454, 0655},
|
||||
{0455, 0332},
|
||||
{0462, 0252},
|
||||
{0464, 0026},
|
||||
{0465, 0331},
|
||||
{0466, 0662},
|
||||
{0503, 0162},
|
||||
{0506, 0073},
|
||||
{0516, 0432},
|
||||
{0523, 0246},
|
||||
{0526, 0325},
|
||||
{0532, 0343},
|
||||
{0546, 0132},
|
||||
{0565, 0703},
|
||||
{0606, 0631},
|
||||
{0612, 0346},
|
||||
{0624, 0632},
|
||||
{0627, 0031},
|
||||
{0631, 0606},
|
||||
{0632, 0624},
|
||||
{0654, 0743},
|
||||
{0662, 0466},
|
||||
{0664, 0311},
|
||||
{0703, 0565},
|
||||
{0712, 0114},
|
||||
{0723, 0431},
|
||||
{0731, 0155},
|
||||
{0732, 0261},
|
||||
{0734, 0371},
|
||||
{0743, 0654},
|
||||
{0754, 0116},
|
||||
};
|
||||
|
||||
|
||||
void DCSCodes::getCanonicalCodes(QList<unsigned int>& codes)
|
||||
{
|
||||
codes.clear();
|
||||
|
||||
for (auto code : m_toCanonicalCode.keys())
|
||||
{
|
||||
if (code == m_toCanonicalCode.value(code)) {
|
||||
codes.append(code);
|
||||
}
|
||||
}
|
||||
}
|
35
sdrbase/dsp/dcscodes.h
Normal file
35
sdrbase/dsp/dcscodes.h
Normal file
@ -0,0 +1,35 @@
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (C) 2021 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 //
|
||||
// (at your option) any later version. //
|
||||
// //
|
||||
// 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/>. //
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef INCLUDE_DSP_DCSCODES_H_
|
||||
#define INCLUDE_DSP_DCSCODES_H_
|
||||
|
||||
#include <QList>
|
||||
#include <QMap>
|
||||
|
||||
#include "export.h"
|
||||
|
||||
class SDRBASE_API DCSCodes
|
||||
{
|
||||
public:
|
||||
static void getCanonicalCodes(QList<unsigned int>& codes);
|
||||
static const int m_nbCodes;
|
||||
static const QMap<unsigned int, unsigned int> m_toCanonicalCode;
|
||||
static const QMap<unsigned int, unsigned int> m_signFlip;
|
||||
};
|
||||
|
||||
#endif // INCLUDE_DSP_DCSCODES_H_
|
253
sdrbase/util/golay2312.cpp
Normal file
253
sdrbase/util/golay2312.cpp
Normal file
@ -0,0 +1,253 @@
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (C) 2021 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 //
|
||||
// (at your option) any later version. //
|
||||
// //
|
||||
// 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 <algorithm>
|
||||
#include <bitset>
|
||||
|
||||
#include "golay2312.h"
|
||||
|
||||
const unsigned int Golay2312::m_B[11] = {
|
||||
0b101001001111,
|
||||
0b111101101000,
|
||||
0b011110110100,
|
||||
0b001111011010,
|
||||
0b000111101101,
|
||||
0b101010111001,
|
||||
0b111100010011,
|
||||
0b110111000110,
|
||||
0b011011100011,
|
||||
0b100100111110,
|
||||
0b010010011111,
|
||||
};
|
||||
|
||||
const unsigned int Golay2312::m_I11[11] = {
|
||||
0b10000000000,
|
||||
0b01000000000,
|
||||
0b00100000000,
|
||||
0b00010000000,
|
||||
0b00001000000,
|
||||
0b00000100000,
|
||||
0b00000010000,
|
||||
0b00000001000,
|
||||
0b00000000100,
|
||||
0b00000000010,
|
||||
0b00000000001,
|
||||
};
|
||||
|
||||
const unsigned int Golay2312::m_I12[12] = {
|
||||
0b100000000000,
|
||||
0b010000000000,
|
||||
0b001000000000,
|
||||
0b000100000000,
|
||||
0b000010000000,
|
||||
0b000001000000,
|
||||
0b000000100000,
|
||||
0b000000010000,
|
||||
0b000000001000,
|
||||
0b000000000100,
|
||||
0b000000000010,
|
||||
0b000000000001,
|
||||
};
|
||||
|
||||
Golay2312::Golay2312()
|
||||
{
|
||||
initG();
|
||||
initH();
|
||||
buildCorrMatrix(m_corrPL, m_HPL);
|
||||
buildCorrMatrix(m_corrPF, m_HPF, true);
|
||||
}
|
||||
|
||||
Golay2312::~Golay2312()
|
||||
{
|
||||
}
|
||||
|
||||
void Golay2312::initG()
|
||||
{
|
||||
for (int r = 0; r < 23; r++)
|
||||
{
|
||||
// parity last
|
||||
if (r < 12) {
|
||||
m_GPL[r] = m_I12[r];
|
||||
} else {
|
||||
m_GPL[r] = m_B[r-12];
|
||||
}
|
||||
// parity first
|
||||
if (r < 11) {
|
||||
m_GPF[r] = m_B[r];
|
||||
} else {
|
||||
m_GPF[r] = m_I12[r-11];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Golay2312::initH()
|
||||
{
|
||||
for (int r = 0; r < 11; r++)
|
||||
{
|
||||
m_HPL[r] = (m_B[r] << 11) + m_I11[r]; // parity last
|
||||
m_HPF[r] = (m_I11[r] << 12) + m_B[r]; // parity first
|
||||
}
|
||||
}
|
||||
|
||||
void Golay2312::encodeParityLast(unsigned int msg, unsigned int *tx)
|
||||
{
|
||||
*tx = 0;
|
||||
|
||||
for (int r = 0; r < 23; r++) {
|
||||
*tx += (std::bitset<32>(m_GPL[r] & msg).count() % 2) << (22-r);
|
||||
}
|
||||
}
|
||||
|
||||
void Golay2312::encodeParityFirst(unsigned int msg, unsigned int *tx)
|
||||
{
|
||||
*tx = 0;
|
||||
|
||||
for (int r = 0; r < 23; r++) {
|
||||
*tx += (std::bitset<32>(m_GPF[r] & msg).count() % 2) << (22-r);
|
||||
}
|
||||
}
|
||||
|
||||
bool Golay2312::decodeParityLast(unsigned int *rx)
|
||||
{
|
||||
unsigned int s = syn(m_HPL, *rx);
|
||||
return lut(m_corrPL, s, rx);
|
||||
}
|
||||
|
||||
bool Golay2312::decodeParityFirst(unsigned int *rx)
|
||||
{
|
||||
unsigned int s = syn(m_HPF, *rx);
|
||||
return lut(m_corrPF, s, rx);
|
||||
}
|
||||
|
||||
unsigned int Golay2312::syn(unsigned int *H, unsigned int rx)
|
||||
{
|
||||
unsigned int s = 0;
|
||||
|
||||
for (int r = 0; r < 11; r++) {
|
||||
s += (std::bitset<32>(H[r] & rx).count() % 2) << (10-r);
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
bool Golay2312::lut(unsigned char *corr, unsigned int syndrome, unsigned int *rx)
|
||||
{
|
||||
if (syndrome == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
|
||||
for (; i < 3; i++)
|
||||
{
|
||||
if (corr[3*syndrome + i] == 0xFF) {
|
||||
break;
|
||||
} else {
|
||||
*rx ^= (1 << corr[3*syndrome + i]); // flip bit
|
||||
}
|
||||
}
|
||||
|
||||
if (i == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Golay2312::buildCorrMatrix(unsigned char *corr, unsigned int *H, bool pf)
|
||||
{
|
||||
int shiftP = pf ? 12 : 0; // shift in position value for parity bits
|
||||
int shiftW = pf ? 0 : 11; // shift in position value for message word bits
|
||||
std::fill(corr, corr + 3*2048, 0xFF);
|
||||
int syndromeI;
|
||||
unsigned int cw;
|
||||
|
||||
for (int i1 = 0; i1 < 12; i1++)
|
||||
{
|
||||
for (int i2 = i1+1; i2 < 12; i2++)
|
||||
{
|
||||
for (int i3 = i2+1; i3 < 12; i3++)
|
||||
{
|
||||
// 3 bit patterns (in message)
|
||||
cw = (1 << (i1+shiftW)) + (1 << (i2+shiftW)) + (1 << (i3+shiftW));
|
||||
syndromeI = syn(H, cw);
|
||||
corr[3*syndromeI + 0] = i1 + shiftW;
|
||||
corr[3*syndromeI + 1] = i2 + shiftW;
|
||||
corr[3*syndromeI + 2] = i3 + shiftW;
|
||||
}
|
||||
|
||||
// 2 bit patterns (in message)
|
||||
cw = (1 << (i1+shiftW)) + (1 << (i2+shiftW));
|
||||
syndromeI = syn(H, cw);
|
||||
corr[3*syndromeI + 0] = i1 + shiftW;
|
||||
corr[3*syndromeI + 1] = i2 + shiftW;
|
||||
|
||||
// 1 possible bit flip left in the parity part
|
||||
for (int ip = 0; ip < 11; ip++)
|
||||
{
|
||||
int syndromeIP = syndromeI ^ (1 << (10-ip));
|
||||
corr[3*syndromeIP + 0] = i1 + shiftW;
|
||||
corr[3*syndromeIP + 1] = i2 + shiftW;
|
||||
corr[3*syndromeIP + 2] = 10 - ip + shiftP;
|
||||
}
|
||||
}
|
||||
|
||||
// single bit patterns (in message)
|
||||
cw = (1 << (i1+shiftW));
|
||||
syndromeI = syn(H, cw);
|
||||
corr[3*syndromeI + 0] = i1 + shiftW;
|
||||
|
||||
for (int ip1 = 0; ip1 < 11; ip1++) // 1 more bit flip in parity
|
||||
{
|
||||
int syndromeIP1 = syndromeI ^ (1 << (10-ip1));
|
||||
corr[3*syndromeIP1 + 0] = i1 + shiftW;
|
||||
corr[3*syndromeIP1 + 1] = 10 - ip1 + shiftP;
|
||||
|
||||
for (int ip2 = ip1+1; ip2 < 11; ip2++) // 1 more bit flip in parity
|
||||
{
|
||||
int syndromeIP2 = syndromeIP1 ^ (1 << (10-ip2));
|
||||
corr[3*syndromeIP2 + 0] = i1 + shiftW;
|
||||
corr[3*syndromeIP2 + 1] = 10 - ip1 + shiftP;
|
||||
corr[3*syndromeIP2 + 2] = 10 - ip2 + shiftP;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// no bit patterns (in message) -> all in parity
|
||||
|
||||
for (int ip1 = 0; ip1 < 11; ip1++) // 1 bit flip in parity
|
||||
{
|
||||
int syndromeIP1 = (1 << (10-ip1));
|
||||
corr[3*syndromeIP1 + 0] = 10 - ip1 + shiftP;
|
||||
|
||||
for (int ip2 = ip1+1; ip2 < 11; ip2++) // 1 more bit flip in parity
|
||||
{
|
||||
int syndromeIP2 = syndromeIP1 ^ (1 << (10-ip2));
|
||||
corr[3*syndromeIP2 + 0] = 10 - ip1 + shiftP;
|
||||
corr[3*syndromeIP2 + 1] = 10 - ip2 + shiftP;
|
||||
|
||||
for (int ip3 = ip2+1; ip3 < 11; ip3++) // 1 more bit flip in parity
|
||||
{
|
||||
int syndromeIP3 = syndromeIP2 ^ (1 << (10-ip3));
|
||||
corr[3*syndromeIP3 + 0] = 10 - ip1 + shiftP;
|
||||
corr[3*syndromeIP3 + 1] = 10 - ip2 + shiftP;
|
||||
corr[3*syndromeIP3 + 2] = 10 - ip3 + shiftP;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
57
sdrbase/util/golay2312.h
Normal file
57
sdrbase/util/golay2312.h
Normal file
@ -0,0 +1,57 @@
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (C) 2021 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 //
|
||||
// (at your option) any later version. //
|
||||
// //
|
||||
// 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/>. //
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef INCLUDE_GOLAY2312_H_
|
||||
#define INCLUDE_GOLAY2312_H_
|
||||
|
||||
#include "export.h"
|
||||
|
||||
class SDRBASE_API Golay2312
|
||||
{
|
||||
public:
|
||||
Golay2312();
|
||||
~Golay2312();
|
||||
|
||||
void encodeParityLast(unsigned int msg, unsigned int *tx);
|
||||
void encodeParityFirst(unsigned int msg, unsigned int *tx);
|
||||
bool decodeParityLast(unsigned int *rx);
|
||||
bool decodeParityFirst(unsigned int *rx);
|
||||
|
||||
private:
|
||||
inline int bitAt(int i, unsigned int v) {
|
||||
return (v>>i) & 0x01;
|
||||
}
|
||||
void initG();
|
||||
void initH();
|
||||
void buildCorrMatrix(unsigned char *corr, unsigned int *H, bool pf = false);
|
||||
unsigned int syn(unsigned int *H, unsigned int rx);
|
||||
bool lut(unsigned char *corr, unsigned int syndrome, unsigned int *rx);
|
||||
|
||||
unsigned char m_corrPL[2048*3]; //!< up to 3 bit error correction by syndrome index - parity last
|
||||
unsigned char m_corrPF[2048*3]; //!< up to 3 bit error correction by syndrome index - parity first
|
||||
unsigned int m_GPL[23]; //!< Generator matrix of 23x12 bits - parity first (MSB)
|
||||
unsigned int m_GPF[23]; //!< Generator matrix of 23x12 bits - parity last (LSB)
|
||||
unsigned int m_HPL[11]; //!< Parity check matrix of 11x23 bits - parity last (LSB)
|
||||
unsigned int m_HPF[11]; //!< Parity check matrix of 11x23 bits - parity first (MSB)
|
||||
// building arrays
|
||||
static const unsigned int m_B[11]; //!< Coding matrix (11x12 bits)
|
||||
static const unsigned int m_I12[12]; //!< 12x12 identity matrix (12x12 bits)
|
||||
static const unsigned int m_I11[11]; //!< 11x11 identity matrix (11x11 bits)
|
||||
|
||||
};
|
||||
|
||||
#endif // INCLUDE_GOLAY2312_H_
|
@ -3,6 +3,7 @@ project (sdrbench)
|
||||
set(sdrbench_SOURCES
|
||||
mainbench.cpp
|
||||
parserbench.cpp
|
||||
test_golay2312.cpp
|
||||
)
|
||||
|
||||
set(sdrbench_HEADERS
|
||||
|
@ -64,6 +64,8 @@ void MainBench::run()
|
||||
testDecimateFF();
|
||||
} else if (m_parser.getTestType() == ParserBench::TestAMBE) {
|
||||
testAMBE();
|
||||
} else if (m_parser.getTestType() == ParserBench::TestGolay2312) {
|
||||
testGolay2312();
|
||||
} else {
|
||||
qDebug() << "MainBench::run: unknown test type: " << m_parser.getTestType();
|
||||
}
|
||||
@ -207,6 +209,7 @@ void MainBench::testAMBE()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void MainBench::decimateII(const qint16* buf, int len)
|
||||
{
|
||||
SampleVector::iterator it = m_convertBuffer.begin();
|
||||
|
@ -54,6 +54,7 @@ private:
|
||||
void testDecimateFI();
|
||||
void testDecimateFF();
|
||||
void testAMBE();
|
||||
void testGolay2312();
|
||||
void decimateII(const qint16 *buf, int len);
|
||||
void decimateInfII(const qint16 *buf, int len);
|
||||
void decimateSupII(const qint16 *buf, int len);
|
||||
|
@ -24,7 +24,7 @@
|
||||
|
||||
ParserBench::ParserBench() :
|
||||
m_testOption(QStringList() << "t" << "test",
|
||||
"Test type: decimateii, decimatefi, decimateff, decimateif, decimateinfii, decimatesupii, ambe",
|
||||
"Test type: decimateii, decimatefi, decimateff, decimateif, decimateinfii, decimatesupii, ambe, golay2312",
|
||||
"test",
|
||||
"decimateii"),
|
||||
m_nbSamplesOption(QStringList() << "n" << "nb-samples",
|
||||
@ -69,7 +69,7 @@ void ParserBench::parse(const QCoreApplication& app)
|
||||
|
||||
QString test = m_parser.value(m_testOption);
|
||||
|
||||
QString testStr = "([a-z]+)";
|
||||
QString testStr = "([a-z0-9]+)";
|
||||
QRegExp ipRegex ("^" + testStr + "$");
|
||||
QRegExpValidator ipValidator(ipRegex);
|
||||
|
||||
@ -127,6 +127,8 @@ ParserBench::TestType ParserBench::getTestType() const
|
||||
return TestDecimatorsSupII;
|
||||
} else if (m_testStr == "ambe") {
|
||||
return TestAMBE;
|
||||
} else if (m_testStr == "golay2312") {
|
||||
return TestGolay2312;
|
||||
} else {
|
||||
return TestDecimatorsII;
|
||||
}
|
||||
|
@ -35,7 +35,8 @@ public:
|
||||
TestDecimatorsFF,
|
||||
TestDecimatorsInfII,
|
||||
TestDecimatorsSupII,
|
||||
TestAMBE
|
||||
TestAMBE,
|
||||
TestGolay2312
|
||||
} TestType;
|
||||
|
||||
ParserBench();
|
||||
|
106
sdrbench/test_golay2312.cpp
Normal file
106
sdrbench/test_golay2312.cpp
Normal file
@ -0,0 +1,106 @@
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (C) 2021 Edouard Griffiths, F4EXB. //
|
||||
// //
|
||||
// Swagger server adapter interface //
|
||||
// //
|
||||
// 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 //
|
||||
// (at your option) any later version. //
|
||||
// //
|
||||
// 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 <QDebug>
|
||||
|
||||
#include "mainbench.h"
|
||||
#include "util/golay2312.h"
|
||||
|
||||
void MainBench::testGolay2312()
|
||||
{
|
||||
qDebug() << "MainBench::testGolay2312: parity first";
|
||||
|
||||
unsigned int msg = 04023; // {1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1};
|
||||
unsigned int expectedCodeword = 035430000 + msg;
|
||||
Golay2312 golay2312;
|
||||
bool success = true;
|
||||
|
||||
unsigned int codeword;
|
||||
golay2312.encodeParityFirst(msg, &codeword);
|
||||
|
||||
if (codeword != expectedCodeword)
|
||||
{
|
||||
qDebug() << "MainBench::testGolay2312:"
|
||||
<< "encoder mismatch: got:" << oct << codeword
|
||||
<< "expected:" << oct << expectedCodeword;
|
||||
success = false;
|
||||
}
|
||||
|
||||
unsigned int rxCodeword = codeword;
|
||||
bool decoded = golay2312.decodeParityFirst(&rxCodeword);
|
||||
|
||||
if (!decoded)
|
||||
{
|
||||
qDebug() << "MainBench::testGolay2312:"
|
||||
<< " unrecoverable error (no error)";
|
||||
success = false;
|
||||
}
|
||||
else if (rxCodeword != codeword)
|
||||
{
|
||||
qDebug() << "MainBench::testGolay2312:"
|
||||
<< "decoder mismatch (no error): got:" << oct << rxCodeword
|
||||
<< "expected:" << oct << codeword;
|
||||
success = false;
|
||||
}
|
||||
|
||||
// flip one bit (4th)
|
||||
rxCodeword = codeword ^ 000020000;
|
||||
decoded = golay2312.decodeParityFirst(&rxCodeword);
|
||||
|
||||
if (!decoded)
|
||||
{
|
||||
qDebug() << "MainBench::testGolay2312:"
|
||||
<< " unrecoverable error (parity[1])";
|
||||
success = false;
|
||||
}
|
||||
else if (rxCodeword != codeword)
|
||||
{
|
||||
qDebug() << "MainBench::testGolay2312:"
|
||||
<< "decoder mismatch (parity[1]): got:" << oct << rxCodeword
|
||||
<< "expected:" << oct << codeword;
|
||||
success = false;
|
||||
}
|
||||
|
||||
// flip two bits (1st, 5th)
|
||||
rxCodeword = codeword ^ 000120000;
|
||||
decoded = golay2312.decodeParityFirst(&rxCodeword);
|
||||
|
||||
if (!decoded)
|
||||
{
|
||||
qDebug() << "MainBench::testGolay2312:"
|
||||
<< " unrecoverable error (parity[1,3])";
|
||||
success = false;
|
||||
}
|
||||
else if (rxCodeword != codeword)
|
||||
{
|
||||
qDebug() << "MainBench::testGolay2312:"
|
||||
<< "decoder mismatch (parity[1,3]): got:" << oct << rxCodeword
|
||||
<< "expected:" << oct << codeword;
|
||||
success = false;
|
||||
}
|
||||
|
||||
// Conclusion
|
||||
|
||||
if (success) {
|
||||
qDebug() << "MainBench::testGolay2312: success";
|
||||
} else {
|
||||
qDebug() << "MainBench::testGolay2312: failed";
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user