1
0
mirror of https://github.com/f4exb/sdrangel.git synced 2025-06-25 05:25:27 -04:00

Merge pull request #2472 from srcejon/fix_2470

Fix --remote-tcp.
This commit is contained in:
Edouard Griffiths 2025-06-23 18:18:05 +02:00 committed by GitHub
commit ca5898bc57
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 129 additions and 175 deletions

View File

@ -190,6 +190,8 @@ static int runQtApplication(int argc, char* argv[], qtwebapp::LoggerWithFile *lo
MainWindow w(logger, parser); MainWindow w(logger, parser);
w.show();
if (parser.getListDevices()) if (parser.getListDevices())
{ {
// List available physical devices and exit // List available physical devices and exit
@ -197,12 +199,6 @@ static int runQtApplication(int argc, char* argv[], qtwebapp::LoggerWithFile *lo
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }
if (parser.getRemoteTCPSink()) {
RemoteTCPSinkStarter::start(parser);
}
w.show();
return a.exec(); return a.exec();
} }

View File

@ -72,6 +72,8 @@ typedef SSIZE_T ssize_t;
#include "ldpctool/algorithms.h" #include "ldpctool/algorithms.h"
#include "ldpctool/ldpcworker.h" #include "ldpctool/ldpcworker.h"
#include <QDebug>
namespace leansdr namespace leansdr
{ {

View File

@ -2019,18 +2019,21 @@ bool ChannelWebAPIUtils::addChannel(unsigned int deviceSetIndex, const QString&
} }
// response will be deleted after device is opened. // response will be deleted after device is opened.
bool ChannelWebAPIUtils::addDevice(const QString hwType, int direction, const QStringList& settingsKeys, SWGSDRangel::SWGDeviceSettings *response) bool ChannelWebAPIUtils::addDevice(const QString hwType, int direction, const QStringList& settingsKeys, SWGSDRangel::SWGDeviceSettings *response, QObject *receiver, const char *slot)
{ {
return DeviceOpener::open(hwType, direction, settingsKeys, response); return DeviceOpener::open(hwType, direction, settingsKeys, response, receiver, slot);
} }
DeviceOpener::DeviceOpener(int deviceIndex, int direction, const QStringList& settingsKeys, SWGSDRangel::SWGDeviceSettings *response) : DeviceOpener::DeviceOpener(int deviceIndex, int direction, const QStringList& settingsKeys, SWGSDRangel::SWGDeviceSettings *response, QObject *receiver, const char *slot) :
m_deviceIndex(deviceIndex), m_deviceIndex(deviceIndex),
m_direction(direction), m_direction(direction),
m_settingsKeys(settingsKeys), m_settingsKeys(settingsKeys),
m_response(response), m_response(response),
m_device(nullptr) m_device(nullptr)
{ {
if (receiver) {
connect(this, SIGNAL(deviceOpened(int)), receiver, slot);
}
connect(MainCore::instance(), &MainCore::deviceSetAdded, this, &DeviceOpener::deviceSetAdded); connect(MainCore::instance(), &MainCore::deviceSetAdded, this, &DeviceOpener::deviceSetAdded);
// Create DeviceSet // Create DeviceSet
MainCore *mainCore = MainCore::instance(); MainCore *mainCore = MainCore::instance();
@ -2046,33 +2049,30 @@ void DeviceOpener::deviceSetAdded(int index, DeviceAPI *device)
disconnect(MainCore::instance(), &MainCore::deviceSetAdded, this, &DeviceOpener::deviceSetAdded); disconnect(MainCore::instance(), &MainCore::deviceSetAdded, this, &DeviceOpener::deviceSetAdded);
m_device = device; m_device = device;
connect(MainCore::instance(), &MainCore::deviceChanged, this, &DeviceOpener::deviceChanged);
// Set the correct device type // Set the correct device type
MainCore::MsgSetDevice *msg = MainCore::MsgSetDevice::create(m_deviceSetIndex, m_deviceIndex, m_direction); MainCore::MsgSetDevice *msg = MainCore::MsgSetDevice::create(m_deviceSetIndex, m_deviceIndex, m_direction);
MainCore::instance()->getMainMessageQueue()->push(msg); MainCore::instance()->getMainMessageQueue()->push(msg);
// Wait until device has initialised - FIXME: Better way to do this other than polling?
m_timer.setInterval(250);
connect(&m_timer, &QTimer::timeout, this, &DeviceOpener::checkInitialised);
m_timer.start();
} }
} }
void DeviceOpener::checkInitialised() void DeviceOpener::deviceChanged(int index)
{ {
if (m_device && m_device->getSampleSource() && (m_device->state() >= DeviceAPI::EngineState::StIdle)) // Apply device settings
{
m_timer.stop();
QString errorMessage; QString errorMessage;
if (200 != m_device->getSampleSource()->webapiSettingsPutPatch(false, m_settingsKeys, *m_response, errorMessage)) { if (200 != m_device->getSampleSource()->webapiSettingsPutPatch(false, m_settingsKeys, *m_response, errorMessage)) {
qDebug() << "DeviceOpener::checkInitialised: webapiSettingsPutPatch failed: " << errorMessage; qDebug() << "DeviceOpener::checkInitialised: webapiSettingsPutPatch failed: " << errorMessage;
} }
// Signal device has been opened
emit deviceOpened(m_deviceSetIndex);
delete m_response; delete m_response;
delete this; delete this;
} }
}
bool DeviceOpener::open(const QString hwType, int direction, const QStringList& settingsKeys, SWGSDRangel::SWGDeviceSettings *response) bool DeviceOpener::open(const QString hwType, int direction, const QStringList& settingsKeys, SWGSDRangel::SWGDeviceSettings *response, QObject *receiver, const char *slot)
{ {
if (direction) { if (direction) {
return false; // FIXME: Only RX support for now return false; // FIXME: Only RX support for now
@ -2090,7 +2090,7 @@ bool DeviceOpener::open(const QString hwType, int direction, const QStringList&
continue; continue;
} }
new DeviceOpener(i, direction, settingsKeys, response); new DeviceOpener(i, direction, settingsKeys, response, receiver, slot);
return true; return true;
} }

View File

@ -43,7 +43,7 @@ class DeviceAPI;
class DeviceOpener : public QObject { class DeviceOpener : public QObject {
Q_OBJECT Q_OBJECT
protected: protected:
DeviceOpener(int deviceIndex, int direction, const QStringList& settingsKeys, SWGSDRangel::SWGDeviceSettings *response); DeviceOpener(int deviceIndex, int direction, const QStringList& settingsKeys, SWGSDRangel::SWGDeviceSettings *response, QObject *receiver, const char *slot);
private: private:
int m_deviceIndex; int m_deviceIndex;
int m_direction; int m_direction;
@ -51,13 +51,17 @@ private:
QStringList m_settingsKeys; QStringList m_settingsKeys;
SWGSDRangel::SWGDeviceSettings *m_response; SWGSDRangel::SWGDeviceSettings *m_response;
DeviceAPI *m_device; DeviceAPI *m_device;
QTimer m_timer;
void createDeviceSet();
private slots: private slots:
void deviceSetAdded(int index, DeviceAPI *device); void deviceSetAdded(int index, DeviceAPI *device);
void checkInitialised(); void deviceChanged(int index);
public: public:
static bool open(const QString hwType, int direction, const QStringList& settingsKeys, SWGSDRangel::SWGDeviceSettings *response); bool open(const QString hwType, int direction, const QStringList& settingsKeys, SWGSDRangel::SWGDeviceSettings *response);
static bool open(const QString hwType, int direction, const QStringList& settingsKeys, SWGSDRangel::SWGDeviceSettings *response, QObject *receiver, const char *slot);
signals:
void deviceOpened(int deviceSetIndex);
}; };
class SDRBASE_API ChannelWebAPIUtils class SDRBASE_API ChannelWebAPIUtils
@ -127,7 +131,7 @@ public:
static bool getChannelSettings(ChannelAPI *channel, SWGSDRangel::SWGChannelSettings &channelSettingsResponse); static bool getChannelSettings(ChannelAPI *channel, SWGSDRangel::SWGChannelSettings &channelSettingsResponse);
static bool getChannelReport(unsigned int deviceIndex, unsigned int channelIndex, SWGSDRangel::SWGChannelReport &channelReport); static bool getChannelReport(unsigned int deviceIndex, unsigned int channelIndex, SWGSDRangel::SWGChannelReport &channelReport);
static bool addChannel(unsigned int deviceSetIndex, const QString& uri, int direction); static bool addChannel(unsigned int deviceSetIndex, const QString& uri, int direction);
static bool addDevice(const QString hwType, int direction, const QStringList& settingsKeys, SWGSDRangel::SWGDeviceSettings *response); static bool addDevice(const QString hwType, int direction, const QStringList& settingsKeys, SWGSDRangel::SWGDeviceSettings *response, QObject *receiver = nullptr, const char *slot = nullptr);
protected: protected:
static QString getDeviceHardwareId(unsigned int deviceIndex); static QString getDeviceHardwareId(unsigned int deviceIndex);
}; };

