#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, QWidget *parent ) : QMainWindow(parent), ui(new Ui::wfmain) { QGuiApplication::setApplicationDisplayName("wfview"); QGuiApplication::setApplicationName(QString("wfview")); setWindowIcon(QIcon( QString(":resources/wfview.png"))); ui->setupUi(this); theParent = parent; setWindowTitle(QString("wfview")); this->serialPortCL = serialPortCL; this->hostCL = hostCL; cal = new calibrationWindow(); sat = new satelliteSetup(); srv = new udpServerSetup(); connect(this, SIGNAL(sendServerConfig(SERVERCONFIG)), srv, SLOT(receiveServerConfig(SERVERCONFIG))); connect(srv, SIGNAL(serverConfig(SERVERCONFIG, bool)), this, SLOT(serverConfigRequested(SERVERCONFIG, bool))); haveRigCaps = false; ui->bandStkLastUsedBtn->setVisible(false); ui->bandStkVoiceBtn->setVisible(false); ui->bandStkDataBtn->setVisible(false); ui->bandStkCWBtn->setVisible(false); 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())); // Enumerate audio devices, need to do before settings are loaded. const auto audioOutputs = QAudioDeviceInfo::availableDevices(QAudio::AudioOutput); for (const QAudioDeviceInfo& deviceInfo : audioOutputs) { ui->audioOutputCombo->addItem(deviceInfo.deviceName()); } const auto audioInputs = QAudioDeviceInfo::availableDevices(QAudio::AudioInput); for (const QAudioDeviceInfo& deviceInfo : audioInputs) { ui->audioInputCombo->addItem(deviceInfo.deviceName()); } setDefaultColors(); // set of UI colors with defaults populated setDefPrefs(); // other default options loadSettings(); // Look for saved preferences setTuningSteps(); // TODO: Combine into preferences // if setting for serial port is "auto" then... // if(prefs.serialPortRadio == QString("auto")) // { // // Find the ICOM IC-7300. // qDebug(logSystem()) << "Searching for serial port..."; // QDirIterator it("/dev/serial", QStringList() << "*IC-7300*", QDir::Files, QDirIterator::Subdirectories); // while (it.hasNext()) // qDebug(logSystem()) << it.next(); // // if (it.isEmpty()) // fail or default to ttyUSB0 if present // // iterator might not make sense // serialPortRig = it.filePath(); // first? last? // if(serialPortRig.isEmpty()) // { // qDebug(logSystem()) << "Cannot find IC-7300 serial port. Trying /dev/ttyUSB0"; // serialPortRig = QString("/dev/ttyUSB0"); // } // // end finding the 7300 code // } else { // serialPortRig = prefs.serialPortRadio; // } // Start server if enabled in config if (serverConfig.enabled) { 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())); serverThread->start(); emit initServer(); } plot = ui->plot; // rename it waterfall. wf = ui->waterfall; tracer = new QCPItemTracer(plot); //tracer->setGraphKey(5.5); tracer->setInterpolating(true); tracer->setStyle(QCPItemTracer::tsCrosshair); tracer->setPen(QPen(Qt::green)); tracer->setBrush(Qt::green); tracer->setSize(30); // spectWidth = 475; // fixed for now // wfLength = 160; // fixed for now, time-length of waterfall // // Initialize before use! // QByteArray empty((int)spectWidth, '\x01'); // spectrumPeaks = QByteArray( (int)spectWidth, '\x01' ); // for(quint16 i=0; imodeSelectCombo->addItem("LSB", 0x00); ui->modeSelectCombo->addItem("USB", 0x01); ui->modeSelectCombo->addItem("AM", 0x02); ui->modeSelectCombo->addItem("CW", 0x03); ui->modeSelectCombo->addItem("RTTY", 0x04); ui->modeSelectCombo->addItem("FM", 0x05); ui->modeSelectCombo->addItem("CW-R", 0x07); 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); spans << "2.5k" << "5.0k" << "10k" << "25k"; spans << "50k" << "100k" << "250k" << "500k"; ui->scopeBWCombo->insertItems(0, spans); edges << "1" << "2" << "3"; // yep ui->scopeEdgeCombo->insertItems(0, edges); ui->splitter->setHandleWidth(5); ui->rfGainSlider->setTickInterval(100); ui->rfGainSlider->setSingleStep(100); ui->afGainSlider->setSingleStep(100); ui->afGainSlider->setSingleStep(100); rigStatus = new QLabel(this); ui->statusBar->addPermanentWidget(rigStatus); ui->statusBar->showMessage("Connecting to rig...", 1000); delayedCommand = new QTimer(this); delayedCommand->setInterval(250); // 250ms until we find rig civ and id, then 100ms. delayedCommand->setSingleShot(true); connect(delayedCommand, SIGNAL(timeout()), this, SLOT(runDelayedCommand())); periodicPollingTimer = new QTimer(this); periodicPollingTimer->setInterval(100); periodicPollingTimer->setSingleShot(false); connect(periodicPollingTimer, SIGNAL(timeout()), this, SLOT(runPeriodicCommands())); openRig(); qRegisterMetaType(); qRegisterMetaType(); qRegisterMetaType(); qRegisterMetaType(); connect(rig, SIGNAL(haveFrequency(double)), this, SLOT(receiveFreq(double))); 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)), rig, SLOT(setDataMode(bool))); 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(float,char,bool)), this, SLOT(receiveBandStackReg(float,char,bool))); 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(this, SIGNAL(getDuplexMode()), rig, SLOT(getDuplexMode())); 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(haveSpectrumFixedMode(bool)), this, SLOT(receiveSpectrumFixedMode(bool))); connect(this, SIGNAL(setFrequency(double)), rig, SLOT(setFrequency(double))); connect(this, SIGNAL(setScopeCenterMode(bool)), rig, SLOT(setSpectrumCenteredMode(bool))); 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(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))); // 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(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(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(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(bool)), rig, SLOT(getMeters(bool))); 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))); // 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))); // 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*))); if (serverConfig.enabled && udp != Q_NULLPTR) { // Server connect(rig, SIGNAL(haveDataForServer(QByteArray)), udp, SLOT(dataForServer(QByteArray))); connect(udp, SIGNAL(haveDataFromServer(QByteArray)), rig, SLOT(dataFromServer(QByteArray))); } ui->plot->addGraph(); // primary ui->plot->addGraph(0, 0); // secondary, peaks, same axis as first? ui->waterfall->addGraph(); tracer->setGraph(plot->graph(0)); 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)); drawPeaks = false; ui->freqMhzLineEdit->setValidator( new QDoubleValidator(0, 100, 6, this)); ui->audioPortTxt->setValidator(new QIntValidator(this)); ui->serialPortTxt->setValidator(new QIntValidator(this)); ui->controlPortTxt->setValidator(new QIntValidator(this)); 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())); amTransmitting = false; // Not needed since we automate this now. /* foreach (const QSerialPortInfo &serialPortInfo, QSerialPortInfo::availablePorts()) { portList.append(serialPortInfo.portName()); // ui->commPortDrop->addItem(serialPortInfo.portName()); } */ #ifdef QT_DEBUG qDebug(logSystem()) << "Running with debugging options enabled."; ui->debugBtn->setVisible(true); #else ui->debugBtn->setVisible(false); #endif // Initial state of UI: 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; //getInitialRigState(); oldFreqDialVal = ui->freqDial->value(); } wfmain::~wfmain() { rigThread->quit(); rigThread->wait(); if (serverThread != Q_NULLPTR) { serverThread->quit(); serverThread->wait(); } delete ui; } 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 #ifdef QT_DEBUG 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; } #endif if (rigThread == Q_NULLPTR) { rig = new rigCommander(); rigThread = new QThread(this); rig->moveToThread(rigThread); connect(rigThread, SIGNAL(started()), rig, SLOT(process())); connect(rigThread, SIGNAL(finished()), rig, SLOT(deleteLater())); rigThread->start(); connect(rig, SIGNAL(haveSerialPortError(QString, QString)), this, SLOT(receiveSerialPortError(QString, QString))); connect(rig, SIGNAL(haveStatusUpdate(QString)), this, SLOT(receiveStatusUpdate(QString))); connect(this, SIGNAL(sendCommSetup(unsigned char, QString, quint16, quint16, quint16, QString, QString,quint16,quint16,quint8,quint16,quint8)), rig, SLOT(commSetup(unsigned char, QString, quint16, quint16, quint16, QString, QString,quint16,quint16,quint8,quint16,quint8))); connect(this, SIGNAL(sendCommSetup(unsigned char, QString, quint32)), rig, SLOT(commSetup(unsigned char, QString, quint32))); connect(this, SIGNAL(sendCloseComm()), rig, SLOT(closeComm())); connect(this, SIGNAL(sendChangeBufferSize(quint16)), rig, SLOT(changeBufferSize(quint16))); connect(this, SIGNAL(getRigCIV()), rig, SLOT(findRigs())); connect(rig, SIGNAL(discoveredRigID(rigCapabilities)), this, SLOT(receiveFoundRigID(rigCapabilities))); connect(rig, SIGNAL(commReady()), this, SLOT(receiveCommReady())); } if (prefs.enableLAN) { emit sendCommSetup(prefs.radioCIVAddr, prefs.ipAddress, prefs.controlLANPort, prefs.serialLANPort, prefs.audioLANPort, prefs.username, prefs.password,prefs.audioRXBufferSize,prefs.audioRXSampleRate,prefs.audioRXCodec,prefs.audioTXSampleRate,prefs.audioTXCodec); } else { if( (prefs.serialPortRadio == QString("auto")) && (serialPortCL.isEmpty())) { // Find the ICOM // qDebug(logSystem()) << "Searching for serial port..."; QDirIterator it73("/dev/serial", 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); if(!it73.filePath().isEmpty()) { // use serialPortRig = it73.filePath(); // first } else if(!it97.filePath().isEmpty()) { // IC-9700 port serialPortRig = it97.filePath(); } else if(!it785x.filePath().isEmpty()) { // IC-785x port serialPortRig = it785x.filePath(); } else if(!it705.filePath().isEmpty()) { // IC-705 serialPortRig = it705.filePath(); } else { //fall back: qDebug(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 } } else { if(serialPortCL.isEmpty()) { serialPortRig = prefs.serialPortRadio; } else { serialPortRig = serialPortCL; } } // Here, the radioCIVAddr is being set from a default preference, which is for the 7300. // However, we will not use it initially. OTOH, if it is set explicitedly to a value in the prefs, // then we skip auto detection. emit sendCommSetup(prefs.radioCIVAddr, serialPortRig, prefs.serialPortBaud); } ui->statusBar->showMessage(QString("Connecting to rig using serial port ").append(serialPortRig), 1000); /* if(prefs.radioCIVAddr == 0) { // tell rigCommander to broadcast a request for all rig IDs. // qDebug(logSystem()) << "Beginning search from wfview for rigCIV (auto-detection broadcast)"; ui->statusBar->showMessage(QString("Searching CIV bus for connected radios."), 1000); emit getRigCIV(); cmdOutQue.append(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. qDebug(logSystem()) << "Skipping automatic CIV, using user-supplied value of " << prefs.radioCIVAddr; getInitialRigState(); } */ } void wfmain::receiveCommReady() { qDebug(logSystem()) << "Received CommReady!! "; // taken from above: if(prefs.radioCIVAddr == 0) { // tell rigCommander to broadcast a request for all rig IDs. // qDebug(logSystem()) << "Beginning search from wfview for rigCIV (auto-detection broadcast)"; ui->statusBar->showMessage(QString("Searching CIV bus for connected radios."), 1000); emit getRigCIV(); cmdOutQue.append(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. qDebug(logSystem()) << "Skipping automatic CIV, using user-supplied value of " << prefs.radioCIVAddr; 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: //qDebug(logSystem()) << "In wfview, we now have a reply to our request for rig identity sent to CIV BROADCAST."; delayedCommand->setInterval(100); // faster polling is ok now. receiveRigID(rigCaps); getInitialRigState(); QString message = QString("Found model: ").append(rigCaps.modelName); ui->statusBar->showMessage(message, 0); return; } void wfmain::receiveSerialPortError(QString port, QString errorText) { qDebug(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(QString text) { this->rigStatus->setText(text); } void wfmain::setDefPrefs() { defPrefs.useFullScreen = false; defPrefs.useDarkMode = true; defPrefs.useSystemTheme = false; defPrefs.drawPeaks = true; defPrefs.stylesheetPath = QString("qdarkstyle/style.qss"); defPrefs.radioCIVAddr = 0x00; // previously was 0x94 for 7300. defPrefs.serialPortRadio = QString("auto"); defPrefs.serialPortBaud = 115200; defPrefs.enablePTT = false; defPrefs.niceTS = true; defPrefs.enableLAN = false; defPrefs.ipAddress = QString(""); defPrefs.controlLANPort = 50001; defPrefs.serialLANPort = 50002; defPrefs.audioLANPort = 50003; defPrefs.username = QString(""); defPrefs.password = QString(""); defPrefs.audioOutput = QAudioDeviceInfo::defaultOutputDevice().deviceName(); defPrefs.audioInput = QAudioDeviceInfo::defaultInputDevice().deviceName(); defPrefs.audioRXBufferSize = 12000; defPrefs.audioRXSampleRate = 48000; defPrefs.audioRXCodec = 4; defPrefs.audioTXSampleRate = 48000; defPrefs.audioTXCodec = 4; } void wfmain::loadSettings() { qDebug(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.drawPeaks = settings.value("DrawPeaks", defPrefs.drawPeaks).toBool(); 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. settings.endGroup(); // Radio and Comms: C-IV addr, port to use settings.beginGroup("Radio"); prefs.radioCIVAddr = (unsigned char) settings.value("RigCIVuInt", defPrefs.radioCIVAddr).toInt(); prefs.serialPortRadio = settings.value("SerialPortRadio", defPrefs.serialPortRadio).toString(); prefs.serialPortBaud = (quint32) settings.value("SerialPortBaud", defPrefs.serialPortBaud).toInt(); 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(); ui->lanEnableChk->setChecked(prefs.enableLAN); prefs.ipAddress = settings.value("IPAddress", defPrefs.ipAddress).toString(); ui->ipAddressTxt->setEnabled(ui->lanEnableChk->isChecked()); ui->ipAddressTxt->setText(prefs.ipAddress); prefs.controlLANPort = settings.value("ControlLANPort", defPrefs.controlLANPort).toInt(); ui->controlPortTxt->setEnabled(ui->lanEnableChk->isChecked()); ui->controlPortTxt->setText(QString("%1").arg(prefs.controlLANPort)); prefs.serialLANPort = settings.value("SerialLANPort", defPrefs.serialLANPort).toInt(); ui->serialPortTxt->setEnabled(ui->lanEnableChk->isChecked()); ui->serialPortTxt->setText(QString("%1").arg(prefs.serialLANPort)); prefs.audioLANPort = settings.value("AudioLANPort", defPrefs.audioLANPort).toInt(); ui->audioPortTxt->setEnabled(ui->lanEnableChk->isChecked()); ui->audioPortTxt->setText(QString("%1").arg(prefs.audioLANPort)); prefs.username = settings.value("Username", defPrefs.username).toString(); ui->usernameTxt->setEnabled(ui->lanEnableChk->isChecked()); ui->usernameTxt->setText(QString("%1").arg(prefs.username)); prefs.password = settings.value("Password", defPrefs.password).toString(); ui->passwordTxt->setEnabled(ui->lanEnableChk->isChecked()); ui->passwordTxt->setText(QString("%1").arg(prefs.password)); prefs.audioRXBufferSize = settings.value("AudioRXBufferSize", defPrefs.audioRXBufferSize).toInt(); ui->audioBufferSizeSlider->setEnabled(ui->lanEnableChk->isChecked()); ui->audioBufferSizeSlider->setValue(prefs.audioRXBufferSize); ui->audioBufferSizeSlider->setTracking(false); // Stop it sending value on every change. prefs.audioRXSampleRate = settings.value("AudioRXSampleRate", defPrefs.audioRXSampleRate).toInt(); prefs.audioTXSampleRate = settings.value("AudioTXSampleRate", defPrefs.audioTXSampleRate).toInt(); ui->audioSampleRateCombo->setEnabled(ui->lanEnableChk->isChecked()); int audioSampleRateIndex = ui->audioSampleRateCombo->findText(QString::number(prefs.audioRXSampleRate)); if (audioSampleRateIndex != -1) { ui->audioOutputCombo->setCurrentIndex(audioSampleRateIndex); } // 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); prefs.audioRXCodec = settings.value("AudioRXCodec", defPrefs.audioRXCodec).toInt(); ui->audioRXCodecCombo->setEnabled(ui->lanEnableChk->isChecked()); for (int f = 0; f < ui->audioRXCodecCombo->count(); f++) if (ui->audioRXCodecCombo->itemData(f).toInt() == prefs.audioRXCodec) ui->audioRXCodecCombo->setCurrentIndex(f); ui->audioTXCodecCombo->addItem("LPCM 1ch 16bit", 4); ui->audioTXCodecCombo->addItem("LPCM 1ch 8bit", 2); ui->audioTXCodecCombo->addItem("uLaw 1ch 8bit", 1); prefs.audioTXCodec = settings.value("AudioTXCodec", defPrefs.audioTXCodec).toInt(); ui->audioTXCodecCombo->setEnabled(ui->lanEnableChk->isChecked()); for (int f = 0; f < ui->audioTXCodecCombo->count(); f++) if (ui->audioTXCodecCombo->itemData(f).toInt() == prefs.audioTXCodec) ui->audioTXCodecCombo->setCurrentIndex(f); prefs.audioOutput = settings.value("AudioOutput", defPrefs.audioOutput).toString(); ui->audioOutputCombo->setEnabled(ui->lanEnableChk->isChecked()); int audioOutputIndex = ui->audioOutputCombo->findText(prefs.audioOutput); if (audioOutputIndex != -1) ui->audioOutputCombo->setCurrentIndex(audioOutputIndex); prefs.audioInput = settings.value("AudioInput", defPrefs.audioInput).toString(); ui->audioInputCombo->setEnabled(ui->lanEnableChk->isChecked()); int audioInputIndex = ui->audioInputCombo->findText(prefs.audioInput); if (audioInputIndex != - 1) ui->audioOutputCombo->setCurrentIndex(audioInputIndex); 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(); int numUsers = settings.value("ServerNumUsers", 2).toInt(); serverConfig.users.clear(); 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); } 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(); emit sendServerConfig(serverConfig); } void wfmain::saveSettings() { qDebug(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("StylesheetPath", prefs.stylesheetPath); settings.setValue("splitter", ui->splitter->saveState()); settings.setValue("windowGeometry", saveGeometry()); settings.setValue("windowState", saveState()); settings.endGroup(); // Radio and Comms: C-IV addr, port to use settings.beginGroup("Radio"); settings.setValue("RigCIVuInt", prefs.radioCIVAddr); settings.setValue("SerialPortRadio", prefs.serialPortRadio); settings.setValue("SerialPortBaud", prefs.serialPortBaud); 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("IPAddress", prefs.ipAddress); settings.setValue("ControlLANPort", prefs.controlLANPort); settings.setValue("SerialLANPort", prefs.serialLANPort); settings.setValue("AudioLANPort", prefs.audioLANPort); settings.setValue("Username", prefs.username); settings.setValue("Password", prefs.password); settings.setValue("AudioRXBufferSize", prefs.audioRXBufferSize); settings.setValue("AudioRXSampleRate", prefs.audioRXSampleRate); settings.setValue("AudioRXCodec", prefs.audioRXCodec); settings.setValue("AudioTXBufferSize", prefs.audioRXBufferSize); settings.setValue("AudioTXSampleRate", prefs.audioRXSampleRate); settings.setValue("AudioTXCodec", prefs.audioTXCodec); settings.setValue("AudioOutput", prefs.audioOutput); settings.setValue("AudioInput", prefs.audioInput); 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", QColor(0,0,0,255)); settings.setValue("Dark_PlotAxisPen", QColor(75,75,75,255)); settings.setValue("Dark_PlotLegendTextColor", QColor(255,255,255,255)); settings.setValue("Dark_PlotLegendBorderPen", QColor(255,255,255,255)); settings.setValue("Dark_PlotLegendBrush", QColor(0,0,0,200)); settings.setValue("Dark_PlotTickLabel", QColor(Qt::white)); settings.setValue("Dark_PlotBasePen", QColor(Qt::white)); settings.setValue("Dark_PlotTickPen", QColor(Qt::white)); settings.setValue("Dark_PlotFreqTracer", QColor(Qt::yellow)); settings.endGroup(); settings.beginGroup("LightColors"); settings.setValue("Light_PlotBackground", QColor(255,255,255,255)); settings.setValue("Light_PlotAxisPen", QColor(200,200,200,255)); settings.setValue("Light_PlotLegendTextColor", QColor(0,0,0,255)); settings.setValue("Light_PlotLegendBorderPen", QColor(0,0,0,255)); settings.setValue("Light_PlotLegendBrush", QColor(255,255,255,200)); settings.setValue("Light_PlotTickLabel", QColor(Qt::black)); settings.setValue("Light_PlotBasePen", QColor(Qt::black)); settings.setValue("Light_PlotTickPen", QColor(Qt::black)); settings.setValue("Light_PlotFreqTracer", QColor(Qt::blue)); settings.endGroup(); // This is a reference to see how the preference file is encoded. settings.beginGroup("StandardColors"); settings.setValue("white", QColor(Qt::white)); settings.setValue("black", QColor(Qt::black)); settings.setValue("red_opaque", QColor(Qt::red)); settings.setValue("red_translucent", QColor(255,0,0,128)); settings.setValue("green_opaque", QColor(Qt::green)); settings.setValue("green_translucent", QColor(0,255,0,128)); settings.setValue("blue_opaque", QColor(Qt::blue)); settings.setValue("blue_translucent", QColor(0,0,255,128)); 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("ServerNumUsers", serverConfig.users.count()); for (int f = 0; f < serverConfig.users.count(); f++) { settings.setValue("ServerUsername_" + QString::number(f), serverConfig.users[f].username); settings.setValue("ServerPassword_" + QString::number(f), serverConfig.users[f].password); settings.setValue("ServerUserType_" + QString::number(f), serverConfig.users[f].userType); } settings.endGroup(); settings.sync(); // Automatic, not needed (supposedly) } void wfmain::prepareWf() { // All this code gets moved in from the constructor of wfmain. if(haveRigCaps) { // do things spectWidth = rigCaps.spectLenMax; // was fixed at 475 wfLength = 160; // fixed for now, time-length of waterfall // Initialize before use! QByteArray empty((int)spectWidth, '\x01'); spectrumPeaks = QByteArray( (int)spectWidth, '\x01' ); for(quint16 i=0; idata()->setValueRange(QCPRange(0, wfLength-1)); colorMap->data()->setKeyRange(QCPRange(0, spectWidth-1)); colorMap->setDataRange(QCPRange(0, rigCaps.spectAmpMax)); colorMap->setGradient(QCPColorGradient::gpJet); // TODO: Add preference colorMapData = new QCPColorMapData(spectWidth, wfLength, QCPRange(0, spectWidth-1), QCPRange(0, wfLength-1)); colorMap->setData(colorMapData); spectRowCurrent = 0; wf->yAxis->setRangeReversed(true); wf->xAxis->setVisible(false); } else { qDebug(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 via IC-7300 showStatusBarText("Sending speech command to radio."); emit sayAll(); } void wfmain::shortcutControlT() { // Transmit qDebug(logSystem()) << "Activated Control-T shortcut"; showStatusBarText(QString("Transmitting. Press Control-R to receive.")); ui->pttOnBtn->click(); } void wfmain::shortcutControlR() { // Receive emit setPTT(false); issueDelayedCommand(cmdGetPTT); } 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 } double wfmain::roundFrequency(double frequency) { return round(frequency*100000) / 100000.0; } void wfmain::shortcutMinus() { if(freqLock) return; freqMhz = roundFrequency(freqMhz - tsPlus); knobFreqMhz = freqMhz; emit setFrequency(freqMhz); issueDelayedCommand(cmdGetFreq); //ui->freqDial->setValue( ui->freqDial->value() - ui->freqDial->singleStep() ); } void wfmain::shortcutPlus() { if(freqLock) return; knobFreqMhz = roundFrequency(freqMhz + tsPlus); freqMhz = knobFreqMhz; emit setFrequency(freqMhz); issueDelayedCommand(cmdGetFreq); //ui->freqDial->setValue( ui->freqDial->value() + ui->freqDial->singleStep() ); } void wfmain::shortcutShiftMinus() { if(freqLock) return; freqMhz= roundFrequency(freqMhz-tsPlusShift); knobFreqMhz = freqMhz; emit setFrequency(freqMhz); issueDelayedCommand(cmdGetFreq); //ui->freqDial->setValue( ui->freqDial->value() - ui->freqDial->pageStep() ); } void wfmain::shortcutShiftPlus() { if(freqLock) return; freqMhz= roundFrequency(freqMhz+tsPlusShift); knobFreqMhz = freqMhz; emit setFrequency(freqMhz); issueDelayedCommand(cmdGetFreq); //ui->freqDial->setValue( ui->freqDial->value() + ui->freqDial->pageStep() ); } void wfmain::shortcutControlMinus() { if(freqLock) return; freqMhz= roundFrequency(freqMhz-tsPlusControl); knobFreqMhz = freqMhz; emit setFrequency(freqMhz); issueDelayedCommand(cmdGetFreq); //ui->freqDial->setValue( ui->freqDial->value() - ui->freqDial->pageStep() ); } void wfmain::shortcutControlPlus() { if(freqLock) return; freqMhz= roundFrequency(freqMhz+tsPlusControl); knobFreqMhz = freqMhz; emit setFrequency(freqMhz); issueDelayedCommand(cmdGetFreq); //ui->freqDial->setValue( ui->freqDial->value() + ui->freqDial->pageStep() ); } void wfmain::shortcutPageUp() { if(freqLock) return; freqMhz = roundFrequency(freqMhz + tsPage); knobFreqMhz = freqMhz; emit setFrequency(freqMhz); issueDelayedCommand(cmdGetFreq); } void wfmain::shortcutPageDown() { if(freqLock) return; freqMhz = roundFrequency(freqMhz - tsPage); knobFreqMhz = freqMhz; emit setFrequency(freqMhz); issueDelayedCommand(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:: 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 occassionally. cmdOutQue.append(cmdGetFreq); cmdOutQue.append(cmdGetMode); cmdOutQue.append(cmdNone); cmdOutQue.append(cmdGetFreq); cmdOutQue.append(cmdGetMode); // From left to right in the UI: cmdOutQue.append(cmdGetDataMode); cmdOutQue.append(cmdGetModInput); cmdOutQue.append(cmdGetModDataInput); cmdOutQue.append(cmdGetRxGain); cmdOutQue.append(cmdGetAfGain); cmdOutQue.append(cmdGetSql); cmdOutQue.append(cmdGetTxPower); cmdOutQue.append(cmdGetCurrentModLevel); // level for currently selected mod sources cmdOutQue.append(cmdGetSpectrumRefLevel); cmdOutQue.append(cmdGetDuplexMode); cmdOutQue.append(cmdDispEnable); cmdOutQue.append(cmdSpecOn); cmdOutQue.append(cmdGetModInput); cmdOutQue.append(cmdGetModDataInput); cmdOutQue.append(cmdNone); cmdOutQue.append(cmdStartRegularPolling); if(rigCaps.hasATU) { cmdOutQue.append(cmdGetATUStatus); } cmdOut = cmdNone; 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) { // QFile f(":qdarkstyle/style.qss"); // built-in resource QFile f("/usr/share/wfview/stylesheets/" + prefs.stylesheetPath); if (!f.exists()) { printf("Unable to set stylesheet, file not found\n"); printf("Tried to load: [%s]\n", QString( QString("/usr/share/wfview/stylesheets/") + prefs.stylesheetPath).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_PlotFreqTracer = QColor(Qt::yellow); 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_PlotFreqTracer = QColor(Qt::blue); } void wfmain::setPlotTheme(QCustomPlot *plot, bool isDark) { if(isDark) { plot->setBackground(QColor(0,0,0,255)); plot->xAxis->grid()->setPen(QColor(75,75,75,255)); plot->yAxis->grid()->setPen(QColor(75,75,75,255)); plot->legend->setTextColor(QColor(255,255,255,255)); plot->legend->setBorderPen(QColor(255,255,255,255)); plot->legend->setBrush(QColor(0,0,0,200)); plot->xAxis->setTickLabelColor(Qt::white); plot->xAxis->setLabelColor(Qt::white); plot->yAxis->setTickLabelColor(Qt::white); plot->yAxis->setLabelColor(Qt::white); plot->xAxis->setBasePen(QPen(Qt::white)); plot->xAxis->setTickPen(QPen(Qt::white)); plot->yAxis->setBasePen(QPen(Qt::white)); plot->yAxis->setTickPen(QPen(Qt::white)); plot->graph(0)->setPen(QPen(Qt::yellow)); // magenta, yellow, green, lightGray } else { //color = ui->groupBox->palette().color(QPalette::Button); plot->setBackground(QColor(255,255,255,255)); //plot->setBackground(color); plot->xAxis->grid()->setPen(QColor(200,200,200,255)); plot->yAxis->grid()->setPen(QColor(200,200,200,255)); plot->legend->setTextColor(QColor(0,0,0,255)); plot->legend->setBorderPen(QColor(0,0,0,255)); plot->legend->setBrush(QColor(255,255,255,200)); plot->xAxis->setTickLabelColor(Qt::black); plot->xAxis->setLabelColor(Qt::black); plot->yAxis->setTickLabelColor(Qt::black); plot->yAxis->setLabelColor(Qt::black); plot->xAxis->setBasePen(QPen(Qt::black)); plot->xAxis->setTickPen(QPen(Qt::black)); plot->yAxis->setBasePen(QPen(Qt::black)); plot->yAxis->setTickPen(QPen(Qt::black)); plot->graph(0)->setPen(QPen(Qt::blue)); } } void wfmain::runPeriodicCommands() { // These commands are run at a regular interval. They are to be used sparingly. // For general radio state queries, use the runDelayedCommand() queue, // accessed by the insertPeriodicCommands() function. // To insert commands to this queue, uset the insertPeriodicCommands() function. // TODO: Queue should not remove items, just hit a different item each time. int nCmds = periodicCmdQueue.length(); cmds pcmd; if(!periodicCmdQueue.isEmpty()) { pcmd = periodicCmdQueue.at( (pCmdNum++)%nCmds ); switch(pcmd) { case cmdNone: break; // Metering commands: case cmdGetRxLevels: case cmdGetTxLevels: emit getMeters(amTransmitting); break; case cmdGetSMeter: break; case cmdGetPowerMeter: break; case cmdGetALCMeter: break; case cmdGetCompMeter: break; case cmdGetRigID: emit getRigID(); break; case cmdGetRigCIV: // if(!know rig civ already) if(!haveRigCaps) { emit getRigCIV(); cmdOutQue.append(cmdGetRigCIV); // This way, we stay here until we get an answer. } break; case cmdGetFreq: emit getFrequency(); break; case cmdGetMode: emit getMode(); break; case cmdGetDataMode: // qDebug(logSystem()) << "Sending query for data mode"; emit getDataMode(); break; case cmdSetDataModeOff: emit setDataMode(false); break; case cmdSetDataModeOn: emit setDataMode(true); break; case cmdGetModInput: emit getModInput(false); break; case cmdGetModDataInput: emit getModInput(true); break; case cmdGetCurrentModLevel: emit getModInputLevel(currentModSrc); emit getModInputLevel(currentModDataSrc); break; case cmdGetDuplexMode: emit getDuplexMode(); break; case cmdDispEnable: emit scopeDisplayEnable(); break; case cmdDispDisable: emit scopeDisplayDisable(); 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 cmdGetTxPower: emit getTxPower(); break; case cmdGetMicGain: emit getMicGain(); break; case cmdGetSpectrumRefLevel: emit getSpectrumRefLevel(); break; case cmdGetATUStatus: emit getATUStatus(); break; case cmdScopeCenterMode: emit setScopeCenterMode(true); break; case cmdScopeFixedMode: emit setScopeCenterMode(false); break; case cmdGetPTT: emit getPTT(); break; case cmdStartRegularPolling: periodicPollingTimer->start(); break; case cmdStopRegularPolling: periodicPollingTimer->stop(); break; default: break; } } } void wfmain::runDelayedCommand() { cmds qdCmd; // Note: This cmdOut queue will be removed entirely soon and only the cmdOutQue will be available. switch (cmdOut) { case cmdGetFreq: emit getFrequency(); break; case cmdGetMode: emit getMode(); break; default: break; } cmdOut = cmdNone; // yep. Hope this wasn't called twice in a row rapidly. // Note: All command should use this queue. There is no need to use the above system. if(!cmdOutQue.isEmpty()) { qdCmd = cmdOutQue.takeFirst(); switch(qdCmd) { case cmdNone: //qDebug(logSystem()) << "NOOP"; break; case cmdGetRigID: emit getRigID(); break; case cmdGetRigCIV: // if(!know rig civ already) if(!haveRigCaps) { emit getRigCIV(); cmdOutQue.append(cmdGetRigCIV); // This way, we stay here until we get an answer. } break; case cmdGetFreq: emit getFrequency(); break; case cmdGetMode: emit getMode(); break; case cmdGetDataMode: // qDebug(logSystem()) << "Sending query for data mode"; emit getDataMode(); break; case cmdSetDataModeOff: emit setDataMode(false); break; case cmdSetDataModeOn: emit setDataMode(true); break; case cmdGetModInput: emit getModInput(false); break; case cmdGetModDataInput: emit getModInput(true); break; case cmdGetCurrentModLevel: emit getModInputLevel(currentModSrc); emit getModInputLevel(currentModDataSrc); break; case cmdGetDuplexMode: emit getDuplexMode(); break; case cmdDispEnable: emit scopeDisplayEnable(); break; case cmdDispDisable: emit scopeDisplayDisable(); 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 cmdGetTxPower: emit getTxPower(); break; case cmdGetMicGain: emit getMicGain(); break; case cmdGetSpectrumRefLevel: emit getSpectrumRefLevel(); break; case cmdGetATUStatus: emit getATUStatus(); break; case cmdScopeCenterMode: emit setScopeCenterMode(true); break; case cmdScopeFixedMode: emit setScopeCenterMode(false); break; case cmdGetPTT: emit getPTT(); break; case cmdStartRegularPolling: periodicPollingTimer->start(); break; case cmdStopRegularPolling: periodicPollingTimer->stop(); break; default: break; } } if(cmdOutQue.isEmpty()) { // done } else { // next // TODO: If we always do ->start, then it will not be necessary for // every command insertion to include a ->start.... probably worth doing. delayedCommand->start(); } } void wfmain::issueDelayedCommand(cmds cmd) { cmdOutQue.append(cmd); delayedCommand->start(); } void wfmain::issueDelayedCommandPriority(cmds cmd) { // Places the new command at the top of the queue // Use only when needed. cmdOutQue.prepend(cmd); delayedCommand->start(); } 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 { #ifdef QT_DEBUG 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; #endif this->rigCaps = rigCaps; this->spectWidth = rigCaps.spectLenMax; // used once haveRigCaps is true. haveRigCaps = true; if(rigCaps.model==model7850) { ui->modeSelectCombo->addItem("PSK", 0x12); ui->modeSelectCombo->addItem("PSK-R", 0x13); } if(rigCaps.hasDV) { ui->modeSelectCombo->addItem("DV", 0x17); } if(rigCaps.hasDD) { ui->modeSelectCombo->addItem("DD", 0x22); } if(rigCaps.model == model9700) { ui->satOpsBtn->setDisabled(false); ui->adjRefBtn->setDisabled(false); } else { ui->satOpsBtn->setDisabled(true); ui->adjRefBtn->setDisabled(true); } QString inName; 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->tuneEnableChk->setEnabled(rigCaps.hasATU); ui->tuneNowBtn->setEnabled(rigCaps.hasATU); ui->connectBtn->setText("Disconnect"); // We must be connected now. prepareWf(); // 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: cmdOutQue.append(cmdGetFreq); cmdOutQue.append(cmdGetMode); initPeriodicCommands(); } } 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(cmdGetRxLevels, 128); insertPeriodicCommand(cmdGetTxLevels, 128); } void wfmain::insertPeriodicCommand(cmds cmd, unsigned char priority) { // TODO: meaningful priority if(priority < 10) { periodicCmdQueue.prepend(cmd); } else { periodicCmdQueue.append(cmd); } } void wfmain::receiveFreq(double freqMhz) { //qDebug(logSystem()) << "HEY WE GOT A Frequency: " << freqMhz; ui->freqLabel->setText(QString("%1").arg(freqMhz, 0, 'f')); this->freqMhz = freqMhz; this->knobFreqMhz = freqMhz; //showStatusBarText(QString("Frequency: %1").arg(freqMhz)); } void wfmain::receivePTTstatus(bool pttOn) { // This is the only place where amTransmitting and the transmit button text should be changed: qDebug(logSystem()) << "PTT status: " << pttOn; 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) { #ifdef QT_DEBUG qDebug(logSystem()) << "Spectrum received, but RigID incomplete."; #endif return; } if((startFreq != oldLowerFreq) || (endFreq != oldUpperFreq)) { // If the frequency changed and we were drawing peaks, now is the time to clearn them if(drawPeaks) { // TODO: create non-button function to do this // This will break if the button is ever moved or renamed. on_clearPeakBtn_clicked(); } } oldLowerFreq = startFreq; oldUpperFreq = endFreq; //qDebug(logSystem()) << "start: " << startFreq << " end: " << endFreq; quint16 specLen = spectrum.length(); //qDebug(logSystem()) << "Spectrum data received at UI! Length: " << specLen; //if( (specLen != 475) || (specLen!=689) ) if( specLen != rigCaps.spectLenMax ) { #ifdef QT_DEBUG qDebug(logSystem()) << "-------------------------------------------"; qDebug(logSystem()) << "------ Unusual spectrum received, length: " << specLen; qDebug(logSystem()) << "------ Expected spectrum length: " << rigCaps.spectLenMax; qDebug(logSystem()) << "------ This should happen once at most. "; #endif 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 spectrumPeaks.at(i)) { spectrumPeaks[i] = spectrum.at(i); } y2[i] = spectrumPeaks.at(i); } } //ui->qcp->addGraph(); plot->graph(0)->setData(x,y); if((freqMhz < endFreq) && (freqMhz > startFreq)) { // tracer->setGraphKey(freqMhz); tracer->setGraphKey(knobFreqMhz); } if(drawPeaks) { plot->graph(1)->setData(x,y2); // peaks } plot->yAxis->setRange(0, rigCaps.spectAmpMax+1); plot->xAxis->setRange(startFreq, endFreq); plot->replot(); if(specLen == spectWidth) { wfimage.prepend(spectrum); if(wfimage.length() > wfLength) { wfimage.remove(wfLength); } // Waterfall: for(int row = 0; row < wfLength; row++) { for(int col = 0; col < spectWidth; col++) { //colorMap->data()->cellToCoord(xIndex, yIndex, &x, &y) // Very fast but doesn't roll downward: //colorMap->data()->setCell( col, spectRowCurrent, spectrum.at(col) ); // Slow but rolls: colorMap->data()->setCell( col, row, wfimage.at(row).at(col)); } } //colorMap->data()->setRange(QCPRange(startFreq, endFreq), QCPRange(0,wfLength-1)); wf->yAxis->setRange(0,wfLength - 1); wf->xAxis->setRange(0, spectWidth-1); wf->replot(); spectRowCurrent = (spectRowCurrent + 1) % wfLength; //qDebug(logSystem()) << "updating spectrum, new row is: " << spectRowCurrent; } } void wfmain::receiveSpectrumFixedMode(bool isFixed) { ui->scopeCenterModeChk->blockSignals(true); ui->scopeCenterModeChk->setChecked(!isFixed); ui->scopeCenterModeChk->blockSignals(false); } void wfmain::handlePlotDoubleClick(QMouseEvent *me) { double x; //double y; //double px; x = plot->xAxis->pixelToCoord(me->pos().x()); //y = plot->yAxis->pixelToCoord(me->pos().y()); emit setFrequency(x); cmdOut = cmdGetFreq; delayedCommand->start(); showStatusBarText(QString("Going to %1 MHz").arg(x)); } void wfmain::handleWFDoubleClick(QMouseEvent *me) { double x; //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: x = plot->xAxis->pixelToCoord(me->pos().x()); emit setFrequency(x); cmdOut = cmdGetFreq; delayedCommand->start(); 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(); // TODO: Use other method, knob has too few positions to be useful for large steps. int steps = we->angleDelta().y() / 120; Qt::KeyboardModifiers key= we->modifiers(); if (key == Qt::ShiftModifier) { steps *=20; } else if (key == Qt::ControlModifier) { steps *=10; } ui->freqDial->setValue( ui->freqDial->value() + (steps)*ui->freqDial->singleStep() ); } void wfmain::handlePlotScroll(QWheelEvent *we) { int steps = we->angleDelta().y() / 120; Qt::KeyboardModifiers key= we->modifiers(); if (key == Qt::ShiftModifier) { // TODO: Zoom } else if (key == Qt::ControlModifier) { steps *=10; } ui->freqDial->setValue( ui->freqDial->value() + (steps)*ui->freqDial->singleStep() ); } void wfmain::on_scopeEnableWFBtn_clicked(bool checked) { if(checked) { emit spectOutputEnable(); } else { emit spectOutputDisable(); } } void wfmain::receiveMode(unsigned char mode, unsigned char filter) { //qDebug(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 { qDebug(logSystem()) << __func__ << "Invalid mode " << mode << " received. "; } if(!found) { qDebug(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: cmdOutQue.append(cmdGetDataMode); delayedCommand->start(); // why was that commented out? } 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() { bool ok = false; double freq = ui->freqMhzLineEdit->text().toDouble(&ok); if(ok) { emit setFrequency(freq); // TODO: change to cmdQueue cmdOut = cmdGetFreq; delayedCommand->start(); } 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_scopeCenterModeChk_clicked(bool checked) { emit setScopeCenterMode(checked); } 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, filter); 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 initated the change. unsigned char newMode = static_cast(ui->modeSelectCombo->itemData(index).toUInt()); currentModeIndex = newMode; int filterSelection = ui->modeFilterCombo->currentData().toInt(); if(filterSelection == 99) { // oops, we forgot to reset the combo box } else { qDebug(logSystem()) << __func__ << " at index " << index << " has newMode: " << newMode; emit setMode(newMode, filterSelection); } } void wfmain::on_freqDial_valueChanged(int value) { int maxVal = ui->freqDial->maximum(); double stepSize = 0.000100; // 100 Hz steps double newFreqMhz = 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; } // qDebug(logSystem()) << "Old value: " << oldFreqDialVal << " New value: " << value ; 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; // mnow 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; } newFreqMhz = knobFreqMhz + (delta * stepSize); // qDebug(logSystem()) << "old freq: " << knobFreqMhz << " new freq: " << newFreqMhz << "knobDelta: " << delta << " freq delta: " << newFreqMhz - knobFreqMhz; if(ui->tuningFloorZerosChk->isChecked()) { newFreqMhz = (double)round(newFreqMhz*10000) / 10000.0; } this->knobFreqMhz = newFreqMhz; // the frequency we think we should be on. oldFreqDialVal = value; ui->freqLabel->setText(QString("%1").arg(knobFreqMhz, 0, 'f')); this->freqMhz = knobFreqMhz; emit setFrequency(newFreqMhz); //emit getFrequency(); } void wfmain::receiveBandStackReg(float freq, char mode, bool dataOn) { // read the band stack and apply by sending out commands setFrequency(freq); int filterSelection = ui->modeFilterCombo->currentData().toInt(); setMode(mode, (unsigned char)filterSelection); // make sure this is what you think it is // setDataMode(dataOn); // signal out if(dataOn) { cmdOutQue.append(cmdSetDataModeOn); } else { cmdOutQue.append(cmdSetDataModeOff); } cmdOutQue.append(cmdGetFreq); cmdOutQue.append(cmdGetMode); ui->tabWidget->setCurrentIndex(0); delayedCommand->start(); } 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_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... setFrequency(5.3305); } void wfmain::on_band80mbtn_clicked() { bandStkBand = 0x02; // 80 meters bandStackBtnClick(); } void wfmain::on_band160mbtn_clicked() { bandStkBand = 0x01; // 160 meters bandStackBtnClick(); } void wfmain::on_bandGenbtn_clicked() { // "GENE" general coverage frequency outside the ham bands // which does probably include any 60 meter frequencies used. bandStkBand = 0x11; // GEN bandStackBtnClick(); } void wfmain::on_aboutBtn_clicked() { // Show..... // Build date, time, git checksum (short) // QT library version // stylesheet credit // contact information QMessageBox msgBox(this); msgBox.setWindowTitle("Abou wfview"); msgBox.setTextFormat(Qt::RichText); msgBox.setWindowIcon(QIcon(":resources/wfview.png")); // TODO: change style of link color based on current CSS sheet. QString head = QString(""); QString copyright = QString("Copyright 2017-2021 Elliott H. Liggett, W6EL. All rights reserved."); QString nacode = QString("

