From 199e09ed4ec22fcf879c6f3e4f8661ea61740394 Mon Sep 17 00:00:00 2001
From: Neil Horne <15316949+elecpower@users.noreply.github.com>
Date: Wed, 12 Jun 2024 10:20:49 +1000
Subject: [PATCH] fix(cpn): profile conversion of models and settings (#5151)

---
 companion/src/firmwares/generalsettings.cpp      | 16 ++++++++++------
 companion/src/firmwares/moduledata.cpp           | 12 ++++++++----
 .../src/firmwares/radiodataconversionstate.cpp   | 14 ++++++++++----
 .../src/firmwares/radiodataconversionstate.h     |  2 ++
 companion/src/firmwares/rawsource.cpp            |  3 ++-
 companion/src/firmwares/rawswitch.cpp            |  3 ++-
 6 files changed, 34 insertions(+), 16 deletions(-)

diff --git a/companion/src/firmwares/generalsettings.cpp b/companion/src/firmwares/generalsettings.cpp
index 6a417a87979..c75bd265891 100644
--- a/companion/src/firmwares/generalsettings.cpp
+++ b/companion/src/firmwares/generalsettings.cpp
@@ -398,6 +398,7 @@ void GeneralSettings::convert(RadioDataConversionState & cstate)
 
   for (int i = 0; i < Boards::getCapability(cstate.fromType, Board::Inputs); i++) {
     if (Boards::isInputConfigurable(i, cstate.fromType)) {
+      cstate.withComponentField("");
       cstate.setItemType(Boards::isInputStick(i, cstate.fromType) ? tr("Axis") : tr("Pot"));
       RadioDataConversionState::LogField oldData(i, Boards::getInputName(i, cstate.fromType));
       const int idx = Boards::getInputIndex(Boards::getInputTag(i, cstate.fromType), Board::LVT_TAG, cstate.toType);
@@ -422,7 +423,7 @@ void GeneralSettings::convert(RadioDataConversionState & cstate)
         // do not copy calibration - use defaults as safer
       }
       else if (cstate.fromGS()->inputConfig[i].type == Board::AIT_FLEX && cstate.fromGS()->inputConfig[i].flexType != Board::FLEX_NONE) {
-        cstate.setInvalid(oldData);
+        cstate.setUnsupported(oldData);
       }
     }
   }
@@ -431,6 +432,7 @@ void GeneralSettings::convert(RadioDataConversionState & cstate)
 
   for (int i = 0; i < Boards::getCapability(cstate.fromType, Board::Switches); i++) {
     if (Boards::isSwitchConfigurable(i, cstate.fromType)) {
+      cstate.withComponentField("");
       cstate.setItemType(Boards::isSwitchFlex(i, cstate.fromType) ? tr("Flex Switch") :
                          Boards::isSwitchFunc(i, cstate.fromType) ? tr("Function Switch") : tr("Switch"));
       RadioDataConversionState::LogField oldData(i, Boards::getSwitchName(i, cstate.fromType));
@@ -443,9 +445,12 @@ void GeneralSettings::convert(RadioDataConversionState & cstate)
 
         if (Boards::getSwitchInfo(i, cstate.fromType).type > Boards::getSwitchInfo(idx, cstate.toType).type) {
           cstate.withComponentField(Boards::getSwitchName(i, cstate.fromType));
+          cstate.setItemType(Boards::isSwitchFlex(i, cstate.fromType) ? tr("Flex Switch") :
+                             Boards::isSwitchFunc(i, cstate.fromType) ? tr("Function Switch") : tr("Switch"));
           RadioDataConversionState::LogField oldSWT(i, Boards::switchTypeToString(fromcfg.type));
-          tocfg.type = Board::SWITCH_NOT_AVAILABLE;
-          cstate.setConverted(oldSWT, RadioDataConversionState::LogField(i, Boards::switchTypeToString(fromcfg.type)));
+          // switch type not supported on to profile so leave as hw default eg from 3 Pos and to 2 Pos
+          // if switch position not supported it will be reported where used on each model
+          cstate.setConverted(oldSWT, RadioDataConversionState::LogField(i, Boards::switchTypeToString(tocfg.type)));
         }
         else
           tocfg.type = fromcfg.type;
@@ -464,9 +469,8 @@ void GeneralSettings::convert(RadioDataConversionState & cstate)
             tocfg.inputIdx = fromcfg.inputIdx;
         }
       }
