1
0
mirror of https://github.com/f4exb/sdrangel.git synced 2024-11-25 01:18:38 -05:00

Compare commits

...

6 Commits

40 changed files with 938 additions and 253 deletions

View File

@ -1,3 +1,11 @@
sdrangel (6.17.6-1) unstable; urgency=medium
* Remote plugins: added capability to choose sample size in transmission. Implements #1078
* Remote input: added some control of remote instance. Implements #1074
* Remote Input: fixed segfault when stream sample rate is lowered
-- Edouard Griffiths, F4EXB <f4exb06@gmail.com> Sun, 26 Dec 2021 11:10:26 +0100
sdrangel (6.17.5-1) unstable; urgency=medium sdrangel (6.17.5-1) unstable; urgency=medium
* ADSB demod and VOR feature: Always use C locale for parsing coords in airport database. * ADSB demod and VOR feature: Always use C locale for parsing coords in airport database.

View File

@ -16,7 +16,7 @@ set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
# configure version # configure version
set(sdrangel_VERSION_MAJOR "6") set(sdrangel_VERSION_MAJOR "6")
set(sdrangel_VERSION_MINOR "17") set(sdrangel_VERSION_MINOR "17")
set(sdrangel_VERSION_PATCH "5") set(sdrangel_VERSION_PATCH "6")
set(sdrangel_VERSION_SUFFIX "") set(sdrangel_VERSION_SUFFIX "")
# SDRAngel cmake options # SDRAngel cmake options

8
debian/changelog vendored
View File

@ -1,3 +1,11 @@
sdrangel (6.17.6-1) unstable; urgency=medium
* Remote plugins: added capability to choose sample size in transmission. Implements #1078
* Remote input: added some control of remote instance. Implements #1074
* Remote Input: fixed segfault when stream sample rate is lowered
-- Edouard Griffiths, F4EXB <f4exb06@gmail.com> Sun, 26 Dec 2021 11:10:26 +0100
sdrangel (6.17.5-1) unstable; urgency=medium sdrangel (6.17.5-1) unstable; urgency=medium
* ADSB demod and VOR feature: Always use C locale for parsing coords in airport database. * ADSB demod and VOR feature: Always use C locale for parsing coords in airport database.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

View File