View File

@ -27,9 +27,11 @@
#include "device/deviceenumerator.h" #include "device/deviceenumerator.h"
#include "dsp/devicesamplesource.h" #include "dsp/devicesamplesource.h"
#include "channel/channelapi.h" #include "channel/channelapi.h"
#include "channel/channelwebapiutils.h"
#include "SWGChannelSettings.h" #include "SWGChannelSettings.h"
#include "SWGRemoteTCPSinkSettings.h" #include "SWGRemoteTCPSinkSettings.h"
#include "SWGDeviceState.h" #include "SWGDeviceState.h"
#include "SWGDeviceSettings.h"
// Lists available physical devices to stdout // Lists available physical devices to stdout
void RemoteTCPSinkStarter::listAvailableDevices() void RemoteTCPSinkStarter::listAvailableDevices()
@ -53,133 +55,46 @@ void RemoteTCPSinkStarter::listAvailableDevices()
} }
} }
// Instantiate specified sampling source device and create a RemoteTCPSink channel RemoteTCPSinkStarter::RemoteTCPSinkStarter(const QString& address, int port, const QString& hwType, const QString& serial) :
// on the specified address and port and start the device m_dataAddress(address),
static void startRemoteTCPSink(const QString& address, int port, const QString& hwType, const QString& serial) m_dataPort(port),
m_deviceSet(nullptr)
{ {
MainCore *mainCore = MainCore::instance(); // Add device of requested type
SWGSDRangel::SWGDeviceSettings *response = new SWGSDRangel::SWGDeviceSettings();
response->init();
ChannelWebAPIUtils::addDevice(hwType, 0, QStringList(), response, this, SLOT(deviceOpened(int)));
}
// Delete any existing device sets, in case requested device is already in use void RemoteTCPSinkStarter::deviceOpened(int deviceSetIndex)
int initialDeviceSets = mainCore->getDeviceSets().size();
for (int i = 0; i < initialDeviceSets; i++)
{ {
MainCore::MsgRemoveLastDeviceSet *msg = MainCore::MsgRemoveLastDeviceSet::create(); m_deviceSet = MainCore::instance()->getDeviceSets()[deviceSetIndex];
mainCore->getMainMessageQueue()->push(msg);
}
// Wait until they've been deleted
if (initialDeviceSets > 0)
{
do
{
QTime dieTime = QTime::currentTime().addMSecs(100);
while (QTime::currentTime() < dieTime) {
QCoreApplication::processEvents(QEventLoop::AllEvents, 100);
}
}
while (mainCore->getDeviceSets().size() > 0);
}
// Create DeviceSet
unsigned int deviceSetIndex = mainCore->getDeviceSets().size();
MainCore::MsgAddDeviceSet *msg = MainCore::MsgAddDeviceSet::create(0);
mainCore->getMainMessageQueue()->push(msg);
// Switch to requested device type
int nbSamplingDevices = DeviceEnumerator::instance()->getNbRxSamplingDevices();
bool found = false;
for (int i = 0; i < nbSamplingDevices; i++)
{
const PluginInterface::SamplingDevice *samplingDevice;
samplingDevice = DeviceEnumerator::instance()->getRxSamplingDevice(i);
if (!hwType.isEmpty() && (hwType != samplingDevice->hardwareId)) {
continue;
}
if (!serial.isEmpty() && (serial != samplingDevice->serial)) {
continue;
}
int direction = 0;
MainCore::MsgSetDevice *msg = MainCore::MsgSetDevice::create(deviceSetIndex, i, direction);
mainCore->getMainMessageQueue()->push(msg);
found = true;
break;
}
if (!found)
{
qCritical() << "startRemoteTCPSink: Failed to find device";
return;
}
// Add RemoteTCPSink channel // Add RemoteTCPSink channel
PluginAPI::ChannelRegistrations *channelRegistrations = mainCore->getPluginManager()->getRxChannelRegistrations(); connect(MainCore::instance(), &MainCore::channelAdded, this, &RemoteTCPSinkStarter::channelAdded);
int nbRegistrations = channelRegistrations->size(); ChannelWebAPIUtils::addChannel(deviceSetIndex, "sdrangel.channel.remotetcpsink", 0);
int index = 0; }
for (; index < nbRegistrations; index++)
void RemoteTCPSinkStarter::channelAdded(int deviceSetIndex, ChannelAPI *channel)
{ {
if (channelRegistrations->at(index).m_channelId == "RemoteTCPSink") { (void) deviceSetIndex;
break;
} // Set RemoteTCPSink settings
ChannelWebAPIUtils::patchChannelSetting(channel, "dataAddress", m_dataAddress);
ChannelWebAPIUtils::patchChannelSetting(channel, "dataPort", m_dataPort);
// Wait for settings to be applied, then start the device
QTimer::singleShot(250, [=] {
startDevice();
});
} }
if (index < nbRegistrations) void RemoteTCPSinkStarter::startDevice()
{ {
MainCore::MsgAddChannel *msg = MainCore::MsgAddChannel::create(deviceSetIndex, index, 0); // Start the device
mainCore->getMainMessageQueue()->push(msg); ChannelWebAPIUtils::run(m_deviceSet->getIndex());
}
else
{
qCritical() << "startRemoteTCPSink: RemoteTCPSink is not available";
return;
}
int channelIndex = 0;
// Wait until device & channel are created - is there a better way? // Delete object as we have finished
DeviceSet *deviceSet = nullptr; delete this;
ChannelAPI *channelAPI = nullptr;
do
{
QTime dieTime = QTime::currentTime().addMSecs(100);
while (QTime::currentTime() < dieTime) {
QCoreApplication::processEvents(QEventLoop::AllEvents, 100);
}
if (mainCore->getDeviceSets().size() > deviceSetIndex)
{
deviceSet = mainCore->getDeviceSets()[deviceSetIndex];
if (deviceSet) {
channelAPI = deviceSet->m_deviceAPI->getChanelSinkAPIAt(channelIndex);
}
}
}
while (channelAPI == nullptr);
// Set TCP settings
QStringList channelSettingsKeys = {"dataAddress", "dataPort"};
SWGSDRangel::SWGChannelSettings response;
response.init();
SWGSDRangel::SWGRemoteTCPSinkSettings *sinkSettings = response.getRemoteTcpSinkSettings();
sinkSettings->setDataAddress(new QString(address));
sinkSettings->setDataPort(port);
QString errorMessage;
channelAPI->webapiSettingsPutPatch(false, channelSettingsKeys, response, errorMessage);
// Wait some time for settings to be applied
QCoreApplication::processEvents(QEventLoop::AllEvents, 100);
// Start the device (use WebAPI so GUI is updated)
DeviceSampleSource *source = deviceSet->m_deviceAPI->getSampleSource();
QStringList deviceActionsKeys;
SWGSDRangel::SWGDeviceState state;
state.init();
int res = source->webapiRun(true, state, errorMessage);
if (res != 200) {
qCritical() << "startRemoteTCPSink: Failed to start device: " << res;
} else {
qInfo().nospace().noquote() << "Remote TCP Sink started on " << address << ":" << port;
}
} }
// Start Remote TCP Sink on specified device, with specified address and port // Start Remote TCP Sink on specified device, with specified address and port
@ -191,8 +106,7 @@ void RemoteTCPSinkStarter::start(const MainParser& parser)
QString remoteTCPSinkSerial = parser.getRemoteTCPSinkSerial(); QString remoteTCPSinkSerial = parser.getRemoteTCPSinkSerial();
QTimer::singleShot(250, [=] { QTimer::singleShot(250, [=] {
startRemoteTCPSink( new RemoteTCPSinkStarter(remoteTCPSinkAddress,
remoteTCPSinkAddress,
remoteTCPSinkPort, remoteTCPSinkPort,
remoteTCPSinkHWType, remoteTCPSinkHWType,
remoteTCPSinkSerial); remoteTCPSinkSerial);

View File

@ -24,12 +24,34 @@
#include "mainparser.h" #include "mainparser.h"
#include "export.h" #include "export.h"
class SDRBASE_API RemoteTCPSinkStarter { #include <QObject>
class DeviceSet;
class DeviceAPI;
class ChannelAPI;
class SDRBASE_API RemoteTCPSinkStarter : public QObject {
Q_OBJECT
QString m_dataAddress;
int m_dataPort;
DeviceSet *m_deviceSet;
public: public:
static void listAvailableDevices(); static void listAvailableDevices();
static void start(const MainParser& parser); static void start(const MainParser& parser);
private:
RemoteTCPSinkStarter(const QString& address, int port, const QString& hwType, const QString& serial);
void startDevice();
private slots:
void deviceOpened(int deviceSetIndex);
void channelAdded(int deviceSetIndex, ChannelAPI *channel);
}; };
#endif /* REMOTETCPSINKSTARTER_H */ #endif /* REMOTETCPSINKSTARTER_H */

View File

@ -105,6 +105,7 @@
#include "util/android.h" #include "util/android.h"
#endif #endif
#include "remotetcpsinkstarter.h"
#include "mainwindow.h" #include "mainwindow.h"
#include <audio/audiodevicemanager.h> #include <audio/audiodevicemanager.h>
@ -136,7 +137,8 @@ MainWindow::MainWindow(qtwebapp::LoggerWithFile *logger, const MainParser& parse
#if QT_CONFIG(process) #if QT_CONFIG(process)
m_fftWisdomProcess(nullptr), m_fftWisdomProcess(nullptr),
#endif #endif
m_settingsSaved(false) m_settingsSaved(false),
m_parser(parser)
{ {
QAccessible::installFactory(AccessibleValueDial::factory); QAccessible::installFactory(AccessibleValueDial::factory);
QAccessible::installFactory(AccessibleValueDialZ::factory); QAccessible::installFactory(AccessibleValueDialZ::factory);
@ -273,10 +275,12 @@ MainWindow::MainWindow(qtwebapp::LoggerWithFile *logger, const MainParser& parse
restoreState(qUncompress(QByteArray::fromBase64(s.value("mainWindowState").toByteArray()))); restoreState(qUncompress(QByteArray::fromBase64(s.value("mainWindowState").toByteArray())));
// Load initial configuration // Load initial configuration
InitFSM *fsm = new InitFSM(this, splash, !parser.getScratch()); InitFSM *fsm = new InitFSM(this, splash, !parser.getScratch() && !parser.getRemoteTCPSink(), !parser.getRemoteTCPSink());
connect(fsm, &InitFSM::finished, fsm, &InitFSM::deleteLater); connect(fsm, &InitFSM::finished, fsm, &InitFSM::deleteLater);
connect(fsm, &InitFSM::finished, splash, &SDRangelSplash::deleteLater); connect(fsm, &InitFSM::finished, splash, &SDRangelSplash::deleteLater);
if (parser.getStart()) { if (parser.getRemoteTCPSink()) {
connect(fsm, &InitFSM::finished, this, &MainWindow::startRemoteTCPSink);
} else if (parser.getStart()) {
connect(fsm, &InitFSM::finished, this, &MainWindow::startAllAfterDelay); connect(fsm, &InitFSM::finished, this, &MainWindow::startAllAfterDelay);
} }
fsm->start(); fsm->start();
@ -1183,9 +1187,10 @@ void LoadConfigurationFSM::restoreGeometry()
} }
} }
InitFSM::InitFSM(MainWindow *mainWindow, SDRangelSplash *splash, bool loadDefault, QObject *parent) : InitFSM::InitFSM(MainWindow *mainWindow, SDRangelSplash *splash, bool loadDefault, bool showConfigs, QObject *parent) :
MainWindowFSM(mainWindow, parent), MainWindowFSM(mainWindow, parent),
m_splash(splash) m_splash(splash),
m_showConfigs(showConfigs)
{ {
// Create FSM // Create FSM
createStates(2); createStates(2);
@ -1222,6 +1227,8 @@ void InitFSM::showDefaultConfigurations()
qDebug() << "MainWindow::MainWindow: no or empty current configuration, creating empty workspace..."; qDebug() << "MainWindow::MainWindow: no or empty current configuration, creating empty workspace...";
m_mainWindow->addWorkspace(); m_mainWindow->addWorkspace();
if (m_showConfigs)
{
// If no configurations, load some basic examples // If no configurations, load some basic examples
if (m_mainWindow->m_mainCore->getMutableSettings().getConfigurations()->size() == 0) { if (m_mainWindow->m_mainCore->getMutableSettings().getConfigurations()->size() == 0) {
m_mainWindow->loadDefaultConfigurations(); m_mainWindow->loadDefaultConfigurations();
@ -1234,6 +1241,7 @@ void InitFSM::showDefaultConfigurations()
m_mainWindow->openConfigurationDialog(true); m_mainWindow->openConfigurationDialog(true);
} }
} }
}
CloseFSM::CloseFSM(MainWindow *mainWindow, QObject *parent) : CloseFSM::CloseFSM(MainWindow *mainWindow, QObject *parent) :
MainWindowFSM(mainWindow, parent) MainWindowFSM(mainWindow, parent)
@ -3391,6 +3399,11 @@ void MainWindow::showAllChannels(int deviceSetIndex)
} }
} }
void MainWindow::startRemoteTCPSink()
{
RemoteTCPSinkStarter::start(m_parser);
}
void MainWindow::startAllAfterDelay() void MainWindow::startAllAfterDelay()
{ {
// Wait a little bit before starting all devices and features, // Wait a little bit before starting all devices and features,

View File

@ -258,10 +258,11 @@ class InitFSM : public MainWindowFSM {
Q_OBJECT Q_OBJECT
public: public:
InitFSM(MainWindow *mainWindow, SDRangelSplash *splash, bool loadDefault, QObject *parent=nullptr); InitFSM(MainWindow *mainWindow, SDRangelSplash *splash, bool loadDefault, bool showConfigs, QObject *parent=nullptr);
private: private:
SDRangelSplash *m_splash; SDRangelSplash *m_splash;
bool m_showConfigs;
LoadConfigurationFSM *m_loadConfigurationFSM; LoadConfigurationFSM *m_loadConfigurationFSM;
void loadDefaultConfiguration(); void loadDefaultConfiguration();
@ -345,6 +346,7 @@ private:
#endif #endif
bool m_settingsSaved; // Records if settings have already been saved in response to a QCloseEvent bool m_settingsSaved; // Records if settings have already been saved in response to a QCloseEvent
const MainParser& m_parser;
void loadSettings(); void loadSettings();
void loadDeviceSetPresetSettings(const Preset* preset, int deviceSetIndex); void loadDeviceSetPresetSettings(const Preset* preset, int deviceSetIndex);
@ -458,6 +460,7 @@ private slots:
void featureMove(FeatureGUI *gui, int wsIndexDestnation); void featureMove(FeatureGUI *gui, int wsIndexDestnation);
void deviceStateChanged(DeviceAPI *deviceAPI); void deviceStateChanged(DeviceAPI *deviceAPI);
void openFeaturePresetsDialog(QPoint p, Workspace *workspace); void openFeaturePresetsDialog(QPoint p, Workspace *workspace);
void startRemoteTCPSink();
void startAllAfterDelay(); void startAllAfterDelay();
void startAll(); void startAll();
void startAllDevices(const Workspace *workspace) const; void startAllDevices(const Workspace *workspace) const;