diff --git a/commhandler.cpp b/commhandler.cpp index 6802066..c681a41 100644 --- a/commhandler.cpp +++ b/commhandler.cpp @@ -115,7 +115,7 @@ void commHandler::receiveDataIn() } } else { // did not receive the entire thing so roll back: - qDebug() << "Rolling back transaction. End not detected. Lenth: " << inPortData.length(); + // qDebug() << "Rolling back transaction. End not detected. Lenth: " << inPortData.length(); //printHex(inPortData, false, true); port->rollbackTransaction(); rolledBack = true; diff --git a/freqmemory.cpp b/freqmemory.cpp index 08c7858..eec8780 100644 --- a/freqmemory.cpp +++ b/freqmemory.cpp @@ -2,5 +2,62 @@ freqMemory::freqMemory() { + // NOTE: These are also present in the header and + // the array must be changed if these are changed. + numPresets = 100; + maxIndex = numPresets - 1; + initializePresets(); } + +void freqMemory::initializePresets() +{ + qDebug() << "Initializing " << numPresets << " memory channels"; + + for(unsigned int p=0; p < numPresets; p++) + { + presets[p].frequency = 14.1 + p/1000.0; + presets[p].mode = modeUSB; + presets[p].isSet = true; + } +} + +void freqMemory::setPreset(unsigned int index, double frequency, mode_kind mode) +{ + if(index <= maxIndex) + { + presets[index].frequency = frequency; + presets[index].mode = mode; + presets[index].isSet = true; + } +} + +preset_kind freqMemory::getPreset(unsigned int index) +{ + //validate then return + + if(index <= maxIndex) + { + return presets[index]; + } + + // else, return something obviously wrong + preset_kind temp; + temp.frequency=12.345; + temp.mode = modeUSB; + temp.isSet = false; + return temp; +} + +unsigned int freqMemory::getNumPresets() +{ + return numPresets; +} + +void freqMemory::dumpMemory() +{ + for(unsigned int p=0; p < numPresets; p++) + { + qDebug() << "Index: " << p << " freq: " << presets[p].frequency << " Mode: " << presets[p].mode << " isSet: " << presets[p].isSet; + } +} diff --git a/freqmemory.h b/freqmemory.h index c1178c4..f6caf53 100644 --- a/freqmemory.h +++ b/freqmemory.h @@ -22,9 +22,9 @@ enum mode_kind { }; struct preset_kind { - QString name; - QString comment; - unsigned int index; // channel number + // QString name; + // QString comment; + // unsigned int index; // channel number double frequency; mode_kind mode; bool isSet; @@ -37,12 +37,17 @@ public: void setPreset(unsigned int index, double frequency, mode_kind mode); void setPreset(unsigned int index, double frequency, mode_kind mode, QString name); void setPreset(unsigned int index, double frequency, mode_kind mode, QString name, QString comment); - + void dumpMemory(); + unsigned int getNumPresets(); preset_kind getPreset(unsigned int index); private: void initializePresets(); + unsigned int numPresets; unsigned int maxIndex; + //QVector presets; + preset_kind presets[100]; + }; #endif // FREQMEMORY_H diff --git a/main.cpp b/main.cpp index b20814f..8f1f05a 100644 --- a/main.cpp +++ b/main.cpp @@ -9,6 +9,11 @@ int main(int argc, char *argv[]) QApplication a(argc, argv); //a.setStyle( "Fusion" ); + + a.setOrganizationName("liggett"); + a.setOrganizationDomain("nodomain"); + a.setApplicationName("RigView"); + wfmain w; w.show(); diff --git a/rigcommander.cpp b/rigcommander.cpp index fb47e31..6c6ca30 100644 --- a/rigcommander.cpp +++ b/rigcommander.cpp @@ -1,6 +1,8 @@ #include "rigcommander.h" #include +#include "rigidentities.h" + // Copytight 2017,2018 Elliott H. Liggett // This file parses data from the radio and also forms commands to the radio. @@ -358,7 +360,7 @@ void rigCommander::parseData(QByteArray dataInput) if(data.length()) { // Finally this almost never happens - qDebug() << "Data length too short: " << data.length() << " bytes. Data:"; + // qDebug() << "Data length too short: " << data.length() << " bytes. Data:"; printHex(data, false, true); } // no @@ -369,14 +371,14 @@ void rigCommander::parseData(QByteArray dataInput) if(!data.startsWith("\xFE\xFE")) { - qDebug() << "Warning: Invalid data received, did not start with FE FE."; + // qDebug() << "Warning: Invalid data received, did not start with FE FE."; // find 94 e0 and shift over, // or look inside for a second FE FE // Often a local echo will miss a few bytes at the beginning. if(data.startsWith('\xFE')) { data.prepend('\xFE'); - qDebug() << "Warning: Working with prepended data stream."; + // qDebug() << "Warning: Working with prepended data stream."; parseData(payloadIn); return; } else { @@ -475,9 +477,9 @@ void rigCommander::parseCommand() parseLevels(); break; case '\x19': - // qDebug() << "Have rig ID: " << (int)payloadIn[2]; + // qDebug() << "Have rig ID: " << (unsigned int)payloadIn[2]; // printHex(payloadIn, false, true); - // This returns the CIV address of the radio. (94 by default) + model = determineRadioModel(payloadIn[2]); break; case '\x27': // scope data diff --git a/rigcommander.h b/rigcommander.h index 2aff6f2..c4332e7 100644 --- a/rigcommander.h +++ b/rigcommander.h @@ -4,6 +4,7 @@ #include #include "commhandler.h" +#include "rigidentities.h" // This file figures out what to send to the comm and also // parses returns into useful things. @@ -109,6 +110,7 @@ private: double spectrumStartFreq; double spectrumEndFreq; + model_kind model; double frequencyMhz; unsigned char civAddr; // 0x94 is default = 148decimal diff --git a/rigidentities.cpp b/rigidentities.cpp new file mode 100644 index 0000000..a09e347 --- /dev/null +++ b/rigidentities.cpp @@ -0,0 +1,40 @@ +#include "rigidentities.h" + +model_kind determineRadioModel(unsigned char rigID) +{ + + model_kind rig; + + switch(rigID) + { + case model7100: + rig = model7100; + break; + case model7200: + rig = model7200; + break; + case model7300: + rig = model7300; + break; + case model7600: + rig = model7600; + break; + case model7610: + rig = model7610; + break; + case model7700: + rig = model7700; + break; + case model7800: + rig = model7800; + break; + case model7850: + rig = model7850; + break; + default: + rig = modelUnknown; + break; + } + + return rig; +} diff --git a/rigidentities.h b/rigidentities.h new file mode 100644 index 0000000..c67c7d1 --- /dev/null +++ b/rigidentities.h @@ -0,0 +1,26 @@ +#ifndef RIGIDENTITIES_H +#define RIGIDENTITIES_H + +// Credit: +// http://www.docksideradio.com/Icom%20Radio%20Hex%20Addresses.htm + +// 7850 and 7851 have the same commands and are essentially identical + +enum model_kind { + model7100 = 0x88, + model7200 = 0x76, + model7300 = 0x94, + model7600 = 0x7A, + model7610 = 0x98, + model7700 = 0x74, + model7800 = 0x6A, + model7850 = 0x8E, + modelUnknown = 0xFF +}; + + +model_kind determineRadioModel(unsigned char rigID); + + + +#endif // RIGIDENTITIES_H diff --git a/wfmain.cpp b/wfmain.cpp index a5ee4e6..89d98a8 100644 --- a/wfmain.cpp +++ b/wfmain.cpp @@ -2,6 +2,7 @@ #include "ui_wfmain.h" #include "commhandler.h" +#include "rigidentities.h" wfmain::wfmain(QWidget *parent) : QMainWindow(parent), @@ -161,19 +162,79 @@ wfmain::~wfmain() delete ui; } +void wfmain::loadSettings() +{ + qDebug() << "Loading settings from " << settings.fileName(); + + // Basic things to load: + + // UI: (full screen, dark theme, draw peaks, colors, etc) + + // Radio and Comms: C-IV addr, port to use + + // Misc. user settings (enable PTT, draw peaks, etc) + + // Memory channels +} + +void wfmain::saveSettings() +{ + qDebug() << "Saving settings to " << settings.fileName(); + // Basic things to load: + + // UI: (full screen, dark theme, draw peaks, colors, etc) + settings.beginGroup("Interface"); + settings.setValue("UseFullScreen", true); + settings.setValue("UseDarkMode", true); + settings.setValue("DrawPeaks", true); + settings.endGroup(); + + // Radio and Comms: C-IV addr, port to use + settings.beginGroup("Radio"); + settings.setValue("RigCIVuInt", 0x94); + settings.setValue("SerialPortRadio", "/dev/ttyUSB0"); + settings.endGroup(); + + // Misc. user settings (enable PTT, draw peaks, etc) + settings.beginGroup("Controls"); + settings.setValue("EnablePTT", true); + settings.setValue("NiceTS", true); + 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("freq", temp.frequency); + settings.setValue("mode", temp.mode); + } + + settings.endArray(); + settings.endGroup(); + + settings.sync(); // Automatic, not needed (supposedly) +} + + void wfmain::getInitialRigState() { - // Things to get: - // Freq, Mode, Scope cent/fixed, scope span, edge setting - // data mode (may be combined with scope mode) + // 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 100ms. Faster is possible but slower + // computers will glitch occassionally. - cmdOutQue.append(cmdGetRigID); + cmdOutQue.append(cmdGetRigID); // This may be used in the future. cmdOutQue.append(cmdGetFreq); cmdOutQue.append(cmdGetMode); - cmdOutQue.append(cmdDispEnable); - cmdOutQue.append(cmdSpecOn); + cmdOutQue.append(cmdNone); cmdOutQue.append(cmdGetFreq); cmdOutQue.append(cmdGetMode); @@ -181,6 +242,14 @@ void wfmain::getInitialRigState() cmdOutQue.append(cmdGetRxGain); cmdOutQue.append(cmdGetAfGain); cmdOutQue.append(cmdGetSql); + // get TX level + // get Scope reference Level + + cmdOutQue.append(cmdDispEnable); + cmdOutQue.append(cmdSpecOn); + + // get spectrum mode (center or edge) + // get spectrum span or edge limit number [1,2,3], update UI cmdOut = cmdNone; delayedCommand->start(); @@ -509,7 +578,6 @@ void wfmain::handleWFClick(QMouseEvent *me) void wfmain::on_startBtn_clicked() { - //emit scopeDisplayEnable(); // TODO: need a little delay between these two emit spectOutputEnable(); } @@ -530,12 +598,18 @@ void wfmain::on_debugBtn_clicked() // emit getBandStackReg(0x11,1); // 20M, latest // emit getRfGain(); - for(int a=0; a<100; a++) - { - cmdOutQue.append(cmdGetRxGain); - cmdOutQue.append(cmdGetSql); - } - delayedCommand->start(); +// for(int a=0; a<100; a++) +// { +// cmdOutQue.append(cmdGetRxGain); +// cmdOutQue.append(cmdGetSql); +// } +// delayedCommand->start(); + + // emit getRigID(); + + //mem.dumpMemory(); + + saveSettings(); } @@ -554,9 +628,10 @@ void wfmain::receiveMode(QString mode) if( currentModeIndex == index) { // do nothing, no need to change the selected mode and fire more events off. - return; - } - if((index >= 0) && (index < 9)) + // TODO/NOTE: This will not check the DATA mode status, may be worth re-thinking this. + // Do not update UI. + // return; + } else if((index >= 0) && (index < 9)) { ui->modeSelectCombo->setCurrentIndex(index); currentModeIndex = index; @@ -576,12 +651,19 @@ void wfmain::receiveDataModeStatus(bool dataEnabled) { // USB ui->modeSelectCombo->setCurrentIndex(8); + ui->modeLabel->setText( "USB-D" ); + } else if (currentModeIndex == 1) { // LSB ui->modeSelectCombo->setCurrentIndex(9); + ui->modeLabel->setText( "LSB-D" ); + } - ui->modeLabel->setText( ui->modeLabel->text() + "-D" ); + // TODO: be more intelligent here to avoid -D-D-D. + // include the text above. + // ui->modeLabel->setText( ui->modeLabel->text() + "-D" ); + // Remove if works. } } @@ -613,8 +695,6 @@ void wfmain::on_fullScreenChk_clicked(bool checked) this->showFullScreen(); else this->showNormal(); - - } void wfmain::on_goFreqBtn_clicked() @@ -624,6 +704,7 @@ void wfmain::on_goFreqBtn_clicked() if(ok) { emit setFrequency(freq); + // TODO: change to cmdQueue cmdOut = cmdGetFreq; delayedCommand->start(); } @@ -729,6 +810,9 @@ void wfmain::on_scopeCenterModeChk_clicked(bool 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(); } @@ -1009,9 +1093,22 @@ void wfmain::on_fStoBtn_clicked() // type frequency // press Enter or Go // change mode if desired + // type in index number 0 through 99 // press STO - // type memory location 0 through 99 - // press Enter + + 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()); + } else { + qDebug() << "Could not store preset. Valid presets are 0 through 99."; + } + + } void wfmain::on_fRclBtn_clicked() @@ -1024,6 +1121,22 @@ void wfmain::on_fRclBtn_clicked() // 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() << "Could not recall preset. Valid presets are 0 through 99."; + } + } void wfmain::on_rfGainSlider_valueChanged(int value) @@ -1065,6 +1178,8 @@ void wfmain::on_tuneNowBtn_clicked() { emit startATU(); showStatusBarText("Starting ATU cycle..."); + // TODO: place commands in a timer queue to check for completion and success + } void wfmain::on_tuneEnableChk_clicked(bool checked) @@ -1083,3 +1198,21 @@ void wfmain::on_exitBtn_clicked() // Are you sure? QApplication::exit(); } + +void wfmain::on_pttOnBtn_clicked() +{ + // is it enabled? + + // Are we already PTT? + + // send PTT + // Start 3 minute timer +} + +void wfmain::on_pttOffBtn_clicked() +{ + // Send the PTT OFF command (more than once?) + + // Stop the 3 min tumer + +} diff --git a/wfmain.h b/wfmain.h index 1d8e071..aa5bcc2 100644 --- a/wfmain.h +++ b/wfmain.h @@ -6,12 +6,14 @@ #include #include #include +#include #include "commhandler.h" #include "rigcommander.h" +#include "freqmemory.h" #include -#include +#include namespace Ui { class wfmain; @@ -168,8 +170,15 @@ private slots: void on_exitBtn_clicked(); + void on_pttOnBtn_clicked(); + + void on_pttOffBtn_clicked(); + private: Ui::wfmain *ui; + QSettings settings; + void loadSettings(); + void saveSettings(); QCustomPlot *plot; // line plot QCustomPlot *wf; // waterfall image QCPItemTracer * tracer; // marker of current frequency @@ -215,6 +224,8 @@ private: cmdGetSql}; cmds cmdOut; QVector cmdOutQue; + freqMemory mem; + int oldFreqDialVal; void bandStackBtnClick(); diff --git a/wfmain.ui b/wfmain.ui index 54bb082..cc9496f 100644 --- a/wfmain.ui +++ b/wfmain.ui @@ -457,6 +457,9 @@ 30M + + 3 + @@ -704,6 +707,9 @@ 30 + + <html><head/><body><p>To recall a preset memory:</p><p>1. Type in the preset number (0 through 99)</p><p>2. Press RCL (or use hotkey &quot;R&quot;)</p></body></html> + &RCL @@ -817,6 +823,9 @@ 30 + + <html><head/><body><p>To store a preset:</p><p>1. Set the desired frequency and mode per normal methods</p><p>2. Type the index to to store to (0 through 99)</p><p>3. Press STO (or use hotkey &quot;S&quot;)</p></body></html> + &STO diff --git a/wfview.pro b/wfview.pro index 06d17c0..ce16670 100644 --- a/wfview.pro +++ b/wfview.pro @@ -45,12 +45,14 @@ SOURCES += main.cpp\ wfmain.cpp \ commhandler.cpp \ rigcommander.cpp \ - freqmemory.cpp + freqmemory.cpp \ + rigidentities.cpp HEADERS += wfmain.h \ ../../../../../usr/include/qcustomplot.h \ commhandler.h \ rigcommander.h \ - freqmemory.h + freqmemory.h \ + rigidentities.h FORMS += wfmain.ui