diff --git a/commhandler.cpp b/commhandler.cpp index 868dda9..7582630 100644 --- a/commhandler.cpp +++ b/commhandler.cpp @@ -131,6 +131,7 @@ commHandler::~commHandler() void commHandler::setupComm() { + serialError = false; port->setPortName(portName); port->setBaudRate(baudrate); port->setStopBits(QSerialPort::OneStop);// OneStop is other option @@ -264,6 +265,8 @@ void commHandler::openPort() // debug? qDebug() << "Could not open serial port " << portName << " , please restart."; isConnected = false; + serialError = true; + emit haveSerialPortError(portName, "Could not open port. Please restart."); return; } diff --git a/commhandler.h b/commhandler.h index 7b46755..cc4b273 100644 --- a/commhandler.h +++ b/commhandler.h @@ -17,6 +17,7 @@ class commHandler : public QObject public: commHandler(); commHandler(QString portName, quint32 baudRate); + bool serialError; ~commHandler(); @@ -30,6 +31,7 @@ signals: void haveTextMessage(QString message); // status, debug only void sendDataOutToPort(const QByteArray &writeData); // not used void haveDataFromPort(QByteArray data); // emit this when we have data, connect to rigcommander + void haveSerialPortError(const QString port, const QString error); private: void setupComm(); diff --git a/main.cpp b/main.cpp index b99b064..56e8320 100644 --- a/main.cpp +++ b/main.cpp @@ -1,7 +1,8 @@ #include "wfmain.h" #include +#include -// Copytight 2017-2020 Elliott H. Liggett +// Copytight 2017-2021 Elliott H. Liggett int main(int argc, char *argv[]) @@ -9,14 +10,70 @@ int main(int argc, char *argv[]) QApplication a(argc, argv); //a.setStyle( "Fusion" ); - a.setOrganizationName("eliggett"); a.setOrganizationDomain("nodomain"); a.setApplicationName("wfview"); + + + QString serialPortCL; + QString hostCL; + QString civCL; + + QString currentArg; + + const QString helpText = QString("Usage: -p --port /dev/port, -h --host remotehostname, -c --civ 0xAddr"); // TODO... + + for(int c=1; c c) + { + serialPortCL = argv[c+1]; + c+=1; + } + } else if ((currentArg == "-h") || (currentArg == "--host")) + { + if(argc > c) + { + hostCL = argv[c+1]; + c+=1; + } + } else if ((currentArg == "-c") || (currentArg == "--civ")) + { + if(argc > c) + { + civCL = argv[c+1]; + c+=1; + } + } else if ((currentArg == "--help")) + { + std::cout << helpText.toStdString(); + return 0; + } else { + std::cout << "Unrecognized option: " << currentArg.toStdString(); + std::cout << helpText.toStdString(); + return -1; + } + + } + + +#ifdef QT_DEBUG + qDebug() << "SerialPortCL as set by parser: " << serialPortCL; + qDebug() << "remote host as set by parser: " << hostCL; + qDebug() << "CIV as set by parser: " << civCL; +#endif a.setWheelScrollLines(1); // one line per wheel click - wfmain w; + wfmain w( serialPortCL, hostCL); + w.show(); + + return a.exec(); } diff --git a/rigcommander.cpp b/rigcommander.cpp index a85651f..2d540c3 100644 --- a/rigcommander.cpp +++ b/rigcommander.cpp @@ -58,6 +58,7 @@ rigCommander::rigCommander(unsigned char rigCivAddr, QString rigSerialPort, quin // lrwxrwxrwx 1 root root 13 Nov 24 21:43 pci-0000:00:12.0-usb-0:2.1:1.0-port0 -> ../../ttyUSB0 // comm = new commHandler("/dev/ttyUSB0"); + this->rigSerialPort = rigSerialPort; comm = new commHandler(rigSerialPort, rigBaudRate); // data from the comm port to the program: @@ -66,8 +67,11 @@ rigCommander::rigCommander(unsigned char rigCivAddr, QString rigSerialPort, quin // data from the program to the comm port: connect(this, SIGNAL(dataForComm(QByteArray)), comm, SLOT(receiveDataFromUserToRig(QByteArray))); + connect(comm, SIGNAL(haveSerialPortError(QString,QString)), this, SLOT(handleSerialPortError(QString,QString))); + connect(this, SIGNAL(getMoreDebug()), comm, SLOT(debugThis())); pttAllowed = true; // This is for developing, set to false for "safe" debugging. Set to true for deployment. + } rigCommander::~rigCommander() @@ -77,7 +81,17 @@ rigCommander::~rigCommander() void rigCommander::process() { - // new thread enters here. Do nothing. + // new thread enters here. Do nothing but do check for errors. + if(comm->serialError) + { + emit haveSerialPortError(rigSerialPort, QString("Error from commhandler. Check serial port.")); + } +} + +void rigCommander::handleSerialPortError(const QString port, const QString errorText) +{ + qDebug() << "Error using port " << port << " message: " << errorText; + emit haveSerialPortError(port, errorText); } void rigCommander::findRigs() @@ -469,7 +483,7 @@ void rigCommander::parseData(QByteArray dataInput) //return; } - incommingCIVAddr = data[03]; // track the CIV of the sender. + incomingCIVAddr = data[03]; // track the CIV of the sender. switch(data[02]) { // case civAddr: // can't have a variable here :-( @@ -888,10 +902,11 @@ void rigCommander::determineRigCaps() rigCaps.model = model; rigCaps.modelID = model; // may delete later - rigCaps.civ = incommingCIVAddr; + rigCaps.civ = incomingCIVAddr; switch(model){ case model7300: + rigCaps.modelName = QString("IC-7300"); rigCaps.hasSpectrum = true; rigCaps.spectSeqMax = 11; rigCaps.spectAmpMax = 160; @@ -901,6 +916,7 @@ void rigCommander::determineRigCaps() rigCaps.hasWiFi = false; break; case model9700: + rigCaps.modelName = QString("IC-9700"); rigCaps.hasSpectrum = true; rigCaps.spectSeqMax = 11; rigCaps.spectAmpMax = 160; @@ -910,6 +926,7 @@ void rigCommander::determineRigCaps() rigCaps.hasWiFi = false; break; case model7610: + rigCaps.modelName = QString("IC-7610"); rigCaps.hasSpectrum = true; rigCaps.spectSeqMax = 15; rigCaps.spectAmpMax = 200; @@ -919,6 +936,7 @@ void rigCommander::determineRigCaps() rigCaps.hasWiFi = false; break; case model7850: + rigCaps.modelName = QString("IC-785x"); rigCaps.hasSpectrum = true; rigCaps.spectSeqMax = 15; rigCaps.spectAmpMax = 136; @@ -928,6 +946,7 @@ void rigCommander::determineRigCaps() rigCaps.hasWiFi = false; break; case model705: + rigCaps.modelName = QString("IC-705"); rigCaps.hasSpectrum = true; rigCaps.spectSeqMax = 11; rigCaps.spectAmpMax = 160; @@ -937,6 +956,7 @@ void rigCommander::determineRigCaps() rigCaps.hasWiFi = true; break; default: + rigCaps.modelName = QString("IC-unknown"); rigCaps.hasSpectrum = false; rigCaps.spectSeqMax = 0; rigCaps.spectAmpMax = 0; @@ -952,14 +972,16 @@ void rigCommander::determineRigCaps() { lookingForRig = false; foundRig = true; +#ifdef QT_DEBUG qDebug() << "---Rig FOUND from broadcast query:"; - this->civAddr = incommingCIVAddr; // Override and use immediately. +#endif + this->civAddr = incomingCIVAddr; // Override and use immediately. payloadPrefix = QByteArray("\xFE\xFE"); payloadPrefix.append(civAddr); payloadPrefix.append(compCivAddr); - // if there is a compile-time error, remove the hex printout prefix from below . - qDebug() << "Using incommingCIVAddr: (int): " << this->civAddr << " hex: " << hex << this->civAddr; + // if there is a compile-time error, remove the following line, the "hex" part is the issue: + qDebug() << "Using incomingCIVAddr: (int): " << this->civAddr << " hex: " << hex << this->civAddr; emit discoveredRigID(rigCaps); } else { emit haveRigID(rigCaps); @@ -970,7 +992,9 @@ void rigCommander::parseSpectrum() { if(!haveRigCaps) { +#ifdef QT_DEBUG qDebug() << "Spectrum received in rigCommander, but rigID is incomplete."; +#endif return; } if(rigCaps.spectSeqMax == 0) @@ -1014,6 +1038,14 @@ void rigCommander::parseSpectrum() unsigned char sequence = bcdHexToDecimal(payloadIn[03]); //unsigned char sequenceMax = bcdHexToDecimal(payloadIn[04]); unsigned char scopeMode = bcdHexToDecimal(payloadIn[05]); + + if(scopeMode != oldScopeMode) + { + //TODO: + // emit haveNewScopeMode(scopeMode); + oldScopeMode = scopeMode; + } + // unsigned char waveInfo = payloadIn[06]; // really just one byte? //qDebug() << "Spectrum Data received: " << sequence << "/" << sequenceMax << " mode: " << scopeMode << " waveInfo: " << waveInfo << " length: " << payloadIn.length(); @@ -1146,6 +1178,9 @@ void rigCommander::parseMode() // USB: //"INDEX: 00 01 02 03 " //"DATA: 01 01 02 fd " + + //TODO: D-Star DV and DD modes. + switch(payloadIn[01]) { case '\x00': diff --git a/rigcommander.h b/rigcommander.h index 0b9e424..069bb81 100644 --- a/rigcommander.h +++ b/rigcommander.h @@ -59,6 +59,7 @@ public slots: void findRigs(); void setCIVAddr(unsigned char civAddr); void handleNewData(const QByteArray &data); + void handleSerialPortError(const QString port, const QString errorText); void sayFrequency(); void sayMode(); void sayAll(); @@ -68,6 +69,7 @@ signals: void haveSpectrumData(QByteArray spectrum, double startFreq, double endFreq); // pass along data to UI void haveRigID(rigCapabilities rigCaps); void discoveredRigID(rigCapabilities rigCaps); + void haveSerialPortError(const QString port, const QString errorText); void haveFrequency(double frequencyMhz); void haveMode(QString mode); void haveDataMode(bool dataModeEnabled); @@ -132,6 +134,7 @@ private: quint8 spectSeqMax; quint16 spectAmpMax; quint16 spectLenMax; + unsigned char oldScopeMode; bool usingNativeLAN; // indicates using OEM LAN connection (705,7610,9700,7850) bool lookingForRig; @@ -139,10 +142,12 @@ private: double frequencyMhz; unsigned char civAddr; // IC-7300: 0x94 is default = 148decimal - unsigned char incommingCIVAddr; // place to store the incoming CIV. + unsigned char incomingCIVAddr; // place to store the incoming CIV. //const unsigned char compCivAddr = 0xE1; // 0xE1 is new default, 0xE0 was before. bool pttAllowed; + QString rigSerialPort; + QString serialPortError; }; diff --git a/rigidentities.h b/rigidentities.h index 1cbc510..c26325e 100644 --- a/rigidentities.h +++ b/rigidentities.h @@ -2,6 +2,7 @@ #define RIGIDENTITIES_H #include +#include // Credit: // http://www.docksideradio.com/Icom%20Radio%20Hex%20Addresses.htm @@ -31,6 +32,8 @@ struct rigCapabilities { quint8 civ; quint8 modelID; + QString modelName; + bool hasLan; // OEM ethernet or wifi connection bool hasEthernet; bool hasWiFi; diff --git a/wfmain.cpp b/wfmain.cpp index fbbe6fa..88f2d6a 100644 --- a/wfmain.cpp +++ b/wfmain.cpp @@ -7,7 +7,7 @@ // This code is copyright 2017-2020 Elliott H. Liggett // All rights reserved -wfmain::wfmain(QWidget *parent) : +wfmain::wfmain(const QString serialPortCL, const QString hostCL, QWidget *parent ) : QMainWindow(parent), ui(new Ui::wfmain) { @@ -20,6 +20,9 @@ wfmain::wfmain(QWidget *parent) : setWindowTitle(QString("wfview")); + this->serialPortCL = serialPortCL; + this->hostCL = hostCL; + haveRigCaps = false; ui->bandStkLastUsedBtn->setVisible(false); @@ -216,7 +219,7 @@ wfmain::wfmain(QWidget *parent) : ui->afGainSlider->setSingleStep(100); - ui->statusBar->showMessage("Almost ready", 2000); + ui->statusBar->showMessage("Connecting to rig...", 1000); delayedCommand = new QTimer(this); delayedCommand->setInterval(250); // 250ms until we find rig civ and id, then 100ms. @@ -225,15 +228,6 @@ wfmain::wfmain(QWidget *parent) : openRig(); -// rig = new rigCommander(prefs.radioCIVAddr, serialPortRig, prefs.serialPortBaud); - -// rigThread = new QThread(this); - -// rig->moveToThread(rigThread); -// connect(rigThread, SIGNAL(started()), rig, SLOT(process())); -// connect(rig, SIGNAL(finished()), rigThread, SLOT(quit())); -// rigThread->start(); - qRegisterMetaType(); connect(rig, SIGNAL(haveFrequency(double)), this, SLOT(receiveFreq(double))); @@ -306,20 +300,7 @@ wfmain::wfmain(QWidget *parent) : wf->addPlottable(colorMap); #endif - //TRY moving to prepareWf(): - colorScale = new QCPColorScale(wf); -// colorMap->data()->setValueRange(QCPRange(0, wfLength-1)); -// colorMap->data()->setKeyRange(QCPRange(0, spectWidth-1)); -// colorMap->setDataRange(QCPRange(0, 160)); -// 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); - - // end TRY ui->tabWidget->setCurrentIndex(0); @@ -332,10 +313,7 @@ wfmain::wfmain(QWidget *parent) : ui->freqMhzLineEdit->setValidator( new QDoubleValidator(0, 100, 6, this)); -// delayedCommand = new QTimer(this); -// delayedCommand->setInterval(100); // ms. 250 was fine. TODO: Find practical maximum with margin on pi -// delayedCommand->setSingleShot(true); -// connect(delayedCommand, SIGNAL(timeout()), this, SLOT(runDelayedCommand())); +; pttTimer = new QTimer(this); pttTimer->setInterval(180*1000); // 3 minute max transmit time in ms @@ -398,29 +376,68 @@ void wfmain::openRig() // TODO: How do we know if the setting was loaded? - if(prefs.serialPortRadio == QString("auto")) + // TODO: Use these if they are found +#ifdef QT_DEBUG + if(!serialPortCL.isEmpty()) { - // Find the ICOM IC-7300. - qDebug() << "Searching for serial port..."; - QDirIterator it("/dev/serial", QStringList() << "*IC-7300*", QDir::Files, QDirIterator::Subdirectories); - QDirIterator it97("/dev/serial", QStringList() << "*IC-9700*", QDir::Files, QDirIterator::Subdirectories); - - while (it.hasNext()) - qDebug() << it.next(); - while(it97.hasNext()) - qDebug() << it97.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() << "Cannot find IC-7300 serial port. Trying /dev/ttyUSB0"; - serialPortRig = QString("/dev/ttyUSB0"); - } - // end finding the 7300 code + qDebug() << "Serial port specified by user: " << serialPortCL; } else { - serialPortRig = prefs.serialPortRadio; + qDebug() << "Serial port not specified. "; + } + + if(!hostCL.isEmpty()) + { + qDebug() << "Remote host name specified by user: " << hostCL; + } +#endif + + if( (prefs.serialPortRadio == QString("auto")) && (serialPortCL.isEmpty())) + { + // Find the ICOM + // qDebug() << "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() << "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_UNIX + serialPortRig = QString("/dev/ttyUSB0"); +#endif + } + + } else { + if(serialPortCL.isEmpty()) + { + serialPortRig = prefs.serialPortRadio; + } else { + serialPortRig = serialPortCL; + } } // Here, the radioCIVAddr is being set from a default preference, whihc is for the 7300. @@ -433,14 +450,17 @@ void wfmain::openRig() rig->moveToThread(rigThread); connect(rigThread, SIGNAL(started()), rig, SLOT(process())); connect(rig, SIGNAL(finished()), rigThread, SLOT(quit())); + connect(rig, SIGNAL(haveSerialPortError(QString,QString)), this, SLOT(receiveSerialPortError(QString,QString))); rigThread->start(); connect(this, SIGNAL(getRigCIV()), rig, SLOT(findRigs())); connect(rig, SIGNAL(discoveredRigID(rigCapabilities)), this, SLOT(receiveFoundRigID(rigCapabilities))); + 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() << "Beginning search from wfview for rigCIV (auto-detection broadcast)"; + // qDebug() << "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(); @@ -456,13 +476,25 @@ 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() << "In wfview, we now have a reply to our request for rig identity sent to CIV BROADCAST."; + //qDebug() << "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, 1500); + return; } +void wfmain::receiveSerialPortError(QString port, QString errorText) +{ + qDebug() << "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::setDefPrefs() { @@ -1120,11 +1152,14 @@ void wfmain::receiveRigID(rigCapabilities rigCaps) { return; } else { +#ifdef QT_DEBUG + qDebug() << "Rig name: " << rigCaps.modelName; + qDebug() << "Has LAN capabilities: " << rigCaps.hasLan; qDebug() << "Rig ID received into wfmain: spectLenMax: " << rigCaps.spectLenMax; qDebug() << "Rig ID received into wfmain: spectAmpMax: " << rigCaps.spectAmpMax; qDebug() << "Rig ID received into wfmain: spectSeqMax: " << rigCaps.spectSeqMax; qDebug() << "Rig ID received into wfmain: hasSpectrum: " << rigCaps.hasSpectrum; - +#endif this->rigCaps = rigCaps; this->spectWidth = rigCaps.spectLenMax; // used once haveRigCaps is true. haveRigCaps = true; @@ -1156,7 +1191,9 @@ void wfmain::receiveSpectrumData(QByteArray spectrum, double startFreq, double e { if(!haveRigCaps) { +#ifdef QT_DEBUG qDebug() << "Spectrum received, but RigID incomplete."; +#endif return; } @@ -1181,10 +1218,12 @@ void wfmain::receiveSpectrumData(QByteArray spectrum, double startFreq, double e if( specLen != rigCaps.spectLenMax ) { +#ifdef QT_DEBUG qDebug() << "-------------------------------------------"; qDebug() << "------ Unusual spectrum received, length: " << specLen; qDebug() << "------ Expected spectrum length: " << rigCaps.spectLenMax; qDebug() << "------ This should happen once at most. "; +#endif return; // safe. Using these unusual length things is a problem. } @@ -1302,12 +1341,15 @@ void wfmain::handleWFScroll(QWheelEvent *we) // .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) { - // TODO: Zoom + steps *=20; } else if (key == Qt::ControlModifier) { steps *=10; diff --git a/wfmain.h b/wfmain.h index 2228958..bcb81f5 100644 --- a/wfmain.h +++ b/wfmain.h @@ -28,7 +28,9 @@ class wfmain : public QMainWindow Q_OBJECT public: - explicit wfmain(QWidget *parent = 0); + explicit wfmain(const QString serialPortCL, const QString hostCL, QWidget *parent = 0); + QString serialPortCL; + QString hostCL; ~wfmain(); signals: @@ -117,6 +119,7 @@ private slots: void receiveATUStatus(unsigned char atustatus); void receiveRigID(rigCapabilities rigCaps); void receiveFoundRigID(rigCapabilities rigCaps); + void receiveSerialPortError(QString port, QString errorText); void handlePlotClick(QMouseEvent *); void handlePlotDoubleClick(QMouseEvent *); void handleWFClick(QMouseEvent *);