262 lines
9.4 KiB
C++
Executable File
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 ¤tData : 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
|