#include "wfmain.h" #include "ui_wfmain.h" #include "commhandler.h" #include "rigidentities.h" #include "logcategories.h" // This code is copyright 2017-2020 Elliott H. Liggett // All rights reserved wfmain::wfmain(const QString serialPortCL, const QString hostCL, const QString settingsFile, QWidget *parent ) : QMainWindow(parent), ui(new Ui::wfmain) { QGuiApplication::setApplicationDisplayName("wfview"); QGuiApplication::setApplicationName(QString("wfview")); setWindowIcon(QIcon( QString(":resources/wfview.png"))); ui->setupUi(this); setWindowTitle(QString("wfview")); this->serialPortCL = serialPortCL; this->hostCL = hostCL; cal = new calibrationWindow(); rpt = new repeaterSetup(); sat = new satelliteSetup(); trxadj = new transceiverAdjustments(); abtBox = new aboutbox(); selRad = new selectRadio(); qRegisterMetaType(); // Needs to be registered early. qRegisterMetaType(); qRegisterMetaType(); qRegisterMetaType(); qRegisterMetaType(); qRegisterMetaType(); qRegisterMetaType(); qRegisterMetaType(); qRegisterMetaType(); qRegisterMetaType(); qRegisterMetaType (); qRegisterMetaType (); qRegisterMetaType (); qRegisterMetaType (); qRegisterMetaType(); qRegisterMetaType>(); qRegisterMetaType(); qRegisterMetaType(); haveRigCaps = false; setupKeyShortcuts(); setupMainUI(); setSerialDevicesUI(); setDefaultColors(); setDefPrefs(); getSettingsFilePath(settingsFile); setupPlots(); loadSettings(); // Look for saved preferences setAudioDevicesUI(); setTuningSteps(); // TODO: Combine into preferences qDebug(logSystem()) << "Running setUIToPrefs()"; setUIToPrefs(); qDebug(logSystem()) << "Running setInititalTiming()"; setInitialTiming(); qDebug(logSystem()) << "Running openRig()"; openRig(); qDebug(logSystem()) << "Running rigConnections()"; rigConnections(); setServerToPrefs(); amTransmitting = false; connect(ui->txPowerSlider, &QSlider::sliderMoved, [&](int value) { QToolTip::showText(QCursor::pos(), QString("%1").arg(value*100/255), nullptr); }); } wfmain::~wfmain() { rigThread->quit(); rigThread->wait(); if (serverThread != Q_NULLPTR) { serverThread->quit(); serverThread->wait(); } if (rigCtl != Q_NULLPTR) { delete rigCtl; } if (prefs.audioSystem == portAudio) { Pa_Terminate(); } delete rpt; delete ui; delete settings; } void wfmain::closeEvent(QCloseEvent *event) { // Are you sure? if (!prefs.confirmExit) { QApplication::exit(); } QCheckBox *cb = new QCheckBox("Don't ask me again"); QMessageBox msgbox; msgbox.setText("Are you sure you wish to exit?\n"); msgbox.setIcon(QMessageBox::Icon::Question); QAbstractButton *yesButton = msgbox.addButton(QMessageBox::Yes); msgbox.addButton(QMessageBox::No); msgbox.setDefaultButton(QMessageBox::Yes); msgbox.setCheckBox(cb); QObject::connect(cb, &QCheckBox::stateChanged, [this](int state){ if (static_cast(state) == Qt::CheckState::Checked) { prefs.confirmExit=false; } else { prefs.confirmExit=true; } settings->beginGroup("Interface"); settings->setValue("ConfirmExit", this->prefs.confirmExit); settings->endGroup(); settings->sync(); }); msgbox.exec(); if (msgbox.clickedButton() == yesButton) { QApplication::exit(); } else { 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? // TODO: Use these if they are found if(!serialPortCL.isEmpty()) { qDebug(logSystem()) << "Serial port specified by user: " << serialPortCL; } else { qDebug(logSystem()) << "Serial port not specified. "; } if(!hostCL.isEmpty()) { qDebug(logSystem()) << "Remote host name specified by user: " << hostCL; } makeRig(); if (prefs.enableLAN) { ui->lanEnableBtn->setChecked(true); usingLAN = true; // We need to setup the tx/rx audio: udpPrefs.waterfallFormat = prefs.waterfallFormat; emit sendCommSetup(prefs.radioCIVAddr, udpPrefs, rxSetup, txSetup, prefs.virtualSerialPort, prefs.tcpPort); } else { ui->serialEnableBtn->setChecked(true); if( (prefs.serialPortRadio.toLower() == QString("auto")) && (serialPortCL.isEmpty())) { findSerialPort(); } else { if(serialPortCL.isEmpty()) { serialPortRig = prefs.serialPortRadio; } else { serialPortRig = serialPortCL; } } usingLAN = false; emit sendCommSetup(prefs.radioCIVAddr, serialPortRig, prefs.serialPortBaud,prefs.virtualSerialPort, prefs.tcpPort,prefs.waterfallFormat); ui->statusBar->showMessage(QString("Connecting to rig using serial port ").append(serialPortRig), 1000); } } void wfmain::createSettingsListItems() { // Add items to the settings tab list widget ui->settingsList->addItem("Radio Access"); // 0 ui->settingsList->addItem("User Interface"); // 1 ui->settingsList->addItem("Radio Settings"); // 2 ui->settingsList->addItem("Radio Server"); // 3 ui->settingsList->addItem("External Control"); // 4 ui->settingsList->addItem("Experimental"); // 5 //ui->settingsList->addItem("Audio Processing"); // 6 ui->settingsStack->setCurrentIndex(0); } void wfmain::on_settingsList_currentRowChanged(int currentRow) { ui->settingsStack->setCurrentIndex(currentRow); } void wfmain::connectSettingsList() { } void wfmain::rigConnections() { 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(rig, SIGNAL(haveFrequency(freqt)), this, SLOT(receiveFreq(freqt))); connect(this, SIGNAL(getFrequency()), rig, SLOT(getFrequency())); connect(this, SIGNAL(getMode()), rig, SLOT(getMode())); connect(this, SIGNAL(getDataMode()), rig, SLOT(getDataMode())); connect(this, SIGNAL(setDataMode(bool, unsigned char)), rig, SLOT(setDataMode(bool, unsigned char))); connect(this, SIGNAL(getBandStackReg(char,char)), rig, SLOT(getBandStackReg(char,char))); connect(rig, SIGNAL(havePTTStatus(bool)), this, SLOT(receivePTTstatus(bool))); connect(this, SIGNAL(setPTT(bool)), rig, SLOT(setPTT(bool))); connect(this, SIGNAL(getPTT()), rig, SLOT(getPTT())); connect(rig, SIGNAL(haveBandStackReg(freqt,char,char,bool)), this, SLOT(receiveBandStackReg(freqt,char,char,bool))); connect(this, SIGNAL(setRitEnable(bool)), rig, SLOT(setRitEnable(bool))); connect(this, SIGNAL(setRitValue(int)), rig, SLOT(setRitValue(int))); connect(rig, SIGNAL(haveRitEnabled(bool)), this, SLOT(receiveRITStatus(bool))); connect(rig, SIGNAL(haveRitFrequency(int)), this, SLOT(receiveRITValue(int))); connect(this, SIGNAL(getRitEnabled()), rig, SLOT(getRitEnabled())); connect(this, SIGNAL(getRitValue()), rig, SLOT(getRitValue())); connect(this, SIGNAL(getDebug()), rig, SLOT(getDebug())); connect(this, SIGNAL(spectOutputDisable()), rig, SLOT(disableSpectOutput())); connect(this, SIGNAL(spectOutputEnable()), rig, SLOT(enableSpectOutput())); connect(this, SIGNAL(scopeDisplayDisable()), rig, SLOT(disableSpectrumDisplay())); connect(this, SIGNAL(scopeDisplayEnable()), rig, SLOT(enableSpectrumDisplay())); connect(rig, SIGNAL(haveMode(unsigned char, unsigned char)), this, SLOT(receiveMode(unsigned char, unsigned char))); connect(rig, SIGNAL(haveDataMode(bool)), this, SLOT(receiveDataModeStatus(bool))); connect(rpt, SIGNAL(getDuplexMode()), rig, SLOT(getDuplexMode())); connect(rpt, SIGNAL(setDuplexMode(duplexMode)), rig, SLOT(setDuplexMode(duplexMode))); connect(rig, SIGNAL(haveDuplexMode(duplexMode)), rpt, SLOT(receiveDuplexMode(duplexMode))); connect(rpt, SIGNAL(getTone()), rig, SLOT(getTone())); connect(rpt, SIGNAL(getTSQL()), rig, SLOT(getTSQL())); connect(rpt, SIGNAL(getDTCS()), rig, SLOT(getDTCS())); connect(rpt, SIGNAL(setTone(quint16)), rig, SLOT(setTone(quint16))); connect(rpt, SIGNAL(setTSQL(quint16)), rig, SLOT(setTSQL(quint16))); connect(rpt, SIGNAL(setDTCS(quint16,bool,bool)), rig, SLOT(setDTCS(quint16,bool,bool))); connect(rpt, SIGNAL(getRptAccessMode()), rig, SLOT(getRptAccessMode())); connect(rpt, SIGNAL(setRptAccessMode(rptAccessTxRx)), rig, SLOT(setRptAccessMode(rptAccessTxRx))); connect(rig, SIGNAL(haveTone(quint16)), rpt, SLOT(handleTone(quint16))); connect(rig, SIGNAL(haveTSQL(quint16)), rpt, SLOT(handleTSQL(quint16))); connect(rig, SIGNAL(haveDTCS(quint16,bool,bool)), rpt, SLOT(handleDTCS(quint16,bool,bool))); connect(rig, SIGNAL(haveRptAccessMode(rptAccessTxRx)), rpt, SLOT(handleRptAccessMode(rptAccessTxRx))); connect(this, SIGNAL(getDuplexMode()), rig, SLOT(getDuplexMode())); connect(this, SIGNAL(getTone()), rig, SLOT(getTone())); connect(this, SIGNAL(getTSQL()), rig, SLOT(getTSQL())); connect(this, SIGNAL(getRptAccessMode()), rig, SLOT(getRptAccessMode())); //connect(this, SIGNAL(setDuplexMode(duplexMode)), rig, SLOT(setDuplexMode(duplexMode))); //connect(rig, SIGNAL(haveDuplexMode(duplexMode)), this, SLOT(receiveDuplexMode(duplexMode))); connect(this, SIGNAL(getModInput(bool)), rig, SLOT(getModInput(bool))); connect(rig, SIGNAL(haveModInput(rigInput,bool)), this, SLOT(receiveModInput(rigInput, bool))); connect(this, SIGNAL(setModInput(rigInput, bool)), rig, SLOT(setModInput(rigInput,bool))); connect(rig, SIGNAL(haveSpectrumData(QByteArray, double, double)), this, SLOT(receiveSpectrumData(QByteArray, double, double))); connect(rig, SIGNAL(haveSpectrumMode(spectrumMode)), this, SLOT(receiveSpectrumMode(spectrumMode))); connect(this, SIGNAL(setScopeMode(spectrumMode)), rig, SLOT(setSpectrumMode(spectrumMode))); connect(this, SIGNAL(getScopeMode()), rig, SLOT(getScopeMode())); connect(this, SIGNAL(setFrequency(unsigned char, freqt)), rig, SLOT(setFrequency(unsigned char, freqt))); connect(this, SIGNAL(setScopeEdge(char)), rig, SLOT(setScopeEdge(char))); connect(this, SIGNAL(setScopeSpan(char)), rig, SLOT(setScopeSpan(char))); //connect(this, SIGNAL(getScopeMode()), rig, SLOT(getScopeMode())); connect(this, SIGNAL(getScopeEdge()), rig, SLOT(getScopeEdge())); connect(this, SIGNAL(getScopeSpan()), rig, SLOT(getScopeSpan())); connect(rig, SIGNAL(haveScopeSpan(freqt,bool)), this, SLOT(receiveSpectrumSpan(freqt,bool))); connect(this, SIGNAL(setScopeFixedEdge(double,double,unsigned char)), rig, SLOT(setSpectrumBounds(double,double,unsigned char))); connect(this, SIGNAL(setMode(unsigned char, unsigned char)), rig, SLOT(setMode(unsigned char, unsigned char))); connect(this, SIGNAL(setMode(mode_info)), rig, SLOT(setMode(mode_info))); // Levels (read and write) // Levels: Query: connect(this, SIGNAL(getLevels()), rig, SLOT(getLevels())); connect(this, SIGNAL(getRfGain()), rig, SLOT(getRfGain())); connect(this, SIGNAL(getAfGain()), rig, SLOT(getAfGain())); connect(this, SIGNAL(getSql()), rig, SLOT(getSql())); connect(this, SIGNAL(getIfShift()), rig, SLOT(getIFShift())); connect(this, SIGNAL(getTPBFInner()), rig, SLOT(getTPBFInner())); connect(this, SIGNAL(getTPBFOuter()), rig, SLOT(getTPBFOuter())); connect(this, SIGNAL(getTxPower()), rig, SLOT(getTxLevel())); connect(this, SIGNAL(getMicGain()), rig, SLOT(getMicGain())); connect(this, SIGNAL(getSpectrumRefLevel()), rig, SLOT(getSpectrumRefLevel())); connect(this, SIGNAL(getModInputLevel(rigInput)), rig, SLOT(getModInputLevel(rigInput))); // Levels: Set: connect(this, SIGNAL(setRfGain(unsigned char)), rig, SLOT(setRfGain(unsigned char))); connect(this, SIGNAL(setAfGain(unsigned char)), rig, SLOT(setAfGain(unsigned char))); connect(this, SIGNAL(setSql(unsigned char)), rig, SLOT(setSquelch(unsigned char))); connect(this, SIGNAL(setIFShift(unsigned char)), rig, SLOT(setIFShift(unsigned char))); connect(this, SIGNAL(setTPBFInner(unsigned char)), rig, SLOT(setTPBFInner(unsigned char))); connect(this, SIGNAL(setTPBFOuter(unsigned char)), rig, SLOT(setTPBFOuter(unsigned char))); connect(this, SIGNAL(setTxPower(unsigned char)), rig, SLOT(setTxPower(unsigned char))); connect(this, SIGNAL(setMicGain(unsigned char)), rig, SLOT(setMicGain(unsigned char))); connect(this, SIGNAL(setMonitorLevel(unsigned char)), rig, SLOT(setMonitorLevel(unsigned char))); connect(this, SIGNAL(setVoxGain(unsigned char)), rig, SLOT(setVoxGain(unsigned char))); connect(this, SIGNAL(setAntiVoxGain(unsigned char)), rig, SLOT(setAntiVoxGain(unsigned char))); connect(this, SIGNAL(setSpectrumRefLevel(int)), rig, SLOT(setSpectrumRefLevel(int))); connect(this, SIGNAL(setModLevel(rigInput, unsigned char)), rig, SLOT(setModInputLevel(rigInput, unsigned char))); // Levels: handle return on query: connect(rig, SIGNAL(haveRfGain(unsigned char)), this, SLOT(receiveRfGain(unsigned char))); connect(rig, SIGNAL(haveAfGain(unsigned char)), this, SLOT(receiveAfGain(unsigned char))); connect(rig, SIGNAL(haveSql(unsigned char)), this, SLOT(receiveSql(unsigned char))); connect(rig, SIGNAL(haveIFShift(unsigned char)), trxadj, SLOT(updateIFShift(unsigned char))); connect(rig, SIGNAL(haveTPBFInner(unsigned char)), trxadj, SLOT(updateTPBFInner(unsigned char))); connect(rig, SIGNAL(haveTPBFOuter(unsigned char)), trxadj, SLOT(updateTPBFOuter(unsigned char))); connect(rig, SIGNAL(haveTxPower(unsigned char)), this, SLOT(receiveTxPower(unsigned char))); connect(rig, SIGNAL(haveMicGain(unsigned char)), this, SLOT(receiveMicGain(unsigned char))); connect(rig, SIGNAL(haveSpectrumRefLevel(int)), this, SLOT(receiveSpectrumRefLevel(int))); connect(rig, SIGNAL(haveACCGain(unsigned char,unsigned char)), this, SLOT(receiveACCGain(unsigned char,unsigned char))); connect(rig, SIGNAL(haveUSBGain(unsigned char)), this, SLOT(receiveUSBGain(unsigned char))); connect(rig, SIGNAL(haveLANGain(unsigned char)), this, SLOT(receiveLANGain(unsigned char))); //Metering: connect(this, SIGNAL(getMeters(meterKind)), rig, SLOT(getMeters(meterKind))); connect(rig, SIGNAL(haveMeter(meterKind,unsigned char)), this, SLOT(receiveMeter(meterKind,unsigned char))); // Rig and ATU info: connect(this, SIGNAL(startATU()), rig, SLOT(startATU())); connect(this, SIGNAL(setATU(bool)), rig, SLOT(setATU(bool))); connect(this, SIGNAL(getATUStatus()), rig, SLOT(getATUStatus())); connect(this, SIGNAL(getRigID()), rig, SLOT(getRigID())); connect(rig, SIGNAL(haveATUStatus(unsigned char)), this, SLOT(receiveATUStatus(unsigned char))); connect(rig, SIGNAL(haveRigID(rigCapabilities)), this, SLOT(receiveRigID(rigCapabilities))); connect(this, SIGNAL(setAttenuator(unsigned char)), rig, SLOT(setAttenuator(unsigned char))); connect(this, SIGNAL(setPreamp(unsigned char)), rig, SLOT(setPreamp(unsigned char))); connect(this, SIGNAL(setAntenna(unsigned char, bool)), rig, SLOT(setAntenna(unsigned char, bool))); connect(this, SIGNAL(getPreamp()), rig, SLOT(getPreamp())); connect(rig, SIGNAL(havePreamp(unsigned char)), this, SLOT(receivePreamp(unsigned char))); connect(this, SIGNAL(getAttenuator()), rig, SLOT(getAttenuator())); connect(rig, SIGNAL(haveAttenuator(unsigned char)), this, SLOT(receiveAttenuator(unsigned char))); connect(this, SIGNAL(getAntenna()), rig, SLOT(getAntenna())); connect(rig, SIGNAL(haveAntenna(unsigned char,bool)), this, SLOT(receiveAntennaSel(unsigned char,bool))); // Speech (emitted from rig speaker) connect(this, SIGNAL(sayAll()), rig, SLOT(sayAll())); connect(this, SIGNAL(sayFrequency()), rig, SLOT(sayFrequency())); connect(this, SIGNAL(sayMode()), rig, SLOT(sayMode())); // calibration window: connect(cal, SIGNAL(requestRefAdjustCourse()), rig, SLOT(getRefAdjustCourse())); connect(cal, SIGNAL(requestRefAdjustFine()), rig, SLOT(getRefAdjustFine())); connect(rig, SIGNAL(haveRefAdjustCourse(unsigned char)), cal, SLOT(handleRefAdjustCourse(unsigned char))); connect(rig, SIGNAL(haveRefAdjustFine(unsigned char)), cal, SLOT(handleRefAdjustFine(unsigned char))); connect(cal, SIGNAL(setRefAdjustCourse(unsigned char)), rig, SLOT(setRefAdjustCourse(unsigned char))); connect(cal, SIGNAL(setRefAdjustFine(unsigned char)), rig, SLOT(setRefAdjustFine(unsigned char))); // Date and Time: connect(this, SIGNAL(setTime(timekind)), rig, SLOT(setTime(timekind))); connect(this, SIGNAL(setDate(datekind)), rig, SLOT(setDate(datekind))); connect(this, SIGNAL(setUTCOffset(timekind)), rig, SLOT(setUTCOffset(timekind))); } //void wfmain::removeRigConnections() //{ //} 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(haveSerialPortError(QString, QString)), this, SLOT(receiveSerialPortError(QString, QString))); 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(unsigned char, udpPreferences, audioSetup, audioSetup, QString, quint16)), rig, SLOT(commSetup(unsigned char, udpPreferences, audioSetup, audioSetup, QString, quint16))); connect(this, SIGNAL(sendCommSetup(unsigned char, QString, quint32,QString, quint16,quint8)), rig, SLOT(commSetup(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(requestRigState()), rig, SLOT(sendState())); connect(this, SIGNAL(stateUpdated()), rig, SLOT(stateUpdated())); connect(rig, SIGNAL(stateInfo(rigstate*)), this, SLOT(receiveStateInfo(rigstate*))); if (rigCtl != Q_NULLPTR) { connect(rig, SIGNAL(stateInfo(rigstate*)), rigCtl, SLOT(receiveStateInfo(rigstate*))); connect(rigCtl, SIGNAL(stateUpdated()), rig, SLOT(stateUpdated())); } // 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) { if (rigCtl != Q_NULLPTR) { rigCtl->disconnect(); } rigThread->disconnect(); rig->disconnect(); delete rigThread; delete rig; rig = 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(); 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 setRigID(prefs.radioCIVAddr); } else { emit getRigID(); getInitialRigState(); } } } 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."; if(rig->usingLAN()) { usingLAN = true; } else { usingLAN = false; } receiveRigID(rigCaps); getInitialRigState(); return; } void wfmain::receiveSerialPortError(QString port, QString errorText) { qInfo(logSystem()) << "wfmain: received serial port error for port: " << port << " with message: " << errorText; ui->statusBar->showMessage(QString("ERROR: using port ").append(port).append(": ").append(errorText), 10000); // TODO: Dialog box, exit, etc } void wfmain::receiveStatusUpdate(networkStatus status) { 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) { qInfo(logSystem()) << "audio level meter received."; meterKind m = meterNone; if(l.haveRxLevels) { m = meterRxAudio; receiveMeter(m, l.rxAudioPeak); } if(l.haveTxLevels) { m = meterTxMod; receiveMeter(m, l.txAudioPeak); } } void wfmain::setupPlots() { spectrumDrawLock = true; plot = ui->plot; wf = ui->waterfall; freqIndicatorLine = new QCPItemLine(plot); freqIndicatorLine->setAntialiased(true); freqIndicatorLine->setPen(QPen(Qt::blue)); ui->plot->addGraph(); // primary ui->plot->addGraph(0, 0); // secondary, peaks, same axis as first. ui->plot->addLayer( "Top Layer", ui->plot->layer("main")); ui->plot->graph(0)->setLayer("Top Layer"); ui->waterfall->addGraph(); colorMap = new QCPColorMap(wf->xAxis, wf->yAxis); colorMapData = NULL; #if QCUSTOMPLOT_VERSION < 0x020001 wf->addPlottable(colorMap); #endif colorScale = new QCPColorScale(wf); ui->tabWidget->setCurrentIndex(0); QColor color(20+200/4.0*1,70*(1.6-1/4.0), 150, 150); plot->graph(1)->setLineStyle(QCPGraph::lsLine); plot->graph(1)->setPen(QPen(color.lighter(200))); plot->graph(1)->setBrush(QBrush(color)); freqIndicatorLine->start->setCoords(0.5,0); freqIndicatorLine->end->setCoords(0.5,160); // Plot user interaction connect(plot, SIGNAL(mouseDoubleClick(QMouseEvent*)), this, SLOT(handlePlotDoubleClick(QMouseEvent*))); connect(wf, SIGNAL(mouseDoubleClick(QMouseEvent*)), this, SLOT(handleWFDoubleClick(QMouseEvent*))); connect(plot, SIGNAL(mousePress(QMouseEvent*)), this, SLOT(handlePlotClick(QMouseEvent*))); connect(wf, SIGNAL(mousePress(QMouseEvent*)), this, SLOT(handleWFClick(QMouseEvent*))); connect(wf, SIGNAL(mouseWheel(QWheelEvent*)), this, SLOT(handleWFScroll(QWheelEvent*))); connect(plot, SIGNAL(mouseWheel(QWheelEvent*)), this, SLOT(handlePlotScroll(QWheelEvent*))); spectrumDrawLock = false; } void wfmain::setupMainUI() { createSettingsListItems(); ui->bandStkLastUsedBtn->setVisible(false); ui->bandStkVoiceBtn->setVisible(false); ui->bandStkDataBtn->setVisible(false); ui->bandStkCWBtn->setVisible(false); ui->baudRateCombo->insertItem(0, QString("115200"), 115200); ui->baudRateCombo->insertItem(1, QString("57600"), 57600); ui->baudRateCombo->insertItem(2, QString("38400"), 38400); ui->baudRateCombo->insertItem(3, QString("28800"), 28800); ui->baudRateCombo->insertItem(4, QString("19200"), 19200); ui->baudRateCombo->insertItem(5, QString("9600"), 9600); ui->baudRateCombo->insertItem(6, QString("4800"), 4800); ui->baudRateCombo->insertItem(7, QString("2400"), 2400); ui->baudRateCombo->insertItem(8, QString("1200"), 1200); ui->baudRateCombo->insertItem(9, QString("300"), 300); ui->spectrumModeCombo->addItem("Center", (spectrumMode)spectModeCenter); ui->spectrumModeCombo->addItem("Fixed", (spectrumMode)spectModeFixed); ui->spectrumModeCombo->addItem("Scroll-C", (spectrumMode)spectModeScrollC); ui->spectrumModeCombo->addItem("Scroll-F", (spectrumMode)spectModeScrollF); ui->modeSelectCombo->addItem("LSB", 0x00); ui->modeSelectCombo->addItem("USB", 0x01); ui->modeSelectCombo->addItem("FM", 0x05); ui->modeSelectCombo->addItem("AM", 0x02); ui->modeSelectCombo->addItem("CW", 0x03); ui->modeSelectCombo->addItem("CW-R", 0x07); ui->modeSelectCombo->addItem("RTTY", 0x04); ui->modeSelectCombo->addItem("RTTY-R", 0x08); ui->modeFilterCombo->addItem("1", 1); ui->modeFilterCombo->addItem("2", 2); ui->modeFilterCombo->addItem("3", 3); ui->modeFilterCombo->addItem("Setup...", 99); ui->tuningStepCombo->blockSignals(true); ui->tuningStepCombo->addItem("1 Hz", (unsigned int) 1); ui->tuningStepCombo->addItem("10 Hz", (unsigned int) 10); ui->tuningStepCombo->addItem("100 Hz", (unsigned int) 100); ui->tuningStepCombo->addItem("500 Hz", (unsigned int) 500); ui->tuningStepCombo->addItem("1 kHz", (unsigned int) 1000); ui->tuningStepCombo->addItem("2.5 kHz", (unsigned int) 2500); ui->tuningStepCombo->addItem("5 kHz", (unsigned int) 5000); ui->tuningStepCombo->addItem("6.125 kHz", (unsigned int) 6125); // PMR ui->tuningStepCombo->addItem("8.333 kHz", (unsigned int) 8333); // airband stepsize ui->tuningStepCombo->addItem("9 kHz", (unsigned int) 9000); // European medium wave stepsize ui->tuningStepCombo->addItem("10 kHz", (unsigned int) 10000); ui->tuningStepCombo->addItem("12.5 kHz", (unsigned int) 12500); ui->tuningStepCombo->addItem("25 kHz", (unsigned int) 25000); ui->tuningStepCombo->addItem("100 kHz", (unsigned int) 100000); ui->tuningStepCombo->addItem("250 kHz", (unsigned int) 250000); ui->tuningStepCombo->addItem("1 MHz", (unsigned int) 1000000); //for 23 cm and HF ui->tuningStepCombo->setCurrentIndex(2); ui->tuningStepCombo->blockSignals(false); ui->wfthemeCombo->addItem("Jet", QCPColorGradient::gpJet); ui->wfthemeCombo->addItem("Cold", QCPColorGradient::gpCold); ui->wfthemeCombo->addItem("Hot", QCPColorGradient::gpHot); ui->wfthemeCombo->addItem("Thermal", QCPColorGradient::gpThermal); ui->wfthemeCombo->addItem("Night", QCPColorGradient::gpNight); ui->wfthemeCombo->addItem("Ion", QCPColorGradient::gpIon); ui->wfthemeCombo->addItem("Gray", QCPColorGradient::gpGrayscale); ui->wfthemeCombo->addItem("Geography", QCPColorGradient::gpGeography); ui->wfthemeCombo->addItem("Hues", QCPColorGradient::gpHues); ui->wfthemeCombo->addItem("Polar", QCPColorGradient::gpPolar); ui->wfthemeCombo->addItem("Spectrum", QCPColorGradient::gpSpectrum); ui->wfthemeCombo->addItem("Candy", QCPColorGradient::gpCandy); ui->meter2selectionCombo->addItem("None", meterNone); ui->meter2selectionCombo->addItem("SWR", meterSWR); ui->meter2selectionCombo->addItem("ALC", meterALC); ui->meter2selectionCombo->addItem("Compression", meterComp); ui->meter2selectionCombo->addItem("Voltage", meterVoltage); ui->meter2selectionCombo->addItem("Current", meterCurrent); ui->meter2selectionCombo->addItem("Center", meterCenter); ui->meter2selectionCombo->addItem("TxRxAudio", meterAudio); ui->meter2selectionCombo->addItem("RxAudio", meterRxAudio); ui->meter2selectionCombo->addItem("TxAudio", meterTxMod); ui->meter2Widget->hide(); ui->meter2selectionCombo->show(); ui->meter2selectionCombo->setCurrentIndex((int)prefs.meter2Type); ui->secondaryMeterSelectionLabel->show(); // Future ideas: //ui->meter2selectionCombo->addItem("Transmit Audio", meterTxMod); //ui->meter2selectionCombo->addItem("Receive Audio", meterRxAudio); //ui->meter2selectionCombo->addItem("Latency", meterLatency); spans << "2.5k" << "5.0k" << "10k" << "25k"; spans << "50k" << "100k" << "250k" << "500k"; ui->scopeBWCombo->insertItems(0, spans); edges << "1" << "2" << "3" << "4"; ui->scopeEdgeCombo->insertItems(0, edges); ui->splitter->setHandleWidth(5); // 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->scopeRefLevelSlider->setTickInterval(50); ui->scopeRefLevelSlider->setSingleStep(20); ui->freqMhzLineEdit->setValidator( new QDoubleValidator(0, 100, 6, this)); ui->controlPortTxt->setValidator(new QIntValidator(this)); qDebug(logSystem()) << "Running with debugging options enabled."; #ifdef QT_DEBUG ui->debugBtn->setVisible(true); ui->satOpsBtn->setVisible(true); #else ui->debugBtn->setVisible(false); ui->satOpsBtn->setVisible(false); #endif 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); 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); freq.MHzDouble = 0.0; freq.Hz = 0; oldFreqDialVal = ui->freqDial->value(); ui->tuneLockChk->setChecked(false); freqLock = false; connect(ui->tabWidget, SIGNAL(currentChanged(int)), this, SLOT(updateSizes(int))); connect( ui->txPowerSlider, &QSlider::valueChanged, [=](const int &newValue) { statusFromSliderPercent("Tx Power", newValue);} ); connect( ui->rfGainSlider, &QSlider::valueChanged, [=](const int &newValue) { statusFromSliderPercent("RF Gain", newValue);} ); connect( ui->afGainSlider, &QSlider::valueChanged, [=](const int &newValue) { statusFromSliderPercent("AF Gain", newValue);} ); connect( ui->micGainSlider, &QSlider::valueChanged, [=](const int &newValue) { statusFromSliderPercent("TX Audio Gain", newValue);} ); connect( ui->sqlSlider, &QSlider::valueChanged, [=](const int &newValue) { statusFromSliderPercent("Squelch", newValue);} ); // -200 0 +200.. take log? connect( ui->scopeRefLevelSlider, &QSlider::valueChanged, [=](const int &newValue) { statusFromSliderRaw("Scope Ref Level", newValue);} ); connect( ui->wfLengthSlider, &QSlider::valueChanged, [=](const int &newValue) { statusFromSliderRaw("Waterfall Length", newValue);} ); connect(this->trxadj, &transceiverAdjustments::setIFShift, [=](const unsigned char &newValue) { issueCmdUniquePriority(cmdSetIFShift, newValue);} ); connect(this->trxadj, &transceiverAdjustments::setTPBFInner, [=](const unsigned char &newValue) { issueCmdUniquePriority(cmdSetTPBFInner, newValue);} ); connect(this->trxadj, &transceiverAdjustments::setTPBFOuter, [=](const unsigned char &newValue) { issueCmdUniquePriority(cmdSetTPBFOuter, newValue);} ); } void wfmain::updateSizes(int tabIndex) { if(!haveRigCaps) return; // This function does nothing unless you are using a rig without spectrum. // This is a hack. It is not great, but it seems to work ok. if(!rigCaps.hasSpectrum) { // Set "ignore" size policy for non-selected tabs: for(int i=0;itabWidget->count();i++) if((i!=tabIndex) && tabIndex != 0) ui->tabWidget->widget(i)->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored); // allows size to be any size that fits the tab bar if(tabIndex==0 && !rigCaps.hasSpectrum) { ui->tabWidget->widget(0)->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); ui->tabWidget->widget(0)->setMaximumSize(ui->tabWidget->widget(0)->minimumSizeHint()); ui->tabWidget->widget(0)->adjustSize(); // tab this->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); this->setMaximumSize(QSize(1024,350)); this->setMinimumSize(QSize(1024,350)); resize(minimumSize()); adjustSize(); // main window } else if(tabIndex==0 && rigCaps.hasSpectrum) { // At main tab (0) and we have spectrum: ui->tabWidget->widget(0)->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); resize(minimumSizeHint()); adjustSize(); // Without this call, the window retains the size of the previous tab. } else { // At some other tab, with or without spectrum: ui->tabWidget->widget(tabIndex)->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); this->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); this->setMinimumSize(QSize(1024, 600)); // not large enough for settings tab this->setMaximumSize(QSize(65535,65535)); adjustSize(); } } else { ui->tabWidget->widget(tabIndex)->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); ui->tabWidget->widget(tabIndex)->setMaximumSize(65535,65535); //ui->tabWidget->widget(0)->setMinimumSize(); } } 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(); } qInfo(logSystem()) << "Loading settings from:" << path + file; 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); delayedCommand->setInterval(delayedCmdStartupInterval_ms); // 250ms until we find rig civ and id, then 100ms. delayedCommand->setSingleShot(false); connect(delayedCommand, SIGNAL(timeout()), this, SLOT(sendRadioCommandLoop())); // TODO: Remove this: // periodicPollingTimer = new QTimer(this); // periodicPollingTimer->setInterval(10); // periodicPollingTimer->setSingleShot(false); //connect(periodicPollingTimer, SIGNAL(timeout()), this, SLOT(sendRadioCommandLoop())); 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); on_fullScreenChk_clicked(prefs.useFullScreen); ui->useDarkThemeChk->setChecked(prefs.useDarkMode); on_useDarkThemeChk_clicked(prefs.useDarkMode); ui->useSystemThemeChk->setChecked(prefs.useSystemTheme); on_useSystemThemeChk_clicked(prefs.useSystemTheme); ui->drawPeakChk->setChecked(prefs.drawPeaks); on_drawPeakChk_clicked(prefs.drawPeaks); drawPeaks = prefs.drawPeaks; underlayMode = prefs.underlayMode; 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->underlayBufferSlider->setValue(prefs.underlayBufferSize); on_underlayBufferSlider_valueChanged(prefs.underlayBufferSize); ui->wfAntiAliasChk->setChecked(prefs.wfAntiAlias); on_wfAntiAliasChk_clicked(prefs.wfAntiAlias); ui->wfInterpolateChk->setChecked(prefs.wfInterpolate); on_wfInterpolateChk_clicked(prefs.wfInterpolate); ui->wfLengthSlider->setValue(prefs.wflength); prepareWf(prefs.wflength); ui->topLevelSlider->setValue(prefs.plotCeiling); ui->botLevelSlider->setValue(prefs.plotFloor); plot->yAxis->setRange(QCPRange(prefs.plotFloor, prefs.plotCeiling)); colorMap->setDataRange(QCPRange(prefs.plotFloor, prefs.plotCeiling)); ui->wfthemeCombo->setCurrentIndex(ui->wfthemeCombo->findData(prefs.wftheme)); colorMap->setGradient(static_cast(prefs.wftheme)); ui->useCIVasRigIDChk->blockSignals(true); ui->useCIVasRigIDChk->setChecked(prefs.CIVisRadioModel); ui->useCIVasRigIDChk->blockSignals(false); } void wfmain::setSerialDevicesUI() { ui->serialDeviceListCombo->blockSignals(true); ui->serialDeviceListCombo->addItem("Auto", 0); int i = 0; foreach(const QSerialPortInfo & serialPortInfo, QSerialPortInfo::availablePorts()) { portList.append(serialPortInfo.portName()); #if defined(Q_OS_LINUX) || defined(Q_OS_MAC) ui->serialDeviceListCombo->addItem(QString("/dev/") + serialPortInfo.portName(), i++); #else ui->serialDeviceListCombo->addItem(serialPortInfo.portName(), i++); //qInfo(logSystem()) << "Serial Port found: " << serialPortInfo.portName() << "Manufacturer:" << serialPortInfo.manufacturer() << "Product ID" << serialPortInfo.description() << "S/N" << serialPortInfo.serialNumber(); #endif } #if defined(Q_OS_LINUX) || defined(Q_OS_MAC) ui->serialDeviceListCombo->addItem("Manual...", 256); #endif ui->serialDeviceListCombo->blockSignals(false); ui->vspCombo->blockSignals(true); #ifdef Q_OS_WIN ui->vspCombo->addItem(QString("None"), i++); foreach(const QSerialPortInfo & serialPortInfo, QSerialPortInfo::availablePorts()) { ui->vspCombo->addItem(serialPortInfo.portName()); } #else // Provide reasonable names for the symbolic link to the pty device #ifdef Q_OS_MAC QString vspName = QStandardPaths::standardLocations(QStandardPaths::DownloadLocation)[0] + "/rig-pty"; #else QString vspName = QDir::homePath() + "/rig-pty"; #endif for (i = 1; i < 8; i++) { ui->vspCombo->addItem(vspName + QString::number(i)); if (QFile::exists(vspName + QString::number(i))) { auto* model = qobject_cast(ui->vspCombo->model()); auto* item = model->item(ui->vspCombo->count() - 1); item->setEnabled(false); } } ui->vspCombo->addItem(vspName + QString::number(i)); ui->vspCombo->addItem(QString("None"), i++); #endif ui->vspCombo->setEditable(true); ui->vspCombo->blockSignals(false); } 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())); keyDebug = new QShortcut(this); keyDebug->setKey(Qt::CTRL + Qt::SHIFT + Qt::Key_D); connect(keyDebug, SIGNAL(activated()), this, SLOT(on_debugBtn_clicked())); } void wfmain::setDefPrefs() { defPrefs.useFullScreen = false; defPrefs.useDarkMode = true; defPrefs.useSystemTheme = false; defPrefs.drawPeaks = true; defPrefs.underlayMode = underlayNone; defPrefs.underlayBufferSize = 64; defPrefs.wfAntiAlias = false; defPrefs.wfInterpolate = true; defPrefs.stylesheetPath = QString("qdarkstyle/style.qss"); defPrefs.radioCIVAddr = 0x00; // previously was 0x94 for 7300. defPrefs.CIVisRadioModel = false; defPrefs.forceRTSasPTT = false; defPrefs.serialPortRadio = QString("auto"); defPrefs.serialPortBaud = 115200; defPrefs.enablePTT = false; defPrefs.niceTS = true; defPrefs.enableRigCtlD = false; defPrefs.rigCtlPort = 4533; defPrefs.virtualSerialPort = QString("none"); defPrefs.localAFgain = 255; defPrefs.wflength = 160; defPrefs.wftheme = static_cast(QCPColorGradient::gpJet); defPrefs.plotFloor = 0; defPrefs.plotCeiling = 160; defPrefs.confirmExit = true; defPrefs.confirmPowerOff = true; defPrefs.meter2Type = meterNone; defPrefs.tcpPort = 0; defPrefs.waterfallFormat = 0; defPrefs.audioSystem = qtAudio; udpDefPrefs.ipAddress = QString(""); udpDefPrefs.controlLANPort = 50001; udpDefPrefs.serialLANPort = 50002; udpDefPrefs.audioLANPort = 50003; udpDefPrefs.username = QString(""); udpDefPrefs.password = QString(""); udpDefPrefs.clientName = QHostInfo::localHostName(); } void wfmain::loadSettings() { qInfo(logSystem()) << "Loading settings from " << settings->fileName(); // Basic things to load: // UI: (full screen, dark theme, draw peaks, colors, etc) settings->beginGroup("Interface"); prefs.useFullScreen = settings->value("UseFullScreen", defPrefs.useFullScreen).toBool(); prefs.useDarkMode = settings->value("UseDarkMode", defPrefs.useDarkMode).toBool(); prefs.useSystemTheme = settings->value("UseSystemTheme", defPrefs.useSystemTheme).toBool(); prefs.wftheme = settings->value("WFTheme", defPrefs.wftheme).toInt(); prefs.plotFloor = settings->value("plotFloor", defPrefs.plotFloor).toInt(); prefs.plotCeiling = settings->value("plotCeiling", defPrefs.plotCeiling).toInt(); plotFloor = prefs.plotFloor; plotCeiling = prefs.plotCeiling; wfFloor = prefs.plotFloor; wfCeiling = prefs.plotCeiling; prefs.drawPeaks = settings->value("DrawPeaks", defPrefs.drawPeaks).toBool(); prefs.underlayBufferSize = settings->value("underlayBufferSize", defPrefs.underlayBufferSize).toInt(); prefs.underlayMode = static_cast(settings->value("underlayMode", defPrefs.underlayMode).toInt()); prefs.wfAntiAlias = settings->value("WFAntiAlias", defPrefs.wfAntiAlias).toBool(); prefs.wfInterpolate = settings->value("WFInterpolate", defPrefs.wfInterpolate).toBool(); prefs.wflength = (unsigned int)settings->value("WFLength", defPrefs.wflength).toInt(); prefs.stylesheetPath = settings->value("StylesheetPath", defPrefs.stylesheetPath).toString(); ui->splitter->restoreState(settings->value("splitter").toByteArray()); restoreGeometry(settings->value("windowGeometry").toByteArray()); restoreState(settings->value("windowState").toByteArray()); setWindowState(Qt::WindowActive); // Works around QT bug to returns window+keyboard focus. prefs.confirmExit = settings->value("ConfirmExit", defPrefs.confirmExit).toBool(); prefs.confirmPowerOff = settings->value("ConfirmPowerOff", defPrefs.confirmPowerOff).toBool(); prefs.meter2Type = static_cast(settings->value("Meter2Type", defPrefs.meter2Type).toInt()); settings->endGroup(); // Load color schemes: // Per this bug: https://forum.qt.io/topic/24725/solved-qvariant-will-drop-alpha-value-when-save-qcolor/5 // the alpha channel is dropped when converting raw qvariant of QColor. Therefore, we are storing as unsigned int and converting back. settings->beginGroup("DarkColors"); prefs.colorScheme.Dark_PlotBackground = QColor::fromRgba(settings->value("Dark_PlotBackground", defaultColors.Dark_PlotBackground.rgba()).toUInt()); prefs.colorScheme.Dark_PlotAxisPen = QColor::fromRgba(settings->value("Dark_PlotAxisPen", defaultColors.Dark_PlotAxisPen.rgba()).toUInt()); prefs.colorScheme.Dark_PlotLegendTextColor = QColor::fromRgba(settings->value("Dark_PlotLegendTextColor", defaultColors.Dark_PlotLegendTextColor.rgba()).toUInt()); prefs.colorScheme.Dark_PlotLegendBorderPen = QColor::fromRgba(settings->value("Dark_PlotLegendBorderPen", defaultColors.Dark_PlotLegendBorderPen.rgba()).toUInt()); prefs.colorScheme.Dark_PlotLegendBrush = QColor::fromRgba(settings->value("Dark_PlotLegendBrush", defaultColors.Dark_PlotLegendBrush.rgba()).toUInt()); prefs.colorScheme.Dark_PlotTickLabel = QColor::fromRgba(settings->value("Dark_PlotTickLabel", defaultColors.Dark_PlotTickLabel.rgba()).toUInt()); prefs.colorScheme.Dark_PlotBasePen = QColor::fromRgba(settings->value("Dark_PlotBasePen", defaultColors.Dark_PlotBasePen.rgba()).toUInt()); prefs.colorScheme.Dark_PlotTickPen = QColor::fromRgba(settings->value("Dark_PlotTickPen", defaultColors.Dark_PlotTickPen.rgba()).toUInt()); prefs.colorScheme.Dark_PeakPlotLine = QColor::fromRgba(settings->value("Dark_PeakPlotLine", defaultColors.Dark_PeakPlotLine.rgba()).toUInt()); prefs.colorScheme.Dark_TuningLine = QColor::fromRgba(settings->value("Dark_TuningLine", defaultColors.Dark_TuningLine.rgba()).toUInt()); settings->endGroup(); settings->beginGroup("LightColors"); prefs.colorScheme.Light_PlotBackground = QColor::fromRgba(settings->value("Light_PlotBackground", defaultColors.Light_PlotBackground.rgba()).toUInt()); prefs.colorScheme.Light_PlotAxisPen = QColor::fromRgba(settings->value("Light_PlotAxisPen", defaultColors.Light_PlotAxisPen.rgba()).toUInt()); prefs.colorScheme.Light_PlotLegendTextColor = QColor::fromRgba(settings->value("Light_PlotLegendTextColo", defaultColors.Light_PlotLegendTextColor.rgba()).toUInt()); prefs.colorScheme.Light_PlotLegendBorderPen = QColor::fromRgba(settings->value("Light_PlotLegendBorderPen", defaultColors.Light_PlotLegendBorderPen.rgba()).toUInt()); prefs.colorScheme.Light_PlotLegendBrush = QColor::fromRgba(settings->value("Light_PlotLegendBrush", defaultColors.Light_PlotLegendBrush.rgba()).toUInt()); prefs.colorScheme.Light_PlotTickLabel = QColor::fromRgba(settings->value("Light_PlotTickLabel", defaultColors.Light_PlotTickLabel.rgba()).toUInt()); prefs.colorScheme.Light_PlotBasePen = QColor::fromRgba(settings->value("Light_PlotBasePen", defaultColors.Light_PlotBasePen.rgba()).toUInt()); prefs.colorScheme.Light_PlotTickPen = QColor::fromRgba(settings->value("Light_PlotTickPen", defaultColors.Light_PlotTickPen.rgba()).toUInt()); prefs.colorScheme.Light_PeakPlotLine = QColor::fromRgba(settings->value("Light_PeakPlotLine", defaultColors.Light_PeakPlotLine.rgba()).toUInt()); prefs.colorScheme.Light_TuningLine = QColor::fromRgba(settings->value("Light_TuningLine", defaultColors.Light_TuningLine.rgba()).toUInt()); settings->endGroup(); // Radio and Comms: C-IV addr, port to use settings->beginGroup("Radio"); prefs.radioCIVAddr = (unsigned char)settings->value("RigCIVuInt", defPrefs.radioCIVAddr).toInt(); if (prefs.radioCIVAddr != 0) { ui->rigCIVManualAddrChk->setChecked(true); ui->rigCIVaddrHexLine->blockSignals(true); ui->rigCIVaddrHexLine->setText(QString("%1").arg(prefs.radioCIVAddr, 2, 16)); ui->rigCIVaddrHexLine->setEnabled(true); ui->rigCIVaddrHexLine->blockSignals(false); } else { ui->rigCIVManualAddrChk->setChecked(false); ui->rigCIVaddrHexLine->setEnabled(false); } prefs.CIVisRadioModel = (bool)settings->value("CIVisRadioModel", defPrefs.CIVisRadioModel).toBool(); prefs.forceRTSasPTT = (bool)settings->value("ForceRTSasPTT", defPrefs.forceRTSasPTT).toBool(); ui->useRTSforPTTchk->setChecked(prefs.forceRTSasPTT); prefs.serialPortRadio = settings->value("SerialPortRadio", defPrefs.serialPortRadio).toString(); int serialIndex = ui->serialDeviceListCombo->findText(prefs.serialPortRadio); if (serialIndex != -1) { ui->serialDeviceListCombo->setCurrentIndex(serialIndex); } prefs.serialPortBaud = (quint32)settings->value("SerialPortBaud", defPrefs.serialPortBaud).toInt(); ui->baudRateCombo->blockSignals(true); ui->baudRateCombo->setCurrentIndex(ui->baudRateCombo->findData(prefs.serialPortBaud)); ui->baudRateCombo->blockSignals(false); if (prefs.serialPortBaud > 0) { serverConfig.baudRate = prefs.serialPortBaud; } prefs.virtualSerialPort = settings->value("VirtualSerialPort", defPrefs.virtualSerialPort).toString(); int vspIndex = ui->vspCombo->findText(prefs.virtualSerialPort); if (vspIndex != -1) { ui->vspCombo->setCurrentIndex(vspIndex); } else { ui->vspCombo->addItem(prefs.virtualSerialPort); ui->vspCombo->setCurrentIndex(ui->vspCombo->count() - 1); } prefs.localAFgain = (unsigned char)settings->value("localAFgain", defPrefs.localAFgain).toUInt(); rxSetup.localAFgain = prefs.localAFgain; txSetup.localAFgain = 255; prefs.audioSystem = static_cast(settings->value("AudioSystem", defPrefs.audioSystem).toInt()); ui->audioSystemCombo->blockSignals(true); ui->audioSystemCombo->setCurrentIndex(prefs.audioSystem); ui->audioSystemCombo->blockSignals(false); settings->endGroup(); // Misc. user settings (enable PTT, draw peaks, etc) settings->beginGroup("Controls"); prefs.enablePTT = settings->value("EnablePTT", defPrefs.enablePTT).toBool(); ui->pttEnableChk->setChecked(prefs.enablePTT); prefs.niceTS = settings->value("NiceTS", defPrefs.niceTS).toBool(); settings->endGroup(); settings->beginGroup("LAN"); prefs.enableLAN = settings->value("EnableLAN", defPrefs.enableLAN).toBool(); // If LAN is enabled, server gets its audio straight from the LAN ui->serverRXAudioInputCombo->setEnabled(!prefs.enableLAN); ui->serverTXAudioOutputCombo->setEnabled(!prefs.enableLAN); ui->baudRateCombo->setEnabled(!prefs.enableLAN); ui->serialDeviceListCombo->setEnabled(!prefs.enableLAN); ui->lanEnableBtn->setChecked(prefs.enableLAN); ui->connectBtn->setEnabled(true); prefs.enableRigCtlD = settings->value("EnableRigCtlD", defPrefs.enableRigCtlD).toBool(); ui->enableRigctldChk->setChecked(prefs.enableRigCtlD); prefs.rigCtlPort = settings->value("RigCtlPort", defPrefs.rigCtlPort).toInt(); ui->rigctldPortTxt->setText(QString("%1").arg(prefs.rigCtlPort)); // Call the function to start rigctld if enabled. on_enableRigctldChk_clicked(prefs.enableRigCtlD); prefs.tcpPort = settings->value("TcpServerPort", defPrefs.tcpPort).toInt(); ui->tcpServerPortTxt->setText(QString("%1").arg(prefs.tcpPort)); prefs.waterfallFormat = settings->value("WaterfallFormat", defPrefs.waterfallFormat).toInt(); ui->waterfallFormatCombo->blockSignals(true); ui->waterfallFormatCombo->setCurrentIndex(prefs.waterfallFormat); ui->waterfallFormatCombo->blockSignals(false); udpPrefs.ipAddress = settings->value("IPAddress", udpDefPrefs.ipAddress).toString(); ui->ipAddressTxt->setEnabled(ui->lanEnableBtn->isChecked()); ui->ipAddressTxt->setText(udpPrefs.ipAddress); udpPrefs.controlLANPort = settings->value("ControlLANPort", udpDefPrefs.controlLANPort).toInt(); ui->controlPortTxt->setEnabled(ui->lanEnableBtn->isChecked()); ui->controlPortTxt->setText(QString("%1").arg(udpPrefs.controlLANPort)); udpPrefs.username = settings->value("Username", udpDefPrefs.username).toString(); ui->usernameTxt->setEnabled(ui->lanEnableBtn->isChecked()); ui->usernameTxt->setText(QString("%1").arg(udpPrefs.username)); udpPrefs.password = settings->value("Password", udpDefPrefs.password).toString(); ui->passwordTxt->setEnabled(ui->lanEnableBtn->isChecked()); ui->passwordTxt->setText(QString("%1").arg(udpPrefs.password)); rxSetup.isinput = false; txSetup.isinput = true; rxSetup.latency = settings->value("AudioRXLatency", "150").toInt(); ui->rxLatencySlider->setEnabled(ui->lanEnableBtn->isChecked()); ui->rxLatencySlider->setValue(rxSetup.latency); ui->rxLatencySlider->setTracking(false); // Stop it sending value on every change. txSetup.latency = settings->value("AudioTXLatency", "150").toInt(); ui->txLatencySlider->setEnabled(ui->lanEnableBtn->isChecked()); ui->txLatencySlider->setValue(txSetup.latency); ui->txLatencySlider->setTracking(false); // Stop it sending value on every change. ui->audioSampleRateCombo->blockSignals(true); rxSetup.sampleRate=settings->value("AudioRXSampleRate", "48000").toInt(); txSetup.sampleRate=rxSetup.sampleRate; ui->audioSampleRateCombo->setEnabled(ui->lanEnableBtn->isChecked()); int audioSampleRateIndex = ui->audioSampleRateCombo->findText(QString::number(rxSetup.sampleRate)); if (audioSampleRateIndex != -1) { ui->audioSampleRateCombo->setCurrentIndex(audioSampleRateIndex); } ui->audioSampleRateCombo->blockSignals(false); // Add codec combobox items here so that we can add userdata! ui->audioRXCodecCombo->addItem("LPCM 1ch 16bit", 4); ui->audioRXCodecCombo->addItem("LPCM 1ch 8bit", 2); ui->audioRXCodecCombo->addItem("uLaw 1ch 8bit", 1); ui->audioRXCodecCombo->addItem("LPCM 2ch 16bit", 16); ui->audioRXCodecCombo->addItem("uLaw 2ch 8bit", 32); ui->audioRXCodecCombo->addItem("PCM 2ch 8bit", 8); ui->audioRXCodecCombo->addItem("Opus 1ch", 64); ui->audioRXCodecCombo->addItem("Opus 2ch", 128); ui->audioRXCodecCombo->blockSignals(true); rxSetup.codec = settings->value("AudioRXCodec", "4").toInt(); ui->audioRXCodecCombo->setEnabled(ui->lanEnableBtn->isChecked()); for (int f = 0; f < ui->audioRXCodecCombo->count(); f++) if (ui->audioRXCodecCombo->itemData(f).toInt() == rxSetup.codec) ui->audioRXCodecCombo->setCurrentIndex(f); ui->audioRXCodecCombo->blockSignals(false); ui->audioTXCodecCombo->addItem("LPCM 1ch 16bit", 4); ui->audioTXCodecCombo->addItem("LPCM 1ch 8bit", 2); ui->audioTXCodecCombo->addItem("uLaw 1ch 8bit", 1); ui->audioTXCodecCombo->addItem("Opus 1ch", 64); ui->audioRXCodecCombo->blockSignals(true); txSetup.codec = settings->value("AudioTXCodec", "4").toInt(); ui->audioTXCodecCombo->setEnabled(ui->lanEnableBtn->isChecked()); for (int f = 0; f < ui->audioTXCodecCombo->count(); f++) if (ui->audioTXCodecCombo->itemData(f).toInt() == txSetup.codec) ui->audioTXCodecCombo->setCurrentIndex(f); ui->audioRXCodecCombo->blockSignals(false); rxSetup.name = settings->value("AudioOutput", "").toString(); qInfo(logGui()) << "Got Audio Output from Settings: " << rxSetup.name; txSetup.name = settings->value("AudioInput", "").toString(); qInfo(logGui()) << "Got Audio Input from Settings: " << txSetup.name; rxSetup.resampleQuality = settings->value("ResampleQuality", "4").toInt(); txSetup.resampleQuality = rxSetup.resampleQuality; udpPrefs.clientName = settings->value("ClientName", udpDefPrefs.clientName).toString(); settings->endGroup(); settings->beginGroup("Server"); serverConfig.enabled = settings->value("ServerEnabled", false).toBool(); serverConfig.controlPort = settings->value("ServerControlPort", 50001).toInt(); serverConfig.civPort = settings->value("ServerCivPort", 50002).toInt(); serverConfig.audioPort = settings->value("ServerAudioPort", 50003).toInt(); serverConfig.users.clear(); int numUsers = settings->beginReadArray("Users"); if (numUsers > 0) { { for (int f = 0; f < numUsers; f++) { settings->setArrayIndex(f); SERVERUSER user; user.username = settings->value("Username", "").toString(); user.password = settings->value("Password", "").toString(); user.userType = settings->value("UserType", 0).toInt(); serverConfig.users.append(user); } } settings->endArray(); } else { /* Support old way of storing users*/ settings->endArray(); numUsers = settings->value("ServerNumUsers", 2).toInt(); for (int f = 0; f < numUsers; f++) { SERVERUSER user; user.username = settings->value("ServerUsername_" + QString::number(f), "").toString(); user.password = settings->value("ServerPassword_" + QString::number(f), "").toString(); user.userType = settings->value("ServerUserType_" + QString::number(f), 0).toInt(); serverConfig.users.append(user); } } ui->serverEnableCheckbox->setChecked(serverConfig.enabled); ui->serverControlPortText->setText(QString::number(serverConfig.controlPort)); ui->serverCivPortText->setText(QString::number(serverConfig.civPort)); ui->serverAudioPortText->setText(QString::number(serverConfig.audioPort)); RIGCONFIG* rigTemp = new RIGCONFIG(); rigTemp->rxAudioSetup.isinput = true; rigTemp->txAudioSetup.isinput = false; rigTemp->rxAudioSetup.localAFgain = 255; rigTemp->txAudioSetup.localAFgain = 255; rigTemp->rxAudioSetup.resampleQuality = 4; rigTemp->txAudioSetup.resampleQuality = 4; rigTemp->rxAudioSetup.type = prefs.audioSystem; rigTemp->txAudioSetup.type = prefs.audioSystem; rigTemp->baudRate = prefs.serialPortBaud; rigTemp->civAddr = prefs.radioCIVAddr; rigTemp->serialPort = prefs.serialPortBaud; QString guid = settings->value("GUID", "").toString(); if (guid.isEmpty()) { guid = QUuid::createUuid().toString(); settings->setValue("GUID", guid); } #if (QT_VERSION >= QT_VERSION_CHECK(5,10,0)) memcpy(rigTemp->guid, QUuid::fromString(guid).toRfc4122().constData(), GUIDLEN); #endif rigTemp->rxAudioSetup.name = settings->value("ServerAudioInput", "").toString(); rigTemp->txAudioSetup.name = settings->value("ServerAudioOutput", "").toString(); serverConfig.rigs.append(rigTemp); int row = 0; ui->serverUsersTable->setRowCount(0); foreach(SERVERUSER user, serverConfig.users) { if (user.username != "" && user.password != "") { serverAddUserLine(user.username, user.password, user.userType); row++; } } if (row == 0) { serverAddUserLine("", "", 0); } settings->endGroup(); // Memory channels settings->beginGroup("Memory"); int size = settings->beginReadArray("Channel"); int chan = 0; double freq; unsigned char mode; bool isSet; // Annoying: QSettings will write the array to the // preference file starting the array at 1 and ending at 100. // Thus, we are writing the channel number each time. // It is also annoying that they get written with their array // numbers in alphabetical order without zero padding. // Also annoying that the preference groups are not written in // the order they are specified here. for (int i = 0; i < size; i++) { settings->setArrayIndex(i); chan = settings->value("chan", 0).toInt(); freq = settings->value("freq", 12.345).toDouble(); mode = settings->value("mode", 0).toInt(); isSet = settings->value("isSet", false).toBool(); if (isSet) { mem.setPreset(chan, freq, (mode_kind)mode); } } settings->endArray(); settings->endGroup(); } void wfmain::serverAddUserLine(const QString& user, const QString& pass, const int& type) { ui->serverUsersTable->blockSignals(true); ui->serverUsersTable->insertRow(ui->serverUsersTable->rowCount()); ui->serverUsersTable->setItem(ui->serverUsersTable->rowCount() - 1, 0, new QTableWidgetItem(user)); ui->serverUsersTable->setItem(ui->serverUsersTable->rowCount() - 1, 1, new QTableWidgetItem()); ui->serverUsersTable->setItem(ui->serverUsersTable->rowCount() - 1, 2, new QTableWidgetItem()); QLineEdit* password = new QLineEdit(); password->setProperty("row", (int)ui->serverUsersTable->rowCount() - 1); password->setEchoMode(QLineEdit::PasswordEchoOnEdit); password->setText(pass); connect(password, SIGNAL(editingFinished()), this, SLOT(onServerPasswordChanged())); ui->serverUsersTable->setCellWidget(ui->serverUsersTable->rowCount() - 1, 1, password); QComboBox* comboBox = new QComboBox(); comboBox->insertItems(0, { "Full User","Full with no TX","Monitor only" }); comboBox->setCurrentIndex(type); ui->serverUsersTable->setCellWidget(ui->serverUsersTable->rowCount() - 1, 2, comboBox); ui->serverUsersTable->blockSignals(false); } void wfmain::onServerPasswordChanged() { int row = sender()->property("row").toInt(); QLineEdit* password = (QLineEdit*)ui->serverUsersTable->cellWidget(row, 1); QByteArray pass; passcode(password->text(), pass); password->setText(pass); qInfo() << "password row" << row << "changed"; serverConfig.users.clear(); for (int rows = 0; rows < ui->serverUsersTable->model()->rowCount(); rows++) { if (ui->serverUsersTable->item(rows, 0) != NULL) { SERVERUSER user; user.username = ui->serverUsersTable->item(rows, 0)->text(); QLineEdit* password = (QLineEdit*)ui->serverUsersTable->cellWidget(rows, 1); user.password = password->text(); QComboBox* comboBox = (QComboBox*)ui->serverUsersTable->cellWidget(rows, 2); user.userType = comboBox->currentIndex(); serverConfig.users.append(user); } else { ui->serverUsersTable->removeRow(rows); } } } void wfmain::on_serverUsersTable_cellClicked(int row, int col) { qInfo() << "Clicked on " << row << "," << col; if (row == ui->serverUsersTable->model()->rowCount() - 1 && ui->serverUsersTable->item(row, 0) != NULL) { serverAddUserLine("", "", 0); } } void wfmain::on_serverEnableCheckbox_clicked(bool checked) { ui->serverSetupGroup->setEnabled(checked); serverConfig.enabled = checked; setServerToPrefs(); } void wfmain::on_serverControlPortText_textChanged(QString text) { serverConfig.controlPort = text.toInt(); } void wfmain::on_serverCivPortText_textChanged(QString text) { serverConfig.civPort = text.toInt(); } void wfmain::on_serverAudioPortText_textChanged(QString text) { serverConfig.audioPort = text.toInt(); } void wfmain::on_serverRXAudioInputCombo_currentIndexChanged(int value) { if (!serverConfig.rigs.isEmpty()) { if (prefs.audioSystem == qtAudio) { QVariant v = ui->serverRXAudioInputCombo->itemData(value); serverConfig.rigs.first()->rxAudioSetup.port = v.value(); } else { serverConfig.rigs.first()->rxAudioSetup.portInt = ui->serverRXAudioInputCombo->itemData(value).toInt(); } serverConfig.rigs.first()->rxAudioSetup.name = ui->serverRXAudioInputCombo->itemText(value); } } void wfmain::on_serverTXAudioOutputCombo_currentIndexChanged(int value) { if (!serverConfig.rigs.isEmpty()) { if (prefs.audioSystem == qtAudio) { QVariant v = ui->serverTXAudioOutputCombo->itemData(value); serverConfig.rigs.first()->txAudioSetup.port = v.value(); } else { serverConfig.rigs.first()->txAudioSetup.portInt = ui->serverTXAudioOutputCombo->itemData(value).toInt(); } serverConfig.rigs.first()->txAudioSetup.name = ui->serverTXAudioOutputCombo->itemText(value); } } void wfmain::on_serverUsersTable_cellChanged(int row, int column) { qInfo() << "Cell Changed:" << row << "," << column; serverConfig.users.clear(); for (int rows = 0; rows < ui->serverUsersTable->model()->rowCount(); rows++) { if (ui->serverUsersTable->item(rows, 0) != NULL) { SERVERUSER user; user.username = ui->serverUsersTable->item(rows, 0)->text(); QLineEdit* password = (QLineEdit*)ui->serverUsersTable->cellWidget(rows, 1); user.password = password->text(); QComboBox* comboBox = (QComboBox*)ui->serverUsersTable->cellWidget(rows, 2); user.userType = comboBox->currentIndex(); serverConfig.users.append(user); } else { ui->serverUsersTable->removeRow(rows); } } } void wfmain::saveSettings() { qInfo(logSystem()) << "Saving settings to " << settings->fileName(); // Basic things to load: // UI: (full screen, dark theme, draw peaks, colors, etc) settings->beginGroup("Interface"); settings->setValue("UseFullScreen", prefs.useFullScreen); settings->setValue("UseSystemTheme", prefs.useSystemTheme); settings->setValue("UseDarkMode", prefs.useDarkMode); settings->setValue("DrawPeaks", prefs.drawPeaks); settings->setValue("underlayMode", prefs.underlayMode); settings->setValue("underlayBufferSize", prefs.underlayBufferSize); settings->setValue("WFAntiAlias", prefs.wfAntiAlias); settings->setValue("WFInterpolate", prefs.wfInterpolate); settings->setValue("WFTheme", prefs.wftheme); settings->setValue("plotFloor", prefs.plotFloor); settings->setValue("plotCeiling", prefs.plotCeiling); settings->setValue("StylesheetPath", prefs.stylesheetPath); settings->setValue("splitter", ui->splitter->saveState()); settings->setValue("windowGeometry", saveGeometry()); settings->setValue("windowState", saveState()); settings->setValue("WFLength", prefs.wflength); settings->setValue("ConfirmExit", prefs.confirmExit); settings->setValue("ConfirmPowerOff", prefs.confirmPowerOff); settings->setValue("Meter2Type", (int)prefs.meter2Type); settings->endGroup(); // Radio and Comms: C-IV addr, port to use settings->beginGroup("Radio"); settings->setValue("RigCIVuInt", prefs.radioCIVAddr); settings->setValue("CIVisRadioModel", prefs.CIVisRadioModel); settings->setValue("ForceRTSasPTT", prefs.forceRTSasPTT); settings->setValue("SerialPortRadio", prefs.serialPortRadio); settings->setValue("SerialPortBaud", prefs.serialPortBaud); settings->setValue("VirtualSerialPort", prefs.virtualSerialPort); settings->setValue("localAFgain", prefs.localAFgain); settings->setValue("AudioSystem", prefs.audioSystem); settings->endGroup(); // Misc. user settings (enable PTT, draw peaks, etc) settings->beginGroup("Controls"); settings->setValue("EnablePTT", prefs.enablePTT); settings->setValue("NiceTS", prefs.niceTS); settings->endGroup(); settings->beginGroup("LAN"); settings->setValue("EnableLAN", prefs.enableLAN); settings->setValue("EnableRigCtlD", prefs.enableRigCtlD); settings->setValue("TcpServerPort", prefs.tcpPort); settings->setValue("RigCtlPort", prefs.rigCtlPort); settings->setValue("tcpServerPort", prefs.tcpPort); settings->setValue("IPAddress", udpPrefs.ipAddress); settings->setValue("ControlLANPort", udpPrefs.controlLANPort); settings->setValue("SerialLANPort", udpPrefs.serialLANPort); settings->setValue("AudioLANPort", udpPrefs.audioLANPort); settings->setValue("Username", udpPrefs.username); settings->setValue("Password", udpPrefs.password); settings->setValue("AudioRXLatency", rxSetup.latency); settings->setValue("AudioTXLatency", txSetup.latency); settings->setValue("AudioRXSampleRate", rxSetup.sampleRate); settings->setValue("AudioRXCodec", rxSetup.codec); settings->setValue("AudioTXSampleRate", txSetup.sampleRate); settings->setValue("AudioTXCodec", txSetup.codec); settings->setValue("AudioOutput", rxSetup.name); settings->setValue("AudioInput", txSetup.name); settings->setValue("ResampleQuality", rxSetup.resampleQuality); settings->setValue("ClientName", udpPrefs.clientName); settings->setValue("WaterfallFormat", prefs.waterfallFormat); settings->endGroup(); // Memory channels settings->beginGroup("Memory"); settings->beginWriteArray("Channel", (int)mem.getNumPresets()); preset_kind temp; for(int i=0; i < (int)mem.getNumPresets(); i++) { temp = mem.getPreset((int)i); settings->setArrayIndex(i); settings->setValue("chan", i); settings->setValue("freq", temp.frequency); settings->setValue("mode", temp.mode); settings->setValue("isSet", temp.isSet); } settings->endArray(); settings->endGroup(); // Note: X and Y get the same colors. See setPlotTheme() function settings->beginGroup("DarkColors"); settings->setValue("Dark_PlotBackground", prefs.colorScheme.Dark_PlotBackground.rgba()); settings->setValue("Dark_PlotAxisPen", prefs.colorScheme.Dark_PlotAxisPen.rgba()); settings->setValue("Dark_PlotLegendTextColor", prefs.colorScheme.Dark_PlotLegendTextColor.rgba()); settings->setValue("Dark_PlotLegendBorderPen", prefs.colorScheme.Dark_PlotLegendBorderPen.rgba()); settings->setValue("Dark_PlotLegendBrush", prefs.colorScheme.Dark_PlotLegendBrush.rgba()); settings->setValue("Dark_PlotTickLabel", prefs.colorScheme.Dark_PlotTickLabel.rgba()); settings->setValue("Dark_PlotBasePen", prefs.colorScheme.Dark_PlotBasePen.rgba()); settings->setValue("Dark_PlotTickPen", prefs.colorScheme.Dark_PlotTickPen.rgba()); settings->setValue("Dark_PeakPlotLine", prefs.colorScheme.Dark_PeakPlotLine.rgba()); settings->setValue("Dark_TuningLine", prefs.colorScheme.Dark_TuningLine.rgba()); settings->endGroup(); settings->beginGroup("LightColors"); settings->setValue("Light_PlotBackground", prefs.colorScheme.Light_PlotBackground.rgba()); settings->setValue("Light_PlotAxisPen", prefs.colorScheme.Light_PlotAxisPen.rgba()); settings->setValue("Light_PlotLegendTextColor", prefs.colorScheme.Light_PlotLegendTextColor.rgba()); settings->setValue("Light_PlotLegendBorderPen", prefs.colorScheme.Light_PlotLegendBorderPen.rgba()); settings->setValue("Light_PlotLegendBrush", prefs.colorScheme.Light_PlotLegendBrush.rgba()); settings->setValue("Light_PlotTickLabel", prefs.colorScheme.Light_PlotTickLabel.rgba()); settings->setValue("Light_PlotBasePen", prefs.colorScheme.Light_PlotBasePen.rgba()); settings->setValue("Light_PlotTickPen", prefs.colorScheme.Light_PlotTickPen.rgba()); settings->setValue("Light_PeakPlotLine", prefs.colorScheme.Light_PeakPlotLine.rgba()); settings->setValue("Light_TuningLine", prefs.colorScheme.Light_TuningLine.rgba()); settings->endGroup(); // This is a reference to see how the preference file is encoded. settings->beginGroup("StandardColors"); settings->setValue("white", QColor(Qt::white).rgba()); settings->setValue("black", QColor(Qt::black).rgba()); settings->setValue("red_opaque", QColor(Qt::red).rgba()); settings->setValue("red_translucent", QColor(255,0,0,128).rgba()); settings->setValue("green_opaque", QColor(Qt::green).rgba()); settings->setValue("green_translucent", QColor(0,255,0,128).rgba()); settings->setValue("blue_opaque", QColor(Qt::blue).rgba()); settings->setValue("blue_translucent", QColor(0,0,255,128).rgba()); settings->setValue("cyan", QColor(Qt::cyan).rgba()); settings->setValue("magenta", QColor(Qt::magenta).rgba()); settings->setValue("yellow", QColor(Qt::yellow).rgba()); settings->endGroup(); settings->beginGroup("Server"); settings->setValue("ServerEnabled", serverConfig.enabled); settings->setValue("ServerControlPort", serverConfig.controlPort); settings->setValue("ServerCivPort", serverConfig.civPort); settings->setValue("ServerAudioPort", serverConfig.audioPort); settings->setValue("ServerAudioOutput", serverConfig.rigs.first()->txAudioSetup.name); settings->setValue("ServerAudioInput", serverConfig.rigs.first()->rxAudioSetup.name); /* Remove old format users*/ int numUsers = settings->value("ServerNumUsers", 0).toInt(); if (numUsers > 0) { settings->remove("ServerNumUsers"); for (int f = 0; f < numUsers; f++) { settings->remove("ServerUsername_" + QString::number(f)); settings->remove("ServerPassword_" + QString::number(f)); settings->remove("ServerUserType_" + QString::number(f)); } } settings->beginWriteArray("Users"); for (int f = 0; f < serverConfig.users.count(); f++) { settings->setArrayIndex(f); settings->setValue("Username", serverConfig.users[f].username); settings->setValue("Password", serverConfig.users[f].password); settings->setValue("UserType", serverConfig.users[f].userType); } settings->endArray(); qInfo() << "Server config stored"; settings->endGroup(); settings->sync(); // Automatic, not needed (supposedly) } void wfmain::showHideSpectrum(bool show) { if(show) { wf->show(); plot->show(); } else { wf->hide(); plot->hide(); } // Controls: ui->spectrumGroupBox->setVisible(show); ui->spectrumModeCombo->setVisible(show); ui->scopeBWCombo->setVisible(show); ui->scopeEdgeCombo->setVisible(show); ui->scopeEnableWFBtn->setVisible(show); ui->scopeRefLevelSlider->setEnabled(show); ui->wfLengthSlider->setEnabled(show); ui->wfthemeCombo->setVisible(show); ui->toFixedBtn->setVisible(show); ui->clearPeakBtn->setVisible(show); // And the labels: ui->specEdgeLabel->setVisible(show); ui->specModeLabel->setVisible(show); ui->specSpanLabel->setVisible(show); ui->specThemeLabel->setVisible(show); // And the layout for space: ui->specControlsHorizLayout->setEnabled(show); ui->splitter->setVisible(show); ui->plot->setVisible(show); ui->waterfall->setVisible(show); ui->spectrumGroupBox->setEnabled(show); // Window resize: updateSizes(ui->tabWidget->currentIndex()); } void wfmain::prepareWf() { prepareWf(160); } void wfmain::prepareWf(unsigned int wfLength) { // All this code gets moved in from the constructor of wfmain. if(haveRigCaps) { showHideSpectrum(rigCaps.hasSpectrum); if(!rigCaps.hasSpectrum) { return; } // TODO: Lock the function that draws on the spectrum while we are updating. spectrumDrawLock = true; spectWidth = rigCaps.spectLenMax; wfLengthMax = 1024; this->wfLength = wfLength; // fixed for now, time-length of waterfall // Initialize before use! QByteArray empty((int)spectWidth, '\x01'); spectrumPeaks = QByteArray( (int)spectWidth, '\x01' ); if(spectrumPlasmaSize == 0) spectrumPlasmaSize = 128; //spectrumPlasma.resize(spectrumPlasmaSize); for(unsigned int p=0; p < spectrumPlasmaSize; p++) { spectrumPlasma.append(empty); } //wfimage.resize(wfLengthMax); if((unsigned int)wfimage.size() < wfLengthMax) { unsigned int i=0; unsigned int oldSize = wfimage.size(); for(i=oldSize; i<(wfLengthMax); i++) { wfimage.append(empty); } } else { // Keep wfimage, do not trim, no performance impact. //wfimage.remove(wfLength, wfimage.size()-wfLength); } wfimage.squeeze(); //colorMap->clearData(); colorMap->data()->clear(); colorMap->data()->setValueRange(QCPRange(0, wfLength-1)); colorMap->data()->setKeyRange(QCPRange(0, spectWidth-1)); colorMap->setDataRange(QCPRange(0, rigCaps.spectAmpMax)); colorMap->setGradient(static_cast(ui->wfthemeCombo->currentData().toInt())); if(colorMapData == Q_NULLPTR) { colorMapData = new QCPColorMapData(spectWidth, wfLength, QCPRange(0, spectWidth-1), QCPRange(0, wfLength-1)); } else { //delete colorMapData; // TODO: Figure out why it crashes if we delete first. colorMapData = new QCPColorMapData(spectWidth, wfLength, QCPRange(0, spectWidth-1), QCPRange(0, wfLength-1)); } colorMap->setData(colorMapData); wf->yAxis->setRangeReversed(true); wf->xAxis->setVisible(false); spectrumDrawLock = false; } else { qInfo(logSystem()) << "Cannot prepare WF view without rigCaps. Waiting on this."; return; } } // Key shortcuts (hotkeys) void wfmain::shortcutF11() { if(onFullscreen) { this->showNormal(); onFullscreen = false; } else { this->showFullScreen(); onFullscreen = true; } ui->fullScreenChk->setChecked(onFullscreen); } void wfmain::shortcutF1() { ui->tabWidget->setCurrentIndex(0); } void wfmain::shortcutF2() { ui->tabWidget->setCurrentIndex(1); } void wfmain::shortcutF3() { ui->tabWidget->setCurrentIndex(2); ui->freqMhzLineEdit->clear(); ui->freqMhzLineEdit->setFocus(); } void wfmain::shortcutF4() { ui->tabWidget->setCurrentIndex(3); } // Mode switch keys: void wfmain::shortcutF5() { // LSB changeMode(modeLSB, false); } void wfmain::shortcutF6() { // USB changeMode(modeUSB, false); } void wfmain::shortcutF7() { // AM changeMode(modeAM, false); } void wfmain::shortcutF8() { // CW changeMode(modeCW, false); } void wfmain::shortcutF9() { // USB-D changeMode(modeUSB, true); } void wfmain::shortcutF10() { // FM changeMode(modeFM, false); } void wfmain::shortcutF12() { // Speak current frequency and mode from the radio showStatusBarText("Sending speech command to radio."); emit sayAll(); } void wfmain::shortcutControlT() { // Transmit qInfo(logSystem()) << "Activated Control-T shortcut"; showStatusBarText(QString("Transmitting. Press Control-R to receive.")); ui->pttOnBtn->click(); } void wfmain::shortcutControlR() { // Receive issueCmdUniquePriority(cmdSetPTT, false); pttTimer->stop(); } void wfmain::shortcutControlI() { // Enable ATU ui->tuneEnableChk->click(); } void wfmain::shortcutControlU() { // Run ATU tuning cycle ui->tuneNowBtn->click(); } void wfmain::shortcutStar() { // Jump to frequency tab from Asterisk key on keypad ui->tabWidget->setCurrentIndex(2); ui->freqMhzLineEdit->clear(); ui->freqMhzLineEdit->setFocus(); } void wfmain::shortcutSlash() { // Cycle through available modes ui->modeSelectCombo->setCurrentIndex( (ui->modeSelectCombo->currentIndex()+1) % ui->modeSelectCombo->count() ); on_modeSelectCombo_activated( ui->modeSelectCombo->currentIndex() ); } void wfmain::setTuningSteps() { // TODO: interact with preferences, tuning step drop down box, and current operating mode // Units are MHz: tsPlusControl = 0.010f; tsPlus = 0.001f; tsPlusShift = 0.0001f; tsPage = 1.0f; tsPageShift = 0.5f; // TODO, unbind this keystroke from the dial tsWfScroll = 0.0001f; // modified by tuning step selector tsKnobMHz = 0.0001f; // modified by tuning step selector // Units are in Hz: tsPlusControlHz = 10000; tsPlusHz = 1000; tsPlusShiftHz = 100; tsPageHz = 1000000; tsPageShiftHz = 500000; // TODO, unbind this keystroke from the dial tsWfScrollHz = 100; // modified by tuning step selector tsKnobHz = 100; // modified by tuning step selector } void wfmain::on_tuningStepCombo_currentIndexChanged(int index) { tsWfScroll = (float)ui->tuningStepCombo->itemData(index).toUInt() / 1000000.0; tsKnobMHz = (float)ui->tuningStepCombo->itemData(index).toUInt() / 1000000.0; tsWfScrollHz = ui->tuningStepCombo->itemData(index).toUInt(); tsKnobHz = ui->tuningStepCombo->itemData(index).toUInt(); } quint64 wfmain::roundFrequency(quint64 frequency, unsigned int tsHz) { quint64 rounded = 0; if(ui->tuningFloorZerosChk->isChecked()) { rounded = ((frequency % tsHz) > tsHz/2) ? frequency + tsHz - frequency%tsHz : frequency - frequency%tsHz; return rounded; } else { return frequency; } } quint64 wfmain::roundFrequencyWithStep(quint64 frequency, int steps, unsigned int tsHz) { quint64 rounded = 0; if(steps > 0) { frequency = frequency + (quint64)(steps*tsHz); } else { frequency = frequency - std::min((quint64)(abs(steps)*tsHz), frequency); } if(ui->tuningFloorZerosChk->isChecked()) { rounded = ((frequency % tsHz) > tsHz/2) ? frequency + tsHz - frequency%tsHz : frequency - frequency%tsHz; return rounded; } else { return frequency; } } void wfmain::shortcutMinus() { if(freqLock) return; freqt f; f.Hz = roundFrequencyWithStep(freq.Hz, -1, tsPlusHz); f.MHzDouble = f.Hz / (double)1E6; setUIFreq(); //emit setFrequency(0,f); issueCmd(cmdSetFreq, f); issueDelayedCommandUnique(cmdGetFreq); } void wfmain::shortcutPlus() { if(freqLock) return; freqt f; f.Hz = roundFrequencyWithStep(freq.Hz, 1, tsPlusHz); f.MHzDouble = f.Hz / (double)1E6; setUIFreq(); //emit setFrequency(0,f); issueCmd(cmdSetFreq, f); issueDelayedCommandUnique(cmdGetFreq); } void wfmain::shortcutShiftMinus() { if(freqLock) return; freqt f; f.Hz = roundFrequencyWithStep(freq.Hz, -1, tsPlusShiftHz); f.MHzDouble = f.Hz / (double)1E6; setUIFreq(); //emit setFrequency(0,f); issueCmd(cmdSetFreq, f); issueDelayedCommandUnique(cmdGetFreq); } void wfmain::shortcutShiftPlus() { if(freqLock) return; freqt f; f.Hz = roundFrequencyWithStep(freq.Hz, 1, tsPlusShiftHz); f.MHzDouble = f.Hz / (double)1E6; setUIFreq(); //emit setFrequency(0,f); issueCmd(cmdSetFreq, f); issueDelayedCommandUnique(cmdGetFreq); } void wfmain::shortcutControlMinus() { if(freqLock) return; freqt f; f.Hz = roundFrequencyWithStep(freq.Hz, -1, tsPlusControlHz); f.MHzDouble = f.Hz / (double)1E6; setUIFreq(); //emit setFrequency(0,f); issueCmd(cmdSetFreq, f); issueDelayedCommandUnique(cmdGetFreq); } void wfmain::shortcutControlPlus() { if(freqLock) return; freqt f; f.Hz = roundFrequencyWithStep(freq.Hz, 1, tsPlusControlHz); f.MHzDouble = f.Hz / (double)1E6; setUIFreq(); //emit setFrequency(0,f); issueCmd(cmdSetFreq, f); issueDelayedCommandUnique(cmdGetFreq); } void wfmain::shortcutPageUp() { if(freqLock) return; freqt f; f.Hz = freq.Hz + tsPageHz; f.MHzDouble = f.Hz / (double)1E6; setUIFreq(); //emit setFrequency(0,f); issueCmd(cmdSetFreq, f); issueDelayedCommandUnique(cmdGetFreq); } void wfmain::shortcutPageDown() { if(freqLock) return; freqt f; f.Hz = freq.Hz - tsPageHz; f.MHzDouble = f.Hz / (double)1E6; setUIFreq(); //emit setFrequency(0,f); issueCmd(cmdSetFreq, f); issueDelayedCommandUnique(cmdGetFreq); } void wfmain::shortcutF() { showStatusBarText("Sending speech command (frequency) to radio."); emit sayFrequency(); } void wfmain::shortcutM() { showStatusBarText("Sending speech command (mode) to radio."); emit sayMode(); } void wfmain::setUIFreq(double frequency) { ui->freqLabel->setText(QString("%1").arg(frequency, 0, 'f')); } void wfmain::setUIFreq() { // Call this function, without arguments, if you know that the // freqMhz variable is already set correctly. setUIFreq(freq.MHzDouble); } void wfmain:: getInitialRigState() { // Initial list of queries to the radio. // These are made when the program starts up // and are used to adjust the UI to match the radio settings // the polling interval is set at 200ms. Faster is possible but slower // computers will glitch occasionally. issueDelayedCommand(cmdGetFreq); issueDelayedCommand(cmdGetMode); issueDelayedCommand(cmdNone); issueDelayedCommand(cmdGetFreq); issueDelayedCommand(cmdGetMode); // From left to right in the UI: if (rigCaps.hasTransmit) { issueDelayedCommand(cmdGetDataMode); issueDelayedCommand(cmdGetModInput); issueDelayedCommand(cmdGetModDataInput); } issueDelayedCommand(cmdGetRxGain); issueDelayedCommand(cmdGetAfGain); issueDelayedCommand(cmdGetSql); if (rigCaps.hasTransmit) { issueDelayedCommand(cmdGetTxPower); issueDelayedCommand(cmdGetCurrentModLevel); // level for currently selected mod sources } issueDelayedCommand(cmdGetSpectrumRefLevel); issueDelayedCommand(cmdGetDuplexMode); if(rigCaps.hasSpectrum) { issueDelayedCommand(cmdDispEnable); issueDelayedCommand(cmdSpecOn); } if (rigCaps.hasTransmit) { issueDelayedCommand(cmdGetModInput); issueDelayedCommand(cmdGetModDataInput); } if(rigCaps.hasCTCSS) { issueDelayedCommand(cmdGetTone); issueDelayedCommand(cmdGetTSQL); } if(rigCaps.hasDTCS) { issueDelayedCommand(cmdGetDTCS); } issueDelayedCommand(cmdGetRptAccessMode); if(rigCaps.hasAntennaSel) { issueDelayedCommand(cmdGetAntenna); } if(rigCaps.hasAttenuator) { issueDelayedCommand(cmdGetAttenuator); } if(rigCaps.hasPreamp) { issueDelayedCommand(cmdGetPreamp); } issueDelayedCommand(cmdGetRitEnabled); issueDelayedCommand(cmdGetRitValue); if(rigCaps.hasIFShift) issueDelayedCommand(cmdGetIFShift); if(rigCaps.hasTBPF) { issueDelayedCommand(cmdGetTPBFInner); issueDelayedCommand(cmdGetTPBFOuter); } if(rigCaps.hasSpectrum) { issueDelayedCommand(cmdGetSpectrumMode); issueDelayedCommand(cmdGetSpectrumSpan); } issueDelayedCommand(cmdNone); issueDelayedCommand(cmdStartRegularPolling); if(rigCaps.hasATU) { issueDelayedCommand(cmdGetATUStatus); } delayedCommand->start(); } void wfmain::showStatusBarText(QString text) { ui->statusBar->showMessage(text, 5000); } void wfmain::on_useDarkThemeChk_clicked(bool checked) { //setAppTheme(checked); setPlotTheme(wf, checked); setPlotTheme(plot, checked); prefs.useDarkMode = checked; } void wfmain::on_useSystemThemeChk_clicked(bool checked) { setAppTheme(!checked); prefs.useSystemTheme = checked; } void wfmain::setAppTheme(bool isCustom) { if(isCustom) { #ifndef Q_OS_LINUX QFile f(":"+prefs.stylesheetPath); // built-in resource #else QFile f(PREFIX "/share/wfview/" + prefs.stylesheetPath); #endif if (!f.exists()) { printf("Unable to set stylesheet, file not found\n"); printf("Tried to load: [%s]\n", f.fileName().toStdString().c_str() ); } else { f.open(QFile::ReadOnly | QFile::Text); QTextStream ts(&f); qApp->setStyleSheet(ts.readAll()); } } else { qApp->setStyleSheet(""); } } void wfmain::setDefaultColors() { defaultColors.Dark_PlotBackground = QColor(0,0,0,255); defaultColors.Dark_PlotAxisPen = QColor(75,75,75,255); defaultColors.Dark_PlotLegendTextColor = QColor(255,255,255,255); defaultColors.Dark_PlotLegendBorderPen = QColor(255,255,255,255); defaultColors.Dark_PlotLegendBrush = QColor(0,0,0,200); defaultColors.Dark_PlotTickLabel = QColor(Qt::white); defaultColors.Dark_PlotBasePen = QColor(Qt::white); defaultColors.Dark_PlotTickPen = QColor(Qt::white); defaultColors.Dark_PeakPlotLine = QColor(Qt::yellow); defaultColors.Dark_TuningLine = QColor(Qt::cyan); defaultColors.Light_PlotBackground = QColor(255,255,255,255); defaultColors.Light_PlotAxisPen = QColor(200,200,200,255); defaultColors.Light_PlotLegendTextColor = QColor(0,0,0,255); defaultColors.Light_PlotLegendBorderPen = QColor(0,0,0,255); defaultColors.Light_PlotLegendBrush = QColor(255,255,255,200); defaultColors.Light_PlotTickLabel = QColor(Qt::black); defaultColors.Light_PlotBasePen = QColor(Qt::black); defaultColors.Light_PlotTickPen = QColor(Qt::black); defaultColors.Light_PeakPlotLine = QColor(Qt::blue); defaultColors.Light_TuningLine = QColor(Qt::blue); } void wfmain::setPlotTheme(QCustomPlot *plot, bool isDark) { if(isDark) { plot->setBackground(prefs.colorScheme.Dark_PlotBackground); //plot->setBackground(QColor(0,0,0,255)); plot->xAxis->grid()->setPen(prefs.colorScheme.Dark_PlotAxisPen); plot->yAxis->grid()->setPen(prefs.colorScheme.Dark_PlotAxisPen); plot->legend->setTextColor(prefs.colorScheme.Dark_PlotLegendTextColor); plot->legend->setBorderPen(prefs.colorScheme.Dark_PlotLegendBorderPen); plot->legend->setBrush(prefs.colorScheme.Dark_PlotLegendBrush); plot->xAxis->setTickLabelColor(prefs.colorScheme.Dark_PlotTickLabel); plot->xAxis->setLabelColor(prefs.colorScheme.Dark_PlotTickLabel); plot->yAxis->setTickLabelColor(prefs.colorScheme.Dark_PlotTickLabel); plot->yAxis->setLabelColor(prefs.colorScheme.Dark_PlotTickLabel); plot->xAxis->setBasePen(prefs.colorScheme.Dark_PlotBasePen); plot->xAxis->setTickPen(prefs.colorScheme.Dark_PlotTickPen); plot->yAxis->setBasePen(prefs.colorScheme.Dark_PlotBasePen); plot->yAxis->setTickPen(prefs.colorScheme.Dark_PlotTickPen); plot->graph(0)->setPen(prefs.colorScheme.Dark_PeakPlotLine); freqIndicatorLine->setPen(prefs.colorScheme.Dark_TuningLine); } else { //color = ui->groupBox->palette().color(QPalette::Button); plot->setBackground(prefs.colorScheme.Light_PlotBackground); plot->xAxis->grid()->setPen(prefs.colorScheme.Light_PlotAxisPen); plot->yAxis->grid()->setPen(prefs.colorScheme.Light_PlotAxisPen); plot->legend->setTextColor(prefs.colorScheme.Light_PlotLegendTextColor); plot->legend->setBorderPen(prefs.colorScheme.Light_PlotLegendBorderPen); plot->legend->setBrush(prefs.colorScheme.Light_PlotLegendBrush); plot->xAxis->setTickLabelColor(prefs.colorScheme.Light_PlotTickLabel); plot->xAxis->setLabelColor(prefs.colorScheme.Light_PlotTickLabel); plot->yAxis->setTickLabelColor(prefs.colorScheme.Light_PlotTickLabel); plot->yAxis->setLabelColor(prefs.colorScheme.Light_PlotTickLabel); plot->xAxis->setBasePen(prefs.colorScheme.Light_PlotBasePen); plot->xAxis->setTickPen(prefs.colorScheme.Light_PlotTickPen); plot->yAxis->setBasePen(prefs.colorScheme.Light_PlotBasePen); plot->yAxis->setTickPen(prefs.colorScheme.Light_PlotTickLabel); plot->graph(0)->setPen(prefs.colorScheme.Light_PeakPlotLine); freqIndicatorLine->setPen(prefs.colorScheme.Light_TuningLine); } } void wfmain::doCmd(commandtype cmddata) { cmds cmd = cmddata.cmd; std::shared_ptr data = cmddata.data; // This switch is for commands with parameters. // the "default" for non-parameter commands is to call doCmd(cmd). switch (cmd) { case cmdSetFreq: { lastFreqCmdTime_ms = QDateTime::currentMSecsSinceEpoch(); freqt f = (*std::static_pointer_cast(data)); emit setFrequency(0,f); break; } case cmdSetMode: { mode_info m = (*std::static_pointer_cast(data)); emit setMode(m); break; } case cmdSetTxPower: { unsigned char txpower = (*std::static_pointer_cast(data)); emit setTxPower(txpower); break; } case cmdSetMicGain: { unsigned char micgain = (*std::static_pointer_cast(data)); emit setTxPower(micgain); break; } case cmdSetRxRfGain: { unsigned char rfgain = (*std::static_pointer_cast(data)); emit setRfGain(rfgain); break; } case cmdSetModLevel: { unsigned char modlevel = (*std::static_pointer_cast(data)); rigInput currentIn; if(usingDataMode) { currentIn = currentModDataSrc; } else { currentIn = currentModSrc; } emit setModLevel(currentIn, modlevel); break; } case cmdSetAfGain: { unsigned char afgain = (*std::static_pointer_cast(data)); emit setAfGain(afgain); break; } case cmdSetSql: { unsigned char sqlLevel = (*std::static_pointer_cast(data)); emit setSql(sqlLevel); break; } case cmdSetIFShift: { unsigned char IFShiftLevel = (*std::static_pointer_cast(data)); emit setIFShift(IFShiftLevel); break; } case cmdSetTPBFInner: { unsigned char innterLevel = (*std::static_pointer_cast(data)); emit setTPBFInner(innterLevel); break; } case cmdSetTPBFOuter: { unsigned char outerLevel = (*std::static_pointer_cast(data)); emit setTPBFOuter(outerLevel); break; } case cmdSetPTT: { bool pttrequest = (*std::static_pointer_cast(data)); emit setPTT(pttrequest); ui->meter2Widget->clearMeterOnPTTtoggle(); if(pttrequest) { ui->meterSPoWidget->setMeterType(meterPower); } else { ui->meterSPoWidget->setMeterType(meterS); } break; } case cmdSetATU: { bool atuOn = (*std::static_pointer_cast(data)); emit setATU(atuOn); break; } case cmdSetUTCOffset: { timekind u = (*std::static_pointer_cast(data)); emit setUTCOffset(u); break; } case cmdSetTime: { timekind t = (*std::static_pointer_cast(data)); emit setTime(t); break; } case cmdSetDate: { datekind d = (*std::static_pointer_cast(data)); emit setDate(d); break; } default: doCmd(cmd); break; } } void wfmain::doCmd(cmds cmd) { // Use this function to take action upon a command. switch(cmd) { case cmdNone: //qInfo(logSystem()) << "NOOP"; break; case cmdGetRigID: emit getRigID(); break; case cmdGetRigCIV: // if(!know rig civ already) if(!haveRigCaps) { emit getRigCIV(); issueDelayedCommand(cmdGetRigCIV); // This way, we stay here until we get an answer. } break; case cmdGetFreq: emit getFrequency(); break; case cmdGetMode: emit getMode(); break; case cmdGetDataMode: if(rigCaps.hasDataModes) emit getDataMode(); break; case cmdSetModeFilter: emit setMode(setModeVal, setFilterVal); break; case cmdSetDataModeOff: emit setDataMode(false, (unsigned char)ui->modeFilterCombo->currentData().toInt()); break; case cmdSetDataModeOn: emit setDataMode(true, (unsigned char)ui->modeFilterCombo->currentData().toInt()); break; case cmdGetRitEnabled: emit getRitEnabled(); break; case cmdGetRitValue: emit getRitValue(); break; case cmdGetModInput: emit getModInput(false); break; case cmdGetModDataInput: emit getModInput(true); break; case cmdGetCurrentModLevel: // TODO: Add delay between these queries emit getModInputLevel(currentModSrc); emit getModInputLevel(currentModDataSrc); break; case cmdGetDuplexMode: emit getDuplexMode(); break; case cmdGetTone: emit getTone(); break; case cmdGetTSQL: emit getTSQL(); break; case cmdGetDTCS: emit getDTCS(); break; case cmdGetRptAccessMode: emit getRptAccessMode(); break; case cmdDispEnable: emit scopeDisplayEnable(); break; case cmdDispDisable: emit scopeDisplayDisable(); break; case cmdGetSpectrumMode: emit getScopeMode(); break; case cmdGetSpectrumSpan: emit getScopeSpan(); break; case cmdSpecOn: emit spectOutputEnable(); break; case cmdSpecOff: emit spectOutputDisable(); break; case cmdGetRxGain: emit getRfGain(); break; case cmdGetAfGain: emit getAfGain(); break; case cmdGetSql: emit getSql(); break; case cmdGetIFShift: emit getIfShift(); break; case cmdGetTPBFInner: emit getTPBFInner(); break; case cmdGetTPBFOuter: emit getTPBFOuter(); break; case cmdGetTxPower: emit getTxPower(); break; case cmdGetMicGain: emit getMicGain(); break; case cmdGetSpectrumRefLevel: emit getSpectrumRefLevel(); break; case cmdGetATUStatus: if(rigCaps.hasATU) emit getATUStatus(); break; case cmdStartATU: if(rigCaps.hasATU) emit startATU(); break; case cmdGetAttenuator: emit getAttenuator(); break; case cmdGetPreamp: emit getPreamp(); break; case cmdGetAntenna: emit getAntenna(); break; case cmdScopeCenterMode: emit setScopeMode(spectModeCenter); break; case cmdScopeFixedMode: emit setScopeMode(spectModeFixed); break; case cmdGetPTT: emit getPTT(); break; case cmdGetTxRxMeter: if(amTransmitting) emit getMeters(meterPower); else emit getMeters(meterS); break; case cmdGetSMeter: if(!amTransmitting) emit getMeters(meterS); break; case cmdGetCenterMeter: if(!amTransmitting) emit getMeters(meterCenter); break; case cmdGetPowerMeter: if(amTransmitting) emit getMeters(meterPower); break; case cmdGetSWRMeter: if(amTransmitting) emit getMeters(meterSWR); break; case cmdGetIdMeter: emit getMeters(meterCurrent); break; case cmdGetVdMeter: emit getMeters(meterVoltage); break; case cmdGetALCMeter: if(amTransmitting) emit getMeters(meterALC); break; case cmdGetCompMeter: if(amTransmitting) emit getMeters(meterComp); break; case cmdStartRegularPolling: runPeriodicCommands = true; break; case cmdStopRegularPolling: runPeriodicCommands = false; break; case cmdQueNormalSpeed: if(usingLAN) { delayedCommand->setInterval(delayedCmdIntervalLAN_ms); } else { delayedCommand->setInterval(delayedCmdIntervalSerial_ms); } break; default: qInfo(logSystem()) << __PRETTY_FUNCTION__ << "WARNING: Command fell through of type: " << (unsigned int)cmd; break; } } void wfmain::sendRadioCommandLoop() { // Called by the periodicPollingTimer, see setInitialTiming() if(!(loopTickCounter % 2)) { // if ther's a command waiting, run it. if(!delayedCmdQue.empty()) { commandtype cmddata = delayedCmdQue.front(); delayedCmdQue.pop_front(); doCmd(cmddata); } else if(!(loopTickCounter % 10)) { // pick from useful queries to make now and then if(haveRigCaps && !slowPollCmdQueue.empty()) { int nCmds = slowPollCmdQueue.size(); cmds sCmd = slowPollCmdQueue[(slowCmdNum++)%nCmds]; doCmd(sCmd); } } } else { // odd-number ticks: // s-meter or other metering if(haveRigCaps && !periodicCmdQueue.empty()) { int nCmds = periodicCmdQueue.size(); cmds pcmd = periodicCmdQueue[ (pCmdNum++)%nCmds ]; doCmd(pcmd); } } loopTickCounter++; } void wfmain::issueDelayedCommand(cmds cmd) { // Append to end of command queue commandtype cmddata; cmddata.cmd = cmd; cmddata.data = NULL; delayedCmdQue.push_back(cmddata); } void wfmain::issueDelayedCommandPriority(cmds cmd) { // Places the new command at the top of the queue // Use only when needed. commandtype cmddata; cmddata.cmd = cmd; cmddata.data = NULL; delayedCmdQue.push_front(cmddata); } void wfmain::issueDelayedCommandUnique(cmds cmd) { // Use this function to insert commands where // multiple (redundant) commands don't make sense. commandtype cmddata; cmddata.cmd = cmd; cmddata.data = NULL; // The following is both expensive and not that great, // since it does not check if the arguments are the same. bool found = false; for(unsigned int i=0; i < delayedCmdQue.size(); i++) { if(delayedCmdQue.at(i).cmd == cmd) { found = true; break; } } if(!found) { delayedCmdQue.push_front(cmddata); } // if( std::find(delayedCmdQue.begin(), delayedCmdQue.end(), cmddata ) == delayedCmdQue.end()) // { // delayedCmdQue.push_front(cmddata); // } } void wfmain::issueCmd(cmds cmd, mode_info m) { commandtype cmddata; cmddata.cmd = cmd; cmddata.data = std::shared_ptr(new mode_info(m)); delayedCmdQue.push_back(cmddata); } void wfmain::issueCmd(cmds cmd, freqt f) { commandtype cmddata; cmddata.cmd = cmd; cmddata.data = std::shared_ptr(new freqt(f)); delayedCmdQue.push_back(cmddata); } void wfmain::issueCmd(cmds cmd, timekind t) { qDebug(logSystem()) << "Issuing timekind command with data: " << t.hours << " hours, " << t.minutes << " minutes, " << t.isMinus << " isMinus"; commandtype cmddata; cmddata.cmd = cmd; cmddata.data = std::shared_ptr(new timekind(t)); delayedCmdQue.push_front(cmddata); } void wfmain::issueCmd(cmds cmd, datekind d) { qDebug(logSystem()) << "Issuing datekind command with data: " << d.day << " day, " << d.month << " month, " << d.year << " year."; commandtype cmddata; cmddata.cmd = cmd; cmddata.data = std::shared_ptr(new datekind(d)); delayedCmdQue.push_front(cmddata); } void wfmain::issueCmd(cmds cmd, int i) { commandtype cmddata; cmddata.cmd = cmd; cmddata.data = std::shared_ptr(new int(i)); delayedCmdQue.push_back(cmddata); } void wfmain::issueCmd(cmds cmd, char c) { commandtype cmddata; cmddata.cmd = cmd; cmddata.data = std::shared_ptr(new char(c)); delayedCmdQue.push_back(cmddata); } void wfmain::issueCmd(cmds cmd, bool b) { commandtype cmddata; cmddata.cmd = cmd; cmddata.data = std::shared_ptr(new bool(b)); delayedCmdQue.push_back(cmddata); } void wfmain::issueCmd(cmds cmd, unsigned char c) { commandtype cmddata; cmddata.cmd = cmd; cmddata.data = std::shared_ptr(new unsigned char(c)); delayedCmdQue.push_back(cmddata); } void wfmain::issueCmdUniquePriority(cmds cmd, bool b) { commandtype cmddata; cmddata.cmd = cmd; cmddata.data = std::shared_ptr(new bool(b)); delayedCmdQue.push_front(cmddata); removeSimilarCommand(cmd); } void wfmain::issueCmdUniquePriority(cmds cmd, unsigned char c) { commandtype cmddata; cmddata.cmd = cmd; cmddata.data = std::shared_ptr(new unsigned char(c)); delayedCmdQue.push_front(cmddata); removeSimilarCommand(cmd); } void wfmain::issueCmdUniquePriority(cmds cmd, char c) { commandtype cmddata; cmddata.cmd = cmd; cmddata.data = std::shared_ptr(new char(c)); delayedCmdQue.push_front(cmddata); removeSimilarCommand(cmd); } void wfmain::issueCmdUniquePriority(cmds cmd, freqt f) { commandtype cmddata; cmddata.cmd = cmd; cmddata.data = std::shared_ptr(new freqt(f)); delayedCmdQue.push_front(cmddata); removeSimilarCommand(cmd); } void wfmain::removeSimilarCommand(cmds cmd) { // pop anything out that is of the same kind of command: // pop anything out that is of the same kind of command: // Start at 1 since we put one in at zero that we want to keep. for(unsigned int i=1; i < delayedCmdQue.size(); i++) { if(delayedCmdQue.at(i).cmd == cmd) { //delayedCmdQue[i].cmd = cmdNone; delayedCmdQue.erase(delayedCmdQue.begin()+i); // i -= 1; } } } void wfmain::receiveRigID(rigCapabilities rigCaps) { // Note: We intentionally request rigID several times // because without rigID, we can't do anything with the waterfall. if(haveRigCaps) { return; } else { showStatusBarText(QString("Found radio at address 0x%1 of name %2 and model ID %3.").arg(rigCaps.civ,2,16).arg(rigCaps.modelName).arg(rigCaps.modelID)); qDebug(logSystem()) << "Rig name: " << rigCaps.modelName; qDebug(logSystem()) << "Has LAN capabilities: " << rigCaps.hasLan; qDebug(logSystem()) << "Rig ID received into wfmain: spectLenMax: " << rigCaps.spectLenMax; qDebug(logSystem()) << "Rig ID received into wfmain: spectAmpMax: " << rigCaps.spectAmpMax; qDebug(logSystem()) << "Rig ID received into wfmain: spectSeqMax: " << rigCaps.spectSeqMax; qDebug(logSystem()) << "Rig ID received into wfmain: hasSpectrum: " << rigCaps.hasSpectrum; this->rigCaps = rigCaps; rigName->setText(rigCaps.modelName); if (serverConfig.enabled) { serverConfig.rigs.first()->modelName = rigCaps.modelName; serverConfig.rigs.first()->rigName = rigCaps.modelName; serverConfig.rigs.first()->civAddr = rigCaps.civ; serverConfig.rigs.first()->baudRate = rigCaps.baudRate; } setWindowTitle(rigCaps.modelName); this->spectWidth = rigCaps.spectLenMax; // used once haveRigCaps is true. //wfCeiling = rigCaps.spectAmpMax; //plotCeiling = rigCaps.spectAmpMax; ui->topLevelSlider->setMaximum(rigCaps.spectAmpMax); haveRigCaps = true; // Added so that server receives rig capabilities. emit sendRigCaps(rigCaps); rpt->setRig(rigCaps); trxadj->setRig(rigCaps); // Set the mode combo box up: ui->modeSelectCombo->blockSignals(true); ui->modeSelectCombo->clear(); for(unsigned int i=0; i < rigCaps.modes.size(); i++) { ui->modeSelectCombo->addItem(rigCaps.modes.at(i).name, rigCaps.modes.at(i).reg); } ui->modeSelectCombo->blockSignals(false); if(rigCaps.model == model9700) { ui->satOpsBtn->setDisabled(false); ui->adjRefBtn->setDisabled(false); } else { ui->satOpsBtn->setDisabled(true); ui->adjRefBtn->setDisabled(true); } QString inName; // Clear input combos before adding known inputs. ui->modInputCombo->clear(); ui->modInputDataCombo->clear(); for(int i=0; i < rigCaps.inputs.length(); i++) { switch(rigCaps.inputs.at(i)) { case inputMic: inName = "Mic"; break; case inputLAN: inName = "LAN"; break; case inputUSB: inName = "USB"; break; case inputACC: inName = "ACC"; break; case inputACCA: inName = "ACCA"; break; case inputACCB: inName = "ACCB"; break; default: inName = "Unknown"; break; } ui->modInputCombo->addItem(inName, rigCaps.inputs.at(i)); ui->modInputDataCombo->addItem(inName, rigCaps.inputs.at(i)); } if(rigCaps.inputs.length() == 0) { ui->modInputCombo->addItem("None", inputNone); ui->modInputDataCombo->addItem("None", inputNone); } ui->attSelCombo->clear(); if(rigCaps.hasAttenuator) { ui->attSelCombo->setDisabled(false); for(unsigned int i=0; i < rigCaps.attenuators.size(); i++) { inName = (i==0)?QString("0dB"):QString("-%1 dB").arg(rigCaps.attenuators.at(i), 0, 16); ui->attSelCombo->addItem(inName, rigCaps.attenuators.at(i)); } } else { ui->attSelCombo->setDisabled(true); } ui->preampSelCombo->clear(); if(rigCaps.hasPreamp) { ui->preampSelCombo->setDisabled(false); for(unsigned int i=0; i < rigCaps.preamps.size(); i++) { inName = (i==0)?QString("Disabled"):QString("Pre #%1").arg(rigCaps.preamps.at(i), 0, 16); ui->preampSelCombo->addItem(inName, rigCaps.preamps.at(i)); } } else { ui->preampSelCombo->setDisabled(true); } ui->antennaSelCombo->clear(); if(rigCaps.hasAntennaSel) { ui->antennaSelCombo->setDisabled(false); for(unsigned int i=0; i < rigCaps.antennas.size(); i++) { inName = QString("%1").arg(rigCaps.antennas.at(i)+1, 0, 16); // adding 1 to have the combobox start with ant 1 instead of 0 ui->antennaSelCombo->addItem(inName, rigCaps.antennas.at(i)); } } else { ui->antennaSelCombo->setDisabled(true); } ui->rxAntennaCheck->setEnabled(rigCaps.hasRXAntenna); ui->rxAntennaCheck->setChecked(false); ui->scopeBWCombo->blockSignals(true); ui->scopeBWCombo->clear(); if(rigCaps.hasSpectrum) { ui->scopeBWCombo->setHidden(false); for(unsigned int i=0; i < rigCaps.scopeCenterSpans.size(); i++) { ui->scopeBWCombo->addItem(rigCaps.scopeCenterSpans.at(i).name, (int)rigCaps.scopeCenterSpans.at(i).cstype); } plot->yAxis->setRange(QCPRange(prefs.plotFloor, prefs.plotCeiling)); colorMap->setDataRange(QCPRange(prefs.plotFloor, prefs.plotCeiling)); } else { ui->scopeBWCombo->setHidden(true); } ui->scopeBWCombo->blockSignals(false); setBandButtons(); ui->tuneEnableChk->setEnabled(rigCaps.hasATU); ui->tuneNowBtn->setEnabled(rigCaps.hasATU); ui->useRTSforPTTchk->blockSignals(true); ui->useRTSforPTTchk->setChecked(rigCaps.useRTSforPTT); ui->useRTSforPTTchk->blockSignals(false); ui->connectBtn->setText("Disconnect"); // We must be connected now. ui->audioSystemCombo->setEnabled(false); prepareWf(ui->wfLengthSlider->value()); if(usingLAN) { ui->afGainSlider->setValue(prefs.localAFgain); } // Adding these here because clearly at this point we have valid // rig comms. In the future, we should establish comms and then // do all the initial grabs. For now, this hack of adding them here and there: issueDelayedCommand(cmdGetFreq); issueDelayedCommand(cmdGetMode); // recalculate command timing now that we know the rig better: calculateTimingParameters(); initPeriodicCommands(); // Set the second meter here as I suspect we need to be connected for it to work? for (int i = 0; i < ui->meter2selectionCombo->count(); i++) { if (static_cast(ui->meter2selectionCombo->itemData(i).toInt()) == prefs.meter2Type) { // I thought that setCurrentIndex() would call the activated() function for the combobox // but it doesn't, so call it manually. ui->meter2selectionCombo->setCurrentIndex(i); on_meter2selectionCombo_activated(i); } } } } void wfmain::initPeriodicCommands() { // This function places periodic polling commands into a queue. // The commands are run using a timer, // and the timer is started by the delayed command cmdStartPeriodicTimer. insertPeriodicCommand(cmdGetTxRxMeter, 128); insertSlowPeriodicCommand(cmdGetFreq, 128); insertSlowPeriodicCommand(cmdGetMode, 128); if(rigCaps.hasTransmit) insertSlowPeriodicCommand(cmdGetPTT, 128); insertSlowPeriodicCommand(cmdGetTxPower, 128); insertSlowPeriodicCommand(cmdGetRxGain, 128); if(rigCaps.hasAttenuator) insertSlowPeriodicCommand(cmdGetAttenuator, 128); if(rigCaps.hasTransmit) insertSlowPeriodicCommand(cmdGetPTT, 128); if(rigCaps.hasPreamp) insertSlowPeriodicCommand(cmdGetPreamp, 128); if (rigCaps.hasRXAntenna) { insertSlowPeriodicCommand(cmdGetAntenna, 128); } insertSlowPeriodicCommand(cmdGetDuplexMode, 128); } void wfmain::insertPeriodicCommand(cmds cmd, unsigned char priority) { // TODO: meaningful priority // These commands get run at the fastest pace possible // Typically just metering. if(priority < 10) { periodicCmdQueue.push_front(cmd); } else { periodicCmdQueue.push_back(cmd); } } void wfmain::insertPeriodicCommandUnique(cmds cmd) { // Use this function to insert a non-duplicate command // into the fast periodic polling queue, typically // meter commands where high refresh rates are desirable. removePeriodicCommand(cmd); periodicCmdQueue.push_front(cmd); } void wfmain::removePeriodicCommand(cmds cmd) { while(true) { auto it = std::find(this->periodicCmdQueue.begin(), this->periodicCmdQueue.end(), cmd); if(it != periodicCmdQueue.end()) { periodicCmdQueue.erase(it); } else { break; } } } void wfmain::insertSlowPeriodicCommand(cmds cmd, unsigned char priority) { // TODO: meaningful priority // These commands are run every 20 "ticks" of the primary radio command loop // Basically 20 times less often than the standard periodic command if(priority < 10) { slowPollCmdQueue.push_front(cmd); } else { slowPollCmdQueue.push_back(cmd); } } void wfmain::receiveFreq(freqt freqStruct) { qint64 tnow_ms = QDateTime::currentMSecsSinceEpoch(); if(tnow_ms - lastFreqCmdTime_ms > delayedCommand->interval() * 2) { ui->freqLabel->setText(QString("%1").arg(freqStruct.MHzDouble, 0, 'f')); freq = freqStruct; } else { qDebug(logSystem()) << "Rejecting stale frequency: " << freqStruct.Hz << " Hz, delta time ms = " << tnow_ms - lastFreqCmdTime_ms\ << ", tnow_ms " << tnow_ms << ", last: " << lastFreqCmdTime_ms; } } void wfmain::receivePTTstatus(bool pttOn) { // This is the only place where amTransmitting and the transmit button text should be changed: //qInfo(logSystem()) << "PTT status: " << pttOn; if (pttOn && !amTransmitting) { pttLed->setState(QLedLabel::State::StateError); } else if (!pttOn && amTransmitting) { pttLed->setState(QLedLabel::State::StateOk); } amTransmitting = pttOn; changeTxBtn(); } void wfmain::changeTxBtn() { if(amTransmitting) { ui->transmitBtn->setText("Receive"); } else { ui->transmitBtn->setText("Transmit"); } } void wfmain::receiveSpectrumData(QByteArray spectrum, double startFreq, double endFreq) { if(!haveRigCaps) { qDebug(logSystem()) << "Spectrum received, but RigID incomplete."; return; } QElapsedTimer performanceTimer; bool updateRange = false; if((startFreq != oldLowerFreq) || (endFreq != oldUpperFreq)) { // If the frequency changed and we were drawing peaks, now is the time to clearn them if(underlayMode == underlayPeakHold) { // TODO: create non-button function to do this // This will break if the button is ever moved or renamed. on_clearPeakBtn_clicked(); } // TODO: Add clear-out for the buffer } oldLowerFreq = startFreq; oldUpperFreq = endFreq; //qInfo(logSystem()) << "start: " << startFreq << " end: " << endFreq; quint16 specLen = spectrum.length(); //qInfo(logSystem()) << "Spectrum data received at UI! Length: " << specLen; //if( (specLen != 475) || (specLen!=689) ) if( specLen != rigCaps.spectLenMax ) { qDebug(logSystem()) << "-------------------------------------------"; qDebug(logSystem()) << "------ Unusual spectrum received, length: " << specLen; qDebug(logSystem()) << "------ Expected spectrum length: " << rigCaps.spectLenMax; qDebug(logSystem()) << "------ This should happen once at most. "; return; // safe. Using these unusual length things is a problem. } QVector x(spectWidth), y(spectWidth), y2(spectWidth); for(int i=0; i < spectWidth; i++) { x[i] = (i * (endFreq-startFreq)/spectWidth) + startFreq; } for(int i=0; i (unsigned char)spectrumPeaks.at(i)) { spectrumPeaks[i] = spectrum.at(i); } y2[i] = (unsigned char)spectrumPeaks.at(i); } } plasmaMutex.lock(); spectrumPlasma.push_front(spectrum); spectrumPlasma.pop_back(); //spectrumPlasma.resize(spectrumPlasmaSize); plasmaMutex.unlock(); // HACK DO NOT CHECK IN: drawPeaks = false; drawPlasma = true; if(!spectrumDrawLock) { if((plotFloor != oldPlotFloor) || (plotCeiling != oldPlotCeiling)) updateRange = true; //ui->qcp->addGraph(); plot->graph(0)->setData(x,y, true); if((freq.MHzDouble < endFreq) && (freq.MHzDouble > startFreq)) { freqIndicatorLine->start->setCoords(freq.MHzDouble,0); freqIndicatorLine->end->setCoords(freq.MHzDouble,rigCaps.spectAmpMax); } if(underlayMode == underlayPeakHold) { plot->graph(1)->setData(x,y2, true); // peaks } else if (underlayMode != underlayNone) { computePlasma(); plot->graph(1)->setData(x,spectrumPlasmaLine); } else { plot->graph(1)->setData(x,y2, true); // peaks, but probably cleared out } if(updateRange) plot->yAxis->setRange(prefs.plotFloor, prefs.plotCeiling); plot->xAxis->setRange(startFreq, endFreq); plot->replot(); if(specLen == spectWidth) { wfimage.prepend(spectrum); wfimage.pop_back(); QByteArray wfRow; // Waterfall: for(int row = 0; row < wfLength; row++) { wfRow = wfimage.at(row); for(int col = 0; col < spectWidth; col++) { colorMap->data()->setCell( col, row, wfRow.at(col)); } } if(updateRange) { colorMap->setDataRange(QCPRange(wfFloor, wfCeiling)); } wf->yAxis->setRange(0,wfLength - 1); wf->xAxis->setRange(0, spectWidth-1); wf->replot(); } oldPlotFloor = plotFloor; oldPlotCeiling = plotCeiling; } } void wfmain::computePlasma() { plasmaMutex.lock(); spectrumPlasmaLine.clear(); spectrumPlasmaLine.resize(spectWidth); int specPlasmaSize = spectrumPlasma.size(); if(underlayMode == underlayAverageBuffer) { for(int col=0; col < spectWidth; col++) { for(int pos=0; pos < specPlasmaSize; pos++) { spectrumPlasmaLine[col] += spectrumPlasma[pos][col]; } spectrumPlasmaLine[col] = spectrumPlasmaLine[col] / specPlasmaSize; } } else if (underlayMode == underlayPeakBuffer){ // peak mode, running peak display for(int col=0; col < spectWidth; col++) { for(int pos=0; pos < specPlasmaSize; pos++) { if((double)(spectrumPlasma[pos][col]) > spectrumPlasmaLine[col]) spectrumPlasmaLine[col] = spectrumPlasma[pos][col]; } } } plasmaMutex.unlock(); } void wfmain::receiveSpectrumMode(spectrumMode spectMode) { for (int i = 0; i < ui->spectrumModeCombo->count(); i++) { if (static_cast(ui->spectrumModeCombo->itemData(i).toInt()) == spectMode) { ui->spectrumModeCombo->blockSignals(true); ui->spectrumModeCombo->setCurrentIndex(i); ui->spectrumModeCombo->blockSignals(false); } } } void wfmain::handlePlotDoubleClick(QMouseEvent *me) { double x; freqt freqGo; //double y; //double px; if(!freqLock) { //y = plot->yAxis->pixelToCoord(me->pos().y()); x = plot->xAxis->pixelToCoord(me->pos().x()); freqGo.Hz = x*1E6; freqGo.Hz = roundFrequency(freqGo.Hz, tsWfScrollHz); freqGo.MHzDouble = (float)freqGo.Hz / 1E6; //emit setFrequency(0,freq); issueCmd(cmdSetFreq, freqGo); freq = freqGo; setUIFreq(); //issueDelayedCommand(cmdGetFreq); showStatusBarText(QString("Going to %1 MHz").arg(x)); } } void wfmain::handleWFDoubleClick(QMouseEvent *me) { double x; freqt freqGo; //double y; //x = wf->xAxis->pixelToCoord(me->pos().x()); //y = wf->yAxis->pixelToCoord(me->pos().y()); // cheap trick until I figure out how the axis works on the WF: if(!freqLock) { x = plot->xAxis->pixelToCoord(me->pos().x()); freqGo.Hz = x*1E6; freqGo.Hz = roundFrequency(freqGo.Hz, tsWfScrollHz); freqGo.MHzDouble = (float)freqGo.Hz / 1E6; //emit setFrequency(0,freq); issueCmd(cmdSetFreq, freqGo); freq = freqGo; setUIFreq(); showStatusBarText(QString("Going to %1 MHz").arg(x)); } } void wfmain::handlePlotClick(QMouseEvent *me) { double x = plot->xAxis->pixelToCoord(me->pos().x()); showStatusBarText(QString("Selected %1 MHz").arg(x)); } void wfmain::handleWFClick(QMouseEvent *me) { double x = plot->xAxis->pixelToCoord(me->pos().x()); showStatusBarText(QString("Selected %1 MHz").arg(x)); } void wfmain::handleWFScroll(QWheelEvent *we) { // The wheel event is typically // .y() and is +/- 120. // We will click the dial once for every 120 received. //QPoint delta = we->angleDelta(); if(freqLock) return; freqt f; f.Hz = 0; f.MHzDouble = 0; int clicks = we->angleDelta().y() / 120; if(!clicks) return; unsigned int stepsHz = tsWfScrollHz; Qt::KeyboardModifiers key= we->modifiers(); if ((key == Qt::ShiftModifier) && (stepsHz !=1)) { stepsHz /= 10; } else if (key == Qt::ControlModifier) { stepsHz *= 10; } f.Hz = roundFrequencyWithStep(freq.Hz, clicks, stepsHz); f.MHzDouble = f.Hz / (double)1E6; freq = f; //emit setFrequency(0,f); issueCmdUniquePriority(cmdSetFreq, f); ui->freqLabel->setText(QString("%1").arg(f.MHzDouble, 0, 'f')); //issueDelayedCommandUnique(cmdGetFreq); } void wfmain::handlePlotScroll(QWheelEvent *we) { handleWFScroll(we); } void wfmain::on_scopeEnableWFBtn_clicked(bool checked) { if(checked) { emit spectOutputEnable(); } else { emit spectOutputDisable(); } } void wfmain::receiveMode(unsigned char mode, unsigned char filter) { //qInfo(logSystem()) << __func__ << "Received mode " << mode << " current mode: " << currentModeIndex; bool found=false; if(mode < 0x23) { for(int i=0; i < ui->modeSelectCombo->count(); i++) { if(ui->modeSelectCombo->itemData(i).toInt() == mode) { ui->modeSelectCombo->blockSignals(true); ui->modeSelectCombo->setCurrentIndex(i); ui->modeSelectCombo->blockSignals(false); found = true; } } currentModeIndex = mode; } else { qInfo(logSystem()) << __func__ << "Invalid mode " << mode << " received. "; } if(!found) { qInfo(logSystem()) << __func__ << "Received mode " << mode << " but could not match to any index within the modeSelectCombo. "; } if( (filter) && (filter < 4)){ ui->modeFilterCombo->blockSignals(true); ui->modeFilterCombo->setCurrentIndex(filter-1); ui->modeFilterCombo->blockSignals(false); } (void)filter; // Note: we need to know if the DATA mode is active to reach mode-D // some kind of queued query: if (rigCaps.hasDataModes && rigCaps.hasTransmit) { issueDelayedCommand(cmdGetDataMode); } } void wfmain::receiveDataModeStatus(bool dataEnabled) { ui->dataModeBtn->blockSignals(true); ui->dataModeBtn->setChecked(dataEnabled); ui->dataModeBtn->blockSignals(false); usingDataMode = dataEnabled; } void wfmain::on_clearPeakBtn_clicked() { if(haveRigCaps) { spectrumPeaks = QByteArray( (int)spectWidth, '\x01' ); } return; } void wfmain::on_drawPeakChk_clicked(bool checked) { if(checked) { on_clearPeakBtn_clicked(); // clear drawPeaks = true; } else { drawPeaks = false; #if QCUSTOMPLOT_VERSION >= 0x020000 plot->graph(1)->data()->clear(); #else plot->graph(1)->clearData(); #endif } prefs.drawPeaks = checked; } void wfmain::on_fullScreenChk_clicked(bool checked) { if(checked) { this->showFullScreen(); onFullscreen = true; } else { this->showNormal(); onFullscreen = false; } prefs.useFullScreen = checked; } void wfmain::on_goFreqBtn_clicked() { freqt f; bool ok = false; double freqDbl = 0; int KHz = 0; if(ui->freqMhzLineEdit->text().contains(".")) { freqDbl = ui->freqMhzLineEdit->text().toDouble(&ok); if(ok) { f.Hz = freqDbl*1E6; issueCmd(cmdSetFreq, f); } } else { KHz = ui->freqMhzLineEdit->text().toInt(&ok); if(ok) { f.Hz = KHz*1E3; issueCmd(cmdSetFreq, f); } } if(ok) { f.MHzDouble = (float)f.Hz / 1E6; freq = f; setUIFreq(); } ui->freqMhzLineEdit->selectAll(); freqTextSelected = true; ui->tabWidget->setCurrentIndex(0); } void wfmain::checkFreqSel() { if(freqTextSelected) { freqTextSelected = false; ui->freqMhzLineEdit->clear(); } } void wfmain::on_f0btn_clicked() { checkFreqSel(); ui->freqMhzLineEdit->setText(ui->freqMhzLineEdit->text().append("0")); } void wfmain::on_f1btn_clicked() { checkFreqSel(); ui->freqMhzLineEdit->setText(ui->freqMhzLineEdit->text().append("1")); } void wfmain::on_f2btn_clicked() { checkFreqSel(); ui->freqMhzLineEdit->setText(ui->freqMhzLineEdit->text().append("2")); } void wfmain::on_f3btn_clicked() { ui->freqMhzLineEdit->setText(ui->freqMhzLineEdit->text().append("3")); } void wfmain::on_f4btn_clicked() { checkFreqSel(); ui->freqMhzLineEdit->setText(ui->freqMhzLineEdit->text().append("4")); } void wfmain::on_f5btn_clicked() { checkFreqSel(); ui->freqMhzLineEdit->setText(ui->freqMhzLineEdit->text().append("5")); } void wfmain::on_f6btn_clicked() { checkFreqSel(); ui->freqMhzLineEdit->setText(ui->freqMhzLineEdit->text().append("6")); } void wfmain::on_f7btn_clicked() { checkFreqSel(); ui->freqMhzLineEdit->setText(ui->freqMhzLineEdit->text().append("7")); } void wfmain::on_f8btn_clicked() { checkFreqSel(); ui->freqMhzLineEdit->setText(ui->freqMhzLineEdit->text().append("8")); } void wfmain::on_f9btn_clicked() { checkFreqSel(); ui->freqMhzLineEdit->setText(ui->freqMhzLineEdit->text().append("9")); } void wfmain::on_fDotbtn_clicked() { checkFreqSel(); ui->freqMhzLineEdit->setText(ui->freqMhzLineEdit->text().append(".")); } void wfmain::on_fBackbtn_clicked() { QString currentFreq = ui->freqMhzLineEdit->text(); currentFreq.chop(1); ui->freqMhzLineEdit->setText(currentFreq); } void wfmain::on_fCEbtn_clicked() { ui->freqMhzLineEdit->clear(); freqTextSelected = false; } void wfmain::on_spectrumModeCombo_currentIndexChanged(int index) { emit setScopeMode(static_cast(ui->spectrumModeCombo->itemData(index).toInt())); } void wfmain::on_fEnterBtn_clicked() { // TODO: do not jump to main tab on enter, only on return // or something. // Maybe this should be an option in settings-> on_goFreqBtn_clicked(); } void wfmain::on_scopeBWCombo_currentIndexChanged(int index) { emit setScopeSpan((char)index); } void wfmain::on_scopeEdgeCombo_currentIndexChanged(int index) { emit setScopeEdge((char)index+1); } void wfmain::changeMode(mode_kind mode) { bool dataOn = false; if(((unsigned char) mode >> 4) == 0x08) { dataOn = true; mode = (mode_kind)((int)mode & 0x0f); } changeMode(mode, dataOn); } void wfmain::changeMode(mode_kind mode, bool dataOn) { int filter = ui->modeFilterCombo->currentData().toInt(); emit setMode((unsigned char)mode, (unsigned char)filter); currentMode = mode; if(dataOn) { issueDelayedCommand(cmdSetDataModeOn); ui->dataModeBtn->blockSignals(true); ui->dataModeBtn->setChecked(true); ui->dataModeBtn->blockSignals(false); } else { issueDelayedCommand(cmdSetDataModeOff); ui->dataModeBtn->blockSignals(true); ui->dataModeBtn->setChecked(false); ui->dataModeBtn->blockSignals(false); } issueDelayedCommand(cmdGetMode); } void wfmain::on_modeSelectCombo_activated(int index) { // The "acticvated" signal means the user initiated a mode change. // This function is not called if code initiated the change. mode_info mode; unsigned char newMode = static_cast(ui->modeSelectCombo->itemData(index).toUInt()); currentModeIndex = newMode; mode.reg = newMode; int filterSelection = ui->modeFilterCombo->currentData().toInt(); if(filterSelection == 99) { // oops, we forgot to reset the combo box return; } else { //qInfo(logSystem()) << __func__ << " at index " << index << " has newMode: " << newMode; currentMode = (mode_kind)newMode; mode.filter = filterSelection; mode.name = ui->modeSelectCombo->currentText(); // for debug for(unsigned int i=0; i < rigCaps.modes.size(); i++) { if(rigCaps.modes.at(i).reg == newMode) { mode.mk = rigCaps.modes.at(i).mk; break; } } issueCmd(cmdSetMode, mode); currentModeInfo = mode; //emit setMode(newMode, filterSelection); } } void wfmain::on_freqDial_valueChanged(int value) { int maxVal = ui->freqDial->maximum(); freqt f; f.Hz = 0; f.MHzDouble = 0; volatile int delta = 0; int directPath = 0; int crossingPath = 0; int distToMaxNew = 0; int distToMaxOld = 0; if(freqLock) { ui->freqDial->blockSignals(true); ui->freqDial->setValue(oldFreqDialVal); ui->freqDial->blockSignals(false); return; } if(value == 0) { distToMaxNew = 0; } else { distToMaxNew = maxVal - value; } if(oldFreqDialVal != 0) { distToMaxOld = maxVal - oldFreqDialVal; } else { distToMaxOld = 0; } directPath = abs(value - oldFreqDialVal); if(value < maxVal / 2) { crossingPath = value + distToMaxOld; } else { crossingPath = distToMaxNew + oldFreqDialVal; } if(directPath > crossingPath) { // use crossing path, it is shorter delta = crossingPath; // now calculate the direction: if( value > oldFreqDialVal) { // CW delta = delta; } else { // CCW delta *= -1; } } else { // use direct path // crossing path is larger than direct path, use direct path //delta = directPath; // now calculate the direction delta = value - oldFreqDialVal; } // With the number of steps and direction of steps established, // we can now adjust the frequency: f.Hz = roundFrequencyWithStep(freq.Hz, delta, tsKnobHz); f.MHzDouble = f.Hz / (double)1E6; if(f.Hz > 0) { freq = f; oldFreqDialVal = value; ui->freqLabel->setText(QString("%1").arg(f.MHzDouble, 0, 'f')); //emit setFrequency(0,f); issueCmdUniquePriority(cmdSetFreq, f); } else { ui->freqDial->blockSignals(true); ui->freqDial->setValue(oldFreqDialVal); ui->freqDial->blockSignals(false); return; } } void wfmain::receiveBandStackReg(freqt freqGo, char mode, char filter, bool dataOn) { // read the band stack and apply by sending out commands qInfo(logSystem()) << __func__ << "BSR received into main: Freq: " << freqGo.Hz << ", mode: " << (unsigned int)mode << ", filter: " << (unsigned int)filter << ", data mode: " << dataOn; //emit setFrequency(0,freq); issueCmd(cmdSetFreq, freqGo); setModeVal = (unsigned char) mode; setFilterVal = (unsigned char) filter; issueDelayedCommand(cmdSetModeFilter); freq = freqGo; setUIFreq(); if(dataOn) { issueDelayedCommand(cmdSetDataModeOn); } else { issueDelayedCommand(cmdSetDataModeOff); } //issueDelayedCommand(cmdGetFreq); //issueDelayedCommand(cmdGetMode); ui->tabWidget->setCurrentIndex(0); receiveMode((unsigned char) mode, (unsigned char) filter); // update UI } void wfmain::bandStackBtnClick() { bandStkRegCode = ui->bandStkPopdown->currentIndex() + 1; waitingForBandStackRtn = true; // so that when the return is parsed we jump to this frequency/mode info emit getBandStackReg(bandStkBand, bandStkRegCode); } void wfmain::on_band23cmbtn_clicked() { bandStkBand = rigCaps.bsr[band23cm]; // 23cm bandStackBtnClick(); } void wfmain::on_band70cmbtn_clicked() { bandStkBand = rigCaps.bsr[band70cm]; // 70cm bandStackBtnClick(); } void wfmain::on_band2mbtn_clicked() { bandStkBand = rigCaps.bsr[band2m]; // 2m bandStackBtnClick(); } void wfmain::on_bandAirbtn_clicked() { bandStkBand = rigCaps.bsr[bandAir]; // VHF Aircraft bandStackBtnClick(); } void wfmain::on_bandWFMbtn_clicked() { bandStkBand = rigCaps.bsr[bandWFM]; // Broadcast FM bandStackBtnClick(); } void wfmain::on_band4mbtn_clicked() { // There isn't a BSR for this one: freqt f; if((currentMode == modeAM) || (currentMode == modeFM)) { f.Hz = (70.260) * 1E6; } else { f.Hz = (70.200) * 1E6; } issueCmd(cmdSetFreq, f); //emit setFrequency(0,f); issueDelayedCommandUnique(cmdGetFreq); ui->tabWidget->setCurrentIndex(0); } void wfmain::on_band6mbtn_clicked() { bandStkBand = 0x10; // 6 meters bandStackBtnClick(); } void wfmain::on_band10mbtn_clicked() { bandStkBand = 0x09; // 10 meters bandStackBtnClick(); } void wfmain::on_band12mbtn_clicked() { bandStkBand = 0x08; // 12 meters bandStackBtnClick(); } void wfmain::on_band15mbtn_clicked() { bandStkBand = 0x07; // 15 meters bandStackBtnClick(); } void wfmain::on_band17mbtn_clicked() { bandStkBand = 0x06; // 17 meters bandStackBtnClick(); } void wfmain::on_band20mbtn_clicked() { bandStkBand = 0x05; // 20 meters bandStackBtnClick(); } void wfmain::on_band30mbtn_clicked() { bandStkBand = 0x04; // 30 meters bandStackBtnClick(); } void wfmain::on_band40mbtn_clicked() { bandStkBand = 0x03; // 40 meters bandStackBtnClick(); } void wfmain::on_band60mbtn_clicked() { // This one is tricky. There isn't a band stack register on the // 7300 for 60 meters, so we just drop to the middle of the band: // Channel 1: 5330.5 kHz // Channel 2: 5346.5 kHz // Channel 3: 5357.0 kHz // Channel 4: 5371.5 kHz // Channel 5: 5403.5 kHz // Really not sure what the best strategy here is, don't want to // clutter the UI with 60M channel buttons... freqt f; f.Hz = (5.3305) * 1E6; issueCmd(cmdSetFreq, f); //emit setFrequency(0,f); issueDelayedCommandUnique(cmdGetFreq); ui->tabWidget->setCurrentIndex(0); } void wfmain::on_band80mbtn_clicked() { bandStkBand = 0x02; // 80 meters bandStackBtnClick(); } void wfmain::on_band160mbtn_clicked() { bandStkBand = 0x01; // 160 meters bandStackBtnClick(); } void wfmain::on_band630mbtn_clicked() { freqt f; f.Hz = 475 * 1E3; //emit setFrequency(0,f); issueCmd(cmdSetFreq, f); issueDelayedCommandUnique(cmdGetFreq); ui->tabWidget->setCurrentIndex(0); } void wfmain::on_band2200mbtn_clicked() { freqt f; f.Hz = 136 * 1E3; //emit setFrequency(0,f); issueCmd(cmdSetFreq, f); issueDelayedCommandUnique(cmdGetFreq); ui->tabWidget->setCurrentIndex(0); } void wfmain::on_bandGenbtn_clicked() { // "GENE" general coverage frequency outside the ham bands // which does probably include any 60 meter frequencies used. bandStkBand = rigCaps.bsr[bandGen]; // GEN bandStackBtnClick(); } void wfmain::on_aboutBtn_clicked() { abtBox->show(); } void wfmain::on_fStoBtn_clicked() { // sequence: // type frequency // press Enter or Go // change mode if desired // type in index number 0 through 99 // press STO bool ok; int preset_number = ui->freqMhzLineEdit->text().toInt(&ok); if(ok && (preset_number >= 0) && (preset_number < 100)) { // TODO: keep an enum around with the current mode mem.setPreset(preset_number, freq.MHzDouble, (mode_kind)ui->modeSelectCombo->currentData().toInt() ); showStatusBarText( QString("Storing frequency %1 to memory location %2").arg( freq.MHzDouble ).arg(preset_number) ); } else { showStatusBarText(QString("Could not store preset to %1. Valid preset numbers are 0 to 99").arg(preset_number)); } } void wfmain::on_fRclBtn_clicked() { // Sequence: // type memory location 0 through 99 // press RCL // Program recalls data stored in vector at position specified // drop contents into text box, press go button // add delayed command for mode and data mode preset_kind temp; bool ok; QString freqString; int preset_number = ui->freqMhzLineEdit->text().toInt(&ok); if(ok && (preset_number >= 0) && (preset_number < 100)) { temp = mem.getPreset(preset_number); // TODO: change to int hz // TODO: store filter setting as well. freqString = QString("%1").arg(temp.frequency); ui->freqMhzLineEdit->setText( freqString ); ui->goFreqBtn->click(); setModeVal = temp.mode; setFilterVal = ui->modeFilterCombo->currentIndex()+1; // TODO, add to memory issueDelayedCommand(cmdSetModeFilter); issueDelayedCommand(cmdGetMode); } else { qInfo(logSystem()) << "Could not recall preset. Valid presets are 0 through 99."; } } void wfmain::on_rfGainSlider_valueChanged(int value) { issueCmdUniquePriority(cmdSetRxRfGain, (unsigned char) value); } void wfmain::on_afGainSlider_valueChanged(int value) { issueCmdUniquePriority(cmdSetAfGain, (unsigned char)value); if(usingLAN) { rxSetup.localAFgain = (unsigned char)(value); prefs.localAFgain = (unsigned char)(value); } } void wfmain::receiveRfGain(unsigned char level) { // qInfo(logSystem()) << "Receive RF level of" << (int)level << " = " << 100*level/255.0 << "%"; ui->rfGainSlider->blockSignals(true); ui->rfGainSlider->setValue(level); ui->rfGainSlider->blockSignals(false); } void wfmain::receiveAfGain(unsigned char level) { // qInfo(logSystem()) << "Receive AF level of" << (int)level << " = " << 100*level/255.0 << "%"; ui->afGainSlider->blockSignals(true); ui->afGainSlider->setValue(level); ui->afGainSlider->blockSignals(false); } void wfmain::receiveSql(unsigned char level) { ui->sqlSlider->setValue(level); } void wfmain::receiveIFShift(unsigned char level) { trxadj->updateIFShift(level); } void wfmain::receiveTBPFInner(unsigned char level) { trxadj->updateTPBFInner(level); } void wfmain::receiveTBPFOuter(unsigned char level) { trxadj->updateTPBFOuter(level); } void wfmain::on_tuneNowBtn_clicked() { issueDelayedCommand(cmdStartATU); showStatusBarText("Starting ATU tuning cycle..."); issueDelayedCommand(cmdGetATUStatus); } void wfmain::on_tuneEnableChk_clicked(bool checked) { issueCmd(cmdSetATU, checked); if(checked) { showStatusBarText("Turning on ATU"); } else { showStatusBarText("Turning off ATU"); } } void wfmain::on_exitBtn_clicked() { // Are you sure? QApplication::exit(); } void wfmain::on_pttOnBtn_clicked() { // is it enabled? if(!ui->pttEnableChk->isChecked()) { showStatusBarText("PTT is disabled, not sending command. Change under Settings tab."); return; } // Are we already PTT? Not a big deal, just send again anyway. showStatusBarText("Sending PTT ON command. Use Control-R to receive."); issueCmdUniquePriority(cmdSetPTT, true); // send PTT // Start 3 minute timer pttTimer->start(); issueDelayedCommand(cmdGetPTT); } void wfmain::on_pttOffBtn_clicked() { // Send the PTT OFF command (more than once?) showStatusBarText("Sending PTT OFF command"); issueCmdUniquePriority(cmdSetPTT, false); // Stop the 3 min timer pttTimer->stop(); issueDelayedCommand(cmdGetPTT); } void wfmain::handlePttLimit() { // transmission time exceeded! showStatusBarText("Transmit timeout at 3 minutes. Sending PTT OFF command now."); issueCmdUniquePriority(cmdSetPTT, false); issueDelayedCommand(cmdGetPTT); } void wfmain::on_saveSettingsBtn_clicked() { saveSettings(); // save memory, UI, and radio settings } void wfmain::receiveATUStatus(unsigned char atustatus) { // qInfo(logSystem()) << "Received ATU status update: " << (unsigned int) atustatus; switch(atustatus) { case 0x00: // ATU not active ui->tuneEnableChk->blockSignals(true); ui->tuneEnableChk->setChecked(false); ui->tuneEnableChk->blockSignals(false); showStatusBarText("ATU not enabled."); break; case 0x01: // ATU enabled ui->tuneEnableChk->blockSignals(true); ui->tuneEnableChk->setChecked(true); ui->tuneEnableChk->blockSignals(false); showStatusBarText("ATU enabled."); break; case 0x02: // ATU tuning in-progress. // Add command queue to check again and update status bar // qInfo(logSystem()) << "Received ATU status update that *tuning* is taking place"; showStatusBarText("ATU is Tuning..."); issueDelayedCommand(cmdGetATUStatus); // Sometimes the first hit seems to be missed. issueDelayedCommand(cmdGetATUStatus); break; default: qInfo(logSystem()) << "Did not understand ATU status: " << (unsigned int) atustatus; break; } } void wfmain::on_pttEnableChk_clicked(bool checked) { prefs.enablePTT = checked; } void wfmain::on_serialEnableBtn_clicked(bool checked) { prefs.enableLAN = !checked; ui->serialDeviceListCombo->setEnabled(checked); ui->connectBtn->setEnabled(true); ui->ipAddressTxt->setEnabled(!checked); ui->controlPortTxt->setEnabled(!checked); ui->usernameTxt->setEnabled(!checked); ui->passwordTxt->setEnabled(!checked); ui->audioRXCodecCombo->setEnabled(!checked); ui->audioTXCodecCombo->setEnabled(!checked); ui->audioSampleRateCombo->setEnabled(!checked); ui->rxLatencySlider->setEnabled(!checked); ui->txLatencySlider->setEnabled(!checked); ui->rxLatencyValue->setEnabled(!checked); ui->txLatencyValue->setEnabled(!checked); ui->audioOutputCombo->setEnabled(!checked); ui->audioInputCombo->setEnabled(!checked); ui->baudRateCombo->setEnabled(checked); ui->serialDeviceListCombo->setEnabled(checked); ui->serverRXAudioInputCombo->setEnabled(checked); ui->serverTXAudioOutputCombo->setEnabled(checked); } void wfmain::on_lanEnableBtn_clicked(bool checked) { prefs.enableLAN = checked; ui->connectBtn->setEnabled(true); ui->ipAddressTxt->setEnabled(checked); ui->controlPortTxt->setEnabled(checked); ui->usernameTxt->setEnabled(checked); ui->passwordTxt->setEnabled(checked); ui->audioRXCodecCombo->setEnabled(checked); ui->audioTXCodecCombo->setEnabled(checked); ui->audioSampleRateCombo->setEnabled(checked); ui->rxLatencySlider->setEnabled(checked); ui->txLatencySlider->setEnabled(checked); ui->rxLatencyValue->setEnabled(checked); ui->txLatencyValue->setEnabled(checked); ui->audioOutputCombo->setEnabled(checked); ui->audioInputCombo->setEnabled(checked); ui->baudRateCombo->setEnabled(!checked); ui->serialDeviceListCombo->setEnabled(!checked); ui->serverRXAudioInputCombo->setEnabled(!checked); ui->serverTXAudioOutputCombo->setEnabled(!checked); if(checked) { showStatusBarText("After filling in values, press Save Settings."); } } void wfmain::on_ipAddressTxt_textChanged(QString text) { udpPrefs.ipAddress = text; } void wfmain::on_controlPortTxt_textChanged(QString text) { udpPrefs.controlLANPort = text.toUInt(); } void wfmain::on_usernameTxt_textChanged(QString text) { udpPrefs.username = text; } void wfmain::on_passwordTxt_textChanged(QString text) { udpPrefs.password = text; } void wfmain::on_audioOutputCombo_currentIndexChanged(int value) { if (prefs.audioSystem == qtAudio) { QVariant v = ui->audioOutputCombo->itemData(value); rxSetup.port = v.value(); } else { rxSetup.portInt = ui->audioOutputCombo->itemData(value).toInt(); } rxSetup.name = ui->audioOutputCombo->itemText(value); qDebug(logGui()) << "Changed audio output to:" << rxSetup.name; } void wfmain::on_audioInputCombo_currentIndexChanged(int value) { if (prefs.audioSystem == qtAudio) { QVariant v = ui->audioInputCombo->itemData(value); txSetup.port = v.value(); } else { txSetup.portInt = ui->audioInputCombo->itemData(value).toInt(); } txSetup.name = ui->audioInputCombo->itemText(value); qDebug(logGui()) << "Changed audio input to:" << txSetup.name; } void wfmain::on_audioSampleRateCombo_currentIndexChanged(QString text) { //udpPrefs.audioRXSampleRate = text.toInt(); //udpPrefs.audioTXSampleRate = text.toInt(); rxSetup.sampleRate=text.toInt(); txSetup.sampleRate=text.toInt(); } void wfmain::on_audioRXCodecCombo_currentIndexChanged(int value) { rxSetup.codec = ui->audioRXCodecCombo->itemData(value).toInt(); } void wfmain::on_audioTXCodecCombo_currentIndexChanged(int value) { txSetup.codec = ui->audioTXCodecCombo->itemData(value).toInt(); } void wfmain::on_rxLatencySlider_valueChanged(int value) { rxSetup.latency = value; ui->rxLatencyValue->setText(QString::number(value)); emit sendChangeLatency(value); } void wfmain::on_txLatencySlider_valueChanged(int value) { txSetup.latency = value; ui->txLatencyValue->setText(QString::number(value)); } void wfmain::on_vspCombo_currentIndexChanged(int value) { Q_UNUSED(value); prefs.virtualSerialPort = ui->vspCombo->currentText(); } void wfmain::on_toFixedBtn_clicked() { emit setScopeFixedEdge(oldLowerFreq, oldUpperFreq, ui->scopeEdgeCombo->currentIndex()+1); emit setScopeEdge(ui->scopeEdgeCombo->currentIndex()+1); issueDelayedCommand(cmdScopeFixedMode); } void wfmain::on_connectBtn_clicked() { this->rigStatus->setText(""); // Clear status if (haveRigCaps) { emit sendCloseComm(); ui->connectBtn->setText("Connect"); ui->audioSystemCombo->setEnabled(true); haveRigCaps = false; rigName->setText("NONE"); } else { emit sendCloseComm(); // Just in case there is a failed connection open. openRig(); } } void wfmain::on_sqlSlider_valueChanged(int value) { issueCmd(cmdSetSql, (unsigned char)value); //emit setSql((unsigned char)value); } // These three are from the transceiver adjustment window: void wfmain::changeIFShift(unsigned char level) { //issueCmd(cmdSetIFShift, level); issueCmdUniquePriority(cmdSetIFShift, level); } void wfmain::changeTPBFInner(unsigned char level) { issueCmdUniquePriority(cmdSetTPBFInner, level); } void wfmain::changeTPBFOuter(unsigned char level) { issueCmdUniquePriority(cmdSetTPBFOuter, level); } void wfmain::on_modeFilterCombo_activated(int index) { int filterSelection = ui->modeFilterCombo->itemData(index).toInt(); if(filterSelection == 99) { // TODO: // Bump the filter selected back to F1, F2, or F3 // possibly track the filter in the class. Would make this easier. // filterSetup.show(); // } else { unsigned char newMode = static_cast(ui->modeSelectCombo->currentData().toUInt()); currentModeIndex = newMode; // we track this for other functions if(ui->dataModeBtn->isChecked()) { emit setDataMode(true, (unsigned char)filterSelection); } else { emit setMode(newMode, (unsigned char)filterSelection); } } } void wfmain::on_dataModeBtn_toggled(bool checked) { emit setDataMode(checked, (unsigned char)ui->modeFilterCombo->currentData().toInt()); usingDataMode = checked; if(usingDataMode) { changeModLabelAndSlider(currentModDataSrc); } else { changeModLabelAndSlider(currentModSrc); } } void wfmain::on_transmitBtn_clicked() { if(!amTransmitting) { // Currently receiving if(!ui->pttEnableChk->isChecked()) { showStatusBarText("PTT is disabled, not sending command. Change under Settings tab."); return; } // Are we already PTT? Not a big deal, just send again anyway. showStatusBarText("Sending PTT ON command. Use Control-R to receive."); issueCmdUniquePriority(cmdSetPTT, true); // send PTT // Start 3 minute timer pttTimer->start(); issueDelayedCommand(cmdGetPTT); //changeTxBtn(); } else { // Currently transmitting issueCmdUniquePriority(cmdSetPTT, false); pttTimer->stop(); issueDelayedCommand(cmdGetPTT); } } void wfmain::on_adjRefBtn_clicked() { cal->show(); } void wfmain::on_satOpsBtn_clicked() { sat->show(); } void wfmain::setRadioTimeDatePrep() { if(!waitingToSetTimeDate) { // 1: Find the current time and date QDateTime now; if(ui->useUTCChk->isChecked()) { now = QDateTime::currentDateTimeUtc(); now.setTime(QTime::currentTime()); } else { now = QDateTime::currentDateTime(); now.setTime(QTime::currentTime()); } int second = now.time().second(); // 2: Find how many mseconds until next minute int msecdelay = QTime::currentTime().msecsTo( QTime::currentTime().addSecs(60-second) ); // 3: Compute time and date at one minute later QDateTime setpoint = now.addMSecs(msecdelay); // at HMS or possibly HMS + some ms. Never under though. // 4: Prepare data structs for the time at one minute later timesetpoint.hours = (unsigned char)setpoint.time().hour(); timesetpoint.minutes = (unsigned char)setpoint.time().minute(); datesetpoint.day = (unsigned char)setpoint.date().day(); datesetpoint.month = (unsigned char)setpoint.date().month(); datesetpoint.year = (uint16_t)setpoint.date().year(); unsigned int utcOffsetSeconds = (unsigned int)abs(setpoint.offsetFromUtc()); bool isMinus = setpoint.offsetFromUtc() < 0; utcsetting.hours = utcOffsetSeconds / 60 / 60; utcsetting.minutes = (utcOffsetSeconds - (utcsetting.hours*60*60) ) / 60; utcsetting.isMinus = isMinus; timeSync->setInterval(msecdelay); timeSync->setSingleShot(true); // 5: start one-shot timer for the delta computed in #2. timeSync->start(); waitingToSetTimeDate = true; showStatusBarText(QString("Setting time, date, and UTC offset for radio in %1 seconds.").arg(msecdelay/1000)); } } void wfmain::setRadioTimeDateSend() { // Issue priority commands for UTC offset, date, and time // UTC offset must come first, otherwise the radio may "help" and correct for any changes. showStatusBarText(QString("Setting time, date, and UTC offset for radio now.")); issueCmd(cmdSetTime, timesetpoint); issueCmd(cmdSetDate, datesetpoint); issueCmd(cmdSetUTCOffset, utcsetting); waitingToSetTimeDate = false; } void wfmain::changeSliderQuietly(QSlider *slider, int value) { slider->blockSignals(true); slider->setValue(value); slider->blockSignals(false); } void wfmain::statusFromSliderRaw(QString name, int rawValue) { showStatusBarText(name + QString(": %1").arg(rawValue)); } void wfmain::statusFromSliderPercent(QString name, int rawValue) { showStatusBarText(name + QString(": %1%").arg((int)(100*rawValue/255.0))); } void wfmain::receiveTxPower(unsigned char power) { changeSliderQuietly(ui->txPowerSlider, power); } void wfmain::receiveMicGain(unsigned char gain) { processModLevel(inputMic, gain); } void wfmain::processModLevel(rigInput source, unsigned char level) { rigInput currentIn; if(usingDataMode) { currentIn = currentModDataSrc; } else { currentIn = currentModSrc; } switch(source) { case inputMic: micGain = level; break; case inputACC: accGain = level; break; case inputACCA: accAGain = level; break; case inputACCB: accBGain = level; break; case inputUSB: usbGain = level; break; case inputLAN: lanGain = level; break; default: break; } if(currentIn == source) { changeSliderQuietly(ui->micGainSlider, level); } } void wfmain::receiveModInput(rigInput input, bool dataOn) { QComboBox *box; QString inputName; bool found; bool foundCurrent = false; if(dataOn) { box = ui->modInputDataCombo; currentModDataSrc = input; if(usingDataMode) foundCurrent = true; } else { box = ui->modInputCombo; currentModSrc = input; if(!usingDataMode) foundCurrent = true; } for(int i=0; i < box->count(); i++) { if(box->itemData(i).toInt() == (int)input) { box->blockSignals(true); box->setCurrentIndex(i); box->blockSignals(false); found = true; } } if(foundCurrent) { changeModLabel(input); } if(!found) qInfo(logSystem()) << "Could not find modulation input: " << (int)input; } void wfmain::receiveACCGain(unsigned char level, unsigned char ab) { if(ab==1) { processModLevel(inputACCB, level); } else { if(rigCaps.model == model7850) { processModLevel(inputACCA, level); } else { processModLevel(inputACC, level); } } } void wfmain::receiveUSBGain(unsigned char level) { processModLevel(inputUSB, level); } void wfmain::receiveLANGain(unsigned char level) { processModLevel(inputLAN, level); } void wfmain::receiveMeter(meterKind inMeter, unsigned char level) { switch(inMeter) { case meterS: ui->meterSPoWidget->setMeterType(meterS); ui->meterSPoWidget->setLevel(level); ui->meterSPoWidget->repaint(); break; case meterPower: ui->meterSPoWidget->setMeterType(meterPower); ui->meterSPoWidget->setLevel(level); ui->meterSPoWidget->update(); break; default: if(ui->meter2Widget->getMeterType() == inMeter) { ui->meter2Widget->setLevel(level); } else if ( (ui->meter2Widget->getMeterType() == meterAudio) && (inMeter == meterTxMod) && amTransmitting) { ui->meter2Widget->setLevel(level); } else if ( (ui->meter2Widget->getMeterType() == meterAudio) && (inMeter == meterRxAudio) && !amTransmitting) { ui->meter2Widget->setLevel(level); } break; } } void wfmain::receiveCompLevel(unsigned char compLevel) { (void)compLevel; } void wfmain::receiveMonitorGain(unsigned char monitorGain) { (void)monitorGain; } void wfmain::receiveVoxGain(unsigned char voxGain) { (void)voxGain; } void wfmain::receiveAntiVoxGain(unsigned char antiVoxGain) { (void)antiVoxGain; } void wfmain::on_txPowerSlider_valueChanged(int value) { issueCmdUniquePriority(cmdSetTxPower, (unsigned char)value); //emit setTxPower(value); } void wfmain::on_micGainSlider_valueChanged(int value) { processChangingCurrentModLevel((unsigned char) value); } void wfmain::on_scopeRefLevelSlider_valueChanged(int value) { value = (value/5) * 5; // rounded to "nearest 5" emit setSpectrumRefLevel(value); } void wfmain::receiveSpectrumRefLevel(int level) { changeSliderQuietly(ui->scopeRefLevelSlider, level); } void wfmain::on_modInputCombo_activated(int index) { emit setModInput( (rigInput)ui->modInputCombo->currentData().toInt(), false ); currentModSrc = (rigInput)ui->modInputCombo->currentData().toInt(); issueDelayedCommand(cmdGetCurrentModLevel); if(!usingDataMode) { changeModLabel(currentModSrc); } (void)index; } void wfmain::on_modInputDataCombo_activated(int index) { emit setModInput( (rigInput)ui->modInputDataCombo->currentData().toInt(), true ); currentModDataSrc = (rigInput)ui->modInputDataCombo->currentData().toInt(); issueDelayedCommand(cmdGetCurrentModLevel); if(usingDataMode) { changeModLabel(currentModDataSrc); } (void)index; } void wfmain::changeModLabelAndSlider(rigInput source) { changeModLabel(source, true); } void wfmain::changeModLabel(rigInput input) { changeModLabel(input, false); } void wfmain::changeModLabel(rigInput input, bool updateLevel) { QString inputName; unsigned char gain = 0; switch(input) { case inputMic: inputName = "Mic"; gain = micGain; break; case inputACC: inputName = "ACC"; gain = accGain; break; case inputACCA: inputName = "ACCA"; gain = accAGain; break; case inputACCB: inputName = "ACCB"; gain = accBGain; break; case inputUSB: inputName = "USB"; gain = usbGain; break; case inputLAN: inputName = "LAN"; gain = lanGain; break; default: inputName = "UNK"; gain=0; break; } ui->modSliderLbl->setText(inputName); if(updateLevel) { changeSliderQuietly(ui->micGainSlider, gain); } } void wfmain::processChangingCurrentModLevel(unsigned char level) { // slider moved, so find the current mod and issue the level set command. issueCmd(cmdSetModLevel, level); } void wfmain::on_tuneLockChk_clicked(bool checked) { freqLock = checked; } void wfmain::on_serialDeviceListCombo_activated(const QString &arg1) { QString manualPort; bool ok; if(arg1==QString("Manual...")) { manualPort = QInputDialog::getText(this, tr("Manual port assignment"), tr("Enter serial port assignment:"), QLineEdit::Normal, tr("/dev/device"), &ok); if(manualPort.isEmpty() || !ok) { ui->serialDeviceListCombo->blockSignals(true); ui->serialDeviceListCombo->setCurrentIndex(0); ui->serialDeviceListCombo->blockSignals(false); return; } else { prefs.serialPortRadio = manualPort; showStatusBarText("Setting preferences to use manually-assigned serial port: " + manualPort); ui->serialEnableBtn->setChecked(true); return; } } if(arg1==QString("Auto")) { prefs.serialPortRadio = "auto"; showStatusBarText("Setting preferences to automatically find rig serial port."); ui->serialEnableBtn->setChecked(true); return; } prefs.serialPortRadio = arg1; showStatusBarText("Setting preferences to use manually-assigned serial port: " + arg1); ui->serialEnableBtn->setChecked(true); } void wfmain::on_rptSetupBtn_clicked() { rpt->show(); } void wfmain::on_attSelCombo_activated(int index) { unsigned char att = (unsigned char)ui->attSelCombo->itemData(index).toInt(); emit setAttenuator(att); issueDelayedCommand(cmdGetPreamp); } void wfmain::on_preampSelCombo_activated(int index) { unsigned char pre = (unsigned char)ui->preampSelCombo->itemData(index).toInt(); emit setPreamp(pre); issueDelayedCommand(cmdGetAttenuator); } void wfmain::on_antennaSelCombo_activated(int index) { unsigned char ant = (unsigned char)ui->antennaSelCombo->itemData(index).toInt(); emit setAntenna(ant,ui->rxAntennaCheck->isChecked()); } void wfmain::on_rxAntennaCheck_clicked(bool value) { unsigned char ant = (unsigned char)ui->antennaSelCombo->itemData(ui->antennaSelCombo->currentIndex()).toInt(); emit setAntenna(ant, value); } void wfmain::on_wfthemeCombo_activated(int index) { colorMap->setGradient(static_cast(ui->wfthemeCombo->itemData(index).toInt())); prefs.wftheme = ui->wfthemeCombo->itemData(index).toInt(); } void wfmain::receivePreamp(unsigned char pre) { int preindex = ui->preampSelCombo->findData(pre); ui->preampSelCombo->setCurrentIndex(preindex); } void wfmain::receiveAttenuator(unsigned char att) { int attindex = ui->attSelCombo->findData(att); ui->attSelCombo->setCurrentIndex(attindex); } void wfmain::receiveAntennaSel(unsigned char ant, bool rx) { ui->antennaSelCombo->setCurrentIndex(ant); ui->rxAntennaCheck->setChecked(rx); } void wfmain::receiveSpectrumSpan(freqt freqspan, bool isSub) { if(!isSub) { switch((int)(freqspan.MHzDouble * 1000000.0)) { case(2500): ui->scopeBWCombo->setCurrentIndex(0); break; case(5000): ui->scopeBWCombo->setCurrentIndex(1); break; case(10000): ui->scopeBWCombo->setCurrentIndex(2); break; case(25000): ui->scopeBWCombo->setCurrentIndex(3); break; case(50000): ui->scopeBWCombo->setCurrentIndex(4); break; case(100000): ui->scopeBWCombo->setCurrentIndex(5); break; case(250000): ui->scopeBWCombo->setCurrentIndex(6); break; case(500000): ui->scopeBWCombo->setCurrentIndex(7); break; case(1000000): ui->scopeBWCombo->setCurrentIndex(8); break; case(2500000): ui->scopeBWCombo->setCurrentIndex(9); break; default: qInfo(logSystem()) << __func__ << "Could not match: " << freqspan.MHzDouble << " to anything like: " << (int)(freqspan.MHzDouble*1E6); break; } } } void wfmain::calculateTimingParameters() { // Function for calculating polling parameters. // Requires that we know the "baud rate" of the actual // radio connection. // baud on the serial port reflects the actual rig connection, // even if a client-server connection is being used. // Computed time for a 10 byte message, with a safety factor of 2. if (prefs.serialPortBaud == 0) { prefs.serialPortBaud = 9600; qInfo(logSystem()) << "WARNING: baud rate received was zero. Assuming 9600 baud, performance may suffer."; } unsigned int usPerByte = 9600*1000 / prefs.serialPortBaud; unsigned int msMinTiming=usPerByte * 10*2/1000; if(msMinTiming < 25) msMinTiming = 25; if(haveRigCaps && rigCaps.hasFDcomms) { delayedCommand->setInterval( msMinTiming); // 20 byte message } else { delayedCommand->setInterval( msMinTiming * 3); // 20 byte message } qInfo(logSystem()) << "Delay command interval timing: " << delayedCommand->interval() << "ms"; // Normal: delayedCmdIntervalLAN_ms = delayedCommand->interval(); delayedCmdIntervalSerial_ms = delayedCommand->interval(); // startup initial state: delayedCmdStartupInterval_ms = delayedCommand->interval() * 3; } void wfmain::receiveBaudRate(quint32 baud) { qInfo() << "Received serial port baud rate from remote server:" << baud; prefs.serialPortBaud = baud; calculateTimingParameters(); } void wfmain::on_rigPowerOnBtn_clicked() { powerRigOn(); } void wfmain::on_rigPowerOffBtn_clicked() { // Are you sure? if (!prefs.confirmPowerOff) { powerRigOff(); return; } QCheckBox* cb = new QCheckBox("Don't ask me again"); QMessageBox msgbox; msgbox.setWindowTitle("Power"); msgbox.setText("Power down the radio?\n"); msgbox.setIcon(QMessageBox::Icon::Question); QAbstractButton* yesButton = msgbox.addButton(QMessageBox::Yes); msgbox.addButton(QMessageBox::No); msgbox.setDefaultButton(QMessageBox::Yes); msgbox.setCheckBox(cb); QObject::connect(cb, &QCheckBox::stateChanged, [this](int state) { if (static_cast(state) == Qt::CheckState::Checked) { prefs.confirmPowerOff = false; } else { prefs.confirmPowerOff = true; } settings->beginGroup("Interface"); settings->setValue("ConfirmPowerOff", this->prefs.confirmPowerOff); settings->endGroup(); settings->sync(); }); msgbox.exec(); if (msgbox.clickedButton() == yesButton) { powerRigOff(); } } void wfmain::powerRigOn() { emit sendPowerOn(); delayedCommand->setInterval(3000); // 3 seconds if(ui->scopeEnableWFBtn->isChecked()) { issueDelayedCommand(cmdDispEnable); issueDelayedCommand(cmdQueNormalSpeed); issueDelayedCommand(cmdSpecOn); issueDelayedCommand(cmdStartRegularPolling); // s-meter, etc } else { issueDelayedCommand(cmdQueNormalSpeed); issueDelayedCommand(cmdStartRegularPolling); // s-meter, etc } delayedCommand->start(); } void wfmain::powerRigOff() { delayedCommand->stop(); delayedCmdQue.clear(); emit sendPowerOff(); } void wfmain::on_ritTuneDial_valueChanged(int value) { emit setRitValue(value); } void wfmain::on_ritEnableChk_clicked(bool checked) { emit setRitEnable(checked); } void wfmain::receiveRITStatus(bool ritEnabled) { ui->ritEnableChk->blockSignals(true); ui->ritEnableChk->setChecked(ritEnabled); ui->ritEnableChk->blockSignals(false); } void wfmain::receiveRITValue(int ritValHz) { if((ritValHz > -500) && (ritValHz < 500)) { ui->ritTuneDial->blockSignals(true); ui->ritTuneDial->setValue(ritValHz); ui->ritTuneDial->blockSignals(false); } else { qInfo(logSystem()) << "Warning: out of range RIT value received: " << ritValHz << " Hz"; } } void wfmain::showButton(QPushButton *btn) { btn->setHidden(false); } void wfmain::hideButton(QPushButton *btn) { btn->setHidden(true); } void wfmain::setBandButtons() { // Turn off each button first: hideButton(ui->band23cmbtn); hideButton(ui->band70cmbtn); hideButton(ui->band2mbtn); hideButton(ui->bandAirbtn); hideButton(ui->bandWFMbtn); hideButton(ui->band4mbtn); hideButton(ui->band6mbtn); hideButton(ui->band10mbtn); hideButton(ui->band12mbtn); hideButton(ui->band15mbtn); hideButton(ui->band17mbtn); hideButton(ui->band20mbtn); hideButton(ui->band30mbtn); hideButton(ui->band40mbtn); hideButton(ui->band60mbtn); hideButton(ui->band80mbtn); hideButton(ui->band160mbtn); hideButton(ui->band630mbtn); hideButton(ui->band2200mbtn); hideButton(ui->bandGenbtn); bandType bandSel; //for (auto band = rigCaps.bands.begin(); band != rigCaps.bands.end(); ++band) // no worky for(unsigned int i=0; i < rigCaps.bands.size(); i++) { bandSel = rigCaps.bands.at(i); switch(bandSel) { case(band23cm): showButton(ui->band23cmbtn); break; case(band70cm): showButton(ui->band70cmbtn); break; case(band2m): showButton(ui->band2mbtn); break; case(bandAir): showButton(ui->bandAirbtn); break; case(bandWFM): showButton(ui->bandWFMbtn); break; case(band4m): showButton(ui->band4mbtn); break; case(band6m): showButton(ui->band6mbtn); break; case(band10m): showButton(ui->band10mbtn); break; case(band12m): showButton(ui->band12mbtn); break; case(band15m): showButton(ui->band15mbtn); break; case(band17m): showButton(ui->band17mbtn); break; case(band20m): showButton(ui->band20mbtn); break; case(band30m): showButton(ui->band30mbtn); break; case(band40m): showButton(ui->band40mbtn); break; case(band60m): showButton(ui->band60mbtn); break; case(band80m): showButton(ui->band80mbtn); break; case(band160m): showButton(ui->band160mbtn); break; case(band630m): showButton(ui->band630mbtn); break; case(band2200m): showButton(ui->band2200mbtn); break; case(bandGen): showButton(ui->bandGenbtn); break; default: break; } } } void wfmain::on_rigCIVManualAddrChk_clicked(bool checked) { if(checked) { ui->rigCIVaddrHexLine->setEnabled(true); ui->rigCIVaddrHexLine->setText(QString("%1").arg(prefs.radioCIVAddr, 2, 16)); } else { ui->rigCIVaddrHexLine->setText("auto"); ui->rigCIVaddrHexLine->setEnabled(false); prefs.radioCIVAddr = 0; // auto showStatusBarText("Setting radio CI-V address to: 'auto'. Make sure CI-V Transceive is enabled on the radio."); } } void wfmain::on_rigCIVaddrHexLine_editingFinished() { bool okconvert=false; unsigned char propCIVAddr = (unsigned char) ui->rigCIVaddrHexLine->text().toUInt(&okconvert, 16); if(okconvert && (propCIVAddr < 0xe0) && (propCIVAddr != 0)) { prefs.radioCIVAddr = propCIVAddr; emit setCIVAddr(propCIVAddr); showStatusBarText(QString("Setting radio CI-V address to: 0x%1. Press Save Settings to retain.").arg(propCIVAddr, 2, 16)); } else { showStatusBarText(QString("Could not use provided CI-V address. Address must be < 0xE0")); } } void wfmain::on_baudRateCombo_activated(int index) { bool ok = false; quint32 baud = ui->baudRateCombo->currentData().toUInt(&ok); if(ok) { prefs.serialPortBaud = baud; serverConfig.baudRate = baud; showStatusBarText(QString("Changed baud rate to %1 bps. Press Save Settings to retain.").arg(baud)); } (void)index; } void wfmain::on_useRTSforPTTchk_clicked(bool checked) { emit setRTSforPTT(checked); prefs.forceRTSasPTT = checked; } void wfmain::on_wfLengthSlider_valueChanged(int value) { prefs.wflength = (unsigned int)(value); prepareWf(value); } void wfmain::on_pollingBtn_clicked() { bool ok; int timing = 0; timing = QInputDialog::getInt(this, "wfview Radio Polling Setup", "Poll Timing Interval (ms)", delayedCommand->interval(), 1, 200, 1, &ok ); if(ok && timing) { delayedCommand->setInterval( timing ); qInfo(logSystem()) << "User changed radio polling interval to " << timing << "ms."; showStatusBarText("User changed radio polling interval to " + QString("%1").arg(timing) + "ms."); } } void wfmain::on_wfAntiAliasChk_clicked(bool checked) { colorMap->setAntialiased(checked); prefs.wfAntiAlias = checked; } void wfmain::on_wfInterpolateChk_clicked(bool checked) { colorMap->setInterpolate(checked); prefs.wfInterpolate = checked; } wfmain::cmds wfmain::meterKindToMeterCommand(meterKind m) { cmds c; switch(m) { case meterNone: c = cmdNone; break; case meterS: c = cmdGetSMeter; break; case meterCenter: c = cmdGetCenterMeter; break; case meterPower: c = cmdGetPowerMeter; break; case meterSWR: c = cmdGetSWRMeter; break; case meterALC: c = cmdGetALCMeter; break; case meterComp: c = cmdGetCompMeter; break; case meterCurrent: c = cmdGetIdMeter; break; case meterVoltage: c = cmdGetVdMeter; break; default: c = cmdNone; break; } return c; } void wfmain::on_meter2selectionCombo_activated(int index) { meterKind newMeterType; meterKind oldMeterType; newMeterType = static_cast(ui->meter2selectionCombo->currentData().toInt()); oldMeterType = ui->meter2Widget->getMeterType(); if(newMeterType == oldMeterType) return; cmds newCmd = meterKindToMeterCommand(newMeterType); cmds oldCmd = meterKindToMeterCommand(oldMeterType); removePeriodicCommand(oldCmd); if(newMeterType==meterNone) { ui->meter2Widget->hide(); ui->meter2Widget->setMeterType(newMeterType); } else { ui->meter2Widget->show(); ui->meter2Widget->setMeterType(newMeterType); if((newMeterType!=meterRxAudio) && (newMeterType!=meterTxMod) && (newMeterType!=meterAudio)) insertPeriodicCommandUnique(newCmd); } prefs.meter2Type = newMeterType; (void)index; } void wfmain::on_enableRigctldChk_clicked(bool checked) { if (rigCtl != Q_NULLPTR) { rigCtl->disconnect(); delete rigCtl; rigCtl = Q_NULLPTR; } if (checked) { // Start rigctld rigCtl = new rigCtlD(this); rigCtl->startServer(prefs.rigCtlPort); connect(this, SIGNAL(sendRigCaps(rigCapabilities)), rigCtl, SLOT(receiveRigCaps(rigCapabilities))); if (rig != Q_NULLPTR) { // We are already connected to a rig. connect(rig, SIGNAL(stateInfo(rigstate*)), rigCtl, SLOT(receiveStateInfo(rigstate*))); connect(rigCtl, SIGNAL(stateUpdated()), rig, SLOT(stateUpdated())); emit sendRigCaps(rigCaps); emit requestRigState(); } } prefs.enableRigCtlD = checked; } void wfmain::on_rigctldPortTxt_editingFinished() { bool okconvert = false; unsigned int port = ui->rigctldPortTxt->text().toUInt(&okconvert); if (okconvert) { prefs.rigCtlPort = port; } } void wfmain::on_tcpServerPortTxt_editingFinished() { bool okconvert = false; unsigned int port = ui->tcpServerPortTxt->text().toUInt(&okconvert); if (okconvert) { prefs.tcpPort = port; } } void wfmain::on_waterfallFormatCombo_activated(int index) { prefs.waterfallFormat = index; } void wfmain::on_moreControlsBtn_clicked() { trxadj->show(); } void wfmain::on_useCIVasRigIDChk_clicked(bool checked) { prefs.CIVisRadioModel = checked; } void wfmain::receiveStateInfo(rigstate* state) { qInfo("Setting rig state for wfmain"); rigState = state; } void wfmain::on_setClockBtn_clicked() { setRadioTimeDatePrep(); } void wfmain::radioSelection(QList radios) { selRad->populate(radios); } void wfmain::on_radioStatusBtn_clicked() { if (selRad->isVisible()) { selRad->hide(); } else { selRad->show(); } } void wfmain::setAudioDevicesUI() { // Enumerate audio devices, need to do before settings are loaded, // First clear all existing entries ui->audioInputCombo->blockSignals(true); ui->audioOutputCombo->blockSignals(true); ui->serverTXAudioOutputCombo->blockSignals(true); ui->serverRXAudioInputCombo->blockSignals(true); ui->audioInputCombo->clear(); ui->audioOutputCombo->clear(); ui->serverTXAudioOutputCombo->clear(); ui->serverRXAudioInputCombo->clear(); qDebug(logSystem()) << "Finding audio devices, output=" << rxSetup.name << "input="<audioInputCombo->addItem(deviceInfo.deviceName(), QVariant::fromValue(deviceInfo)); ui->serverRXAudioInputCombo->addItem(deviceInfo.deviceName(), QVariant::fromValue(deviceInfo)); inCount++; #ifdef Q_OS_WIN } #endif } const auto audioOutputs = QAudioDeviceInfo::availableDevices(QAudio::AudioOutput); for (const QAudioDeviceInfo& deviceInfo : audioOutputs) { #ifdef Q_OS_WIN if (deviceInfo.realm() == "wasapi") { #endif ui->audioOutputCombo->addItem(deviceInfo.deviceName(), QVariant::fromValue(deviceInfo)); ui->serverTXAudioOutputCombo->addItem(deviceInfo.deviceName(), QVariant::fromValue(deviceInfo)); outCount++; #ifdef Q_OS_WIN } #endif } break; } case portAudio: { PaError err; err = Pa_Initialize(); if (err != paNoError) { qInfo(logAudio()) << "ERROR: Cannot initialize Portaudio"; return; } qInfo(logAudio()) << "PortAudio version: " << Pa_GetVersionInfo()->versionText; int numDevices = Pa_GetDeviceCount(); qInfo(logAudio()) << "Pa_CountDevices returned" << numDevices; const PaDeviceInfo* info; for (int i = 0; i < numDevices; i++) { info = Pa_GetDeviceInfo(i); if (info->maxInputChannels > 0) { qDebug(logAudio()) << (i == Pa_GetDefaultInputDevice() ? "*" : " ") << "(" << i << ") Input Device : " << info->name; ui->audioInputCombo->addItem(info->name, i); ui->serverRXAudioInputCombo->addItem(info->name, i); if (i == Pa_GetDefaultInputDevice()) { defaultAudioInputIndex = inCount; } inCount++; } if (info->maxOutputChannels > 0) { qDebug(logAudio()) << (i == Pa_GetDefaultOutputDevice() ? "*" : " ") << "(" << i << ") Output Device : " << info->name; ui->audioOutputCombo->addItem(info->name, i); ui->serverTXAudioOutputCombo->addItem(info->name, i); if (i == Pa_GetDefaultOutputDevice()) { defaultAudioOutputIndex = outCount; } outCount++; } } break; } case rtAudio: { Pa_Terminate(); #if defined(Q_OS_LINUX) RtAudio* audio = new RtAudio(RtAudio::Api::LINUX_ALSA); #elif defined(Q_OS_WIN) RtAudio* audio = new RtAudio(RtAudio::Api::WINDOWS_WASAPI); #elif defined(Q_OS_MACX) RtAudio* audio = new RtAudio(RtAudio::Api::MACOSX_CORE); #endif // Enumerate audio devices, need to do before settings are loaded. std::map apiMap; apiMap[RtAudio::MACOSX_CORE] = "OS-X Core Audio"; apiMap[RtAudio::WINDOWS_ASIO] = "Windows ASIO"; apiMap[RtAudio::WINDOWS_DS] = "Windows DirectSound"; apiMap[RtAudio::WINDOWS_WASAPI] = "Windows WASAPI"; apiMap[RtAudio::UNIX_JACK] = "Jack Client"; apiMap[RtAudio::LINUX_ALSA] = "Linux ALSA"; apiMap[RtAudio::LINUX_PULSE] = "Linux PulseAudio"; apiMap[RtAudio::LINUX_OSS] = "Linux OSS"; apiMap[RtAudio::RTAUDIO_DUMMY] = "RtAudio Dummy"; std::vector< RtAudio::Api > apis; RtAudio::getCompiledApi(apis); qInfo(logAudio()) << "RtAudio Version " << QString::fromStdString(RtAudio::getVersion()); qInfo(logAudio()) << "Compiled APIs:"; for (unsigned int i = 0; i < apis.size(); i++) { qInfo(logAudio()) << " " << QString::fromStdString(apiMap[apis[i]]); } RtAudio::DeviceInfo info; qInfo(logAudio()) << "Current API: " << QString::fromStdString(apiMap[audio->getCurrentApi()]); unsigned int devices = audio->getDeviceCount(); qInfo(logAudio()) << "Found " << devices << " audio device(s) *=default"; for (unsigned int i = 1; i < devices; i++) { info = audio->getDeviceInfo(i); if (info.inputChannels > 0) { qInfo(logAudio()) << (info.isDefaultInput ? "*" : " ") << "(" << i << ") Input Device : " << QString::fromStdString(info.name); ui->audioInputCombo->addItem(QString::fromStdString(info.name), i); ui->serverRXAudioInputCombo->addItem(QString::fromStdString(info.name), i); if (info.isDefaultInput) { defaultAudioInputIndex = inCount; } inCount++; } if (info.outputChannels > 0) { qInfo(logAudio()) << (info.isDefaultOutput ? "*" : " ") << "(" << i << ") Output Device : " << QString::fromStdString(info.name); ui->audioOutputCombo->addItem(QString::fromStdString(info.name), i); ui->serverTXAudioOutputCombo->addItem(QString::fromStdString(info.name), i); if (info.isDefaultOutput) { defaultAudioOutputIndex = outCount; } outCount++; } } delete audio; break; } } // Stop blocking signals so we can set the current values ui->audioInputCombo->blockSignals(false); ui->audioOutputCombo->blockSignals(false); ui->serverTXAudioOutputCombo->blockSignals(false); ui->serverRXAudioInputCombo->blockSignals(false); rxSetup.type = prefs.audioSystem; txSetup.type = prefs.audioSystem; int audioInputIndex = ui->audioInputCombo->findText(txSetup.name); if (audioInputIndex != -1) { ui->audioInputCombo->setCurrentIndex(audioInputIndex); } else { qDebug(logSystem()) << "Audio input not found"; ui->audioInputCombo->setCurrentIndex(defaultAudioInputIndex); } int audioOutputIndex = ui->audioOutputCombo->findText(rxSetup.name); if (audioOutputIndex != -1) { ui->audioOutputCombo->setCurrentIndex(audioOutputIndex); } else { qDebug(logSystem()) << "Audio output not found"; ui->audioOutputCombo->setCurrentIndex(defaultAudioOutputIndex); } if (!serverConfig.rigs.isEmpty()) { qInfo(logGui()) << "Got Server Audio Input: " << serverConfig.rigs.first()->rxAudioSetup.name; serverConfig.rigs.first()->rxAudioSetup.type = prefs.audioSystem; serverConfig.rigs.first()->txAudioSetup.type = prefs.audioSystem; int serverAudioInputIndex = ui->serverRXAudioInputCombo->findText(serverConfig.rigs.first()->rxAudioSetup.name); if (serverAudioInputIndex != -1) { ui->serverRXAudioInputCombo->setCurrentIndex(serverAudioInputIndex); } else { // Set to default ui->serverRXAudioInputCombo->setCurrentIndex(defaultAudioInputIndex); } qInfo(logGui()) << "Got Server Audio Output: " << serverConfig.rigs.first()->txAudioSetup.name; int serverAudioOutputIndex = ui->serverTXAudioOutputCombo->findText(serverConfig.rigs.first()->txAudioSetup.name); if (serverAudioOutputIndex != -1) { ui->serverTXAudioOutputCombo->setCurrentIndex(serverAudioOutputIndex); } else { ui->serverTXAudioOutputCombo->setCurrentIndex(defaultAudioOutputIndex); } } qDebug(logSystem()) << "Audio devices done."; } void wfmain::on_audioSystemCombo_currentIndexChanged(int value) { prefs.audioSystem = static_cast(value); setAudioDevicesUI(); // Force all audio devices to update } void wfmain::on_topLevelSlider_valueChanged(int value) { wfCeiling = value; plotCeiling = value; prefs.plotCeiling = value; plot->yAxis->setRange(QCPRange(plotFloor, plotCeiling)); colorMap->setDataRange(QCPRange(wfFloor, wfCeiling)); } void wfmain::on_botLevelSlider_valueChanged(int value) { wfFloor = value; plotFloor = value; prefs.plotFloor = value; plot->yAxis->setRange(QCPRange(plotFloor, plotCeiling)); colorMap->setDataRange(QCPRange(wfFloor, wfCeiling)); } void wfmain::on_underlayBufferSlider_valueChanged(int value) { resizePlasmaBuffer(value); prefs.underlayBufferSize = value; } void wfmain::resizePlasmaBuffer(int newSize) { QByteArray empty((int)spectWidth, '\x01'); plasmaMutex.lock(); int oldSize = spectrumPlasma.size(); if(oldSize < newSize) { spectrumPlasma.resize(newSize); for(int p=oldSize; p < newSize; p++) { spectrumPlasma.append(empty); } } else if (oldSize > newSize){ for(int p = oldSize; p > newSize; p--) { spectrumPlasma.pop_back(); } } spectrumPlasma.squeeze(); plasmaMutex.unlock(); } void wfmain::on_underlayNone_toggled(bool checked) { ui->underlayBufferSlider->setDisabled(checked); if(checked) { underlayMode = underlayNone; prefs.underlayMode = underlayMode; on_clearPeakBtn_clicked(); } } void wfmain::on_underlayPeakHold_toggled(bool checked) { ui->underlayBufferSlider->setDisabled(checked); if(checked) { underlayMode = underlayPeakHold; prefs.underlayMode = underlayMode; on_clearPeakBtn_clicked(); } } void wfmain::on_underlayPeakBuffer_toggled(bool checked) { ui->underlayBufferSlider->setDisabled(!checked); if(checked) { underlayMode = underlayPeakBuffer; prefs.underlayMode = underlayMode; } } void wfmain::on_underlayAverageBuffer_toggled(bool checked) { ui->underlayBufferSlider->setDisabled(!checked); if(checked) { underlayMode = underlayAverageBuffer; prefs.underlayMode = underlayMode; } } // --- DEBUG FUNCTION --- void wfmain::on_debugBtn_clicked() { qInfo(logSystem()) << "Debug button pressed."; // issueDelayedCommand(cmdGetRigID); //emit getRigCIV(); //trxadj->show(); //setRadioTimeDatePrep(); //wf->setInteraction(QCP::iRangeZoom, true); //wf->setInteraction(QCP::iRangeDrag, true); plot->yAxis->setRange(QCPRange(plotFloor, plotCeiling)); colorMap->setDataRange(QCPRange(wfFloor, wfCeiling)); // bool ok; // int height = QInputDialog::getInt(this, "wfview window fixed height", "number: ", 350, 1, 500, 1, &ok ); // this->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); // this->setMaximumSize(QSize(1025,height)); // this->setMinimumSize(QSize(1025,height)); // //this->setMaximumSize(QSize(929, 270)); // //this->setMinimumSize(QSize(929, 270)); // resize(minimumSize()); // adjustSize(); // main window // adjustSize(); }