@ -35,6 +35,7 @@
#include "dsp/hbfilterchainconverter.h" #include "dsp/hbfilterchainconverter.h"
#include "dsp/devicesamplemimo.h" #include "dsp/devicesamplemimo.h"
#include "dsp/dspdevicesourceengine.h" #include "dsp/dspdevicesourceengine.h"
#include "dsp/devicesamplesource.h"
#include "device/deviceapi.h" #include "device/deviceapi.h"
#include "feature/feature.h" #include "feature/feature.h"
#include "settings/serializable.h" #include "settings/serializable.h"
@ -54,6 +55,7 @@ RemoteSink::RemoteSink(DeviceAPI *deviceAPI) :
m_basebandSampleRate(0) m_basebandSampleRate(0)
{ {
setObjectName(m_channelId); setObjectName(m_channelId);
updateWithDeviceData();
m_basebandSink = new RemoteSinkBaseband(); m_basebandSink = new RemoteSinkBaseband();
m_basebandSink->moveToThread(&m_thread); m_basebandSink->moveToThread(&m_thread);
@ -96,6 +98,8 @@ void RemoteSink::start()
{ {
qDebug("RemoteSink::start: m_basebandSampleRate: %d", m_basebandSampleRate); qDebug("RemoteSink::start: m_basebandSampleRate: %d", m_basebandSampleRate);
m_basebandSink->reset(); m_basebandSink->reset();
m_basebandSink->setDeviceIndex(m_deviceAPI->getDeviceSetIndex());
m_basebandSink->setChannelIndex(getIndexInDeviceSet());
m_basebandSink->startWork(); m_basebandSink->startWork();
m_thread.start(); m_thread.start();
@ -128,6 +132,7 @@ bool RemoteSink::handleMessage(const Message& cmd)
m_basebandSampleRate = notif.getSampleRate(); m_basebandSampleRate = notif.getSampleRate();
qDebug() << "RemoteSink::handleMessage: DSPSignalNotification: m_basebandSampleRate:" << m_basebandSampleRate; qDebug() << "RemoteSink::handleMessage: DSPSignalNotification: m_basebandSampleRate:" << m_basebandSampleRate;
calculateFrequencyOffset(); calculateFrequencyOffset();
updateWithDeviceData(); // Device center frequency and/or sample rate has changed
// Forward to the sink // Forward to the sink
DSPSignalNotification* msgToBaseband = new DSPSignalNotification(notif); // make a copy DSPSignalNotification* msgToBaseband = new DSPSignalNotification(notif); // make a copy
@ -199,6 +204,17 @@ void RemoteSink::applySettings(const RemoteSinkSettings& settings, bool force)
reverseAPIKeys.append("title"); reverseAPIKeys.append("title");
} }
if ((m_settings.m_deviceCenterFrequency != settings.m_deviceCenterFrequency) || force)
{
reverseAPIKeys.append("deviceCenterFrequency");
if (m_deviceAPI->getSampleSource()) {
m_deviceAPI->getSampleSource()->setCenterFrequency(settings.m_deviceCenterFrequency);
} else if (m_deviceAPI->getSampleMIMO()) {
m_deviceAPI->getSampleMIMO()->setSourceCenterFrequency(settings.m_deviceCenterFrequency, settings.m_streamIndex);
}
}
if ((m_settings.m_log2Decim != settings.m_log2Decim) || force) if ((m_settings.m_log2Decim != settings.m_log2Decim) || force)
{ {
reverseAPIKeys.append("log2Decim"); reverseAPIKeys.append("log2Decim");
@ -275,6 +291,15 @@ void RemoteSink::calculateFrequencyOffset()
m_frequencyOffset = m_basebandSampleRate * shiftFactor; m_frequencyOffset = m_basebandSampleRate * shiftFactor;
} }
void RemoteSink::updateWithDeviceData()
{
if (m_deviceAPI->getSampleSource()) {
m_settings.m_deviceCenterFrequency = m_deviceAPI->getSampleSource()->getCenterFrequency();
} else if (m_deviceAPI->getSampleMIMO()) {
m_settings.m_deviceCenterFrequency = m_deviceAPI->getSampleMIMO()->getSourceCenterFrequency(m_settings.m_streamIndex);
}
}
int RemoteSink::webapiSettingsGet( int RemoteSink::webapiSettingsGet(
SWGSDRangel::SWGChannelSettings& response, SWGSDRangel::SWGChannelSettings& response,
QString& errorMessage) QString& errorMessage)
@ -332,6 +357,10 @@ void RemoteSink::webapiUpdateChannelSettings(
settings.m_nbTxBytes = response.getRemoteSinkSettings()->getNbTxBytes(); settings.m_nbTxBytes = response.getRemoteSinkSettings()->getNbTxBytes();
} }
if (channelSettingsKeys.contains("deviceCenterFrequency")) {
settings.m_deviceCenterFrequency = response.getRemoteSinkSettings()->getDeviceCenterFrequency();
}
if (channelSettingsKeys.contains("dataAddress")) { if (channelSettingsKeys.contains("dataAddress")) {
settings.m_dataAddress = *response.getRemoteSinkSettings()->getDataAddress(); settings.m_dataAddress = *response.getRemoteSinkSettings()->getDataAddress();
} }
@ -398,6 +427,7 @@ void RemoteSink::webapiFormatChannelSettings(SWGSDRangel::SWGChannelSettings& re
} }
response.getRemoteSinkSettings()->setNbTxBytes(settings.m_nbTxBytes); response.getRemoteSinkSettings()->setNbTxBytes(settings.m_nbTxBytes);
response.getRemoteSinkSettings()->setDeviceCenterFrequency(settings.m_deviceCenterFrequency);
response.getRemoteSinkSettings()->setDataPort(settings.m_dataPort); response.getRemoteSinkSettings()->setDataPort(settings.m_dataPort);
response.getRemoteSinkSettings()->setRgbColor(settings.m_rgbColor); response.getRemoteSinkSettings()->setRgbColor(settings.m_rgbColor);
@ -506,6 +536,9 @@ void RemoteSink::webapiFormatChannelSettings(
if (channelSettingsKeys.contains("nbTxBytes") || force) { if (channelSettingsKeys.contains("nbTxBytes") || force) {
swgRemoteSinkSettings->setNbTxBytes(settings.m_nbTxBytes); swgRemoteSinkSettings->setNbTxBytes(settings.m_nbTxBytes);
} }
if (channelSettingsKeys.contains("deviceCenterFrequency") || force) {
swgRemoteSinkSettings->setDeviceCenterFrequency(settings.m_deviceCenterFrequency);
}
if (channelSettingsKeys.contains("dataAddress") || force) { if (channelSettingsKeys.contains("dataAddress") || force) {
swgRemoteSinkSettings->setDataAddress(new QString(settings.m_dataAddress)); swgRemoteSinkSettings->setDataAddress(new QString(settings.m_dataAddress));
} }

View File

@ -130,6 +130,7 @@ private:
void applySettings(const RemoteSinkSettings& settings, bool force = false); void applySettings(const RemoteSinkSettings& settings, bool force = false);
static void validateFilterChainHash(RemoteSinkSettings& settings); static void validateFilterChainHash(RemoteSinkSettings& settings);
void calculateFrequencyOffset(); void calculateFrequencyOffset();
void updateWithDeviceData();
void webapiReverseSendSettings(QList<QString>& channelSettingsKeys, const RemoteSinkSettings& settings, bool force); void webapiReverseSendSettings(QList<QString>& channelSettingsKeys, const RemoteSinkSettings& settings, bool force);
void sendChannelSettings( void sendChannelSettings(
QList<MessageQueue*> *messageQueues, QList<MessageQueue*> *messageQueues,

View File

@ -70,6 +70,8 @@ public:
MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } //!< Get the queue for asynchronous inbound communication MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } //!< Get the queue for asynchronous inbound communication
int getChannelSampleRate() const; int getChannelSampleRate() const;
void setBasebandSampleRate(int sampleRate); void setBasebandSampleRate(int sampleRate);
void setDeviceIndex(uint32_t deviceIndex) { m_sink.setDeviceIndex(deviceIndex); }
void setChannelIndex(uint32_t channelIndex) { m_sink.setChannelIndex(channelIndex); }
private: private:
bool m_running; bool m_running;

View File

@ -30,7 +30,7 @@
const PluginDescriptor RemoteSinkPlugin::m_pluginDescriptor = { const PluginDescriptor RemoteSinkPlugin::m_pluginDescriptor = {
RemoteSink::m_channelId, RemoteSink::m_channelId,
QStringLiteral("Remote channel sink"), QStringLiteral("Remote channel sink"),
QStringLiteral("6.17.4"), QStringLiteral("6.17.6"),
QStringLiteral("(c) Edouard Griffiths, F4EXB"), QStringLiteral("(c) Edouard Griffiths, F4EXB"),
QStringLiteral("https://github.com/f4exb/sdrangel"), QStringLiteral("https://github.com/f4exb/sdrangel"),
true, true,

View File

@ -68,6 +68,12 @@ void RemoteSinkSender::started()
void RemoteSinkSender::stopWork() void RemoteSinkSender::stopWork()
{ {
qDebug("RemoteSinkSender::stopWork"); qDebug("RemoteSinkSender::stopWork");
QObject::disconnect(
&m_fifo,
&RemoteSinkFifo::dataBlockServed,
this,
&RemoteSinkSender::handleData
);
} }
void RemoteSinkSender::finished() void RemoteSinkSender::finished()

View File

@ -38,6 +38,7 @@ void RemoteSinkSettings::resetToDefaults()
{ {
m_nbFECBlocks = 0; m_nbFECBlocks = 0;
m_nbTxBytes = 2; m_nbTxBytes = 2;
m_deviceCenterFrequency = 0;
m_dataAddress = "127.0.0.1"; m_dataAddress = "127.0.0.1";
m_dataPort = 9090; m_dataPort = 9090;
m_rgbColor = QColor(140, 4, 4).rgb(); m_rgbColor = QColor(140, 4, 4).rgb();
@ -71,6 +72,7 @@ QByteArray RemoteSinkSettings::serialize() const
s.writeU32(13, m_filterChainHash); s.writeU32(13, m_filterChainHash);
s.writeS32(14, m_streamIndex); s.writeS32(14, m_streamIndex);
s.writeBlob(15, m_rollupState); s.writeBlob(15, m_rollupState);
s.writeU64(16, m_deviceCenterFrequency);
return s.final(); return s.final();
} }
@ -129,6 +131,7 @@ bool RemoteSinkSettings::deserialize(const QByteArray& data)
d.readU32(13, &m_filterChainHash, 0); d.readU32(13, &m_filterChainHash, 0);
d.readS32(14, &m_streamIndex, 0); d.readS32(14, &m_streamIndex, 0);
d.readBlob(15, &m_rollupState); d.readBlob(15, &m_rollupState);
d.readU64(16, &m_deviceCenterFrequency, 0);
return true; return true;
} }

View File

@ -33,6 +33,7 @@ struct RemoteSinkSettings
{ {
uint16_t m_nbFECBlocks; uint16_t m_nbFECBlocks;
uint32_t m_nbTxBytes; uint32_t m_nbTxBytes;
quint64 m_deviceCenterFrequency;
QString m_dataAddress; QString m_dataAddress;
uint16_t m_dataPort; uint16_t m_dataPort;
quint32 m_rgbColor; quint32 m_rgbColor;

View File

@ -131,6 +131,8 @@ void RemoteSinkSink::feed(const SampleVector::const_iterator& begin, const Sampl
metaData.m_sampleBits = getNbSampleBits(); metaData.m_sampleBits = getNbSampleBits();
metaData.m_nbOriginalBlocks = RemoteNbOrginalBlocks; metaData.m_nbOriginalBlocks = RemoteNbOrginalBlocks;
metaData.m_nbFECBlocks = m_nbBlocksFEC; metaData.m_nbFECBlocks = m_nbBlocksFEC;
metaData.m_deviceIndex = m_deviceIndex % 256;
metaData.m_channelIndex = m_channelIndex % 256;
metaData.m_tv_sec = nowus / 1000000UL; // tv.tv_sec; metaData.m_tv_sec = nowus / 1000000UL; // tv.tv_sec;
metaData.m_tv_usec = nowus % 1000000UL; // tv.tv_usec; metaData.m_tv_usec = nowus % 1000000UL; // tv.tv_usec;
@ -160,6 +162,8 @@ void RemoteSinkSink::feed(const SampleVector::const_iterator& begin, const Sampl
<< ":" << (int) metaData.m_sampleBits << ":" << (int) metaData.m_sampleBits
<< "|" << (int) metaData.m_nbOriginalBlocks << "|" << (int) metaData.m_nbOriginalBlocks
<< ":" << (int) metaData.m_nbFECBlocks << ":" << (int) metaData.m_nbFECBlocks
<< "|" << metaData.m_deviceIndex
<< ":" << metaData.m_channelIndex
<< "|" << metaData.m_tv_sec << "|" << metaData.m_tv_sec
<< ":" << metaData.m_tv_usec; << ":" << metaData.m_tv_usec;

View File

@ -46,6 +46,8 @@ public:
void applySettings(const RemoteSinkSettings& settings, bool force = false); void applySettings(const RemoteSinkSettings& settings, bool force = false);
void applyBasebandSampleRate(uint32_t sampleRate); void applyBasebandSampleRate(uint32_t sampleRate);
void setDeviceCenterFrequency(uint64_t frequency) { m_deviceCenterFrequency = frequency; } void setDeviceCenterFrequency(uint64_t frequency) { m_deviceCenterFrequency = frequency; }
void setDeviceIndex(uint32_t deviceIndex) { m_deviceIndex = deviceIndex; }
void setChannelIndex(uint32_t channelIndex) { m_channelIndex = channelIndex; }
private: private:
RemoteSinkSettings m_settings; RemoteSinkSettings m_settings;
@ -63,6 +65,8 @@ private:
uint64_t m_deviceCenterFrequency; uint64_t m_deviceCenterFrequency;
int64_t m_frequencyOffset; int64_t m_frequencyOffset;
uint32_t m_basebandSampleRate; uint32_t m_basebandSampleRate;
uint32_t m_deviceIndex;
uint32_t m_channelIndex;
int m_nbBlocksFEC; int m_nbBlocksFEC;
uint32_t m_nbTxBytes; uint32_t m_nbTxBytes;
QString m_dataAddress; QString m_dataAddress;

View File

@ -28,7 +28,7 @@
const PluginDescriptor RemoteSourcePlugin::m_pluginDescriptor = { const PluginDescriptor RemoteSourcePlugin::m_pluginDescriptor = {
RemoteSource::m_channelId, RemoteSource::m_channelId,
QStringLiteral("Remote channel source"), QStringLiteral("Remote channel source"),
QStringLiteral("6.17.5"), QStringLiteral("6.17.6"),
QStringLiteral("(c) Edouard Griffiths, F4EXB"), QStringLiteral("(c) Edouard Griffiths, F4EXB"),
QStringLiteral("https://github.com/f4exb/sdrangel"), QStringLiteral("https://github.com/f4exb/sdrangel"),
true, true,

View File

@ -218,6 +218,8 @@ void RemoteSourceSource::printMeta(const QString& header, RemoteMetaDataFEC *met
<< ":" << (int) metaData->m_sampleBits << ":" << (int) metaData->m_sampleBits
<< ":" << (int) metaData->m_nbOriginalBlocks << ":" << (int) metaData->m_nbOriginalBlocks
<< ":" << (int) metaData->m_nbFECBlocks << ":" << (int) metaData->m_nbFECBlocks
<< "|" << metaData->m_deviceIndex
<< ":" << metaData->m_channelIndex
<< "|" << metaData->m_tv_sec << "|" << metaData->m_tv_sec
<< ":" << metaData->m_tv_usec << ":" << metaData->m_tv_usec
<< "|"; << "|";

View File

@ -90,6 +90,7 @@ bool RemoteOutput::start()
m_remoteOutputWorker = new RemoteOutputWorker(&m_sampleSourceFifo); m_remoteOutputWorker = new RemoteOutputWorker(&m_sampleSourceFifo);
m_remoteOutputWorker->moveToThread(&m_remoteOutputWorkerThread); m_remoteOutputWorker->moveToThread(&m_remoteOutputWorkerThread);
m_remoteOutputWorker->setDeviceIndex(m_deviceAPI->getDeviceSetIndex());
m_remoteOutputWorker->setDataAddress(m_settings.m_dataAddress, m_settings.m_dataPort); m_remoteOutputWorker->setDataAddress(m_settings.m_dataAddress, m_settings.m_dataPort);
m_remoteOutputWorker->setSamplerate(m_sampleRate); m_remoteOutputWorker->setSamplerate(m_sampleRate);
m_remoteOutputWorker->setNbBlocksFEC(m_settings.m_nbFECBlocks); m_remoteOutputWorker->setNbBlocksFEC(m_settings.m_nbFECBlocks);

View File

@ -41,8 +41,6 @@
#include "channel/remotedatablock.h" #include "channel/remotedatablock.h"
#include "udpsinkfec.h"
RemoteOutputSinkGui::RemoteOutputSinkGui(DeviceUISet *deviceUISet, QWidget* parent) : RemoteOutputSinkGui::RemoteOutputSinkGui(DeviceUISet *deviceUISet, QWidget* parent) :
DeviceGUI(parent), DeviceGUI(parent),
ui(new Ui::RemoteOutputGui), ui(new Ui::RemoteOutputGui),

View File

@ -31,7 +31,7 @@
const PluginDescriptor RemoteOutputPlugin::m_pluginDescriptor = { const PluginDescriptor RemoteOutputPlugin::m_pluginDescriptor = {
QStringLiteral("RemoteOutput"), QStringLiteral("RemoteOutput"),
QStringLiteral("Remote device output"), QStringLiteral("Remote device output"),
QStringLiteral("6.17.5"), QStringLiteral("6.17.6"),
QStringLiteral("(c) Edouard Griffiths, F4EXB"), QStringLiteral("(c) Edouard Griffiths, F4EXB"),
QStringLiteral("https://github.com/f4exb/sdrangel"), QStringLiteral("https://github.com/f4exb/sdrangel"),
true, true,

View File

@ -47,6 +47,7 @@ public:
void startWork(); void startWork();
void stopWork(); void stopWork();
void setDeviceIndex(uint32_t deviceIndex) { m_udpSinkFEC.setDeviceIndex(deviceIndex); }
void setSamplerate(int samplerate); void setSamplerate(int samplerate);
void setNbBlocksFEC(uint32_t nbBlocksFEC) { m_udpSinkFEC.setNbBlocksFEC(nbBlocksFEC); }; void setNbBlocksFEC(uint32_t nbBlocksFEC) { m_udpSinkFEC.setNbBlocksFEC(nbBlocksFEC); };
void setNbTxBytes(uint32_t nbTxBytes) { m_udpSinkFEC.setNbTxBytes(nbTxBytes); }; void setNbTxBytes(uint32_t nbTxBytes) { m_udpSinkFEC.setNbTxBytes(nbTxBytes); };

View File

@ -120,6 +120,8 @@ void UDPSinkFEC::write(const SampleVector::iterator& begin, uint32_t sampleChunk
metaData.m_sampleBits = getNbSampleBits(); metaData.m_sampleBits = getNbSampleBits();
metaData.m_nbOriginalBlocks = RemoteNbOrginalBlocks; metaData.m_nbOriginalBlocks = RemoteNbOrginalBlocks;
metaData.m_nbFECBlocks = m_nbBlocksFEC; metaData.m_nbFECBlocks = m_nbBlocksFEC;
metaData.m_deviceIndex = m_deviceIndex; // index of device set in the instance
metaData.m_channelIndex = 0; // irrelavant
metaData.m_tv_sec = nowus / 1000000UL; // tv.tv_sec; metaData.m_tv_sec = nowus / 1000000UL; // tv.tv_sec;
metaData.m_tv_usec = nowus % 1000000UL; // tv.tv_usec; metaData.m_tv_usec = nowus % 1000000UL; // tv.tv_usec;
@ -149,6 +151,8 @@ void UDPSinkFEC::write(const SampleVector::iterator& begin, uint32_t sampleChunk
<< ":" << (int) metaData.m_sampleBits << ":" << (int) metaData.m_sampleBits
<< "|" << (int) metaData.m_nbOriginalBlocks << "|" << (int) metaData.m_nbOriginalBlocks
<< ":" << (int) metaData.m_nbFECBlocks << ":" << (int) metaData.m_nbFECBlocks
<< "|" << metaData.m_deviceIndex
<< ":" << metaData.m_channelIndex
<< "|" << metaData.m_tv_sec << "|" << metaData.m_tv_sec
<< ":" << metaData.m_tv_usec; << ":" << metaData.m_tv_usec;

View File

@ -64,6 +64,7 @@ public:
return ret; return ret;
} }
void setDeviceIndex(uint32_t deviceIndex) { m_deviceIndex = deviceIndex; }
/** Set sample rate given in S/s */ /** Set sample rate given in S/s */
void setSampleRate(uint32_t sampleRate); void setSampleRate(uint32_t sampleRate);
@ -94,6 +95,7 @@ private:
int m_txBlockIndex; //!< Current index in blocks to transmit in the Tx row int m_txBlockIndex; //!< Current index in blocks to transmit in the Tx row
uint16_t m_frameCount; //!< transmission frame count uint16_t m_frameCount; //!< transmission frame count
int m_sampleIndex; //!< Current sample index in protected block data int m_sampleIndex; //!< Current sample index in protected block data
uint32_t m_deviceIndex; //!< Index of current device set
RemoteOutputSender *m_remoteOutputSender; RemoteOutputSender *m_remoteOutputSender;
QThread *m_senderThread; QThread *m_senderThread;

View File

@ -10,7 +10,7 @@ Please note that there is no provision for handling out of sync UDP blocks. It i
The remote SDRangel instance that sends the data stream is controlled via its REST API using a separate control software for example [SDRangelcli](https://github.com/f4exb/sdrangelcli) The remote SDRangel instance that sends the data stream is controlled via its REST API using a separate control software for example [SDRangelcli](https://github.com/f4exb/sdrangelcli)
A sample size conversion takes place if the stream sample size sent by the remote instance and the Rx sample size of the local instance do not match (i.e. 16 to 24 bits or 24 to 16 bits). Best performance is obtained when both instances use the same sample size. A sample size conversion takes place if the stream sample size sent by the remote instance and the Rx sample size of the local instance do not match (i.e. 8, 16 to 24 bits or 8, 24 to 16 bits). Best performance is obtained when the stream sample size matches the instance sample size.
<h2>Build</h2> <h2>Build</h2>
@ -35,22 +35,54 @@ This is the center frequency in Hz sent in the meta data from the remote SDRange
Stream I/Q sample rate in kS/s Stream I/Q sample rate in kS/s
<h3>4: Auto correction options and stream status</h3> <h3>4: Set remote device center frequency</h3>
Uses the API at the address and port specified in (12) to control the remote device center frequency (kHz)
<h3>5: Remote sink channel decimation factor</h3>
The remote device baseband can be decimated in the remote sink channel and its center can be selected with (8). The resulting sample rate of the I/Q stream sent over the network is the remote device baseband sample rate divided by this value. The value is displayed in (3).
It uses the API at the address and port specified in (12) to control the remote sink channel.
<h3>6: Remote sink half band filters chain sequence</h3>
This string represents the sequence of half-band filters used in the decimation from device baseband to resulting I/Q stream. Each character represents a filter type:
- **L**: lower half-band
- **H**: higher half-band
- **C**: centered
<h3>7: Remote sink center frequency shift</h3>
This is the shift of the remote sink channel center frequency from the remte device center frequency. Its value is driven by the remote device sample rate, the decimation (5) and the filter chain sequence (8).
<h3>8: Remote sink half-band filter chain sequence</h3>
The slider moves the remote sink channel center frequency roughly from the lower to the higher frequency in the remote device baseband. The number on the right represents the filter sequence as the decimal value of a base 3 number. Each base 3 digit represents the filter type and its sequence from MSB to LSB in the filter chain:
- **0**: lower half-band
- **1**: centered
- **2**: higher half-band
It uses the API at the address and port specified in (12) to control the remote sink channel.
<h3>9: Auto correction options and stream status</h3>
![SDR Remote input stream GUI](../../../doc/img/RemoteInput_plugin_02.png) ![SDR Remote input stream GUI](../../../doc/img/RemoteInput_plugin_02.png)
<h4>4.1: Auto correction options</h4> <h4>9.1: Auto correction options</h4>
These buttons control the local DSP auto correction options: These buttons control the local DSP auto correction options:
- **DC**: auto remove DC component - **DC**: auto remove DC component
- **IQ**: auto make I/Q balance - **IQ**: auto make I/Q balance
<h4>4.2: Receive buffer length</h4> <h4>9.2: Receive buffer length</h4>
This is the main buffer (writes from UDP / reads from DSP engine) length in units of time (seconds). As read and write pointers are normally about half the buffer apart the nominal delay introduced by the buffer is the half of this value. This is the main buffer (writes from UDP / reads from DSP engine) length in units of time (seconds). As read and write pointers are normally about half the buffer apart the nominal delay introduced by the buffer is the half of this value.
<h4>4.3: Main buffer R/W pointers positions</h4> <h4>9.3: Main buffer R/W pointers positions</h4>
Read and write pointers should always be a half buffer distance buffer apart. This is the difference in percent of the main buffer size from this ideal position. Read and write pointers should always be a half buffer distance buffer apart. This is the difference in percent of the main buffer size from this ideal position.
@ -59,11 +91,11 @@ Read and write pointers should always be a half buffer distance buffer apart. Th
This corresponds to the value shown in the gauges above (9) This corresponds to the value shown in the gauges above (9)
<h4>4.4: Date/time</h4> <h4>9.4: Date/time</h4>
This is the current timestamp of the block of data sent from the receiver. It is refreshed about every second. The plugin tries to take into account the buffer that is used between the data received from the network and the data effectively used by the system however this may not be extremely accurate. It is based on the timestamps sent from the Remote sink channel at the other hand that does not take into account its own buffers. This is the current timestamp of the block of data sent from the receiver. It is refreshed about every second. The plugin tries to take into account the buffer that is used between the data received from the network and the data effectively used by the system however this may not be extremely accurate. It is based on the timestamps sent from the Remote sink channel at the other hand that does not take into account its own buffers.
<h3>5: Main buffer R/W pointers gauge</h3> <h3>10: Main buffer R/W pointers gauge</h3>
There are two gauges separated by a dot in the center. Ideally these gauges should not display any value thus read and write pointers are always half a buffer apart. However due to the fact that a whole frame is reconstructed at once up to ~10% variation is normal and should appear on the left gauge (write leads). There are two gauges separated by a dot in the center. Ideally these gauges should not display any value thus read and write pointers are always half a buffer apart. However due to the fact that a whole frame is reconstructed at once up to ~10% variation is normal and should appear on the left gauge (write leads).
@ -72,15 +104,15 @@ There are two gauges separated by a dot in the center. Ideally these gauges shou
The system tries to compensate read / write unbalance however at start or when a large stream disruption has occurred a delay of a few tens of seconds is necessary before read / write reaches equilibrium. The system tries to compensate read / write unbalance however at start or when a large stream disruption has occurred a delay of a few tens of seconds is necessary before read / write reaches equilibrium.
<h3>6: Data stream status</h3> <h3>11: Data stream status</h3>
![SDR Remote input stream GUI](../../../doc/img/RemoteInput_plugin_04.png) ![SDR Remote input stream GUI](../../../doc/img/RemoteInput_plugin_04.png)
<h4>6.1: Sample size</h4> <h4>11.1: Sample size</h4>
This is the size in bits of a I or Q sample sent in the stream by the remote server. This is the size in bits of a I or Q sample sent in the stream by the remote server.
<h4>6.2: Total number of frames and number of FEC blocks</h4> <h4>11.2: Total number of frames and number of FEC blocks</h4>
This is the total number of frames and number of FEC blocks separated by a slash '/' as sent in the meta data block thus acknowledged by the remote server. When you set the number of FEC blocks with (4.1) the effect may not be immediate and this information can be used to monitor when it gets effectively set in the remote server. This is the total number of frames and number of FEC blocks separated by a slash '/' as sent in the meta data block thus acknowledged by the remote server. When you set the number of FEC blocks with (4.1) the effect may not be immediate and this information can be used to monitor when it gets effectively set in the remote server.
@ -88,7 +120,7 @@ A frame consists of 128 data blocks (1 meta data block followed by 127 I/Q data
Using the Cauchy MDS block erasure correction ensures that if at least the number of data blocks (128) is received per complete frame then all lost blocks in any position can be restored. For example if 8 FEC blocks are used then 136 blocks are transmitted per frame. If only 130 blocks (128 or greater) are received then data can be recovered. If only 127 blocks (or less) are received then none of the lost blocks can be recovered. Using the Cauchy MDS block erasure correction ensures that if at least the number of data blocks (128) is received per complete frame then all lost blocks in any position can be restored. For example if 8 FEC blocks are used then 136 blocks are transmitted per frame. If only 130 blocks (128 or greater) are received then data can be recovered. If only 127 blocks (or less) are received then none of the lost blocks can be recovered.
<h4>6.3: Stream status</h4> <h4>11.3: Stream status</h4>
The color of the icon indicates stream status: The color of the icon indicates stream status:
@ -96,82 +128,82 @@ The color of the icon indicates stream status:
- No color: some original blocks were reconstructed from FEC blocks for some frames during the last polling timeframe (ex: between 128 and 135) - No color: some original blocks were reconstructed from FEC blocks for some frames during the last polling timeframe (ex: between 128 and 135)
- Red: some original blocks were definitely lost for some frames during the last polling timeframe (ex: less than 128) - Red: some original blocks were definitely lost for some frames during the last polling timeframe (ex: less than 128)
<h4>6.4: Minimum total number of blocks per frame</h4> <h4>11.4: Minimum total number of blocks per frame</h4>
This is the minimum total number of blocks per frame during the last polling period. If all blocks were received for all frames then this number is the nominal number of original blocks plus FEC blocks (Green lock icon). In our example this is 128+8 = 136. This is the minimum total number of blocks per frame during the last polling period. If all blocks were received for all frames then this number is the nominal number of original blocks plus FEC blocks (Green lock icon). In our example this is 128+8 = 136.
If this number falls below 128 then some blocks are definitely lost and the lock lights in red. If this number falls below 128 then some blocks are definitely lost and the lock lights in red.
<h4>6.5: Maximum number of FEC blocks used by frame</h4> <h4>11.5: Maximum number of FEC blocks used by frame</h4>
Maximum number of FEC blocks used for original blocks recovery during the last polling timeframe. Ideally this should be 0 when no blocks are lost but the system is able to correct lost blocks up to the nominal number of FEC blocks (Neutral lock icon). Maximum number of FEC blocks used for original blocks recovery during the last polling timeframe. Ideally this should be 0 when no blocks are lost but the system is able to correct lost blocks up to the nominal number of FEC blocks (Neutral lock icon).
<h4>6.6: Reset events counters</h4> <h4>11.6: Reset events counters</h4>
This push button can be used to reset the events counters (4.7 and 4.8) and reset the event counts timer (4.9) This push button can be used to reset the events counters (9.7 and 9.8) and reset the event counts timer (9.9)
<h4>6.7: Unrecoverable error events counter</h4> <h4>11.7: Unrecoverable error events counter</h4>
This counter counts the unrecoverable error conditions found (i.e. 4.4 lower than 128) since the last counters reset. This counter counts the unrecoverable error conditions found (i.e. 9.4 lower than 128) since the last counters reset.
<h4>6.8: Recoverable error events counter</h4> <h4>11.8: Recoverable error events counter</h4>
This counter counts the unrecoverable error conditions found (i.e. 4.4 between 128 and 128 plus the number of FEC blocks) since the last counters reset. This counter counts the unrecoverable error conditions found (i.e. 9.4 between 128 and 128 plus the number of FEC blocks) since the last counters reset.
<h4>6.9: events counters timer</h4> <h4>11.9: events counters timer</h4>
This HH:mm:ss time display shows the time since the reset events counters button (4.6) was pushed. This HH:mm:ss time display shows the time since the reset events counters button (9.6) was pushed.
<h3>7: Remote server test</h3> <h3>12: Remote server test</h3>
Test remote connection with its API. Test remote connection with its API.
![SDR Remote input stream GUI](../../../doc/img/RemoteInput_plugin_05.png) ![SDR Remote input stream GUI](../../../doc/img/RemoteInput_plugin_05.png)
<h4>7.1: Remote connection indicator</h4> <h4>12.1: Remote connection indicator</h4>
The "Remote" label is lit in green when the connection is successful The "Remote" label is lit in green when the connection is successful
<h4>7.2: API IP address</h4> <h4>12.2: API IP address</h4>
IP address of the remote SDRangel instance REST API IP address of the remote SDRangel instance REST API
<h4>7.3: API port</h4> <h4>12.3: API port</h4>
Port of the remote SDRangel instance REST API Port of the remote SDRangel instance REST API
<h4>7.4: Get information button</h4> <h4>12.4: Get information button</h4>
When the return key is hit within the address (5.2) or port (5.3) the changes are effective immediately. You can also use this button to set again these values. Clicking on this button will send a request to the API to get the remote SDRangel instance information that is displayed in the API message box (8) When the return key is hit within the address (10.2) or port (10.3) the changes are effective immediately. You can also use this button to set again these values. Clicking on this button will send a request to the API to get the remote SDRangel instance information that is displayed in the API message box (13)
<h3>8: Local network interface address and port for data reception</h3> <h3>13: Local network interface address and port for data reception</h3>
![SDR Remote source input stream GUI](../../../doc/img/RemoteInput_plugin_06.png) ![SDR Remote source input stream GUI](../../../doc/img/RemoteInput_plugin_06.png)
<h4>8.1: Interface IP address</h4> <h4>13.1: Interface IP address</h4>
IP address of the local network interface the remote SDRangel instance sends the data to. Effective when the validation button (8.3) is pressed. IP address of the local network interface the remote SDRangel instance sends the data to. Effective when the validation button (13.3) is pressed.
<h4>8.2: Interface port</h4> <h4>13.2: Interface port</h4>
Local port the remote SDRangel instance sends the data to. Effective when the validation button (8.3) is pressed. Local port the remote SDRangel instance sends the data to. Effective when the validation button (13.3) is pressed.
<h4>8.3: Validation button</h4> <h4>13.3: Validation button</h4>
When the return key is hit within the interface address (8.2), port (8.3), multicast group address (10) and multicast group join/leave (9) the changes of parameters for data reception are ready for commit and this button turns green. You then push this button to commit the changes. When the return key is hit within the interface address (13.2), port (13.3), multicast group address (15) and multicast group join/leave (14) the changes of parameters for data reception are ready for commit and this button turns green. You then push this button to commit the changes.
<h3>9: Join or leave multicast group</h3> <h3>14: Join or leave multicast group</h3>
Use this toggle button to join or leave the multicast group which address is specified next (10). Effective when the validation button (8.3) is pressed. Use this toggle button to join or leave the multicast group which address is specified next (15). Effective when the validation button (13.3) is pressed.
<h3>10: Multicast group address</h3> <h3>15: Multicast group address</h3>
This is the address of the multicast group. Effective when the validation button (8.3) is pressed. This is the address of the multicast group. Effective when the validation button (13.3) is pressed.
<h3>11: Status message</h3> <h3>16: Status message</h3>
The API status is displayed in this box. It shows "API OK" when the connection is successful and reply is OK The API status is displayed in this box. It shows "API OK" when the connection is successful and reply is OK
<h3>12: Remote information</h3> <h3>17: Remote information</h3>
This is the information returned by the remote when connection with its API is successful This is the information returned by the remote when connection with its API is successful

View File

@ -21,8 +21,10 @@
#include <QDebug> #include <QDebug>
#include <QNetworkReply> #include <QNetworkReply>
#include <QBuffer> #include <QBuffer>
#include <QJsonParseError>
#include "SWGDeviceSettings.h" #include "SWGDeviceSettings.h"
#include "SWGChannelSettings.h"
#include "SWGDeviceState.h" #include "SWGDeviceState.h"
#include "SWGDeviceReport.h" #include "SWGDeviceReport.h"
#include "SWGRemoteInputReport.h" #include "SWGRemoteInputReport.h"
@ -40,7 +42,11 @@ MESSAGE_CLASS_DEFINITION(RemoteInput::MsgConfigureRemoteInputTiming, Message)
MESSAGE_CLASS_DEFINITION(RemoteInput::MsgReportRemoteInputAcquisition, Message) MESSAGE_CLASS_DEFINITION(RemoteInput::MsgReportRemoteInputAcquisition, Message)
MESSAGE_CLASS_DEFINITION(RemoteInput::MsgReportRemoteInputStreamData, Message) MESSAGE_CLASS_DEFINITION(RemoteInput::MsgReportRemoteInputStreamData, Message)
MESSAGE_CLASS_DEFINITION(RemoteInput::MsgReportRemoteInputStreamTiming, Message) MESSAGE_CLASS_DEFINITION(RemoteInput::MsgReportRemoteInputStreamTiming, Message)
MESSAGE_CLASS_DEFINITION(RemoteInput::MsgConfigureRemoteChannel, Message)
MESSAGE_CLASS_DEFINITION(RemoteInput::MsgStartStop, Message) MESSAGE_CLASS_DEFINITION(RemoteInput::MsgStartStop, Message)
MESSAGE_CLASS_DEFINITION(RemoteInput::MsgReportRemoteFixedData, Message)
MESSAGE_CLASS_DEFINITION(RemoteInput::MsgReportRemoteAPIError, Message)
MESSAGE_CLASS_DEFINITION(RemoteInput::MsgRequestFixedData, Message)
RemoteInput::RemoteInput(DeviceAPI *deviceAPI) : RemoteInput::RemoteInput(DeviceAPI *deviceAPI) :
m_deviceAPI(deviceAPI), m_deviceAPI(deviceAPI),
@ -63,6 +69,7 @@ RemoteInput::RemoteInput(DeviceAPI *deviceAPI) :
RemoteInput::~RemoteInput() RemoteInput::~RemoteInput()
{ {
disconnect(m_remoteInputUDPHandler, SIGNAL(metaChanged()), this, SLOT(handleMetaChanged()));
disconnect(m_networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(networkManagerFinished(QNetworkReply*))); disconnect(m_networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(networkManagerFinished(QNetworkReply*)));
delete m_networkManager; delete m_networkManager;
stop(); stop();
@ -156,19 +163,31 @@ bool RemoteInput::isStreaming() const
bool RemoteInput::handleMessage(const Message& message) bool RemoteInput::handleMessage(const Message& message)
{ {
if (RemoteInputUDPHandler::MsgReportSampleRateChange::match(message)) if (RemoteInputUDPHandler::MsgReportMetaDataChange::match(message))
{ {
RemoteInputUDPHandler::MsgReportSampleRateChange& notif = (RemoteInputUDPHandler::MsgReportSampleRateChange&) message; qDebug() << "RemoteInput::handleMessage:" << message.getIdentifier();
int sampleRate = notif.getSampleRate(); RemoteInputUDPHandler::MsgReportMetaDataChange& notif = (RemoteInputUDPHandler::MsgReportMetaDataChange&) message;
m_currentMeta = notif.getMetaData();
int sampleRate = m_currentMeta.m_sampleRate;
if (sampleRate != m_sampleRate) if (sampleRate != m_sampleRate)
{ {
qDebug("RemoteInput::handleMessage: RemoteInputUDPHandler::MsgReportSampleRateChange: %d", sampleRate); qDebug("RemoteInput::handleMessage: RemoteInputUDPHandler::MsgReportMetaDataChange: new sampleRate: %d", sampleRate);
QMutexLocker mutexLocker(&m_mutex); QMutexLocker mutexLocker(&m_mutex);
m_sampleFifo.setSize(sampleRate * 8); m_sampleFifo.setSize(sampleRate * 8);
m_sampleRate = sampleRate; m_sampleRate = sampleRate;
} }
m_currentMeta = m_remoteInputUDPHandler->getCurrentMeta();
QString getSettingsURL= QString("http://%1:%2/sdrangel/deviceset/%3/channel/%4/settings")
.arg(m_settings.m_apiAddress)
.arg(m_settings.m_apiPort)
.arg(m_currentMeta.m_deviceIndex)
.arg(m_currentMeta.m_channelIndex);
m_networkRequest.setUrl(QUrl(getSettingsURL));
m_networkManager->get(m_networkRequest);
return true; return true;
} }
else if (MsgStartStop::match(message)) else if (MsgStartStop::match(message))
@ -201,6 +220,27 @@ bool RemoteInput::handleMessage(const Message& message)
applySettings(conf.getSettings(), conf.getForce()); applySettings(conf.getSettings(), conf.getForce());
return true; return true;
} }
else if (MsgConfigureRemoteChannel::match(message))
{
qDebug() << "RemoteInput::handleMessage:" << message.getIdentifier();
MsgConfigureRemoteChannel& conf = (MsgConfigureRemoteChannel&) message;
applyRemoteChannelSettings(conf.getSettings());
return true;
}
else if (MsgRequestFixedData::match(message))
{
qDebug() << "RemoteInput::handleMessage:" << message.getIdentifier();
QString reportURL;
reportURL = QString("http://%1:%2/sdrangel")
.arg(m_settings.m_apiAddress)
.arg(m_settings.m_apiPort);
m_networkRequest.setUrl(QUrl(reportURL));
m_networkManager->get(m_networkRequest);
return true;
}
else else
{ {
return false; return false;
@ -248,10 +288,10 @@ void RemoteInput::applySettings(const RemoteInputSettings& settings, bool force)
settings.m_iqCorrection ? "true" : "false"); settings.m_iqCorrection ? "true" : "false");
} }
if ((m_settings.m_dataAddress != settings.m_dataAddress) || if ((m_settings.m_dataAddress != settings.m_dataAddress) ||
(m_settings.m_dataPort != settings.m_dataPort) || (m_settings.m_dataPort != settings.m_dataPort) ||
(m_settings.m_multicastAddress != settings.m_multicastAddress) || (m_settings.m_multicastAddress != settings.m_multicastAddress) ||
(m_settings.m_multicastJoin != settings.m_multicastJoin) || force) (m_settings.m_multicastJoin != settings.m_multicastJoin) || force)
{ {
m_remoteInputUDPHandler->configureUDPLink(settings.m_dataAddress, settings.m_dataPort, settings.m_multicastAddress, settings.m_multicastJoin); m_remoteInputUDPHandler->configureUDPLink(settings.m_dataAddress, settings.m_dataPort, settings.m_multicastAddress, settings.m_multicastJoin);
m_remoteInputUDPHandler->getRemoteAddress(remoteAddress); m_remoteInputUDPHandler->getRemoteAddress(remoteAddress);
@ -272,13 +312,70 @@ void RemoteInput::applySettings(const RemoteInputSettings& settings, bool force)
m_remoteAddress = remoteAddress; m_remoteAddress = remoteAddress;
qDebug() << "RemoteInput::applySettings: " qDebug() << "RemoteInput::applySettings: "
<< " m_dataAddress: " << m_settings.m_dataAddress << " m_dataAddress: " << m_settings.m_dataAddress
<< " m_dataPort: " << m_settings.m_dataPort << " m_dataPort: " << m_settings.m_dataPort
<< " m_multicastAddress: " << m_settings.m_multicastAddress << " m_multicastAddress: " << m_settings.m_multicastAddress
<< " m_multicastJoin: " << m_settings.m_multicastJoin << " m_multicastJoin: " << m_settings.m_multicastJoin
<< " m_apiAddress: " << m_settings.m_apiAddress << " m_apiAddress: " << m_settings.m_apiAddress
<< " m_apiPort: " << m_settings.m_apiPort << " m_apiPort: " << m_settings.m_apiPort
<< " m_remoteAddress: " << m_remoteAddress; << " m_remoteAddress: " << m_remoteAddress;
}
void RemoteInput::applyRemoteChannelSettings(const RemoteChannelSettings& settings)
{
SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings();;
swgChannelSettings->setOriginatorChannelIndex(0);
swgChannelSettings->setOriginatorDeviceSetIndex(m_deviceAPI->getDeviceSetIndex());
swgChannelSettings->setChannelType(new QString("RemoteSink"));
swgChannelSettings->setRemoteSinkSettings(new SWGSDRangel::SWGRemoteSinkSettings());
SWGSDRangel::SWGRemoteSinkSettings *swgRemoteSinkSettings = swgChannelSettings->getRemoteSinkSettings();
bool hasChanged = false;
if (settings.m_deviceCenterFrequency != m_remoteChannelSettings.m_deviceCenterFrequency)
{
swgRemoteSinkSettings->setDeviceCenterFrequency(settings.m_deviceCenterFrequency);
hasChanged = true;
}
if (settings.m_log2Decim != m_remoteChannelSettings.m_log2Decim)
{
swgRemoteSinkSettings->setLog2Decim(settings.m_log2Decim);
hasChanged = true;
}
if (settings.m_filterChainHash != m_remoteChannelSettings.m_filterChainHash)
{
swgRemoteSinkSettings->setFilterChainHash(settings.m_filterChainHash);
hasChanged = true;
}
if (hasChanged)
{
QString channelSettingsURL = QString("http://%1:%2/sdrangel/deviceset/%3/channel/%4/settings")
.arg(m_settings.m_apiAddress)
.arg(m_settings.m_apiPort)
.arg(m_currentMeta.m_deviceIndex)
.arg(m_currentMeta.m_channelIndex);
m_networkRequest.setUrl(QUrl(channelSettingsURL));
m_networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
QBuffer *buffer = new QBuffer();
buffer->open((QBuffer::ReadWrite));
buffer->write(swgChannelSettings->asJson().toUtf8());
buffer->seek(0);
// Always use PATCH to avoid passing reverse API settings
QNetworkReply *reply = m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer);
buffer->setParent(reply);
}
m_remoteChannelSettings = settings;
qDebug() << "RemoteInput::applyRemoteChannelSettings: "
<< " m_deviceCenterFrequency: " << m_remoteChannelSettings.m_deviceCenterFrequency
<< " m_deviceSampleRate: " << m_remoteChannelSettings.m_deviceSampleRate
<< " m_log2Decim: " << m_remoteChannelSettings.m_log2Decim
<< " m_filterChainHash: " << m_remoteChannelSettings.m_filterChainHash;
} }
int RemoteInput::webapiRunGet( int RemoteInput::webapiRunGet(
@ -528,13 +625,92 @@ void RemoteInput::networkManagerFinished(QNetworkReply *reply)
<< " error(" << (int) replyError << " error(" << (int) replyError
<< "): " << replyError << "): " << replyError
<< ": " << reply->errorString(); << ": " << reply->errorString();
if (m_guiMessageQueue)
{
MsgReportRemoteAPIError *msg = MsgReportRemoteAPIError::create(reply->errorString());
m_guiMessageQueue->push(msg);
}
} }
else else
{ {
QString answer = reply->readAll(); QString answer = reply->readAll();
answer.chop(1); // remove last \n answer.chop(1); // remove last \n
qDebug("RemoteInput::networkManagerFinished: reply:\n%s", answer.toStdString().c_str()); qDebug("RemoteInput::networkManagerFinished: reply:\n%s", answer.toStdString().c_str());
QByteArray jsonBytes(answer.toStdString().c_str());
QJsonParseError error;
QJsonDocument doc = QJsonDocument::fromJson(jsonBytes, &error);
if (error.error == QJsonParseError::NoError)
{
const QJsonObject&jsonObject = doc.object();
if (jsonObject.contains("RemoteSinkSettings")) {
analyzeRemoteChannelSettingsReply(jsonObject);
} else if (jsonObject.contains("version")) {
analyzeInstanceSummaryReply(jsonObject);
}
}
else
{
QString errorMsg = QString("Reply JSON error: ") + error.errorString() + QString(" at offset ") + QString::number(error.offset);
qInfo().noquote() << "RemoteInputGui::networkManagerFinished: " << errorMsg;
if (m_guiMessageQueue)
{
MsgReportRemoteAPIError *msg = MsgReportRemoteAPIError::create(errorMsg);
m_guiMessageQueue->push(msg);
}
}
} }
reply->deleteLater(); reply->deleteLater();
} }
void RemoteInput::analyzeInstanceSummaryReply(const QJsonObject& jsonObject)
{
MsgReportRemoteFixedData::RemoteData msgRemoteFixedData;
msgRemoteFixedData.m_version = jsonObject["version"].toString();
if (jsonObject.contains("qtVersion")) {
msgRemoteFixedData.m_qtVersion = jsonObject["qtVersion"].toString();
}
if (jsonObject.contains("architecture")) {
msgRemoteFixedData.m_architecture = jsonObject["architecture"].toString();
}
if (jsonObject.contains("os")) {
msgRemoteFixedData.m_os = jsonObject["os"].toString();
}
if (jsonObject.contains("dspRxBits") && jsonObject.contains("dspTxBits"))
{
msgRemoteFixedData.m_rxBits = jsonObject["dspRxBits"].toInt();
msgRemoteFixedData.m_txBits = jsonObject["dspTxBits"].toInt();
}
if (m_guiMessageQueue)
{
MsgReportRemoteFixedData *msg = MsgReportRemoteFixedData::create(msgRemoteFixedData);
m_guiMessageQueue->push(msg);
}
}
void RemoteInput::analyzeRemoteChannelSettingsReply(const QJsonObject& jsonObject)
{
QJsonObject settings = jsonObject["RemoteSinkSettings"].toObject();
m_remoteChannelSettings.m_deviceCenterFrequency = settings["deviceCenterFrequency"].toInt();
m_remoteChannelSettings.m_deviceSampleRate = settings["deviceSampleRate"].toInt();
m_remoteChannelSettings.m_log2Decim = settings["log2Decim"].toInt();
m_remoteChannelSettings.m_filterChainHash = settings["filterChainHash"].toInt();
if (m_guiMessageQueue) // forward to GUI if any
{
MsgConfigureRemoteChannel *msg = MsgConfigureRemoteChannel::create(m_remoteChannelSettings);
m_guiMessageQueue->push(msg);
}
}

View File

@ -28,6 +28,7 @@
#include <QNetworkRequest> #include <QNetworkRequest>
#include "dsp/devicesamplesource.h" #include "dsp/devicesamplesource.h"
#include "channel/remotedatablock.h"
#include "remoteinputsettings.h" #include "remoteinputsettings.h"
@ -39,6 +40,21 @@ class RemoteInputUDPHandler;
class RemoteInput : public DeviceSampleSource { class RemoteInput : public DeviceSampleSource {
Q_OBJECT Q_OBJECT
public: public:
struct RemoteChannelSettings
{
uint64_t m_deviceCenterFrequency;
uint32_t m_deviceSampleRate;
uint32_t m_log2Decim;
uint32_t m_filterChainHash;
RemoteChannelSettings() :
m_deviceCenterFrequency(0),
m_deviceSampleRate(1),
m_log2Decim(0),
m_filterChainHash(0)
{}
};
class MsgConfigureRemoteInput : public Message { class MsgConfigureRemoteInput : public Message {
MESSAGE_CLASS_DECLARATION MESSAGE_CLASS_DECLARATION
@ -125,6 +141,26 @@ public:
{ } { }
}; };
class MsgConfigureRemoteChannel : public Message {
MESSAGE_CLASS_DECLARATION
public:
const RemoteChannelSettings& getSettings() const { return m_settings; }
static MsgConfigureRemoteChannel* create(const RemoteChannelSettings& settings)
{
return new MsgConfigureRemoteChannel(settings);
}
protected:
RemoteChannelSettings m_settings;
MsgConfigureRemoteChannel(const RemoteChannelSettings& settings) :
Message(),
m_settings(settings)
{ }
};
class MsgReportRemoteInputStreamTiming : public Message { class MsgReportRemoteInputStreamTiming : public Message {
MESSAGE_CLASS_DECLARATION MESSAGE_CLASS_DECLARATION
@ -248,6 +284,68 @@ public:
{ } { }
}; };
class MsgReportRemoteFixedData : public Message {
MESSAGE_CLASS_DECLARATION
public:
struct RemoteData
{
QString m_version; //!< Remote SDRangel version
QString m_qtVersion; //!< Remote Qt version used to build SDRangel
QString m_architecture; //!< Remote CPU architecture
QString m_os; //!< Remote O/S
int m_rxBits; //!< Number of bits used for I or Q sample on Rx side
int m_txBits; //!< Number of bits used for I or Q sample on Tx side
};
const RemoteData& getData() const { return m_remoteData; }
static MsgReportRemoteFixedData* create(const RemoteData& remoteData) {
return new MsgReportRemoteFixedData(remoteData);
}
private:
RemoteData m_remoteData;
MsgReportRemoteFixedData(const RemoteData& remoteData) :
Message(),
m_remoteData(remoteData)
{}
};
class MsgReportRemoteAPIError : public Message {
MESSAGE_CLASS_DECLARATION
public:
const QString& getMessage() const { return m_message; }
static MsgReportRemoteAPIError* create(const QString& message) {
return new MsgReportRemoteAPIError(message);
}
private:
QString m_message;
MsgReportRemoteAPIError(const QString& message) :
Message(),
m_message(message)
{}
};
class MsgRequestFixedData : public Message {
MESSAGE_CLASS_DECLARATION
public:
static MsgRequestFixedData* create() {
return new MsgRequestFixedData();
}
private:
MsgRequestFixedData() :
Message()
{}
};
RemoteInput(DeviceAPI *deviceAPI); RemoteInput(DeviceAPI *deviceAPI);
virtual ~RemoteInput(); virtual ~RemoteInput();
virtual void destroy(); virtual void destroy();
@ -307,7 +405,9 @@ private:
int m_sampleRate; int m_sampleRate;
QMutex m_mutex; QMutex m_mutex;
RemoteInputSettings m_settings; RemoteInputSettings m_settings;
RemoteChannelSettings m_remoteChannelSettings;
RemoteInputUDPHandler* m_remoteInputUDPHandler; RemoteInputUDPHandler* m_remoteInputUDPHandler;
RemoteMetaDataFEC m_currentMeta;
QString m_remoteAddress; QString m_remoteAddress;
QString m_deviceDescription; QString m_deviceDescription;
std::time_t m_startingTimeStamp; std::time_t m_startingTimeStamp;
@ -315,9 +415,12 @@ private:
QNetworkRequest m_networkRequest; QNetworkRequest m_networkRequest;
void applySettings(const RemoteInputSettings& settings, bool force = false); void applySettings(const RemoteInputSettings& settings, bool force = false);
void applyRemoteChannelSettings(const RemoteChannelSettings& settings);
void webapiFormatDeviceReport(SWGSDRangel::SWGDeviceReport& response); void webapiFormatDeviceReport(SWGSDRangel::SWGDeviceReport& response);
void webapiReverseSendSettings(QList<QString>& deviceSettingsKeys, const RemoteInputSettings& settings, bool force); void webapiReverseSendSettings(QList<QString>& deviceSettingsKeys, const RemoteInputSettings& settings, bool force);
void webapiReverseSendStartStop(bool start); void webapiReverseSendStartStop(bool start);
void analyzeRemoteChannelSettingsReply(const QJsonObject& jsonObject);
void analyzeInstanceSummaryReply(const QJsonObject& jsonObject);
private slots: private slots:
void networkManagerFinished(QNetworkReply *reply); void networkManagerFinished(QNetworkReply *reply);

View File

@ -93,8 +93,8 @@ void RemoteInputBuffer::setNbDecoderSlots(int nbDecoderSlots)
m_decoderSlots = new DecoderSlot[m_nbDecoderSlots]; m_decoderSlots = new DecoderSlot[m_nbDecoderSlots];
m_frames = new BufferFrame[m_nbDecoderSlots]; m_frames = new BufferFrame[m_nbDecoderSlots];
m_frameHead = -1; m_frameHead = -1;
initReadIndex();
} }
void RemoteInputBuffer::setBufferLenSec(const RemoteMetaDataFEC& metaData) void RemoteInputBuffer::setBufferLenSec(const RemoteMetaDataFEC& metaData)
@ -415,6 +415,8 @@ void RemoteInputBuffer::printMeta(const QString& header, RemoteMetaDataFEC *meta
<< ":" << (int) metaData->m_sampleBits << ":" << (int) metaData->m_sampleBits
<< ":" << (int) metaData->m_nbOriginalBlocks << ":" << (int) metaData->m_nbOriginalBlocks
<< ":" << (int) metaData->m_nbFECBlocks << ":" << (int) metaData->m_nbFECBlocks
<< "|" << metaData->m_deviceIndex
<< ":" << metaData->m_channelIndex
<< "|" << metaData->m_tv_sec << "|" << metaData->m_tv_sec
<< ":" << metaData->m_tv_usec << ":" << metaData->m_tv_usec
<< "|"; << "|";

View File

@ -18,11 +18,14 @@
#ifndef PLUGINS_SAMPLESOURCE_REMOTEINPUT_REMOTEINPUTBUFFER_H_ #ifndef PLUGINS_SAMPLESOURCE_REMOTEINPUT_REMOTEINPUTBUFFER_H_
#define PLUGINS_SAMPLESOURCE_REMOTEINPUT_REMOTEINPUTBUFFER_H_ #define PLUGINS_SAMPLESOURCE_REMOTEINPUT_REMOTEINPUTBUFFER_H_
#include <channel/remotedatablock.h>
#include <QString> #include <QString>
#include <QDebug> #include <QDebug>
#include <cstdlib> #include <cstdlib>
#include "cm256cc/cm256.h" #include "cm256cc/cm256.h"
#include "channel/remotedatablock.h"
#include "util/movingaverage.h" #include "util/movingaverage.h"

View File

@ -25,10 +25,6 @@
#include <QTime> #include <QTime>
#include <QDateTime> #include <QDateTime>
#include <QString> #include <QString>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QJsonParseError>
#include <QJsonObject>
#include "ui_remoteinputgui.h" #include "ui_remoteinputgui.h"
#include "gui/colormapper.h" #include "gui/colormapper.h"
@ -37,6 +33,7 @@
#include "gui/basicdevicesettingsdialog.h" #include "gui/basicdevicesettingsdialog.h"
#include "dsp/dspengine.h" #include "dsp/dspengine.h"
#include "dsp/dspcommands.h" #include "dsp/dspcommands.h"
#include "dsp/hbfilterchainconverter.h"
#include "mainwindow.h" #include "mainwindow.h"
#include "util/simpleserializer.h" #include "util/simpleserializer.h"
#include "device/deviceapi.h" #include "device/deviceapi.h"
@ -76,6 +73,9 @@ RemoteInputGui::RemoteInputGui(DeviceUISet *deviceUISet, QWidget* parent) :
m_startingTimeStampms = 0; m_startingTimeStampms = 0;
ui->setupUi(this); ui->setupUi(this);
ui->remoteDeviceFrequency->setColorMapper(ColorMapper(ColorMapper::GrayGold));
ui->remoteDeviceFrequency->setValueRange(8, 0, 99999999);
CRightClickEnabler *startStopRightClickEnabler = new CRightClickEnabler(ui->startStop); CRightClickEnabler *startStopRightClickEnabler = new CRightClickEnabler(ui->startStop);
connect(startStopRightClickEnabler, SIGNAL(rightClick(const QPoint &)), this, SLOT(openDeviceSettingsDialog(const QPoint &))); connect(startStopRightClickEnabler, SIGNAL(rightClick(const QPoint &)), this, SLOT(openDeviceSettingsDialog(const QPoint &)));
@ -84,15 +84,13 @@ RemoteInputGui::RemoteInputGui(DeviceUISet *deviceUISet, QWidget* parent) :
connect(&m_statusTimer, SIGNAL(timeout()), this, SLOT(updateStatus())); connect(&m_statusTimer, SIGNAL(timeout()), this, SLOT(updateStatus()));
m_statusTimer.start(500); m_statusTimer.start(500);
connect(&m_updateTimer, SIGNAL(timeout()), this, SLOT(updateHardware())); connect(&m_updateTimer, SIGNAL(timeout()), this, SLOT(updateHardware()));
connect(&m_remoteUpdateTimer, SIGNAL(timeout()), this, SLOT(updateRemote()));
m_sampleSource = (RemoteInput*) m_deviceUISet->m_deviceAPI->getSampleSource(); m_sampleSource = (RemoteInput*) m_deviceUISet->m_deviceAPI->getSampleSource();
connect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages()), Qt::QueuedConnection); connect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages()), Qt::QueuedConnection);
m_sampleSource->setMessageQueueToGUI(&m_inputMessageQueue); m_sampleSource->setMessageQueueToGUI(&m_inputMessageQueue);
m_networkManager = new QNetworkAccessManager();
connect(m_networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(networkManagerFinished(QNetworkReply*)));
m_eventsTime.start(); m_eventsTime.start();
displayEventCounts(); displayEventCounts();
displayEventTimer(); displayEventTimer();
@ -103,8 +101,6 @@ RemoteInputGui::RemoteInputGui(DeviceUISet *deviceUISet, QWidget* parent) :
RemoteInputGui::~RemoteInputGui() RemoteInputGui::~RemoteInputGui()
{ {
disconnect(m_networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(networkManagerFinished(QNetworkReply*)));
delete m_networkManager;
delete ui; delete ui;
} }
@ -160,6 +156,16 @@ bool RemoteInputGui::handleMessage(const Message& message)
blockApplySettings(false); blockApplySettings(false);
return true; return true;
} }
else if (RemoteInput::MsgConfigureRemoteChannel::match(message))
{
qDebug("RemoteInputGui::handleMessage: RemoteInput::MsgConfigureRemoteChannel");
const RemoteInput::MsgConfigureRemoteChannel& cfg = (RemoteInput::MsgConfigureRemoteChannel&) message;
m_remoteChannelSettings = cfg.getSettings();
blockApplySettings(true);
displayRemoteSettings();
blockApplySettings(false);
return true;
}
else if (RemoteInput::MsgReportRemoteInputAcquisition::match(message)) else if (RemoteInput::MsgReportRemoteInputAcquisition::match(message))
{ {
m_acquisition = ((RemoteInput::MsgReportRemoteInputAcquisition&)message).getAcquisition(); m_acquisition = ((RemoteInput::MsgReportRemoteInputAcquisition&)message).getAcquisition();
@ -208,7 +214,20 @@ bool RemoteInputGui::handleMessage(const Message& message)
blockApplySettings(true); blockApplySettings(true);
ui->startStop->setChecked(notif.getStartStop()); ui->startStop->setChecked(notif.getStartStop());
blockApplySettings(false); blockApplySettings(false);
return true;
}
else if (RemoteInput::MsgReportRemoteFixedData::match(message))
{
ui->apiAddressLabel->setStyleSheet("QLabel { background-color : green; }");
const RemoteInput::MsgReportRemoteFixedData& report = (const RemoteInput::MsgReportRemoteFixedData&) message;
displayRemoteFixedData(report.getData());
return true;
}
else if (RemoteInput::MsgReportRemoteAPIError::match(message))
{
ui->apiAddressLabel->setStyleSheet("QLabel { background:rgb(79,79,79); }");
const RemoteInput::MsgReportRemoteAPIError& report = (const RemoteInput::MsgReportRemoteAPIError&) message;
ui->statusText->setText(QString(report.getMessage()));
return true; return true;
} }
else else
@ -286,10 +305,81 @@ void RemoteInputGui::displaySettings()
blockApplySettings(false); blockApplySettings(false);
} }
void RemoteInputGui::displayRemoteSettings()
{
blockApplySettings(true);
ui->remoteDeviceFrequency->setValue(m_remoteChannelSettings.m_deviceCenterFrequency/1000);
ui->decimationFactor->setCurrentIndex(m_remoteChannelSettings.m_log2Decim);
applyDecimation();
blockApplySettings(false);
}
void RemoteInputGui::displayRemoteShift()
{
int basebandSampleRate = m_streamSampleRate * (1<<m_remoteChannelSettings.m_log2Decim);
int shift = m_remoteShiftFrequencyFactor * basebandSampleRate;
QLocale loc;
ui->offsetFrequencyText->setText(tr("%1 Hz").arg(loc.toString(shift)));
}
void RemoteInputGui::applyDecimation()
{
uint32_t maxHash = 1;
for (uint32_t i = 0; i < m_remoteChannelSettings.m_log2Decim; i++) {
maxHash *= 3;
}
ui->position->setMaximum(maxHash-1);
ui->position->setValue(m_remoteChannelSettings.m_filterChainHash);
m_remoteChannelSettings.m_filterChainHash = ui->position->value();
applyPosition();
}
void RemoteInputGui::applyPosition()
{
ui->filterChainIndex->setText(tr("%1").arg(m_remoteChannelSettings.m_filterChainHash));
QString s;
m_remoteShiftFrequencyFactor = HBFilterChainConverter::convertToString(
m_remoteChannelSettings.m_log2Decim,
m_remoteChannelSettings.m_filterChainHash, s)
;
ui->filterChainText->setText(s);
displayRemoteShift();
applyRemoteSettings();
}
void RemoteInputGui::applyRemoteSettings()
{
if (!m_remoteUpdateTimer.isActive()) {
m_remoteUpdateTimer.start(100);
}
}
void RemoteInputGui::sendSettings() void RemoteInputGui::sendSettings()
{ {
if(!m_updateTimer.isActive()) if (!m_updateTimer.isActive()) {
m_updateTimer.start(100); m_updateTimer.start(100);
}
}
void RemoteInputGui::on_remoteDeviceFrequency_changed(quint64 value)
{
m_remoteChannelSettings.m_deviceCenterFrequency = value * 1000;
applyRemoteSettings();
}
void RemoteInputGui::on_decimationFactor_currentIndexChanged(int index)
{
m_remoteChannelSettings.m_log2Decim = index;
applyDecimation();
}
void RemoteInputGui::on_position_valueChanged(int value)
{
m_remoteChannelSettings.m_filterChainHash = value;
applyPosition();
} }
void RemoteInputGui::on_apiApplyButton_clicked(bool checked) void RemoteInputGui::on_apiApplyButton_clicked(bool checked)
@ -306,9 +396,9 @@ void RemoteInputGui::on_apiApplyButton_clicked(bool checked)
sendSettings(); sendSettings();
QString infoURL = QString("http://%1:%2/sdrangel").arg(m_settings.m_apiAddress).arg(m_settings.m_apiPort); ui->apiAddressLabel->setStyleSheet("QLabel { background:rgb(79,79,79); }");
m_networkRequest.setUrl(QUrl(infoURL)); RemoteInput::MsgRequestFixedData *msg = RemoteInput::MsgRequestFixedData::create();
m_networkManager->get(m_networkRequest); m_sampleSource->getInputMessageQueue()->push(msg);
} }
void RemoteInputGui::on_dataApplyButton_clicked(bool checked) void RemoteInputGui::on_dataApplyButton_clicked(bool checked)
@ -325,9 +415,9 @@ void RemoteInputGui::on_apiAddress_editingFinished()
{ {
m_settings.m_apiAddress = ui->apiAddress->text(); m_settings.m_apiAddress = ui->apiAddress->text();
QString infoURL = QString("http://%1:%2/sdrangel").arg(m_settings.m_apiAddress).arg(m_settings.m_apiPort); ui->apiAddressLabel->setStyleSheet("QLabel { background:rgb(79,79,79); }");
m_networkRequest.setUrl(QUrl(infoURL)); RemoteInput::MsgRequestFixedData *msg = RemoteInput::MsgRequestFixedData::create();
m_networkManager->get(m_networkRequest); m_sampleSource->getInputMessageQueue()->push(msg);
sendSettings(); sendSettings();
} }
@ -382,9 +472,9 @@ void RemoteInputGui::on_apiPort_editingFinished()
{ {
m_settings.m_apiPort = udpApiPort; m_settings.m_apiPort = udpApiPort;
QString infoURL = QString("http://%1:%2/sdrangel").arg(m_settings.m_apiAddress).arg(m_settings.m_apiPort); ui->apiAddressLabel->setStyleSheet("QLabel { background:rgb(79,79,79); }");
m_networkRequest.setUrl(QUrl(infoURL)); RemoteInput::MsgRequestFixedData *msg = RemoteInput::MsgRequestFixedData::create();
m_networkManager->get(m_networkRequest); m_sampleSource->getInputMessageQueue()->push(msg);
sendSettings(); sendSettings();
} }
@ -438,6 +528,21 @@ void RemoteInputGui::displayEventTimer()
ui->eventCountsTimeText->setText(s_time); ui->eventCountsTimeText->setText(s_time);
} }
void RemoteInputGui::displayRemoteFixedData(const RemoteInput::MsgReportRemoteFixedData::RemoteData& remoteData)
{
QString infoLine;
infoLine = remoteData.m_version;
infoLine += " Qt" + remoteData.m_qtVersion;
infoLine += " " + remoteData.m_architecture;
infoLine += " " + remoteData.m_os;
infoLine += QString(" %1/%2b").arg(remoteData.m_rxBits).arg(remoteData.m_txBits);
if (infoLine.size() > 0) {
ui->infoText->setText(infoLine);
}
}
void RemoteInputGui::updateWithAcquisition() void RemoteInputGui::updateWithAcquisition()
{ {
} }
@ -508,6 +613,18 @@ void RemoteInputGui::updateHardware()
} }
} }
void RemoteInputGui::updateRemote()
{
if (m_doApplySettings)
{
qDebug() << "RemoteInputGui::updateRemote";
RemoteInput::MsgConfigureRemoteChannel* message =
RemoteInput::MsgConfigureRemoteChannel::create(m_remoteChannelSettings);
m_sampleSource->getInputMessageQueue()->push(message);
m_remoteUpdateTimer.stop();
}
}
void RemoteInputGui::updateStatus() void RemoteInputGui::updateStatus()
{ {
if (m_sampleSource->isStreaming()) if (m_sampleSource->isStreaming())
@ -548,78 +665,6 @@ void RemoteInputGui::updateStatus()
} }
} }
void RemoteInputGui::networkManagerFinished(QNetworkReply *reply)
{
if (reply->error())
{
ui->apiAddressLabel->setStyleSheet("QLabel { background:rgb(79,79,79); }");
ui->statusText->setText(reply->errorString());
}
else
{
QString answer = reply->readAll();
try
{
QByteArray jsonBytes(answer.toStdString().c_str());
QJsonParseError error;
QJsonDocument doc = QJsonDocument::fromJson(jsonBytes, &error);
if (error.error == QJsonParseError::NoError)
{
ui->apiAddressLabel->setStyleSheet("QLabel { background-color : green; }");
ui->statusText->setText(QString("API OK"));
analyzeApiReply(doc.object());
}
else
{
ui->apiAddressLabel->setStyleSheet("QLabel { background:rgb(79,79,79); }");
QString errorMsg = QString("Reply JSON error: ") + error.errorString() + QString(" at offset ") + QString::number(error.offset);
ui->statusText->setText(QString("JSON error. See log"));
qInfo().noquote() << "RemoteInputGui::networkManagerFinished" << errorMsg;
}
}
catch (const std::exception& ex)
{
ui->apiAddressLabel->setStyleSheet("QLabel { background:rgb(79,79,79); }");
QString errorMsg = QString("Error parsing request: ") + ex.what();
ui->statusText->setText("Error parsing request. See log for details");
qInfo().noquote() << "RemoteInputGui::networkManagerFinished" << errorMsg;
}
}
reply->deleteLater();
}
void RemoteInputGui::analyzeApiReply(const QJsonObject& jsonObject)
{
QString infoLine;
if (jsonObject.contains("version")) {
infoLine = jsonObject["version"].toString();
}
if (jsonObject.contains("qtVersion")) {
infoLine += " Qt" + jsonObject["qtVersion"].toString();
}
if (jsonObject.contains("architecture")) {
infoLine += " " + jsonObject["architecture"].toString();
}
if (jsonObject.contains("os")) {
infoLine += " " + jsonObject["os"].toString();
}
if (jsonObject.contains("dspRxBits") && jsonObject.contains("dspTxBits")) {
infoLine += QString(" %1/%2b").arg(jsonObject["dspRxBits"].toInt()).arg(jsonObject["dspTxBits"].toInt());
}
if (infoLine.size() > 0) {
ui->infoText->setText(infoLine);
}
}
void RemoteInputGui::openDeviceSettingsDialog(const QPoint& p) void RemoteInputGui::openDeviceSettingsDialog(const QPoint& p)
{ {
BasicDeviceSettingsDialog dialog(this); BasicDeviceSettingsDialog dialog(this);

View File

@ -21,7 +21,6 @@
#include <QTimer> #include <QTimer>
#include <QElapsedTimer> #include <QElapsedTimer>
#include <QWidget> #include <QWidget>
#include <QNetworkRequest>
#include "device/devicegui.h" #include "device/devicegui.h"
#include "util/messagequeue.h" #include "util/messagequeue.h"
@ -55,11 +54,14 @@ private:
DeviceUISet* m_deviceUISet; DeviceUISet* m_deviceUISet;
RemoteInputSettings m_settings; //!< current settings RemoteInputSettings m_settings; //!< current settings
RemoteInput::RemoteChannelSettings m_remoteChannelSettings;
double m_remoteShiftFrequencyFactor; //!< Remote channel frequency shift factor
RemoteInput* m_sampleSource; RemoteInput* m_sampleSource;
bool m_acquisition; bool m_acquisition;
int m_streamSampleRate; //!< Sample rate of received stream int m_streamSampleRate; //!< Sample rate of received stream
quint64 m_streamCenterFrequency; //!< Center frequency of received stream quint64 m_streamCenterFrequency; //!< Center frequency of received stream
QTimer m_updateTimer; QTimer m_updateTimer;
QTimer m_remoteUpdateTimer;
QTimer m_statusTimer; QTimer m_statusTimer;
int m_lastEngineState; int m_lastEngineState;
MessageQueue m_inputMessageQueue; MessageQueue m_inputMessageQueue;
@ -98,23 +100,28 @@ private:
QPalette m_paletteGreenText; QPalette m_paletteGreenText;
QPalette m_paletteWhiteText; QPalette m_paletteWhiteText;
QNetworkAccessManager *m_networkManager;
QNetworkRequest m_networkRequest;
void blockApplySettings(bool block); void blockApplySettings(bool block);
void displaySettings(); void displaySettings();
void displayRemoteSettings();
void displayRemoteShift();
void displayTime(); void displayTime();
void displayRemoteFixedData(const RemoteInput::MsgReportRemoteFixedData::RemoteData& remoteData);
void sendSettings(); void sendSettings();
void updateWithAcquisition(); void updateWithAcquisition();
void updateWithStreamTime(); void updateWithStreamTime();
void updateSampleRateAndFrequency(); void updateSampleRateAndFrequency();
void displayEventCounts(); void displayEventCounts();
void displayEventTimer(); void displayEventTimer();
void analyzeApiReply(const QJsonObject& jsonObject); void applyDecimation();
void applyPosition();
void applyRemoteSettings();
bool handleMessage(const Message& message); bool handleMessage(const Message& message);
private slots: private slots:
void handleInputMessages(); void handleInputMessages();
void on_remoteDeviceFrequency_changed(quint64 value);
void on_decimationFactor_currentIndexChanged(int index);
void on_position_valueChanged(int value);
void on_apiApplyButton_clicked(bool checked); void on_apiApplyButton_clicked(bool checked);
void on_dataApplyButton_clicked(bool checked); void on_dataApplyButton_clicked(bool checked);
void on_dcOffset_toggled(bool checked); void on_dcOffset_toggled(bool checked);
@ -128,8 +135,8 @@ private slots:
void on_startStop_toggled(bool checked); void on_startStop_toggled(bool checked);
void on_eventCountsReset_clicked(bool checked); void on_eventCountsReset_clicked(bool checked);
void updateHardware(); void updateHardware();
void updateRemote();
void updateStatus(); void updateStatus();
void networkManagerFinished(QNetworkReply *reply);
void openDeviceSettingsDialog(const QPoint& p); void openDeviceSettingsDialog(const QPoint& p);
}; };

