| 418 | } |
| 419 | |
| 420 | void MeterModel::updateValues(const QVector<quint16>& ids, const QVector<qint16>& vals) |
| 421 | { |
| 422 | const int n = qMin(ids.size(), vals.size()); |
| 423 | const qint64 packetUpdatedMs = QDateTime::currentMSecsSinceEpoch(); |
| 424 | const int activeCompPeakIdx = compPeakIndexForActiveTxSlice(); |
| 425 | // sLevelChanged is emitted per-slice inline in the loop below |
| 426 | bool txChanged = false; |
| 427 | bool fwdInstantChanged = false; |
| 428 | bool micChanged = false; |
| 429 | bool hwAlcChangedFlag = false; |
| 430 | bool swAlcChangedFlag = false; |
| 431 | bool hwChanged = false; |
| 432 | bool ampChanged = false; |
| 433 | bool tgxlChanged = false; |
| 434 | |
| 435 | for (int i = 0; i < n; ++i) { |
| 436 | const int idx = static_cast<int>(ids[i]); |
| 437 | auto it = m_defs.constFind(idx); |
| 438 | if (it == m_defs.constEnd()) continue; |
| 439 | |
| 440 | const float v = convertRaw(*it, vals[i]); |
| 441 | m_values[idx] = v; |
| 442 | m_valueUpdatedMs[idx] = packetUpdatedMs; // per-meter freshness (#3646) |
| 443 | |
| 444 | // Check if this meter is a per-slice LEVEL meter |
| 445 | bool isSliceLevel = false; |
| 446 | for (auto sit = m_sLevelIdxBySlice.constBegin(); sit != m_sLevelIdxBySlice.constEnd(); ++sit) { |
| 447 | if (sit.value() == idx) { |
| 448 | emit sLevelChanged(sit.key(), v); |
| 449 | isSliceLevel = true; |
| 450 | break; |
| 451 | } |
| 452 | } |
| 453 | // Check if this meter is a per-slice ESC meter |
| 454 | if (!isSliceLevel) { |
| 455 | for (auto sit = m_escLevelIdxBySlice.constBegin(); sit != m_escLevelIdxBySlice.constEnd(); ++sit) { |
| 456 | if (sit.value() == idx) { |
| 457 | emit escLevelChanged(sit.key(), v); |
| 458 | isSliceLevel = true; |
| 459 | break; |
| 460 | } |
| 461 | } |
| 462 | } |
| 463 | if (isSliceLevel) { |
| 464 | // no-op, already emitted |
| 465 | } else if (idx == m_fwdPwrIdx) { |
| 466 | m_lastTxMeterUpdateMs = packetUpdatedMs; |
| 467 | m_lastFwdPowerUpdateMs = m_lastTxMeterUpdateMs; |
| 468 | // FWDPWR meter reports in dBm — convert to watts for display. |
| 469 | // watts = 10^(dBm/10) / 1000 |
| 470 | // e.g. 50 dBm = 100 W, 47 dBm ≈ 50 W, 40 dBm = 10 W |
| 471 | float watts = std::pow(10.0f, v / 10.0f) / 1000.0f; |
| 472 | m_fwdPowerInstant = watts; |
| 473 | fwdInstantChanged = true; |
| 474 | // Smooth: fast attack (α=0.5) to track peaks, slow decay (α=0.15) |
| 475 | // for stable display without jitter (#980) |
| 476 | if (m_fwdPower < 0.01f) { |
| 477 | m_fwdPower = watts; // first sample — no smoothing |