137 lines
19 KiB
Diff
137 lines
19 KiB
Diff
--- a/DSView/pv/view/decodetrace.cpp
|
|
+++ b/DSView/pv/view/decodetrace.cpp
|
|
@@ -188,9 +188,17 @@
|
|
|
|
}
|
|
|
|
+static QString pwm_motor_scale(pv::data::decode::Decoder *decoder) // Физическая шкала тока относится к тому же экземпляру, который создал нормированные сегменты.
|
|
+{ // Старый декодер заполнения сохраняет прежнюю безразмерную шкалу.
|
|
+ if (QString::fromUtf8(decoder->decoder()->id) != "pwm_motor") return ": -1 .. +1"; // Только модель двигателя имеет значения в амперах.
|
|
+ const auto option = decoder->options().find("plot_range_a"); // Шкала сохраняется штатным механизмом настроек DSL.
|
|
+ const double range = option != decoder->options().end() && option->second && g_variant_is_of_type(option->second, G_VARIANT_TYPE_DOUBLE) ? g_variant_get_double(option->second) : 100.0; // Сто ампер соответствует исходному значению адаптера при отсутствии опции в записи.
|
|
+ return QString(": -%1 .. +%1 A (estimate)").arg(range, 0, 'g', 6); // Единицы и расчётный характер значения видны рядом с общей либо отдельной кривой.
|
|
+} // Физический ток в таблице остаётся ненормированным независимо от выбранной шкалы.
|
|
+
|
|
static bool pwm_combined(pv::data::decode::Decoder *decoder) // Режим берётся из штатных настроек конкретного экземпляра декодера.
|
|
{ // Старые записи без новой опции должны открываться с прежними отдельными графиками.
|
|
- if (QString::fromUtf8(decoder->decoder()->id) != "pwm_waveform") return false; // Настройка PWM не меняет компоновку остальных анализаторов.
|
|
+ if ((QString::fromUtf8(decoder->decoder()->id) != "pwm_waveform" && QString::fromUtf8(decoder->decoder()->id) != "pwm_motor")) return false; // Настройка PWM не меняет компоновку остальных анализаторов.
|
|
const auto option = decoder->options().find("waveform_layout"); // Ищем сохранённый параметр без добавления отсутствующего ключа в карту.
|
|
return option != decoder->options().end() && option->second && g_variant_is_of_type(option->second, G_VARIANT_TYPE_STRING) // Проверяем тип перед чтением, чтобы повреждённая настройка не завершила приложение.
|
|
&& QString::fromUtf8(g_variant_get_string(option->second, nullptr)) == "combined"; // Только явно выбранный combined включает наложение цветных кривых.
|
|
@@ -260,7 +268,7 @@
|
|
if ((*i).second) {
|
|
const Row &row = (*i).first;
|
|
// Для обзорного масштаба берём индексированные экстремумы, сохраняя кривую и короткие выбросы.
|
|
- if (QString::fromUtf8(dec->decoder()->id) == "pwm_waveform" // Специальная геометрия применяется только к декодеру восстановления ШИМ.
|
|
+ if ((QString::fromUtf8(dec->decoder()->id) == "pwm_waveform" || QString::fromUtf8(dec->decoder()->id) == "pwm_motor") // Специальная геометрия применяется только к декодеру восстановления ШИМ.
|
|
&& row.row() && QString::fromUtf8(row.row()->id).startsWith("wave_")) { // Числовые строки duty продолжают использовать штатные аннотации.
|
|
std::vector<set_pwm::Line> points; // Геометрия ограничивается шириной видимой области вместо числа периодов во всей записи.
|
|
_decoder_stack->get_pwm_waveform(points, row, start_sample, end_sample, std::max(1, right - left)); // Индекс экстремумов сохраняет короткие пики при уменьшении масштаба.
|
|
@@ -295,7 +303,7 @@
|
|
_cur_row_heading_offsets.push_back(row_top); // Заголовок графика привязывается к его фактической верхней границе.
|
|
row_top += annotation_height * 3; // Масштабируемая область сохраняет прежнюю высоту из трёх строк на график.
|
|
y += annotation_height * 3; // Следующая графическая область начинается сразу после текущей.
|
|
- QString title = row.title(); // Раздельный график сохраняет прежнее название своего канала.
|
|
+ QString title = row.title() + (QString::fromUtf8(dec->decoder()->id) == "pwm_motor" ? pwm_motor_scale(dec) : QString()); // Раздельный график сохраняет прежнее название своего канала.
|
|
if (row_combined) { // Общая подпись перечисляет только основные видимые фазы, сохраняя собственные шкалы θ и несущей.
|
|
QStringList channels; // Список нужен для записи с одним, двумя или тремя видимыми входами.
|
|
for (const auto &entry : rows) { // Порядок совпадает с порядком строк и цветами A, B, C.
|
|
@@ -303,7 +311,7 @@
|
|
&& QString::fromUtf8(entry.first.row()->id).size() == 6 && QString::fromUtf8(entry.first.row()->id).startsWith("wave_") && _decoder_stack->has_annotations(entry.first)) // Из общей подписи исключены неподключённые фазы и дополнительные расчётные графики.
|
|
channels.append(QString::fromUtf8(entry.first.row()->id).right(1).toUpper()); // Суффикс wave_a…wave_c даёт обозначение фазы без разбора текста аннотаций.
|
|
} // Полученный список соответствует кривым, которые действительно будут нарисованы.
|
|
- title = QString::fromUtf8(dec->decoder()->name) + ": " + channels.join(" / ") + ": -1 .. +1"; // Общая шкала остаётся нормированной для всех видимых каналов.
|
|
+ title = QString::fromUtf8(dec->decoder()->name) + ": " + channels.join(" / ") + pwm_motor_scale(dec); // Общая шкала остаётся нормированной для всех видимых каналов.
|
|
} // Значения PWM и числовые результаты не изменяются при переключении вида.
|
|
_cur_row_headings.push_back(title); // Единственный заголовок относится ко всей выделенной области.
|
|
} // Повторная совмещённая фаза не сдвигает последующие аннотации.
|
|
@@ -627,6 +635,7 @@
|
|
{
|
|
on_new_decode_data();
|
|
_session->decode_done();
|
|
+ if (_view) _view->data_updated(); // Финальная перерисовка обновляет кэш после последних сегментов и диагностических строк, добавленных в end декодера.
|
|
}
|
|
|
|
int DecodeTrace::rows_size()
|
|
@@ -646,7 +655,7 @@
|
|
_decoder_stack->has_annotations((*i).first) &&
|
|
(*i).second)
|
|
{ // Учитываем только заполненные строки, разрешённые в настройках Decoders.
|
|
- const bool waveform = QString::fromUtf8(dec->decoder()->id) == "pwm_waveform" // Особая высота относится только к кривым восстановления ШИМ.
|
|
+ const bool waveform = (QString::fromUtf8(dec->decoder()->id) == "pwm_waveform" || QString::fromUtf8(dec->decoder()->id) == "pwm_motor") // Особая высота относится только к кривым восстановления ШИМ.
|
|
&& _row.row() && QString::fromUtf8(_row.row()->id).startsWith("wave_"); // Числовые duty/frequency строки сохраняют собственное место.
|
|
const bool phase_wave = waveform && QString::fromUtf8(_row.row()->id).size() == 6; // Только wave_a…wave_c относятся к общей области фаз; θ и несущая имеют собственную высоту.
|
|
if (phase_wave && combined && wave_shown) continue; // Следующая совмещённая основная фаза не увеличивает полную высоту дорожки.
|
|
@@ -674,7 +683,7 @@
|
|
int size = 0; // Текстовый анализатор без графиков не имеет масштабируемой области.
|
|
const auto rows = _decoder_stack->get_rows_gshow(); // Используем тот же порядок видимых строк, что нативный рендерер.
|
|
for (auto dec : _decoder_stack->stack()) { // У каждого экземпляра стека собственная настройка совмещения фаз.
|
|
- if (!dec->shown() || QString::fromUtf8(dec->decoder()->id) != "pwm_waveform") continue; // Скрытые и обычные текстовые декодеры не меняют фиксированную геометрию.
|
|
+ if (!dec->shown() || (QString::fromUtf8(dec->decoder()->id) != "pwm_waveform" && QString::fromUtf8(dec->decoder()->id) != "pwm_motor")) continue; // Скрытые и обычные текстовые декодеры не меняют фиксированную геометрию.
|
|
bool phase_shown = false; // Совмещённая область A/B/C учитывается отдельно от самостоятельных графиков θ и несущей.
|
|
for (const auto &entry : rows) { // Неподключённые и скрытые каналы исключаются до выделения высоты.
|
|
if (entry.first.decoder() != dec->decoder() || !entry.second || !entry.first.row() || !_decoder_stack->has_annotations(entry.first)) continue; // Должны совпасть экземпляр декодера, наличие данных и разрешение показа строки.
|
|
--- a/DSView/pv/data/decoderstack.cpp
|
|
+++ b/DSView/pv/data/decoderstack.cpp
|
|
@@ -187,7 +187,7 @@
|
|
const Row row(decc, ann_row, order);
|
|
|
|
// Add a new empty row data object
|
|
- const bool waveform = QString::fromUtf8(decc->id) == "pwm_waveform" && QString::fromUtf8(ann_row->id).startsWith("wave_"); // Только графические строки PWM требуют многоуровневого индекса.
|
|
+ const bool waveform = (QString::fromUtf8(decc->id) == "pwm_waveform" || QString::fromUtf8(decc->id) == "pwm_motor") && QString::fromUtf8(ann_row->id).startsWith("wave_"); // Только графические строки PWM требуют многоуровневого индекса.
|
|
_rows[row] = new decode::RowData(waveform); // Индекс создаётся вместе со строкой и очищается при повторном анализе.
|
|
std::map<const decode::Row, bool>::const_iterator iter = _rows_gshow.find(row);
|
|
if (iter == _rows_gshow.end()) {
|
|
--- a/DSView/pv/data/decode/decoder.cpp
|
|
+++ b/DSView/pv/data/decode/decoder.cpp
|
|
@@ -83,7 +83,7 @@
|
|
if (_setted) {
|
|
bool changed = !_committed || _probes != _probes_back || _decode_start != _decode_start_back || _decode_end != _decode_end_back; // Повторный анализ нужен при первом применении, новых входах или изменении границ отсчётов.
|
|
for (const auto &option : _options_back) { // Диалог повторно передаёт и неизменённые параметры, поэтому сравниваем значения, а не факт вызова setter.
|
|
- if (std::string(_decoder->id) == "pwm_waveform" && option.first == "waveform_layout") continue; // Наложение фаз меняет только отрисовку уже рассчитанных кривых.
|
|
+ if ((std::string(_decoder->id) == "pwm_waveform" || std::string(_decoder->id) == "pwm_motor") && option.first == "waveform_layout") continue; // Наложение фаз меняет только отрисовку уже рассчитанных кривых.
|
|
const auto previous = _options.find(option.first); // Ищем значение, с которым построены сохранённые аннотации.
|
|
GVariant *value = previous == _options.end() ? nullptr : previous->second; // Отсутствующий ключ означает штатное значение декодера, а не автоматическое изменение.
|
|
if (!value) for (const GSList *item = _decoder->options; item; item = item->next) { // Сравниваем явно сохранённый параметр с его исходным значением по умолчанию.
|
|
--- a/DSView/pv/dock/protocoldock.cpp
|
|
+++ b/DSView/pv/dock/protocoldock.cpp
|
|
@@ -383,7 +383,7 @@
|
|
log(QString("display cache phase %1: %2").arg(phase).arg(ok ? "ok" : "FAIL")); // Журнал различает видимость, неизменённый диалог и раскладку графиков.
|
|
} // После всех принятий остаются результаты единственного исходного декодирования.
|
|
auto decoder = stack->stack().front(); // Контрольное изменение реального параметра должно по-прежнему требовать нового анализа.
|
|
- if (QString::fromUtf8(decoder->decoder()->id) == "pwm_waveform") { // Проверка использует математический параметр сглаживания штатного PWM-декодера.
|
|
+ if ((QString::fromUtf8(decoder->decoder()->id) == "pwm_waveform" || QString::fromUtf8(decoder->decoder()->id) == "pwm_motor")) { // Проверка использует математический параметр сглаживания штатного PWM-декодера.
|
|
decoder->set_option("smoothing_ms", g_variant_new_double(1.0)); // Отличие на одну миллисекунду меняет вычисляемую кривую, поэтому игнорировать его нельзя.
|
|
ok = decoder->commit() && ok; // Новое вычислительное значение обязано инвалидировать прежние результаты.
|
|
decoder->set_option("smoothing_ms", g_variant_new_double(0.0)); // Возвращаем стандартный режим без сглаживания для проверочной записи.
|
|
@@ -465,8 +465,8 @@
|
|
const auto after = _protocol_lay_items.size();
|
|
ok = phase % 2 == 0 ? after == before : after == (phase == 1 ? before - 1 : 0);
|
|
}
|
|
- } else if (phase < 9) { // Проверяем также новый парсер терминальных UART-посылок ТМС.
|
|
- const QString id = QStringList({"gate_driver_timing", "set_uart", "set_can", "pm35_uart", "tms_uart"})[phase - 4]; // Индекс отсчитывается после четырёх проверок удаления анализаторов.
|
|
+ } else if (phase < 10) { // Проверяем штатное добавление пяти протокольных анализаторов и модели токов двигателя через реальные диалоги DSView.
|
|
+ const QString id = QStringList({"gate_driver_timing", "set_uart", "set_can", "pm35_uart", "tms_uart", "pwm_motor"})[phase - 4]; // Индекс отсчитывается после четырёх проверок удаления анализаторов.
|
|
if (get_protocol_index_by_id(id) < 0) ok = false;
|
|
else {
|
|
QTimer::singleShot(80, this, [report, id]() {
|
|
@@ -486,7 +486,7 @@
|
|
ok = QString(trace->decoder()->stack().back()->decoder()->id) == id;
|
|
}
|
|
}
|
|
- } else if (phase == 9) { // После пяти прикладных анализаторов проверяем удаление всего набора дорожек.
|
|
+ } else if (phase == 10) { // После шести анализаторов, включая фазные токи двигателя, проверяем удаление всего набора дорожек.
|
|
answer(QMessageBox::Yes);
|
|
on_del_all_protocol();
|
|
ok = _protocol_lay_items.empty() && _session->get_decode_signals().empty();
|
|
@@ -1155,7 +1155,7 @@
|
|
{
|
|
SearchComboBox *panel = new SearchComboBox(this);
|
|
|
|
- const QStringList customIds = {"gate_driver_timing", "transistor_pair", "pwm_waveform", "set_uart", "set_can", "pm35_uart", "tms_uart", "plates_pbus", "plates_sbus"}; // При сборке пользовательский раздел включает анализаторы обеих шин 96-контактного интерфейса.
|
|
+ const QStringList customIds = {"gate_driver_timing", "transistor_pair", "pwm_waveform", "pwm_motor", "set_uart", "set_can", "pm35_uart", "tms_uart", "plates_pbus", "plates_sbus"}; // При сборке пользовательский раздел включает анализаторы обеих шин 96-контактного интерфейса.
|
|
for (bool custom : {true, false}) {
|
|
for (auto info : _decoderInfoList) {
|
|
srd_decoder *dec = (srd_decoder *)(info->_data_handle);
|