This commit is contained in:
2026-04-13 22:06:52 +03:00
parent 14d983c840
commit dde80e5696
19 changed files with 1599 additions and 1107 deletions
+62 -13
View File
@@ -39,6 +39,7 @@
// use WIDEBAND_PROCESSOR_DEBUG
#include "cusdr_dataEngine.h"
#include "cusdr_protocol2_profile.h"
/*!
@@ -62,6 +63,45 @@ static int firstTimeRxInit;
static quint8 adc_rx1_4, adc_rx5_8, adc_rx9_16;
static quint8 new_adc_rx1_4, new_adc_rx5_8, new_adc_rx9_16;
namespace {
bool invokeDataIOInitFrame(DataIO *dataIO, int rx) {
if (!dataIO)
return false;
return QMetaObject::invokeMethod(
dataIO,
"sendInitFramesToNetworkDevice",
Qt::BlockingQueuedConnection,
Q_ARG(int, rx));
}
bool invokeDataIOStartStop(DataIO *dataIO, char value) {
if (!dataIO)
return false;
return QMetaObject::invokeMethod(
dataIO,
"networkDeviceStartStop",
Qt::BlockingQueuedConnection,
Q_ARG(char, value));
}
bool invokeDataIOStop(DataIO *dataIO) {
if (!dataIO)
return false;
return QMetaObject::invokeMethod(
dataIO,
"stop",
Qt::BlockingQueuedConnection);
}
}
DataEngine::DataEngine(QObject *parent)
: QObject(parent)
, set(Settings::instance())
@@ -509,6 +549,15 @@ bool DataEngine::findHPSDRDevices() {
SleeperThread::msleep(100);
if (set->getCurrentMetisCard().protocolVersion >= 2) {
const TNetworkDevicecard currentDevice = set->getCurrentMetisCard();
set->setHPSDRHardware(1);
set->setMercuryPresence(false);
set->setPenelopePresence(false);
set->setPennyLanePresence(false);
set->setExcaliburPresence(false);
set->setAlexPresence(currentDevice.hasAlex0 || currentDevice.hasAlex1);
if (currentDevice.ddcCount > 0 && set->getNumberOfReceivers() > currentDevice.ddcCount)
set->setReceivers(this, currentDevice.ddcCount);
io.hermesFW = set->getCurrentMetisCard().firmwareVersion;
set->setHermesVersion(io.hermesFW);
return true;
@@ -584,12 +633,12 @@ bool DataEngine::getFirmwareVersions() {
//setSampleRate(this, set->getSampleRate());
SleeperThread::msleep(100);
// pre-conditioning
for (int i = 0; i < io.receivers; i++)
m_dataIO->sendInitFramesToNetworkDevice(i);
// pre-conditioning
for (int i = 0; i < io.receivers; i++)
invokeDataIOInitFrame(m_dataIO, i);
if (m_serverMode == QSDR::SDRMode)
m_dataIO->networkDeviceStartStop(0x01); // 0x01 for starting Metis without wide band data
if (m_serverMode == QSDR::SDRMode)
invokeDataIOStartStop(m_dataIO, 0x01); // 0x01 for starting Metis without wide band data
m_networkDeviceRunning = true;
setSystemState(QSDR::NoError, m_hwInterface, m_serverMode, QSDR::DataEngineUp);
@@ -992,12 +1041,12 @@ bool DataEngine::start() {
// pre-conditioning
for (int i = 0; i < io.receivers; i++)
m_dataIO->sendInitFramesToNetworkDevice(i);
invokeDataIOInitFrame(m_dataIO, i);
if (m_serverMode == QSDR::SDRMode && set->getWidebandData())
m_dataIO->networkDeviceStartStop(0x03); // 0x03 for starting the device with wide band data
invokeDataIOStartStop(m_dataIO, 0x03); // 0x03 for starting the device with wide band data
else
m_dataIO->networkDeviceStartStop(0x01); // 0x01 for starting the device without wide band data
invokeDataIOStartStop(m_dataIO, 0x01); // 0x01 for starting the device without wide band data
m_networkDeviceRunning = true;
@@ -1021,10 +1070,10 @@ void DataEngine::stop() {
// turn time stamping off
setTimeStamp(this, false);
// stop the device
m_dataIO->networkDeviceStartStop(0);
m_networkDeviceRunning = false;
DATA_ENGINE_DEBUG << "HPSDR device stopped";
// stop the device
invokeDataIOStartStop(m_dataIO, 0);
m_networkDeviceRunning = false;
DATA_ENGINE_DEBUG << "HPSDR device stopped";
// stop the threads
//SleeperThread::msleep(100);
@@ -1577,7 +1626,7 @@ void DataEngine::stopDataIO() {
if (m_dataIOThread->isRunning()) {
m_dataIO->stop();
invokeDataIOStop(m_dataIO);
m_dataIOThread->quit();
while (!m_dataIOThread->isFinished()) {
+8 -5
View File
@@ -109,11 +109,17 @@ DataIO::DataIO(THPSDRParameter *ioData)
DataIO::~DataIO() {
if (m_dataIOSocketOn) {
if (m_dataIOSocketOn && m_dataIOSocket) {
m_dataIOSocket->close();
delete m_dataIOSocket;
m_dataIOSocket = 0;
}
if (m_pSoundCardOut) {
m_pSoundCardOut->Stop();
delete m_pSoundCardOut;
m_pSoundCardOut = 0;
}
}
void DataIO::stop() {
@@ -125,11 +131,8 @@ void DataIO::stop() {
if (m_protocol2 && m_protocol2->isActive())
m_protocol2->stop();
if(m_pSoundCardOut) {
if (m_pSoundCardOut)
SleeperThread::msleep(100);
m_pSoundCardOut->Stop();
delete m_pSoundCardOut;
}
}
void DataIO::initDataReceiverSocket() {
@@ -228,6 +228,13 @@ int DiscovererP1::findHPSDRDevices() {
mcP1.boardName = str;
mcP1.protocolVersion = 1;
mcP1.firmwareVersion = m_deviceDatagram.at(9) & 0xFF;
mcP1.adcCount = 0;
mcP1.ddcCount = 0;
mcP1.dspClockHz = 0;
mcP1.iqFormatFlags = 0;
mcP1.phaseWords = false;
mcP1.hasAlex0 = false;
mcP1.hasAlex1 = false;
io->networkIOMutex.lock();
DISCOVERER_DEBUG << "Device board ID: " << no;
DISCOVERER_DEBUG << "Device is: " << qPrintable(str);
+23 -25
View File
@@ -28,6 +28,7 @@
#define LOG_DISCOVERER
#include "cusdr_discoverer_P2.h"
#include "cusdr_protocol2_profile.h"
#include "Util/cusdr_buttons.h"
@@ -44,25 +45,6 @@ DiscovererP2::~DiscovererP2() {
TNetworkDevicecard mcP2;
namespace {
static QString protocol2BoardName(int boardId) {
switch (boardId) {
case 0: return "ATLAS";
case 1: return "Hermes";
case 2: return "Hermes";
case 3: return "Angelia";
case 4: return "Orion";
case 5: return "Orion MkII";
case 6: return "Hermes-Lite";
case 10: return "Saturn";
default: return QString("Protocol2-%1").arg(boardId);
}
}
}
void DiscovererP2::initHPSDRDevice() {
m_searchTime.start();
@@ -223,24 +205,40 @@ int DiscovererP2::findHPSDRDevices() {
io->networkIOMutex.unlock();
device = m_deviceDatagram[11] & 0xFF;
QString str = protocol2BoardName(device);
const Protocol2BoardProfile profile = protocol2BoardProfile(device);
QString str = profile.boardName;
mcP2.boardID = device;
mcP2.boardName = str;
mcP2.protocolVersion = m_deviceDatagram[12] & 0xFF;
mcP2.firmwareVersion = m_deviceDatagram[13] & 0xFF;
mcP2.adcCount = profile.adcCount;
mcP2.ddcCount = profile.defaultDdcCount;
mcP2.dspClockHz = profile.dspClockHz;
mcP2.iqFormatFlags = 0;
mcP2.phaseWords = profile.phaseWords;
mcP2.hasAlex0 = profile.hasAlex0;
mcP2.hasAlex1 = profile.hasAlex1;
if (m_deviceDatagram.size() >= 25) {
mcP2.ddcCount = m_deviceDatagram[20] & 0xFF;
mcP2.phaseWords = (m_deviceDatagram[21] & 0xFF) != 0;
mcP2.iqFormatFlags = m_deviceDatagram[22] & 0xFF;
}
io->networkIOMutex.lock();
DISCOVERER_DEBUG << "Protocol 2 device board ID: " << device;
DISCOVERER_DEBUG << "Protocol 2 device is: " << qPrintable(str);
DISCOVERER_DEBUG << "Protocol 2 capabilities: "
<< mcP2.adcCount << " ADC, "
<< mcP2.ddcCount << " DDC, phaseWords="
<< mcP2.phaseWords << ", iqFlags=0x"
<< QString::number(mcP2.iqFormatFlags, 16);
io->networkIOMutex.unlock();
m_deviceCards.append(mcP2);
str += " (";
str += mcP2.ip_address.toString();
str += ")";
set->addNetworkIOComboBoxEntry(str);
set->addNetworkIOComboBoxEntry(protocol2DeviceSummary(mcP2));
devicesFound++;
}
else {
+57 -9
View File
@@ -6,6 +6,7 @@
#define LOG_DATAIO
#include "cusdr_protocol2_io.h"
#include "cusdr_protocol2_profile.h"
#ifdef LOG_DATAIO
# define PROTOCOL2_DEBUG qDebug().nospace() << "Protocol2::\t"
@@ -25,6 +26,17 @@ static const int kProtocol2GeneralPacketSize = 60;
static const int kProtocol2HighPriorityPacketSize = 1444;
static const int kProtocol2StatusPacketMinSize = 31;
int protocol2ReceiverCount(Settings *set) {
const TNetworkDevicecard device = set->getCurrentMetisCard();
const int requestedReceivers = qMax(1, set->getNumberOfReceivers());
if (device.ddcCount > 0)
return qMin(requestedReceivers, device.ddcCount);
return requestedReceivers;
}
quint32 alexFilterWordForFrequency(Settings *set, long frequency, int currentBand) {
if (!set || !set->getAlexPresence())
@@ -128,7 +140,7 @@ bool Protocol2DataPath::initSockets() {
const QHostAddress localAddress(set->getHPSDRDeviceLocalAddr());
const quint16 discoveryPort = set->getMetisPort();
const int receivers = qMax(1, set->getNumberOfReceivers());
const int receivers = protocol2ReceiverCount(set);
m_commandSocket = new QUdpSocket(this);
if (!m_commandSocket->bind(localAddress, discoveryPort, QUdpSocket::DontShareAddress)) {
@@ -191,12 +203,13 @@ bool Protocol2DataPath::initSockets() {
void Protocol2DataPath::stop() {
const bool wasRunning = m_running;
m_running = false;
if (m_heartbeatTimer)
m_heartbeatTimer->stop();
if (m_commandSocket)
if (wasRunning && m_commandSocket)
sendHighPriorityPacket(false);
closeSockets();
@@ -212,6 +225,9 @@ void Protocol2DataPath::networkDeviceStartStop(char value) {
return;
if (value == 0) {
if (!m_running)
return;
m_running = false;
if (m_heartbeatTimer)
m_heartbeatTimer->stop();
@@ -288,11 +304,13 @@ void Protocol2DataPath::sendHeartbeat() {
void Protocol2DataPath::closeSockets() {
if (m_heartbeatTimer) {
disconnect(m_heartbeatTimer, 0, this, 0);
delete m_heartbeatTimer;
m_heartbeatTimer = 0;
}
foreach (QUdpSocket *socket, m_ddcSockets) {
disconnect(socket, 0, this, 0);
socket->close();
delete socket;
}
@@ -300,12 +318,14 @@ void Protocol2DataPath::closeSockets() {
m_ddcSampleBuffers.clear();
if (m_statusSocket) {
disconnect(m_statusSocket, 0, this, 0);
m_statusSocket->close();
delete m_statusSocket;
m_statusSocket = 0;
}
if (m_commandSocket) {
disconnect(m_commandSocket, 0, this, 0);
m_commandSocket->close();
delete m_commandSocket;
m_commandSocket = 0;
@@ -343,7 +363,21 @@ void Protocol2DataPath::sendGeneralPacket() {
datagram[26] = 0x10;
datagram[27] = 20;
datagram[28] = 32;
datagram[59] = set->getAlexPresence() ? 0x01 : 0x00;
const TNetworkDevicecard device = set->getCurrentMetisCard();
if (device.phaseWords)
datagram[37] = (char)((quint8)datagram.at(37) | 0x08);
if ((device.iqFormatFlags & 0x05) == 0x05)
datagram[39] = 0x05;
if (device.boardID == 0)
datagram[56] = qBound(0, protocol2ReceiverCount(set) - 1, 3);
if (device.hasAlex0)
datagram[59] = (char)((quint8)datagram.at(59) | 0x01);
if (device.hasAlex1)
datagram[59] = (char)((quint8)datagram.at(59) | 0x02);
if (m_commandSocket->writeDatagram(datagram, set->getCurrentMetisCard().ip_address, DEVICE_PORT) >= 0)
++m_generalSequence;
@@ -353,7 +387,8 @@ void Protocol2DataPath::sendGeneralPacket() {
void Protocol2DataPath::sendDdcSpecificPacket() {
const int receivers = qMax(1, set->getNumberOfReceivers());
const TNetworkDevicecard device = set->getCurrentMetisCard();
const int receivers = protocol2ReceiverCount(set);
QByteArray datagram(17 + receivers * 6, 0x00);
datagram[0] = (m_ddcSequence >> 24) & 0xFF;
@@ -361,15 +396,22 @@ void Protocol2DataPath::sendDdcSpecificPacket() {
datagram[2] = (m_ddcSequence >> 8) & 0xFF;
datagram[3] = m_ddcSequence & 0xFF;
datagram[4] = 0x01;
datagram[5] = io->ccTx.dither ? 0x01 : 0x00;
datagram[6] = io->ccTx.random ? 0x01 : 0x00;
const int adcCount = qMax(1, device.adcCount);
datagram[4] = adcCount;
for (int adc = 0; adc < adcCount && adc < 8; ++adc) {
if (io->ccTx.dither)
datagram[5] = datagram.at(5) | (1 << adc);
if (io->ccTx.random)
datagram[6] = datagram.at(6) | (1 << adc);
}
for (int rx = 0; rx < receivers; ++rx) {
datagram[7 + rx / 8] = datagram.at(7 + rx / 8) | (1 << (rx % 8));
const int offset = 17 + rx * 6;
datagram[offset + 0] = 0x00;
datagram[offset + 0] = (adcCount > 1) ? (rx % adcCount) : 0x00;
datagram[offset + 1] = (io->samplerate >> 8) & 0xFF;
datagram[offset + 2] = io->samplerate & 0xFF;
datagram[offset + 3] = 0x00;
@@ -387,7 +429,7 @@ void Protocol2DataPath::sendHighPriorityPacket(bool run) {
QByteArray datagram(kProtocol2HighPriorityPacketSize, 0x00);
const QList<long> frequencies = set->getCtrFrequencies();
const int receivers = qMax(1, set->getNumberOfReceivers());
const int receivers = protocol2ReceiverCount(set);
const int currentReceiver = set->getCurrentReceiver();
const int currentBand = (int)set->getCurrentHamBand(currentReceiver);
const long currentVfoFrequency = set->getVfoFrequency(currentReceiver);
@@ -504,7 +546,13 @@ int Protocol2DataPath::samplesPerLegacyHalfFrame() const {
}
quint32 Protocol2DataPath::encodeFrequency(long frequency) const {
return (quint32)frequency;
const TNetworkDevicecard device = set->getCurrentMetisCard();
if (!device.phaseWords)
return (quint32)frequency;
const quint64 dspClock = (device.dspClockHz > 0) ? (quint64)device.dspClockHz : 122880000ULL;
return (quint32)(((quint64)(quint32)frequency << 32) / dspClock);
}
qint32 Protocol2DataPath::read24BitSample(const char *data) const {
@@ -0,0 +1,140 @@
/**
* @file cusdr_protocol2_profile.cpp
* @brief openHPSDR Protocol 2 board capability helpers
*/
#include "cusdr_protocol2_profile.h"
namespace {
static Protocol2BoardProfile makeDefaultProfile(int boardId) {
Protocol2BoardProfile profile;
profile.boardId = boardId;
profile.boardName = "Protocol2 SDR";
profile.adcCount = 1;
profile.defaultDdcCount = 2;
profile.dspClockHz = 122880000;
profile.phaseWords = true;
profile.hasAlex0 = true;
profile.hasAlex1 = false;
return profile;
}
}
Protocol2BoardProfile protocol2BoardProfile(int boardId) {
Protocol2BoardProfile profile = makeDefaultProfile(boardId);
switch (boardId) {
case 0:
profile.boardName = "ATLAS";
profile.adcCount = 4;
profile.defaultDdcCount = 4;
profile.dspClockHz = 122880000;
profile.phaseWords = false;
profile.hasAlex0 = true;
profile.hasAlex1 = false;
break;
case 1:
profile.boardName = "Hermes / ANAN-10/100";
profile.adcCount = 1;
profile.defaultDdcCount = 2;
profile.dspClockHz = 122880000;
profile.phaseWords = true;
profile.hasAlex0 = true;
profile.hasAlex1 = false;
break;
case 2:
profile.boardName = "Hermes / ANAN-10E/100B";
profile.adcCount = 1;
profile.defaultDdcCount = 2;
profile.dspClockHz = 122880000;
profile.phaseWords = true;
profile.hasAlex0 = false;
profile.hasAlex1 = false;
break;
case 3:
profile.boardName = "Angelia / ANAN-100D";
profile.adcCount = 2;
profile.defaultDdcCount = 4;
profile.dspClockHz = 122880000;
profile.phaseWords = true;
profile.hasAlex0 = true;
profile.hasAlex1 = false;
break;
case 4:
profile.boardName = "Orion / ANAN-200D";
profile.adcCount = 2;
profile.defaultDdcCount = 4;
profile.dspClockHz = 122880000;
profile.phaseWords = true;
profile.hasAlex0 = true;
profile.hasAlex1 = false;
break;
case 5:
profile.boardName = "Orion MkII / ANAN-7/8000DLE";
profile.adcCount = 2;
profile.defaultDdcCount = 4;
profile.dspClockHz = 122880000;
profile.phaseWords = true;
profile.hasAlex0 = true;
profile.hasAlex1 = true;
break;
case 6:
profile.boardName = "Hermes Lite";
profile.adcCount = 1;
profile.defaultDdcCount = 2;
profile.dspClockHz = 76800000;
profile.phaseWords = true;
profile.hasAlex0 = false;
profile.hasAlex1 = false;
break;
case 10:
profile.boardName = "Saturn / ANAN-G2";
profile.adcCount = 2;
profile.defaultDdcCount = 4;
profile.dspClockHz = 122880000;
profile.phaseWords = true;
profile.hasAlex0 = true;
profile.hasAlex1 = true;
break;
default:
break;
}
return profile;
}
QString protocol2DeviceSummary(const TNetworkDevicecard &device) {
QString summary = device.boardName;
if (device.protocolVersion > 0)
summary += QString(" P%1").arg(device.protocolVersion);
if (device.firmwareVersion > 0)
summary += QString(" FW %1.%2").arg(device.firmwareVersion / 10).arg(device.firmwareVersion % 10);
if (device.adcCount > 0 || device.ddcCount > 0)
summary += QString(" %1ADC/%2DDC").arg(device.adcCount).arg(device.ddcCount);
if (device.phaseWords)
summary += " phase";
if (device.hasAlex0 || device.hasAlex1)
summary += device.hasAlex1 ? " Alex0/1" : " Alex";
summary += QString(" (%1)").arg(device.ip_address.toString());
return summary;
}
@@ -0,0 +1,26 @@
/**
* @file cusdr_protocol2_profile.h
* @brief openHPSDR Protocol 2 board capability helpers
*/
#ifndef _CUSDR_PROTOCOL2_PROFILE_H
#define _CUSDR_PROTOCOL2_PROFILE_H
#include "cusdr_settings.h"
struct Protocol2BoardProfile {
int boardId;
const char* boardName;
int adcCount;
int defaultDdcCount;
int dspClockHz;
bool phaseWords;
bool hasAlex0;
bool hasAlex1;
};
Protocol2BoardProfile protocol2BoardProfile(int boardId);
QString protocol2DeviceSummary(const TNetworkDevicecard &device);
#endif // _CUSDR_PROTOCOL2_PROFILE_H