1392 lines
52 KiB
C++
1392 lines
52 KiB
C++
#include "appwindow.h"
|
|
|
|
#include "unit.h"
|
|
#include "CustomWidgets/toggleswitch.h"
|
|
#include "Traces/tracemodel.h"
|
|
#include "Traces/tracewidget.h"
|
|
#include "Traces/tracesmithchart.h"
|
|
#include "Traces/tracexyplot.h"
|
|
#include "Traces/traceimportdialog.h"
|
|
#include "CustomWidgets/tilewidget.h"
|
|
#include "CustomWidgets/siunitedit.h"
|
|
#include "Traces/Marker/markerwidget.h"
|
|
#include "Tools/impedancematchdialog.h"
|
|
#include "ui_main.h"
|
|
#include "preferences.h"
|
|
#include "Generator/signalgenwidget.h"
|
|
#include "VNA/vna.h"
|
|
#include "Generator/generator.h"
|
|
#include "SpectrumAnalyzer/spectrumanalyzer.h"
|
|
#include "CustomWidgets/informationbox.h"
|
|
#include "Util/app_common.h"
|
|
#include "about.h"
|
|
#include "mode.h"
|
|
#include "modehandler.h"
|
|
#include "modewindow.h"
|
|
#include "Device/LibreVNA/librevnausbdriver.h"
|
|
#include "Device/LibreVNA/librevnatcpdriver.h"
|
|
|
|
#include <QDockWidget>
|
|
#include <QApplication>
|
|
#include <QActionGroup>
|
|
#include <QDebug>
|
|
#include <QGridLayout>
|
|
#include <QVBoxLayout>
|
|
#include <QHBoxLayout>
|
|
#include <QPushButton>
|
|
#include <math.h>
|
|
#include <QToolBar>
|
|
#include <QMenu>
|
|
#include <QToolButton>
|
|
#include <QActionGroup>
|
|
#include <QSpinBox>
|
|
#include <QCheckBox>
|
|
#include <QComboBox>
|
|
#include <QSettings>
|
|
#include <algorithm>
|
|
#include <QMessageBox>
|
|
#include <QFileDialog>
|
|
#include <QFile>
|
|
#include <iostream>
|
|
#include <fstream>
|
|
#include <iomanip>
|
|
#include <QDateTime>
|
|
#include <QCommandLineParser>
|
|
#include <QScrollArea>
|
|
#include <QStringList>
|
|
|
|
using namespace std;
|
|
|
|
|
|
static const QString APP_VERSION = QString::number(FW_MAJOR) + "." +
|
|
QString::number(FW_MINOR) + "." +
|
|
QString::number(FW_PATCH) + QString(FW_SUFFIX);
|
|
static const QString APP_GIT_HASH = QString(GITHASH);
|
|
|
|
static bool noGUIset = false;
|
|
|
|
AppWindow::AppWindow(QWidget *parent)
|
|
: QMainWindow(parent)
|
|
, deviceActionGroup(new QActionGroup(this))
|
|
, ui(new Ui::MainWindow)
|
|
, server(nullptr)
|
|
, appVersion(APP_VERSION)
|
|
, appGitHash(APP_GIT_HASH)
|
|
{
|
|
|
|
// qDebug().setVerbosity(0);
|
|
qDebug() << "Application start";
|
|
|
|
this->setWindowIcon(QIcon(":/app/logo.png"));
|
|
|
|
parser.setApplicationDescription(qlibrevnaApp->applicationName());
|
|
parser.addHelpOption();
|
|
parser.addVersionOption();
|
|
parser.addOption(QCommandLineOption({"p","port"}, "Specify port to listen for SCPI commands", "port"));
|
|
parser.addOption(QCommandLineOption({"d","device"}, "Only allow connections to the specified device", "device"));
|
|
parser.addOption(QCommandLineOption("no-gui", "Disables the graphical interface"));
|
|
parser.addOption(QCommandLineOption("cal", "Calibration file to load on startup", "cal"));
|
|
parser.addOption(QCommandLineOption("setup", "Setup file to load on startup", "setup"));
|
|
parser.addOption(QCommandLineOption("reset-preferences", "Resets all preferences to their default values"));
|
|
|
|
parser.process(QCoreApplication::arguments());
|
|
|
|
if(parser.isSet("reset-preferences")) {
|
|
Preferences::getInstance().setDefault();
|
|
} else {
|
|
Preferences::getInstance().load();
|
|
}
|
|
|
|
device = nullptr;
|
|
// vdevice = nullptr;
|
|
modeHandler = nullptr;
|
|
|
|
if(parser.isSet("port")) {
|
|
bool OK;
|
|
auto port = parser.value("port").toUInt(&OK);
|
|
if(!OK) {
|
|
// set default port
|
|
port = Preferences::getInstance().SCPIServer.port;
|
|
}
|
|
StartTCPServer(port);
|
|
Preferences::getInstance().manualTCPport();
|
|
} else if(Preferences::getInstance().SCPIServer.enabled) {
|
|
StartTCPServer(Preferences::getInstance().SCPIServer.port);
|
|
}
|
|
|
|
ui->setupUi(this);
|
|
|
|
SetupStatusBar();
|
|
UpdateStatusBar(DeviceStatusBar::Disconnected);
|
|
|
|
CreateToolbars();
|
|
|
|
auto logDock = new QDockWidget("Device Log");
|
|
logDock->setWidget(&deviceLog);
|
|
logDock->setObjectName("Log Dock");
|
|
addDockWidget(Qt::BottomDockWidgetArea, logDock);
|
|
|
|
// fill toolbar/dock menu
|
|
ui->menuDocks->clear();
|
|
for(auto d : findChildren<QDockWidget*>()) {
|
|
ui->menuDocks->addAction(d->toggleViewAction());
|
|
}
|
|
ui->menuToolbars->clear();
|
|
for(auto t : findChildren<QToolBar*>()) {
|
|
ui->menuToolbars->addAction(t->toggleViewAction());
|
|
}
|
|
|
|
modeHandler = new ModeHandler(this);
|
|
auto modeWindow = new ModeWindow(modeHandler, this);
|
|
ui->menubar->insertMenu(ui->menuHelp->menuAction(), modeWindow->getMenu());
|
|
|
|
central = new QStackedWidget;
|
|
setCentralWidget(central);
|
|
|
|
auto vnaIndex = modeHandler->createMode("Vector Network Analyzer", Mode::Type::VNA);
|
|
modeHandler->createMode("Signal Generator", Mode::Type::SG);
|
|
modeHandler->createMode("Spectrum Analyzer", Mode::Type::SA);
|
|
modeHandler->setCurrentIndex(vnaIndex);
|
|
|
|
auto setModeStatusbar = [=](const QString &msg) {
|
|
lModeInfo.setText(msg);
|
|
};
|
|
|
|
connect(modeHandler, &ModeHandler::StatusBarMessageChanged, setModeStatusbar);
|
|
|
|
SetupMenu();
|
|
|
|
setWindowTitle(qlibrevnaApp->applicationName() + " v" + getAppVersion());
|
|
|
|
setCorner(Qt::TopLeftCorner, Qt::LeftDockWidgetArea);
|
|
setCorner(Qt::BottomLeftCorner, Qt::LeftDockWidgetArea);
|
|
setCorner(Qt::TopRightCorner, Qt::RightDockWidgetArea);
|
|
setCorner(Qt::BottomRightCorner, Qt::RightDockWidgetArea);
|
|
|
|
{
|
|
QSettings settings;
|
|
restoreGeometry(settings.value("geometry").toByteArray());
|
|
}
|
|
|
|
SetupSCPI();
|
|
|
|
auto& pref = Preferences::getInstance();
|
|
if(pref.Startup.UseSetupFile) {
|
|
LoadSetup(pref.Startup.SetupFile);
|
|
}
|
|
// List available devices
|
|
UpdateDeviceList();
|
|
if(pref.Startup.ConnectToFirstDevice && deviceList.size() > 0) {
|
|
// at least one device available
|
|
ConnectToDevice(deviceList[0].serial);
|
|
}
|
|
|
|
if(parser.isSet("setup")) {
|
|
LoadSetup(parser.value("setup"));
|
|
}
|
|
if(parser.isSet("cal")) {
|
|
VNA* mode = static_cast<VNA*>(modeHandler->findFirstOfType(Mode::Type::VNA));
|
|
mode->LoadCalibration(parser.value("cal"));
|
|
}
|
|
if(!parser.isSet("no-gui")) {
|
|
InformationBox::setGUI(true);
|
|
resize(1280, 800);
|
|
show();
|
|
} else {
|
|
InformationBox::setGUI(false);
|
|
noGUIset = true;
|
|
}
|
|
}
|
|
|
|
AppWindow::~AppWindow()
|
|
{
|
|
StopTCPServer();
|
|
delete ui;
|
|
}
|
|
|
|
void AppWindow::SetupMenu()
|
|
{
|
|
// UI connections
|
|
connect(ui->actionUpdate_Device_List, &QAction::triggered, this, &AppWindow::UpdateDeviceList);
|
|
connect(ui->actionDisconnect, &QAction::triggered, this, &AppWindow::DisconnectDevice);
|
|
connect(ui->actionQuit, &QAction::triggered, this, &AppWindow::close);
|
|
connect(ui->actionSave_setup, &QAction::triggered, [=](){
|
|
auto filename = QFileDialog::getSaveFileName(nullptr, "Save setup data", "", "Setup files (*.setup)", nullptr, QFileDialog::DontUseNativeDialog);
|
|
if(filename.isEmpty()) {
|
|
// aborted selection
|
|
return;
|
|
}
|
|
SaveSetup(filename);
|
|
});
|
|
connect(ui->actionLoad_setup, &QAction::triggered, [=](){
|
|
auto filename = QFileDialog::getOpenFileName(nullptr, "Load setup data", "", "Setup files (*.setup)", nullptr, QFileDialog::DontUseNativeDialog);
|
|
if(filename.isEmpty()) {
|
|
// aborted selection
|
|
return;
|
|
}
|
|
LoadSetup(filename);
|
|
});
|
|
connect(ui->actionSave_image, &QAction::triggered, [=](){
|
|
modeHandler->getActiveMode()->saveSreenshot();
|
|
});
|
|
|
|
connect(ui->actionPreset, &QAction::triggered, [=](){
|
|
modeHandler->getActiveMode()->preset();
|
|
});
|
|
|
|
connect(ui->actionPreferences, &QAction::triggered, [=](){
|
|
// save previous SCPI settings in case they change
|
|
auto &p = Preferences::getInstance();
|
|
auto SCPIenabled = p.SCPIServer.enabled;
|
|
auto SCPIport = p.SCPIServer.port;
|
|
p.edit();
|
|
// store the updated settings
|
|
p.store();
|
|
if(SCPIenabled != p.SCPIServer.enabled || SCPIport != p.SCPIServer.port) {
|
|
StopTCPServer();
|
|
if(p.SCPIServer.enabled) {
|
|
StartTCPServer(p.SCPIServer.port);
|
|
}
|
|
}
|
|
// averaging mode may have changed, update for all relevant modes
|
|
for (auto m : modeHandler->getModes())
|
|
{
|
|
switch (m->getType())
|
|
{
|
|
case Mode::Type::VNA:
|
|
case Mode::Type::SA:
|
|
if(p.Acquisition.useMedianAveraging) {
|
|
m->setAveragingMode(Averaging::Mode::Median);
|
|
}
|
|
else {
|
|
m->setAveragingMode(Averaging::Mode::Mean);
|
|
}
|
|
break;
|
|
case Mode::Type::SG:
|
|
case Mode::Type::Last:
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
// acquisition frequencies may have changed, update
|
|
// UpdateAcquisitionFrequencies();
|
|
|
|
auto active = modeHandler->getActiveMode();
|
|
if (active)
|
|
{
|
|
active->updateGraphColors();
|
|
if(device) {
|
|
active->initializeDevice();
|
|
}
|
|
}
|
|
|
|
});
|
|
|
|
connect(ui->actionAbout, &QAction::triggered, [=](){
|
|
auto &a = About::getInstance();
|
|
a.about();
|
|
});
|
|
}
|
|
|
|
void AppWindow::closeEvent(QCloseEvent *event)
|
|
{
|
|
auto& pref = Preferences::getInstance();
|
|
if(pref.Startup.UseSetupFile && pref.Startup.AutosaveSetupFile) {
|
|
SaveSetup(pref.Startup.SetupFile);
|
|
}
|
|
modeHandler->shutdown();
|
|
QSettings settings;
|
|
settings.setValue("geometry", saveGeometry());
|
|
// deactivate currently used mode (stores mode state in settings)
|
|
if(modeHandler->getActiveMode()) {
|
|
modeHandler->deactivate(modeHandler->getActiveMode());
|
|
}
|
|
if(device) {
|
|
device->disconnectDevice();
|
|
device = nullptr;
|
|
}
|
|
delete modeHandler;
|
|
modeHandler = nullptr;
|
|
pref.store();
|
|
for(auto driver : DeviceDriver::getDrivers()) {
|
|
delete driver;
|
|
}
|
|
QMainWindow::closeEvent(event);
|
|
}
|
|
|
|
bool AppWindow::ConnectToDevice(QString serial, DeviceDriver *driver)
|
|
{
|
|
if(serial.isEmpty()) {
|
|
qDebug() << "Trying to connect to any device";
|
|
} else {
|
|
qDebug() << "Trying to connect to" << serial;
|
|
}
|
|
if(device) {
|
|
qDebug() << "Already connected to a device, disconnecting first...";
|
|
DisconnectDevice();
|
|
}
|
|
try {
|
|
qDebug() << "Attempting to connect to device...";
|
|
for(auto d : DeviceDriver::getDrivers()) {
|
|
if(driver && driver != d) {
|
|
// not the specified driver
|
|
continue;
|
|
}
|
|
if(d->GetAvailableDevices().count(serial)) {
|
|
// this driver can connect to the device
|
|
connect(d, &DeviceDriver::InfoUpdated, this, &AppWindow::DeviceInfoUpdated, Qt::QueuedConnection);
|
|
connect(d, &DeviceDriver::LogLineReceived, &deviceLog, &DeviceLog::addLine);
|
|
connect(d, &DeviceDriver::ConnectionLost, this, &AppWindow::DeviceConnectionLost);
|
|
connect(d, &DeviceDriver::StatusUpdated, this, &AppWindow::DeviceStatusUpdated);
|
|
connect(d, &DeviceDriver::FlagsUpdated, this, &AppWindow::DeviceFlagsUpdated);
|
|
connect(d, &DeviceDriver::releaseControl, this, [=](){
|
|
if(lastActiveMode) {
|
|
modeHandler->activate(lastActiveMode);
|
|
}
|
|
});
|
|
connect(d, &DeviceDriver::acquireControl, this, [=](){
|
|
lastActiveMode = modeHandler->getActiveMode();
|
|
modeHandler->deactivate(lastActiveMode);
|
|
});
|
|
|
|
if(d->connectDevice(serial)) {
|
|
device = d;
|
|
} else {
|
|
disconnect(d, nullptr, this, nullptr);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if(!device) {
|
|
// failed to connect
|
|
InformationBox::ShowError("Failed to connect", "Could not connect to "+serial);
|
|
return false;
|
|
}
|
|
UpdateStatusBar(AppWindow::DeviceStatusBar::Connected);
|
|
// connect(vdevice, &VirtualDevice::NeedsFirmwareUpdate, this, &AppWindow::DeviceNeedsUpdate);
|
|
ui->actionDisconnect->setEnabled(true);
|
|
// find correct position to add device specific actions at
|
|
QAction *before = nullptr;
|
|
for(int i=0;i<ui->menuDevice->actions().size();i++) {
|
|
auto comp = ui->menuDevice->actions()[i];
|
|
if(comp == ui->actionDisconnect) {
|
|
if(i + 2 < ui->menuDevice->actions().size()) {
|
|
before = ui->menuDevice->actions()[i+2];
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
for(auto a : device->driverSpecificActions()) {
|
|
ui->menuDevice->insertAction(before, a);
|
|
}
|
|
// if(!vdevice->isCompoundDevice()) {
|
|
// ui->actionManual_Control->setEnabled(true);
|
|
// ui->actionFirmware_Update->setEnabled(true);
|
|
// ui->actionSource_Calibration->setEnabled(true);
|
|
// ui->actionReceiver_Calibration->setEnabled(true);
|
|
// ui->actionFrequency_Calibration->setEnabled(true);
|
|
// }
|
|
ui->actionPreset->setEnabled(true);
|
|
|
|
DeviceEntry e;
|
|
e.serial = device->getSerial();
|
|
e.driver = device;
|
|
for(auto d : deviceActionGroup->actions()) {
|
|
if(d->text() == e.toString()) {
|
|
d->blockSignals(true);
|
|
d->setChecked(true);
|
|
d->blockSignals(false);
|
|
break;
|
|
}
|
|
}
|
|
for(auto m : modeHandler->getModes()) {
|
|
connect(device, &DeviceDriver::InfoUpdated, m, &Mode::deviceInfoUpdated);
|
|
}
|
|
|
|
// vdevice->initialize();
|
|
|
|
// UpdateAcquisitionFrequencies();
|
|
// if (modeHandler->getActiveMode()) {
|
|
// modeHandler->getActiveMode()->initializeDevice();
|
|
// }
|
|
return true;
|
|
} catch (const runtime_error &e) {
|
|
qWarning() << "Failed to connect:" << e.what();
|
|
DisconnectDevice();
|
|
UpdateDeviceList();
|
|
return false;
|
|
}
|
|
}
|
|
|
|
void AppWindow::DisconnectDevice()
|
|
{
|
|
if(device) {
|
|
for(auto a : device->driverSpecificActions()) {
|
|
ui->menuDevice->removeAction(a);
|
|
}
|
|
device->disconnectDevice();
|
|
disconnect(device, nullptr, &deviceLog, nullptr);
|
|
disconnect(device, nullptr, this, nullptr);
|
|
device = nullptr;
|
|
}
|
|
ui->actionDisconnect->setEnabled(false);
|
|
ui->actionManual_Control->setEnabled(false);
|
|
ui->actionFirmware_Update->setEnabled(false);
|
|
ui->actionSource_Calibration->setEnabled(false);
|
|
ui->actionReceiver_Calibration->setEnabled(false);
|
|
ui->actionFrequency_Calibration->setEnabled(false);
|
|
ui->actionPreset->setEnabled(false);
|
|
for(auto a : deviceActionGroup->actions()) {
|
|
a->setChecked(false);
|
|
}
|
|
if(deviceActionGroup->checkedAction()) {
|
|
deviceActionGroup->checkedAction()->setChecked(false);
|
|
}
|
|
UpdateStatusBar(DeviceStatusBar::Disconnected);
|
|
if(modeHandler->getActiveMode()) {
|
|
modeHandler->getActiveMode()->deviceDisconnected();
|
|
}
|
|
qDebug() << "Disconnected device";
|
|
}
|
|
|
|
void AppWindow::DeviceConnectionLost()
|
|
{
|
|
DisconnectDevice();
|
|
InformationBox::ShowError("Disconnected", "The connection to the device has been lost");
|
|
UpdateDeviceList();
|
|
}
|
|
|
|
void AppWindow::CreateToolbars()
|
|
{
|
|
// Reference toolbar
|
|
auto tb_reference = new QToolBar("Reference", this);
|
|
tb_reference->addWidget(new QLabel("Ref in:"));
|
|
toolbars.reference.type = new QComboBox();
|
|
tb_reference->addWidget(toolbars.reference.type);
|
|
tb_reference->addSeparator();
|
|
tb_reference->addWidget(new QLabel("Ref out:"));
|
|
toolbars.reference.outFreq = new QComboBox();
|
|
tb_reference->addWidget(toolbars.reference.outFreq);
|
|
connect(toolbars.reference.type, qOverload<int>(&QComboBox::currentIndexChanged), this, &AppWindow::UpdateReference);
|
|
connect(toolbars.reference.outFreq, qOverload<int>(&QComboBox::currentIndexChanged), this, &AppWindow::UpdateReference);
|
|
addToolBar(tb_reference);
|
|
tb_reference->setObjectName("Reference Toolbar");
|
|
}
|
|
|
|
void AppWindow::SetupSCPI()
|
|
{
|
|
scpi.add(new SCPICommand("*IDN", nullptr, [=](QStringList){
|
|
return "LibreVNA-GUI";
|
|
}));
|
|
auto scpi_dev = new SCPINode("DEVice");
|
|
scpi.add(scpi_dev);
|
|
scpi_dev->add(new SCPICommand("DISConnect", [=](QStringList params) -> QString {
|
|
Q_UNUSED(params)
|
|
DisconnectDevice();
|
|
return SCPI::getResultName(SCPI::Result::Empty);
|
|
}, nullptr));
|
|
scpi_dev->add(new SCPICommand("CONNect", [=](QStringList params) -> QString {
|
|
QString serial;
|
|
if(params.size() > 0) {
|
|
serial = params[0];
|
|
} else if(UpdateDeviceList() > 0) {
|
|
serial = deviceList[0].serial;
|
|
} else {
|
|
return SCPI::getResultName(SCPI::Result::Error);
|
|
}
|
|
if(!ConnectToDevice(serial)) {
|
|
return SCPI::getResultName(SCPI::Result::Error);
|
|
} else {
|
|
return SCPI::getResultName(SCPI::Result::Empty);
|
|
}
|
|
}, [=](QStringList) -> QString {
|
|
if(device) {
|
|
return device->getSerial();
|
|
} else {
|
|
return "Not connected";
|
|
}
|
|
}));
|
|
scpi_dev->add(new SCPICommand("LIST", nullptr, [=](QStringList) -> QString {
|
|
QString ret;
|
|
for(auto driver : DeviceDriver::getDrivers()) {
|
|
for(auto d : driver->GetAvailableDevices()) {
|
|
ret += d + ",";
|
|
}
|
|
}
|
|
// remove last comma
|
|
ret.chop(1);
|
|
return ret;
|
|
}));
|
|
auto scpi_ref = new SCPINode("REFerence");
|
|
scpi_dev->add(scpi_ref);
|
|
scpi_ref->add(new SCPICommand("OUT", [=](QStringList params) -> QString {
|
|
if(params.size() != 1) {
|
|
return SCPI::getResultName(SCPI::Result::Error);
|
|
} else if(params[0] == "0" || params[0] == "OFF") {
|
|
int index = toolbars.reference.outFreq->findText("Off");
|
|
if(index >= 0) {
|
|
toolbars.reference.outFreq->setCurrentIndex(index);
|
|
} else {
|
|
return SCPI::getResultName(SCPI::Result::Error);
|
|
}
|
|
} else {
|
|
bool isInt;
|
|
params[0].toInt(&isInt);
|
|
if(isInt) {
|
|
params[0].append(" MHz");
|
|
int index = toolbars.reference.outFreq->findText(params[0]);
|
|
if(index >= 0) {
|
|
toolbars.reference.outFreq->setCurrentIndex(index);
|
|
} else {
|
|
return SCPI::getResultName(SCPI::Result::Error);
|
|
}
|
|
} else {
|
|
return SCPI::getResultName(SCPI::Result::Error);
|
|
}
|
|
}
|
|
return SCPI::getResultName(SCPI::Result::Empty);
|
|
}, [=](QStringList) -> QString {
|
|
auto fOutString = toolbars.reference.outFreq->currentText().toUpper();
|
|
if(fOutString.endsWith(" MHZ")) {
|
|
fOutString.chop(4);
|
|
}
|
|
if(fOutString.isEmpty()) {
|
|
return SCPI::getResultName(SCPI::Result::Error);
|
|
} else {
|
|
return fOutString;
|
|
}
|
|
}));
|
|
scpi_ref->add(new SCPICommand("IN", [=](QStringList params) -> QString {
|
|
// reference settings translation
|
|
map<QString, QString> translation {
|
|
make_pair("INT", "Internal"),
|
|
make_pair("EXT", "External"),
|
|
make_pair("AUTO", "Auto"),
|
|
};
|
|
if(params.size() != 1 || translation.count(params[0]) == 0) {
|
|
return SCPI::getResultName(SCPI::Result::Error);
|
|
} else {
|
|
int index = toolbars.reference.type->findText(translation[params[0]]);
|
|
if(index >= 0) {
|
|
toolbars.reference.type->setCurrentIndex(index);
|
|
} else {
|
|
return SCPI::getResultName(SCPI::Result::Error);
|
|
}
|
|
}
|
|
return SCPI::getResultName(SCPI::Result::Empty);
|
|
}, [=](QStringList) -> QString {
|
|
if(device) {
|
|
return device->asserted(DeviceDriver::Flag::ExtRef) ? "EXT" : "INT";
|
|
} else {
|
|
return SCPI::getResultName(SCPI::Result::Error);
|
|
}
|
|
}));
|
|
scpi_dev->add(new SCPICommand("MODE", [=](QStringList params) -> QString {
|
|
if (params.size() != 1) {
|
|
return SCPI::getResultName(SCPI::Result::Error);
|
|
}
|
|
Mode *mode = nullptr;
|
|
if (params[0] == "VNA") {
|
|
mode = modeHandler->findFirstOfType(Mode::Type::VNA);
|
|
} else if(params[0] == "GEN") {
|
|
mode = modeHandler->findFirstOfType(Mode::Type::SG);
|
|
} else if(params[0] == "SA") {
|
|
mode = modeHandler->findFirstOfType(Mode::Type::SA);
|
|
} else {
|
|
return "INVALID MDOE";
|
|
}
|
|
if(mode) {
|
|
int index = modeHandler->findIndex(mode);
|
|
modeHandler->setCurrentIndex(index);
|
|
return SCPI::getResultName(SCPI::Result::Empty);
|
|
} else {
|
|
return SCPI::getResultName(SCPI::Result::Error);
|
|
}
|
|
}, [=](QStringList) -> QString {
|
|
auto active = modeHandler->getActiveMode();
|
|
if(active) {
|
|
switch(active->getType()) {
|
|
case Mode::Type::VNA: return "VNA";
|
|
case Mode::Type::SG: return "GEN";
|
|
case Mode::Type::SA: return "SA";
|
|
case Mode::Type::Last: return SCPI::getResultName(SCPI::Result::Error);
|
|
}
|
|
}
|
|
return SCPI::getResultName(SCPI::Result::Error);
|
|
}));
|
|
auto scpi_status = new SCPINode("STAtus");
|
|
scpi_dev->add(scpi_status);
|
|
scpi_status->add(new SCPICommand("UNLOcked", nullptr, [=](QStringList){
|
|
if(device) {
|
|
return device->asserted(DeviceDriver::Flag::Unlocked) ? SCPI::getResultName(SCPI::Result::True) : SCPI::getResultName(SCPI::Result::False);
|
|
} else {
|
|
return SCPI::getResultName(SCPI::Result::Error);
|
|
}
|
|
}));
|
|
scpi_status->add(new SCPICommand("ADCOVERload", nullptr, [=](QStringList){
|
|
if(device) {
|
|
return device->asserted(DeviceDriver::Flag::Overload) ? SCPI::getResultName(SCPI::Result::True) : SCPI::getResultName(SCPI::Result::False);
|
|
} else {
|
|
return SCPI::getResultName(SCPI::Result::Error);
|
|
}
|
|
}));
|
|
scpi_status->add(new SCPICommand("UNLEVel", nullptr, [=](QStringList){
|
|
if(device) {
|
|
return device->asserted(DeviceDriver::Flag::Unlevel) ? SCPI::getResultName(SCPI::Result::True) : SCPI::getResultName(SCPI::Result::False);
|
|
} else {
|
|
return SCPI::getResultName(SCPI::Result::Error);
|
|
}
|
|
}));
|
|
auto scpi_info = new SCPINode("INFo");
|
|
scpi_dev->add(scpi_info);
|
|
scpi_info->add(new SCPICommand("FWREVision", nullptr, [=](QStringList){
|
|
if(device) {
|
|
return device->getInfo().firmware_version;
|
|
} else {
|
|
return SCPI::getResultName(SCPI::Result::Error);
|
|
}
|
|
}));
|
|
scpi_info->add(new SCPICommand("HWREVision", nullptr, [=](QStringList){
|
|
if(device) {
|
|
return device->getInfo().hardware_version;
|
|
} else {
|
|
return SCPI::getResultName(SCPI::Result::Error);
|
|
}
|
|
}));
|
|
// scpi_info->add(new SCPICommand("TEMPeratures", nullptr, [=](QStringList){
|
|
// if(!vdevice) {
|
|
// return QString("0/0/0");
|
|
// } else if(vdevice->isCompoundDevice()) {
|
|
// // show highest temperature of all devices
|
|
// int maxTempSource = 0;
|
|
// int maxTempLO = 0;
|
|
// int maxTempMCU = 0;
|
|
// for(auto dev : vdevice->getDevices()) {
|
|
// auto status = dev->StatusV1();
|
|
// if(status.temp_source > maxTempSource) {
|
|
// maxTempSource = status.temp_source;
|
|
// }
|
|
// if(status.temp_LO1 > maxTempLO) {
|
|
// maxTempLO = status.temp_LO1;
|
|
// }
|
|
// if(status.temp_MCU > maxTempMCU) {
|
|
// maxTempMCU = status.temp_MCU;
|
|
// }
|
|
// }
|
|
// return QString::number(maxTempSource)+"/"+QString::number(maxTempLO)+"/"+QString::number(maxTempMCU);
|
|
// } else {
|
|
// auto dev = vdevice->getDevice();
|
|
// return QString::number(dev->StatusV1().temp_source)+"/"+QString::number(dev->StatusV1().temp_LO1)+"/"+QString::number(dev->StatusV1().temp_MCU);
|
|
// }
|
|
// }));
|
|
auto scpi_limits = new SCPINode("LIMits");
|
|
scpi_info->add(scpi_limits);
|
|
scpi_limits->add(new SCPICommand("MINFrequency", nullptr, [=](QStringList){
|
|
return QString::number(DeviceDriver::getInfo(getDevice()).Limits.VNA.minFreq);
|
|
}));
|
|
scpi_limits->add(new SCPICommand("MAXFrequency", nullptr, [=](QStringList){
|
|
return QString::number(DeviceDriver::getInfo(getDevice()).Limits.SA.maxFreq);
|
|
}));
|
|
scpi_limits->add(new SCPICommand("MINIFBW", nullptr, [=](QStringList){
|
|
return QString::number(DeviceDriver::getInfo(getDevice()).Limits.VNA.minIFBW);
|
|
}));
|
|
scpi_limits->add(new SCPICommand("MAXIFBW", nullptr, [=](QStringList){
|
|
return QString::number(DeviceDriver::getInfo(getDevice()).Limits.VNA.maxIFBW);
|
|
}));
|
|
scpi_limits->add(new SCPICommand("MAXPoints", nullptr, [=](QStringList){
|
|
return QString::number(DeviceDriver::getInfo(getDevice()).Limits.VNA.maxPoints);
|
|
}));
|
|
scpi_limits->add(new SCPICommand("MINPOWer", nullptr, [=](QStringList){
|
|
return QString::number(DeviceDriver::getInfo(getDevice()).Limits.VNA.mindBm);
|
|
}));
|
|
scpi_limits->add(new SCPICommand("MAXPOWer", nullptr, [=](QStringList){
|
|
return QString::number(DeviceDriver::getInfo(getDevice()).Limits.VNA.maxdBm);
|
|
}));
|
|
scpi_limits->add(new SCPICommand("MINRBW", nullptr, [=](QStringList){
|
|
return QString::number(DeviceDriver::getInfo(getDevice()).Limits.SA.minRBW);
|
|
}));
|
|
scpi_limits->add(new SCPICommand("MAXRBW", nullptr, [=](QStringList){
|
|
return QString::number(DeviceDriver::getInfo(getDevice()).Limits.SA.maxRBW);
|
|
}));
|
|
scpi_limits->add(new SCPICommand("MAXHARMonicfrequency", nullptr, [=](QStringList){
|
|
return QString::number(DeviceDriver::getInfo(getDevice()).Limits.VNA.maxFreq);
|
|
}));
|
|
|
|
// TODO
|
|
// auto scpi_manual = new SCPINode("MANual");
|
|
// scpi_manual->add(new SCPICommand("STArt",[=](QStringList) -> QString {
|
|
//// StartManualControl();
|
|
// return SCPI::getResultName(SCPI::Result::Empty);
|
|
// }, nullptr));
|
|
// scpi_manual->add(new SCPICommand("STOp",[=](QStringList) -> QString {
|
|
// manual->close();
|
|
// delete manual;
|
|
// return SCPI::getResultName(SCPI::Result::Empty);
|
|
// }, nullptr));
|
|
//
|
|
// auto addBooleanManualSetting = [=](QString cmd, void(ManualControlDialog::*set)(bool), bool(ManualControlDialog::*get)(void)) {
|
|
// scpi_manual->add(new SCPICommand(cmd, [=](QStringList params) -> QString {
|
|
// bool enable;
|
|
// if(!manual || !SCPI::paramToBool(params, 0, enable)) {
|
|
// return SCPI::getResultName(SCPI::Result::Error);
|
|
// }
|
|
// auto set_fn = std::bind(set, manual, std::placeholders::_1);
|
|
// set_fn(enable);
|
|
// return SCPI::getResultName(SCPI::Result::Empty);
|
|
// }, [=](QStringList) -> QString {
|
|
// if(!manual) {
|
|
// return SCPI::getResultName(SCPI::Result::Error);
|
|
// }
|
|
// auto get_fn = std::bind(get, manual);
|
|
// return get_fn() ? SCPI::getResultName(SCPI::Result::True) : SCPI::getResultName(SCPI::Result::False);
|
|
// }));
|
|
// };
|
|
|
|
// auto addDoubleManualSetting = [=](QString cmd, void(ManualControlDialog::*set)(double), double(ManualControlDialog::*get)(void)) {
|
|
// scpi_manual->add(new SCPICommand(cmd, [=](QStringList params) -> QString {
|
|
// double value;
|
|
// if(!manual || !SCPI::paramToDouble(params, 0, value)) {
|
|
// return SCPI::getResultName(SCPI::Result::Error);
|
|
// }
|
|
// auto set_fn = std::bind(set, manual, std::placeholders::_1);
|
|
// set_fn(value);
|
|
// return SCPI::getResultName(SCPI::Result::Empty);
|
|
// }, [=](QStringList) -> QString {
|
|
// if(!manual) {
|
|
// return SCPI::getResultName(SCPI::Result::Error);
|
|
// }
|
|
// auto get_fn = std::bind(get, manual);
|
|
// return QString::number(get_fn());
|
|
// }));
|
|
// };
|
|
// auto addIntegerManualSetting = [=](QString cmd, void(ManualControlDialog::*set)(int), int(ManualControlDialog::*get)(void)) {
|
|
// scpi_manual->add(new SCPICommand(cmd, [=](QStringList params) -> QString {
|
|
// double value;
|
|
// if(!manual || !SCPI::paramToDouble(params, 0, value)) {
|
|
// return SCPI::getResultName(SCPI::Result::Error);
|
|
// }
|
|
// auto set_fn = std::bind(set, manual, std::placeholders::_1);
|
|
// set_fn(value);
|
|
// return SCPI::getResultName(SCPI::Result::Empty);
|
|
// }, [=](QStringList) -> QString {
|
|
// if(!manual) {
|
|
// return SCPI::getResultName(SCPI::Result::Error);
|
|
// }
|
|
// auto get_fn = std::bind(get, manual);
|
|
// return QString::number(get_fn());
|
|
// }));
|
|
// };
|
|
// auto addIntegerManualSettingWithReturnValue = [=](QString cmd, bool(ManualControlDialog::*set)(int), int(ManualControlDialog::*get)(void)) {
|
|
// scpi_manual->add(new SCPICommand(cmd, [=](QStringList params) -> QString {
|
|
// double value;
|
|
// if(!manual || !SCPI::paramToDouble(params, 0, value)) {
|
|
// return SCPI::getResultName(SCPI::Result::Error);
|
|
// }
|
|
// auto set_fn = std::bind(set, manual, std::placeholders::_1);
|
|
// if(set_fn(value)) {
|
|
// return SCPI::getResultName(SCPI::Result::Empty);
|
|
// } else {
|
|
// return SCPI::getResultName(SCPI::Result::Error);
|
|
// }
|
|
// }, [=](QStringList) -> QString {
|
|
// if(!manual) {
|
|
// return SCPI::getResultName(SCPI::Result::Error);
|
|
// }
|
|
// auto get_fn = std::bind(get, manual);
|
|
// return QString::number(get_fn());
|
|
// }));
|
|
// };
|
|
// auto addIntegerManualQuery = [=](QString cmd, int(ManualControlDialog::*get)(void)) {
|
|
// scpi_manual->add(new SCPICommand(cmd, nullptr, [=](QStringList) -> QString {
|
|
// if(!manual) {
|
|
// return SCPI::getResultName(SCPI::Result::Error);
|
|
// }
|
|
// auto get_fn = std::bind(get, manual);
|
|
// return QString::number(get_fn());
|
|
// }));
|
|
// };
|
|
// auto addDoubleManualQuery = [=](QString cmd, double(ManualControlDialog::*get)(void)) {
|
|
// scpi_manual->add(new SCPICommand(cmd, nullptr, [=](QStringList) -> QString {
|
|
// if(!manual) {
|
|
// return SCPI::getResultName(SCPI::Result::Error);
|
|
// }
|
|
// auto get_fn = std::bind(get, manual);
|
|
// return QString::number(get_fn());
|
|
// }));
|
|
// };
|
|
// auto addBooleanManualQuery = [=](QString cmd, bool(ManualControlDialog::*get)(void)) {
|
|
// scpi_manual->add(new SCPICommand(cmd, nullptr, [=](QStringList) -> QString {
|
|
// if(!manual) {
|
|
// return SCPI::getResultName(SCPI::Result::Error);
|
|
// }
|
|
// auto get_fn = std::bind(get, manual);
|
|
// return get_fn() ? SCPI::getResultName(SCPI::Result::True) : SCPI::getResultName(SCPI::Result::False);
|
|
// }));
|
|
// };
|
|
// auto addComplexManualQuery = [=](QString cmd, std::complex<double>(ManualControlDialog::*get)(void)) {
|
|
// scpi_manual->add(new SCPICommand(cmd, nullptr, [=](QStringList) -> QString {
|
|
// if(!manual) {
|
|
// return SCPI::getResultName(SCPI::Result::Error);
|
|
// }
|
|
// auto get_fn = std::bind(get, manual);
|
|
// auto res = get_fn();
|
|
// return QString::number(res.real())+","+QString::number(res.imag());
|
|
// }));
|
|
// };
|
|
|
|
// addBooleanManualSetting("HSRC_CE", &ManualControlDialog::setHighSourceChipEnable, &ManualControlDialog::getHighSourceChipEnable);
|
|
// addBooleanManualSetting("HSRC_RFEN", &ManualControlDialog::setHighSourceRFEnable, &ManualControlDialog::getHighSourceRFEnable);
|
|
// addBooleanManualQuery("HSRC_LOCKed", &ManualControlDialog::getHighSourceLocked);
|
|
// addIntegerManualSettingWithReturnValue("HSRC_PWR", &ManualControlDialog::setHighSourcePower, &ManualControlDialog::getHighSourcePower);
|
|
// addDoubleManualSetting("HSRC_FREQ", &ManualControlDialog::setHighSourceFrequency, &ManualControlDialog::getHighSourceFrequency);
|
|
// scpi_manual->add(new SCPICommand("HSRC_LPF", [=](QStringList params) -> QString {
|
|
// long value;
|
|
// if(!manual || !SCPI::paramToLong(params, 0, value)) {
|
|
// return SCPI::getResultName(SCPI::Result::Error);
|
|
// }
|
|
// switch(value) {
|
|
// case 947:
|
|
// manual->setHighSourceLPF(ManualControlDialog::LPF::M947);
|
|
// break;
|
|
// case 1880:
|
|
// manual->setHighSourceLPF(ManualControlDialog::LPF::M1880);
|
|
// break;
|
|
// case 3500:
|
|
// manual->setHighSourceLPF(ManualControlDialog::LPF::M3500);
|
|
// break;
|
|
// case 0:
|
|
// manual->setHighSourceLPF(ManualControlDialog::LPF::None);
|
|
// break;
|
|
// default:
|
|
// return SCPI::getResultName(SCPI::Result::Error);
|
|
// }
|
|
// return SCPI::getResultName(SCPI::Result::Empty);
|
|
// }, [=](QStringList) -> QString {
|
|
// if(!manual) {
|
|
// return SCPI::getResultName(SCPI::Result::Error);
|
|
// }
|
|
// auto lpf = manual->getHighSourceLPF();
|
|
// switch(lpf) {
|
|
// case ManualControlDialog::LPF::M947: return "947";
|
|
// case ManualControlDialog::LPF::M1880: return "1880";
|
|
// case ManualControlDialog::LPF::M3500: return "3500";
|
|
// case ManualControlDialog::LPF::None: return "0";
|
|
// default: return SCPI::getResultName(SCPI::Result::Error);
|
|
// }
|
|
// }));
|
|
// addBooleanManualSetting("LSRC_EN", &ManualControlDialog::setLowSourceEnable, &ManualControlDialog::getLowSourceEnable);
|
|
// addIntegerManualSettingWithReturnValue("LSRC_PWR", &ManualControlDialog::setLowSourcePower, &ManualControlDialog::getLowSourcePower);
|
|
// addDoubleManualSetting("LSRC_FREQ", &ManualControlDialog::setLowSourceFrequency, &ManualControlDialog::getLowSourceFrequency);
|
|
// addBooleanManualSetting("BAND_SW", &ManualControlDialog::setHighband, &ManualControlDialog::getHighband);
|
|
// addDoubleManualSetting("ATTenuator", &ManualControlDialog::setAttenuator, &ManualControlDialog::getAttenuator);
|
|
// addBooleanManualSetting("AMP_EN", &ManualControlDialog::setAmplifierEnable, &ManualControlDialog::getAmplifierEnable);
|
|
// addIntegerManualSettingWithReturnValue("PORT_SW", &ManualControlDialog::setPortSwitch, &ManualControlDialog::getPortSwitch);
|
|
// addBooleanManualSetting("LO1_CE", &ManualControlDialog::setLO1ChipEnable, &ManualControlDialog::getLO1ChipEnable);
|
|
// addBooleanManualSetting("LO1_RFEN", &ManualControlDialog::setLO1RFEnable, &ManualControlDialog::getLO1RFEnable);
|
|
// addBooleanManualQuery("LO1_LOCKed", &ManualControlDialog::getLO1Locked);
|
|
// addDoubleManualSetting("LO1_FREQ", &ManualControlDialog::setLO1Frequency, &ManualControlDialog::getLO1Frequency);
|
|
// addDoubleManualSetting("IF1_FREQ", &ManualControlDialog::setIF1Frequency, &ManualControlDialog::getIF1Frequency);
|
|
// addBooleanManualSetting("LO2_EN", &ManualControlDialog::setLO2Enable, &ManualControlDialog::getLO2Enable);
|
|
// addDoubleManualSetting("LO2_FREQ", &ManualControlDialog::setLO2Frequency, &ManualControlDialog::getLO2Frequency);
|
|
// addDoubleManualSetting("IF2_FREQ", &ManualControlDialog::setIF2Frequency, &ManualControlDialog::getIF2Frequency);
|
|
// addBooleanManualSetting("PORT1_EN", &ManualControlDialog::setPort1Enable, &ManualControlDialog::getPort1Enable);
|
|
// addBooleanManualSetting("PORT2_EN", &ManualControlDialog::setPort2Enable, &ManualControlDialog::getPort2Enable);
|
|
// addBooleanManualSetting("REF_EN", &ManualControlDialog::setRefEnable, &ManualControlDialog::getRefEnable);
|
|
// addIntegerManualSetting("SAMPLES", &ManualControlDialog::setNumSamples, &ManualControlDialog::getNumSamples);
|
|
// scpi_manual->add(new SCPICommand("WINdow", [=](QStringList params) -> QString {
|
|
// if(!manual || params.size() < 1) {
|
|
// return SCPI::getResultName(SCPI::Result::Error);
|
|
// }
|
|
// if (params[0] == "NONE") {
|
|
// manual->setWindow(ManualControlDialog::Window::None);
|
|
// } else if(params[0] == "KAISER") {
|
|
// manual->setWindow(ManualControlDialog::Window::Kaiser);
|
|
// } else if(params[0] == "HANN") {
|
|
// manual->setWindow(ManualControlDialog::Window::Hann);
|
|
// } else if(params[0] == "FLATTOP") {
|
|
// manual->setWindow(ManualControlDialog::Window::FlatTop);
|
|
// } else {
|
|
// return "INVALID WINDOW";
|
|
// }
|
|
// return SCPI::getResultName(SCPI::Result::Empty);
|
|
// }, [=](QStringList) -> QString {
|
|
// if(!manual) {
|
|
// return SCPI::getResultName(SCPI::Result::Error);
|
|
// }
|
|
// switch((ManualControlDialog::Window) manual->getWindow()) {
|
|
// case ManualControlDialog::Window::None: return "NONE";
|
|
// case ManualControlDialog::Window::Kaiser: return "KAISER";
|
|
// case ManualControlDialog::Window::Hann: return "HANN";
|
|
// case ManualControlDialog::Window::FlatTop: return "FLATTOP";
|
|
// default: return SCPI::getResultName(SCPI::Result::Error);
|
|
// }
|
|
// }));
|
|
// addIntegerManualQuery("PORT1_MIN", &ManualControlDialog::getPort1MinADC);
|
|
// addIntegerManualQuery("PORT1_MAX", &ManualControlDialog::getPort1MaxADC);
|
|
// addDoubleManualQuery("PORT1_MAG", &ManualControlDialog::getPort1Magnitude);
|
|
// addDoubleManualQuery("PORT1_PHAse", &ManualControlDialog::getPort1Phase);
|
|
// addComplexManualQuery("PORT1_REFerenced", &ManualControlDialog::getPort1Referenced);
|
|
|
|
// addIntegerManualQuery("PORT2_MIN", &ManualControlDialog::getPort2MinADC);
|
|
// addIntegerManualQuery("PORT2_MAX", &ManualControlDialog::getPort2MaxADC);
|
|
// addDoubleManualQuery("PORT2_MAG", &ManualControlDialog::getPort2Magnitude);
|
|
// addDoubleManualQuery("PORT2_PHAse", &ManualControlDialog::getPort2Phase);
|
|
// addComplexManualQuery("PORT2_REFerenced", &ManualControlDialog::getPort2Referenced);
|
|
|
|
// addIntegerManualQuery("REF_MIN", &ManualControlDialog::getRefMinADC);
|
|
// addIntegerManualQuery("REF_MAX", &ManualControlDialog::getRefMaxADC);
|
|
// addDoubleManualQuery("REF_MAG", &ManualControlDialog::getRefMagnitude);
|
|
// addDoubleManualQuery("REF_PHAse", &ManualControlDialog::getRefPhase);
|
|
|
|
// scpi.add(scpi_manual);
|
|
}
|
|
|
|
void AppWindow::StartTCPServer(int port)
|
|
{
|
|
server = new TCPServer(port);
|
|
connect(server, &TCPServer::received, &scpi, &SCPI::input);
|
|
connect(&scpi, &SCPI::output, server, &TCPServer::send);
|
|
}
|
|
|
|
void AppWindow::StopTCPServer()
|
|
{
|
|
delete server;
|
|
server = nullptr;
|
|
}
|
|
|
|
SCPI* AppWindow::getSCPI()
|
|
{
|
|
return &scpi;
|
|
}
|
|
|
|
void AppWindow::setModeStatus(QString msg)
|
|
{
|
|
lModeInfo.setText(msg);
|
|
}
|
|
|
|
int AppWindow::UpdateDeviceList()
|
|
{
|
|
deviceActionGroup->setExclusive(true);
|
|
ui->menuConnect_to->clear();
|
|
deviceList.clear();
|
|
for(auto driver : DeviceDriver::getDrivers()) {
|
|
for(auto serial : driver->GetAvailableDevices()) {
|
|
DeviceEntry e;
|
|
e.driver = driver;
|
|
e.serial = serial;
|
|
deviceList.push_back(e);
|
|
}
|
|
}
|
|
if(device) {
|
|
DeviceEntry e;
|
|
e.driver = device;
|
|
e.serial = device->getSerial();
|
|
if(std::find(deviceList.begin(), deviceList.end(), e) == deviceList.end()) {
|
|
// connected device is not in list (this may happen if the driver does not detect a connected device as "available")
|
|
deviceList.push_back(e);
|
|
}
|
|
}
|
|
int available = 0;
|
|
bool found = false;
|
|
for(auto d : deviceList) {
|
|
if(!parser.value("device").isEmpty() && parser.value("device") != d.serial) {
|
|
// specified device does not match, ignore
|
|
continue;
|
|
}
|
|
auto connectAction = ui->menuConnect_to->addAction(d.toString());
|
|
connectAction->setCheckable(true);
|
|
connectAction->setActionGroup(deviceActionGroup);
|
|
if(device && d.serial == device->getSerial()) {
|
|
connectAction->setChecked(true);
|
|
}
|
|
connect(connectAction, &QAction::triggered, [this, d]() {
|
|
ConnectToDevice(d.serial, d.driver);
|
|
});
|
|
found = true;
|
|
available++;
|
|
}
|
|
ui->menuConnect_to->setEnabled(found);
|
|
qDebug() << "Updated device list, found" << available;
|
|
return available;
|
|
}
|
|
|
|
//void AppWindow::StartManualControl()
|
|
//{
|
|
// if(!vdevice || vdevice->isCompoundDevice()) {
|
|
// return;
|
|
// }
|
|
// if(manual) {
|
|
// // dialog already active, nothing to do
|
|
// return;
|
|
// }
|
|
// manual = new ManualControlDialog(*vdevice->getDevice(), this);
|
|
// connect(manual, &QDialog::finished, [=](){
|
|
// manual = nullptr;
|
|
// if(vdevice) {
|
|
// modeHandler->getActiveMode()->initializeDevice();
|
|
// }
|
|
// });
|
|
// if(AppWindow::showGUI()) {
|
|
// manual->show();
|
|
// }
|
|
//}
|
|
|
|
void AppWindow::UpdateReferenceToolbar()
|
|
{
|
|
toolbars.reference.type->blockSignals(true);
|
|
toolbars.reference.outFreq->blockSignals(true);
|
|
toolbars.reference.type->setEnabled(device && device->supports(DeviceDriver::Feature::ExtRefIn));
|
|
toolbars.reference.outFreq->setEnabled(device && device->supports(DeviceDriver::Feature::ExtRefOut));
|
|
if(device) {
|
|
// save current setting
|
|
auto refInBuf = toolbars.reference.type->currentText();
|
|
auto refOutBuf = toolbars.reference.outFreq->currentText();
|
|
toolbars.reference.type->clear();
|
|
for(auto in : device->availableExtRefInSettings()) {
|
|
toolbars.reference.type->addItem(in);
|
|
}
|
|
toolbars.reference.outFreq->clear();
|
|
for(auto out : device->availableExtRefOutSettings()) {
|
|
toolbars.reference.outFreq->addItem(out);
|
|
}
|
|
// restore previous setting if still available
|
|
if(toolbars.reference.type->findText(refInBuf) >= 0) {
|
|
toolbars.reference.type->setCurrentText(refInBuf);
|
|
} else {
|
|
toolbars.reference.type->setCurrentIndex(0);
|
|
}
|
|
if(toolbars.reference.outFreq->findText(refOutBuf) >= 0) {
|
|
toolbars.reference.outFreq->setCurrentText(refOutBuf);
|
|
} else {
|
|
toolbars.reference.outFreq->setCurrentIndex(0);
|
|
}
|
|
}
|
|
toolbars.reference.type->blockSignals(false);
|
|
toolbars.reference.outFreq->blockSignals(false);
|
|
UpdateReference();
|
|
}
|
|
|
|
void AppWindow::UpdateReference()
|
|
{
|
|
if(!device) {
|
|
// can't update without a device connected
|
|
return;
|
|
}
|
|
device->setExtRef(toolbars.reference.type->currentText(), toolbars.reference.outFreq->currentText());
|
|
}
|
|
|
|
//void AppWindow::DeviceNeedsUpdate(int reported, int expected)
|
|
//{
|
|
// auto ret = InformationBox::AskQuestion("Warning",
|
|
// "The device reports a different protocol"
|
|
// "version (" + QString::number(reported) + ") than expected (" + QString::number(expected) + ").\n"
|
|
// "A firmware update is strongly recommended. Do you want to update now?", false);
|
|
// if (ret) {
|
|
// if (vdevice->isCompoundDevice()) {
|
|
// InformationBox::ShowError("Unable to update the firmware", "The connected device is a compound device, direct firmware"
|
|
// " update is not supported. Connect to each LibreVNA individually for the update.");
|
|
// return;
|
|
// }
|
|
// StartFirmwareUpdateDialog();
|
|
// }
|
|
//}
|
|
|
|
void AppWindow::DeviceStatusUpdated()
|
|
{
|
|
lDeviceInfo.setText(device->getStatus());
|
|
}
|
|
|
|
void AppWindow::DeviceFlagsUpdated()
|
|
{
|
|
lADCOverload.setVisible(device->asserted(DeviceDriver::Flag::Overload));
|
|
lUnlevel.setVisible(device->asserted(DeviceDriver::Flag::Unlevel));
|
|
lUnlock.setVisible(device->asserted(DeviceDriver::Flag::Unlocked));
|
|
}
|
|
|
|
void AppWindow::DeviceInfoUpdated()
|
|
{
|
|
if (modeHandler->getActiveMode()) {
|
|
modeHandler->getActiveMode()->initializeDevice();
|
|
}
|
|
UpdateReferenceToolbar();
|
|
}
|
|
|
|
//void AppWindow::SourceCalibrationDialog()
|
|
//{
|
|
// if(!vdevice || vdevice->isCompoundDevice()) {
|
|
// return;
|
|
// }
|
|
// auto d = new SourceCalDialog(vdevice->getDevice(), modeHandler);
|
|
// if(AppWindow::showGUI()) {
|
|
// d->exec();
|
|
// }
|
|
//}
|
|
|
|
//void AppWindow::ReceiverCalibrationDialog()
|
|
//{
|
|
// if(!vdevice || vdevice->isCompoundDevice()) {
|
|
// return;
|
|
// }
|
|
// auto d = new ReceiverCalDialog(vdevice->getDevice(), modeHandler);
|
|
// if(AppWindow::showGUI()) {
|
|
// d->exec();
|
|
// }
|
|
//}
|
|
|
|
//void AppWindow::FrequencyCalibrationDialog()
|
|
//{
|
|
// if(!vdevice || vdevice->isCompoundDevice()) {
|
|
// return;
|
|
// }
|
|
// auto d = new FrequencyCalDialog(vdevice->getDevice(), modeHandler);
|
|
// if(AppWindow::showGUI()) {
|
|
// d->exec();
|
|
// }
|
|
//}
|
|
|
|
void AppWindow::SaveSetup(QString filename)
|
|
{
|
|
if(!filename.endsWith(".setup")) {
|
|
filename.append(".setup");
|
|
}
|
|
ofstream file;
|
|
file.open(filename.toStdString());
|
|
file << setw(4) << SaveSetup() << endl;
|
|
file.close();
|
|
QFileInfo fi(filename);
|
|
lSetupName.setText("Setup: "+fi.fileName());
|
|
}
|
|
|
|
nlohmann::json AppWindow::SaveSetup()
|
|
{
|
|
nlohmann::json j;
|
|
nlohmann::json jm;
|
|
for(auto m : modeHandler->getModes()) {
|
|
nlohmann::json jmode;
|
|
jmode["type"] = Mode::TypeToName(m->getType()).toStdString();
|
|
jmode["name"] = m->getName().toStdString();
|
|
jmode["settings"] = m->toJSON();
|
|
jm.push_back(jmode);
|
|
}
|
|
j["Modes"] = jm;
|
|
if(modeHandler->getActiveMode()) {
|
|
j["activeMode"] = modeHandler->getActiveMode()->getName().toStdString();
|
|
}
|
|
nlohmann::json ref;
|
|
|
|
ref["Mode"] = toolbars.reference.type->currentText().toStdString();
|
|
ref["Output"] = toolbars.reference.outFreq->currentText().toStdString();
|
|
j["Reference"] = ref;
|
|
j["version"] = qlibrevnaApp->applicationVersion().toStdString();
|
|
return j;
|
|
}
|
|
|
|
void AppWindow::LoadSetup(QString filename)
|
|
{
|
|
ifstream file;
|
|
file.open(filename.toStdString());
|
|
if(!file.is_open()) {
|
|
qWarning() << "Unable to open file:" << filename;
|
|
return;
|
|
}
|
|
nlohmann::json j;
|
|
try {
|
|
file >> j;
|
|
} catch (exception &e) {
|
|
InformationBox::ShowError("Error", "Failed to parse the setup file (" + QString(e.what()) + ")");
|
|
qWarning() << "Parsing of setup file failed: " << e.what();
|
|
file.close();
|
|
return;
|
|
}
|
|
file.close();
|
|
LoadSetup(j);
|
|
QFileInfo fi(filename);
|
|
lSetupName.setText("Setup: "+fi.fileName());
|
|
}
|
|
|
|
void AppWindow::LoadSetup(nlohmann::json j)
|
|
{
|
|
// auto d = new JSONPickerDialog(j);
|
|
// d->exec();
|
|
if(j.contains("Reference")) {
|
|
toolbars.reference.type->setCurrentText(QString::fromStdString(j["Reference"].value("Mode", "Internal")));
|
|
toolbars.reference.outFreq->setCurrentText(QString::fromStdString(j["Reference"].value("Output", "Off")));
|
|
}
|
|
|
|
// Disconnect device prior to deleting and creating new modes. This prevents excessice and unnnecessary configuration of the device
|
|
QString serial = QString();
|
|
if(device) {
|
|
serial = device->getSerial();
|
|
device->disconnectDevice();
|
|
device = nullptr;
|
|
}
|
|
|
|
modeHandler->closeModes();
|
|
|
|
/* old style VNA/Generator/Spectrum Analyzer settings,
|
|
* no more than one instance in each mode running */
|
|
if(j.contains("VNA")) {
|
|
auto vnaIndex = modeHandler->createMode("Vector Network Analyzer", Mode::Type::VNA);
|
|
auto *vna = static_cast<VNA*>(modeHandler->getMode(vnaIndex));
|
|
vna->fromJSON(j["VNA"]);
|
|
}
|
|
if(j.contains("Generator")) {
|
|
auto sgIndex = modeHandler->createMode("Generator", Mode::Type::SG);
|
|
auto *generator = static_cast<Generator*>(modeHandler->getMode(sgIndex));
|
|
generator->fromJSON(j["Generator"]);
|
|
}
|
|
if(j.contains("SpectrumAnalyzer")) {
|
|
auto saIndex = modeHandler->createMode("Spectrum Analyzer", Mode::Type::SA);
|
|
auto *spectrumAnalyzer = static_cast<SpectrumAnalyzer*>(modeHandler->getMode(saIndex));
|
|
spectrumAnalyzer->fromJSON(j["SpectrumAnalyzer"]);
|
|
}
|
|
if(j.contains("Modes")) {
|
|
for(auto jm : j["Modes"]) {
|
|
auto type = Mode::TypeFromName(QString::fromStdString(jm.value("type", "Invalid")));
|
|
if(type != Mode::Type::Last && jm.contains("settings")) {
|
|
auto index = modeHandler->createMode(QString::fromStdString(jm.value("name", "")), type);
|
|
auto m = modeHandler->getMode(index);
|
|
m->fromJSON(jm["settings"]);
|
|
}
|
|
}
|
|
}
|
|
|
|
// reconnect to device
|
|
if(!serial.isEmpty()) {
|
|
ConnectToDevice(serial);
|
|
}
|
|
|
|
// activate the correct mode
|
|
QString modeName = QString::fromStdString(j.value("activeMode", ""));
|
|
for(auto m : modeHandler->getModes()) {
|
|
if(m->getName() == modeName) {
|
|
auto index = modeHandler->findIndex(m);
|
|
modeHandler->setCurrentIndex(index);
|
|
break;
|
|
}
|
|
}
|
|
// if no mode is activated, there might have been a problem with the setup file. Activate the first mode anyway, to prevent invalid GUI state
|
|
if(!modeHandler->getActiveMode() && modeHandler->getModes().size() > 0) {
|
|
modeHandler->activate(modeHandler->getModes()[0]);
|
|
}
|
|
}
|
|
|
|
DeviceDriver *AppWindow::getDevice()
|
|
{
|
|
return device;
|
|
}
|
|
|
|
QStackedWidget *AppWindow::getCentral() const
|
|
{
|
|
return central;
|
|
}
|
|
|
|
ModeHandler* AppWindow::getModeHandler() const
|
|
{
|
|
return modeHandler;
|
|
}
|
|
|
|
|
|
Ui::MainWindow *AppWindow::getUi() const
|
|
{
|
|
return ui;
|
|
}
|
|
|
|
const QString& AppWindow::getAppVersion() const
|
|
{
|
|
return appVersion;
|
|
}
|
|
|
|
const QString& AppWindow::getAppGitHash() const
|
|
{
|
|
return appGitHash;
|
|
}
|
|
|
|
bool AppWindow::showGUI()
|
|
{
|
|
return !noGUIset;
|
|
}
|
|
|
|
void AppWindow::SetupStatusBar()
|
|
{
|
|
ui->statusbar->addWidget(&lConnectionStatus);
|
|
auto div1 = new QFrame;
|
|
div1->setFrameShape(QFrame::VLine);
|
|
ui->statusbar->addWidget(div1);
|
|
ui->statusbar->addWidget(&lDeviceInfo);
|
|
ui->statusbar->addWidget(new QLabel, 1);
|
|
|
|
ui->statusbar->addWidget(&lSetupName);
|
|
lSetupName.setText("Setup: -");
|
|
auto div2 = new QFrame;
|
|
div2->setFrameShape(QFrame::VLine);
|
|
ui->statusbar->addWidget(div2);
|
|
ui->statusbar->addWidget(&lModeInfo);
|
|
auto div3 = new QFrame;
|
|
div3->setFrameShape(QFrame::VLine);
|
|
ui->statusbar->addWidget(div3);
|
|
|
|
lADCOverload.setStyleSheet("color : red");
|
|
lADCOverload.setText("ADC overload");
|
|
lADCOverload.setVisible(false);
|
|
ui->statusbar->addWidget(&lADCOverload);
|
|
|
|
lUnlevel.setStyleSheet("color : red");
|
|
lUnlevel.setText("Unlevel");
|
|
lUnlevel.setVisible(false);
|
|
ui->statusbar->addWidget(&lUnlevel);
|
|
|
|
lUnlock.setStyleSheet("color : red");
|
|
lUnlock.setText("Unlock");
|
|
lUnlock.setVisible(false);
|
|
ui->statusbar->addWidget(&lUnlock);
|
|
//ui->statusbar->setStyleSheet("QStatusBar::item { border: 1px solid black; };");
|
|
}
|
|
|
|
void AppWindow::UpdateStatusBar(DeviceStatusBar status)
|
|
{
|
|
switch(status) {
|
|
case DeviceStatusBar::Connected:
|
|
lConnectionStatus.setText("Connected to " + device->getSerial());
|
|
qInfo() << "Connected to" << device->getSerial();
|
|
break;
|
|
case DeviceStatusBar::Disconnected:
|
|
lConnectionStatus.setText("No device connected");
|
|
lDeviceInfo.setText("No status information available yet");
|
|
break;
|
|
default:
|
|
// invalid status
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
QString AppWindow::DeviceEntry::toString()
|
|
{
|
|
return serial + " (" + driver->getDriverName()+")";
|
|
}
|
|
|
|
AppWindow::DeviceEntry AppWindow::DeviceEntry::fromString(QString s, std::vector<DeviceDriver*> drivers)
|
|
{
|
|
DeviceEntry e;
|
|
QStringList parts = s.split(" ");
|
|
if(parts.size() < 2) {
|
|
// invalid string
|
|
e.serial = "";
|
|
e.driver = nullptr;
|
|
} else {
|
|
e.serial = parts[0];
|
|
e.driver = nullptr;
|
|
parts[1].chop(1);
|
|
auto driverName = parts[1].mid(1);
|
|
for(auto d : drivers) {
|
|
if(d->getDriverName() == driverName) {
|
|
e.driver = d;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return e;
|
|
}
|