| 80 | } // namespace |
| 81 | |
| 82 | TciServer::TciServer(RadioModel* model, QObject* parent) |
| 83 | : QObject(parent) |
| 84 | , m_model(model) |
| 85 | { |
| 86 | // Load per-channel RX gains from persistence (decoupled from DaxRxGain<n>, #1627). |
| 87 | // Migrate DaxRxGain<n> → TciRxGain<n> on first read so existing users keep |
| 88 | // their current balance when the applets split. |
| 89 | { |
| 90 | auto& s = AppSettings::instance(); |
| 91 | for (int ch = 1; ch <= 4; ++ch) { |
| 92 | const QString key = QStringLiteral("TciRxGain%1").arg(ch); |
| 93 | if (!s.contains(key)) { |
| 94 | const QString legacy = s.value(QStringLiteral("DaxRxGain%1").arg(ch), "0.5").toString(); |
| 95 | s.setValue(key, legacy); |
| 96 | } |
| 97 | m_rxChannelGain[ch - 1] = std::clamp( |
| 98 | s.value(key, "0.5").toString().toFloat(), 0.0f, 1.0f); |
| 99 | } |
| 100 | s.save(); |
| 101 | } |
| 102 | |
| 103 | // Cache S-meter values for periodic broadcast (avoid flooding clients) |
| 104 | if (m_model) { |
| 105 | connect(&m_model->meterModel(), &MeterModel::sLevelChanged, |
| 106 | this, [this](int sliceIndex, float dbm) { |
| 107 | if (sliceIndex >= 0 && sliceIndex < 8) |
| 108 | m_cachedSLevel[sliceIndex] = dbm; |
| 109 | }); |
| 110 | } |
| 111 | |
| 112 | // Cache TX meter values |
| 113 | if (m_model) { |
| 114 | connect(&m_model->meterModel(), &MeterModel::txMetersChanged, |
| 115 | this, [this](float fwd, float swr) { |
| 116 | m_cachedFwdPower = fwd; |
| 117 | m_cachedSwr = swr; |
| 118 | }); |
| 119 | connect(&m_model->meterModel(), &MeterModel::micMetersChanged, |
| 120 | this, [this](float micLevel, float, float, float) { |
| 121 | m_cachedMicLevel = micLevel; |
| 122 | }); |
| 123 | connect(&m_model->meterModel(), &MeterModel::swAlcChanged, |
| 124 | this, [this](float dbfs) { |
| 125 | m_cachedAlc = dbfs; |
| 126 | }); |
| 127 | } |
| 128 | |
| 129 | // Capture DAX RX stream creation responses so we can register them |
| 130 | // in PanadapterStream for VITA-49 routing (#1331). |
| 131 | if (m_model) { |
| 132 | connect(m_model, &RadioModel::statusReceived, |
| 133 | this, [this](const QString& obj, const QMap<QString,QString>& kvs) { |
| 134 | if (!obj.startsWith("stream ")) return; |
| 135 | const QStringList parts = obj.split(QLatin1Char(' '), Qt::SkipEmptyParts); |
| 136 | if (parts.size() < 2) return; |
| 137 | bool ok = false; |
| 138 | quint32 streamId = parts[1].toUInt(&ok, 0); |
| 139 | if (!ok || streamId == 0) return; |
nothing calls this directly
no test coverage detected