#include "wfmain.h" #include "ui_wfmain.h" #include "commhandler.h" #include "rigidentities.h" #include "logcategories.h" // This code is copyright 2017-2022 Elliott H. Liggett // All rights reserved // Log support: //static void messageHandler(QtMsgType type, const QMessageLogContext& context, const QString& msg); QScopedPointer m_logFile; QMutex logMutex; QMutex logTextMutex; QVector> logStringBuffer; #ifdef QT_DEBUG bool debugModeLogging = true; #else bool debugModeLogging = false; #endif wfmain::wfmain(const QString settingsFile, const QString logFile, bool debugMode, QWidget *parent ) : QMainWindow(parent), ui(new Ui::wfmain), logFilename(logFile) { QGuiApplication::setApplicationDisplayName("wfview"); QGuiApplication::setApplicationName(QString("wfview")); setWindowIcon(QIcon( QString(":resources/wfview.png"))); this->debugMode = debugMode; debugModeLogging = debugMode; version = QString("wfview version: %1 (Git:%2 on %3 at %4 by %5@%6). Operating System: %7 (%8). Build Qt Version %9. Current Qt Version: %10") .arg(QString(WFVIEW_VERSION)) .arg(GITSHORT).arg(__DATE__).arg(__TIME__).arg(UNAME).arg(HOST) .arg(QSysInfo::prettyProductName()).arg(QSysInfo::buildCpuArchitecture()) .arg(QT_VERSION_STR).arg(qVersion()); ui->setupUi(this); setWindowTitle(QString("wfview")); ui->monitorLabel->setText("Mon"); logWindow = new loggingWindow(logFile); initLogging(); logWindow->setInitialDebugState(debugMode); qInfo(logSystem()) << version; cal = new calibrationWindow(); rpt = new repeaterSetup(); sat = new satelliteSetup(); trxadj = new transceiverAdjustments(); cw = new cwSender(); abtBox = new aboutbox(); selRad = new selectRadio(); bandbtns = new bandbuttons(); finputbtns = new frequencyinputwidget(); setupui = new settingswidget(); qRegisterMetaType(); // Needs to be registered early. qRegisterMetaType(); qRegisterMetaType(); qRegisterMetaType(); qRegisterMetaType(); qRegisterMetaType(); qRegisterMetaType(); qRegisterMetaType(); qRegisterMetaType(); qRegisterMetaType(); qRegisterMetaType(); qRegisterMetaType(); qRegisterMetaType(); qRegisterMetaType(); qRegisterMetaType(); qRegisterMetaType(); qRegisterMetaType(); qRegisterMetaType(); qRegisterMetaType>(); qRegisterMetaType*>(); qRegisterMetaType*>(); qRegisterMetaType*>(); qRegisterMetaType(); qRegisterMetaType(); qRegisterMetaType>(); qRegisterMetaType>(); qRegisterMetaType(); qRegisterMetaType(); qRegisterMetaType(); qRegisterMetaType(); qRegisterMetaType(); qRegisterMetaType(); qRegisterMetaType(); qRegisterMetaType(); qRegisterMetaType(); qRegisterMetaType(); qRegisterMetaType(); qRegisterMetaType(); qRegisterMetaType(); qRegisterMetaType(); qRegisterMetaType(); qRegisterMetaType(); qRegisterMetaType(); haveRigCaps = false; this->setObjectName("wfmain"); queue = cachingQueue::getInstance(this); connect(queue,SIGNAL(sendValue(cacheItem)),this,SLOT(receiveValue(cacheItem))); // We need to populate the list of rigs as early as possible so do it now #ifndef Q_OS_LINUX QString systemRigLocation = QCoreApplication::applicationDirPath(); #else QString systemRigLocation = PREFIX; #endif #ifdef Q_OS_LINUX systemRigLocation += "/share/wfview/rigs"; #else systemRigLocation +="/rigs"; #endif QDir systemRigDir(systemRigLocation); if (!systemRigDir.exists()) { qWarning() << "********* Rig directory does not exist ********"; } else { QStringList rigs = systemRigDir.entryList(QStringList() << "*.rig" << "*.RIG", QDir::Files); foreach (QString rig, rigs) { QSettings* rigSettings = new QSettings(systemRigDir.absoluteFilePath(rig), QSettings::Format::IniFormat); if (!rigSettings->childGroups().contains("Rig")) { qWarning() << rig << "Does not seem to be a rig description file"; delete rigSettings; continue; } rigSettings->beginGroup("Rig"); qDebug() << QString("Found Rig %0 with CI-V address of %1").arg(rigSettings->value("Model","").toString(), rigSettings->value("CIVAddress",0).toString()); // Any user modified rig files will override system provided ones. this->rigList.insert(rigSettings->value("CIVAddress",0).toInt(),systemRigDir.absoluteFilePath(rig)); rigSettings->endGroup(); delete rigSettings; } } QString userRigLocation = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation)+"/rigs"; QDir userRigDir(userRigLocation); if (userRigDir.exists()){ QStringList rigs = userRigDir.entryList(QStringList() << "*.rig" << "*.RIG", QDir::Files); foreach (QString rig, rigs) { QSettings* rigSettings = new QSettings(userRigDir.absoluteFilePath(rig), QSettings::Format::IniFormat); if (!rigSettings->childGroups().contains("Rig")) { qWarning() << rig << "Does not seem to be a rig description file"; delete rigSettings; continue; } rigSettings->beginGroup("Rig"); qDebug() << QString("Found User Rig %0 with CI-V address of %1").arg(rigSettings->value("Model","").toString(), rigSettings->value("CIVAddress",0).toString()); // Any user modified rig files will override system provided ones. this->rigList.insert(rigSettings->value("CIVAddress",0).toInt(),userRigDir.absoluteFilePath(rig)); rigSettings->endGroup(); delete rigSettings; } } ui->subScope->setVisible(false); // Disable sub scope until we need it setupKeyShortcuts(); setupMainUI(); connectSettingsWidget(); setSerialDevicesUI(); setDefPrefs(); getSettingsFilePath(settingsFile); setDefaultColorPresets(); loadSettings(); // Look for saved preferences //setAudioDevicesUI(); // no need to call this as it will be called by the updated() signal setTuningSteps(); // TODO: Combine into preferences qDebug(logSystem()) << "Running setUIToPrefs()"; setUIToPrefs(); qDebug(logSystem()) << "Running setInititalTiming()"; setInitialTiming(); qDebug(logSystem()) << "Running openRig()"; openRig(); cluster = new dxClusterClient(); clusterThread = new QThread(this); clusterThread->setObjectName("dxcluster()"); cluster->moveToThread(clusterThread); connect(this, SIGNAL(setClusterEnableUdp(bool)), cluster, SLOT(enableUdp(bool))); connect(this, SIGNAL(setClusterEnableTcp(bool)), cluster, SLOT(enableTcp(bool))); connect(this, SIGNAL(setClusterUdpPort(int)), cluster, SLOT(setUdpPort(int))); connect(this, SIGNAL(setClusterServerName(QString)), cluster, SLOT(setTcpServerName(QString))); connect(this, SIGNAL(setClusterTcpPort(int)), cluster, SLOT(setTcpPort(int))); connect(this, SIGNAL(setClusterUserName(QString)), cluster, SLOT(setTcpUserName(QString))); connect(this, SIGNAL(setClusterPassword(QString)), cluster, SLOT(setTcpPassword(QString))); connect(this, SIGNAL(setClusterTimeout(int)), cluster, SLOT(setTcpTimeout(int))); connect(this, SIGNAL(setClusterSkimmerSpots(bool)), cluster, SLOT(enableSkimmerSpots(bool))); connect(ui->mainScope, SIGNAL(frequencyRange(bool, double, double)), cluster, SLOT(freqRange(bool, double, double))); connect(ui->subScope, SIGNAL(frequencyRange(bool, double, double)), cluster, SLOT(freqRange(bool, double, double))); connect(cluster, SIGNAL(sendMainSpots(QList)), ui->mainScope, SLOT(receiveSpots(QList))); connect(cluster, SIGNAL(sendSubSpots(QList)), ui->subScope, SLOT(receiveSpots(QList))); connect(cluster, SIGNAL(sendOutput(QString)), this, SLOT(receiveClusterOutput(QString))); connect(clusterThread, SIGNAL(finished()), cluster, SLOT(deleteLater())); clusterThread->start(); emit setClusterUdpPort(prefs.clusterUdpPort); emit setClusterEnableUdp(prefs.clusterUdpEnable); for (int f = 0; f < prefs.clusters.size(); f++) { if (prefs.clusters[f].isdefault) { emit setClusterServerName(prefs.clusters[f].server); emit setClusterTcpPort(prefs.clusters[f].port); emit setClusterUserName(prefs.clusters[f].userName); emit setClusterPassword(prefs.clusters[f].password); emit setClusterTimeout(prefs.clusters[f].timeout); emit setClusterSkimmerSpots(prefs.clusterSkimmerSpotsEnable); } } emit setClusterEnableTcp(prefs.clusterTcpEnable); setServerToPrefs(); amTransmitting = false; connect(ui->txPowerSlider, &QSlider::sliderMoved, [&](int value) { QToolTip::showText(QCursor::pos(), QString("%1").arg(value*100/255), nullptr); }); #if defined(USB_CONTROLLER) #if defined(USB_HOTPLUG) && defined(Q_OS_LINUX) uDev = udev_new(); if (!uDev) { qInfo(logUsbControl()) << "Cannot register udev, hotplug of USB devices is not available"; return; } uDevMonitor = udev_monitor_new_from_netlink(uDev, "udev"); if (!uDevMonitor) { qInfo(logUsbControl()) << "Cannot register udev_monitor, hotplug of USB devices is not available"; return; } int fd = udev_monitor_get_fd(uDevMonitor); uDevNotifier = new QSocketNotifier(fd, QSocketNotifier::Read,this); connect(uDevNotifier, SIGNAL(activated(int)), this, SLOT(uDevEvent())); udev_monitor_enable_receiving(uDevMonitor); #endif #endif } wfmain::~wfmain() { if(rigThread != Q_NULLPTR) { rigThread->quit(); rigThread->wait(); } if (serverThread != Q_NULLPTR) { serverThread->quit(); serverThread->wait(); } if (clusterThread != Q_NULLPTR) { clusterThread->quit(); clusterThread->wait(); } if (tciThread != Q_NULLPTR) { tciThread->quit(); tciThread->wait(); } if (rigCtl != Q_NULLPTR) { delete rigCtl; } if (colorPrefs != Q_NULLPTR) { delete colorPrefs; } delete rpt; delete ui; delete settings; #if defined(USB_CONTROLLER) if (usbControllerThread != Q_NULLPTR) { usbControllerThread->quit(); usbControllerThread->wait(); } #if defined(Q_OS_LINUX) if (uDevMonitor) { udev_monitor_unref(uDevMonitor); udev_unref(uDev); delete uDevNotifier; } #endif #endif } void wfmain::closeEvent(QCloseEvent *event) { if (on_exitBtn_clicked()) event->ignore(); } void wfmain::openRig() { // This function is intended to handle opening a connection to the rig. // the connection can be either serial or network, // and this function is also responsible for initiating the search for a rig model and capabilities. // Any errors, such as unable to open connection or unable to open port, are to be reported to the user. //TODO: if(hasRunPreviously) //TODO: if(useNetwork){... // } else { // if (prefs.fileWasNotFound) { // showRigSettings(); // rig setting dialog box for network/serial, CIV, hostname, port, baud rate, serial device, etc // TODO: How do we know if the setting was loaded? emit connectionStatus(true); // Signal any other parts that need to know if we are connecting/connected. ui->connectBtn->setText("Cancel connection"); // We are attempting to connect connStatus = connConnecting; makeRig(); if (prefs.enableLAN) { usingLAN = true; // "We need to setup the tx/rx audio: udpPrefs.waterfallFormat = prefs.waterfallFormat; emit sendCommSetup(rigList, prefs.radioCIVAddr, udpPrefs, prefs.rxSetup, prefs.txSetup, prefs.virtualSerialPort, prefs.tcpPort); } else { if( (prefs.serialPortRadio.toLower() == QString("auto"))) { findSerialPort(); } else { serialPortRig = prefs.serialPortRadio; } usingLAN = false; emit sendCommSetup(rigList, prefs.radioCIVAddr, serialPortRig, prefs.serialPortBaud,prefs.virtualSerialPort, prefs.tcpPort,prefs.waterfallFormat); ui->statusBar->showMessage(QString("Connecting to rig using serial port ").append(serialPortRig), 1000); } } // Deprecated (moved to makeRig()) void wfmain::rigConnections() { } void wfmain::makeRig() { if (rigThread == Q_NULLPTR) { rig = new rigCommander(); rigThread = new QThread(this); rigThread->setObjectName("rigCommander()"); // Thread: rig->moveToThread(rigThread); connect(rigThread, SIGNAL(started()), rig, SLOT(process())); connect(rigThread, SIGNAL(finished()), rig, SLOT(deleteLater())); rigThread->start(); // Rig status and Errors: connect(rig, SIGNAL(havePortError(errorType)), this, SLOT(receivePortError(errorType))); connect(rig, SIGNAL(haveStatusUpdate(networkStatus)), this, SLOT(receiveStatusUpdate(networkStatus))); connect(rig, SIGNAL(haveNetworkAudioLevels(networkAudioLevels)), this, SLOT(receiveNetworkAudioLevels(networkAudioLevels))); connect(rig, SIGNAL(requestRadioSelection(QList)), this, SLOT(radioSelection(QList))); connect(rig, SIGNAL(setRadioUsage(quint8, quint8, QString, QString)), selRad, SLOT(setInUse(quint8, quint8, QString, QString))); connect(selRad, SIGNAL(selectedRadio(quint8)), rig, SLOT(setCurrentRadio(quint8))); // Rig comm setup: connect(this, SIGNAL(sendCommSetup(rigTypedef,unsigned char, udpPreferences, audioSetup, audioSetup, QString, quint16)), rig, SLOT(commSetup(rigTypedef,unsigned char, udpPreferences, audioSetup, audioSetup, QString, quint16))); connect(this, SIGNAL(sendCommSetup(rigTypedef,unsigned char, QString, quint32,QString, quint16,quint8)), rig, SLOT(commSetup(rigTypedef,unsigned char, QString, quint32,QString, quint16,quint8))); connect(this, SIGNAL(setRTSforPTT(bool)), rig, SLOT(setRTSforPTT(bool))); connect(rig, SIGNAL(haveBaudRate(quint32)), this, SLOT(receiveBaudRate(quint32))); connect(this, SIGNAL(sendCloseComm()), rig, SLOT(closeComm())); connect(this, SIGNAL(sendChangeLatency(quint16)), rig, SLOT(changeLatency(quint16))); connect(this, SIGNAL(getRigCIV()), rig, SLOT(findRigs())); connect(this, SIGNAL(setRigID(unsigned char)), rig, SLOT(setRigID(unsigned char))); connect(rig, SIGNAL(discoveredRigID(rigCapabilities)), this, SLOT(receiveFoundRigID(rigCapabilities))); connect(rig, SIGNAL(commReady()), this, SLOT(receiveCommReady())); connect(this, SIGNAL(setCIVAddr(unsigned char)), rig, SLOT(setCIVAddr(unsigned char))); connect(this, SIGNAL(sendPowerOn()), rig, SLOT(powerOn())); connect(this, SIGNAL(sendPowerOff()), rig, SLOT(powerOff())); connect(this, SIGNAL(getDebug()), rig, SLOT(getDebug())); // Repeater, duplex, and split: //connect(rpt, SIGNAL(getDuplexMode()), rig, SLOT(getDuplexMode())); //connect(rpt, SIGNAL(setDuplexMode(duplexMode_t)), rig, SLOT(setDuplexMode(duplexMode_t))); //connect(rig, SIGNAL(haveDuplexMode(duplexMode_t)), rpt, SLOT(receiveDuplexMode(duplexMode_t))); //connect(this, SIGNAL(getRptDuplexOffset()), rig, SLOT(getRptDuplexOffset())); connect(rig, SIGNAL(haveRptOffsetFrequency(freqt)), rpt, SLOT(handleRptOffsetFrequency(freqt))); // Memories //connect(this, SIGNAL(setMemoryMode()), rig, SLOT(setMemoryMode())); //connect(this, SIGNAL(setSatelliteMode(bool)), rig, SLOT(setSatelliteMode(bool))); //connect(this, SIGNAL(getMemory(quint32)), rig, SLOT(getMemory(quint32))); //connect(this, SIGNAL(getSatMemory(quint32)), rig, SLOT(getSatMemory(quint32))); //connect(this, SIGNAL(setMemory(memoryType)), rig, SLOT(setMemory(memoryType))); //connect(this, SIGNAL(clearMemory(quint32)), rig, SLOT(clearMemory(quint32))); //connect(this, SIGNAL(recallMemory(quint32)), rig, SLOT(recallMemory(quint32))); connect(this->rpt, &repeaterSetup::setDuplexMode, this->rig, [=](const duplexMode_t &t) { queue->add(priorityImmediate,queueItem(funcSplitStatus,QVariant::fromValue(t),false));}); connect(this->rpt, &repeaterSetup::getTone, this->rig, [=]() { queue->add(priorityImmediate,funcRepeaterTone,false,false);}); connect(this->rpt, &repeaterSetup::setTSQL, this->rig, [=](const toneInfo& t) { queue->add(priorityImmediate,queueItem(funcTSQLFreq,QVariant::fromValue(t),false));}); connect(this->rpt, &repeaterSetup::getTSQL, this->rig, [=]() { queue->add(priorityImmediate,funcRepeaterTSQL,false,false);}); connect(this->rpt, &repeaterSetup::setDTCS, this->rig, [=](const toneInfo& t) { queue->add(priorityImmediate,queueItem(funcRepeaterDTCS,QVariant::fromValue(t),false));}); connect(this->rpt, &repeaterSetup::getDTCS, this->rig, [=]() { queue->add(priorityImmediate,funcRepeaterDTCS,false,false);}); connect(this->rpt, &repeaterSetup::getRptAccessMode, this->rig, [=]() { if (rigCaps.commands.contains(funcToneSquelchType)) { queue->add(priorityImmediate,funcToneSquelchType,false,false); } else { queue->add(priorityImmediate,funcRepeaterTone,false,false); queue->add(priorityImmediate,funcRepeaterTSQL,false,false); } }); connect(this->rpt, &repeaterSetup::setQuickSplit, this->rig, [=](const bool &qsEnabled) { queue->add(priorityImmediate,queueItem(funcQuickSplit,QVariant::fromValue(qsEnabled),false)); }); connect(this->rpt, &repeaterSetup::setRptAccessMode, this->rig, [=](const rptrAccessData &rd) { queue->add(priorityImmediate,queueItem(funcToneSquelchType,QVariant::fromValue(rd),false)); }); connect(this->rig, &rigCommander::haveDuplexMode, this->rpt, [=](const duplexMode_t &dm) { if(dm==dmSplitOn) this->splitModeEnabled = true; else this->splitModeEnabled = false; }); connect(this->rpt, &repeaterSetup::setTransmitFrequency, this->rig, [=](const freqt &transmitFreq) { queue->add(priorityImmediate,queueItem(funcFreqSet,QVariant::fromValue(transmitFreq),false));}); connect(this->rpt, &repeaterSetup::setTransmitMode, this->rig, [=](const modeInfo &transmitMode) { queue->add(priorityImmediate,queueItem(funcModeSet,QVariant::fromValue(transmitMode),false));}); connect(this->rpt, &repeaterSetup::selectVFO, this->rig, [=](const vfo_t &v) { queue->add(priorityImmediate,queueItem(funcSelectVFO,QVariant::fromValue(v),false));}); connect(this->rpt, &repeaterSetup::equalizeVFOsAB, this->rig, [=]() { queue->add(priorityImmediate,funcVFOEqualAB,false,false);}); connect(this->rpt, &repeaterSetup::equalizeVFOsMS, this->rig, [=]() { queue->add(priorityImmediate,funcVFOEqualMS,false,false);}); connect(this->rpt, &repeaterSetup::swapVFOs, this->rig, [=]() { queue->add(priorityImmediate,funcVFOSwapMS,false,false);}); connect(this->rpt, &repeaterSetup::setRptDuplexOffset, this->rig, [=](const freqt &fOffset) { queue->add(priorityImmediate,queueItem(funcSendFreqOffset,QVariant::fromValue(fOffset),false));}); connect(this->rpt, &repeaterSetup::getRptDuplexOffset, this->rig, [=]() { queue->add(priorityImmediate,funcReadFreqOffset,false,false);}); connect(this, SIGNAL(setAfGain(unsigned char)), rig, SLOT(setAfGain(unsigned char))); connect(ui->mainScope, SIGNAL(updateSettings(bool,int,quint16,int,int)), this, SLOT(receiveScopeSettings(bool,int,quint16,int,int))); connect(ui->subScope, SIGNAL(updateSettings(bool,int,quint16,int,int)), this, SLOT(receiveScopeSettings(bool,int,quint16,int,int))); connect(ui->mainScope, SIGNAL(elapsedTime(bool,qint64)), this, SLOT(receiveElapsed(bool,qint64))); connect(ui->subScope, SIGNAL(elapsedTime(bool,qint64)), this, SLOT(receiveElapsed(bool,qint64))); connect(ui->mainScope, SIGNAL(dataChanged(modeInfo)), this, SLOT(dataModeChanged(modeInfo))); // Create link for server so it can have easy access to rig. if (serverConfig.rigs.first() != Q_NULLPTR) { serverConfig.rigs.first()->rig = rig; serverConfig.rigs.first()->rigThread = rigThread; } } } void wfmain::removeRig() { if (rigThread != Q_NULLPTR) { rigThread->quit(); rigThread->wait(); rig = Q_NULLPTR; rigThread = Q_NULLPTR; } } void wfmain::findSerialPort() { // Find the ICOM radio connected, or, if none, fall back to OS default. // qInfo(logSystem()) << "Searching for serial port..."; bool found = false; // First try to find first Icom port: foreach(const QSerialPortInfo & serialPortInfo, QSerialPortInfo::availablePorts()) { if (serialPortInfo.serialNumber().left(3) == "IC-") { qInfo(logSystem()) << "Serial Port found: " << serialPortInfo.portName() << "Manufacturer:" << serialPortInfo.manufacturer() << "Product ID" << serialPortInfo.description() << "S/N" << serialPortInfo.serialNumber(); #if defined(Q_OS_LINUX) || defined(Q_OS_MAC) serialPortRig = (QString("/dev/") + serialPortInfo.portName()); #else serialPortRig = serialPortInfo.portName(); #endif found = true; break; } } if (!found) { QDirIterator it73("/dev/serial/by-id", QStringList() << "*IC-7300*", QDir::Files, QDirIterator::Subdirectories); QDirIterator it97("/dev/serial", QStringList() << "*IC-9700*A*", QDir::Files, QDirIterator::Subdirectories); QDirIterator it785x("/dev/serial", QStringList() << "*IC-785*A*", QDir::Files, QDirIterator::Subdirectories); QDirIterator it705("/dev/serial", QStringList() << "*IC-705*A", QDir::Files, QDirIterator::Subdirectories); QDirIterator it7610("/dev/serial", QStringList() << "*IC-7610*A", QDir::Files, QDirIterator::Subdirectories); QDirIterator itR8600("/dev/serial", QStringList() << "*IC-R8600*A", QDir::Files, QDirIterator::Subdirectories); if(!it73.filePath().isEmpty()) { // IC-7300 serialPortRig = it73.filePath(); // first } else if(!it97.filePath().isEmpty()) { // IC-9700 serialPortRig = it97.filePath(); } else if(!it785x.filePath().isEmpty()) { // IC-785x serialPortRig = it785x.filePath(); } else if(!it705.filePath().isEmpty()) { // IC-705 serialPortRig = it705.filePath(); } else if(!it7610.filePath().isEmpty()) { // IC-7610 serialPortRig = it7610.filePath(); } else if(!itR8600.filePath().isEmpty()) { // IC-R8600 serialPortRig = itR8600.filePath(); } else { //fall back: qInfo(logSystem()) << "Could not find Icom serial port. Falling back to OS default. Use --port to specify, or modify preferences."; #ifdef Q_OS_MAC serialPortRig = QString("/dev/tty.SLAB_USBtoUART"); #endif #ifdef Q_OS_LINUX serialPortRig = QString("/dev/ttyUSB0"); #endif #ifdef Q_OS_WIN serialPortRig = QString("COM1"); #endif } } } void wfmain::receiveCommReady() { qInfo(logSystem()) << "Received CommReady!! "; if(!usingLAN) { // usingLAN gets set when we emit the sendCommSetup signal. // If we're not using the LAN, then we're on serial, and // we already know the baud rate and can calculate the timing parameters. calculateTimingParameters(); } if(prefs.radioCIVAddr == 0) { // tell rigCommander to broadcast a request for all rig IDs. // qInfo(logSystem()) << "Beginning search from wfview for rigCIV (auto-detection broadcast)"; ui->statusBar->showMessage(QString("Searching CI-V bus for connected radios."), 1000); //emit getRigCIV(); //queue->add(priorityImmediate,funcTransceiverId,false); queue->addUnique(priorityHighest,funcTransceiverId,true); //issueDelayedCommand(cmdGetRigCIV); //delayedCommand->start(); } else { // don't bother, they told us the CIV they want, stick with it. // We still query the rigID to find the model, but at least we know the CIV. qInfo(logSystem()) << "Skipping automatic CIV, using user-supplied value of " << prefs.radioCIVAddr; showStatusBarText(QString("Using user-supplied radio CI-V address of 0x%1").arg(prefs.radioCIVAddr, 2, 16)); if(prefs.CIVisRadioModel) { qInfo(logSystem()) << "Skipping Rig ID query, using user-supplied model from CI-V address: " << prefs.radioCIVAddr; emit setCIVAddr(prefs.radioCIVAddr); emit setRigID(prefs.radioCIVAddr); } else { emit setCIVAddr(prefs.radioCIVAddr); //emit getRigCIV(); //queue->add(priorityImmediate,funcTransceiverId,false); queue->addUnique(priorityHighest,funcTransceiverId,true); //emit getRigID(); //issueDelayedCommand(cmdGetRigID); //delayedCommand->start(); } } } void wfmain::receiveFoundRigID(rigCapabilities rigCaps) { // Entry point for unknown rig being identified at the start of the program. //now we know what the rig ID is: //qInfo(logSystem()) << "In wfview, we now have a reply to our request for rig identity sent to CIV BROADCAST."; receiveRigID(rigCaps); initPeriodicCommands(); getInitialRigState(); return; } void wfmain::receivePortError(errorType err) { if (err.alert) { connectionHandler(false); // Force disconnect QMessageBox::critical(this, err.device, err.message, QMessageBox::Ok); } else { qInfo(logSystem()) << "wfmain: received error for device: " << err.device << " with message: " << err.message; ui->statusBar->showMessage(QString("ERROR: using device ").append(err.device).append(": ").append(err.message), 10000); } // TODO: Dialog box, exit, etc } void wfmain::receiveStatusUpdate(networkStatus status) { //this->rigStatus->setText(QString("%0/%1 %2").arg(mainElapsed).arg(subElapsed).arg(status.message)); this->rigStatus->setText(status.message); selRad->audioOutputLevel(status.rxAudioLevel); selRad->audioInputLevel(status.txAudioLevel); //qInfo(logSystem()) << "Got Status Update" << status.rxAudioLevel; } void wfmain::receiveNetworkAudioLevels(networkAudioLevels l) { /* meter_t m2mtr = ui->meter2Widget->getMeterType(); if(m2mtr == meterAudio) { if(amTransmitting) { if(l.haveTxLevels) ui->meter2Widget->setLevels(l.txAudioRMS, l.txAudioPeak); } else { if(l.haveRxLevels) ui->meter2Widget->setLevels(l.rxAudioRMS, l.rxAudioPeak); } } else if (m2mtr == meterTxMod) { if(l.haveTxLevels) ui->meter2Widget->setLevels(l.txAudioRMS, l.txAudioPeak); } else if (m2mtr == meterRxAudio) { if(l.haveRxLevels) ui->meter2Widget->setLevels(l.rxAudioRMS, l.rxAudioPeak); } */ meter_t m = meterNone; if(l.haveRxLevels) { m = meterRxAudio; receiveMeter(m, l.rxAudioPeak); } if(l.haveTxLevels) { m = meterTxMod; receiveMeter(m, l.txAudioPeak); } } void wfmain::setupMainUI() { ui->meter2Widget->hide(); // Future ideas: //ui->meter2selectionCombo->addItem("Transmit Audio", meterTxMod); //ui->meter2selectionCombo->addItem("Receive Audio", meterRxAudio); //ui->meter2selectionCombo->addItem("Latency", meterLatency); // Set scroll wheel response (tick interval) // and set arrow key response (single step) ui->rfGainSlider->setTickInterval(100); ui->rfGainSlider->setSingleStep(10); ui->afGainSlider->setTickInterval(100); ui->afGainSlider->setSingleStep(10); ui->sqlSlider->setTickInterval(100); ui->sqlSlider->setSingleStep(10); ui->txPowerSlider->setTickInterval(100); ui->txPowerSlider->setSingleStep(10); ui->micGainSlider->setTickInterval(100); ui->micGainSlider->setSingleStep(10); ui->monitorSlider->setTickInterval(100); ui->monitorSlider->setSingleStep(10); // Keep this code when the rest is removed from this function: qDebug(logSystem()) << "Running with debugging options enabled."; rigStatus = new QLabel(this); ui->statusBar->addPermanentWidget(rigStatus); ui->statusBar->showMessage("Connecting to rig...", 1000); pttLed = new QLedLabel(this); ui->statusBar->addPermanentWidget(pttLed); pttLed->setState(QLedLabel::State::StateOk); pttLed->setToolTip("Receiving"); connectedLed = new QLedLabel(this); ui->statusBar->addPermanentWidget(connectedLed); rigName = new QLabel(this); rigName->setAlignment(Qt::AlignRight); ui->statusBar->addPermanentWidget(rigName); rigName->setText("NONE"); rigName->setFixedWidth(60); freqt f; f.MHzDouble = 0.0; f.Hz = 0; ui->mainScope->setIdentity("Main Band",false); ui->subScope->setIdentity("Sub Band",true); connect(ui->mainScope,SIGNAL(showStatusBarText(QString)),this,SLOT(showStatusBarText(QString))); connect(ui->subScope,SIGNAL(showStatusBarText(QString)),this,SLOT(showStatusBarText(QString))); oldFreqDialVal = ui->freqDial->value(); ui->tuneLockChk->setChecked(false); freqLock = false; connect( ui->txPowerSlider, &QSlider::valueChanged, this, [=](const int &newValue) { statusFromSliderPercent("Tx Power", newValue);} ); connect( ui->rfGainSlider, &QSlider::valueChanged, this, [=](const int &newValue) { statusFromSliderPercent("RF Gain", newValue);} ); connect( ui->afGainSlider, &QSlider::valueChanged, this, [=](const int &newValue) { statusFromSliderPercent("AF Gain", newValue);} ); connect( ui->micGainSlider, &QSlider::valueChanged, this, [=](const int &newValue) { statusFromSliderPercent("TX Audio Gain", newValue);} ); connect( ui->sqlSlider, &QSlider::valueChanged, this, [=](const int &newValue) { statusFromSliderPercent("Squelch", newValue);} ); /* connect(this->cw, &cwSender::sendCW, [=](const QString &cwMessage) { issueCmd(cmdSendCW, cwMessage);}); connect(this->cw, &cwSender::stopCW, [=]() { issueDelayedCommand(cmdStopCW);}); connect(this->cw, &cwSender::setBreakInMode, [=](const unsigned char &bmode) { issueCmd(cmdSetBreakMode, bmode);}); connect(this->cw, &cwSender::setKeySpeed, [=](const unsigned char& wpm) { issueCmd(cmdSetKeySpeed, wpm); }); connect(this->cw, &cwSender::setPitch, [=](const unsigned char& pitch) { issueCmd(cmdSetCwPitch, pitch); }); connect(this->cw, &cwSender::getCWSettings, [=]() { issueDelayedCommand(cmdGetKeySpeed); issueDelayedCommand(cmdGetBreakMode);}); */ } void wfmain::connectSettingsWidget() { connect(setupui, SIGNAL(changedClusterPref(prefClusterItem)), this, SLOT(extChangedClusterPref(prefClusterItem))); connect(setupui, SIGNAL(changedClusterPrefs(quint64)), this, SLOT(extChangedClusterPrefs(quint64))); connect(setupui, SIGNAL(changedCtPref(prefCtItem)), this, SLOT(extChangedCtPref(prefCtItem))); connect(setupui, SIGNAL(changedCtPrefs(quint64)), this, SLOT(extChangedCtPrefs(quint64))); connect(setupui, SIGNAL(changedIfPref(prefIfItem)), this, SLOT(extChangedIfPref(prefIfItem))); connect(setupui, SIGNAL(changedIfPrefs(quint64)), this, SLOT(extChangedIfPrefs(quint64))); connect(setupui, SIGNAL(changedColPref(prefColItem)), this, SLOT(extChangedColPref(prefColItem))); connect(setupui, SIGNAL(changedColPrefs(quint64)), this, SLOT(extChangedColPrefs(quint64))); connect(setupui, SIGNAL(changedLanPref(prefLanItem)), this, SLOT(extChangedLanPref(prefLanItem))); connect(setupui, SIGNAL(changedLanPrefs(quint64)), this, SLOT(extChangedLanPrefs(quint64))); connect(setupui, SIGNAL(changedRaPref(prefRaItem)), this, SLOT(extChangedRaPref(prefRaItem))); connect(setupui, SIGNAL(changedRaPrefs(quint64)), this, SLOT(extChangedRaPrefs(quint64))); connect(setupui, SIGNAL(changedRsPref(prefRsItem)), this, SLOT(extChangedRsPref(prefRsItem))); connect(setupui, SIGNAL(changedRsPrefs(quint64)), this, SLOT(extChangedRsPrefs(quint64))); connect(setupui, SIGNAL(changedUdpPref(prefUDPItem)), this, SLOT(extChangedUdpPref(prefUDPItem))); connect(setupui, SIGNAL(changedUdpPrefs(quint64)), this, SLOT(extChangedUdpPrefs(quint64))); connect(setupui, SIGNAL(changedServerPref(prefServerItem)), this, SLOT(extChangedServerPref(prefServerItem))); connect(setupui, SIGNAL(changedServerPrefs(quint64)), this, SLOT(extChangedServerPrefs(quint64))); //connect(setupui, SIGNAL(changedAudioInputCombo(int)), this, SLOT(changedAudioInput(int))); //connect(setupui, SIGNAL(changedAudioOutputCombo(int)), this, SLOT(changedAudioOutput(int))); //connect(setupui, SIGNAL(changedServerRXAudioInputCombo(int)), this, SLOT(changedServerRXAudioInput(int))); //connect(setupui, SIGNAL(changedServerTXAudioOutputCombo(int)), this, SLOT(changedServerTXAudioOutput(int))); connect(this, SIGNAL(connectionStatus(bool)), setupui, SLOT(connectionStatus(bool))); } // NOT Migrated, EHL TODO, carefully remove this function void wfmain::getSettingsFilePath(QString settingsFile) { if (settingsFile.isNull()) { settings = new QSettings(); } else { QString file = settingsFile; QFile info(settingsFile); QString path=""; if (!QFileInfo(info).isAbsolute()) { path = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation); if (path.isEmpty()) { path = QDir::homePath(); } path = path + "/"; file = info.fileName(); } settings = new QSettings(path + file, QSettings::Format::IniFormat); } } void wfmain::setInitialTiming() { loopTickCounter = 0; delayedCmdIntervalLAN_ms = 70; // interval for regular delayed commands, including initial rig/UI state queries delayedCmdIntervalSerial_ms = 100; // interval for regular delayed commands, including initial rig/UI state queries delayedCmdStartupInterval_ms = 250; // interval for rigID polling delayedCommand = new QTimer(this); queue->interval(delayedCmdStartupInterval_ms); pttTimer = new QTimer(this); pttTimer->setInterval(180*1000); // 3 minute max transmit time in ms pttTimer->setSingleShot(true); connect(pttTimer, SIGNAL(timeout()), this, SLOT(handlePttLimit())); timeSync = new QTimer(this); connect(timeSync, SIGNAL(timeout()), this, SLOT(setRadioTimeDateSend())); waitingToSetTimeDate = false; lastFreqCmdTime_ms = QDateTime::currentMSecsSinceEpoch() - 5000; // 5 seconds ago } void wfmain::setServerToPrefs() { // Start server if enabled in config //ui->serverSetupGroup->setEnabled(serverConfig.enabled); if (serverThread != Q_NULLPTR) { serverThread->quit(); serverThread->wait(); serverThread = Q_NULLPTR; udp = Q_NULLPTR; ui->statusBar->showMessage(QString("Server disabled"), 1000); } if (serverConfig.enabled) { serverConfig.lan = prefs.enableLAN; udp = new udpServer(&serverConfig); serverThread = new QThread(this); udp->moveToThread(serverThread); connect(this, SIGNAL(initServer()), udp, SLOT(init())); connect(serverThread, SIGNAL(finished()), udp, SLOT(deleteLater())); if (rig != Q_NULLPTR) { connect(rig, SIGNAL(haveAudioData(audioPacket)), udp, SLOT(receiveAudioData(audioPacket))); // Need to add a signal/slot for audio from the client to rig. //connect(udp, SIGNAL(haveAudioData(audioPacket)), rig, SLOT(receiveAudioData(audioPacket))); connect(rig, SIGNAL(haveDataForServer(QByteArray)), udp, SLOT(dataForServer(QByteArray))); connect(udp, SIGNAL(haveDataFromServer(QByteArray)), rig, SLOT(dataFromServer(QByteArray))); } if (serverConfig.lan) { connect(udp, SIGNAL(haveNetworkStatus(networkStatus)), this, SLOT(receiveStatusUpdate(networkStatus))); } else { qInfo(logAudio()) << "Audio Input device " << serverConfig.rigs.first()->rxAudioSetup.name; qInfo(logAudio()) << "Audio Output device " << serverConfig.rigs.first()->txAudioSetup.name; } serverThread->start(); emit initServer(); connect(this, SIGNAL(sendRigCaps(rigCapabilities)), udp, SLOT(receiveRigCaps(rigCapabilities))); ui->statusBar->showMessage(QString("Server enabled"), 1000); } } void wfmain::setUIToPrefs() { //ui->fullScreenChk->setChecked(prefs.useFullScreen); changeFullScreenMode(prefs.useFullScreen); //ui->useSystemThemeChk->setChecked(prefs.useSystemTheme); useSystemTheme(prefs.useSystemTheme); ui->mainScope->setUnderlayMode(prefs.underlayMode); ui->mainScope->wfAntiAliased(prefs.wfAntiAlias); ui->mainScope->wfInterpolate(prefs.wfInterpolate); ui->mainScope->wfTheme(prefs.mainWfTheme); ui->mainScope->setScrollSpeedXY(prefs.scopeScrollX, prefs.scopeScrollY); ui->subScope->setUnderlayMode(prefs.underlayMode); ui->subScope->wfAntiAliased(prefs.wfAntiAlias); ui->subScope->wfInterpolate(prefs.wfInterpolate); ui->subScope->wfTheme(prefs.subWfTheme); ui->subScope->setScrollSpeedXY(prefs.scopeScrollX, prefs.scopeScrollY); // switch(underlayMode) // { // case underlayNone: // ui->underlayNone->setChecked(true); // break; // case underlayPeakHold: // ui->underlayPeakHold->setChecked(true); // break; // case underlayPeakBuffer: // ui->underlayPeakBuffer->setChecked(true); // break; // case underlayAverageBuffer: // ui->underlayAverageBuffer->setChecked(true); // break; // default: // break; // } ui->mainScope->prepareWf(prefs.mainWflength); ui->mainScope->preparePlasma(); ui->subScope->prepareWf(prefs.subWflength); ui->subScope->preparePlasma(); ui->mainScope->setRange(prefs.mainPlotFloor, prefs.mainPlotCeiling); ui->subScope->setRange(prefs.subPlotFloor, prefs.subPlotCeiling); ui->mainScope->wfTheme(prefs.mainWfTheme); ui->subScope->wfTheme(prefs.subWfTheme); finputbtns->setAutomaticSidebandSwitching(prefs.automaticSidebandSwitching); } void wfmain::setSerialDevicesUI() { } void wfmain::setupKeyShortcuts() { keyF1 = new QShortcut(this); keyF1->setKey(Qt::Key_F1); connect(keyF1, SIGNAL(activated()), this, SLOT(shortcutF1())); keyF2 = new QShortcut(this); keyF2->setKey(Qt::Key_F2); connect(keyF2, SIGNAL(activated()), this, SLOT(shortcutF2())); keyF3 = new QShortcut(this); keyF3->setKey(Qt::Key_F3); connect(keyF3, SIGNAL(activated()), this, SLOT(shortcutF3())); keyF4 = new QShortcut(this); keyF4->setKey(Qt::Key_F4); connect(keyF4, SIGNAL(activated()), this, SLOT(shortcutF4())); keyF5 = new QShortcut(this); keyF5->setKey(Qt::Key_F5); connect(keyF5, SIGNAL(activated()), this, SLOT(shortcutF5())); keyF6 = new QShortcut(this); keyF6->setKey(Qt::Key_F6); connect(keyF6, SIGNAL(activated()), this, SLOT(shortcutF6())); keyF7 = new QShortcut(this); keyF7->setKey(Qt::Key_F7); connect(keyF7, SIGNAL(activated()), this, SLOT(shortcutF7())); keyF8 = new QShortcut(this); keyF8->setKey(Qt::Key_F8); connect(keyF8, SIGNAL(activated()), this, SLOT(shortcutF8())); keyF9 = new QShortcut(this); keyF9->setKey(Qt::Key_F9); connect(keyF9, SIGNAL(activated()), this, SLOT(shortcutF9())); keyF10 = new QShortcut(this); keyF10->setKey(Qt::Key_F10); connect(keyF10, SIGNAL(activated()), this, SLOT(shortcutF10())); keyF11 = new QShortcut(this); keyF11->setKey(Qt::Key_F11); connect(keyF11, SIGNAL(activated()), this, SLOT(shortcutF11())); keyF12 = new QShortcut(this); keyF12->setKey(Qt::Key_F12); connect(keyF12, SIGNAL(activated()), this, SLOT(shortcutF12())); keyControlT = new QShortcut(this); keyControlT->setKey(Qt::CTRL | Qt::Key_T); connect(keyControlT, SIGNAL(activated()), this, SLOT(shortcutControlT())); keyControlR = new QShortcut(this); keyControlR->setKey(Qt::CTRL | Qt::Key_R); connect(keyControlR, SIGNAL(activated()), this, SLOT(shortcutControlR())); keyControlI = new QShortcut(this); keyControlI->setKey(Qt::CTRL | Qt::Key_I); connect(keyControlI, SIGNAL(activated()), this, SLOT(shortcutControlI())); keyControlU = new QShortcut(this); keyControlU->setKey(Qt::CTRL | Qt::Key_U); connect(keyControlU, SIGNAL(activated()), this, SLOT(shortcutControlU())); keyStar = new QShortcut(this); keyStar->setKey(Qt::Key_Asterisk); connect(keyStar, SIGNAL(activated()), this, SLOT(shortcutStar())); keySlash = new QShortcut(this); keySlash->setKey(Qt::Key_Slash); connect(keySlash, SIGNAL(activated()), this, SLOT(shortcutSlash())); keyMinus = new QShortcut(this); keyMinus->setKey(Qt::Key_Minus); connect(keyMinus, SIGNAL(activated()), this, SLOT(shortcutMinus())); keyPlus = new QShortcut(this); keyPlus->setKey(Qt::Key_Plus); connect(keyPlus, SIGNAL(activated()), this, SLOT(shortcutPlus())); keyShiftMinus = new QShortcut(this); keyShiftMinus->setKey(Qt::SHIFT | Qt::Key_Minus); connect(keyShiftMinus, SIGNAL(activated()), this, SLOT(shortcutShiftMinus())); keyShiftPlus = new QShortcut(this); keyShiftPlus->setKey(Qt::SHIFT | Qt::Key_Plus); connect(keyShiftPlus, SIGNAL(activated()), this, SLOT(shortcutShiftPlus())); keyControlMinus = new QShortcut(this); keyControlMinus->setKey(Qt::CTRL | Qt::Key_Minus); connect(keyControlMinus, SIGNAL(activated()), this, SLOT(shortcutControlMinus())); keyControlPlus = new QShortcut(this); keyControlPlus->setKey(Qt::CTRL | Qt::Key_Plus); connect(keyControlPlus, SIGNAL(activated()), this, SLOT(shortcutControlPlus())); keyQuit = new QShortcut(this); keyQuit->setKey(Qt::CTRL | Qt::Key_Q); connect(keyQuit, SIGNAL(activated()), this, SLOT(on_exitBtn_clicked())); keyPageUp = new QShortcut(this); keyPageUp->setKey(Qt::Key_PageUp); connect(keyPageUp, SIGNAL(activated()), this, SLOT(shortcutPageUp())); keyPageDown = new QShortcut(this); keyPageDown->setKey(Qt::Key_PageDown); connect(keyPageDown, SIGNAL(activated()), this, SLOT(shortcutPageDown())); keyF = new QShortcut(this); keyF->setKey(Qt::Key_F); connect(keyF, SIGNAL(activated()), this, SLOT(shortcutF())); keyM = new QShortcut(this); keyM->setKey(Qt::Key_M); connect(keyM, SIGNAL(activated()), this, SLOT(shortcutM())); // Alternate for plus: keyK = new QShortcut(this); keyK->setKey(Qt::Key_K); connect(keyK, &QShortcut::activated, [=]() { if (freqLock) return; this->shortcutPlus(); }); // Alternate for minus: keyJ = new QShortcut(this); keyJ->setKey(Qt::Key_J); connect(keyJ, &QShortcut::activated, [=]() { if (freqLock) return; this->shortcutMinus(); }); keyShiftK = new QShortcut(this); keyShiftK->setKey(Qt::SHIFT | Qt::Key_K); connect(keyShiftK, &QShortcut::activated, [=]() { if (freqLock) return; this->shortcutShiftPlus(); }); keyShiftJ = new QShortcut(this); keyShiftJ->setKey(Qt::SHIFT | Qt::Key_J); connect(keyShiftJ, &QShortcut::activated, [=]() { if (freqLock) return; this->shortcutShiftMinus(); }); keyControlK = new QShortcut(this); keyControlK->setKey(Qt::CTRL | Qt::Key_K); connect(keyControlK, &QShortcut::activated, [=]() { if (freqLock) return; this->shortcutControlPlus(); }); keyControlJ = new QShortcut(this); keyControlJ->setKey(Qt::CTRL | Qt::Key_J); connect(keyControlJ, &QShortcut::activated, [=]() { if (freqLock) return; this->shortcutControlMinus(); }); // Move the tuning knob by the tuning step selected: // H = Down keyH = new QShortcut(this); keyH->setKey(Qt::Key_H); connect(keyH, &QShortcut::activated, [=]() { if (freqLock) return; freqt f; f.Hz = roundFrequencyWithStep(ui->mainScope->getFrequency().Hz, -1, tsKnobHz); f.MHzDouble = f.Hz / (double)1E6; queue->add(priorityImmediate,queueItem(funcSelectedFreq,QVariant::fromValue(f))); }); // L = Up keyL = new QShortcut(this); keyL->setKey(Qt::Key_L); connect(keyL, &QShortcut::activated, [=]() { if (freqLock) return; freqt f; f.Hz = roundFrequencyWithStep(ui->mainScope->getFrequency().Hz, 1, tsKnobHz); f.MHzDouble = f.Hz / (double)1E6; queue->add(priorityImmediate,queueItem(funcSelectedFreq,QVariant::fromValue(f))); }); keyDebug = new QShortcut(this); #if (QT_VERSION < QT_VERSION_CHECK(6,0,0)) keyDebug->setKey(Qt::CTRL | Qt::SHIFT | Qt::Key_D); #else keyDebug->setKey(Qt::CTRL | Qt::Key_D); #endif connect(keyDebug, SIGNAL(activated()), this, SLOT(debugBtn_clicked())); } void wfmain::setupUsbControllerDevice() { #if defined (USB_CONTROLLER) if (usbWindow == Q_NULLPTR) { usbWindow = new controllerSetup(); } usbControllerDev = new usbController(); usbControllerThread = new QThread(this); usbControllerThread->setObjectName("usb()"); usbControllerDev->moveToThread(usbControllerThread); connect(usbControllerThread, SIGNAL(started()), usbControllerDev, SLOT(run())); connect(usbControllerThread, SIGNAL(finished()), usbControllerDev, SLOT(deleteLater())); connect(usbControllerThread, SIGNAL(finished()), usbWindow, SLOT(deleteLater())); // Delete window when controller is deleted connect(usbControllerDev, SIGNAL(sendJog(int)), this, SLOT(changeFrequency(int))); connect(usbControllerDev, SIGNAL(doShuttle(bool,unsigned char)), this, SLOT(doShuttle(bool,unsigned char))); connect(usbControllerDev, SIGNAL(button(const COMMAND*)), this, SLOT(buttonControl(const COMMAND*))); connect(usbControllerDev, SIGNAL(setBand(int)), this, SLOT(setBand(int))); connect(usbControllerDev, SIGNAL(removeDevice(USBDEVICE*)), usbWindow, SLOT(removeDevice(USBDEVICE*))); connect(usbControllerDev, SIGNAL(initUI(usbDevMap*, QVector