#include "servermain.h" #include "commhandler.h" #include "rigidentities.h" #include "logcategories.h" // This code is copyright 2017-2020 Elliott H. Liggett // All rights reserved servermain::servermain(const QString serialPortCL, const QString hostCL, const QString settingsFile) { this->serialPortCL = serialPortCL; this->hostCL = hostCL; qRegisterMetaType(); // Needs to be registered early. qRegisterMetaType(); qRegisterMetaType(); qRegisterMetaType(); qRegisterMetaType(); qRegisterMetaType(); qRegisterMetaType(); qRegisterMetaType(); qRegisterMetaType(); qRegisterMetaType(); qRegisterMetaType (); qRegisterMetaType (); qRegisterMetaType (); qRegisterMetaType (); qRegisterMetaType(); //signal(SIGINT, handleCtrlC); haveRigCaps = false; setDefPrefs(); getSettingsFilePath(settingsFile); loadSettings(); // Look for saved preferences setInitialTiming(); openRig(); rigConnections(); setServerToPrefs(); amTransmitting = false; } servermain::~servermain() { rigThread->quit(); rigThread->wait(); if (serverThread != Q_NULLPTR) { serverThread->quit(); serverThread->wait(); } if (rigCtl != Q_NULLPTR) { delete rigCtl; } delete settings; #if defined(PORTAUDIO) Pa_Terminate(); #endif } void servermain::closeEvent(QCloseEvent *event) { // Are you sure? } void servermain::openRig() { // This function is intended to handle opening a connection to the rig. // the connection can be either serial or network, // and this function is also responsible for initiating the search for a rig model and capabilities. // Any errors, such as unable to open connection or unable to open port, are to be reported to the user. //TODO: if(hasRunPreviously) //TODO: if(useNetwork){... // } else { // if (prefs.fileWasNotFound) { // showRigSettings(); // rig setting dialog box for network/serial, CIV, hostname, port, baud rate, serial device, etc // TODO: How do we know if the setting was loaded? // TODO: Use these if they are found if(!serialPortCL.isEmpty()) { qDebug(logSystem()) << "Serial port specified by user: " << serialPortCL; } else { qDebug(logSystem()) << "Serial port not specified. "; } if(!hostCL.isEmpty()) { qDebug(logSystem()) << "Remote host name specified by user: " << hostCL; } makeRig(); if (prefs.enableLAN) { usingLAN = true; // We need to setup the tx/rx audio: emit sendCommSetup(prefs.radioCIVAddr, udpPrefs, rxSetup, txSetup, prefs.virtualSerialPort); } else { if( (prefs.serialPortRadio.toLower() == QString("auto")) && (serialPortCL.isEmpty())) { findSerialPort(); } else { if(serialPortCL.isEmpty()) { serialPortRig = prefs.serialPortRadio; } else { serialPortRig = serialPortCL; } } usingLAN = false; emit sendCommSetup(prefs.radioCIVAddr, serialPortRig, prefs.serialPortBaud,prefs.virtualSerialPort); } } void servermain::rigConnections() { connect(this, SIGNAL(setCIVAddr(unsigned char)), rig, SLOT(setCIVAddr(unsigned char))); connect(this, SIGNAL(sendPowerOn()), rig, SLOT(powerOn())); connect(this, SIGNAL(sendPowerOff()), rig, SLOT(powerOff())); connect(rig, SIGNAL(haveFrequency(freqt)), this, SLOT(receiveFreq(freqt))); connect(this, SIGNAL(getFrequency()), rig, SLOT(getFrequency())); connect(this, SIGNAL(getMode()), rig, SLOT(getMode())); connect(this, SIGNAL(getDataMode()), rig, SLOT(getDataMode())); connect(this, SIGNAL(setDataMode(bool, unsigned char)), rig, SLOT(setDataMode(bool, unsigned char))); connect(this, SIGNAL(getBandStackReg(char,char)), rig, SLOT(getBandStackReg(char,char))); connect(rig, SIGNAL(havePTTStatus(bool)), this, SLOT(receivePTTstatus(bool))); connect(this, SIGNAL(setPTT(bool)), rig, SLOT(setPTT(bool))); connect(this, SIGNAL(getPTT()), rig, SLOT(getPTT())); connect(rig, SIGNAL(haveBandStackReg(freqt,char,char,bool)), this, SLOT(receiveBandStackReg(freqt,char,char,bool))); connect(this, SIGNAL(setRitEnable(bool)), rig, SLOT(setRitEnable(bool))); connect(this, SIGNAL(setRitValue(int)), rig, SLOT(setRitValue(int))); connect(rig, SIGNAL(haveRitEnabled(bool)), this, SLOT(receiveRITStatus(bool))); connect(rig, SIGNAL(haveRitFrequency(int)), this, SLOT(receiveRITValue(int))); connect(this, SIGNAL(getRitEnabled()), rig, SLOT(getRitEnabled())); connect(this, SIGNAL(getRitValue()), rig, SLOT(getRitValue())); connect(this, SIGNAL(getDebug()), rig, SLOT(getDebug())); connect(this, SIGNAL(spectOutputDisable()), rig, SLOT(disableSpectOutput())); connect(this, SIGNAL(spectOutputEnable()), rig, SLOT(enableSpectOutput())); connect(this, SIGNAL(scopeDisplayDisable()), rig, SLOT(disableSpectrumDisplay())); connect(this, SIGNAL(scopeDisplayEnable()), rig, SLOT(enableSpectrumDisplay())); connect(rig, SIGNAL(haveDataMode(bool)), this, SLOT(receiveDataModeStatus(bool))); connect(this, SIGNAL(getDuplexMode()), rig, SLOT(getDuplexMode())); connect(this, SIGNAL(getTone()), rig, SLOT(getTone())); connect(this, SIGNAL(getTSQL()), rig, SLOT(getTSQL())); connect(this, SIGNAL(getRptAccessMode()), rig, SLOT(getRptAccessMode())); //connect(this, SIGNAL(setDuplexMode(duplexMode)), rig, SLOT(setDuplexMode(duplexMode))); //connect(rig, SIGNAL(haveDuplexMode(duplexMode)), this, SLOT(receiveDuplexMode(duplexMode))); connect(this, SIGNAL(getModInput(bool)), rig, SLOT(getModInput(bool))); connect(rig, SIGNAL(haveModInput(rigInput,bool)), this, SLOT(receiveModInput(rigInput, bool))); connect(this, SIGNAL(setModInput(rigInput, bool)), rig, SLOT(setModInput(rigInput,bool))); connect(rig, SIGNAL(haveSpectrumData(QByteArray, double, double)), this, SLOT(receiveSpectrumData(QByteArray, double, double))); connect(rig, SIGNAL(haveSpectrumMode(spectrumMode)), this, SLOT(receiveSpectrumMode(spectrumMode))); connect(this, SIGNAL(setScopeMode(spectrumMode)), rig, SLOT(setSpectrumMode(spectrumMode))); connect(this, SIGNAL(getScopeMode()), rig, SLOT(getScopeMode())); connect(this, SIGNAL(setFrequency(unsigned char, freqt)), rig, SLOT(setFrequency(unsigned char, freqt))); connect(this, SIGNAL(setScopeEdge(char)), rig, SLOT(setScopeEdge(char))); connect(this, SIGNAL(setScopeSpan(char)), rig, SLOT(setScopeSpan(char))); //connect(this, SIGNAL(getScopeMode()), rig, SLOT(getScopeMode())); connect(this, SIGNAL(getScopeEdge()), rig, SLOT(getScopeEdge())); connect(this, SIGNAL(getScopeSpan()), rig, SLOT(getScopeSpan())); connect(rig, SIGNAL(haveScopeSpan(freqt,bool)), this, SLOT(receiveSpectrumSpan(freqt,bool))); connect(this, SIGNAL(setScopeFixedEdge(double,double,unsigned char)), rig, SLOT(setSpectrumBounds(double,double,unsigned char))); connect(this, SIGNAL(setMode(unsigned char, unsigned char)), rig, SLOT(setMode(unsigned char, unsigned char))); connect(this, SIGNAL(setMode(mode_info)), rig, SLOT(setMode(mode_info))); // Levels (read and write) // Levels: Query: connect(this, SIGNAL(getLevels()), rig, SLOT(getLevels())); connect(this, SIGNAL(getRfGain()), rig, SLOT(getRfGain())); connect(this, SIGNAL(getAfGain()), rig, SLOT(getAfGain())); connect(this, SIGNAL(getSql()), rig, SLOT(getSql())); connect(this, SIGNAL(getIfShift()), rig, SLOT(getIFShift())); connect(this, SIGNAL(getTPBFInner()), rig, SLOT(getTPBFInner())); connect(this, SIGNAL(getTPBFOuter()), rig, SLOT(getTPBFOuter())); connect(this, SIGNAL(getTxPower()), rig, SLOT(getTxLevel())); connect(this, SIGNAL(getMicGain()), rig, SLOT(getMicGain())); connect(this, SIGNAL(getSpectrumRefLevel()), rig, SLOT(getSpectrumRefLevel())); connect(this, SIGNAL(getModInputLevel(rigInput)), rig, SLOT(getModInputLevel(rigInput))); // Levels: Set: connect(this, SIGNAL(setRfGain(unsigned char)), rig, SLOT(setRfGain(unsigned char))); connect(this, SIGNAL(setAfGain(unsigned char)), rig, SLOT(setAfGain(unsigned char))); connect(this, SIGNAL(setSql(unsigned char)), rig, SLOT(setSquelch(unsigned char))); connect(this, SIGNAL(setIFShift(unsigned char)), rig, SLOT(setIFShift(unsigned char))); connect(this, SIGNAL(setTPBFInner(unsigned char)), rig, SLOT(setTPBFInner(unsigned char))); connect(this, SIGNAL(setTPBFOuter(unsigned char)), rig, SLOT(setTPBFOuter(unsigned char))); connect(this, SIGNAL(setTxPower(unsigned char)), rig, SLOT(setTxPower(unsigned char))); connect(this, SIGNAL(setMicGain(unsigned char)), rig, SLOT(setMicGain(unsigned char))); connect(this, SIGNAL(setMonitorLevel(unsigned char)), rig, SLOT(setMonitorLevel(unsigned char))); connect(this, SIGNAL(setVoxGain(unsigned char)), rig, SLOT(setVoxGain(unsigned char))); connect(this, SIGNAL(setAntiVoxGain(unsigned char)), rig, SLOT(setAntiVoxGain(unsigned char))); connect(this, SIGNAL(setSpectrumRefLevel(int)), rig, SLOT(setSpectrumRefLevel(int))); connect(this, SIGNAL(setModLevel(rigInput, unsigned char)), rig, SLOT(setModInputLevel(rigInput, unsigned char))); // Levels: handle return on query: connect(rig, SIGNAL(haveRfGain(unsigned char)), this, SLOT(receiveRfGain(unsigned char))); connect(rig, SIGNAL(haveAfGain(unsigned char)), this, SLOT(receiveAfGain(unsigned char))); connect(rig, SIGNAL(haveSql(unsigned char)), this, SLOT(receiveSql(unsigned char))); connect(rig, SIGNAL(haveTxPower(unsigned char)), this, SLOT(receiveTxPower(unsigned char))); connect(rig, SIGNAL(haveMicGain(unsigned char)), this, SLOT(receiveMicGain(unsigned char))); connect(rig, SIGNAL(haveSpectrumRefLevel(int)), this, SLOT(receiveSpectrumRefLevel(int))); connect(rig, SIGNAL(haveACCGain(unsigned char,unsigned char)), this, SLOT(receiveACCGain(unsigned char,unsigned char))); connect(rig, SIGNAL(haveUSBGain(unsigned char)), this, SLOT(receiveUSBGain(unsigned char))); connect(rig, SIGNAL(haveLANGain(unsigned char)), this, SLOT(receiveLANGain(unsigned char))); //Metering: connect(this, SIGNAL(getMeters(meterKind)), rig, SLOT(getMeters(meterKind))); connect(rig, SIGNAL(haveMeter(meterKind,unsigned char)), this, SLOT(receiveMeter(meterKind,unsigned char))); // Rig and ATU info: connect(this, SIGNAL(startATU()), rig, SLOT(startATU())); connect(this, SIGNAL(setATU(bool)), rig, SLOT(setATU(bool))); connect(this, SIGNAL(getATUStatus()), rig, SLOT(getATUStatus())); connect(this, SIGNAL(getRigID()), rig, SLOT(getRigID())); connect(rig, SIGNAL(haveATUStatus(unsigned char)), this, SLOT(receiveATUStatus(unsigned char))); connect(rig, SIGNAL(haveRigID(rigCapabilities)), this, SLOT(receiveRigID(rigCapabilities))); connect(this, SIGNAL(setAttenuator(unsigned char)), rig, SLOT(setAttenuator(unsigned char))); connect(this, SIGNAL(setPreamp(unsigned char)), rig, SLOT(setPreamp(unsigned char))); connect(this, SIGNAL(setAntenna(unsigned char, bool)), rig, SLOT(setAntenna(unsigned char, bool))); connect(this, SIGNAL(getPreamp()), rig, SLOT(getPreamp())); connect(rig, SIGNAL(havePreamp(unsigned char)), this, SLOT(receivePreamp(unsigned char))); connect(this, SIGNAL(getAttenuator()), rig, SLOT(getAttenuator())); connect(rig, SIGNAL(haveAttenuator(unsigned char)), this, SLOT(receiveAttenuator(unsigned char))); connect(this, SIGNAL(getAntenna()), rig, SLOT(getAntenna())); connect(rig, SIGNAL(haveAntenna(unsigned char,bool)), this, SLOT(receiveAntennaSel(unsigned char,bool))); // Speech (emitted from rig speaker) connect(this, SIGNAL(sayAll()), rig, SLOT(sayAll())); connect(this, SIGNAL(sayFrequency()), rig, SLOT(sayFrequency())); connect(this, SIGNAL(sayMode()), rig, SLOT(sayMode())); // Date and Time: connect(this, SIGNAL(setTime(timekind)), rig, SLOT(setTime(timekind))); connect(this, SIGNAL(setDate(datekind)), rig, SLOT(setDate(datekind))); connect(this, SIGNAL(setUTCOffset(timekind)), rig, SLOT(setUTCOffset(timekind))); } void servermain::makeRig() { if (rigThread == Q_NULLPTR) { rig = new rigCommander(); rigThread = new QThread(this); // Thread: rig->moveToThread(rigThread); connect(rigThread, SIGNAL(started()), rig, SLOT(process())); connect(rigThread, SIGNAL(finished()), rig, SLOT(deleteLater())); rigThread->start(); // Rig status and Errors: connect(rig, SIGNAL(haveSerialPortError(QString, QString)), this, SLOT(receiveSerialPortError(QString, QString))); connect(rig, SIGNAL(haveStatusUpdate(QString)), this, SLOT(receiveStatusUpdate(QString))); // Rig comm setup: connect(this, SIGNAL(sendCommSetup(unsigned char, udpPreferences, audioSetup, audioSetup, QString)), rig, SLOT(commSetup(unsigned char, udpPreferences, audioSetup, audioSetup, QString))); connect(this, SIGNAL(sendCommSetup(unsigned char, QString, quint32,QString)), rig, SLOT(commSetup(unsigned char, QString, quint32,QString))); connect(this, SIGNAL(setRTSforPTT(bool)), rig, SLOT(setRTSforPTT(bool))); connect(rig, SIGNAL(haveBaudRate(quint32)), this, SLOT(receiveBaudRate(quint32))); connect(this, SIGNAL(sendCloseComm()), rig, SLOT(closeComm())); connect(this, SIGNAL(sendChangeLatency(quint16)), rig, SLOT(changeLatency(quint16))); connect(this, SIGNAL(getRigCIV()), rig, SLOT(findRigs())); connect(this, SIGNAL(setRigID(unsigned char)), rig, SLOT(setRigID(unsigned char))); connect(rig, SIGNAL(discoveredRigID(rigCapabilities)), this, SLOT(receiveFoundRigID(rigCapabilities))); connect(rig, SIGNAL(commReady()), this, SLOT(receiveCommReady())); connect(this, SIGNAL(requestRigState()), rig, SLOT(sendState())); connect(this, SIGNAL(stateUpdated()), rig, SLOT(stateUpdated())); connect(rig, SIGNAL(stateInfo(rigstate*)), this, SLOT(receiveStateInfo(rigstate*))); if (rigCtl != Q_NULLPTR) { connect(rig, SIGNAL(stateInfo(rigstate*)), rigCtl, SLOT(receiveStateInfo(rigstate*))); connect(rigCtl, SIGNAL(stateUpdated()), rig, SLOT(stateUpdated())); } } } void servermain::removeRig() { if (rigThread != Q_NULLPTR) { if (rigCtl != Q_NULLPTR) { rigCtl->disconnect(); } rigThread->disconnect(); rig->disconnect(); delete rigThread; delete rig; rig = Q_NULLPTR; } } void servermain::findSerialPort() { // Find the ICOM radio connected, or, if none, fall back to OS default. // qInfo(logSystem()) << "Searching for serial port..."; QDirIterator it73("/dev/serial/by-id", QStringList() << "*IC-7300*", QDir::Files, QDirIterator::Subdirectories); QDirIterator it97("/dev/serial", QStringList() << "*IC-9700*A*", QDir::Files, QDirIterator::Subdirectories); QDirIterator it785x("/dev/serial", QStringList() << "*IC-785*A*", QDir::Files, QDirIterator::Subdirectories); QDirIterator it705("/dev/serial", QStringList() << "*IC-705*A", QDir::Files, QDirIterator::Subdirectories); QDirIterator it7610("/dev/serial", QStringList() << "*IC-7610*A", QDir::Files, QDirIterator::Subdirectories); QDirIterator itR8600("/dev/serial", QStringList() << "*IC-R8600*A", QDir::Files, QDirIterator::Subdirectories); if(!it73.filePath().isEmpty()) { // IC-7300 serialPortRig = it73.filePath(); // first } else if(!it97.filePath().isEmpty()) { // IC-9700 serialPortRig = it97.filePath(); } else if(!it785x.filePath().isEmpty()) { // IC-785x serialPortRig = it785x.filePath(); } else if(!it705.filePath().isEmpty()) { // IC-705 serialPortRig = it705.filePath(); } else if(!it7610.filePath().isEmpty()) { // IC-7610 serialPortRig = it7610.filePath(); } else if(!itR8600.filePath().isEmpty()) { // IC-R8600 serialPortRig = itR8600.filePath(); } else { //fall back: qInfo(logSystem()) << "Could not find Icom serial port. Falling back to OS default. Use --port to specify, or modify preferences."; #ifdef Q_OS_MAC serialPortRig = QString("/dev/tty.SLAB_USBtoUART"); #endif #ifdef Q_OS_LINUX serialPortRig = QString("/dev/ttyUSB0"); #endif #ifdef Q_OS_WIN serialPortRig = QString("COM1"); #endif } } void servermain::receiveCommReady() { qInfo(logSystem()) << "Received CommReady!! "; if(!usingLAN) { // usingLAN gets set when we emit the sendCommSetup signal. // If we're not using the LAN, then we're on serial, and // we already know the baud rate and can calculate the timing parameters. calculateTimingParameters(); } if(prefs.radioCIVAddr == 0) { // tell rigCommander to broadcast a request for all rig IDs. // qInfo(logSystem()) << "Beginning search from wfview for rigCIV (auto-detection broadcast)"; emit getRigCIV(); issueDelayedCommand(cmdGetRigCIV); delayedCommand->start(); } else { // don't bother, they told us the CIV they want, stick with it. // We still query the rigID to find the model, but at least we know the CIV. qInfo(logSystem()) << "Skipping automatic CIV, using user-supplied value of " << prefs.radioCIVAddr; if(prefs.CIVisRadioModel) { qInfo(logSystem()) << "Skipping Rig ID query, using user-supplied model from CI-V address: " << prefs.radioCIVAddr; emit setRigID(prefs.radioCIVAddr); } else { emit getRigID(); getInitialRigState(); } } } void servermain::receiveFoundRigID(rigCapabilities rigCaps) { // Entry point for unknown rig being identified at the start of the program. //now we know what the rig ID is: //qInfo(logSystem()) << "In wfview, we now have a reply to our request for rig identity sent to CIV BROADCAST."; if(rig->usingLAN()) { usingLAN = true; } else { usingLAN = false; } receiveRigID(rigCaps); getInitialRigState(); return; } void servermain::receiveSerialPortError(QString port, QString errorText) { qInfo(logSystem()) << "servermain: received serial port error for port: " << port << " with message: " << errorText; // TODO: Dialog box, exit, etc } void servermain::getSettingsFilePath(QString settingsFile) { if (settingsFile.isNull()) { settings = new QSettings(); } else { QString file = settingsFile; QFile info(settingsFile); QString path=""; if (!QFileInfo(info).isAbsolute()) { path = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation); if (path.isEmpty()) { path = QDir::homePath(); } path = path + "/"; file = info.fileName(); } qInfo(logSystem()) << "Loading settings from:" << path + file; settings = new QSettings(path + file, QSettings::Format::IniFormat); } } void servermain::setInitialTiming() { loopTickCounter = 0; delayedCmdIntervalLAN_ms = 70; // interval for regular delayed commands, including initial rig/UI state queries delayedCmdIntervalSerial_ms = 100; // interval for regular delayed commands, including initial rig/UI state queries delayedCmdStartupInterval_ms = 250; // interval for rigID polling delayedCommand = new QTimer(this); delayedCommand->setInterval(delayedCmdStartupInterval_ms); // 250ms until we find rig civ and id, then 100ms. delayedCommand->setSingleShot(false); connect(delayedCommand, SIGNAL(timeout()), this, SLOT(sendRadioCommandLoop())); // TODO: Remove this: // periodicPollingTimer = new QTimer(this); // periodicPollingTimer->setInterval(10); // periodicPollingTimer->setSingleShot(false); //connect(periodicPollingTimer, SIGNAL(timeout()), this, SLOT(sendRadioCommandLoop())); pttTimer = new QTimer(this); pttTimer->setInterval(180*1000); // 3 minute max transmit time in ms pttTimer->setSingleShot(true); connect(pttTimer, SIGNAL(timeout()), this, SLOT(handlePttLimit())); timeSync = new QTimer(this); connect(timeSync, SIGNAL(timeout()), this, SLOT(setRadioTimeDateSend())); waitingToSetTimeDate = false; lastFreqCmdTime_ms = QDateTime::currentMSecsSinceEpoch() - 5000; // 5 seconds ago } void servermain::setServerToPrefs() { // Start server if enabled in config if (serverThread != Q_NULLPTR) { serverThread->quit(); serverThread->wait(); serverThread = Q_NULLPTR; udp = Q_NULLPTR; } if (serverConfig.enabled) { serverConfig.lan = prefs.enableLAN; qInfo(logAudio()) << "Audio Input device " << serverRxSetup.name; qInfo(logAudio()) << "Audio Output device " << serverTxSetup.name; udp = new udpServer(serverConfig, serverTxSetup, serverRxSetup); serverThread = new QThread(this); udp->moveToThread(serverThread); connect(this, SIGNAL(initServer()), udp, SLOT(init())); connect(serverThread, SIGNAL(finished()), udp, SLOT(deleteLater())); if (rig != Q_NULLPTR) { connect(rig, SIGNAL(haveAudioData(audioPacket)), udp, SLOT(receiveAudioData(audioPacket))); connect(rig, SIGNAL(haveDataForServer(QByteArray)), udp, SLOT(dataForServer(QByteArray))); connect(udp, SIGNAL(haveDataFromServer(QByteArray)), rig, SLOT(dataFromServer(QByteArray))); } if (!prefs.enableLAN) { connect(udp, SIGNAL(haveNetworkStatus(QString)), this, SLOT(receiveStatusUpdate(QString))); } serverThread->start(); emit initServer(); connect(this, SIGNAL(sendRigCaps(rigCapabilities)), udp, SLOT(receiveRigCaps(rigCapabilities))); } } void servermain::setDefPrefs() { defPrefs.useFullScreen = false; defPrefs.useDarkMode = true; defPrefs.useSystemTheme = false; defPrefs.drawPeaks = true; defPrefs.wfAntiAlias = false; defPrefs.wfInterpolate = true; defPrefs.radioCIVAddr = 0x00; // previously was 0x94 for 7300. defPrefs.CIVisRadioModel = false; defPrefs.forceRTSasPTT = false; defPrefs.serialPortRadio = QString("auto"); defPrefs.serialPortBaud = 115200; defPrefs.enablePTT = false; defPrefs.niceTS = true; defPrefs.enableRigCtlD = false; defPrefs.rigCtlPort = 4533; defPrefs.virtualSerialPort = QString("none"); defPrefs.localAFgain = 255; defPrefs.wflength = 160; defPrefs.confirmExit = true; defPrefs.confirmPowerOff = true; defPrefs.meter2Type = meterNone; udpDefPrefs.ipAddress = QString(""); udpDefPrefs.controlLANPort = 50001; udpDefPrefs.serialLANPort = 50002; udpDefPrefs.audioLANPort = 50003; udpDefPrefs.username = QString(""); udpDefPrefs.password = QString(""); udpDefPrefs.clientName = QHostInfo::localHostName(); } void servermain::loadSettings() { qInfo(logSystem()) << "Loading settings from " << settings->fileName(); // Radio and Comms: C-IV addr, port to use settings->beginGroup("Radio"); prefs.radioCIVAddr = (unsigned char)settings->value("RigCIVuInt", defPrefs.radioCIVAddr).toInt(); prefs.CIVisRadioModel = (bool)settings->value("CIVisRadioModel", defPrefs.CIVisRadioModel).toBool(); prefs.forceRTSasPTT = (bool)settings->value("ForceRTSasPTT", defPrefs.forceRTSasPTT).toBool(); prefs.serialPortRadio = settings->value("SerialPortRadio", defPrefs.serialPortRadio).toString(); prefs.serialPortBaud = (quint32)settings->value("SerialPortBaud", defPrefs.serialPortBaud).toInt(); if (prefs.serialPortBaud > 0) { serverConfig.baudRate = prefs.serialPortBaud; } prefs.virtualSerialPort = settings->value("VirtualSerialPort", defPrefs.virtualSerialPort).toString(); prefs.localAFgain = (unsigned char)settings->value("localAFgain", defPrefs.localAFgain).toUInt(); rxSetup.localAFgain = prefs.localAFgain; txSetup.localAFgain = 255; settings->endGroup(); // Misc. user settings (enable PTT, draw peaks, etc) settings->beginGroup("Controls"); prefs.enablePTT = settings->value("EnablePTT", defPrefs.enablePTT).toBool(); prefs.niceTS = settings->value("NiceTS", defPrefs.niceTS).toBool(); settings->endGroup(); settings->beginGroup("LAN"); prefs.enableLAN = settings->value("EnableLAN", defPrefs.enableLAN).toBool(); prefs.enableRigCtlD = settings->value("EnableRigCtlD", defPrefs.enableRigCtlD).toBool(); prefs.rigCtlPort = settings->value("RigCtlPort", defPrefs.rigCtlPort).toInt(); udpPrefs.ipAddress = settings->value("IPAddress", udpDefPrefs.ipAddress).toString(); udpPrefs.controlLANPort = settings->value("ControlLANPort", udpDefPrefs.controlLANPort).toInt(); udpPrefs.username = settings->value("Username", udpDefPrefs.username).toString(); udpPrefs.password = settings->value("Password", udpDefPrefs.password).toString(); rxSetup.isinput = false; txSetup.isinput = true; rxSetup.latency = settings->value("AudioRXLatency", "150").toInt(); txSetup.latency = settings->value("AudioTXLatency", "150").toInt(); rxSetup.samplerate = settings->value("AudioRXSampleRate", "48000").toInt(); txSetup.samplerate = rxSetup.samplerate; rxSetup.codec = settings->value("AudioRXCodec", "4").toInt(); txSetup.codec = settings->value("AudioTXCodec", "4").toInt(); rxSetup.name = settings->value("AudioOutput", "").toString(); qInfo(logGui()) << "Got Audio Output: " << rxSetup.name; txSetup.name = settings->value("AudioInput", "").toString(); // qInfo(logGui()) << "Got Audio Input: " << txSetup.name; int audioInputIndex = ui->audioInputCombo->findText(txSetup.name); rxSetup.resampleQuality = settings->value("ResampleQuality", "4").toInt(); txSetup.resampleQuality = rxSetup.resampleQuality; udpPrefs.clientName = settings->value("ClientName", udpDefPrefs.clientName).toString(); settings->endGroup(); settings->beginGroup("Server"); serverConfig.enabled = settings->value("ServerEnabled", false).toBool(); serverConfig.controlPort = settings->value("ServerControlPort", 50001).toInt(); serverConfig.civPort = settings->value("ServerCivPort", 50002).toInt(); serverConfig.audioPort = settings->value("ServerAudioPort", 50003).toInt(); 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); } serverRxSetup.isinput = true; serverTxSetup.isinput = false; serverRxSetup.localAFgain = 255; serverTxSetup.localAFgain = 255; serverRxSetup.name = settings->value("ServerAudioInput", "").toString(); qInfo(logGui()) << "Got Server Audio Input: " << serverRxSetup.name; serverRxSetup.resampleQuality = rxSetup.resampleQuality; serverTxSetup.resampleQuality = serverRxSetup.resampleQuality; serverTxSetup.name = settings->value("ServerAudioOutput", "").toString(); qInfo(logGui()) << "Got Server Audio Output: " << serverTxSetup.name; 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(); #if defined(RTAUDIO) #if defined(Q_OS_LINUX) RtAudio* audio = new RtAudio(RtAudio::Api::LINUX_ALSA); #elif defined(Q_OS_WIN) RtAudio* audio = new RtAudio(RtAudio::Api::WINDOWS_WASAPI); #elif defined(Q_OS_MACX) RtAudio* audio = new RtAudio(RtAudio::Api::MACOSX_CORE); #endif // Enumerate audio devices, need to do before settings are loaded. std::map apiMap; apiMap[RtAudio::MACOSX_CORE] = "OS-X Core Audio"; apiMap[RtAudio::WINDOWS_ASIO] = "Windows ASIO"; apiMap[RtAudio::WINDOWS_DS] = "Windows DirectSound"; apiMap[RtAudio::WINDOWS_WASAPI] = "Windows WASAPI"; apiMap[RtAudio::UNIX_JACK] = "Jack Client"; apiMap[RtAudio::LINUX_ALSA] = "Linux ALSA"; apiMap[RtAudio::LINUX_PULSE] = "Linux PulseAudio"; apiMap[RtAudio::LINUX_OSS] = "Linux OSS"; apiMap[RtAudio::RTAUDIO_DUMMY] = "RtAudio Dummy"; std::vector< RtAudio::Api > apis; RtAudio::getCompiledApi(apis); qInfo(logAudio()) << "RtAudio Version " << QString::fromStdString(RtAudio::getVersion()); qInfo(logAudio()) << "Compiled APIs:"; for (unsigned int i = 0; i < apis.size(); i++) { qInfo(logAudio()) << " " << QString::fromStdString(apiMap[apis[i]]); } RtAudio::DeviceInfo info; qInfo(logAudio()) << "Current API: " << QString::fromStdString(apiMap[audio->getCurrentApi()]); unsigned int devices = audio->getDeviceCount(); qInfo(logAudio()) << "Found " << devices << " audio device(s) *=default"; for (unsigned int i = 1; i < devices; i++) { info = audio->getDeviceInfo(i); if (info.outputChannels > 0) { if (QString::fromStdString(info.name) == rxSetup.name) { rxSetup.port = i; } if (QString::fromStdString(info.name) == serverTxSetup.name) { serverTxSetup.port = i; } } if (info.inputChannels > 0) { if (QString::fromStdString(info.name) == txSetup.name) { txSetup.port = i; } if (QString::fromStdString(info.name) == serverRxSetup.name) { serverRxSetup.port = i; } } } delete audio; #elif defined(PORTAUDIO) // Use PortAudio device enumeration PaError err; err = Pa_Initialize(); if (err != paNoError) { qInfo(logAudio()) << "ERROR: Cannot initialize Portaudio"; } qInfo(logAudio()) << "PortAudio version: " << Pa_GetVersionInfo()->versionText; int numDevices; numDevices = Pa_GetDeviceCount(); qInfo(logAudio()) << "Pa_CountDevices returned" << numDevices; const PaDeviceInfo* info; for (int i = 0; i < numDevices; i++) { info = Pa_GetDeviceInfo(i); if (info->maxInputChannels > 0) { if (QString::fromStdString(info.name) == rxSetup.name) { rxSetup.port = i; } if (QString::fromStdString(info.name) == serverTxSetup.name) { serverTxSetup.port = i; } } if (info->maxOutputChannels > 0) { if (QString::fromStdString(info.name) == txSetup.name) { txSetup.port = i; } if (QString::fromStdString(info.name) == serverRxSetup.name) { serverRxSetup.port = i; } } } #else // If no external library is configured, use QTMultimedia // // Set these to default audio devices initially. rxSetup.port = QAudioDeviceInfo::defaultOutputDevice(); txSetup.port = QAudioDeviceInfo::defaultInputDevice(); serverRxSetup.port = QAudioDeviceInfo::defaultInputDevice(); serverTxSetup.port = QAudioDeviceInfo::defaultOutputDevice(); // Enumerate audio devices, need to do before settings are loaded. const auto audioOutputs = QAudioDeviceInfo::availableDevices(QAudio::AudioOutput); for (const QAudioDeviceInfo& deviceInfo : audioOutputs) { if (deviceInfo.deviceName() == rxSetup.name) { rxSetup.port = deviceInfo; qInfo(logGui()) << "Setting Audio Output: " << rxSetup.name; } if (deviceInfo.deviceName() == serverTxSetup.name) { serverTxSetup.port = deviceInfo; qInfo(logGui()) << "Setting Server Audio Input: " << serverTxSetup.name; } } const auto audioInputs = QAudioDeviceInfo::availableDevices(QAudio::AudioInput); for (const QAudioDeviceInfo& deviceInfo : audioInputs) { if (deviceInfo.deviceName() == txSetup.name) { txSetup.port = deviceInfo; qInfo(logGui()) << "Setting Audio Input: " << txSetup.name; } if (deviceInfo.deviceName() == serverRxSetup.name) { serverRxSetup.port = deviceInfo; qInfo(logGui()) << "Setting Server Audio Output: " << serverRxSetup.name; } } #endif } quint64 servermain::roundFrequency(quint64 frequency, unsigned int tsHz) { return frequency; } quint64 servermain::roundFrequencyWithStep(quint64 frequency, int steps, unsigned int tsHz) { quint64 rounded = 0; if(steps > 0) { frequency = frequency + (quint64)(steps*tsHz); } else { frequency = frequency - std::min((quint64)(abs(steps)*tsHz), frequency); } return frequency; } void servermain:: 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. issueDelayedCommand(cmdGetFreq); issueDelayedCommand(cmdGetMode); issueDelayedCommand(cmdNone); issueDelayedCommand(cmdGetFreq); issueDelayedCommand(cmdGetMode); // From left to right in the UI: if (rigCaps.hasTransmit) { issueDelayedCommand(cmdGetDataMode); issueDelayedCommand(cmdGetModInput); issueDelayedCommand(cmdGetModDataInput); } issueDelayedCommand(cmdGetRxGain); issueDelayedCommand(cmdGetAfGain); issueDelayedCommand(cmdGetSql); if (rigCaps.hasTransmit) { issueDelayedCommand(cmdGetTxPower); issueDelayedCommand(cmdGetCurrentModLevel); // level for currently selected mod sources } issueDelayedCommand(cmdGetSpectrumRefLevel); issueDelayedCommand(cmdGetDuplexMode); if(rigCaps.hasSpectrum) { issueDelayedCommand(cmdDispEnable); issueDelayedCommand(cmdSpecOn); } if (rigCaps.hasTransmit) { issueDelayedCommand(cmdGetModInput); issueDelayedCommand(cmdGetModDataInput); } if(rigCaps.hasCTCSS) { issueDelayedCommand(cmdGetTone); issueDelayedCommand(cmdGetTSQL); } if(rigCaps.hasDTCS) { issueDelayedCommand(cmdGetDTCS); } issueDelayedCommand(cmdGetRptAccessMode); if(rigCaps.hasAntennaSel) { issueDelayedCommand(cmdGetAntenna); } if(rigCaps.hasAttenuator) { issueDelayedCommand(cmdGetAttenuator); } if(rigCaps.hasPreamp) { issueDelayedCommand(cmdGetPreamp); } issueDelayedCommand(cmdGetRitEnabled); issueDelayedCommand(cmdGetRitValue); if(rigCaps.hasIFShift) issueDelayedCommand(cmdGetIFShift); if(rigCaps.hasTBPF) { issueDelayedCommand(cmdGetTPBFInner); issueDelayedCommand(cmdGetTPBFOuter); } if(rigCaps.hasSpectrum) { issueDelayedCommand(cmdGetSpectrumMode); issueDelayedCommand(cmdGetSpectrumSpan); } issueDelayedCommand(cmdNone); issueDelayedCommand(cmdStartRegularPolling); if(rigCaps.hasATU) { issueDelayedCommand(cmdGetATUStatus); } delayedCommand->start(); } void servermain::doCmd(commandtype cmddata) { cmds cmd = cmddata.cmd; std::shared_ptr data = cmddata.data; // This switch is for commands with parameters. // the "default" for non-parameter commands is to call doCmd(cmd). switch (cmd) { case cmdSetFreq: { lastFreqCmdTime_ms = QDateTime::currentMSecsSinceEpoch(); freqt f = (*std::static_pointer_cast(data)); emit setFrequency(0,f); break; } case cmdSetMode: { mode_info m = (*std::static_pointer_cast(data)); emit setMode(m); break; } case cmdSetTxPower: { unsigned char txpower = (*std::static_pointer_cast(data)); emit setTxPower(txpower); break; } case cmdSetMicGain: { unsigned char micgain = (*std::static_pointer_cast(data)); emit setTxPower(micgain); break; } case cmdSetRxRfGain: { unsigned char rfgain = (*std::static_pointer_cast(data)); emit setRfGain(rfgain); break; } case cmdSetModLevel: { unsigned char modlevel = (*std::static_pointer_cast(data)); rigInput currentIn; if(usingDataMode) { currentIn = currentModDataSrc; } else { currentIn = currentModSrc; } emit setModLevel(currentIn, modlevel); break; } case cmdSetAfGain: { unsigned char afgain = (*std::static_pointer_cast(data)); emit setAfGain(afgain); break; } case cmdSetSql: { unsigned char sqlLevel = (*std::static_pointer_cast(data)); emit setSql(sqlLevel); break; } case cmdSetIFShift: { unsigned char IFShiftLevel = (*std::static_pointer_cast(data)); emit setIFShift(IFShiftLevel); break; } case cmdSetTPBFInner: { unsigned char innterLevel = (*std::static_pointer_cast(data)); emit setTPBFInner(innterLevel); break; } case cmdSetTPBFOuter: { unsigned char outerLevel = (*std::static_pointer_cast(data)); emit setTPBFOuter(outerLevel); break; } case cmdSetPTT: { bool pttrequest = (*std::static_pointer_cast(data)); emit setPTT(pttrequest); break; } case cmdSetATU: { bool atuOn = (*std::static_pointer_cast(data)); emit setATU(atuOn); break; } case cmdSetUTCOffset: { timekind u = (*std::static_pointer_cast(data)); emit setUTCOffset(u); break; } case cmdSetTime: { timekind t = (*std::static_pointer_cast(data)); emit setTime(t); break; } case cmdSetDate: { datekind d = (*std::static_pointer_cast(data)); emit setDate(d); break; } default: doCmd(cmd); break; } } void servermain::doCmd(cmds cmd) { } void servermain::sendRadioCommandLoop() { // Called by the periodicPollingTimer, see setInitialTiming() if(!(loopTickCounter % 2)) { // if ther's a command waiting, run it. if(!delayedCmdQue.empty()) { commandtype cmddata = delayedCmdQue.front(); delayedCmdQue.pop_front(); doCmd(cmddata); } else if(!(loopTickCounter % 10)) { // pick from useful queries to make now and then if(haveRigCaps && !slowPollCmdQueue.empty()) { int nCmds = slowPollCmdQueue.size(); cmds sCmd = slowPollCmdQueue[(slowCmdNum++)%nCmds]; doCmd(sCmd); } } } else { // odd-number ticks: // s-meter or other metering if(haveRigCaps && !periodicCmdQueue.empty()) { int nCmds = periodicCmdQueue.size(); cmds pcmd = periodicCmdQueue[ (pCmdNum++)%nCmds ]; doCmd(pcmd); } } loopTickCounter++; } void servermain::issueDelayedCommand(cmds cmd) { // Append to end of command queue commandtype cmddata; cmddata.cmd = cmd; cmddata.data = NULL; delayedCmdQue.push_back(cmddata); } void servermain::issueDelayedCommandPriority(cmds cmd) { // Places the new command at the top of the queue // Use only when needed. commandtype cmddata; cmddata.cmd = cmd; cmddata.data = NULL; delayedCmdQue.push_front(cmddata); } void servermain::issueDelayedCommandUnique(cmds cmd) { // Use this function to insert commands where // multiple (redundant) commands don't make sense. commandtype cmddata; cmddata.cmd = cmd; cmddata.data = NULL; // The following is both expensive and not that great, // since it does not check if the arguments are the same. bool found = false; for(unsigned int i=0; i < delayedCmdQue.size(); i++) { if(delayedCmdQue.at(i).cmd == cmd) { found = true; break; } } if(!found) { delayedCmdQue.push_front(cmddata); } // if( std::find(delayedCmdQue.begin(), delayedCmdQue.end(), cmddata ) == delayedCmdQue.end()) // { // delayedCmdQue.push_front(cmddata); // } } void servermain::issueCmd(cmds cmd, mode_info m) { commandtype cmddata; cmddata.cmd = cmd; cmddata.data = std::shared_ptr(new mode_info(m)); delayedCmdQue.push_back(cmddata); } void servermain::issueCmd(cmds cmd, freqt f) { commandtype cmddata; cmddata.cmd = cmd; cmddata.data = std::shared_ptr(new freqt(f)); delayedCmdQue.push_back(cmddata); } void servermain::issueCmd(cmds cmd, timekind t) { qDebug(logSystem()) << "Issuing timekind command with data: " << t.hours << " hours, " << t.minutes << " minutes, " << t.isMinus << " isMinus"; commandtype cmddata; cmddata.cmd = cmd; cmddata.data = std::shared_ptr(new timekind(t)); delayedCmdQue.push_front(cmddata); } void servermain::issueCmd(cmds cmd, datekind d) { qDebug(logSystem()) << "Issuing datekind command with data: " << d.day << " day, " << d.month << " month, " << d.year << " year."; commandtype cmddata; cmddata.cmd = cmd; cmddata.data = std::shared_ptr(new datekind(d)); delayedCmdQue.push_front(cmddata); } void servermain::issueCmd(cmds cmd, int i) { commandtype cmddata; cmddata.cmd = cmd; cmddata.data = std::shared_ptr(new int(i)); delayedCmdQue.push_back(cmddata); } void servermain::issueCmd(cmds cmd, char c) { commandtype cmddata; cmddata.cmd = cmd; cmddata.data = std::shared_ptr(new char(c)); delayedCmdQue.push_back(cmddata); } void servermain::issueCmd(cmds cmd, bool b) { commandtype cmddata; cmddata.cmd = cmd; cmddata.data = std::shared_ptr(new bool(b)); delayedCmdQue.push_back(cmddata); } void servermain::issueCmd(cmds cmd, unsigned char c) { commandtype cmddata; cmddata.cmd = cmd; cmddata.data = std::shared_ptr(new unsigned char(c)); delayedCmdQue.push_back(cmddata); } void servermain::issueCmdUniquePriority(cmds cmd, bool b) { commandtype cmddata; cmddata.cmd = cmd; cmddata.data = std::shared_ptr(new bool(b)); delayedCmdQue.push_front(cmddata); removeSimilarCommand(cmd); } void servermain::issueCmdUniquePriority(cmds cmd, unsigned char c) { commandtype cmddata; cmddata.cmd = cmd; cmddata.data = std::shared_ptr(new unsigned char(c)); delayedCmdQue.push_front(cmddata); removeSimilarCommand(cmd); } void servermain::issueCmdUniquePriority(cmds cmd, char c) { commandtype cmddata; cmddata.cmd = cmd; cmddata.data = std::shared_ptr(new char(c)); delayedCmdQue.push_front(cmddata); removeSimilarCommand(cmd); } void servermain::issueCmdUniquePriority(cmds cmd, freqt f) { commandtype cmddata; cmddata.cmd = cmd; cmddata.data = std::shared_ptr(new freqt(f)); delayedCmdQue.push_front(cmddata); removeSimilarCommand(cmd); } void servermain::removeSimilarCommand(cmds cmd) { // pop anything out that is of the same kind of command: // pop anything out that is of the same kind of command: // Start at 1 since we put one in at zero that we want to keep. for(unsigned int i=1; i < delayedCmdQue.size(); i++) { if(delayedCmdQue.at(i).cmd == cmd) { //delayedCmdQue[i].cmd = cmdNone; delayedCmdQue.erase(delayedCmdQue.begin()+i); // i -= 1; } } } void servermain::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 { qDebug(logSystem()) << "Rig name: " << rigCaps.modelName; qDebug(logSystem()) << "Has LAN capabilities: " << rigCaps.hasLan; qDebug(logSystem()) << "Rig ID received into servermain: spectLenMax: " << rigCaps.spectLenMax; qDebug(logSystem()) << "Rig ID received into servermain: spectAmpMax: " << rigCaps.spectAmpMax; qDebug(logSystem()) << "Rig ID received into servermain: spectSeqMax: " << rigCaps.spectSeqMax; qDebug(logSystem()) << "Rig ID received into servermain: hasSpectrum: " << rigCaps.hasSpectrum; this->rigCaps = rigCaps; this->spectWidth = rigCaps.spectLenMax; // used once haveRigCaps is true. haveRigCaps = true; // Added so that server receives rig capabilities. emit sendRigCaps(rigCaps); } } void servermain::initPeriodicCommands() { // This function places periodic polling commands into a queue. // The commands are run using a timer, // and the timer is started by the delayed command cmdStartPeriodicTimer. insertPeriodicCommand(cmdGetTxRxMeter, 128); insertSlowPeriodicCommand(cmdGetFreq, 128); insertSlowPeriodicCommand(cmdGetMode, 128); if(rigCaps.hasTransmit) insertSlowPeriodicCommand(cmdGetPTT, 128); insertSlowPeriodicCommand(cmdGetTxPower, 128); insertSlowPeriodicCommand(cmdGetRxGain, 128); if(rigCaps.hasAttenuator) insertSlowPeriodicCommand(cmdGetAttenuator, 128); if(rigCaps.hasTransmit) insertSlowPeriodicCommand(cmdGetPTT, 128); if(rigCaps.hasPreamp) insertSlowPeriodicCommand(cmdGetPreamp, 128); if (rigCaps.hasRXAntenna) { insertSlowPeriodicCommand(cmdGetAntenna, 128); } insertSlowPeriodicCommand(cmdGetDuplexMode, 128); } void servermain::insertPeriodicCommand(cmds cmd, unsigned char priority) { // TODO: meaningful priority // These commands get run at the fastest pace possible // Typically just metering. if(priority < 10) { periodicCmdQueue.push_front(cmd); } else { periodicCmdQueue.push_back(cmd); } } void servermain::insertPeriodicCommandUnique(cmds cmd) { // Use this function to insert a non-duplicate command // into the fast periodic polling queue, typically // meter commands where high refresh rates are desirable. removePeriodicCommand(cmd); periodicCmdQueue.push_front(cmd); } void servermain::removePeriodicCommand(cmds cmd) { while(true) { auto it = std::find(this->periodicCmdQueue.begin(), this->periodicCmdQueue.end(), cmd); if(it != periodicCmdQueue.end()) { periodicCmdQueue.erase(it); } else { break; } } } void servermain::insertSlowPeriodicCommand(cmds cmd, unsigned char priority) { // TODO: meaningful priority // These commands are run every 20 "ticks" of the primary radio command loop // Basically 20 times less often than the standard peridic command if(priority < 10) { slowPollCmdQueue.push_front(cmd); } else { slowPollCmdQueue.push_back(cmd); } } void servermain::receiveFreq(freqt freqStruct) { qint64 tnow_ms = QDateTime::currentMSecsSinceEpoch(); if(tnow_ms - lastFreqCmdTime_ms > delayedCommand->interval() * 2) { freq = freqStruct; } else { qDebug(logSystem()) << "Rejecting stale frequency: " << freqStruct.Hz << " Hz, delta time ms = " << tnow_ms - lastFreqCmdTime_ms\ << ", tnow_ms " << tnow_ms << ", last: " << lastFreqCmdTime_ms; } } void servermain::receivePTTstatus(bool pttOn) { // This is the only place where amTransmitting and the transmit button text should be changed: //qInfo(logSystem()) << "PTT status: " << pttOn; amTransmitting = pttOn; } void servermain::changeTxBtn() { } void servermain::receiveDataModeStatus(bool dataEnabled) { } void servermain::checkFreqSel() { if(freqTextSelected) { freqTextSelected = false; } } void servermain::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 servermain::changeMode(mode_kind mode, bool dataOn) { } void servermain::receiveBandStackReg(freqt freqGo, char mode, char filter, bool dataOn) { // read the band stack and apply by sending out commands qInfo(logSystem()) << __func__ << "BSR received into main: Freq: " << freqGo.Hz << ", mode: " << (unsigned int)mode << ", filter: " << (unsigned int)filter << ", data mode: " << dataOn; //emit setFrequency(0,freq); issueCmd(cmdSetFreq, freqGo); setModeVal = (unsigned char) mode; setFilterVal = (unsigned char) filter; issueDelayedCommand(cmdSetModeFilter); freq = freqGo; if(dataOn) { issueDelayedCommand(cmdSetDataModeOn); } else { issueDelayedCommand(cmdSetDataModeOff); } //issueDelayedCommand(cmdGetFreq); //issueDelayedCommand(cmdGetMode); } void servermain::bandStackBtnClick() { } void servermain::receiveRfGain(unsigned char level) { } void servermain::receiveAfGain(unsigned char level) { } void servermain::receiveSql(unsigned char level) { } void servermain::receiveIFShift(unsigned char level) { } void servermain::receiveTBPFInner(unsigned char level) { } void servermain::receiveTBPFOuter(unsigned char level) { } void servermain::setRadioTimeDatePrep() { if(!waitingToSetTimeDate) { // 1: Find the current time and date QDateTime now; now = QDateTime::currentDateTime(); now.setTime(QTime::currentTime()); int second = now.time().second(); // 2: Find how many mseconds until next minute int msecdelay = QTime::currentTime().msecsTo( QTime::currentTime().addSecs(60-second) ); // 3: Compute time and date at one minute later QDateTime setpoint = now.addMSecs(msecdelay); // at HMS or posibly HMS + some ms. Never under though. // 4: Prepare data structs for the time at one minute later timesetpoint.hours = (unsigned char)setpoint.time().hour(); timesetpoint.minutes = (unsigned char)setpoint.time().minute(); datesetpoint.day = (unsigned char)setpoint.date().day(); datesetpoint.month = (unsigned char)setpoint.date().month(); datesetpoint.year = (uint16_t)setpoint.date().year(); unsigned int utcOffsetSeconds = (unsigned int)abs(setpoint.offsetFromUtc()); bool isMinus = setpoint.offsetFromUtc() < 0; utcsetting.hours = utcOffsetSeconds / 60 / 60; utcsetting.minutes = (utcOffsetSeconds - (utcsetting.hours*60*60) ) / 60; utcsetting.isMinus = isMinus; timeSync->setInterval(msecdelay); timeSync->setSingleShot(true); // 5: start one-shot timer for the delta computed in #2. timeSync->start(); waitingToSetTimeDate = true; } } void servermain::setRadioTimeDateSend() { // Issue priority commands for UTC offset, date, and time // UTC offset must come first, otherwise the radio may "help" and correct for any changes. issueCmd(cmdSetTime, timesetpoint); issueCmd(cmdSetDate, datesetpoint); issueCmd(cmdSetUTCOffset, utcsetting); waitingToSetTimeDate = false; } void servermain::receiveTxPower(unsigned char power) { } void servermain::receiveMicGain(unsigned char gain) { processModLevel(inputMic, gain); } void servermain::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; } } void servermain::receiveModInput(rigInput input, bool dataOn) { } void servermain::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 servermain::receiveUSBGain(unsigned char level) { processModLevel(inputUSB, level); } void servermain::receiveLANGain(unsigned char level) { processModLevel(inputLAN, level); } void servermain::receiveMeter(meterKind inMeter, unsigned char level) { } void servermain::receiveCompLevel(unsigned char compLevel) { (void)compLevel; } void servermain::receiveMonitorGain(unsigned char monitorGain) { (void)monitorGain; } void servermain::receiveVoxGain(unsigned char voxGain) { (void)voxGain; } void servermain::receiveAntiVoxGain(unsigned char antiVoxGain) { (void)antiVoxGain; } void servermain::receiveSpectrumRefLevel(int level) { } void servermain::changeModLabelAndSlider(rigInput source) { changeModLabel(source, true); } void servermain::changeModLabel(rigInput input) { changeModLabel(input, false); } void servermain::changeModLabel(rigInput input, bool updateLevel) { } void servermain::processChangingCurrentModLevel(unsigned char level) { // slider moved, so find the current mod and issue the level set command. issueCmd(cmdSetModLevel, level); } void servermain::receivePreamp(unsigned char pre) { } void servermain::receiveAttenuator(unsigned char att) { } void servermain::receiveAntennaSel(unsigned char ant, bool rx) { } void servermain::calculateTimingParameters() { // Function for calculating polling parameters. // Requires that we know the "baud rate" of the actual // radio connection. // baud on the serial port reflects the actual rig connection, // even if a client-server connection is being used. // Computed time for a 10 byte message, with a safety factor of 2. if (prefs.serialPortBaud == 0) { prefs.serialPortBaud = 9600; qInfo(logSystem()) << "WARNING: baud rate received was zero. Assuming 9600 baud, performance may suffer."; } unsigned int usPerByte = 9600*1000 / prefs.serialPortBaud; unsigned int msMinTiming=usPerByte * 10*2/1000; if(msMinTiming < 25) msMinTiming = 25; if(haveRigCaps && rigCaps.hasFDcomms) { delayedCommand->setInterval( msMinTiming); // 20 byte message } else { delayedCommand->setInterval( msMinTiming * 3); // 20 byte message } qInfo(logSystem()) << "Delay command interval timing: " << delayedCommand->interval() << "ms"; // Normal: delayedCmdIntervalLAN_ms = delayedCommand->interval(); delayedCmdIntervalSerial_ms = delayedCommand->interval(); // startup initial state: delayedCmdStartupInterval_ms = delayedCommand->interval() * 3; } void servermain::receiveBaudRate(quint32 baud) { qInfo() << "Received serial port baud rate from remote server:" << baud; prefs.serialPortBaud = baud; calculateTimingParameters(); } void servermain::powerRigOn() { emit sendPowerOn(); delayedCommand->setInterval(3000); // 3 seconds issueDelayedCommand(cmdQueNormalSpeed); issueDelayedCommand(cmdStartRegularPolling); // s-meter, etc delayedCommand->start(); } void servermain::powerRigOff() { delayedCommand->stop(); delayedCmdQue.clear(); emit sendPowerOff(); } void servermain::receiveRITStatus(bool ritEnabled) { } void servermain::receiveRITValue(int ritValHz) { } servermain::cmds servermain::meterKindToMeterCommand(meterKind m) { cmds c; switch(m) { case meterNone: c = cmdNone; break; case meterS: c = cmdGetSMeter; break; case meterCenter: c = cmdGetCenterMeter; break; case meterPower: c = cmdGetPowerMeter; break; case meterSWR: c = cmdGetSWRMeter; break; case meterALC: c = cmdGetALCMeter; break; case meterComp: c = cmdGetCompMeter; break; case meterCurrent: c = cmdGetIdMeter; break; case meterVoltage: c = cmdGetVdMeter; break; default: c = cmdNone; break; } return c; } void servermain::handleCtrlC(int sig) { if (sig == 2) { QCoreApplication::quit(); //exit(EXIT_FAILURE); } }