From edaba32e2b9dc175cdee3ce8c18bb7ba1fb3593c Mon Sep 17 00:00:00 2001 From: Neil Horne <15316949+elecpower@users.noreply.github.com> Date: Wed, 29 Oct 2025 12:23:45 +1100 Subject: [PATCH] fix(cpn): preserve current calibration when writing models and settings to radio (#6722) --- companion/src/mdichild.cpp | 9 ++- companion/src/storage/etx.cpp | 2 +- companion/src/storage/etx.h | 2 +- companion/src/storage/labeled.cpp | 68 +++++++++++++++----- companion/src/storage/labeled.h | 3 +- companion/src/storage/sdcard.cpp | 2 +- companion/src/storage/sdcard.h | 2 +- companion/src/storage/storage.cpp | 103 ++++++++++++++++++++---------- companion/src/storage/storage.h | 12 +++- companion/src/storage/yaml.h | 2 +- 10 files changed, 143 insertions(+), 62 deletions(-) diff --git a/companion/src/mdichild.cpp b/companion/src/mdichild.cpp index b4743f70c..4518b23ef 100644 --- a/companion/src/mdichild.cpp +++ b/companion/src/mdichild.cpp @@ -1493,10 +1493,11 @@ int MdiChild::askQuestion(const QString & msg, QMessageBox::StandardButtons butt return QMessageBox::question(this, CPN_STR_APP_NAME, msg, buttons, defaultButton); } -void MdiChild::writeSettings(StatusDialog * status, bool toRadio) // write to Tx +void MdiChild::writeSettings(StatusDialog * status, bool toRadio) { // safeguard as the menu actions should be disabled int cnt = radioData.invalidModels(); + if (cnt) { QMessageBox::critical(this, tr("Write Models and Settings"), tr("Operation aborted as %1 models have significant errors that may affect model operation.").arg(cnt)); return; @@ -1522,8 +1523,7 @@ void MdiChild::writeSettings(StatusDialog * status, bool toRadio) // write to T if (toRadio) { radioPath = findMassStoragePath("RADIO", true); qDebug() << "Searching for SD card, found" << radioPath; - } - else { + } else { radioPath = g.currentProfile().sdPath(); if (!QFile(radioPath % "/RADIO").exists()) radioPath.clear(); @@ -1538,8 +1538,7 @@ void MdiChild::writeSettings(StatusDialog * status, bool toRadio) // write to T if (saveFile(radioPath, false)) { status->hide(); QMessageBox::information(this, CPN_STR_TTL_INFO, tr("Models and settings written")); - } - else { + } else { status->hide(); QMessageBox::critical(this, CPN_STR_TTL_ERROR, tr("Error writing models and settings!")); } diff --git a/companion/src/storage/etx.cpp b/companion/src/storage/etx.cpp index 242a9bf38..f0c8985ed 100644 --- a/companion/src/storage/etx.cpp +++ b/companion/src/storage/etx.cpp @@ -49,7 +49,7 @@ bool EtxFormat::load(RadioData & radioData) return result; } -bool EtxFormat::write(const RadioData & radioData) +bool EtxFormat::write(RadioData & radioData) { qDebug() << "Saving to archive" << filename; diff --git a/companion/src/storage/etx.h b/companion/src/storage/etx.h index 6bdfc11c7..7092ea1e2 100644 --- a/companion/src/storage/etx.h +++ b/companion/src/storage/etx.h @@ -37,7 +37,7 @@ class EtxFormat : public LabelsStorageFormat virtual QString name() { return "etx"; } virtual bool load(RadioData & radioData); - virtual bool write(const RadioData & radioData); + virtual bool write(RadioData & radioData); protected: virtual bool loadFile(QByteArray & fileData, const QString & fileName, bool optional = false); diff --git a/companion/src/storage/labeled.cpp b/companion/src/storage/labeled.cpp index a289b22c3..0d699d92e 100644 --- a/companion/src/storage/labeled.cpp +++ b/companion/src/storage/labeled.cpp @@ -57,21 +57,8 @@ bool LabelsStorageFormat::load(RadioData & radioData) qDebug() << tr("Found %1").arg(filename); } - QByteArray radioSettingsBuffer; - if (!loadFile(radioSettingsBuffer, "RADIO/radio.yml")) { - setError(tr("Cannot extract RADIO/radio.yml")); + if (!loadRadioSettings(radioData.generalSettings)) return false; - } - - try { - if (!loadRadioSettingsFromYaml(radioData.generalSettings, radioSettingsBuffer)) { - setError(tr("Cannot load RADIO/radio.yml")); - return false; - } - } catch(const std::runtime_error& e) { - setError(tr("Cannot load RADIO/radio.yml") + ":\n" + QString(e.what())); - return false; - } board = (Board::Type)radioData.generalSettings.variant; @@ -187,8 +174,34 @@ bool LabelsStorageFormat::load(RadioData & radioData) return true; } -bool LabelsStorageFormat::write(const RadioData & radioData) +bool LabelsStorageFormat::write(RadioData & radioData) { + // TODO + // move all unique radio settings to a separate file eg RADIO/hardware.yml. + // These settings/values should never be transferred to another radio. + // Also some are at a point in time eg calibration and + // therefore not restored to the radio from say an etx file + + // may not exist on a new sd card or path + if (QFile(filename + "/RADIO/radio.yml").exists()) { + GeneralSettings gsCur; + + if (loadRadioSettings(gsCur)) { + GeneralSettings & gsNew = radioData.generalSettings; + gsNew.txCurrentCalibration = gsCur.txCurrentCalibration; + gsNew.txVoltageCalibration = gsCur.txVoltageCalibration; + + for (int i = 0; i < CPN_MAX_INPUTS; i++) { + gsNew.inputConfig[i].calib = gsCur.inputConfig[i].calib; + } + + qDebug() << "Hardware specific settings preserved"; + } else { + setError("Error reading current settings from radio"); + return false; + } + } + QByteArray radioSettingsBuffer; if (!writeRadioSettingsToYaml(radioData.generalSettings, radioSettingsBuffer)) return false; @@ -280,3 +293,28 @@ bool LabelsStorageFormat::writeChecklist(const ModelData & model) return true; } + +bool LabelsStorageFormat::loadRadioSettings(GeneralSettings & generalSettings) +{ + QByteArray radioSettingsBuffer; + + const QString file("RADIO/radio.yml"); + const QString filePath(QDir::toNativeSeparators(filename + "/" + file)); + + if (!loadFile(radioSettingsBuffer, file)) { + setError(tr("Cannot extract %1").arg(filePath)); + return false; + } + + try { + if (!loadRadioSettingsFromYaml(generalSettings, radioSettingsBuffer)) { + setError(tr("Cannot load %1").arg(filePath)); + return false; + } + } catch(const std::runtime_error& e) { + setError(tr("Cannot load %1").arg(filePath) + ":\n" + QString(e.what())); + return false; + } + + return true; +} diff --git a/companion/src/storage/labeled.h b/companion/src/storage/labeled.h index a08109b79..41ba159c3 100644 --- a/companion/src/storage/labeled.h +++ b/companion/src/storage/labeled.h @@ -42,7 +42,7 @@ class LabelsStorageFormat : public StorageFormat } virtual bool load(RadioData & radioData); - virtual bool write(const RadioData & radioData); + virtual bool write(RadioData & radioData); protected: virtual bool loadFile(QByteArray & fileData, const QString & fileName, bool optional = false) = 0; @@ -54,4 +54,5 @@ class LabelsStorageFormat : public StorageFormat bool loadChecklist(ModelData &model); bool writeChecklist(const ModelData & model); + bool loadRadioSettings(GeneralSettings & generalSettings); }; diff --git a/companion/src/storage/sdcard.cpp b/companion/src/storage/sdcard.cpp index d3287d9a1..1d4f49b24 100644 --- a/companion/src/storage/sdcard.cpp +++ b/companion/src/storage/sdcard.cpp @@ -23,7 +23,7 @@ #include #include -bool SdcardFormat::write(const RadioData & radioData) +bool SdcardFormat::write(RadioData & radioData) { QDir dir(filename); dir.mkdir("RADIO"); diff --git a/companion/src/storage/sdcard.h b/companion/src/storage/sdcard.h index 42cb219ea..1cff37b2f 100644 --- a/companion/src/storage/sdcard.h +++ b/companion/src/storage/sdcard.h @@ -36,7 +36,7 @@ class SdcardFormat : public LabelsStorageFormat } virtual QString name() { return "sdcard"; } - virtual bool write(const RadioData & radioData); + virtual bool write(RadioData & radioData); protected: virtual bool loadFile(QByteArray & fileData, const QString & fileName, bool optional = false); diff --git a/companion/src/storage/storage.cpp b/companion/src/storage/storage.cpp index ab3d307d4..86b016d50 100644 --- a/companion/src/storage/storage.cpp +++ b/companion/src/storage/storage.cpp @@ -62,57 +62,94 @@ void unregisterStorageFactories() bool Storage::load(RadioData & radioData) { - QFile file(filename); - if (!file.exists()) { - setError(tr("Unable to find file %1!").arg(filename)); + if (!fileExists()) return false; - } bool ret = false; - foreach (StorageFactory * factory, registeredStorageFactories) { - if (factory->probe(filename)) { - StorageFormat * format = factory->instance(filename); - if (format->load(radioData)) { - board = format->getBoard(); - setWarning(format->warning()); - ret = true; - delete format; - break; - } - else { - setError(format->error()); - } - delete format; + StorageFormat *format = getStorageFormat(); + + if (format) { + if (format->load(radioData)) { + board = format->getBoard(); + setWarning(format->warning()); + ret = true; + } else { + setError(format->error()); } + + delete format; } return ret; } -bool Storage::write(const RadioData & radioData) +bool Storage::write(RadioData & radioData) { bool ret = false; - foreach (StorageFactory * factory, registeredStorageFactories) { - if (factory->probe(filename)) { - StorageFormat * format = factory->instance(filename); - ret = format->write(radioData); - delete format; - break; - } + StorageFormat *format = getStorageFormat(); + + if (format) { + ret = format->write(radioData); + delete format; } + return ret; } bool Storage::writeModel(const RadioData & radioData, const int modelIndex) { bool ret = false; - foreach (StorageFactory * factory, registeredStorageFactories) { - if (factory->probe(filename)) { - StorageFormat * format = factory->instance(filename); - ret = format->writeModel(radioData, modelIndex); - delete format; - break; - } + StorageFormat *format = getStorageFormat(); + + if (format) { + ret = format->writeModel(radioData, modelIndex); + delete format; } + + return ret; +} + +bool Storage::fileExists() +{ + QFile file(filename); + + if (!file.exists()) { + setError(tr("Unable to find file %1!").arg(filename)); + return false; + } + + return true; +} + +StorageFormat * Storage::getStorageFormat() +{ + foreach (StorageFactory * factory, registeredStorageFactories) { + if (factory->probe(filename)) + return factory->instance(filename); + } + + return nullptr; +} + +bool Storage::load(GeneralSettings & generalSettings) +{ + if (!fileExists()) + return false; + + bool ret = false; + StorageFormat *format = getStorageFormat(); + + if (format) { + if (format->load(generalSettings)) { + board = format->getBoard(); + setWarning(format->warning()); + ret = true; + } + else + setError(format->error()); + + delete format; + } + return ret; } diff --git a/companion/src/storage/storage.h b/companion/src/storage/storage.h index 8999ab7bc..997a69a24 100644 --- a/companion/src/storage/storage.h +++ b/companion/src/storage/storage.h @@ -51,7 +51,8 @@ class StorageFormat } virtual ~StorageFormat() {} virtual bool load(RadioData & radioData) = 0; - virtual bool write(const RadioData & radioData) = 0; + virtual bool load(GeneralSettings & generalSettings) { return false; } + virtual bool write(RadioData & radioData) = 0; virtual bool writeModel(const RadioData & radioData, const int modelIndex) { return false; } QString error() { @@ -151,9 +152,14 @@ class Storage : public StorageFormat _warning = warning; } - virtual bool load(RadioData & radioData); - virtual bool write(const RadioData & radioData); + virtual bool load(RadioData & radioData) override; + virtual bool load(GeneralSettings & generalSettings) override; + virtual bool write(RadioData & radioData); virtual bool writeModel(const RadioData & radioData, const int modelIndex); + + protected: + bool fileExists(); + StorageFormat * getStorageFormat(); }; void registerStorageFactories(); diff --git a/companion/src/storage/yaml.h b/companion/src/storage/yaml.h index 3906ca1f4..7df69c2fe 100644 --- a/companion/src/storage/yaml.h +++ b/companion/src/storage/yaml.h @@ -37,7 +37,7 @@ class YamlFormat : public StorageFormat virtual QString name() override { return "yml"; } virtual bool load(RadioData & radioData) override; - virtual bool write(const RadioData & radioData) override { return false; } + virtual bool write(RadioData & radioData) override { return false; } virtual bool writeModel(const RadioData & radioData, const int modelIndex) override; protected: