protocol 2 fix

This commit is contained in:
2026-04-14 22:06:31 +03:00
parent dde80e5696
commit 6ca18411cf
13 changed files with 1135 additions and 1024 deletions
@@ -338,6 +338,12 @@ void DataEngine::setupConnections() {
this,
SLOT(searchHpsdrNetworkDevices()));
CHECKED_CONNECT(
set,
SIGNAL(widebandDataChanged(QObject *, bool)),
this,
SLOT(setWidebandData(QObject *, bool)));
/*CHECKED_CONNECT(
set,
SIGNAL(spectrumAveragingChanged(QObject*, int, bool)),
@@ -2567,6 +2573,19 @@ void DataEngine::setFrequency(QObject* sender, int mode, int rx, long frequency)
io.tx_freq_change = rx;
}
void DataEngine::setWidebandData(QObject *sender, bool value) {
Q_UNUSED(sender)
if (m_dataEngineState != QSDR::DataEngineUp || !m_dataIO)
return;
const TNetworkDevicecard device = set->getCurrentMetisCard();
if (device.protocolVersion >= 2)
return;
invokeDataIOStartStop(m_dataIO, value ? 0x03 : 0x01);
}
void DataEngine::loadWavFile(const QString &fileName) {
if (m_audioEngine->loadFile(fileName))
+6 -5
View File
@@ -141,11 +141,12 @@ public slots:
void set122_88MhzSource(QObject *sender, int source);
void setMicSource(QObject *sender, int source);
void setMercuryClass(QObject *sender, int value);
void setMercuryTiming(QObject* sender, int value);
void setHamBand(QObject *sender, int rx, bool byBtn, HamBand band);
void setFrequency(QObject* sender, int mode, int rx, long frequency);
void loadWavFile(const QString &fileName);
void setMercuryTiming(QObject* sender, int value);
void setHamBand(QObject *sender, int rx, bool byBtn, HamBand band);
void setFrequency(QObject* sender, int mode, int rx, long frequency);
void setWidebandData(QObject *sender, bool value);
void loadWavFile(const QString &fileName);
void suspend();
void startPlayback();
void showSettingsDialog();
+631 -45
View File
@@ -8,6 +8,8 @@
#include "cusdr_protocol2_io.h"
#include "cusdr_protocol2_profile.h"
#include <algorithm>
#ifdef LOG_DATAIO
# define PROTOCOL2_DEBUG qDebug().nospace() << "Protocol2::\t"
#else
@@ -18,14 +20,26 @@
namespace {
static const quint16 kProtocol2DdcSpecificPort = 1025;
static const quint16 kProtocol2DucSpecificPort = 1026;
static const quint16 kProtocol2MicDataPort = 1026;
static const quint16 kProtocol2WidebandBasePort = 1027;
static const quint16 kProtocol2HighPriorityToPcPort = 1025;
static const quint16 kProtocol2DdcAudioPort = 1028;
static const quint16 kProtocol2DucIqPort = 1029;
static const quint16 kProtocol2DdcBasePort = 1035;
static const int kProtocol2GeneralPacketSize = 60;
static const int kProtocol2DucSpecificPacketSize = 60;
static const int kProtocol2HighPriorityPacketSize = 1444;
static const int kProtocol2StatusPacketMinSize = 31;
QString hexSlice(const QByteArray &datagram, int offset, int length) {
QStringList bytes;
for (int i = 0; i < length && offset + i < datagram.size(); ++i)
bytes << QString("%1").arg((quint8)datagram.at(offset + i), 2, 16, QLatin1Char('0')).toUpper();
return bytes.join(' ');
}
int protocol2ReceiverCount(Settings *set) {
const TNetworkDevicecard device = set->getCurrentMetisCard();
@@ -37,6 +51,25 @@ int protocol2ReceiverCount(Settings *set) {
return requestedReceivers;
}
QList<int> protocol2ActiveDdcIndexes(Settings *set) {
QList<int> ddcIndexes;
if (!set)
return ddcIndexes;
const TNetworkDevicecard device = set->getCurrentMetisCard();
const int receivers = protocol2ReceiverCount(set);
const bool useHighEndMapping =
device.protocolVersion >= 2 &&
(device.boardID == 3 || device.boardID == 4 || device.boardID == 5 || device.boardID == 10);
const int baseDdc = useHighEndMapping ? 2 : 0;
for (int rx = 0; rx < receivers; ++rx)
ddcIndexes.append(baseDdc + rx);
return ddcIndexes;
}
quint32 alexFilterWordForFrequency(Settings *set, long frequency, int currentBand) {
if (!set || !set->getAlexPresence())
@@ -114,13 +147,92 @@ Protocol2DataPath::Protocol2DataPath(Settings *settings, THPSDRParameter *ioData
, io(ioData)
, m_commandSocket(0)
, m_statusSocket(0)
, m_widebandSocket(0)
, m_heartbeatTimer(0)
, m_running(false)
, m_collectWideband(false)
, m_widebandSequence(0)
, m_widebandSequencePrevious((quint32)-1)
, m_widebandPacketCount(0)
, m_generalSequence(0)
, m_ddcSequence(0)
, m_ducSequence(0)
, m_highPrioritySequence(0)
, m_heartbeatTick(0)
, m_ddcDatagramsReceived(0)
, m_ddcSamplesReceived(0)
, m_legacyFramesEnqueued(0)
, m_legacyFramesQueued(0)
, m_legacyFramesDropped(0)
, m_statusPacketsReceived(0)
, m_highPriorityPacketsSent(0)
, m_logConfigPackets(true)
, m_lastStatusByte4(0)
, m_lastStatusByte5(0)
, m_loggedFirstDdcDatagram(false)
{
m_legacyControlBytes = QByteArray(5, 0x00);
CHECKED_CONNECT(
set,
SIGNAL(numberOfRXChanged(QObject *, int)),
this,
SLOT(handleNumberOfRxChanged(QObject *, int)));
CHECKED_CONNECT(
set,
SIGNAL(sampleRateChanged(QObject *, int)),
this,
SLOT(handleSampleRateChanged(QObject *, int)));
CHECKED_CONNECT(
set,
SIGNAL(ditherChanged(QObject *, int)),
this,
SLOT(handleDitherChanged(QObject *, int)));
CHECKED_CONNECT(
set,
SIGNAL(randomChanged(QObject *, int)),
this,
SLOT(handleRandomChanged(QObject *, int)));
CHECKED_CONNECT(
set,
SIGNAL(ctrFrequencyChanged(QObject *, int, int, long)),
this,
SLOT(handleCtrFrequencyChanged(QObject *, int, int, long)));
CHECKED_CONNECT(
set,
SIGNAL(vfoFrequencyChanged(QObject *, int, int, long)),
this,
SLOT(handleVfoFrequencyChanged(QObject *, int, int, long)));
CHECKED_CONNECT(
set,
SIGNAL(currentReceiverChanged(QObject *, int)),
this,
SLOT(handleCurrentReceiverChanged(QObject *, int)));
CHECKED_CONNECT(
set,
SIGNAL(hamBandChanged(QObject *, int, bool, HamBand)),
this,
SLOT(handleHamBandChanged(QObject *, int, bool, HamBand)));
CHECKED_CONNECT(
set,
SIGNAL(alexConfigurationChanged(quint16)),
this,
SLOT(handleAlexConfigurationChanged(quint16)));
CHECKED_CONNECT(
set,
SIGNAL(alexStateChanged(HamBand, const QList<int> &)),
this,
SLOT(handleAlexStateChanged(HamBand, const QList<int> &)));
CHECKED_CONNECT(
set,
SIGNAL(alexPresenceChanged(bool)),
this,
SLOT(handleAlexPresenceChanged(bool)));
CHECKED_CONNECT(
set,
SIGNAL(widebandDataChanged(QObject *, bool)),
this,
SLOT(handleWidebandDataChanged(QObject *, bool)));
}
Protocol2DataPath::~Protocol2DataPath() {
@@ -140,7 +252,7 @@ bool Protocol2DataPath::initSockets() {
const QHostAddress localAddress(set->getHPSDRDeviceLocalAddr());
const quint16 discoveryPort = set->getMetisPort();
const int receivers = protocol2ReceiverCount(set);
const QList<int> ddcIndexes = activeDdcIndexes();
m_commandSocket = new QUdpSocket(this);
if (!m_commandSocket->bind(localAddress, discoveryPort, QUdpSocket::DontShareAddress)) {
@@ -148,6 +260,11 @@ bool Protocol2DataPath::initSockets() {
closeSockets();
return false;
}
CHECKED_CONNECT(
m_commandSocket,
SIGNAL(readyRead()),
this,
SLOT(readCommandData()));
m_statusSocket = new QUdpSocket(this);
if (!m_statusSocket->bind(localAddress, kProtocol2HighPriorityToPcPort, QUdpSocket::DontShareAddress)) {
@@ -161,12 +278,26 @@ bool Protocol2DataPath::initSockets() {
this,
SLOT(readStatusData()));
if (set->getWidebandData()) {
m_widebandSocket = new QUdpSocket(this);
if (!m_widebandSocket->bind(localAddress, kProtocol2WidebandBasePort, QUdpSocket::DontShareAddress)) {
PROTOCOL2_DEBUG << "wideband socket bind failed on port " << kProtocol2WidebandBasePort;
closeSockets();
return false;
}
CHECKED_CONNECT(
m_widebandSocket,
SIGNAL(readyRead()),
this,
SLOT(readWidebandData()));
}
m_ddcSampleBuffers.clear();
m_ddcSockets.clear();
for (int rx = 0; rx < receivers; ++rx) {
for (int rx = 0; rx < ddcIndexes.size(); ++rx) {
QUdpSocket *socket = new QUdpSocket(this);
const quint16 port = kProtocol2DdcBasePort + rx;
const quint16 port = kProtocol2DdcBasePort + ddcIndexes.at(rx);
if (!socket->bind(localAddress, port, QUdpSocket::DontShareAddress)) {
PROTOCOL2_DEBUG << "DDC socket bind failed on port " << port;
delete socket;
@@ -195,9 +326,28 @@ bool Protocol2DataPath::initSockets() {
m_partialLegacyFrame.clear();
m_partialLegacyFrame.reserve(BUFFER_SIZE);
m_legacyControlBytes.fill(0x00, 5);
m_widebandDatagram.clear();
m_running = false;
m_collectWideband = false;
m_widebandSequence = 0;
m_widebandSequencePrevious = (quint32)-1;
m_widebandPacketCount = 0;
m_heartbeatTick = 0;
m_ddcDatagramsReceived = 0;
m_ddcSamplesReceived = 0;
m_legacyFramesEnqueued = 0;
m_legacyFramesQueued = 0;
m_legacyFramesDropped = 0;
m_statusPacketsReceived = 0;
m_highPriorityPacketsSent = 0;
m_commandPortCounters.clear();
m_loggedFirstSourcePorts.clear();
m_logConfigPackets = true;
m_lastStatusByte4 = 0;
m_lastStatusByte5 = 0;
m_loggedFirstDdcDatagram = false;
PROTOCOL2_DEBUG << "sockets initialized for " << receivers << " receiver(s).";
PROTOCOL2_DEBUG << "sockets initialized for DDC indexes " << ddcIndexes;
return true;
}
@@ -229,21 +379,95 @@ void Protocol2DataPath::networkDeviceStartStop(char value) {
return;
m_running = false;
m_heartbeatTick = 0;
if (m_heartbeatTimer)
m_heartbeatTimer->stop();
sendHighPriorityPacket(false);
return;
}
m_running = false;
m_generalSequence = 0;
m_ddcSequence = 0;
m_ducSequence = 0;
m_highPrioritySequence = 0;
m_heartbeatTick = 0;
m_ddcDatagramsReceived = 0;
m_ddcSamplesReceived = 0;
m_legacyFramesEnqueued = 0;
m_legacyFramesQueued = 0;
m_legacyFramesDropped = 0;
m_statusPacketsReceived = 0;
m_highPriorityPacketsSent = 0;
m_commandPortCounters.clear();
m_loggedFirstSourcePorts.clear();
m_logConfigPackets = true;
m_partialLegacyFrame.clear();
for (int rx = 0; rx < m_ddcSampleBuffers.size(); ++rx)
m_ddcSampleBuffers[rx].clear();
sendGeneralPacket();
sendDucSpecificPacket();
sendDdcSpecificPacket();
m_running = true;
sendHighPriorityPacket(true);
m_running = true;
if (m_heartbeatTimer)
m_heartbeatTimer->start();
}
void Protocol2DataPath::readCommandData() {
bool receivedDdcData = false;
while (m_commandSocket && m_commandSocket->hasPendingDatagrams()) {
QByteArray datagram;
datagram.resize(m_commandSocket->pendingDatagramSize());
QHostAddress senderAddress;
quint16 senderPort = 0;
m_commandSocket->readDatagram(datagram.data(), datagram.size(), &senderAddress, &senderPort);
Q_UNUSED(senderAddress)
++m_commandPortCounters[senderPort];
if (!m_loggedFirstSourcePorts.contains(senderPort)) {
PROTOCOL2_DEBUG
<< "first src port " << senderPort
<< ": len=" << datagram.size()
<< " head=" << hexSlice(datagram, 0, qMin(16, datagram.size()));
m_loggedFirstSourcePorts.insert(senderPort);
}
if (senderPort == kProtocol2HighPriorityToPcPort) {
if (datagram.size() >= kProtocol2StatusPacketMinSize) {
++m_statusPacketsReceived;
m_lastStatusByte4 = (uchar)datagram.at(4);
m_lastStatusByte5 = (uchar)datagram.at(5);
updateLegacyControlBytes(datagram);
}
continue;
}
if (senderPort == kProtocol2MicDataPort)
continue;
if (senderPort == kProtocol2WidebandBasePort) {
continue;
}
if (senderPort >= kProtocol2DdcBasePort) {
const int ddc = senderPort - kProtocol2DdcBasePort;
const int rx = activeDdcIndexes().indexOf(ddc);
if (rx >= 0) {
handleDdcDatagram(rx, datagram);
receivedDdcData = true;
}
}
}
if (receivedDdcData)
tryProduceLegacyFrames();
}
void Protocol2DataPath::readStatusData() {
while (m_statusSocket && m_statusSocket->hasPendingDatagrams()) {
@@ -269,25 +493,7 @@ void Protocol2DataPath::readDdcData() {
QByteArray datagram;
datagram.resize(socket->pendingDatagramSize());
socket->readDatagram(datagram.data(), datagram.size());
if (datagram.size() < 16)
continue;
const int bitsPerSample = ((quint8)datagram.at(12) << 8) | (quint8)datagram.at(13);
const int sampleCount = ((quint8)datagram.at(14) << 8) | (quint8)datagram.at(15);
const int payloadBytes = 16 + sampleCount * 6;
if (bitsPerSample != 24 || datagram.size() < payloadBytes)
continue;
for (int i = 0; i < sampleCount; ++i) {
const char *sample = datagram.constData() + 16 + i * 6;
Protocol2IQSample iqSample;
iqSample.i = read24BitSample(sample);
iqSample.q = read24BitSample(sample + 3);
m_ddcSampleBuffers[rx].append(iqSample);
}
handleDdcDatagram(rx, datagram);
}
tryProduceLegacyFrames();
@@ -298,7 +504,172 @@ void Protocol2DataPath::sendHeartbeat() {
if (!m_running)
return;
++m_heartbeatTick;
const int cycle = ((m_heartbeatTick - 1) % 8) + 1;
sendHighPriorityPacket(true);
switch (cycle) {
case 1:
case 3:
case 5:
case 7:
sendDucSpecificPacket();
break;
case 2:
case 4:
case 6:
sendDdcSpecificPacket();
break;
case 8:
sendDdcSpecificPacket();
sendGeneralPacket();
break;
default:
break;
}
if ((m_heartbeatTick % 10) == 0) {
QStringList fillLevels;
for (int rx = 0; rx < m_ddcSampleBuffers.size(); ++rx)
fillLevels << QString("rx%1=%2").arg(rx + 1).arg(m_ddcSampleBuffers.at(rx).size());
QStringList portCounters;
QList<quint16> ports = m_commandPortCounters.keys();
std::sort(ports.begin(), ports.end());
foreach (quint16 port, ports)
portCounters << QString("%1=%2").arg(port).arg(m_commandPortCounters.value(port));
PROTOCOL2_DEBUG
<< "rx flow: dgrams=" << m_ddcDatagramsReceived
<< " samples=" << m_ddcSamplesReceived
<< " iqFrames=" << m_legacyFramesEnqueued
<< " queued=" << m_legacyFramesQueued
<< " dropped=" << m_legacyFramesDropped
<< " hpTx=" << m_highPriorityPacketsSent
<< " hpRx=" << m_statusPacketsReceived
<< " st4=0x" << QString("%1").arg(m_lastStatusByte4, 2, 16, QLatin1Char('0')).toUpper()
<< " st5=0x" << QString("%1").arg(m_lastStatusByte5, 2, 16, QLatin1Char('0')).toUpper()
<< " flags[ptt=" << ((m_lastStatusByte4 & 0x01) ? 1 : 0)
<< " dot=" << ((m_lastStatusByte4 & 0x02) ? 1 : 0)
<< " dash=" << ((m_lastStatusByte4 & 0x04) ? 1 : 0)
<< " pll=" << ((m_lastStatusByte4 & 0x10) ? 1 : 0)
<< " fifoE=" << ((m_lastStatusByte4 & 0x20) ? 1 : 0)
<< " fifoF=" << ((m_lastStatusByte4 & 0x40) ? 1 : 0)
<< " ovf=" << ((m_lastStatusByte5 & 0x01) ? 1 : 0)
<< "]"
<< " partial=" << m_partialLegacyFrame.size()
<< " queue=" << io->iq_queue.count()
<< " buffers[" << fillLevels.join(", ") << "]"
<< " ports[" << portCounters.join(", ") << "]";
}
}
void Protocol2DataPath::readWidebandData() {
while (m_widebandSocket && m_widebandSocket->hasPendingDatagrams()) {
QByteArray datagram;
datagram.resize(m_widebandSocket->pendingDatagramSize());
m_widebandSocket->readDatagram(datagram.data(), datagram.size());
handleWidebandDatagram(datagram);
}
}
void Protocol2DataPath::handleNumberOfRxChanged(QObject *sender, int value) {
Q_UNUSED(sender)
Q_UNUSED(value)
refreshDdcConfiguration(true);
}
void Protocol2DataPath::handleSampleRateChanged(QObject *sender, int value) {
Q_UNUSED(sender)
Q_UNUSED(value)
refreshDdcConfiguration(false);
}
void Protocol2DataPath::handleDitherChanged(QObject *sender, int value) {
Q_UNUSED(sender)
Q_UNUSED(value)
refreshDdcConfiguration(false);
}
void Protocol2DataPath::handleRandomChanged(QObject *sender, int value) {
Q_UNUSED(sender)
Q_UNUSED(value)
refreshDdcConfiguration(false);
}
void Protocol2DataPath::handleCtrFrequencyChanged(QObject *sender, int mode, int rx, long frequency) {
Q_UNUSED(sender)
Q_UNUSED(mode)
Q_UNUSED(rx)
Q_UNUSED(frequency)
refreshHighPriorityState();
}
void Protocol2DataPath::handleVfoFrequencyChanged(QObject *sender, int mode, int rx, long frequency) {
Q_UNUSED(sender)
Q_UNUSED(mode)
Q_UNUSED(rx)
Q_UNUSED(frequency)
refreshHighPriorityState();
}
void Protocol2DataPath::handleCurrentReceiverChanged(QObject *sender, int rx) {
Q_UNUSED(sender)
Q_UNUSED(rx)
refreshHighPriorityState();
}
void Protocol2DataPath::handleHamBandChanged(QObject *sender, int rx, bool byButton, HamBand band) {
Q_UNUSED(sender)
Q_UNUSED(rx)
Q_UNUSED(byButton)
Q_UNUSED(band)
refreshHighPriorityState();
}
void Protocol2DataPath::handleAlexConfigurationChanged(quint16 config) {
Q_UNUSED(config)
if (!m_commandSocket || !isActive())
return;
sendGeneralPacket();
refreshHighPriorityState();
}
void Protocol2DataPath::handleAlexStateChanged(HamBand band, const QList<int> &states) {
Q_UNUSED(band)
Q_UNUSED(states)
refreshHighPriorityState();
}
void Protocol2DataPath::handleAlexPresenceChanged(bool value) {
Q_UNUSED(value)
if (!m_commandSocket || !isActive())
return;
sendGeneralPacket();
refreshHighPriorityState();
}
void Protocol2DataPath::handleWidebandDataChanged(QObject *sender, bool value) {
Q_UNUSED(sender)
Q_UNUSED(value)
refreshWidebandConfiguration();
}
void Protocol2DataPath::closeSockets() {
@@ -324,6 +695,13 @@ void Protocol2DataPath::closeSockets() {
m_statusSocket = 0;
}
if (m_widebandSocket) {
disconnect(m_widebandSocket, 0, this, 0);
m_widebandSocket->close();
delete m_widebandSocket;
m_widebandSocket = 0;
}
if (m_commandSocket) {
disconnect(m_commandSocket, 0, this, 0);
m_commandSocket->close();
@@ -332,6 +710,81 @@ void Protocol2DataPath::closeSockets() {
}
m_partialLegacyFrame.clear();
m_widebandDatagram.clear();
m_collectWideband = false;
m_widebandPacketCount = 0;
m_widebandSequencePrevious = (quint32)-1;
m_heartbeatTick = 0;
}
void Protocol2DataPath::refreshDdcConfiguration(bool rebuildSockets) {
if (!isActive())
return;
const bool wasRunning = m_running;
if (rebuildSockets && (m_commandSocket || m_statusSocket || !m_ddcSockets.isEmpty())) {
m_running = false;
if (m_heartbeatTimer)
m_heartbeatTimer->stop();
closeSockets();
if (!initSockets())
return;
}
if (!m_commandSocket)
return;
sendGeneralPacket();
sendDdcSpecificPacket();
sendDucSpecificPacket();
sendHighPriorityPacket(wasRunning);
m_running = wasRunning;
if (m_running && m_heartbeatTimer)
m_heartbeatTimer->start();
}
void Protocol2DataPath::refreshHighPriorityState() {
if (!m_commandSocket || !isActive())
return;
sendHighPriorityPacket(m_running);
}
void Protocol2DataPath::refreshWidebandConfiguration() {
if (!m_commandSocket || !isActive())
return;
const bool needWidebandSocket = false;
const bool haveWidebandSocket = (m_widebandSocket != 0);
if (needWidebandSocket != haveWidebandSocket) {
const bool wasRunning = m_running;
m_running = false;
if (m_heartbeatTimer)
m_heartbeatTimer->stop();
closeSockets();
if (!initSockets())
return;
m_running = wasRunning;
if (m_running && m_heartbeatTimer)
m_heartbeatTimer->start();
}
sendGeneralPacket();
m_collectWideband = false;
m_widebandDatagram.clear();
m_widebandPacketCount = 0;
m_widebandSequencePrevious = (quint32)-1;
set->resetWidebandSpectrumBuffer();
}
void Protocol2DataPath::sendGeneralPacket() {
@@ -345,8 +798,8 @@ void Protocol2DataPath::sendGeneralPacket() {
datagram[4] = 0x00;
datagram[5] = (kProtocol2DdcSpecificPort >> 8) & 0xFF;
datagram[6] = kProtocol2DdcSpecificPort & 0xFF;
datagram[7] = (kProtocol2DucIqPort >> 8) & 0xFF;
datagram[8] = kProtocol2DucIqPort & 0xFF;
datagram[7] = (kProtocol2DucSpecificPort >> 8) & 0xFF;
datagram[8] = kProtocol2DucSpecificPort & 0xFF;
datagram[9] = (HIGH_PRIORITY_FROM_HOST_PORT >> 8) & 0xFF;
datagram[10] = HIGH_PRIORITY_FROM_HOST_PORT & 0xFF;
datagram[11] = (kProtocol2HighPriorityToPcPort >> 8) & 0xFF;
@@ -357,16 +810,20 @@ void Protocol2DataPath::sendGeneralPacket() {
datagram[16] = kProtocol2DucIqPort & 0xFF;
datagram[17] = (kProtocol2DdcBasePort >> 8) & 0xFF;
datagram[18] = kProtocol2DdcBasePort & 0xFF;
datagram[21] = (HIGH_PRIORITY_FROM_HOST_PORT >> 8) & 0xFF;
datagram[22] = HIGH_PRIORITY_FROM_HOST_PORT & 0xFF;
datagram[19] = (kProtocol2MicDataPort >> 8) & 0xFF;
datagram[20] = kProtocol2MicDataPort & 0xFF;
datagram[21] = (kProtocol2WidebandBasePort >> 8) & 0xFF;
datagram[22] = kProtocol2WidebandBasePort & 0xFF;
datagram[23] = set->getWidebandData() ? 0x01 : 0x00;
datagram[24] = 0x02;
datagram[25] = 0x00;
datagram[26] = 0x10;
datagram[27] = 20;
datagram[28] = 32;
datagram[23] = 0x00;
const TNetworkDevicecard device = set->getCurrentMetisCard();
if (device.phaseWords)
datagram[37] = (char)((quint8)datagram.at(37) | 0x08);
datagram[38] = (char)((quint8)datagram.at(38) | 0x01);
if ((device.iqFormatFlags & 0x05) == 0x05)
datagram[39] = 0x05;
@@ -378,18 +835,56 @@ void Protocol2DataPath::sendGeneralPacket() {
datagram[59] = (char)((quint8)datagram.at(59) | 0x01);
if (device.hasAlex1)
datagram[59] = (char)((quint8)datagram.at(59) | 0x02);
datagram[58] = (char)((quint8)datagram.at(58) | 0x01);
if (m_commandSocket->writeDatagram(datagram, set->getCurrentMetisCard().ip_address, DEVICE_PORT) >= 0)
++m_generalSequence;
else
PROTOCOL2_DEBUG << "general packet write failed.";
if (m_logConfigPackets) {
PROTOCOL2_DEBUG
<< "GP bytes[5..28] " << hexSlice(datagram, 5, 24)
<< " flags37..39 " << hexSlice(datagram, 37, 3)
<< " tail56..59 " << hexSlice(datagram, 56, 4);
}
}
void Protocol2DataPath::sendDucSpecificPacket() {
QByteArray datagram(kProtocol2DucSpecificPacketSize, 0x00);
datagram[0] = (m_ducSequence >> 24) & 0xFF;
datagram[1] = (m_ducSequence >> 16) & 0xFF;
datagram[2] = (m_ducSequence >> 8) & 0xFF;
datagram[3] = m_ducSequence & 0xFF;
datagram[4] = 0x01;
datagram[6] = 50;
datagram[7] = (600 >> 8) & 0xFF;
datagram[8] = 600 & 0xFF;
datagram[9] = 20;
datagram[10] = 50;
datagram[14] = 0x00;
datagram[15] = 192;
datagram[16] = 24;
if (m_commandSocket->writeDatagram(datagram, set->getCurrentMetisCard().ip_address, kProtocol2DucSpecificPort) >= 0)
++m_ducSequence;
else
PROTOCOL2_DEBUG << "DUC specific packet write failed.";
if (m_logConfigPackets) {
PROTOCOL2_DEBUG
<< "DUC bytes[4..16] " << hexSlice(datagram, 4, 13)
<< " mic/line[50..59] " << hexSlice(datagram, 50, 10);
}
}
void Protocol2DataPath::sendDdcSpecificPacket() {
const TNetworkDevicecard device = set->getCurrentMetisCard();
const int receivers = protocol2ReceiverCount(set);
QByteArray datagram(17 + receivers * 6, 0x00);
const QList<int> ddcIndexes = activeDdcIndexes();
QByteArray datagram(kProtocol2HighPriorityPacketSize, 0x00);
datagram[0] = (m_ddcSequence >> 24) & 0xFF;
datagram[1] = (m_ddcSequence >> 16) & 0xFF;
@@ -406,14 +901,17 @@ void Protocol2DataPath::sendDdcSpecificPacket() {
datagram[6] = datagram.at(6) | (1 << adc);
}
for (int rx = 0; rx < receivers; ++rx) {
for (int rx = 0; rx < ddcIndexes.size(); ++rx) {
datagram[7 + rx / 8] = datagram.at(7 + rx / 8) | (1 << (rx % 8));
const int ddc = ddcIndexes.at(rx);
const int sampleRateKsps = qMax(48, io->samplerate / 1000);
const int offset = 17 + rx * 6;
datagram[7 + ddc / 8] = datagram.at(7 + ddc / 8) | (1 << (ddc % 8));
const int offset = 17 + ddc * 6;
datagram[offset + 0] = (adcCount > 1) ? (rx % adcCount) : 0x00;
datagram[offset + 1] = (io->samplerate >> 8) & 0xFF;
datagram[offset + 2] = io->samplerate & 0xFF;
datagram[offset + 1] = (sampleRateKsps >> 8) & 0xFF;
datagram[offset + 2] = sampleRateKsps & 0xFF;
datagram[offset + 3] = 0x00;
datagram[offset + 4] = 0x00;
datagram[offset + 5] = 24;
@@ -423,17 +921,29 @@ void Protocol2DataPath::sendDdcSpecificPacket() {
++m_ddcSequence;
else
PROTOCOL2_DEBUG << "DDC specific packet write failed.";
if (m_logConfigPackets) {
const QList<int> ddcIndexes = activeDdcIndexes();
QStringList ddcSlices;
foreach (int ddc, ddcIndexes)
ddcSlices << QString("ddc%1[%2]").arg(ddc).arg(hexSlice(datagram, 17 + ddc * 6, 6));
PROTOCOL2_DEBUG
<< "DDC enable[7..16] " << hexSlice(datagram, 7, 10)
<< " cfg " << ddcSlices.join(' ');
}
}
void Protocol2DataPath::sendHighPriorityPacket(bool run) {
QByteArray datagram(kProtocol2HighPriorityPacketSize, 0x00);
const QList<long> frequencies = set->getCtrFrequencies();
const int receivers = protocol2ReceiverCount(set);
const QList<int> ddcIndexes = activeDdcIndexes();
const int currentReceiver = set->getCurrentReceiver();
const int currentBand = (int)set->getCurrentHamBand(currentReceiver);
const long currentVfoFrequency = set->getVfoFrequency(currentReceiver);
const quint32 alexWord = alexFilterWordForFrequency(set, currentVfoFrequency, currentBand);
const long currentRxFrequency = frequencies.value(currentReceiver, frequencies.value(0, 0));
const quint32 alexWord = alexFilterWordForFrequency(set, currentRxFrequency, currentBand);
const quint32 encodedDucFrequency = encodeFrequency(currentRxFrequency);
datagram[0] = (m_highPrioritySequence >> 24) & 0xFF;
datagram[1] = (m_highPrioritySequence >> 16) & 0xFF;
@@ -441,10 +951,11 @@ void Protocol2DataPath::sendHighPriorityPacket(bool run) {
datagram[3] = m_highPrioritySequence & 0xFF;
datagram[4] = run ? 0x01 : 0x00;
for (int rx = 0; rx < receivers; ++rx) {
for (int rx = 0; rx < ddcIndexes.size(); ++rx) {
const quint32 encodedFrequency = encodeFrequency(frequencies.value(rx, frequencies.value(0, 0)));
const int offset = 9 + rx * 4;
const int ddc = ddcIndexes.at(rx);
const int offset = 9 + ddc * 4;
datagram[offset + 0] = (encodedFrequency >> 24) & 0xFF;
datagram[offset + 1] = (encodedFrequency >> 16) & 0xFF;
@@ -452,6 +963,16 @@ void Protocol2DataPath::sendHighPriorityPacket(bool run) {
datagram[offset + 3] = encodedFrequency & 0xFF;
}
datagram[329] = (encodedDucFrequency >> 24) & 0xFF;
datagram[330] = (encodedDucFrequency >> 16) & 0xFF;
datagram[331] = (encodedDucFrequency >> 8) & 0xFF;
datagram[332] = encodedDucFrequency & 0xFF;
datagram[345] = 0x00;
datagram[1400] = 0x00;
datagram[1401] = 0x00;
datagram[1442] = 0x00;
datagram[1443] = 0x00;
if (set->getAlexPresence()) {
datagram[1432] = (alexWord >> 24) & 0xFF;
@@ -461,9 +982,26 @@ void Protocol2DataPath::sendHighPriorityPacket(bool run) {
}
if (m_commandSocket->writeDatagram(datagram, set->getCurrentMetisCard().ip_address, HIGH_PRIORITY_FROM_HOST_PORT) >= 0)
{
++m_highPrioritySequence;
++m_highPriorityPacketsSent;
}
else
PROTOCOL2_DEBUG << "high priority packet write failed.";
if (m_logConfigPackets) {
const QList<int> ddcIndexes = activeDdcIndexes();
QStringList hpSlices;
foreach (int ddc, ddcIndexes)
hpSlices << QString("ddc%1[%2]").arg(ddc).arg(hexSlice(datagram, 9 + ddc * 4, 4));
PROTOCOL2_DEBUG
<< "HP run/freq " << hexSlice(datagram, 4, 1)
<< " " << hpSlices.join(' ')
<< " duc[329..332] " << hexSlice(datagram, 329, 4)
<< " alex[1432..1435] " << hexSlice(datagram, 1432, 4);
m_logConfigPackets = false;
}
}
void Protocol2DataPath::updateLegacyControlBytes(const QByteArray &statusDatagram) {
@@ -483,9 +1021,47 @@ void Protocol2DataPath::updateLegacyControlBytes(const QByteArray &statusDatagra
m_legacyControlBytes[4] = (char)(set->getCurrentMetisCard().firmwareVersion & 0xFF);
}
void Protocol2DataPath::handleDdcDatagram(int rx, const QByteArray &datagram) {
if (rx < 0 || rx >= m_ddcSampleBuffers.size() || datagram.size() < 16)
return;
const int bitsPerSample = ((quint8)datagram.at(12) << 8) | (quint8)datagram.at(13);
const int sampleCount = ((quint8)datagram.at(14) << 8) | (quint8)datagram.at(15);
const int payloadBytes = 16 + sampleCount * 6;
if (!m_loggedFirstDdcDatagram) {
PROTOCOL2_DEBUG
<< "first DDC datagram: len=" << datagram.size()
<< " bits=" << bitsPerSample
<< " samples=" << sampleCount
<< " head=" << hexSlice(datagram, 0, qMin(16, datagram.size()));
m_loggedFirstDdcDatagram = true;
}
if (bitsPerSample != 24 || datagram.size() < payloadBytes)
return;
++m_ddcDatagramsReceived;
m_ddcSamplesReceived += sampleCount;
for (int i = 0; i < sampleCount; ++i) {
const char *sample = datagram.constData() + 16 + i * 6;
Protocol2IQSample iqSample;
iqSample.i = read24BitSample(sample);
iqSample.q = read24BitSample(sample + 3);
m_ddcSampleBuffers[rx].append(iqSample);
}
}
void Protocol2DataPath::handleWidebandDatagram(const QByteArray &datagram) {
Q_UNUSED(datagram)
}
void Protocol2DataPath::tryProduceLegacyFrames() {
const int receivers = qMax(1, set->getNumberOfReceivers());
const int receivers = qMax(1, protocol2ReceiverCount(set));
const int halfFrameSamples = samplesPerLegacyHalfFrame();
if (halfFrameSamples <= 0)
@@ -530,8 +1106,14 @@ void Protocol2DataPath::tryProduceLegacyFrames() {
m_partialLegacyFrame += halfFrame;
if (m_partialLegacyFrame.size() == BUFFER_SIZE) {
if (!io->iq_queue.isFull())
if (!io->iq_queue.isFull()) {
io->iq_queue.enqueue(m_partialLegacyFrame);
++m_legacyFramesQueued;
}
else {
++m_legacyFramesDropped;
}
++m_legacyFramesEnqueued;
m_partialLegacyFrame.clear();
}
}
@@ -539,7 +1121,7 @@ void Protocol2DataPath::tryProduceLegacyFrames() {
int Protocol2DataPath::samplesPerLegacyHalfFrame() const {
const int receivers = qMax(1, set->getNumberOfReceivers());
const int receivers = qMax(1, protocol2ReceiverCount(set));
const int bytesPerSample = receivers * 6 + 2;
return (BUFFER_SIZE / 2 - 8) / bytesPerSample;
@@ -566,3 +1148,7 @@ qint32 Protocol2DataPath::read24BitSample(const char *data) const {
return value;
}
QList<int> Protocol2DataPath::activeDdcIndexes() const {
return protocol2ActiveDdcIndexes(set);
}
@@ -8,7 +8,9 @@
#include "cusdr_settings.h"
#include <QHash>
#include <QList>
#include <QSet>
#include <QTimer>
#include <QUdpSocket>
@@ -32,16 +34,37 @@ public:
void networkDeviceStartStop(char value);
private slots:
void readCommandData();
void readStatusData();
void readDdcData();
void readWidebandData();
void sendHeartbeat();
void handleNumberOfRxChanged(QObject *sender, int value);
void handleSampleRateChanged(QObject *sender, int value);
void handleDitherChanged(QObject *sender, int value);
void handleRandomChanged(QObject *sender, int value);
void handleCtrFrequencyChanged(QObject *sender, int mode, int rx, long frequency);
void handleVfoFrequencyChanged(QObject *sender, int mode, int rx, long frequency);
void handleCurrentReceiverChanged(QObject *sender, int rx);
void handleHamBandChanged(QObject *sender, int rx, bool byButton, HamBand band);
void handleAlexConfigurationChanged(quint16 config);
void handleAlexStateChanged(HamBand band, const QList<int> &states);
void handleAlexPresenceChanged(bool value);
void handleWidebandDataChanged(QObject *sender, bool value);
private:
QList<int> activeDdcIndexes() const;
void closeSockets();
void sendGeneralPacket();
void sendDdcSpecificPacket();
void sendDucSpecificPacket();
void sendHighPriorityPacket(bool run);
void refreshDdcConfiguration(bool rebuildSockets);
void refreshHighPriorityState();
void refreshWidebandConfiguration();
void updateLegacyControlBytes(const QByteArray &statusDatagram);
void handleDdcDatagram(int rx, const QByteArray &datagram);
void handleWidebandDatagram(const QByteArray &datagram);
void tryProduceLegacyFrames();
int samplesPerLegacyHalfFrame() const;
quint32 encodeFrequency(long frequency) const;
@@ -52,16 +75,37 @@ private:
THPSDRParameter* io;
QUdpSocket* m_commandSocket;
QUdpSocket* m_statusSocket;
QUdpSocket* m_widebandSocket;
QList<QUdpSocket*> m_ddcSockets;
QList<QList<Protocol2IQSample> > m_ddcSampleBuffers;
QTimer* m_heartbeatTimer;
QByteArray m_partialLegacyFrame;
QByteArray m_statusDatagram;
QByteArray m_legacyControlBytes;
QByteArray m_widebandDatagram;
bool m_running;
bool m_collectWideband;
quint32 m_widebandSequence;
quint32 m_widebandSequencePrevious;
int m_widebandPacketCount;
quint32 m_generalSequence;
quint32 m_ddcSequence;
quint32 m_ducSequence;
quint32 m_highPrioritySequence;
int m_heartbeatTick;
quint64 m_ddcDatagramsReceived;
quint64 m_ddcSamplesReceived;
quint64 m_legacyFramesEnqueued;
quint64 m_legacyFramesQueued;
quint64 m_legacyFramesDropped;
quint64 m_statusPacketsReceived;
quint64 m_highPriorityPacketsSent;
QHash<quint16, quint64> m_commandPortCounters;
QSet<quint16> m_loggedFirstSourcePorts;
bool m_logConfigPackets;
uchar m_lastStatusByte4;
uchar m_lastStatusByte5;
bool m_loggedFirstDdcDatagram;
};
#endif // _CUSDR_PROTOCOL2_IO_H