View File

@ -7,13 +7,13 @@
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>400</width> <width>400</width>
<height>312</height> <height>480</height>
</rect> </rect>
</property> </property>
<property name="minimumSize"> <property name="minimumSize">
<size> <size>
<width>360</width> <width>360</width>
<height>270</height> <height>480</height>
</size> </size>
</property> </property>
<property name="font"> <property name="font">
@ -27,7 +27,7 @@
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout"> <layout class="QVBoxLayout" name="verticalLayout">
<property name="spacing"> <property name="spacing">
<number>3</number> <number>2</number>
</property> </property>
<property name="leftMargin"> <property name="leftMargin">
<number>2</number> <number>2</number>
@ -162,6 +162,233 @@
</property> </property>
</widget> </widget>
</item> </item>
<item>
<layout class="QHBoxLayout" name="remoteDevFreqLayout">
<property name="spacing">
<number>6</number>
</property>
<item>
<widget class="QLabel" name="remoteFrequencyLabel">
<property name="text">
<string>Rem dev Fc</string>
</property>
</widget>
</item>
<item>
<widget class="ValueDial" name="remoteDeviceFrequency" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>32</width>
<height>16</height>
</size>
</property>
<property name="font">
<font>
<family>Liberation Mono</family>
<pointsize>12</pointsize>
<weight>50</weight>
<bold>false</bold>
</font>
</property>
<property name="cursor">
<cursorShape>PointingHandCursor</cursorShape>
</property>
<property name="toolTip">
<string>Remote device center ferquency in kHz</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="remoteDeviceFreqUnits">
<property name="text">
<string>kHz</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_9">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<layout class="QVBoxLayout" name="remoteChDecimationLayer">
<property name="spacing">
<number>3</number>
</property>
<item>
<layout class="QHBoxLayout" name="decimationStageLayer">
<item>
<widget class="QLabel" name="decimationLabel">
<property name="text">
<string>Rem ch Dec</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="decimationFactor">
<property name="maximumSize">
<size>
<width>55</width>
<height>16777215</height>
</size>
</property>
<property name="toolTip">
<string>Decimation factor</string>
</property>
<item>
<property name="text">
<string>1</string>
</property>
</item>
<item>
<property name="text">
<string>2</string>
</property>
</item>
<item>
<property name="text">
<string>4</string>
</property>
</item>
<item>
<property name="text">
<string>8</string>
</property>
</item>
<item>
<property name="text">
<string>16</string>
</property>
</item>
<item>
<property name="text">
<string>32</string>
</property>
</item>
<item>
<property name="text">
<string>64</string>
</property>
</item>
</widget>
</item>
<item>
<widget class="QLabel" name="filterChainText">
<property name="minimumSize">
<size>
<width>50</width>
<height>0</height>
</size>
</property>
<property name="toolTip">
<string>Filter chain stages left to right (L: low, C: center, H: high) </string>
</property>
<property name="text">
<string>LLLLLL</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_8">
<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="offsetFrequencyText">
<property name="minimumSize">
<size>
<width>85</width>
<height>0</height>
</size>
</property>
<property name="toolTip">
<string>Offset frequency with thousands separator (Hz)</string>
</property>
<property name="text">
<string>-9,999,999 Hz</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="decimationShiftLayer">
<property name="rightMargin">
<number>10</number>
</property>
<item>
<widget class="QLabel" name="positionLabel">
<property name="text">
<string>Rem ch Pos</string>
</property>
</widget>
</item>
<item>
<widget class="QSlider" name="position">
<property name="toolTip">
<string>Center frequency position</string>
</property>
<property name="maximum">
<number>2</number>
</property>
<property name="pageStep">
<number>1</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="filterChainIndex">
<property name="minimumSize">
<size>
<width>24</width>
<height>0</height>
</size>
</property>
<property name="toolTip">
<string>Filter chain hash code</string>
</property>
<property name="text">
<string>000</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
<item> <item>
<layout class="QHBoxLayout" name="gridLayout_corr"> <layout class="QHBoxLayout" name="gridLayout_corr">
<item> <item>
@ -860,6 +1087,12 @@
<extends>QToolButton</extends> <extends>QToolButton</extends>
<header>gui/buttonswitch.h</header> <header>gui/buttonswitch.h</header>
</customwidget> </customwidget>
<customwidget>
<class>ValueDial</class>
<extends>QWidget</extends>
<header>gui/valuedial.h</header>
<container>1</container>
</customwidget>
</customwidgets> </customwidgets>
<resources> <resources>
<include location="../../../sdrgui/resources/res.qrc"/> <include location="../../../sdrgui/resources/res.qrc"/>

