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

274 lines
8.9 KiB
C++
Executable File

#include "cnr_frequency_planning_helper.h"
#include <AudioVideoManagement/avm_translation.h>
#include <QJsonObject>
#include <QJsonArray>
#include <QSet>
#include <QVector>
// Todo: Better tr() ?
#include <QCoreApplication>
namespace AudioVideoManagement {
template<typename T>
T fromJson(const QByteArray &json)
{
QJsonParseError jError;
QJsonDocument doc(QJsonDocument::fromJson(json, &jError));
if (jError.error)
return {};
QJsonObject obj = doc.object();
return T::fromJson(obj);
}
// Todo:
//
// FreqPlanningDataSet ist nur noch ein pro FreqPlanningData vorhanden. Also integrieren in die Relation.
// DB und DDS Typen anpassen
// Die Properties einer FreqPlanningData(Set) sind ein Array (REL) (VHF/UHF/HF)
// wie in der Methode unter diesem Kommentar (bei dem die RadioSpecificaJSON schon mit rein geht!),
// siehe avm_edit_frequency_planning_resource_dialog.cpp:120
// Aus dieser einen Zeile müssen dann im Übersichtsdialog entweder ein Eintrag oder (mindestens) 3 Einträge (REL) gemacht werden.
// Die RadioSpecificaHelper also um Hilfsmethoden erweitern, damit man passende Objekte bekommt.
// Vielleicht die drei items Name, FreqBand, RadioStation ID gleich mit in die Specifica, bzw. von was ableiten, dass das beinhaltet!
// Method to obtain all "FrequencySetDataId" from an QJsonObject
QJsonObject frequencyPlanningJson(QJsonObject obj, const QString &name, FrequencyBand freqBand, int radioStationId)
{
obj.insert(QStringLiteral("Name"), name);
obj.insert(QStringLiteral("FrequencyBand"), freqBand.underlying());
obj.insert(QStringLiteral("RadioStationId"), radioStationId);
return obj;
}
bool RadioCircuitHF::isValid() const
{
if ((modulationType != ModulationType::AM && modulationType != ModulationType::FM) ||
(channelSpacing != ChannelSpacingHF::CS_100_Hz) ||
frequency < FREQ_MIN || frequency > FREQ_MAX ||
squelch < (SQUELCH_MIN-1) || squelch > SQUELCH_MAX
)
return false;
return true;
}
QJsonObject RadioCircuitHF::toJson() const
{
QJsonObject obj;
obj.insert(QStringLiteral("ModulationType"), modulationType.underlying());
obj.insert(QStringLiteral("ChannelSpacing"), channelSpacing.underlying());
obj.insert(QStringLiteral("Frequency"), frequency);
obj.insert(QStringLiteral("Squelch"), squelch);
return obj;
}
RadioCircuitHF* RadioCircuitHF::fromJson(const QJsonObject &obj)
{
RadioCircuitHF *spec = new RadioCircuitHF();
spec->modulationType = static_cast<ModulationType::inner_enum>(obj.value(QStringLiteral("ModulationType")).toInt(-1));
spec->channelSpacing = static_cast<ChannelSpacingHF::inner_enum>(obj.value(QStringLiteral("ChannelSpacing")).toInt());
spec->frequency = obj.value(QStringLiteral("Frequency")).toInt();
spec->squelch = obj.value(QStringLiteral("Squelch")).toInt(-1);
if (spec->isValid())
return spec;
return nullptr;
}
bool RadioCircuitUHF::isValid() const
{
if ((modulationType != ModulationType::AM && modulationType != ModulationType::FM) ||
(channelSpacing != ChannelSpacing::CS_8_33_kHz && channelSpacing != ChannelSpacing::CS_12_50_kHz && channelSpacing != ChannelSpacing::CS_25_00_kHz) ||
frequency < FREQ_MIN || frequency > FREQ_MAX ||
((squelchDB < SQUELCH_MIN || squelchDB > SQUELCH_MAX) && squelchDB != 0) // 0 or Min <squelch < max
)
return false;
return true;
}
QJsonObject RadioCircuitUHF::toJson() const
{
QJsonObject obj;
obj.insert(QStringLiteral("ModulationType"), modulationType.underlying());
obj.insert(QStringLiteral("ChannelSpacing"), channelSpacing.underlying());
obj.insert(QStringLiteral("Frequency"), frequency);
obj.insert(QStringLiteral("Squelch"), squelchDB);
obj.insert(QStringLiteral("Clipper"), clipper);
obj.insert(QStringLiteral("AGC"), agc);
return obj;
}
RadioCircuitUHF* RadioCircuitUHF::fromJson(const QJsonObject &obj)
{
RadioCircuitUHF *spec = new RadioCircuitUHF();
spec->modulationType = static_cast<ModulationType::inner_enum>(obj.value(QStringLiteral("ModulationType")).toInt(-1));
spec->channelSpacing = static_cast<ChannelSpacing::inner_enum>(obj.value(QStringLiteral("ChannelSpacing")).toInt());
spec->frequency = obj.value(QStringLiteral("Frequency")).toInt();
spec->squelchDB = obj.value(QStringLiteral("Squelch")).toInt(-1);
auto clipper = obj.value(QStringLiteral("Clipper"));
if (clipper.isUndefined() || !clipper.isBool())
return nullptr;
spec->clipper = clipper.toBool();
auto agc = obj.value(QStringLiteral("AGC"));
if (agc.isUndefined() || !agc.isBool())
return {};
spec->agc = agc.toBool();
if (spec->isValid())
return spec;
return nullptr;
}
QJsonObject RadioCircuitVHF::toJson() const
{
QJsonObject obj;
obj.insert(QStringLiteral("OperatingMode"), operatingMode.underlying());
obj.insert(QStringLiteral("FrequencySetDataId"), freqSetDataId);
obj.insert(QStringLiteral("PilotTone"), pilotTone);
return obj;
}
RadioCircuitVHF* RadioCircuitVHF::fromJson(const QJsonObject &obj)
{
RadioCircuitVHF *spec = new RadioCircuitVHF();
spec->operatingMode = static_cast<RcOperatingMode::inner_enum>(obj.value(QStringLiteral("OperatingMode")).toInt(-1));
spec->freqSetDataId = obj.value(QStringLiteral("FrequencySetDataId")).toInt();
auto pilotTone = obj.value(QStringLiteral("PilotTone"));
if (pilotTone.isUndefined() || !pilotTone.isBool())
return nullptr;
spec->pilotTone = pilotTone.toBool();
if (spec->isValid())
return spec;
return nullptr;
}
QString RadioCircuitHF::toString() const
{
return QCoreApplication::translate("AVM", "Frequency: %1, ModulationType: %2, ChannelSpacing: %3, Squelch: %4")
.arg(frequency)
.arg(AudioVideoManagement::toString(modulationType))
.arg(100)
.arg(squelch);
}
QString RadioCircuitUHF::toString() const
{
return QCoreApplication::translate("AVM", "Frequency: %1, ModulationType: %2, ChannelSpacing: %3, Squelch: %4, Clipper: %5, AGC: %6")
.arg(frequency)
.arg(AudioVideoManagement::toString(modulationType))
.arg(AudioVideoManagement::toString(channelSpacing))
.arg(squelchDB)
.arg(clipper)
.arg(agc);
}
QString RadioCircuitVHF::toString() const
{
return QCoreApplication::translate("AVM", "OperatingMode: %1, PilotTone: %2")
.arg(AudioVideoManagement::toString(operatingMode))
.arg(pilotTone);
}
QVector<RadioCircuit*> fromJson(const std::string &json)
{
QVector<RadioCircuit*> vec;
QJsonParseError err;
QJsonDocument doc = QJsonDocument::fromJson(QByteArray::fromStdString(json), &err);
if(err.error != QJsonParseError::NoError)
return {};
QJsonArray arr = doc.object().value(QStringLiteral("subCircuits")).toArray();
// Todo? Check if values are correctly filled and values are present...
// maybe VHF is missing a frequencysetid : show ErrorMessage?
for(const QJsonValue &val : qAsConst(arr))
{
RadioCircuit *rc = nullptr;
const QJsonObject obj = val.toObject();
FrequencyBand ft = static_cast<FrequencyBand::inner_enum>(obj[QStringLiteral("FrequencyBand")].toInt());
switch (ft.underlying())
{
case FrequencyBand_def::HF:
rc = RadioCircuitHF::fromJson(obj);
break;
case FrequencyBand_def::UHF:
rc = RadioCircuitUHF::fromJson(obj);
break;
case FrequencyBand_def::VHF:
rc = RadioCircuitVHF::fromJson(obj);
break;
case FrequencyBand_def::REL:
default:
break;
}
if(rc)
{
rc->freqBand = ft;
rc->name = obj[QStringLiteral("Name")].toString();
rc->radioStationId = obj[QStringLiteral("RadioStationId")].toInt();
vec << rc;
}
}
return vec;
}
QSet<int> frequencySetDataIds(const std::string &frequencyPlanDataProperties)
{
QSet<int> set;
QJsonParseError err;
QJsonDocument doc = QJsonDocument::fromJson(QByteArray::fromStdString(frequencyPlanDataProperties), &err);
if(err.error != QJsonParseError::NoError)
return {};
QJsonArray arr = doc.object().value(QStringLiteral("subCircuits")).toArray();
// Todo? Check if values are correctly filled and values are present...
for(const QJsonValue &val : qAsConst(arr))
{
const QJsonObject obj = val.toObject();
FrequencyBand ft = static_cast<FrequencyBand::inner_enum>(obj[QStringLiteral("FrequencyBand")].toInt());
switch (ft.underlying())
{
case FrequencyBand_def::VHF:
{
RadioCircuitVHF *rcVhf = RadioCircuitVHF::fromJson(obj);
if(!rcVhf)
break;
set << rcVhf->frequencySetDataId();
delete rcVhf;
break;
}
case FrequencyBand_def::UHF:
case FrequencyBand_def::HF:
default:
break;
}
}
return set;
}
bool isReadOnly(const std::string &frequencyPlanDataProperties)
{
QJsonParseError err;
QJsonDocument doc = QJsonDocument::fromJson(QByteArray::fromStdString(frequencyPlanDataProperties), &err);
if(err.error != QJsonParseError::NoError)
return false;
return doc.object().value(QStringLiteral("readOnly")).toBool();
}
bool isAkwMode(RcOperatingMode mode)
{
return mode == RcOperatingMode::AkwEncEccm || mode == RcOperatingMode::AkwEncNone;
}
} // AudioVideoManagement