Files
qt5-legatus-legacy/Lts/Proxies/CombatNetRadio/config_cnr.cpp
T
2026-08-13 18:33:10 +02:00

262 lines
9.4 KiB
C++
Executable File

/**
* @RDE_HEADER@
* ConfigCnr
* $Id$
* $HeadURL$
* $Author$
* Created by Christian Fröbel, NLE, 2019-08-05
*/
#include "config_cnr.h"
#include "helper.h"
#include <AudioVideoManagement/avm_dtc.h>
#include <AudioVideoManagement/avm_translation.h>
#include <InfrastructureManagement/ism_dtc.h>
#include <QDateTime>
#include <QString>
#include <QtGlobal>
#include <QJsonDocument>
#include <Proxies/CombatNetRadio/Helper/cnr_frequency_planning_helper.h>
namespace CombatNetRadio
{
ConfigCnr::ConfigCnr(int exerciseId, AudioVideoManagement::Interface::Dtc *avmDtc, InfrastructureManagement::Interface::Dtc *ismDtc)
: m_exerciseId(exerciseId)
, m_avmDtc(avmDtc)
, m_ismDtc(ismDtc)
, m_logger(getLogger("ConfigCnr"))
, m_loggerJson(getLogger("ConfigCnr.Json"))
{
Q_ASSERT(avmDtc);
Q_ASSERT(ismDtc);
m_timer.setSingleShot(true);
m_timer.setInterval(200);
connect(&m_timer, &QTimer::timeout, this, &ConfigCnr::buildConfigCnrData);
connect(m_avmDtc, &AudioVideoManagement::Interface::Dtc::activeFrequencyPlanningChanged, this, &ConfigCnr::onActiveFrequencyPlanningChanged);
connect(m_avmDtc, &AudioVideoManagement::Interface::Dtc::frequencyPlanningChanged, this, &ConfigCnr::onFrequencyPlanningChanged);
connect(m_avmDtc, &AudioVideoManagement::Interface::Dtc::cnrConfigChanged, this, &ConfigCnr::onCnrConfigChanged);
buildConfigCnrData();
}
const WebSocketInterface::Messages::ConfigCnrMessage::ConfigCnrData &ConfigCnr::data() const
{
Q_ASSERT(hasActiveFrequencyPlanning());
return m_configCnrData;
}
void ConfigCnr::buildConfigCnrData()
{
WebSocketInterface::Messages::ConfigCnrMessage::ConfigCnrData configCnr;
boost::optional<AudioVideoManagement::FrequencyPlanning> plan = activePlan();
if (!plan)
{
m_configCnrData = configCnr;
emit changed();
return;
}
AudioVideoManagement::FrequencySet frequencySet = m_avmDtc->frequencySet(plan->frequencySetId());
QMap<int, AudioVideoManagement::FrequencySetDataWithId> fsdMap;
for (const auto &fsd : qAsConst(frequencySet.data()))
fsdMap.insert(fsd.id(), fsd);
configCnr.setId = plan->frequencySetId();
configCnr.time = QDateTime::fromMSecsSinceEpoch(plan->date()).toString(Qt::ISODate);
configCnr.radioCircuit.reserve(plan->data().size());
for (const auto &currentData : plan->data())
{
WebSocketInterface::Messages::ConfigCnrMessage::RadioCircuit radioCircuit;
AudioVideoManagement::CnrConfig cnrConfig = m_avmDtc->cnrConfig(currentData.cnrConfigId());
AudioVideoManagement::CnrChannel cnrChannel = m_avmDtc->cnrChannel(cnrConfig.cnrChannelId());
QVector<AudioVideoManagement::RadioCircuit*> circuits = AudioVideoManagement::fromJson(currentData.properties());
int subCircuitCount = 0;
for (AudioVideoManagement::RadioCircuit* circuit : qAsConst(circuits))
{
InfrastructureManagement::MainStructureElement radioStation = m_ismDtc->mainStructureElement(circuit->radioStationId);
WebSocketInterface::Messages::ConfigCnrMessage::SubRadioCircuit subCircuit;
switch (circuit->freqBand.underlying())
{
case AudioVideoManagement::FrequencyBand_def::VHF:
{
AudioVideoManagement::RadioCircuitVHF *rcVhf = dynamic_cast<AudioVideoManagement::RadioCircuitVHF*>(circuit);
if (!rcVhf)
break;
AudioVideoManagement::FrequencySetDataWithId &fsd = fsdMap[rcVhf->freqSetDataId];
subCircuit.agc = false;
subCircuit.akw = fsd.akwBundle().is_set() ? fsd.akwBundle().get() : 0;
subCircuit.channelSpacing = 0;
subCircuit.clipper = false;
subCircuit.comsec = fsd.comsec().is_set() ? fsd.comsec().get() : 0;
subCircuit.crossbeam = 0;
subCircuit.frequency = fsd.frequency() * 1000; // kHz --> Hz
subCircuit.frequencyBand = fsd.frequencyBand().underlying();
subCircuit.fsb = fsd.fsbBundle().is_set() ? fsd.fsbBundle().get() : 0;
subCircuit.modulationType = 0;
subCircuit.orientation = 0;
subCircuit.ptSig = rcVhf->pilotTone;
subCircuit.rcAkw = fsd.akwRadioCircuit().is_set() ? fsd.akwRadioCircuit().get() : 0;
subCircuit.rcMode = rcVhf->operatingMode.underlying();
subCircuit.rcSubId = toRcIdString(cnrChannel);
subCircuit.rcSubName = rcVhf->name;
subCircuit.rcType = 2;//circuit->freqBand.underlying();
subCircuit.squelch = 0;
subCircuit.station = stationId(radioStation);
break;
}
case AudioVideoManagement::FrequencyBand_def::UHF:
{
AudioVideoManagement::RadioCircuitUHF *rcUhf = dynamic_cast<AudioVideoManagement::RadioCircuitUHF*>(circuit);
if (!rcUhf)
break;
subCircuit.agc = rcUhf->agc;
subCircuit.akw = 0;
subCircuit.channelSpacing = rcUhf->channelSpacing.underlying();
subCircuit.clipper = rcUhf->clipper;
subCircuit.comsec = 0;
subCircuit.crossbeam = 0;
subCircuit.frequency = rcUhf->frequency; // Really? ICD says different
subCircuit.frequencyBand = 0; // == rcType?
subCircuit.fsb = 0;
subCircuit.modulationType = rcUhf->modulationType.underlying();
subCircuit.orientation = 0;
subCircuit.ptSig = 0;
subCircuit.rcAkw = 0;
subCircuit.rcMode = 0; // VHF only?
subCircuit.rcSubId = toRcIdString(cnrChannel);
subCircuit.rcSubName = rcUhf->name;
subCircuit.rcType = 3;//circuit->freqBand.underlying();
subCircuit.squelch = rcUhf->squelchDB;
subCircuit.station = stationId(radioStation);
break;
}
case AudioVideoManagement::FrequencyBand_def::HF:
{
AudioVideoManagement::RadioCircuitHF *rcHf = dynamic_cast<AudioVideoManagement::RadioCircuitHF*>(circuit);
if (!rcHf)
break;
subCircuit.agc = 0;
subCircuit.akw = 0;
subCircuit.channelSpacing = rcHf->channelSpacing.underlying();
subCircuit.clipper = 0;
subCircuit.comsec = 0;
subCircuit.crossbeam = 0;
subCircuit.frequency = rcHf->frequency; // Really? ICD says different
subCircuit.frequencyBand = 0; // == rcType?
subCircuit.fsb = 0;
subCircuit.modulationType = rcHf->modulationType.underlying();
subCircuit.orientation = 0;
subCircuit.ptSig = 0;
subCircuit.rcAkw = 0;
subCircuit.rcMode = 0; // VHF only?
subCircuit.rcSubId = toRcIdString(cnrChannel);
subCircuit.rcSubName = rcHf->name;
subCircuit.rcType = 1;//circuit->freqBand.underlying();
subCircuit.squelch = rcHf->squelch;
subCircuit.station = stationId(radioStation);
break;
}
default:
break;
}
if (circuits.count() > 1)
subCircuit.rcSubId.append(QChar('A' + subCircuitCount++));
radioCircuit.subCircuits.append(subCircuit);
}
qDeleteAll(circuits);
radioCircuit.rcId = toRcIdString(cnrChannel);
radioCircuit.rcName = QString::fromStdString(cnrConfig.radioCircuit());
radioCircuit.ssrc = cnrChannel.ssrc();
configCnr.radioCircuit.append(radioCircuit);
}
// NOTICE_LOG(m_loggerJson) << WebSocketInterface::Messages::ConfigCnrMessage(configCnr, QUuid::createUuid().toString()).toJsonString();
m_configCnrData = configCnr;
emit changed();
}
boost::optional<AudioVideoManagement::FrequencyPlanning> ConfigCnr::activePlan() const
{
AudioVideoManagement::ActiveFrequencyPlanning activePlanning = m_avmDtc->activeFrequencyPlanning(m_exerciseId);
if (activePlanning.exerciseId() != m_exerciseId)
return boost::none;
AudioVideoManagement::FrequencyPlanning frequencyPlanning = m_avmDtc->frequencyPlanning(activePlanning.frequencyPlanningId());
return frequencyPlanning;
}
void ConfigCnr::onActiveFrequencyPlanningChanged(const AudioVideoManagement::ActiveFrequencyPlanning &data, DataModification modType)
{
DEBUG_LOG(m_logger) << LOGFUNCTION << ": " << data;
Q_UNUSED(modType);
if (data.exerciseId() == m_exerciseId)
m_timer.start();
}
void ConfigCnr::onFrequencyPlanningChanged(const AudioVideoManagement::FrequencyPlanning &data, DataModification modType)
{
DEBUG_LOG(m_logger) << LOGFUNCTION << ": " << data;
Q_UNUSED(modType);
boost::optional<AudioVideoManagement::FrequencyPlanning> plan = activePlan();
if (!plan)
return;
if (data.id() == plan->id() || !data.exerciseId().is_set())
m_timer.start();
}
//Daten nur rausschicken, wenn cnrConfig Data gerade in einer aktiven Übung verwendet wird
void ConfigCnr::onCnrConfigChanged(const AudioVideoManagement::CnrConfig &data, DataModification modType)
{
DEBUG_LOG(m_logger) << LOGFUNCTION << ": " << data;
Q_UNUSED(modType);
bool isGlobal = !data.exerciseId().is_set();
if ((isGlobal || data.exerciseId().get() == m_exerciseId) && modType != DataModification::eAdded && isInActiveFrequencyPlanning(data))
m_timer.start();
}
//todo: wird das noch wo anders benötigt?
bool ConfigCnr::isInActiveFrequencyPlanning(const AudioVideoManagement::CnrConfig &data)
{
//globale Änderung immer schicken
if(!data.exerciseId().is_set())
return true;
const auto activePlans = m_avmDtc->activeFrequencyPlannings();
for (const AudioVideoManagement::ActiveFrequencyPlanning &activePlan : activePlans)
{
const auto frequencyPlannings = m_avmDtc->frequencyPlanning(activePlan.frequencyPlanningId());
for(const auto &frequencyPlanningData : frequencyPlannings.data())
{
if(frequencyPlanningData.cnrConfigId() == data.id())
return true;
}
}
return false;
}
} // namespace CombatNetRadio