Non-working standalone server

merge-requests/9/merge
Phil Taylor 2022-01-26 09:49:52 +00:00
rodzic 5ae3549ba5
commit 4a1be30c40
8 zmienionych plików z 799 dodań i 1701 usunięć

Wyświetl plik

@ -4,6 +4,11 @@
#include <QApplication>
#endif
#ifdef Q_OS_WIN
#include <windows.h>
#include <csignal>
#endif
#include <iostream>
#include "wfmain.h"
#include "logcategories.h"
@ -15,6 +20,29 @@ QScopedPointer<QFile> m_logFile;
QMutex logMutex;
bool debugMode=false;
#ifdef BUILD_WFSERVER
servermain* w=Q_NULLPTR;
#ifdef Q_OS_WIN
bool __stdcall cleanup(DWORD sig)
#else
static void cleanup(int sig)
#endif
{
Q_UNUSED(sig)
qDebug() << "Exiting via SIGNAL";
if (w!=Q_NULLPTR) w->deleteLater();
qApp->quit();
#ifdef Q_OS_WIN
return true;
#else
return;
#endif
}
#endif
void messageHandler(QtMsgType type, const QMessageLogContext& context, const QString& msg);
int main(int argc, char *argv[])
@ -140,9 +168,12 @@ int main(int argc, char *argv[])
qDebug(logSystem()) << QString("CIV as set by parser: %1").arg(civCL);
#ifdef BUILD_WFSERVER
servermain *w = new servermain(serialPortCL, hostCL, settingsFile);
Q_UNUSED(w); // Prevent warning!
#ifdef Q_OS_WIN
SetConsoleCtrlHandler((PHANDLER_ROUTINE)cleanup, TRUE);
#else
signal(SIGINT, cleanup);
#endif
w = new servermain(serialPortCL, hostCL, settingsFile);
#else
a.setWheelScrollLines(1); // one line per wheel click
wfmain w(serialPortCL, hostCL, settingsFile);

Wyświetl plik

@ -22,11 +22,20 @@
rigCommander::rigCommander()
{
state.set(SCOPEFUNC,true,false);
qInfo(logRig()) << "creating instance of rigCommander()";
state.set(SCOPEFUNC, true, false);
}
rigCommander::rigCommander(quint8 guid[16])
{
qInfo(logRig()) << "creating instance of rigCommander()";
state.set(SCOPEFUNC, true, false);
memcpy(this->guid, guid, sizeof(this->guid));
}
rigCommander::~rigCommander()
{
qInfo(logRig()) << "closing instance of rigCommander()";
closeComm();
}
@ -40,13 +49,14 @@ void rigCommander::commSetup(unsigned char rigCivAddr, QString rigSerialPort, qu
// civAddr = 0x94; // address of the radio. Decimal is 148.
civAddr = rigCivAddr; // address of the radio. Decimal is 148.
usingNativeLAN = false;
//qInfo(logRig()) << "Opening connection to Rig:" << hex << (unsigned char)rigCivAddr << "on serial port" << rigSerialPort << "at baud rate" << rigBaudRate;
// ---
setup();
// ---
this->rigSerialPort = rigSerialPort;
this->rigBaudRate = rigBaudRate;
rigCaps.baudRate = rigBaudRate;
comm = new commHandler(rigSerialPort, rigBaudRate);
ptty = new pttyHandler(vsp);
@ -217,6 +227,7 @@ bool rigCommander::usingLAN()
}
void rigCommander::receiveBaudRate(quint32 baudrate) {
rigCaps.baudRate = baudrate;
emit haveBaudRate(baudrate);
}
@ -3612,6 +3623,9 @@ void rigCommander::determineRigCaps()
}
haveRigCaps = true;
// Copy received guid so we can recognise this radio.
memcpy(rigCaps.guid, this->guid, sizeof(rigCaps.guid));
if(!usingNativeLAN)
{
if(useRTSforPTT_isSet)
@ -4676,6 +4690,9 @@ void rigCommander::dataFromServer(QByteArray data)
emit dataForComm(data);
}
quint8* rigCommander::getGUID() {
return guid;
}

Wyświetl plik

@ -69,13 +69,16 @@ class rigCommander : public QObject
public:
rigCommander();
rigCommander(quint8 guid[16]);
~rigCommander();
bool usingLAN();
quint8* getGUID();
public slots:
void process();
void commSetup(unsigned char rigCivAddr, QString rigSerialPort, quint32 rigBaudRate,QString vsp);
void commSetup(unsigned char rigCivAddr, QString rigSerialPort, quint32 rigBaudRate, QString vsp);
void commSetup(unsigned char rigCivAddr, udpPreferences prefs, audioSetup rxSetup, audioSetup txSetup, QString vsp);
void closeComm();
void stateUpdated();
@ -475,7 +478,7 @@ private:
QString serialPortError;
unsigned char localVolume=0;
quint8 guid[16] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
};

Wyświetl plik

@ -138,6 +138,8 @@ struct rigCapabilities {
std::vector <mode_info> modes;
QByteArray transceiveCommand;
quint8 guid[16] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
quint32 baudRate;
};

Plik diff jest za duży Load Diff

Wyświetl plik

