wfview/servermain.cpp

1826 wiersze
58 KiB
C++

#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<udpPreferences>(); // Needs to be registered early.
qRegisterMetaType<rigCapabilities>();
qRegisterMetaType<duplexMode>();
qRegisterMetaType<rptAccessTxRx>();
qRegisterMetaType<rigInput>();
qRegisterMetaType<meterKind>();
qRegisterMetaType<spectrumMode>();
qRegisterMetaType<freqt>();
qRegisterMetaType<mode_info>();
qRegisterMetaType<audioPacket>();
qRegisterMetaType <audioSetup>();
qRegisterMetaType <SERVERCONFIG>();
qRegisterMetaType <timekind>();
qRegisterMetaType <datekind>();
qRegisterMetaType<rigstate*>();
//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<int, std::string> 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<void> 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<freqt>(data));
emit setFrequency(0,f);
break;
}
case cmdSetMode:
{
mode_info m = (*std::static_pointer_cast<mode_info>(data));
emit setMode(m);
break;
}
case cmdSetTxPower:
{
unsigned char txpower = (*std::static_pointer_cast<unsigned char>(data));
emit setTxPower(txpower);
break;
}
case cmdSetMicGain:
{
unsigned char micgain = (*std::static_pointer_cast<unsigned char>(data));
emit setTxPower(micgain);
break;
}
case cmdSetRxRfGain:
{
unsigned char rfgain = (*std::static_pointer_cast<unsigned char>(data));
emit setRfGain(rfgain);
break;
}
case cmdSetModLevel:
{
unsigned char modlevel = (*std::static_pointer_cast<unsigned char>(data));
rigInput currentIn;
if(usingDataMode)
{
currentIn = currentModDataSrc;
} else {
currentIn = currentModSrc;
}
emit setModLevel(currentIn, modlevel);
break;
}
case cmdSetAfGain:
{
unsigned char afgain = (*std::static_pointer_cast<unsigned char>(data));
emit setAfGain(afgain);
break;
}
case cmdSetSql:
{
unsigned char sqlLevel = (*std::static_pointer_cast<unsigned char>(data));
emit setSql(sqlLevel);
break;
}
case cmdSetIFShift:
{
unsigned char IFShiftLevel = (*std::static_pointer_cast<unsigned char>(data));
emit setIFShift(IFShiftLevel);
break;
}
case cmdSetTPBFInner:
{
unsigned char innterLevel = (*std::static_pointer_cast<unsigned char>(data));
emit setTPBFInner(innterLevel);
break;
}
case cmdSetTPBFOuter:
{
unsigned char outerLevel = (*std::static_pointer_cast<unsigned char>(data));
emit setTPBFOuter(outerLevel);
break;
}
case cmdSetPTT:
{
bool pttrequest = (*std::static_pointer_cast<bool>(data));
emit setPTT(pttrequest);
break;
}
case cmdSetATU:
{
bool atuOn = (*std::static_pointer_cast<bool>(data));
emit setATU(atuOn);
break;
}
case cmdSetUTCOffset:
{
timekind u = (*std::static_pointer_cast<timekind>(data));
emit setUTCOffset(u);
break;
}
case cmdSetTime:
{
timekind t = (*std::static_pointer_cast<timekind>(data));
emit setTime(t);
break;
}
case cmdSetDate:
{
datekind d = (*std::static_pointer_cast<datekind>(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<mode_info>(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<freqt>(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<timekind>(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<datekind>(new datekind(d));
delayedCmdQue.push_front(cmddata);
}
void servermain::issueCmd(cmds cmd, int i)
{
commandtype cmddata;
cmddata.cmd = cmd;
cmddata.data = std::shared_ptr<int>(new int(i));
delayedCmdQue.push_back(cmddata);
}
void servermain::issueCmd(cmds cmd, char c)
{
commandtype cmddata;
cmddata.cmd = cmd;
cmddata.data = std::shared_ptr<char>(new char(c));
delayedCmdQue.push_back(cmddata);
}
void servermain::issueCmd(cmds cmd, bool b)
{
commandtype cmddata;
cmddata.cmd = cmd;
cmddata.data = std::shared_ptr<bool>(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<unsigned char>(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<bool>(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<unsigned char>(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<char>(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<freqt>(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);
}
}