DSD demod: old code cleanup

pull/85/head
f4exb 2017-10-04 00:29:47 +02:00
rodzic 392f1f43d6
commit 3405424ad1
4 zmienionych plików z 23 dodań i 506 usunięć

Wyświetl plik

@ -33,19 +33,22 @@
MESSAGE_CLASS_DEFINITION(DSDDemod::MsgConfigureChannelizer, Message)
MESSAGE_CLASS_DEFINITION(DSDDemod::MsgConfigureDSDDemod, Message)
MESSAGE_CLASS_DEFINITION(DSDDemod::MsgConfigureDSDDemodPrivate, Message)
MESSAGE_CLASS_DEFINITION(DSDDemod::MsgConfigureMyPosition, Message)
const int DSDDemod::m_udpBlockSize = 512;
DSDDemod::DSDDemod(DeviceSourceAPI *deviceAPI) :
m_deviceAPI(deviceAPI),
m_sampleCount(0),
m_squelchCount(0),
m_squelchOpen(false),
m_interpolatorDistance(0.0f),
m_interpolatorDistanceRemain(0.0f),
m_sampleCount(0),
m_squelchCount(0),
m_squelchGate(0),
m_squelchLevel(1e-4),
m_squelchOpen(false),
m_movingAverage(40, 0),
m_fmExcursion(24),
m_audioFifo1(48000),
m_audioFifo1(48000),
m_audioFifo2(48000),
m_scope(0),
m_scopeEnabled(true),
@ -54,19 +57,6 @@ DSDDemod::DSDDemod(DeviceSourceAPI *deviceAPI) :
{
setObjectName("DSDDemod");
m_config.m_inputSampleRate = 96000;
m_config.m_inputFrequencyOffset = 0;
m_config.m_rfBandwidth = 10000.0;
m_config.m_fmDeviation = 5000.0;
m_config.m_demodGain = 1.0;
m_config.m_squelchGate = 5; // 10s of ms at 48000 Hz sample rate. Corresponds to 2400 for AGC attack
m_config.m_squelch = -30.0;
m_config.m_volume = 1.0;
m_config.m_baudRate = 4800;
m_config.m_audioMute = false;
m_config.m_audioSampleRate = DSPEngine::instance()->getAudioSampleRate();
m_config.m_enableCosineFiltering = false;
m_audioBuffer.resize(1<<14);
m_audioBufferFill = 0;
@ -82,7 +72,7 @@ DSDDemod::DSDDemod(DeviceSourceAPI *deviceAPI) :
DSPEngine::instance()->addAudioSink(&m_audioFifo1);
DSPEngine::instance()->addAudioSink(&m_audioFifo2);
m_udpBufferAudio = new UDPSink<AudioSample>(this, m_udpBlockSize, m_config.m_udpPort);
m_udpBufferAudio = new UDPSink<AudioSample>(this, m_udpBlockSize, m_settings.m_udpPort);
m_audioFifo1.setUDPSink(m_udpBufferAudio);
m_audioFifo2.setUDPSink(m_udpBufferAudio);
@ -90,7 +80,7 @@ DSDDemod::DSDDemod(DeviceSourceAPI *deviceAPI) :
m_threadedChannelizer = new ThreadedBasebandSampleSink(m_channelizer, this);
m_deviceAPI->addThreadedSink(m_threadedChannelizer);
apply(true);
applySettings(m_settings, true);
}
DSDDemod::~DSDDemod()
@ -105,47 +95,6 @@ DSDDemod::~DSDDemod()
delete m_channelizer;
}
void DSDDemod::configure(MessageQueue* messageQueue,
Real rfBandwidth,
Real fmDeviation,
Real demodGain,
Real volume,
int baudRate,
int squelchGate,
Real squelch,
bool audioMute,
bool enableCosineFiltering,
bool syncOrConstellation,
bool slot1On,
bool slot2On,
bool tdmaStereo,
bool pllLock,
bool udpCopyAudio,
const QString& udpAddress,
quint16 udpPort,
bool force)
{
Message* cmd = MsgConfigureDSDDemodPrivate::create(rfBandwidth,
fmDeviation,
demodGain,
volume,
baudRate,
squelchGate,
squelch,
audioMute,
enableCosineFiltering,
syncOrConstellation,
slot1On,
slot2On,
tdmaStereo,
pllLock,
udpCopyAudio,
udpAddress,
udpPort,
force);
messageQueue->push(cmd);
}
void DSDDemod::configureMyPosition(MessageQueue* messageQueue, float myLatitude, float myLongitude)
{
Message* cmd = MsgConfigureMyPosition::create(myLatitude, myLongitude);
@ -369,13 +318,14 @@ bool DSDDemod::handleMessage(const Message& cmd)
{
DownChannelizer::MsgChannelizerNotification& notif = (DownChannelizer::MsgChannelizerNotification&) cmd;
m_config.m_inputSampleRate = notif.getSampleRate();
m_config.m_inputFrequencyOffset = notif.getFrequencyOffset();
DSDDemodSettings settings = m_settings;
settings.m_inputSampleRate = notif.getSampleRate();
settings.m_inputFrequencyOffset = notif.getFrequencyOffset();
apply();
applySettings(settings);
qDebug() << "DSDDemod::handleMessage: MsgChannelizerNotification: m_inputSampleRate: " << m_config.m_inputSampleRate
<< " m_inputFrequencyOffset: " << m_config.m_inputFrequencyOffset;
qDebug() << "DSDDemod::handleMessage: MsgChannelizerNotification: m_inputSampleRate: " << settings.m_inputSampleRate
<< " m_inputFrequencyOffset: " << settings.m_inputFrequencyOffset;
return true;
}
@ -422,50 +372,6 @@ bool DSDDemod::handleMessage(const Message& cmd)
return true;
}
else if (MsgConfigureDSDDemodPrivate::match(cmd))
{
MsgConfigureDSDDemodPrivate& cfg = (MsgConfigureDSDDemodPrivate&) cmd;
m_config.m_rfBandwidth = cfg.getRFBandwidth();
m_config.m_demodGain = cfg.getDemodGain();
m_config.m_fmDeviation = cfg.getFMDeviation();
m_config.m_volume = cfg.getVolume();
m_config.m_baudRate = cfg.getBaudRate();
m_config.m_squelchGate = cfg.getSquelchGate();
m_config.m_squelch = cfg.getSquelch();
m_config.m_audioMute = cfg.getAudioMute();
m_config.m_enableCosineFiltering = cfg.getEnableCosineFiltering();
m_config.m_syncOrConstellation = cfg.getSyncOrConstellation();
m_config.m_slot1On = cfg.getSlot1On();
m_config.m_slot2On = cfg.getSlot2On();
m_config.m_tdmaStereo = cfg.getTDMAStereo();
m_config.m_pllLock = cfg.getPLLLock();
m_config.m_udpCopyAudio = cfg.getUDPCopyAudio();
m_config.m_udpAddress = cfg.getUDPAddress();
m_config.m_udpPort = cfg.getUDPPort();
apply();
qDebug() << "DSDDemod::handleMessage: MsgConfigureDSDDemodPrivate: m_rfBandwidth: " << m_config.m_rfBandwidth
<< " m_fmDeviation: " << m_config.m_fmDeviation
<< " m_demodGain: " << m_config.m_demodGain
<< " m_volume: " << m_config.m_volume
<< " m_baudRate: " << m_config.m_baudRate
<< " m_squelchGate" << m_config.m_squelchGate
<< " m_squelch: " << m_config.m_squelch
<< " m_audioMute: " << m_config.m_audioMute
<< " m_enableCosineFiltering: " << m_config.m_enableCosineFiltering
<< " m_syncOrConstellation: " << m_config.m_syncOrConstellation
<< " m_slot1On: " << m_config.m_slot1On
<< " m_slot2On: " << m_config.m_slot2On
<< " m_tdmaStereo: " << m_config.m_tdmaStereo
<< " m_pllLock: " << m_config.m_pllLock
<< " m_udpCopyAudio: " << m_config.m_udpCopyAudio
<< " m_udpAddress: " << m_config.m_udpAddress
<< " m_udpPort: " << m_config.m_udpPort;
return true;
}
else if (MsgConfigureMyPosition::match(cmd))
{
MsgConfigureMyPosition& cfg = (MsgConfigureMyPosition&) cmd;
@ -478,86 +384,6 @@ bool DSDDemod::handleMessage(const Message& cmd)
}
}
void DSDDemod::apply(bool force)
{
if ((m_config.m_inputFrequencyOffset != m_running.m_inputFrequencyOffset) ||
(m_config.m_inputSampleRate != m_running.m_inputSampleRate) || force)
{
m_nco.setFreq(-m_config.m_inputFrequencyOffset, m_config.m_inputSampleRate);
}
if ((m_config.m_inputSampleRate != m_running.m_inputSampleRate) ||
(m_config.m_rfBandwidth != m_running.m_rfBandwidth) || force)
{
m_settingsMutex.lock();
m_interpolator.create(16, m_config.m_inputSampleRate, (m_config.m_rfBandwidth) / 2.2);
m_interpolatorDistanceRemain = 0;
m_interpolatorDistance = (Real) m_config.m_inputSampleRate / (Real) m_config.m_audioSampleRate;
m_phaseDiscri.setFMScaling((float) m_config.m_rfBandwidth / (float) m_config.m_fmDeviation);
m_settingsMutex.unlock();
}
if ((m_config.m_fmDeviation != m_running.m_fmDeviation) || force)
{
m_phaseDiscri.setFMScaling((float) m_config.m_rfBandwidth / (float) m_config.m_fmDeviation);
}
if ((m_config.m_squelchGate != m_running.m_squelchGate) || force)
{
m_squelchGate = 480 * m_config.m_squelchGate; // gate is given in 10s of ms at 48000 Hz audio sample rate
m_squelchCount = 0; // reset squelch open counter
}
if ((m_config.m_squelch != m_running.m_squelch) || force)
{
// input is a value in dB
m_squelchLevel = std::pow(10.0, m_config.m_squelch / 10.0);
//m_squelchLevel *= m_squelchLevel;
}
if ((m_config.m_volume != m_running.m_volume) || force)
{
m_dsdDecoder.setAudioGain(m_config.m_volume);
}
if ((m_config.m_baudRate != m_running.m_baudRate) || force)
{
m_dsdDecoder.setBaudRate(m_config.m_baudRate);
}
if ((m_config.m_enableCosineFiltering != m_running.m_enableCosineFiltering) || force)
{
m_dsdDecoder.enableCosineFiltering(m_config.m_enableCosineFiltering);
}
if ((m_config.m_tdmaStereo != m_running.m_tdmaStereo) || force)
{
m_dsdDecoder.setTDMAStereo(m_config.m_tdmaStereo);
}
if ((m_config.m_pllLock != m_running.m_pllLock) || force)
{
m_dsdDecoder.setSymbolPLLLock(m_config.m_pllLock);
}
if ((m_config.m_udpAddress != m_running.m_udpAddress)
|| (m_config.m_udpPort != m_running.m_udpPort) || force)
{
m_udpBufferAudio->setAddress(m_config.m_udpAddress);
m_udpBufferAudio->setPort(m_config.m_udpPort);
}
if ((m_config.m_udpCopyAudio != m_running.m_udpCopyAudio)
|| (m_config.m_slot1On != m_running.m_slot1On)
|| (m_config.m_slot2On != m_running.m_slot2On) || force)
{
m_audioFifo1.setCopyToUDP(m_config.m_slot1On && m_config.m_udpCopyAudio);
m_audioFifo2.setCopyToUDP(m_config.m_slot2On && !m_config.m_slot1On && m_config.m_udpCopyAudio);
}
m_running = m_config;
}
void DSDDemod::applySettings(DSDDemodSettings& settings, bool force)
{
if ((settings.m_inputFrequencyOffset != m_settings.m_inputFrequencyOffset) ||
@ -592,7 +418,6 @@ void DSDDemod::applySettings(DSDDemodSettings& settings, bool force)
{
// input is a value in dB
m_squelchLevel = std::pow(10.0, settings.m_squelch / 10.0);
//m_squelchLevel *= m_squelchLevel;
}
if ((settings.m_volume != m_settings.m_volume) || force)

Wyświetl plik

@ -92,26 +92,6 @@ public:
~DSDDemod();
void setScopeSink(BasebandSampleSink* sampleSink) { m_scope = sampleSink; }
void configure(MessageQueue* messageQueue,
Real rfBandwidth,
Real fmDeviation,
Real demodGain,
Real volume,
int baudRate,
int squelchGate,
Real squelch,
bool audioMute,
bool enableCosineFiltering,
bool syncOrConstellation,
bool slot1On,
bool slot2On,
bool tdmaStereo,
bool pllLock,
bool udpCopyAudio,
const QString& udpAddress,
quint16 udpPort,
bool force);
void configureMyPosition(MessageQueue* messageQueue, float myLatitude, float myLongitude);
virtual void feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool po);
@ -159,180 +139,11 @@ private:
{}
};
class MsgConfigureDSDDemodPrivate : public Message {
MESSAGE_CLASS_DECLARATION
public:
Real getRFBandwidth() const { return m_rfBandwidth; }
Real getFMDeviation() const { return m_fmDeviation; }
Real getDemodGain() const { return m_demodGain; }
Real getVolume() const { return m_volume; }
int getBaudRate() const { return m_baudRate; }
int getSquelchGate() const { return m_squelchGate; }
Real getSquelch() const { return m_squelch; }
bool getAudioMute() const { return m_audioMute; }
bool getEnableCosineFiltering() const { return m_enableCosineFiltering; }
bool getSyncOrConstellation() const { return m_syncOrConstellation; }
bool getSlot1On() const { return m_slot1On; }
bool getSlot2On() const { return m_slot2On; }
bool getTDMAStereo() const { return m_tdmaStereo; }
bool getPLLLock() const { return m_pllLock; }
bool getUDPCopyAudio() const { return m_udpCopyAudio; }
const QString& getUDPAddress() const { return m_udpAddress; }
quint16 getUDPPort() const { return m_udpPort; }
static MsgConfigureDSDDemodPrivate* create(Real rfBandwidth,
Real fmDeviation,
Real demodGain,
Real volume,
int baudRate,
int squelchGate,
Real squelch,
bool audioMute,
bool enableCosineFiltering,
bool syncOrConstellation,
bool slot1On,
bool slot2On,
bool tdmaStereo,
bool pllLock,
bool udpCopyAudio,
const QString& udpAddress,
quint16 udpPort,
bool force)
{
return new MsgConfigureDSDDemodPrivate(rfBandwidth,
fmDeviation,
demodGain,
volume,
baudRate,
squelchGate,
squelch,
audioMute,
enableCosineFiltering,
syncOrConstellation,
slot1On,
slot2On,
tdmaStereo,
pllLock,
udpCopyAudio,
udpAddress,
udpPort,
force);
}
private:
Real m_rfBandwidth;
Real m_fmDeviation;
Real m_demodGain;
Real m_volume;
int m_baudRate;
int m_squelchGate;
Real m_squelch;
bool m_audioMute;
bool m_enableCosineFiltering;
bool m_syncOrConstellation;
bool m_slot1On;
bool m_slot2On;
bool m_tdmaStereo;
bool m_pllLock;
bool m_udpCopyAudio;
QString m_udpAddress;
quint16 m_udpPort;
bool m_force;
MsgConfigureDSDDemodPrivate(Real rfBandwidth,
Real fmDeviation,
Real demodGain,
Real volume,
int baudRate,
int squelchGate,
Real squelch,
bool audioMute,
bool enableCosineFiltering,
bool syncOrConstellation,
bool slot1On,
bool slot2On,
bool tdmaStereo,
bool pllLock,
bool udpCopyAudio,
const QString& udpAddress,
quint16 udpPort,
bool force) :
Message(),
m_rfBandwidth(rfBandwidth),
m_fmDeviation(fmDeviation),
m_demodGain(demodGain),
m_volume(volume),
m_baudRate(baudRate),
m_squelchGate(squelchGate),
m_squelch(squelch),
m_audioMute(audioMute),
m_enableCosineFiltering(enableCosineFiltering),
m_syncOrConstellation(syncOrConstellation),
m_slot1On(slot1On),
m_slot2On(slot2On),
m_tdmaStereo(tdmaStereo),
m_pllLock(pllLock),
m_udpCopyAudio(udpCopyAudio),
m_udpAddress(udpAddress),
m_udpPort(udpPort),
m_force(force)
{ }
};
enum RateState {
RSInitialFill,
RSRunning
};
struct Config {
int m_inputSampleRate;
qint64 m_inputFrequencyOffset;
Real m_rfBandwidth;
Real m_fmDeviation;
Real m_demodGain;
Real m_volume;
int m_baudRate;
int m_squelchGate;
Real m_squelch;
bool m_audioMute;
quint32 m_audioSampleRate;
bool m_enableCosineFiltering;
bool m_syncOrConstellation;
bool m_slot1On;
bool m_slot2On;
bool m_tdmaStereo;
bool m_pllLock;
bool m_udpCopyAudio;
QString m_udpAddress;
quint16 m_udpPort;
Config() :
m_inputSampleRate(-1),
m_inputFrequencyOffset(0),
m_rfBandwidth(10000.0),
m_fmDeviation(5000.0),
m_demodGain(1.0),
m_volume(1.0),
m_baudRate(4800),
m_squelchGate(1),
m_squelch(-40.0),
m_audioMute(false),
m_audioSampleRate(0),
m_enableCosineFiltering(false),
m_syncOrConstellation(false),
m_slot1On(false),
m_slot2On(false),
m_tdmaStereo(false),
m_pllLock(true),
m_udpCopyAudio(false),
m_udpAddress("127.0.0.1"),
m_udpPort(9999)
{ }
};
Config m_config;
Config m_running;
DSDDemodSettings m_settings;
DeviceSourceAPI *m_deviceAPI;
@ -350,7 +161,6 @@ private:
double m_squelchLevel;
bool m_squelchOpen;
Real m_lastArgument;
MovingAverage<double> m_movingAverage;
double m_magsq;
double m_magsqSum;
@ -378,7 +188,6 @@ private:
static const int m_udpBlockSize;
void apply(bool force = false);
void applySettings(DSDDemodSettings& settings, bool force = false);
};