@ -168,30 +168,24 @@ private slots:
void receiveCommReady();
void receivePTTstatus(bool pttOn);
void receiveRigID(rigCapabilities rigCaps);
void receiveFoundRigID(rigCapabilities rigCaps);
void receiveSerialPortError(QString port, QString errorText);
void sendRadioCommandLoop();
void receiveBaudRate(quint32 baudrate);
void handlePttLimit();
void receiveStatusUpdate(QString text);
void receiveStatusUpdate(networkStatus status);
void receiveStateInfo(rigstate* state);
private:
QSettings *settings=Q_NULLPTR;
void loadSettings();
void getInitialRigState();
void openRig();
void powerRigOff();
void powerRigOn();
QStringList portList;
QString serialPortRig;
rigCommander * rig=Q_NULLPTR;
QThread* rigThread = Q_NULLPTR;
QTimer * delayedCommand;
QTimer * pttTimer;
uint16_t loopTickCounter;
@ -199,7 +193,6 @@ private:
QString lastMessage="";
void makeRig();
void rigConnections();
void removeRig();
void findSerialPort();
@ -235,119 +228,19 @@ private:
unsigned char setModeVal=0;
unsigned char setFilterVal=0;
enum cmds {cmdNone, cmdGetRigID, cmdGetRigCIV, cmdGetFreq, cmdSetFreq, cmdGetMode, cmdSetMode,
cmdGetDataMode, cmdSetModeFilter, cmdSetDataModeOn, cmdSetDataModeOff, cmdGetRitEnabled, cmdGetRitValue,
cmdSpecOn, cmdSpecOff, cmdDispEnable, cmdDispDisable, cmdGetRxGain, cmdSetRxRfGain, cmdGetAfGain, cmdSetAfGain,
cmdGetSql, cmdSetSql, cmdGetIFShift, cmdSetIFShift, cmdGetTPBFInner, cmdSetTPBFInner,
cmdGetTPBFOuter, cmdSetTPBFOuter, cmdGetATUStatus,
cmdSetATU, cmdStartATU, cmdGetSpectrumMode,
cmdGetSpectrumSpan, cmdScopeCenterMode, cmdScopeFixedMode, cmdGetPTT, cmdSetPTT,
cmdGetTxPower, cmdSetTxPower, cmdGetMicGain, cmdSetMicGain, cmdSetModLevel,
cmdGetSpectrumRefLevel, cmdGetDuplexMode, cmdGetModInput, cmdGetModDataInput,
cmdGetCurrentModLevel, cmdStartRegularPolling, cmdStopRegularPolling, cmdQueNormalSpeed,
cmdGetVdMeter, cmdGetIdMeter, cmdGetSMeter, cmdGetCenterMeter, cmdGetPowerMeter,
cmdGetSWRMeter, cmdGetALCMeter, cmdGetCompMeter, cmdGetTxRxMeter,
cmdGetTone, cmdGetTSQL, cmdGetDTCS, cmdGetRptAccessMode, cmdGetPreamp, cmdGetAttenuator, cmdGetAntenna,
cmdSetTime, cmdSetDate, cmdSetUTCOffset};
struct commandtype {
cmds cmd;
std::shared_ptr<void> data;
};
std::deque <commandtype> delayedCmdQue; // rapid que for commands to the radio
std::deque <cmds> periodicCmdQueue; // rapid que for metering
std::deque <cmds> slowPollCmdQueue; // slow, regular checking for UI sync
void doCmd(cmds cmd);
void doCmd(commandtype cmddata);
void issueCmd(cmds cmd, freqt f);
void issueCmd(cmds cmd, mode_info m);
void issueCmd(cmds cmd, timekind t);
void issueCmd(cmds cmd, datekind d);
void issueCmd(cmds cmd, int i);
void issueCmd(cmds cmd, unsigned char c);
void issueCmd(cmds cmd, char c);
void issueCmd(cmds cmd, bool b);
// These commands pop_front and remove similar commands:
void issueCmdUniquePriority(cmds cmd, bool b);
void issueCmdUniquePriority(cmds cmd, unsigned char c);
void issueCmdUniquePriority(cmds cmd, char c);
void issueCmdUniquePriority(cmds cmd, freqt f);
void removeSimilarCommand(cmds cmd);
qint64 lastFreqCmdTime_ms;
int pCmdNum = 0;
int delayedCmdIntervalLAN_ms = 100;
int delayedCmdIntervalSerial_ms = 100;
int delayedCmdStartupInterval_ms = 100;
bool runPeriodicCommands;
bool usingLAN = false;
// Radio time sync:
QTimer *timeSync;
bool waitingToSetTimeDate;
void setRadioTimeDatePrep();
timekind timesetpoint;
timekind utcsetting;
datekind datesetpoint;
freqMemory mem;
struct colors {
QColor Dark_PlotBackground;
QColor Dark_PlotAxisPen;
QColor Dark_PlotLegendTextColor;
QColor Dark_PlotLegendBorderPen;
QColor Dark_PlotLegendBrush;
QColor Dark_PlotTickLabel;
QColor Dark_PlotBasePen;
QColor Dark_PlotTickPen;
QColor Dark_PeakPlotLine;
QColor Dark_TuningLine;
QColor Light_PlotBackground;
QColor Light_PlotAxisPen;
QColor Light_PlotLegendTextColor;
QColor Light_PlotLegendBorderPen;
QColor Light_PlotLegendBrush;
QColor Light_PlotTickLabel;
QColor Light_PlotBasePen;
QColor Light_PlotTickPen;
QColor Light_PeakPlotLine;
QColor Light_TuningLine;
} colorScheme;
struct preferences {
bool useFullScreen;
bool useDarkMode;
bool useSystemTheme;
bool drawPeaks;
bool wfAntiAlias;
bool wfInterpolate;
QString stylesheetPath;
unsigned char radioCIVAddr;
bool CIVisRadioModel;
bool forceRTSasPTT;
QString serialPortRadio;
quint32 serialPortBaud;
bool enablePTT;
bool niceTS;
bool enableLAN;
bool enableRigCtlD;
quint16 rigCtlPort;
colors colorScheme;
QString virtualSerialPort;
unsigned char localAFgain;
unsigned int wflength;
int wftheme;
bool confirmExit;
bool confirmPowerOff;
meterKind meter2Type;
// plot scheme
audioSetup rxAudio;
audioSetup txAudio;
rigCapabilities rigCaps;
bool haveRigCaps = false;
} prefs;
preferences defPrefs;
@ -361,35 +254,9 @@ private:
audioSetup serverRxSetup;
audioSetup serverTxSetup;
colors defaultColors;
void setDefPrefs(); // populate default values to default prefs
void issueDelayedCommand(cmds cmd);
void issueDelayedCommandPriority(cmds cmd);
void issueDelayedCommandUnique(cmds cmd);
// Fast command queue:
void initPeriodicCommands();
void insertPeriodicCommand(cmds cmd, unsigned char priority);
void insertPeriodicCommandUnique(cmds cmd);
void removePeriodicCommand(cmds cmd);
void insertSlowPeriodicCommand(cmds cmd, unsigned char priority);
void calculateTimingParameters();
cmds meterKindToMeterCommand(meterKind m);
int oldFreqDialVal;
rigCapabilities rigCaps;
rigInput currentModSrc = inputUnknown;
rigInput currentModDataSrc = inputUnknown;
mode_kind currentMode = modeUSB;
mode_info currentModeInfo;
bool haveRigCaps;
bool amTransmitting;
bool usingDataMode = false;
@ -405,33 +272,9 @@ private:
rigCtlD* rigCtl = Q_NULLPTR;
QThread* serverThread = Q_NULLPTR;
void bandStackBtnClick();
bool waitingForBandStackRtn;
char bandStkBand;
char bandStkRegCode;
bool freqLock;
float tsPlus;
float tsPlusShift;
float tsPlusControl;
float tsPage;
float tsPageShift;
float tsWfScroll;
unsigned int tsPlusHz;
unsigned int tsPlusShiftHz;
unsigned int tsPlusControlHz;
unsigned int tsPageHz;
unsigned int tsPageShiftHz;
unsigned int tsWfScrollHz;
unsigned int tsKnobHz;
rigstate* rigState = Q_NULLPTR;
SERVERCONFIG serverConfig;
static void handleCtrlC(int sig);
};
Q_DECLARE_METATYPE(struct rigCapabilities)

