From 6ca54547bb1683edb19d2cadac20e78e47bc389e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20K=C3=A4berich?= Date: Thu, 20 Jun 2024 15:56:38 +0200 Subject: [PATCH] added streaming servers --- .../LibreVNA-GUI/LibreVNA-GUI.pro | 2 + .../SpectrumAnalyzer/spectrumanalyzer.cpp | 4 + .../PC_Application/LibreVNA-GUI/VNA/vna.cpp | 8 + .../PC_Application/LibreVNA-GUI/appwindow.cpp | 75 +++++- .../PC_Application/LibreVNA-GUI/appwindow.h | 21 ++ .../LibreVNA-GUI/preferences.cpp | 22 ++ .../PC_Application/LibreVNA-GUI/preferences.h | 32 +++ .../LibreVNA-GUI/preferencesdialog.ui | 216 +++++++++++++++++- .../LibreVNA-GUI/streamingserver.cpp | 60 +++++ .../LibreVNA-GUI/streamingserver.h | 27 +++ .../LibreVNA-Test/LibreVNA-Test.pro | 2 + 11 files changed, 457 insertions(+), 12 deletions(-) create mode 100644 Software/PC_Application/LibreVNA-GUI/streamingserver.cpp create mode 100644 Software/PC_Application/LibreVNA-GUI/streamingserver.h diff --git a/Software/PC_Application/LibreVNA-GUI/LibreVNA-GUI.pro b/Software/PC_Application/LibreVNA-GUI/LibreVNA-GUI.pro index e119bc7..138e61e 100644 --- a/Software/PC_Application/LibreVNA-GUI/LibreVNA-GUI.pro +++ b/Software/PC_Application/LibreVNA-GUI/LibreVNA-GUI.pro @@ -155,6 +155,7 @@ HEADERS += \ preferences.h \ savable.h \ scpi.h \ + streamingserver.h \ tcpserver.h \ touchstone.h \ unit.h @@ -301,6 +302,7 @@ SOURCES += \ preferences.cpp \ savable.cpp \ scpi.cpp \ + streamingserver.cpp \ tcpserver.cpp \ touchstone.cpp \ unit.cpp diff --git a/Software/PC_Application/LibreVNA-GUI/SpectrumAnalyzer/spectrumanalyzer.cpp b/Software/PC_Application/LibreVNA-GUI/SpectrumAnalyzer/spectrumanalyzer.cpp index b1e4d16..e45747b 100644 --- a/Software/PC_Application/LibreVNA-GUI/SpectrumAnalyzer/spectrumanalyzer.cpp +++ b/Software/PC_Application/LibreVNA-GUI/SpectrumAnalyzer/spectrumanalyzer.cpp @@ -530,6 +530,8 @@ void SpectrumAnalyzer::NewDatapoint(DeviceDriver::SAMeasurement m) } } + window->addStreamingData(m_avg, AppWindow::SADataType::Raw); + if(normalize.measuring) { if(average.currentSweep() == averages) { // this is the last averaging sweep, use values for normalization @@ -561,6 +563,8 @@ void SpectrumAnalyzer::NewDatapoint(DeviceDriver::SAMeasurement m) } } + window->addStreamingData(m_avg, AppWindow::SADataType::Normalized); + traceModel.addSAData(m_avg, settings); emit dataChanged(); if(m_avg.pointNum == DeviceDriver::SApoints() - 1) { diff --git a/Software/PC_Application/LibreVNA-GUI/VNA/vna.cpp b/Software/PC_Application/LibreVNA-GUI/VNA/vna.cpp index 5287245..e1a96d3 100644 --- a/Software/PC_Application/LibreVNA-GUI/VNA/vna.cpp +++ b/Software/PC_Application/LibreVNA-GUI/VNA/vna.cpp @@ -931,6 +931,9 @@ void VNA::NewDatapoint(DeviceDriver::VNAMeasurement m) } m_avg = average.process(m_avg); + + window->addStreamingData(m_avg, AppWindow::VNADataType::Raw); + if(average.settled()) { setOperationPending(false); } @@ -955,6 +958,8 @@ void VNA::NewDatapoint(DeviceDriver::VNAMeasurement m) cal.correctMeasurement(m_avg); + window->addStreamingData(m_avg, AppWindow::VNADataType::Calibrated); + TraceMath::DataType type; if(settings.zerospan) { type = TraceMath::DataType::TimeZeroSpan; @@ -983,6 +988,9 @@ void VNA::NewDatapoint(DeviceDriver::VNAMeasurement m) deembedding.Deembed(m_avg); traceModel.addVNAData(m_avg, type, true); } + + window->addStreamingData(m_avg, AppWindow::VNADataType::Deembedded); + emit dataChanged(); if(m_avg.pointNum == settings.npoints - 1) { UpdateAverageCount(); diff --git a/Software/PC_Application/LibreVNA-GUI/appwindow.cpp b/Software/PC_Application/LibreVNA-GUI/appwindow.cpp index 00c3d68..a8ca10e 100644 --- a/Software/PC_Application/LibreVNA-GUI/appwindow.cpp +++ b/Software/PC_Application/LibreVNA-GUI/appwindow.cpp @@ -70,6 +70,11 @@ AppWindow::AppWindow(QWidget *parent) , deviceActionGroup(new QActionGroup(this)) , ui(new Ui::MainWindow) , server(nullptr) + , streamVNARawData(nullptr) + , streamVNACalibratedData(nullptr) + , streamVNADeembeddedData(nullptr) + , streamSARawData(nullptr) + , streamSANormalizedData(nullptr) , appVersion(APP_VERSION) , appGitHash(APP_GIT_HASH) { @@ -97,6 +102,8 @@ AppWindow::AppWindow(QWidget *parent) Preferences::getInstance().load(); } + auto &p = Preferences::getInstance(); + device = nullptr; // vdevice = nullptr; modeHandler = nullptr; @@ -109,9 +116,25 @@ AppWindow::AppWindow(QWidget *parent) port = Preferences::getInstance().SCPIServer.port; } StartTCPServer(port); - Preferences::getInstance().manualTCPport(); - } else if(Preferences::getInstance().SCPIServer.enabled) { - StartTCPServer(Preferences::getInstance().SCPIServer.port); + p.manualTCPport(); + } else if(p.SCPIServer.enabled) { + StartTCPServer(p.SCPIServer.port); + } + + if(p.StreamingServers.VNARawData.enabled) { + streamVNARawData = new StreamingServer(p.StreamingServers.VNARawData.port); + } + if(p.StreamingServers.VNACalibratedData.enabled) { + streamVNACalibratedData = new StreamingServer(p.StreamingServers.VNACalibratedData.port); + } + if(p.StreamingServers.VNADeembeddedData.enabled) { + streamVNADeembeddedData = new StreamingServer(p.StreamingServers.VNADeembeddedData.port); + } + if(p.StreamingServers.SARawData.enabled) { + streamSARawData = new StreamingServer(p.StreamingServers.SARawData.port); + } + if(p.StreamingServers.SANormalizedData.enabled) { + streamSANormalizedData = new StreamingServer(p.StreamingServers.SANormalizedData.port); } ui->setupUi(this); @@ -1019,6 +1042,25 @@ void AppWindow::preferencesChanged() StopTCPServer(); StartTCPServer(p.SCPIServer.port); } + + auto updateStreamingServer = [](StreamingServer **server, bool enabled, int port) { + if(*server && !enabled) { + delete *server; + *server = nullptr; + } else if(!*server && enabled) { + *server = new StreamingServer(port); + } else if(*server && (*server)->getPort() != port) { + delete *server; + *server = new StreamingServer(port); + } + }; + + updateStreamingServer(&streamVNARawData, p.StreamingServers.VNARawData.enabled, p.StreamingServers.VNARawData.port); + updateStreamingServer(&streamVNACalibratedData, p.StreamingServers.VNACalibratedData.enabled, p.StreamingServers.VNACalibratedData.port); + updateStreamingServer(&streamVNADeembeddedData, p.StreamingServers.VNADeembeddedData.enabled, p.StreamingServers.VNADeembeddedData.port); + updateStreamingServer(&streamSARawData, p.StreamingServers.SARawData.enabled, p.StreamingServers.SARawData.port); + updateStreamingServer(&streamSANormalizedData, p.StreamingServers.SANormalizedData.enabled, p.StreamingServers.SANormalizedData.port); + // averaging mode may have changed, update for all relevant modes for (auto m : modeHandler->getModes()) { @@ -1055,6 +1097,33 @@ SCPI* AppWindow::getSCPI() return &scpi; } +void AppWindow::addStreamingData(const DeviceDriver::VNAMeasurement &m, VNADataType type) +{ + StreamingServer *server = nullptr; + switch(type) { + case VNADataType::Raw: server = streamVNARawData; break; + case VNADataType::Calibrated: server = streamVNACalibratedData; break; + case VNADataType::Deembedded: server = streamVNADeembeddedData; break; + } + + if(server) { + server->addData(m); + } +} + +void AppWindow::addStreamingData(const DeviceDriver::SAMeasurement &m, SADataType type) +{ + StreamingServer *server = nullptr; + switch(type) { + case SADataType::Raw: server = streamSARawData; break; + case SADataType::Normalized: server = streamSANormalizedData; break; + } + + if(server) { + server->addData(m); + } +} + void AppWindow::setModeStatus(QString msg) { lModeInfo.setText(msg); diff --git a/Software/PC_Application/LibreVNA-GUI/appwindow.h b/Software/PC_Application/LibreVNA-GUI/appwindow.h index 80d7dd4..54b542b 100644 --- a/Software/PC_Application/LibreVNA-GUI/appwindow.h +++ b/Software/PC_Application/LibreVNA-GUI/appwindow.h @@ -10,6 +10,7 @@ #include "preferences.h" #include "scpi.h" #include "tcpserver.h" +#include "streamingserver.h" #include "Device/devicedriver.h" #include @@ -52,6 +53,21 @@ public: SCPI* getSCPI(); + enum class VNADataType { + Raw = 0, + Calibrated = 1, + Deembedded = 2, + }; + + void addStreamingData(const DeviceDriver::VNAMeasurement &m, VNADataType type); + + enum class SADataType { + Raw = 0, + Normalized = 1, + }; + + void addStreamingData(const DeviceDriver::SAMeasurement &m, SADataType type); + public slots: void setModeStatus(QString msg); @@ -143,6 +159,11 @@ private: SCPI scpi; TCPServer *server; + StreamingServer *streamVNARawData; + StreamingServer *streamVNACalibratedData; + StreamingServer *streamVNADeembeddedData; + StreamingServer *streamSARawData; + StreamingServer *streamSANormalizedData; QString appVersion; QString appGitHash; diff --git a/Software/PC_Application/LibreVNA-GUI/preferences.cpp b/Software/PC_Application/LibreVNA-GUI/preferences.cpp index c15f079..8e671b6 100644 --- a/Software/PC_Application/LibreVNA-GUI/preferences.cpp +++ b/Software/PC_Application/LibreVNA-GUI/preferences.cpp @@ -320,6 +320,17 @@ void PreferencesDialog::setInitialGUIState() ui->SCPIServerEnabled->setChecked(p->SCPIServer.enabled); ui->SCPIServerPort->setValue(p->SCPIServer.port); + ui->streamingServerVNArawEnabled->setChecked(p->StreamingServers.VNARawData.enabled); + ui->streamingServerVNArawPort->setValue(p->StreamingServers.VNARawData.port); + ui->streamingServerVNAcalibratedEnabled->setChecked(p->StreamingServers.VNACalibratedData.enabled); + ui->streamingServerVNAcalibratedPort->setValue(p->StreamingServers.VNACalibratedData.port); + ui->streamingServerVNAdeembeddedEnabled->setChecked(p->StreamingServers.VNADeembeddedData.enabled); + ui->streamingServerVNAdeembeddedPort->setValue(p->StreamingServers.VNADeembeddedData.port); + ui->streamingServerSArawEnabled->setChecked(p->StreamingServers.SARawData.enabled); + ui->streamingServerSArawPort->setValue(p->StreamingServers.SARawData.port); + ui->streamingServerSAnormalizedEnabled->setChecked(p->StreamingServers.SANormalizedData.enabled); + ui->streamingServerSAnormalizedPort->setValue(p->StreamingServers.SANormalizedData.port); + ui->DebugMaxUSBlogSize->setValue(p->Debug.USBlogSizeLimit); ui->DebugSaveTraceData->setChecked(p->Debug.saveTraceData); @@ -420,6 +431,17 @@ void PreferencesDialog::updateFromGUI() p->SCPIServer.enabled = ui->SCPIServerEnabled->isChecked(); p->SCPIServer.port = ui->SCPIServerPort->value(); + p->StreamingServers.VNARawData.enabled = ui->streamingServerVNArawEnabled->isChecked(); + p->StreamingServers.VNARawData.port = ui->streamingServerVNArawPort->value(); + p->StreamingServers.VNACalibratedData.enabled = ui->streamingServerVNAcalibratedEnabled->isChecked(); + p->StreamingServers.VNACalibratedData.port = ui->streamingServerVNAcalibratedPort->value(); + p->StreamingServers.VNADeembeddedData.enabled = ui->streamingServerVNAdeembeddedEnabled->isChecked(); + p->StreamingServers.VNADeembeddedData.port = ui->streamingServerVNAdeembeddedPort->value(); + p->StreamingServers.SARawData.enabled = ui->streamingServerSArawEnabled->isChecked(); + p->StreamingServers.SARawData.port = ui->streamingServerSArawPort->value(); + p->StreamingServers.SANormalizedData.enabled = ui->streamingServerSAnormalizedEnabled->isChecked(); + p->StreamingServers.SANormalizedData.port = ui->streamingServerSAnormalizedPort->value(); + p->Debug.USBlogSizeLimit = ui->DebugMaxUSBlogSize->value(); p->Debug.saveTraceData = ui->DebugSaveTraceData->isChecked(); diff --git a/Software/PC_Application/LibreVNA-GUI/preferences.h b/Software/PC_Application/LibreVNA-GUI/preferences.h index 52fbe9c..38024ac 100644 --- a/Software/PC_Application/LibreVNA-GUI/preferences.h +++ b/Software/PC_Application/LibreVNA-GUI/preferences.h @@ -163,6 +163,28 @@ public: bool enabled; int port; } SCPIServer; + struct { + struct { + bool enabled; + int port; + } VNARawData; + struct { + bool enabled; + int port; + } VNACalibratedData; + struct { + bool enabled; + int port; + } VNADeembeddedData; + struct { + bool enabled; + int port; + } SARawData; + struct { + bool enabled; + int port; + } SANormalizedData; + } StreamingServers; struct { double USBlogSizeLimit; bool saveTraceData; @@ -273,6 +295,16 @@ private: {&Marker.symbolStyle, "Marker.symbolStyle", MarkerSymbolStyle::EmptyNumberAbove}, {&SCPIServer.enabled, "SCPIServer.enabled", true}, {&SCPIServer.port, "SCPIServer.port", 19542}, + {&StreamingServers.VNARawData.enabled, "StreamingServers.VNARawData.enabled", false}, + {&StreamingServers.VNARawData.port, "StreamingServers.VNARawData.port", 19000}, + {&StreamingServers.VNACalibratedData.enabled, "StreamingServers.VNACalibratedData.enabled", false}, + {&StreamingServers.VNACalibratedData.port, "StreamingServers.VNACalibratedData.port", 19001}, + {&StreamingServers.VNADeembeddedData.enabled, "StreamingServers.VNADeembeddedData.enabled", false}, + {&StreamingServers.VNADeembeddedData.port, "StreamingServers.VNADeembeddedData.port", 19002}, + {&StreamingServers.SARawData.enabled, "StreamingServers.sARawData.enabled", false}, + {&StreamingServers.SARawData.port, "StreamingServers.sARawData.port", 19100}, + {&StreamingServers.SANormalizedData.enabled, "StreamingServers.SANormalizedData.enabled", false}, + {&StreamingServers.SANormalizedData.port, "StreamingServers.SANormalizedData.port", 19101}, {&Debug.USBlogSizeLimit, "Debug.USBlogSizeLimit", 10000000.0}, {&Debug.saveTraceData, "Debug.saveTraceData", false}, }}; diff --git a/Software/PC_Application/LibreVNA-GUI/preferencesdialog.ui b/Software/PC_Application/LibreVNA-GUI/preferencesdialog.ui index fd3a7a8..f446262 100644 --- a/Software/PC_Application/LibreVNA-GUI/preferencesdialog.ui +++ b/Software/PC_Application/LibreVNA-GUI/preferencesdialog.ui @@ -68,6 +68,11 @@ SCPI Server + + + Streaming Servers + + Debug @@ -93,7 +98,7 @@ - 3 + 5 @@ -698,8 +703,8 @@ 0 0 - 697 - 563 + 565 + 477 @@ -939,8 +944,8 @@ 0 0 - 683 - 1058 + 553 + 1075 @@ -1779,8 +1784,8 @@ 0 0 - 168 - 127 + 697 + 563 @@ -1857,6 +1862,199 @@ + + + + + + + + + + VNA raw data: + + + + + + + Enabled + + + + + + + Port: + + + + + + + 1 + + + 65535 + + + + + + + VNA calibrated data: + + + + + + + Enabled + + + + + + + Port: + + + + + + + 1 + + + 65535 + + + + + + + VNA de-embedded data: + + + + + + + Enabled + + + + + + + Port: + + + + + + + 1 + + + 65535 + + + + + + + SA raw data: + + + + + + + Enabled + + + + + + + Port: + + + + + + + 1 + + + 65535 + + + + + + + SA normalized data: + + + + + + + Enabled + + + + + + + Port: + + + + + + + 1 + + + 65535 + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + Qt::Horizontal + + + + 316 + 20 + + + + + + @@ -1869,8 +2067,8 @@ 0 0 - 215 - 168 + 697 + 563 diff --git a/Software/PC_Application/LibreVNA-GUI/streamingserver.cpp b/Software/PC_Application/LibreVNA-GUI/streamingserver.cpp new file mode 100644 index 0000000..1e29caf --- /dev/null +++ b/Software/PC_Application/LibreVNA-GUI/streamingserver.cpp @@ -0,0 +1,60 @@ +#include "streamingserver.h" + +#include "json.hpp" + +StreamingServer::StreamingServer(int port) +{ + this->port = port; + server.listen(QHostAddress::Any, port); + connect(&server, &QTcpServer::newConnection, [&](){ + auto socket = server.nextPendingConnection(); + sockets.insert(socket); + + connect(socket, &QTcpSocket::stateChanged, [this, socket](QAbstractSocket::SocketState state){ + if (state == QAbstractSocket::UnconnectedState) + { + sockets.erase(socket); + socket->deleteLater(); + } + }); + }); +} + +void StreamingServer::addData(const DeviceDriver::VNAMeasurement &m) +{ + nlohmann::json j; + j["pointNum"] = m.pointNum; + j["frequency"] = m.frequency; + j["dBm"] = m.dBm; + j["Z0"] = m.Z0; + nlohmann::json jp; + for(auto const &p : m.measurements) { + jp[QString(p.first+"_real").toStdString()] = p.second.real(); + jp[QString(p.first+"_imag").toStdString()] = p.second.imag(); + } + j["measurements"] = jp; + std::string toSend = j.dump(); + for(auto s : sockets) { + if(s->isOpen()) { + s->write(QByteArray::fromStdString(toSend+'\n')); + } + } +} + +void StreamingServer::addData(const DeviceDriver::SAMeasurement &m) +{ + nlohmann::json j; + j["pointNum"] = m.pointNum; + j["frequency"] = m.frequency; + nlohmann::json jp; + for(auto const &p : m.measurements) { + jp[p.first.toStdString()] = p.second; + } + j["measurements"] = jp; + std::string toSend = j.dump(); + for(auto s : sockets) { + if(s->isOpen()) { + s->write(QByteArray::fromStdString(toSend+'\n')); + } + } +} diff --git a/Software/PC_Application/LibreVNA-GUI/streamingserver.h b/Software/PC_Application/LibreVNA-GUI/streamingserver.h new file mode 100644 index 0000000..7bcfcc3 --- /dev/null +++ b/Software/PC_Application/LibreVNA-GUI/streamingserver.h @@ -0,0 +1,27 @@ +#ifndef STREAMINGSERVER_H +#define STREAMINGSERVER_H + +#include +#include +#include + +#include "Device/devicedriver.h" + +class StreamingServer : public QObject +{ + Q_OBJECT +public: + StreamingServer(int port); + + void addData(const DeviceDriver::VNAMeasurement &m); + void addData(const DeviceDriver::SAMeasurement &m); + + int getPort() {return port;} + +private: + int port; + QTcpServer server; + std::set sockets; +}; + +#endif // STREAMINGSERVER_H diff --git a/Software/PC_Application/LibreVNA-Test/LibreVNA-Test.pro b/Software/PC_Application/LibreVNA-Test/LibreVNA-Test.pro index 08634f3..51c979a 100644 --- a/Software/PC_Application/LibreVNA-Test/LibreVNA-Test.pro +++ b/Software/PC_Application/LibreVNA-Test/LibreVNA-Test.pro @@ -147,6 +147,7 @@ SOURCES += \ ../LibreVNA-GUI/savable.cpp \ ../LibreVNA-GUI/scpi.cpp \ ../LibreVNA-GUI/tcpserver.cpp \ + ../LibreVNA-GUI/streamingserver.cpp \ ../LibreVNA-GUI/touchstone.cpp \ ../LibreVNA-GUI/unit.cpp \ main.cpp \ @@ -338,6 +339,7 @@ HEADERS += \ ../LibreVNA-GUI/savable.h \ ../LibreVNA-GUI/scpi.h \ ../LibreVNA-GUI/tcpserver.h \ + ../LibreVNA-GUI/streamingserver.h \ ../LibreVNA-GUI/touchstone.h \ ../LibreVNA-GUI/unit.h \ parametertests.h \