View File

@ -31,7 +31,7 @@
const PluginDescriptor RemoteInputPlugin::m_pluginDescriptor = { const PluginDescriptor RemoteInputPlugin::m_pluginDescriptor = {
QStringLiteral("RemoteInput"), QStringLiteral("RemoteInput"),
QStringLiteral("Remote device input"), QStringLiteral("Remote device input"),
QStringLiteral("6.17.5"), QStringLiteral("6.17.6"),
QStringLiteral("(c) Edouard Griffiths, F4EXB"), QStringLiteral("(c) Edouard Griffiths, F4EXB"),
QStringLiteral("https://github.com/f4exb/sdrangel"), QStringLiteral("https://github.com/f4exb/sdrangel"),
true, true,

View File

@ -26,7 +26,7 @@
#include "remoteinputudphandler.h" #include "remoteinputudphandler.h"
#include "remoteinput.h" #include "remoteinput.h"
MESSAGE_CLASS_DEFINITION(RemoteInputUDPHandler::MsgReportSampleRateChange, Message) MESSAGE_CLASS_DEFINITION(RemoteInputUDPHandler::MsgReportMetaDataChange, Message)
MESSAGE_CLASS_DEFINITION(RemoteInputUDPHandler::MsgUDPAddressAndPort, Message) MESSAGE_CLASS_DEFINITION(RemoteInputUDPHandler::MsgUDPAddressAndPort, Message)
RemoteInputUDPHandler::RemoteInputUDPHandler(SampleSinkFifo *sampleFifo, DeviceAPI *deviceAPI) : RemoteInputUDPHandler::RemoteInputUDPHandler(SampleSinkFifo *sampleFifo, DeviceAPI *deviceAPI) :
@ -55,7 +55,7 @@ RemoteInputUDPHandler::RemoteInputUDPHandler(SampleSinkFifo *sampleFifo, DeviceA
m_throttlems(REMOTEINPUT_THROTTLE_MS), m_throttlems(REMOTEINPUT_THROTTLE_MS),
m_readLengthSamples(0), m_readLengthSamples(0),
m_readLength(0), m_readLength(0),
m_converterBuffer(0), m_converterBuffer(nullptr),
m_converterBufferNbSamples(0), m_converterBufferNbSamples(0),
m_throttleToggle(false), m_throttleToggle(false),
m_autoCorrBuffer(true) m_autoCorrBuffer(true)
@ -149,7 +149,7 @@ void RemoteInputUDPHandler::stop()
if (m_dataSocket) if (m_dataSocket)
{ {
delete m_dataSocket; delete m_dataSocket;
m_dataSocket = 0; m_dataSocket = nullptr;
} }
m_centerFrequency = 0; m_centerFrequency = 0;
@ -213,6 +213,18 @@ void RemoteInputUDPHandler::processData()
{ {
m_remoteInputBuffer.writeData(m_udpBuf); m_remoteInputBuffer.writeData(m_udpBuf);
const RemoteMetaDataFEC& metaData = m_remoteInputBuffer.getCurrentMeta(); const RemoteMetaDataFEC& metaData = m_remoteInputBuffer.getCurrentMeta();
if (!(m_currentMeta == metaData))
{
m_currentMeta = metaData;
if (m_messageQueueToInput)
{
MsgReportMetaDataChange *msg = MsgReportMetaDataChange::create(m_currentMeta);
m_messageQueueToInput->push(msg);
}
}
bool change = false; bool change = false;
m_tv_msec = m_remoteInputBuffer.getTVOutMSec(); m_tv_msec = m_remoteInputBuffer.getTVOutMSec();
@ -227,13 +239,6 @@ void RemoteInputUDPHandler::processData()
{ {
disconnectTimer(); disconnectTimer();
adjustNbDecoderSlots(metaData); adjustNbDecoderSlots(metaData);
if (m_messageQueueToInput)
{
MsgReportSampleRateChange *msg = MsgReportSampleRateChange::create(metaData.m_sampleRate);
m_messageQueueToInput->push(msg);
}
m_samplerate = metaData.m_sampleRate; m_samplerate = metaData.m_sampleRate;
change = true; change = true;
} }
@ -256,6 +261,8 @@ void RemoteInputUDPHandler::processData()
} }
m_dataSocket->setSocketOption(QAbstractSocket::ReceiveBufferSizeSocketOption, getDataSocketBufferSize()); m_dataSocket->setSocketOption(QAbstractSocket::ReceiveBufferSizeSocketOption, getDataSocketBufferSize());
m_elapsedTimer.restart();
m_throttlems = 0;
connectTimer(); connectTimer();
} }
} }
@ -310,7 +317,7 @@ void RemoteInputUDPHandler::tick()
if (throttlems != m_throttlems) if (throttlems != m_throttlems)
{ {
m_throttlems = throttlems; m_throttlems = throttlems;
m_readLengthSamples = (m_remoteInputBuffer.getCurrentMeta().m_sampleRate * (m_throttlems+(m_throttleToggle ? 1 : 0))) / 1000; m_readLengthSamples = (m_currentMeta.m_sampleRate * (m_throttlems+(m_throttleToggle ? 1 : 0))) / 1000;
m_throttleToggle = !m_throttleToggle; m_throttleToggle = !m_throttleToggle;
} }
@ -319,20 +326,19 @@ void RemoteInputUDPHandler::tick()
m_readLengthSamples += m_remoteInputBuffer.getRWBalanceCorrection(); m_readLengthSamples += m_remoteInputBuffer.getRWBalanceCorrection();
// Eliminate negative or excessively high values // Eliminate negative or excessively high values
m_readLengthSamples = m_readLengthSamples < 0 ? m_readLengthSamples = m_readLengthSamples < 0 ?
0 : m_readLengthSamples > (int) m_remoteInputBuffer.getCurrentMeta().m_sampleRate/5 ? 0 : m_readLengthSamples > (int) m_currentMeta.m_sampleRate/5 ?
m_remoteInputBuffer.getCurrentMeta().m_sampleRate/5 : m_readLengthSamples; m_remoteInputBuffer.getCurrentMeta().m_sampleRate/5 : m_readLengthSamples;
} }
const RemoteMetaDataFEC& metaData = m_remoteInputBuffer.getCurrentMeta(); m_readLength = m_readLengthSamples * (m_currentMeta.m_sampleBytes & 0xF) * 2;
m_readLength = m_readLengthSamples * (metaData.m_sampleBytes & 0xF) * 2;
if (metaData.m_sampleBits == SDR_RX_SAMP_SZ) // no conversion if (m_currentMeta.m_sampleBits == SDR_RX_SAMP_SZ) // no conversion
{ {
// read samples directly feeding the SampleFifo (no callback) // read samples directly feeding the SampleFifo (no callback)
m_sampleFifo->write(reinterpret_cast<quint8*>(m_remoteInputBuffer.readData(m_readLength)), m_readLength); m_sampleFifo->write(reinterpret_cast<quint8*>(m_remoteInputBuffer.readData(m_readLength)), m_readLength);
m_samplesCount += m_readLengthSamples; m_samplesCount += m_readLengthSamples;
} }
else if ((metaData.m_sampleBits == 8) && (SDR_RX_SAMP_SZ == 16)) // 8 -> 16 else if ((m_currentMeta.m_sampleBits == 8) && (SDR_RX_SAMP_SZ == 16)) // 8 -> 16
{ {
if (m_readLengthSamples > (int) m_converterBufferNbSamples) if (m_readLengthSamples > (int) m_converterBufferNbSamples)
{ {
@ -349,7 +355,7 @@ void RemoteInputUDPHandler::tick()
m_converterBuffer[is] += buf[2*is] * (1<<8); // I -> LSB m_converterBuffer[is] += buf[2*is] * (1<<8); // I -> LSB
} }
} }
else if ((metaData.m_sampleBits == 8) && (SDR_RX_SAMP_SZ == 24)) // 8 -> 24 else if ((m_currentMeta.m_sampleBits == 8) && (SDR_RX_SAMP_SZ == 24)) // 8 -> 24
{ {
if (m_readLengthSamples > (int) m_converterBufferNbSamples) if (m_readLengthSamples > (int) m_converterBufferNbSamples)
{ {
@ -367,7 +373,7 @@ void RemoteInputUDPHandler::tick()
m_sampleFifo->write(reinterpret_cast<quint8*>(m_converterBuffer), m_readLengthSamples*sizeof(Sample)); m_sampleFifo->write(reinterpret_cast<quint8*>(m_converterBuffer), m_readLengthSamples*sizeof(Sample));
} }
else if (metaData.m_sampleBits == 16) // 16 -> 24 else if (m_currentMeta.m_sampleBits == 16) // 16 -> 24
{ {
if (m_readLengthSamples > (int) m_converterBufferNbSamples) if (m_readLengthSamples > (int) m_converterBufferNbSamples)
{ {
@ -385,7 +391,7 @@ void RemoteInputUDPHandler::tick()
m_sampleFifo->write(reinterpret_cast<quint8*>(m_converterBuffer), m_readLengthSamples*sizeof(Sample)); m_sampleFifo->write(reinterpret_cast<quint8*>(m_converterBuffer), m_readLengthSamples*sizeof(Sample));
} }
else if (metaData.m_sampleBits == 24) // 24 -> 16 else if (m_currentMeta.m_sampleBits == 24) // 24 -> 16
{ {
if (m_readLengthSamples > (int) m_converterBufferNbSamples) if (m_readLengthSamples > (int) m_converterBufferNbSamples)
{ {
@ -406,59 +412,9 @@ void RemoteInputUDPHandler::tick()
} }
else // invalid size else // invalid size
{ {
qWarning("RemoteInputUDPHandler::tick: unexpected sample size in stream: %d bits", (int) metaData.m_sampleBits); qWarning("RemoteInputUDPHandler::tick: unexpected sample size in stream: %d bits", (int) m_currentMeta.m_sampleBits);
} }
// if ((metaData.m_sampleBits == 16) && (SDR_RX_SAMP_SZ == 24)) // 16 -> 24 bits
// {
// if (m_readLengthSamples > (int) m_converterBufferNbSamples)
// {
// if (m_converterBuffer) { delete[] m_converterBuffer; }
// m_converterBuffer = new int32_t[m_readLengthSamples*2];
// }
// uint8_t *buf = m_remoteInputBuffer.readData(m_readLength);
// for (int is = 0; is < m_readLengthSamples; is++)
// {
// m_converterBuffer[2*is] = ((int16_t*)buf)[2*is]; // I
// m_converterBuffer[2*is]<<=8;
// m_converterBuffer[2*is+1] = ((int16_t*)buf)[2*is+1]; // Q
// m_converterBuffer[2*is+1]<<=8;
// }
// m_sampleFifo->write(reinterpret_cast<quint8*>(m_converterBuffer), m_readLengthSamples*sizeof(Sample));
// }
// else if ((metaData.m_sampleBits == 24) && (SDR_RX_SAMP_SZ == 16)) // 24 -> 16 bits
// {
// if (m_readLengthSamples > (int) m_converterBufferNbSamples)
// {
// if (m_converterBuffer) { delete[] m_converterBuffer; }
// m_converterBuffer = new int32_t[m_readLengthSamples];
// }
// uint8_t *buf = m_remoteInputBuffer.readData(m_readLength);
// for (int is = 0; is < m_readLengthSamples; is++)
// {
// m_converterBuffer[is] = ((int32_t *)buf)[2*is+1]>>8; // Q -> MSB
// m_converterBuffer[is] <<=16;
// m_converterBuffer[is] += ((int32_t *)buf)[2*is]>>8; // I -> LSB
// }
// m_sampleFifo->write(reinterpret_cast<quint8*>(m_converterBuffer), m_readLengthSamples*sizeof(Sample));
// }
// else if ((metaData.m_sampleBits == 16) || (metaData.m_sampleBits == 24)) // same sample size and valid size
// {
// // read samples directly feeding the SampleFifo (no callback)
// m_sampleFifo->write(reinterpret_cast<quint8*>(m_remoteInputBuffer.readData(m_readLength)), m_readLength);
// m_samplesCount += m_readLengthSamples;
// }
// else // invalid size
// {
// qWarning("RemoteInputUDPHandler::tick: unexpected sample size in stream: %d bits", (int) metaData.m_sampleBits);
// }
if (m_tickCount < m_rateDivider) if (m_tickCount < m_rateDivider)
{ {
m_tickCount++; m_tickCount++;

View File

@ -38,23 +38,23 @@ class RemoteInputUDPHandler : public QObject
{ {
Q_OBJECT Q_OBJECT
public: public:
class MsgReportSampleRateChange : public Message { class MsgReportMetaDataChange : public Message {
MESSAGE_CLASS_DECLARATION MESSAGE_CLASS_DECLARATION
public: public:
int getSampleRate() const { return m_sampleRate; } const RemoteMetaDataFEC& getMetaData() const { return m_metaData; }
static MsgReportSampleRateChange* create(int sampleRate) static MsgReportMetaDataChange* create(const RemoteMetaDataFEC& metaData)
{ {
return new MsgReportSampleRateChange(sampleRate); return new MsgReportMetaDataChange(metaData);
} }
protected: protected:
int m_sampleRate; RemoteMetaDataFEC m_metaData;
MsgReportSampleRateChange(int sampleRate) : MsgReportMetaDataChange(const RemoteMetaDataFEC& metaData) :
Message(), Message(),
m_sampleRate(sampleRate) m_metaData(metaData)
{ } { }
}; };
@ -74,6 +74,8 @@ public:
uint64_t getTVmSec() const { return m_tv_msec; } uint64_t getTVmSec() const { return m_tv_msec; }
int getMinNbBlocks() { return m_remoteInputBuffer.getMinNbBlocks(); } int getMinNbBlocks() { return m_remoteInputBuffer.getMinNbBlocks(); }
int getMaxNbRecovery() { return m_remoteInputBuffer.getMaxNbRecovery(); } int getMaxNbRecovery() { return m_remoteInputBuffer.getMaxNbRecovery(); }
const RemoteMetaDataFEC& getCurrentMeta() const { return m_currentMeta; }
public slots: public slots:
void dataReadyRead(); void dataReadyRead();
@ -113,6 +115,7 @@ private:
bool m_running; bool m_running;
uint32_t m_rateDivider; uint32_t m_rateDivider;
RemoteInputBuffer m_remoteInputBuffer; RemoteInputBuffer m_remoteInputBuffer;
RemoteMetaDataFEC m_currentMeta;
QUdpSocket *m_dataSocket; QUdpSocket *m_dataSocket;
QHostAddress m_dataAddress; QHostAddress m_dataAddress;
QHostAddress m_remoteAddress; QHostAddress m_remoteAddress;

View File

@ -38,16 +38,18 @@
#pragma pack(push, 1) #pragma pack(push, 1)
struct RemoteMetaDataFEC struct RemoteMetaDataFEC
{ {
uint64_t m_centerFrequency; //!< 8 center frequency in kHz uint64_t m_centerFrequency; //!< 8 center frequency in kHz
uint32_t m_sampleRate; //!< 12 sample rate in Hz uint32_t m_sampleRate; //!< 12 sample rate in Hz
uint8_t m_sampleBytes; //!< 13 4 LSB: number of bytes per sample (2 or 4) uint8_t m_sampleBytes; //!< 13 4 LSB: number of bytes per sample (2 or 4)
uint8_t m_sampleBits; //!< 14 number of effective bits per sample (deprecated) uint8_t m_sampleBits; //!< 14 number of effective bits per sample (deprecated)
uint8_t m_nbOriginalBlocks; //!< 15 number of blocks with original (protected) data uint8_t m_nbOriginalBlocks; //!< 15 number of blocks with original (protected) data
uint8_t m_nbFECBlocks; //!< 16 number of blocks carrying FEC uint8_t m_nbFECBlocks; //!< 16 number of blocks carrying FEC
uint8_t m_deviceIndex; //!< 29 index of device set in instance
uint8_t m_channelIndex; //!< 30 index of channel in device set
uint32_t m_tv_sec; //!< 20 seconds of timestamp at start time of super-frame processing uint32_t m_tv_sec; //!< 34 seconds of timestamp at start time of super-frame processing
uint32_t m_tv_usec; //!< 24 microseconds of timestamp at start time of super-frame processing uint32_t m_tv_usec; //!< 38 microseconds of timestamp at start time of super-frame processing
uint32_t m_crc32; //!< 28 CRC32 of the above uint32_t m_crc32; //!< 42 CRC32 of the above
bool operator==(const RemoteMetaDataFEC& rhs) bool operator==(const RemoteMetaDataFEC& rhs)
{ {
@ -68,6 +70,8 @@ struct RemoteMetaDataFEC
m_sampleBits = 0; m_sampleBits = 0;
m_nbOriginalBlocks = 0; m_nbOriginalBlocks = 0;
m_nbFECBlocks = 0; m_nbFECBlocks = 0;
m_deviceIndex = 0;
m_channelIndex = 0;
m_tv_sec = 0; m_tv_sec = 0;
m_tv_usec = 0; m_tv_usec = 0;
m_crc32 = 0; m_crc32 = 0;

View File

@ -9911,6 +9911,10 @@ margin-bottom: 20px;
"type" : "integer", "type" : "integer",
"description" : "Number of bytes in a transmited I or Q sample\n * 1\n * 2\n * 4\n" "description" : "Number of bytes in a transmited I or Q sample\n * 1\n * 2\n * 4\n"
}, },
"deviceCenterFrequency" : {
"type" : "integer",
"description" : "Device center frequency in kHz"
},
"dataAddress" : { "dataAddress" : {
"type" : "string", "type" : "string",
"description" : "Receiving USB data address" "description" : "Receiving USB data address"
@ -51630,7 +51634,7 @@ except ApiException as e:
</div> </div>
<div id="generator"> <div id="generator">
<div class="content"> <div class="content">
Generated 2021-12-19T12:04:51.409+01:00 Generated 2021-12-24T20:37:17.750+01:00
</div> </div>
</div> </div>
</div> </div>

View File

@ -11,6 +11,9 @@ RemoteSinkSettings:
* 1 * 1
* 2 * 2
* 4 * 4
deviceCenterFrequency:
type: integer
description: Device center frequency in kHz
dataAddress: dataAddress:
description: "Receiving USB data address" description: "Receiving USB data address"
type: string type: string

View File

@ -11,6 +11,9 @@ RemoteSinkSettings:
* 1 * 1
* 2 * 2
* 4 * 4
deviceCenterFrequency:
type: integer
description: Device center frequency in kHz
dataAddress: dataAddress:
description: "Receiving USB data address" description: "Receiving USB data address"
type: string type: string

View File

@ -9911,6 +9911,10 @@ margin-bottom: 20px;
"type" : "integer", "type" : "integer",
"description" : "Number of bytes in a transmited I or Q sample\n * 1\n * 2\n * 4\n" "description" : "Number of bytes in a transmited I or Q sample\n * 1\n * 2\n * 4\n"
}, },
"deviceCenterFrequency" : {
"type" : "integer",
"description" : "Device center frequency in kHz"
},
"dataAddress" : { "dataAddress" : {
"type" : "string", "type" : "string",
"description" : "Receiving USB data address" "description" : "Receiving USB data address"
@ -51630,7 +51634,7 @@ except ApiException as e:
</div> </div>
<div id="generator"> <div id="generator">
<div class="content"> <div class="content">
Generated 2021-12-19T12:04:51.409+01:00 Generated 2021-12-24T20:37:17.750+01:00
</div> </div>
</div> </div>
</div> </div>

View File

@ -32,6 +32,8 @@ SWGRemoteSinkSettings::SWGRemoteSinkSettings() {
m_nb_fec_blocks_isSet = false; m_nb_fec_blocks_isSet = false;
nb_tx_bytes = 0; nb_tx_bytes = 0;
m_nb_tx_bytes_isSet = false; m_nb_tx_bytes_isSet = false;
device_center_frequency = 0;
m_device_center_frequency_isSet = false;
data_address = nullptr; data_address = nullptr;
m_data_address_isSet = false; m_data_address_isSet = false;
data_port = 0; data_port = 0;
@ -70,6 +72,8 @@ SWGRemoteSinkSettings::init() {
m_nb_fec_blocks_isSet = false; m_nb_fec_blocks_isSet = false;
nb_tx_bytes = 0; nb_tx_bytes = 0;
m_nb_tx_bytes_isSet = false; m_nb_tx_bytes_isSet = false;
device_center_frequency = 0;
m_device_center_frequency_isSet = false;
data_address = new QString(""); data_address = new QString("");
m_data_address_isSet = false; m_data_address_isSet = false;
data_port = 0; data_port = 0;
@ -102,6 +106,7 @@ void
SWGRemoteSinkSettings::cleanup() { SWGRemoteSinkSettings::cleanup() {
if(data_address != nullptr) { if(data_address != nullptr) {
delete data_address; delete data_address;
} }
@ -140,6 +145,8 @@ SWGRemoteSinkSettings::fromJsonObject(QJsonObject &pJson) {
::SWGSDRangel::setValue(&nb_tx_bytes, pJson["nbTxBytes"], "qint32", ""); ::SWGSDRangel::setValue(&nb_tx_bytes, pJson["nbTxBytes"], "qint32", "");
::SWGSDRangel::setValue(&device_center_frequency, pJson["deviceCenterFrequency"], "qint32", "");
::SWGSDRangel::setValue(&data_address, pJson["dataAddress"], "QString", "QString"); ::SWGSDRangel::setValue(&data_address, pJson["dataAddress"], "QString", "QString");
::SWGSDRangel::setValue(&data_port, pJson["dataPort"], "qint32", ""); ::SWGSDRangel::setValue(&data_port, pJson["dataPort"], "qint32", "");
@ -188,6 +195,9 @@ SWGRemoteSinkSettings::asJsonObject() {
if(m_nb_tx_bytes_isSet){ if(m_nb_tx_bytes_isSet){
obj->insert("nbTxBytes", QJsonValue(nb_tx_bytes)); obj->insert("nbTxBytes", QJsonValue(nb_tx_bytes));
} }
if(m_device_center_frequency_isSet){
obj->insert("deviceCenterFrequency", QJsonValue(device_center_frequency));
}
if(data_address != nullptr && *data_address != QString("")){ if(data_address != nullptr && *data_address != QString("")){
toJsonValue(QString("dataAddress"), data_address, obj, QString("QString")); toJsonValue(QString("dataAddress"), data_address, obj, QString("QString"));
} }
@ -251,6 +261,16 @@ SWGRemoteSinkSettings::setNbTxBytes(qint32 nb_tx_bytes) {
this->m_nb_tx_bytes_isSet = true; this->m_nb_tx_bytes_isSet = true;
} }
qint32
SWGRemoteSinkSettings::getDeviceCenterFrequency() {
return device_center_frequency;
}
void
SWGRemoteSinkSettings::setDeviceCenterFrequency(qint32 device_center_frequency) {
this->device_center_frequency = device_center_frequency;
this->m_device_center_frequency_isSet = true;
}
QString* QString*
SWGRemoteSinkSettings::getDataAddress() { SWGRemoteSinkSettings::getDataAddress() {
return data_address; return data_address;
@ -392,6 +412,9 @@ SWGRemoteSinkSettings::isSet(){
if(m_nb_tx_bytes_isSet){ if(m_nb_tx_bytes_isSet){
isObjectUpdated = true; break; isObjectUpdated = true; break;
} }
if(m_device_center_frequency_isSet){
isObjectUpdated = true; break;
}
if(data_address && *data_address != QString("")){ if(data_address && *data_address != QString("")){
isObjectUpdated = true; break; isObjectUpdated = true; break;
} }

View File

@ -49,6 +49,9 @@ public:
qint32 getNbTxBytes(); qint32 getNbTxBytes();
void setNbTxBytes(qint32 nb_tx_bytes); void setNbTxBytes(qint32 nb_tx_bytes);
qint32 getDeviceCenterFrequency();
void setDeviceCenterFrequency(qint32 device_center_frequency);
QString* getDataAddress(); QString* getDataAddress();
void setDataAddress(QString* data_address); void setDataAddress(QString* data_address);
@ -98,6 +101,9 @@ private:
qint32 nb_tx_bytes; qint32 nb_tx_bytes;
bool m_nb_tx_bytes_isSet; bool m_nb_tx_bytes_isSet;
qint32 device_center_frequency;
bool m_device_center_frequency_isSet;
QString* data_address; QString* data_address;
bool m_data_address_isSet; bool m_data_address_isSet;