Wyświetl plik

@ -4,8 +4,8 @@
#define STALE_CONNECTION 15
#define LOCK_PERIOD 10 // time to attempt to lock Mutex in ms
#define AUDIO_SEND_PERIOD 20 //
udpServer::udpServer(SERVERCONFIG config, audioSetup outAudio, audioSetup inAudio) :
config(config),
udpServer::udpServer(SERVERCONFIG* config, audioSetup outAudio, audioSetup inAudio) :
config(*config),
outAudio(outAudio),
inAudio(inAudio)
{
@ -15,6 +15,31 @@ udpServer::udpServer(SERVERCONFIG config, audioSetup outAudio, audioSetup inAudi
void udpServer::init()
{
for (RIGCONFIG rig : config.rigs)
{
qDebug(logUdpServer()) << "CIV:" << rig.civAddr;
qDebug(logUdpServer()) << "Model:" << rig.modelName;
qDebug(logUdpServer()) << "Name:" << rig.rigName;
qDebug(logUdpServer()) << "CIV:" << rig.civAddr;
qDebug(logUdpServer()).noquote() << QString("GUID: {%1%2%3%4-%5%6-%7%8-%9%10-%11%12%13%14%15%16}")
.arg(rig.guid[0], 2, 16, QLatin1Char('0'))
.arg(rig.guid[1], 2, 16, QLatin1Char('0'))
.arg(rig.guid[2], 2, 16, QLatin1Char('0'))
.arg(rig.guid[3], 2, 16, QLatin1Char('0'))
.arg(rig.guid[4], 2, 16, QLatin1Char('0'))
.arg(rig.guid[5], 2, 16, QLatin1Char('0'))
.arg(rig.guid[6], 2, 16, QLatin1Char('0'))
.arg(rig.guid[7], 2, 16, QLatin1Char('0'))
.arg(rig.guid[8], 2, 16, QLatin1Char('0'))
.arg(rig.guid[9], 2, 16, QLatin1Char('0'))
.arg(rig.guid[10], 2, 16, QLatin1Char('0'))
.arg(rig.guid[11], 2, 16, QLatin1Char('0'))
.arg(rig.guid[12], 2, 16, QLatin1Char('0'))
.arg(rig.guid[13], 2, 16, QLatin1Char('0'))
.arg(rig.guid[14], 2, 16, QLatin1Char('0'))
.arg(rig.guid[15], 2, 16, QLatin1Char('0'))
;
}
srand(time(NULL)); // Generate random key
timeStarted.start();
// Convoluted way to find the external IP address, there must be a better way????
@ -112,7 +137,17 @@ udpServer::~udpServer()
void udpServer::receiveRigCaps(rigCapabilities caps)
{
this->rigCaps = caps;
for (RIGCONFIG &rig: config.rigs) {
if (!memcmp(rig.guid, caps.guid, sizeof(rig.guid))) {
// Matching rig, fill-in missing details
rig.rigAvailable = true;
rig.modelName = caps.modelName;
rig.civAddr = caps.civ;
if (rig.rigName=="<NONE>") {
rig.rigName = caps.modelName;
}
}
}
}
void udpServer::controlReceived()
@ -164,8 +199,6 @@ void udpServer::controlReceived()
connect(current->retransmitTimer, &QTimer::timeout, this, std::bind(&udpServer::sendRetransmitRequest, this, current));
current->retransmitTimer->start(RETRANSMIT_PERIOD);
current->commonCap = 0x8010;
qInfo(logUdpServer()) << current->ipAddress.toString() << ": New Control connection created";
if (connMutex.try_lock_for(std::chrono::milliseconds(LOCK_PERIOD)))
@ -234,7 +267,9 @@ void udpServer::controlReceived()
// Request for new token
qInfo(logUdpServer()) << current->ipAddress.toString() << ": Received create token request";
sendCapabilities(current);
sendConnectionInfo(current);
for (RIGCONFIG& radio : config.rigs) {
sendConnectionInfo(current, radio.guid);
}
}
else if (in->res == 0x01) {
// Token disconnect
@ -245,7 +280,12 @@ void udpServer::controlReceived()
// Disconnect audio/civ
sendTokenResponse(current, in->res);
current->isStreaming = false;
sendConnectionInfo(current);
for (RIGCONFIG& radio : config.rigs) {
if (!memcmp(radio.guid, current->guid, sizeof(radio.guid)))
{
sendConnectionInfo(current, radio.guid);
}
}
}
else {
qInfo(logUdpServer()) << current->ipAddress.toString() << ": Received token request";
@ -301,10 +341,10 @@ void udpServer::controlReceived()
current->txBufferLen = qFromBigEndian<quint32>(in->txbuffer);
current->authInnerSeq = in->innerseq;
memcpy(current->macaddress, in->macaddress, 6);
memcpy(current->guid, in->guid, sizeof(in->guid));
sendStatus(current);
current->authInnerSeq = 0x00;
sendConnectionInfo(current);
sendConnectionInfo(current,in->guid);
qInfo(logUdpServer()) << current->ipAddress.toString() << ": rxCodec:" << current->rxCodec << " txCodec:" << current->txCodec <<
" rxSampleRate" << current->rxSampleRate <<
" txSampleRate" << current->txSampleRate <<
@ -316,55 +356,62 @@ void udpServer::controlReceived()
audioSetup setup;
setup.resampleQuality = config.resampleQuality;
for (RIGCONFIG& radio : config.rigs) {
if (!memcmp(radio.guid, current->guid, sizeof(radio.guid)) && radio.txaudio == Q_NULLPTR)
{
radio.txAudioSetup.codec = current->txCodec;
radio.txAudioSetup.samplerate = current->txSampleRate;
radio.txAudioSetup.isinput = false;
radio.txAudioSetup.latency = current->txBufferLen;
outAudio.isinput = false;
if (txaudio == Q_NULLPTR)
{
outAudio.codec = current->txCodec;
outAudio.samplerate = current->txSampleRate;
outAudio.isinput = false;
outAudio.latency = current->txBufferLen;
outAudio.isinput = false;
radio.txaudio = new audioHandler();
radio.txAudioThread = new QThread(this);
txaudio = new audioHandler();
txAudioThread = new QThread(this);
radio.txaudio->moveToThread(radio.txAudioThread);
txaudio->moveToThread(txAudioThread);
radio.txAudioThread->start(QThread::TimeCriticalPriority);
txAudioThread->start(QThread::TimeCriticalPriority);
//connect(this, SIGNAL(setupTxAudio(audioSetup)), txaudio, SLOT(init(audioSetup)));
connect(radio.txAudioThread, SIGNAL(finished()), radio.txaudio, SLOT(deleteLater()));
connect(this, SIGNAL(setupTxAudio(audioSetup)), txaudio, SLOT(init(audioSetup)));
connect(txAudioThread, SIGNAL(finished()), txaudio, SLOT(deleteLater()));
QMetaObject::invokeMethod(radio.txaudio, [=]() {
radio.txaudio->init(radio.txAudioSetup);
}, Qt::QueuedConnection);
emit setupTxAudio(outAudio);
hasTxAudio = datagram.senderAddress();
emit setupTxAudio(outAudio);
hasTxAudio = datagram.senderAddress();
connect(this, SIGNAL(haveAudioData(audioPacket)), txaudio, SLOT(incomingAudio(audioPacket)));
connect(this, SIGNAL(haveAudioData(audioPacket)), radio.txaudio, SLOT(incomingAudio(audioPacket)));
}
if (rxaudio == Q_NULLPTR)
{
inAudio.codec = current->rxCodec;
inAudio.samplerate = current->rxSampleRate;
inAudio.latency = current->txBufferLen;
inAudio.isinput = true;
}
if (!memcmp(radio.guid, current->guid, sizeof(radio.guid)) && radio.rxaudio == Q_NULLPTR)
{
radio.rxAudioSetup.codec = current->rxCodec;
radio.rxAudioSetup.samplerate = current->rxSampleRate;
radio.rxAudioSetup.latency = current->txBufferLen;
radio.rxAudioSetup.isinput = true;
rxaudio = new audioHandler();
radio.rxaudio = new audioHandler();
rxAudioThread = new QThread(this);
radio.rxAudioThread = new QThread(this);
rxaudio->moveToThread(rxAudioThread);
radio.rxaudio->moveToThread(radio.rxAudioThread);
rxAudioThread->start(QThread::TimeCriticalPriority);
radio.rxAudioThread->start(QThread::TimeCriticalPriority);
connect(this, SIGNAL(setupRxAudio(audioSetup)), rxaudio, SLOT(init(audioSetup)));
connect(rxAudioThread, SIGNAL(finished()), rxaudio, SLOT(deleteLater()));
//connect(this, SIGNAL(setupRxAudio(audioSetup)), rxaudio, SLOT(init(audioSetup)));
connect(radio.rxAudioThread, SIGNAL(finished()), radio.rxaudio, SLOT(deleteLater()));
emit setupRxAudio(inAudio);
QMetaObject::invokeMethod(radio.rxaudio, [=]() {
radio.rxaudio->init(radio.rxAudioSetup);
}, Qt::QueuedConnection);
rxAudioTimer = new QTimer();
rxAudioTimer->setTimerType(Qt::PreciseTimer);
connect(rxAudioTimer, &QTimer::timeout, this, std::bind(&udpServer::sendRxAudio, this));
rxAudioTimer->start(TXAUDIO_PERIOD);
radio.rxAudioTimer = new QTimer();
radio.rxAudioTimer->setTimerType(Qt::PreciseTimer);
connect(radio.rxAudioTimer, &QTimer::timeout, this, std::bind(&udpServer::sendRxAudio, this));
radio.rxAudioTimer->start(TXAUDIO_PERIOD);
}
}
}
@ -420,6 +467,7 @@ void udpServer::civReceived()
{
current->controlClient = client;
client->civClient = current;
memcpy(current->guid, client->guid, sizeof(current->guid));
}
}
}
@ -518,9 +566,18 @@ void udpServer::civReceived()
qDebug(logUdpServer()) << current->ipAddress.toString() << ": Detected different remote CI-V:" << hex << current->civId; qInfo(logUdpServer()) << current->ipAddress.toString() << ": Detected different remote CI-V:" << hex << current->civId;
} else if (r.length() > lastFE+2 && (quint8)r[lastFE+2] != 0xE1) {
qDebug(logUdpServer()) << current->ipAddress.toString() << ": Detected invalid remote CI-V:" << hex << (quint8)r[lastFE+2];
}
}
for (RIGCONFIG& radio : config.rigs) {
if (!memcmp(radio.guid, current->guid, sizeof(radio.guid)))
{
// Only send to the rig that it belongs to!
QMetaObject::invokeMethod(radio.rig, [=]() {
radio.rig->dataFromServer(r.mid(0x15));;
}, Qt::DirectConnection);
}
}
emit haveDataFromServer(r.mid(0x15));
}
else {
qInfo(logUdpServer()) << current->ipAddress.toString() << ": Datalen mismatch " << quint16(in->datalen + 0x15) << ":" << (quint16)in->len;
@ -571,6 +628,7 @@ void udpServer::audioReceived()
{
current->controlClient = client;
client->audioClient = current;
memcpy(current->guid, client->guid, sizeof(current->guid));
}
}
}
@ -743,7 +801,7 @@ void udpServer::commonReceived(QList<CLIENT*>* l, CLIENT* current, QByteArray r)
}
default:
{
//break;
//break
}
}
@ -1036,13 +1094,8 @@ void udpServer::sendLoginResponse(CLIENT* c, bool allowed)
void udpServer::sendCapabilities(CLIENT* c)
{
qInfo(logUdpServer()) << c->ipAddress.toString() << "(" << c->type << "): Sending Capabilities :" << c->txSeq;
capabilities_packet p;
radio_cap_packet r;
memset(p.packet, 0x0, sizeof(p)); // We can't be sure it is initialized with 0x00!
memset(r.packet, 0x0, sizeof(r)); // We can't be sure it is initialized with 0x00!
p.len = sizeof(p);
p.type = 0x00;
p.seq = c->txSeq;
p.sentid = c->myId;
@ -1050,79 +1103,86 @@ void udpServer::sendCapabilities(CLIENT* c)
p.innerseq = c->authInnerSeq;
p.tokrequest = c->tokenRx;
p.token = c->tokenTx;
p.payloadsize = sizeof(p)-0x0f;
p.res = 0x0202;
p.numradios = 0x01;
r.commoncap = c->commonCap;
memcpy(r.macaddress, macAddress.toLocal8Bit(), 6);
// IRU seems to expect an "Icom" mac address so replace the first 3 octets of our Mac with one in their range!
memcpy(r.macaddress, QByteArrayLiteral("\x00\x90\xc7").constData(), 3);
memcpy(r.name, rigCaps.modelName.toLocal8Bit(), rigCaps.modelName.length());
memcpy(r.audio, QByteArrayLiteral("ICOM_VAUDIO").constData(), 11);
if (rigCaps.hasWiFi && !rigCaps.hasEthernet) {
r.conntype = 0x0707; // 0x0707 for wifi rig.
}
else {
r.conntype = 0x073f; // 0x073f for ethernet rig.
}
r.civ = rigCaps.civ;
r.baudrate = (quint32)qToBigEndian(config.baudRate);
/*
0x80 = 12K only
0x40 = 44.1K only
0x20 = 22.05K only
0x10 = 11.025K only
0x08 = 48K only
0x04 = 32K only
0x02 = 16K only
0x01 = 8K only
*/
if (rxaudio == Q_NULLPTR) {
r.rxsample = 0x8b01; // all rx sample frequencies supported
}
else {
if (rxSampleRate == 48000) {
r.rxsample = 0x0800; // fixed rx sample frequency
}
else if (rxSampleRate == 32000) {
r.rxsample = 0x0400;
}
else if (rxSampleRate == 24000) {
r.rxsample = 0x0001;
}
else if (rxSampleRate == 16000) {
r.rxsample = 0x0200;
}
else if (rxSampleRate == 12000) {
r.rxsample = 0x8000;
}
}
if (txaudio == Q_NULLPTR) {
r.txsample = 0x8b01; // all tx sample frequencies supported
r.enablea = 0x01; // 0x01 enables TX 24K mode?
qInfo(logUdpServer()) << c->ipAddress.toString() << "(" << c->type << "): Client will have TX audio";
}
else {
qInfo(logUdpServer()) << c->ipAddress.toString() << "(" << c->type << "): Disable tx audio for client";
r.txsample = 0;
}
// I still don't know what these are?
r.enableb = 0x01; // 0x01 doesn't seem to do anything?
r.enablec = 0x01; // 0x01 doesn't seem to do anything?
r.capf = 0x5001;
r.capg = 0x0190;
p.numradios = config.rigs.count();
SEQBUFENTRY s;
s.seqNum = p.seq;
s.timeSent = QTime::currentTime();
s.retransmitCount = 0;
s.data = QByteArray::fromRawData((const char*)p.packet, sizeof(p));
s.data.append(QByteArray::fromRawData((const char*)r.packet, sizeof(r)));
for (RIGCONFIG &rig : config.rigs) {
qInfo(logUdpServer()) << c->ipAddress.toString() << "(" << c->type << "): Sending Capabilities :" << c->txSeq << "for" << rig.modelName;
radio_cap_packet r;
memset(r.packet, 0x0, sizeof(r)); // We can't be sure it is initialized with 0x00!
memcpy(r.guid, rig.guid, sizeof(r.guid));
memcpy(r.name, rig.rigName.toLocal8Bit(), sizeof(r.name));
memcpy(r.audio, QByteArrayLiteral("ICOM_VAUDIO").constData(), 11);
if (rig.hasWiFi && !rig.hasEthernet) {
r.conntype = 0x0707; // 0x0707 for wifi rig.
}
else {
r.conntype = 0x073f; // 0x073f for ethernet rig.
}
r.civ = rig.civAddr;
r.baudrate = (quint32)qToBigEndian(rig.baudRate);
/*
0x80 = 12K only
0x40 = 44.1K only
0x20 = 22.05K only
0x10 = 11.025K only
0x08 = 48K only
0x04 = 32K only
0x02 = 16K only
0x01 = 8K only
*/
if (rig.rxaudio == Q_NULLPTR) {
r.rxsample = 0x8b01; // all rx sample frequencies supported
}
else {
if (rxSampleRate == 48000) {
r.rxsample = 0x0800; // fixed rx sample frequency
}
else if (rxSampleRate == 32000) {
r.rxsample = 0x0400;
}
else if (rxSampleRate == 24000) {
r.rxsample = 0x0001;
}
else if (rxSampleRate == 16000) {
r.rxsample = 0x0200;
}
else if (rxSampleRate == 12000) {
r.rxsample = 0x8000;
}
}
if (rig.txaudio == Q_NULLPTR) {
r.txsample = 0x8b01; // all tx sample frequencies supported
r.enablea = 0x01; // 0x01 enables TX 24K mode?
qInfo(logUdpServer()) << c->ipAddress.toString() << "(" << c->type << "): Client will have TX audio";
}
else {
qInfo(logUdpServer()) << c->ipAddress.toString() << "(" << c->type << "): Disable tx audio for client";
r.txsample = 0;
}
// I still don't know what these are?
r.enableb = 0x01; // 0x01 doesn't seem to do anything?
r.enablec = 0x01; // 0x01 doesn't seem to do anything?
r.capf = 0x5001;
r.capg = 0x0190;
s.data.append(QByteArray::fromRawData((const char*)r.packet, sizeof(r)));
}
p.len = sizeof(p)+s.data.length();
p.payloadsize = sizeof(p)+s.data.length() - 0x0f;
s.data.insert(0,QByteArray::fromRawData((const char*)p.packet, sizeof(p)));
if (c->txMutex.try_lock_for(std::chrono::milliseconds(LOCK_PERIOD)))
{
if (c->txSeqBuf.size() > BUFSIZE)
@ -1155,68 +1215,79 @@ void udpServer::sendCapabilities(CLIENT* c)
// When client has requested civ/audio connection, this will contain their details
// Also used to display currently connected used information.
void udpServer::sendConnectionInfo(CLIENT* c)
void udpServer::sendConnectionInfo(CLIENT* c, quint8 guid[16])
{
qInfo(logUdpServer()) << c->ipAddress.toString() << "(" << c->type << "): Sending ConnectionInfo :" << c->txSeq;
conninfo_packet p;
memset(p.packet, 0x0, sizeof(p));
p.len = sizeof(p);
p.type = 0x00;
p.seq = c->txSeq;
p.sentid = c->myId;
p.rcvdid = c->remoteId;
//p.innerseq = c->authInnerSeq; // Innerseq not used in user packet
p.tokrequest = c->tokenRx;
p.token = c->tokenTx;
p.code = 0x0380;
p.commoncap = c->commonCap;
memcpy(p.macaddress, c->macaddress, 6);
// 0x1a-0x1f is authid (random number?
// memcpy(p + 0x40, QByteArrayLiteral("IC-7851").constData(), 7);
memcpy(p.packet + 0x40, rigCaps.modelName.toLocal8Bit(), rigCaps.modelName.length());
// This is the current streaming client (should we support multiple clients?)
if (c->isStreaming) {
p.busy = 0x01;
memcpy(p.computer, c->clientName.constData(), c->clientName.length());
p.ipaddress = qToBigEndian(c->ipAddress.toIPv4Address());
memcpy(p.macaddress, c->macaddress, 6);
}
SEQBUFENTRY s;
s.seqNum = p.seq;
s.timeSent = QTime::currentTime();
s.retransmitCount = 0;
s.data = QByteArray::fromRawData((const char*)p.packet, sizeof(p));
if (c->txMutex.try_lock_for(std::chrono::milliseconds(LOCK_PERIOD)))
{
if (c->txSeqBuf.size() > BUFSIZE)
for (RIGCONFIG& radio : config.rigs) {
if (!memcmp(guid, radio.guid, sizeof(guid)))
{
c->txSeqBuf.remove(c->txSeqBuf.firstKey());
qInfo(logUdpServer()) << c->ipAddress.toString() << "(" << c->type << "): Sending ConnectionInfo :" << c->txSeq;
conninfo_packet p;
memset(p.packet, 0x0, sizeof(p));
p.len = sizeof(p);
p.type = 0x00;
p.seq = c->txSeq;
p.sentid = c->myId;
p.rcvdid = c->remoteId;
//p.innerseq = c->authInnerSeq; // Innerseq not used in user packet
p.tokrequest = c->tokenRx;
p.token = c->tokenTx;
p.code = 0x0380;
memcpy(p.guid, radio.guid, sizeof(p.guid));
memcpy(p.name, radio.rigName.toLocal8Bit(), sizeof(p.name));
if (radio.rigAvailable) {
if (c->isStreaming) {
p.busy = 0x01;
}
else {
p.busy = 0x00;
}
}
else
{
p.busy = 0x02;
}
// This is the current streaming client (should we support multiple clients?)
if (c->isStreaming) {
memcpy(p.computer, c->clientName.constData(), c->clientName.length());
p.ipaddress = qToBigEndian(c->ipAddress.toIPv4Address());
}
SEQBUFENTRY s;
s.seqNum = p.seq;
s.timeSent = QTime::currentTime();
s.retransmitCount = 0;
s.data = QByteArray::fromRawData((const char*)p.packet, sizeof(p));
if (c->txMutex.try_lock_for(std::chrono::milliseconds(LOCK_PERIOD)))
{
if (c->txSeqBuf.size() > BUFSIZE)
{
c->txSeqBuf.remove(c->txSeqBuf.firstKey());
}
c->txSeqBuf.insert(p.seq, s);
c->txSeq++;
c->txMutex.unlock();
}
else {
qInfo(logUdpServer()) << "Unable to lock txMutex()";
}
if (udpMutex.try_lock_for(std::chrono::milliseconds(LOCK_PERIOD)))
{
c->socket->writeDatagram(QByteArray::fromRawData((const char*)p.packet, sizeof(p)), c->ipAddress, c->port);
udpMutex.unlock();
}
else {
qInfo(logUdpServer()) << "Unable to lock udpMutex()";
}
}
c->txSeqBuf.insert(p.seq, s);
c->txSeq++;
c->txMutex.unlock();
}
else {
qInfo(logUdpServer()) << "Unable to lock txMutex()";
}
if (udpMutex.try_lock_for(std::chrono::milliseconds(LOCK_PERIOD)))
{
c->socket->writeDatagram(QByteArray::fromRawData((const char*)p.packet, sizeof(p)), c->ipAddress, c->port);
udpMutex.unlock();
}
else {
qInfo(logUdpServer()) << "Unable to lock udpMutex()";
}
if (c->idleTimer != Q_NULLPTR)
c->idleTimer->start(100);
@ -1395,84 +1466,108 @@ void udpServer::sendStatus(CLIENT* c)
void udpServer::dataForServer(QByteArray d)
{
//qInfo(logUdpServer()) << "Server got:" << d;
foreach(CLIENT * client, civClients)
rigCommander* sender = qobject_cast<rigCommander*>(QObject::sender());
if (sender == Q_NULLPTR)
{
int lastFE = d.lastIndexOf((quint8)0xfe);
if (client != Q_NULLPTR && client->connected && d.length() > lastFE + 2 &&
((quint8)d[lastFE + 1] == client->civId || (quint8)d[lastFE + 2] == client->civId ||
(quint8)d[lastFE + 1] == 0x00 || (quint8)d[lastFE + 2]==0x00 || (quint8)d[lastFE + 1] == 0xE1 || (quint8)d[lastFE + 2] == 0xE1)) {
data_packet p;
memset(p.packet, 0x0, sizeof(p)); // We can't be sure it is initialized with 0x00!
p.len = (quint16)d.length() + sizeof(p);
p.seq = client->txSeq;
p.sentid = client->myId;
p.rcvdid = client->remoteId;
p.reply = (char)0xc1;
p.datalen = (quint16)d.length();
p.sendseq = client->innerSeq;
QByteArray t = QByteArray::fromRawData((const char*)p.packet, sizeof(p));
t.append(d);
SEQBUFENTRY s;
s.seqNum = p.seq;
s.timeSent = QTime::currentTime();
s.retransmitCount = 0;
s.data = t;
if (client->txMutex.try_lock_for(std::chrono::milliseconds(LOCK_PERIOD)))
{
if (client->txSeqBuf.size() > BUFSIZE)
{
client->txSeqBuf.remove(client->txSeqBuf.firstKey());
}
client->txSeqBuf.insert(p.seq, s);
client->txSeq++;
client->innerSeq++;
client->txMutex.unlock();
}
else {
qInfo(logUdpServer()) << "Unable to lock txMutex()";
}
if (udpMutex.try_lock_for(std::chrono::milliseconds(LOCK_PERIOD)))
{
client->socket->writeDatagram(t, client->ipAddress, client->port);
udpMutex.unlock();
}
else {
qInfo(logUdpServer()) << "Unable to lock udpMutex()";
}
} else {
qInfo(logUdpServer()) << "Got data for different ID" << hex << (quint8)d[lastFE+1] << ":" << hex << (quint8)d[lastFE+2];
}
return;
}
for (CLIENT* client : civClients)
{
if (client == Q_NULLPTR || !client->connected)
{
continue;
}
for (RIGCONFIG& radio : config.rigs)
{
if (memcmp(radio.guid, client->guid, sizeof(radio.guid)))
{
continue;
}
int lastFE = d.lastIndexOf((quint8)0xfe);
// Use the GUID to determine which radio the response is from
qInfo(logUdpServer()) << "Server got CIV data from" << radio.rigName << "length" << d.length();
if (client->connected && d.length() > lastFE + 2 &&
((quint8)d[lastFE + 1] == client->civId || (quint8)d[lastFE + 2] == client->civId ||
(quint8)d[lastFE + 1] == 0x00 || (quint8)d[lastFE + 2] == 0x00 || (quint8)d[lastFE + 1] == 0xE1 || (quint8)d[lastFE + 2] == 0xE1))
{
data_packet p;
memset(p.packet, 0x0, sizeof(p)); // We can't be sure it is initialized with 0x00!
p.len = (quint16)d.length() + sizeof(p);
p.seq = client->txSeq;
p.sentid = client->myId;
p.rcvdid = client->remoteId;
p.reply = (char)0xc1;
p.datalen = (quint16)d.length();
p.sendseq = client->innerSeq;
QByteArray t = QByteArray::fromRawData((const char*)p.packet, sizeof(p));
t.append(d);
SEQBUFENTRY s;
s.seqNum = p.seq;
s.timeSent = QTime::currentTime();
s.retransmitCount = 0;
s.data = t;
if (client->txMutex.try_lock_for(std::chrono::milliseconds(LOCK_PERIOD)))
{
if (client->txSeqBuf.size() > BUFSIZE)
{
client->txSeqBuf.remove(client->txSeqBuf.firstKey());
}
client->txSeqBuf.insert(p.seq, s);
client->txSeq++;
client->innerSeq++;
client->txMutex.unlock();
}
else {
qInfo(logUdpServer()) << "Unable to lock txMutex()";
}
if (udpMutex.try_lock_for(std::chrono::milliseconds(LOCK_PERIOD)))
{
client->socket->writeDatagram(t, client->ipAddress, client->port);
udpMutex.unlock();
}
else {
qInfo(logUdpServer()) << "Unable to lock udpMutex()";
}
}
else {
qInfo(logUdpServer()) << "Got data for different ID" << hex << (quint8)d[lastFE + 1] << ":" << hex << (quint8)d[lastFE + 2];
}
}
}
return;
}
void udpServer::sendRxAudio()
{
QByteArray audio;
if (rxaudio) {
if (audioMutex.try_lock_for(std::chrono::milliseconds(LOCK_PERIOD)))
{
audio.clear();
rxaudio->getNextAudioChunk(audio);
int len = 0;
while (len < audio.length()) {
audioPacket partial;
partial.data = audio.mid(len, 1364);
receiveAudioData(partial);
len = len + partial.data.length();
for (RIGCONFIG &rig : config.rigs) {
if (rig.rxaudio != Q_NULLPTR) {
if (audioMutex.try_lock_for(std::chrono::milliseconds(LOCK_PERIOD)))
{
audio.clear();
rig.rxaudio->getNextAudioChunk(audio);
int len = 0;
while (len < audio.length()) {
audioPacket partial;
partial.data = audio.mid(len, 1364);
receiveAudioData(partial);
len = len + partial.data.length();
}
// Now we have the next audio chunk, we can release the mutex.
audioMutex.unlock();
}
else {
qInfo(logUdpServer()) << "Unable to lock mutex for rxaudio";
}
// Now we have the next audio chunk, we can release the mutex.
audioMutex.unlock();
}
else {
qInfo(logUdpServer()) << "Unable to lock mutex for rxaudio";
}
}
}
@ -1721,6 +1816,10 @@ void udpServer::sendRetransmitRequest(CLIENT* c)
void udpServer::deleteConnection(QList<CLIENT*>* l, CLIENT* c)
{
quint8 guid[16];
memcpy(guid, c->guid, sizeof(guid));
int len = l->length();
qInfo(logUdpServer()) << "Deleting" << c->type << "connection to: " << c->ipAddress.toString() << ":" << QString::number(c->port);
if (c->idleTimer != Q_NULLPTR) {
c->idleTimer->stop();
@ -1774,6 +1873,7 @@ void udpServer::deleteConnection(QList<CLIENT*>* l, CLIENT* c)
if (client != Q_NULLPTR && client == c) {
qInfo(logUdpServer()) << "Found" << client->type << "connection to: " << client->ipAddress.toString() << ":" << QString::number(client->port);
it = l->erase(it);
len--;
}
else {
++it;
@ -1788,27 +1888,30 @@ void udpServer::deleteConnection(QList<CLIENT*>* l, CLIENT* c)
qInfo(logUdpServer()) << "Unable to lock connMutex()";
}
if (l->length() == 0) {
if (len == 0) {
for (RIGCONFIG& radio : config.rigs) {
if (!memcmp(radio.guid, guid, sizeof(radio.guid)))
{
if (radio.rxAudioTimer != Q_NULLPTR) {
radio.rxAudioTimer->stop();
delete radio.rxAudioTimer;
radio.rxAudioTimer = Q_NULLPTR;
}
if (rxAudioTimer != Q_NULLPTR) {
rxAudioTimer->stop();
delete rxAudioTimer;
rxAudioTimer = Q_NULLPTR;
if (radio.rxAudioThread != Q_NULLPTR) {
radio.rxAudioThread->quit();
radio.rxAudioThread->wait();
radio.rxaudio = Q_NULLPTR;
radio.rxAudioThread = Q_NULLPTR;
}
if (radio.txAudioThread != Q_NULLPTR) {
radio.txAudioThread->quit();
radio.txAudioThread->wait();
radio.txaudio = Q_NULLPTR;
radio.txAudioThread = Q_NULLPTR;
}
}
}
if (rxAudioThread != Q_NULLPTR) {
rxAudioThread->quit();
rxAudioThread->wait();
rxaudio = Q_NULLPTR;
rxAudioThread = Q_NULLPTR;
}
if (txAudioThread != Q_NULLPTR) {
txAudioThread->quit();
txAudioThread->wait();
txaudio = Q_NULLPTR;
txAudioThread = Q_NULLPTR;
}
}
}

Wyświetl plik

@ -23,6 +23,7 @@
#include "rigidentities.h"
#include "udphandler.h"
#include "audiohandler.h"
#include "rigcommander.h"
extern void passcode(QString in,QByteArray& out);
extern QByteArray parseNullTerminatedString(QByteArray c, int s);
@ -41,6 +42,32 @@ struct SERVERUSER {
quint8 userType;
};
struct RIGCONFIG {
QString serialPort;
quint32 baudRate;
unsigned char civAddr;
bool civIsRadioModel;
bool forceRTSasPTT;
bool hasWiFi = false;
bool hasEthernet=false;
audioSetup rxAudioSetup;
audioSetup txAudioSetup;
QString modelName;
QString rigName;
quint8 guid[16];
bool rigAvailable=false;
rigCapabilities rigCaps;
rigCommander* rig = Q_NULLPTR;
QThread* rigThread = Q_NULLPTR;
audioHandler* rxaudio = Q_NULLPTR;
QThread* rxAudioThread = Q_NULLPTR;
audioHandler* txaudio = Q_NULLPTR;
QThread* txAudioThread = Q_NULLPTR;
QTimer* rxAudioTimer = Q_NULLPTR;
};
struct SERVERCONFIG {
bool enabled;
bool lan;
@ -51,8 +78,8 @@ struct SERVERCONFIG {
int audioInput;
quint8 resampleQuality;
quint32 baudRate;
QList <SERVERUSER> users;
QList <RIGCONFIG> rigs;
};
@ -61,7 +88,7 @@ class udpServer : public QObject
Q_OBJECT
public:
udpServer(SERVERCONFIG config, audioSetup outAudio, audioSetup inAudio);
udpServer(SERVERCONFIG* config, audioSetup outAudio, audioSetup inAudio);
~udpServer();
public slots:
@ -140,6 +167,7 @@ private:
CLIENT* controlClient = Q_NULLPTR;
CLIENT* civClient = Q_NULLPTR;
CLIENT* audioClient = Q_NULLPTR;
quint8 guid[16];
};
void controlReceived();
@ -151,7 +179,7 @@ private:
void sendControl(CLIENT* c, quint8 type, quint16 seq);
void sendLoginResponse(CLIENT* c, bool allowed);
void sendCapabilities(CLIENT* c);
void sendConnectionInfo(CLIENT* c);
void sendConnectionInfo(CLIENT* c,quint8 guid[16]);
void sendTokenResponse(CLIENT* c,quint8 type);
void sendStatus(CLIENT* c);
void sendRetransmitRequest(CLIENT* c);
@ -171,8 +199,6 @@ private:
quint32 civId = 0;
quint32 audioId = 0;
quint8 rigciv = 0xa2;
QMutex udpMutex; // Used for critical operations.
QMutex connMutex;
QMutex audioMutex;
@ -180,19 +206,13 @@ private:
QList <CLIENT*> controlClients = QList<CLIENT*>();
QList <CLIENT*> civClients = QList<CLIENT*>();
QList <CLIENT*> audioClients = QList<CLIENT*>();
QTime timeStarted;
rigCapabilities rigCaps;
audioHandler* rxaudio = Q_NULLPTR;
QThread* rxAudioThread = Q_NULLPTR;
audioHandler* txaudio = Q_NULLPTR;
QThread* txAudioThread = Q_NULLPTR;
audioSetup outAudio;
audioSetup inAudio;
QTimer* rxAudioTimer=Q_NULLPTR;
quint16 rxSampleRate = 0;
quint16 txSampleRate = 0;
quint8 rxCodec = 0;