-      else if (cstate.fromGS()->switchConfig[i].type != Board::SWITCH_NOT_AVAILABLE) {
-        cstate.setInvalid(oldData);
-      }
+      else if (cstate.fromGS()->switchConfig[i].type != Board::SWITCH_NOT_AVAILABLE)
+        cstate.setUnsupported(oldData);
     }
   }
 
diff --git a/companion/src/firmwares/moduledata.cpp b/companion/src/firmwares/moduledata.cpp
index 5ae9f47a5a1..48591b42e09 100644
--- a/companion/src/firmwares/moduledata.cpp
+++ b/companion/src/firmwares/moduledata.cpp
@@ -48,15 +48,19 @@ void ModuleData::convert(RadioDataConversionState & cstate)
     //else if (!isProtocolAvailable(cstate.subCompIdx, (PulsesProtocol) protocol, cstate.toGS)) {
       evt = RadioDataConversionState::EVT_INV;
     }
+
+    if (evt == RadioDataConversionState::EVT_INV) {
+      cstate.setInvalid(oldData);
+    }
   }
   else {
-    evt = RadioDataConversionState::EVT_INV;
-    qDebug() << "Error - current firmware board does not match conversion to board!";
+    evt = RadioDataConversionState::EVT_ERR;
+    cstate.setErr(tr("Current firmware board does not match conversion to board"));
   }
 
-  if (evt == RadioDataConversionState::EVT_INV) {
-    cstate.setInvalid(oldData);
+  if (evt != RadioDataConversionState::EVT_NONE) {
     clear();
+    cstate.setConverted(oldData, RadioDataConversionState::LogField(protocol, protocolToString(protocol)));
   }
 }
 
diff --git a/companion/src/firmwares/radiodataconversionstate.cpp b/companion/src/firmwares/radiodataconversionstate.cpp
index 5901754d2d9..6a554ad92c5 100644
--- a/companion/src/firmwares/radiodataconversionstate.cpp
+++ b/companion/src/firmwares/radiodataconversionstate.cpp
@@ -126,6 +126,12 @@ void RadioDataConversionState::setMoved(const LogField & from, const LogField &
   addLogEntry(EVT_INF, tr("verify is"));
 }
 