Wyświetl plik

@ -83,24 +83,6 @@ void DSDDemodGUI::resetToDefaults()
QByteArray DSDDemodGUI::serialize() const
{
return m_settings.serialize();
// SimpleSerializer s(1);
// s.writeS32(1, m_channelMarker.getCenterFrequency());
// s.writeS32(2, ui->rfBW->value());
// s.writeS32(3, ui->demodGain->value());
// s.writeS32(4, ui->fmDeviation->value());
// s.writeS32(5, ui->squelch->value());
// s.writeU32(7, m_channelMarker.getColor().rgb());
// s.writeS32(8, ui->squelchGate->value());
// s.writeS32(9, ui->volume->value());
// s.writeBlob(10, ui->scopeGUI->serialize());
// s.writeS32(11, ui->baudRate->currentIndex());
// s.writeBool(12, m_enableCosineFiltering);
// s.writeBool(13, m_syncOrConstellation);
// s.writeBool(14, m_slot1On);
// s.writeBool(15, m_slot2On);
// s.writeBool(16, m_tdmaStereo);
// s.writeBlob(17, m_channelMarker.serialize());
// return s.final();
}
bool DSDDemodGUI::deserialize(const QByteArray& data)
@ -116,73 +98,6 @@ bool DSDDemodGUI::deserialize(const QByteArray& data)
resetToDefaults();
return false;
}
// SimpleDeserializer d(data);
//
// if (!d.isValid())
// {
// resetToDefaults();
// return false;
// }
//
// if (d.getVersion() == 1)
// {
// QByteArray bytetmp;
// QString strtmp;
// quint32 u32tmp;
// qint32 tmp;
//
// blockApplySettings(true);
// m_channelMarker.blockSignals(true);
//
// d.readBlob(17, &bytetmp);
// m_channelMarker.deserialize(bytetmp);
//
// d.readS32(1, &tmp, 0);
// m_channelMarker.setCenterFrequency(tmp);
// d.readS32(2, &tmp, 4);
// ui->rfBW->setValue(tmp);
// d.readS32(3, &tmp, 3);
// ui->demodGain->setValue(tmp);
// d.readS32(4, &tmp, 20);
// ui->fmDeviation->setValue(tmp);
// d.readS32(5, &tmp, -40);
// ui->squelch->setValue(tmp);
//
// if(d.readU32(7, &u32tmp))
// {
// m_channelMarker.setColor(u32tmp);
// }
//
// d.readS32(8, &tmp, 5);
// ui->squelchGate->setValue(tmp);
// d.readS32(9, &tmp, 20);
// ui->volume->setValue(tmp);
// d.readBlob(10, &bytetmp);
// ui->scopeGUI->deserialize(bytetmp);
// d.readS32(11, &tmp, 20);
// ui->baudRate->setCurrentIndex(tmp);
// d.readBool(12, &m_enableCosineFiltering, false);
// d.readBool(13, &m_syncOrConstellation, false);
// d.readBool(14, &m_slot1On, false);
// d.readBool(15, &m_slot2On, false);
// d.readBool(16, &m_tdmaStereo, false);
//
// this->setWindowTitle(m_channelMarker.getTitle());
// displayUDPAddress();
//
// blockApplySettings(false);
// m_channelMarker.blockSignals(false);
//
// updateMyPosition(); // we do it also here to be able to refresh with latest settings
// applySettings(true);
// return true;
// }
// else
// {
// resetToDefaults();
// return false;
// }
}
bool DSDDemodGUI::handleMessage(const Message& message __attribute__((unused)))
@ -464,38 +379,6 @@ void DSDDemodGUI::applySettings(bool force)
DSDDemod::MsgConfigureDSDDemod* message = DSDDemod::MsgConfigureDSDDemod::create( m_settings, force);
m_dsdDemod->getInputMessageQueue()->push(message);
// ui->deltaFrequency->setValue(m_channelMarker.getCenterFrequency());
// ui->rfBWText->setText(QString("%1k").arg(ui->rfBW->value() / 10.0, 0, 'f', 1));
// ui->demodGainText->setText(QString("%1").arg(ui->demodGain->value() / 100.0, 0, 'f', 2));
// ui->fmDeviationText->setText(QString("%1k").arg(ui->fmDeviation->value() / 10.0, 0, 'f', 1));
// ui->squelchGateText->setText(QString("%1").arg(ui->squelchGate->value() * 10.0, 0, 'f', 0));
// ui->volumeText->setText(QString("%1").arg(ui->volume->value() / 10.0, 0, 'f', 1));
// ui->enableCosineFiltering->setChecked(m_enableCosineFiltering);
// ui->syncOrConstellation->setChecked(m_syncOrConstellation);
// ui->slot1On->setChecked(m_slot1On);
// ui->slot2On->setChecked(m_slot2On);
// ui->tdmaStereoSplit->setChecked(m_tdmaStereo);
// m_dsdDemod->configure(m_dsdDemod->getInputMessageQueue(),
// m_settings.m_rfBandwidth,
// m_settings.m_fmDeviation,
// m_settings.m_demodGain,
// m_settings.m_volume,
// DSDDemodBaudRates::getRate(ui->baudRate->currentIndex()),
// m_settings.m_squelchGate, // in 10ths of ms
// m_settings.m_squelch,
// m_settings.m_audioMute,
// m_settings.m_enableCosineFiltering,
// m_settings.m_syncOrConstellation,
// m_settings.m_slot1On,
// m_settings.m_slot2On,
// m_settings.m_tdmaStereo,
// m_settings.m_pllLock,
// m_settings.m_udpCopyAudio,
// m_channelMarker.getUDPAddress(),
// m_channelMarker.getUDPSendPort(),
// force);
}
}

