|
|
|
@@ -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);
|
|
|
|
|
}
|
|
|
|
|