+void RadioDataConversionState::setUnsupported(const LogField & item)
+{
+  setLogField(FLD_ITM_BEFORE, item);
+  addLogEntry(EVT_UNSUP, tr("unsupported"));
+}
+
 const ModelData * RadioDataConversionState::toModel() const
 {
   if (rd && modelIdx > -1 && modelIdx < (int)rd->models.size())
@@ -161,15 +167,15 @@ bool RadioDataConversionState::hasLogEntries(EventType logLevel) const
 
 QString RadioDataConversionState::eventTypeToString(int type) const
 {
-  // enum EventType                             { EVT_NONE,   EVT_DBG,       EVT_INF,       EVT_WRN,       EVT_CVRT,      EVT_ERR,       EVT_INV
-  static const QStringList evtTypes =  QStringList() << "" << tr("[DBG]") << tr("[NFO]") << tr("[WRN]") << tr("[CVT]") << tr("[ERR]") << tr("[INV]");
+  // enum EventType                             { EVT_NONE,   EVT_DBG,       EVT_INF,       EVT_WRN,       EVT_CVRT,      EVT_ERR,       EVT_INV,       EVT_UNSUP
+  static const QStringList evtTypes =  QStringList() << "" << tr("[DBG]") << tr("[NFO]") << tr("[WRN]") << tr("[CVT]") << tr("[ERR]") << tr("[INV]") << tr("[XSP]");
   return (type < evtTypes.size() ? evtTypes.at(type) : "");
 }
 
 QString RadioDataConversionState::eventTypeToColor(int type) const
 {
-  // enum EventType                                   { EVT_NONE,  EVT_DBG,     EVT_INF,   EVT_WRN,     EVT_CVRT,    EVT_ERR,  EVT_INV
-  static const QStringList evtColors = QStringList() << "black" << "dimgrey" << "black" << "#ea7104" << "#ea7104" << "red"  << "red";
+  // enum EventType                                   { EVT_NONE,  EVT_DBG,     EVT_INF,   EVT_WRN,     EVT_CVRT,    EVT_ERR,  EVT_INV, EVT_UNSUP
+  static const QStringList evtColors = QStringList() << "black" << "dimgrey" << "black" << "orange" << "magenta" << "red"  << "red"  << "blue";
   return (type < evtColors.size() ? evtColors.at(type) : "black");
 }
 
diff --git a/companion/src/firmwares/radiodataconversionstate.h b/companion/src/firmwares/radiodataconversionstate.h
index dd319d11524..e8e86cf27f8 100644
--- a/companion/src/firmwares/radiodataconversionstate.h
+++ b/companion/src/firmwares/radiodataconversionstate.h
@@ -42,6 +42,7 @@ class RadioDataConversionState
       EVT_CVRT,  // something was converted (A->B)
       EVT_ERR,   // misc. error, place error-level events after this
       EVT_INV,   // invalid, control/etc not available on destination radio
+      EVT_UNSUP, // unsupported, control not available on destiation radio
     };
 
     enum LogFieldType {
@@ -89,6 +90,7 @@ class RadioDataConversionState
     void setInvalid(const LogField & item);
     void setConverted(const LogField & from, const LogField & to);
     void setMoved(const LogField & from, const LogField & to);
+    void setUnsupported(const LogField & item);
     inline void setDbg(const QString & msg) { addLogEntry(EVT_DBG, msg); }
     inline void setInf(const QString & msg) { addLogEntry(EVT_INF, msg); }
     inline void setWrn(const QString & msg) { addLogEntry(EVT_WRN, msg); }
diff --git a/companion/src/firmwares/rawsource.cpp b/companion/src/firmwares/rawsource.cpp
index bcde00787c0..d43c6a06394 100644
--- a/companion/src/firmwares/rawsource.cpp
+++ b/companion/src/firmwares/rawsource.cpp
@@ -377,7 +377,7 @@ bool RawSource::isAvailable(const ModelData * const model, const GeneralSettings
 
 RawSource RawSource::convert(RadioDataConversionState & cstate)
 {
-  cstate.setItemType(tr("SRC"), 1);
+  cstate.setItemType(tr("Source"), 1);
   RadioDataConversionState::LogField oldData(index, toString(cstate.fromModel(), cstate.fromGS(), cstate.fromType));
 
   if (type == SOURCE_TYPE_INPUT)
@@ -389,6 +389,7 @@ RawSource RawSource::convert(RadioDataConversionState & cstate)
   if (index < 0 || !isAvailable(nullptr, cstate.toGS(), cstate.toType)) {
     cstate.setInvalid(oldData);
     clear();  // no source is safer than an invalid one
+    cstate.setConverted(oldData, RadioDataConversionState::LogField(index, tr("None")));
   }
 
   return *this;
diff --git a/companion/src/firmwares/rawswitch.cpp b/companion/src/firmwares/rawswitch.cpp
index de8825c2650..da7d055798d 100644
--- a/companion/src/firmwares/rawswitch.cpp
+++ b/companion/src/firmwares/rawswitch.cpp
@@ -206,7 +206,7 @@ RawSwitch RawSwitch::convert(RadioDataConversionState & cstate)
   if (!index)
     return *this;
 
-  cstate.setItemType(tr("SW"), 2);
+  cstate.setItemType(tr("Switch"), 2);
   RadioDataConversionState::LogField oldData(index, toString(cstate.fromType, cstate.fromGS(), cstate.fromModel()));
 
   int newIdx = 0;
@@ -223,6 +223,7 @@ RawSwitch RawSwitch::convert(RadioDataConversionState & cstate)
   if (newIdx < 0 || !isAvailable(nullptr, cstate.toGS(), cstate.toType)) {
     cstate.setInvalid(oldData);
     clear();  // no switch is safer than an invalid one
+    cstate.setConverted(oldData, RadioDataConversionState::LogField(index, tr("None")));
   }
 
   return *this;