Networking and audio code written by Phil Taylor, M0VSE"); QString doctest = QString("

Testing, documentation, bug fixes, and development mentorship from Roeland Jansen, PA3MET, and Jim Nijkamp, PA8E."); QString ssCredit = QString("

Stylesheet qdarkstyle used under MIT license, stored in /usr/share/wfview/stylesheets/."); QString website = QString("

Get the latest version from our gitlab repo: https://gitlab.com/eliggett/wfview"); QString docs = QString("
Also see the wiki for the FAQ, Keystrokes, and more."); QString contact = QString("
email the author: kilocharlie8@gmail.com or W6EL on the air!"); QString buildInfo = QString("

Build " + QString(GITSHORT) + " on " + QString(__DATE__) + " at " + __TIME__ + " by " + UNAME + "@" + HOST); QString end = QString(""); QString aboutText = head + copyright + "\n" + nacode + "\n" + doctest + "\n" + ssCredit + "\n"; aboutText.append(website + "\n"+ docs + contact +"\n" + buildInfo + end); msgBox.setText(aboutText); msgBox.exec(); } 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; QString freqString; 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, freqMhz, (mode_kind)ui->modeSelectCombo->currentIndex()); showStatusBarText( QString("Storing frequency %1 to memory location %2").arg( freqMhz ).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); freqString = QString("%1").arg(temp.frequency); ui->freqMhzLineEdit->setText( freqString ); ui->goFreqBtn->click(); } else { qDebug(logSystem()) << "Could not recall preset. Valid presets are 0 through 99."; } } void wfmain::on_rfGainSlider_valueChanged(int value) { emit setRfGain((unsigned char) value); } void wfmain::on_afGainSlider_valueChanged(int value) { // qDebug(logSystem()) << "Setting AF gain to " << value; emit setAfGain((unsigned char) value); } void wfmain::receiveRfGain(unsigned char level) { // qDebug(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) { // qDebug(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::on_drawTracerChk_toggled(bool checked) { tracer->setVisible(checked); prefs.drawTracer = checked; } void wfmain::on_tuneNowBtn_clicked() { emit startATU(); showStatusBarText("Starting ATU tuning cycle..."); cmdOutQue.append(cmdGetATUStatus); delayedCommand->start(); } void wfmain::on_tuneEnableChk_clicked(bool checked) { emit setATU(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."); emit setPTT(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"); emit setPTT(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."); emit setPTT(false); issueDelayedCommand(cmdGetPTT); } void wfmain::on_saveSettingsBtn_clicked() { saveSettings(); // save memory, UI, and radio settings } void wfmain::receiveATUStatus(unsigned char atustatus) { // qDebug(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 // qDebug(logSystem()) << "Received ATU status update that *tuning* is taking place"; showStatusBarText("ATU is Tuning..."); cmdOutQue.append(cmdGetATUStatus); // Sometimes the first hit seems to be missed. cmdOutQue.append(cmdGetATUStatus); delayedCommand->start(); break; default: qDebug(logSystem()) << "Did not understand ATU status: " << (unsigned int) atustatus; break; } } void wfmain::on_pttEnableChk_clicked(bool checked) { prefs.enablePTT = checked; } void wfmain::on_lanEnableChk_clicked(bool checked) { prefs.enableLAN = checked; ui->ipAddressTxt->setEnabled(checked); ui->controlPortTxt->setEnabled(checked); ui->serialPortTxt->setEnabled(checked); ui->audioPortTxt->setEnabled(checked); ui->usernameTxt->setEnabled(checked); ui->passwordTxt->setEnabled(checked); if(checked) { showStatusBarText("After filling in values, press Save Settings and re-start wfview."); } } void wfmain::on_ipAddressTxt_textChanged(QString text) { prefs.ipAddress = text; } void wfmain::on_controlPortTxt_textChanged(QString text) { prefs.controlLANPort = text.toUInt(); } void wfmain::on_serialPortTxt_textChanged(QString text) { prefs.serialLANPort = text.toUInt(); } void wfmain::on_audioPortTxt_textChanged(QString text) { prefs.audioLANPort = text.toUInt(); } void wfmain::on_usernameTxt_textChanged(QString text) { prefs.username = text; } void wfmain::on_passwordTxt_textChanged(QString text) { prefs.password = text; } void wfmain::on_audioOutputCombo_currentIndexChanged(QString text) { prefs.audioOutput = text; } void wfmain::on_audioInputCombo_currentIndexChanged(QString text) { prefs.audioInput = text; } void wfmain::on_audioSampleRateCombo_currentIndexChanged(QString text) { prefs.audioRXSampleRate = text.toInt(); prefs.audioTXSampleRate = text.toInt(); } void wfmain::on_audioRXCodecCombo_currentIndexChanged(int value) { prefs.audioRXCodec = ui->audioRXCodecCombo->itemData(value).toInt(); } void wfmain::on_audioTXCodecCombo_currentIndexChanged(int value) { prefs.audioTXCodec = ui->audioTXCodecCombo->itemData(value).toInt(); } void wfmain::on_audioBufferSizeSlider_valueChanged(int value) { prefs.audioRXBufferSize = value; ui->bufferValue->setText(QString::number(value)); emit sendChangeBufferSize(value); } void wfmain::on_toFixedBtn_clicked() { emit setScopeFixedEdge(oldLowerFreq, oldUpperFreq, ui->scopeEdgeCombo->currentIndex()+1); emit setScopeEdge(ui->scopeEdgeCombo->currentIndex()+1); cmdOutQue.append(cmdScopeFixedMode); delayedCommand->start(); } void wfmain::on_connectBtn_clicked() { this->rigStatus->setText(""); // Clear status if (haveRigCaps) { emit sendCloseComm(); ui->connectBtn->setText("Connect"); haveRigCaps = false; } else { emit sendCloseComm(); // Just in case there is a failed connection open. openRig(); } } void wfmain::on_udpServerSetupBtn_clicked() { srv->show(); } void wfmain::on_sqlSlider_valueChanged(int value) { emit setSql((unsigned char)value); } 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 emit setMode(newMode, (unsigned char)filterSelection); } } void wfmain::on_dataModeBtn_toggled(bool checked) { setDataMode(checked); 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."); emit setPTT(true); // send PTT // Start 3 minute timer pttTimer->start(); issueDelayedCommand(cmdGetPTT); //changeTxBtn(); } else { // Currently transmitting emit setPTT(false); pttTimer->stop(); issueDelayedCommand(cmdGetPTT); } } void wfmain::on_adjRefBtn_clicked() { cal->show(); } void wfmain::on_satOpsBtn_clicked() { sat->show(); } void wfmain::changeSliderQuietly(QSlider *slider, int value) { slider->blockSignals(true); slider->setValue(value); slider->blockSignals(false); } 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) qDebug(logSystem()) << "Could not find modulation input: " << (int)input; } void wfmain::receiveDuplexMode(duplexMode dm) { switch(dm) { case dmSimplex: ui->rptSimplexBtn->setChecked(true); break; case dmDupPlus: ui->rptDupPlusBtn->setChecked(true); break; case dmDupMinus: ui->rptDupMinusBtn->setChecked(true); break; default: break; } (void)dm; } 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->levelIndicator->setValue((int)level); break; case meterSWR: //ui->levelIndicator->setValue((int)level); break; case meterPower: ui->levelIndicator->setValue((int)level); break; case meterALC: //ui->levelIndicator->setValue((int)level); break; case meterComp: //ui->levelIndicator->setValue((int)level); break; case meterCurrent: //ui->levelIndicator->setValue((int)level); break; case meterVoltage: //ui->levelIndicator->setValue((int)level); break; default: 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) { 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); } // Slot to send/receive server config. // If store is true then write to config otherwise send current config by signal void wfmain::serverConfigRequested(SERVERCONFIG conf, bool store) { if (!store) { emit sendServerConfig(serverConfig); } else { // Store config in file! qDebug(logSystem()) << "Storing server config"; serverConfig = conf; } } void wfmain::on_rptDupPlusBtn_clicked() { // DUP+ emit setDuplexMode(dmDupAutoOff); emit setDuplexMode(dmDupPlus); } void wfmain::on_rptSimplexBtn_clicked() { // Simplex emit setDuplexMode(dmDupAutoOff); emit setDuplexMode(dmSimplex); } void wfmain::on_rptDupMinusBtn_clicked() { // DUP- emit setDuplexMode(dmDupAutoOff); emit setDuplexMode(dmDupMinus); } void wfmain::on_rptAutoBtn_clicked() { // Auto Rptr (enable this feature) // TODO: Hide an AutoOff button somewhere for non-US users emit setDuplexMode(dmDupAutoOn); } 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. rigInput currentIn; if(usingDataMode) { currentIn = currentModDataSrc; } else { currentIn = currentModSrc; } //qDebug(logSystem()) << __func__ << ": setting current level: " << level; emit setModLevel(currentIn, level); } void wfmain::on_tuneLockChk_clicked(bool checked) { freqLock = checked; } // --- DEBUG FUNCTION --- void wfmain::on_debugBtn_clicked() { qDebug(logSystem()) << "Debug button pressed."; // TODO: Why don't these commands work?! //emit getScopeMode(); //emit getScopeEdge(); // 1,2,3 only in "fixed" mode //emit getScopeSpan(); // in khz, only in "center" mode // emit getLevels(); // emit getMeters(amTransmitting); // emit getTSQL(); }