Wyświetl plik

@ -32,13 +32,13 @@ void DSDDemodSettings::resetToDefaults()
{
m_inputSampleRate = 96000;
m_inputFrequencyOffset = 0;
m_rfBandwidth = 10000.0;
m_rfBandwidth = 12500.0;
m_fmDeviation = 5000.0;
m_demodGain = 1.0;
m_volume = 1.0;
m_demodGain = 1.25;
m_volume = 2.0;
m_baudRate = 4800;
m_squelchGate = 5; // 10s of ms at 48000 Hz sample rate. Corresponds to 2400 for AGC attack
m_squelch = -30.0;
m_squelch = -40.0;
m_audioMute = false;
m_audioSampleRate = DSPEngine::instance()->getAudioSampleRate();
m_enableCosineFiltering = false;
@ -107,11 +107,11 @@ bool DSDDemodSettings::deserialize(const QByteArray& data)
d.readS32(1, &tmp, 0);
m_inputFrequencyOffset = tmp;
d.readS32(2, &tmp, 4);
d.readS32(2, &tmp, 125);
m_rfBandwidth = tmp * 100.0;
d.readS32(3, &tmp, 3);
d.readS32(3, &tmp, 125);
m_demodGain = tmp / 100.0;
d.readS32(4, &tmp, 20);
d.readS32(4, &tmp, 50);
m_fmDeviation = tmp * 100.0;
d.readS32(5, &tmp, -400);
m_squelch = tmp / 10.0;