From: Soeren Apel Date: Tue, 4 Jul 2017 20:17:22 +0000 (+0200) Subject: Re-use DecodeTrace::ChannelSelector as DecodeChannel X-Git-Url: https://sigrok.org/gitaction?a=commitdiff_plain;h=9f97b3576f527239594ea0accb82a4087147c746;p=pulseview.git Re-use DecodeTrace::ChannelSelector as DecodeChannel --- diff --git a/pv/data/decode/decoder.cpp b/pv/data/decode/decoder.cpp index 841d4fd7..ffdbeb93 100644 --- a/pv/data/decode/decoder.cpp +++ b/pv/data/decode/decoder.cpp @@ -37,8 +37,7 @@ namespace decode { Decoder::Decoder(const srd_decoder *const dec) : decoder_(dec), - shown_(true), - initial_pins_(nullptr) + shown_(true) { } @@ -75,18 +74,6 @@ void Decoder::set_channels(map& Decoder::options() const { return options_; @@ -143,11 +130,20 @@ srd_decoder_inst* Decoder::create_decoder_inst(srd_session *session) const return nullptr; // Setup the channels + GArray *const init_pin_states = g_array_sized_new(FALSE, TRUE, + sizeof(uint8_t), channels_.size()); + + g_array_set_size(init_pin_states, channels_.size()); + GHashTable *const channels = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, (GDestroyNotify)g_variant_unref); for (const auto& channel : channels_) { shared_ptr b(channel.second); + +// init_pin_states->data[pdch->order] = +// channel.initial_pin_state; + GVariant *const gvar = g_variant_new_int32(b->index()); g_variant_ref_sink(gvar); g_hash_table_insert(channels, channel.first->id, gvar); @@ -155,7 +151,8 @@ srd_decoder_inst* Decoder::create_decoder_inst(srd_session *session) const srd_inst_channel_set_all(decoder_inst, channels); - srd_inst_initial_pins_set_all(decoder_inst, initial_pins_); +// srd_inst_initial_pins_set_all(decoder_inst, initial_pin_states); + g_array_free(init_pin_states, TRUE); return decoder_inst; } diff --git a/pv/data/decode/decoder.hpp b/pv/data/decode/decoder.hpp index eff2367f..1b655662 100644 --- a/pv/data/decode/decoder.hpp +++ b/pv/data/decode/decoder.hpp @@ -62,10 +62,6 @@ public: void set_channels(map > channels); - void set_initial_pins(GArray *initial_pins); - - GArray *initial_pins() const; - const map& options() const; void set_option(const char *id, GVariant *value); @@ -82,7 +78,6 @@ private: bool shown_; map > channels_; - GArray *initial_pins_; map options_; }; diff --git a/pv/data/decodesignal.cpp b/pv/data/decodesignal.cpp index 253e3a98..6bc691ab 100644 --- a/pv/data/decodesignal.cpp +++ b/pv/data/decodesignal.cpp @@ -42,6 +42,8 @@ DecodeSignal::DecodeSignal(shared_ptr decoder_stack) : { set_name(QString::fromUtf8(decoder_stack_->stack().front()->decoder()->name)); + update_channel_list(); + connect(decoder_stack_.get(), SIGNAL(new_annotations()), this, SLOT(on_new_annotations())); } @@ -70,12 +72,14 @@ void DecodeSignal::stack_decoder(srd_decoder *decoder) assert(decoder); assert(decoder_stack); decoder_stack_->push(make_shared(decoder)); + update_channel_list(); decoder_stack_->begin_decode(); } void DecodeSignal::remove_decoder(int index) { decoder_stack_->remove(index); + update_channel_list(); decoder_stack_->begin_decode(); } @@ -104,6 +108,33 @@ QString DecodeSignal::error_message() const return decoder_stack_->error_message(); } +const list DecodeSignal::get_channels() const +{ + return channels_; +} + +void DecodeSignal::assign_signal(const uint16_t channel_id, const SignalBase *signal) +{ + for (data::DecodeChannel &ch : channels_) + if (ch.id == channel_id) + ch.assigned_signal = signal; + + channels_updated(); + + decoder_stack_->begin_decode(); +} + +void DecodeSignal::set_initial_pin_state(const uint16_t channel_id, const int init_state) +{ + for (data::DecodeChannel &ch : channels_) + if (ch.id == channel_id) + ch.initial_pin_state = init_state; + + channels_updated(); + + decoder_stack_->begin_decode(); +} + vector DecodeSignal::visible_rows() const { return decoder_stack_->get_visible_rows(); @@ -118,6 +149,68 @@ void DecodeSignal::get_annotation_subset( start_sample, end_sample); } +void DecodeSignal::update_channel_list() +{ + list prev_channels = channels_; + channels_.clear(); + + uint16_t id = 0; + + // Copy existing entries, create new as needed + for (shared_ptr decoder : decoder_stack_->stack()) { + const srd_decoder* srd_d = decoder->decoder(); + const GSList *l; + + // Mandatory channels + for (l = srd_d->channels; l; l = l->next) { + const struct srd_channel *const pdch = (struct srd_channel *)l->data; + bool ch_added = false; + + // Copy but update ID if this channel was in the list before + for (data::DecodeChannel ch : prev_channels) + if (ch.pdch_ == pdch) { + ch.id = id++; + channels_.push_back(ch); + ch_added = true; + break; + } + + if (!ch_added) { + // Create new entry without a mapped signal + data::DecodeChannel ch = {id++, false, nullptr, + QString::fromUtf8(pdch->name), QString::fromUtf8(pdch->desc), + SRD_INITIAL_PIN_SAME_AS_SAMPLE0, decoder, pdch}; + channels_.push_back(ch); + } + } + + // Optional channels + for (l = srd_d->opt_channels; l; l = l->next) { + const struct srd_channel *const pdch = (struct srd_channel *)l->data; + bool ch_added = false; + + // Copy but update ID if this channel was in the list before + for (data::DecodeChannel ch : prev_channels) + if (ch.pdch_ == pdch) { + ch.id = id++; + channels_.push_back(ch); + ch_added = true; + break; + } + + if (!ch_added) { + // Create new entry without a mapped signal + data::DecodeChannel ch = {id++, true, nullptr, + QString::fromUtf8(pdch->name), QString::fromUtf8(pdch->desc), + SRD_INITIAL_PIN_SAME_AS_SAMPLE0, decoder, pdch}; + channels_.push_back(ch); + } + } + } + + channels_updated(); +} + void DecodeSignal::on_new_annotations() { // Forward the signal to the frontend diff --git a/pv/data/decodesignal.hpp b/pv/data/decodesignal.hpp index 0f3a0330..f9b866e2 100644 --- a/pv/data/decodesignal.hpp +++ b/pv/data/decodesignal.hpp @@ -43,8 +43,20 @@ class Row; class DecoderStack; class Logic; +class SignalBase; class SignalData; +struct DecodeChannel +{ + uint16_t id; // Also tells which bit within a sample represents this channel + const bool is_optional; + const pv::data::SignalBase *assigned_signal; + const QString name, desc; + int initial_pin_state; + const shared_ptr decoder_; + const srd_channel *pdch_; +}; + class DecodeSignal : public SignalBase { Q_OBJECT @@ -63,6 +75,11 @@ public: QString error_message() const; + const list get_channels() const; + void assign_signal(const uint16_t channel_id, const SignalBase *signal); + + void set_initial_pin_state(const uint16_t channel_id, const int init_state); + vector visible_rows() const; /** @@ -73,14 +90,19 @@ public: const decode::Row &row, uint64_t start_sample, uint64_t end_sample) const; +private: + void update_channel_list(); + Q_SIGNALS: void new_annotations(); + void channels_updated(); private Q_SLOTS: void on_new_annotations(); private: shared_ptr decoder_stack_; + list channels_; }; } // namespace data diff --git a/pv/views/trace/decodetrace.cpp b/pv/views/trace/decodetrace.cpp index dfc1fe5d..4ea29755 100644 --- a/pv/views/trace/decodetrace.cpp +++ b/pv/views/trace/decodetrace.cpp @@ -71,6 +71,8 @@ using std::vector; using pv::data::decode::Annotation; using pv::data::decode::Row; +using pv::data::DecodeChannel; +using pv::data::DecodeSignal; namespace pv { namespace views { @@ -148,6 +150,9 @@ DecodeTrace::DecodeTrace(pv::Session &session, connect(decode_signal_.get(), SIGNAL(new_annotations()), this, SLOT(on_new_annotations())); + connect(decode_signal_.get(), SIGNAL(channels_updated()), + this, SLOT(on_channels_updated())); + connect(&delete_mapper_, SIGNAL(mapped(int)), this, SLOT(on_delete_decoder(int))); connect(&show_hide_mapper_, SIGNAL(mapped(int)), @@ -296,7 +301,8 @@ void DecodeTrace::populate_popup_form(QWidget *parent, QFormLayout *form) // Add the decoder options bindings_.clear(); - channel_selectors_.clear(); + channel_id_map_.clear(); + init_state_map_.clear(); decoder_forms_.clear(); const list< shared_ptr >& stack = @@ -774,7 +780,6 @@ void DecodeTrace::create_decoder_form(int index, shared_ptr &dec, QWidget *parent, QFormLayout *form) { - const GSList *l; GlobalSettings settings; assert(dec); @@ -803,60 +808,35 @@ void DecodeTrace::create_decoder_form(int index, QFormLayout *const decoder_form = new QFormLayout; group->add_layout(decoder_form); - // Add the mandatory channels - for (l = decoder->channels; l; l = l->next) { - const struct srd_channel *const pdch = - (struct srd_channel *)l->data; + const list channels = decode_signal_->get_channels(); - QComboBox *const combo = create_channel_selector(parent, dec, pdch); - QComboBox *const combo_initial_pin = create_channel_selector_initial_pin(parent, dec, pdch); + // Add the channels + for (DecodeChannel ch : channels) { + // Ignore channels not part of the decoder we create the form for + if (ch.decoder_ != dec) + continue; - connect(combo, SIGNAL(currentIndexChanged(int)), - this, SLOT(on_channel_selected(int))); - connect(combo_initial_pin, SIGNAL(currentIndexChanged(int)), - this, SLOT(on_initial_pin_selected(int))); + QComboBox *const combo = create_channel_selector(parent, &ch); + QComboBox *const combo_init_state = create_channel_selector_init_state(parent, &ch); - QHBoxLayout *const hlayout = new QHBoxLayout; - hlayout->addWidget(combo); - hlayout->addWidget(combo_initial_pin); - - if (!settings.value(GlobalSettings::Key_Dec_InitialStateConfigurable).toBool()) - combo_initial_pin->hide(); - - decoder_form->addRow(tr("%1 (%2) *") - .arg(QString::fromUtf8(pdch->name), - QString::fromUtf8(pdch->desc)), hlayout); - - const ChannelSelector s = {combo, combo_initial_pin, dec, pdch}; - channel_selectors_.push_back(s); - } - - // Add the optional channels - for (l = decoder->opt_channels; l; l = l->next) { - const struct srd_channel *const pdch = - (struct srd_channel *)l->data; - - QComboBox *const combo = create_channel_selector(parent, dec, pdch); - QComboBox *const combo_initial_pin = create_channel_selector_initial_pin(parent, dec, pdch); + channel_id_map_[combo] = ch.id; + init_state_map_[combo_init_state] = ch.id; connect(combo, SIGNAL(currentIndexChanged(int)), this, SLOT(on_channel_selected(int))); - connect(combo_initial_pin, SIGNAL(currentIndexChanged(int)), - this, SLOT(on_initial_pin_selected(int))); + connect(combo_init_state, SIGNAL(currentIndexChanged(int)), + this, SLOT(on_init_state_changed(int))); QHBoxLayout *const hlayout = new QHBoxLayout; hlayout->addWidget(combo); - hlayout->addWidget(combo_initial_pin); + hlayout->addWidget(combo_init_state); if (!settings.value(GlobalSettings::Key_Dec_InitialStateConfigurable).toBool()) - combo_initial_pin->hide(); - - decoder_form->addRow(tr("%1 (%2)") - .arg(QString::fromUtf8(pdch->name), - QString::fromUtf8(pdch->desc)), hlayout); + combo_init_state->hide(); - const ChannelSelector s = {combo, combo_initial_pin, dec, pdch}; - channel_selectors_.push_back(s); + const QString required_flag = ch.is_optional ? QString() : QString("*"); + decoder_form->addRow(tr("%1 (%2) %3") + .arg(ch.name, ch.desc, required_flag), hlayout); } shared_ptr decoder_stack = base_->decoder_stack(); @@ -872,14 +852,11 @@ void DecodeTrace::create_decoder_form(int index, decoder_forms_.push_back(group); } -QComboBox* DecodeTrace::create_channel_selector( - QWidget *parent, const shared_ptr &dec, - const srd_channel *const pdch) +QComboBox* DecodeTrace::create_channel_selector(QWidget *parent, const DecodeChannel *ch) { - assert(dec); - const auto sigs(session_.signalbases()); + // Sort signals in natural order vector< shared_ptr > sig_list(sigs.begin(), sigs.end()); sort(sig_list.begin(), sig_list.end(), [](const shared_ptr &a, @@ -887,13 +864,11 @@ QComboBox* DecodeTrace::create_channel_selector( return strnatcasecmp(a->name().toStdString(), b->name().toStdString()) < 0; }); - const auto channel_iter = dec->channels().find(pdch); - QComboBox *selector = new QComboBox(parent); selector->addItem("-", qVariantFromValue((void*)nullptr)); - if (channel_iter == dec->channels().end()) + if (!ch->assigned_signal) selector->setCurrentIndex(0); for (const shared_ptr &b : sig_list) { @@ -902,18 +877,16 @@ QComboBox* DecodeTrace::create_channel_selector( selector->addItem(b->name(), qVariantFromValue((void*)b.get())); - if (channel_iter != dec->channels().end() && - (*channel_iter).second == b) - selector->setCurrentIndex( - selector->count() - 1); + if (ch->assigned_signal == b.get()) + selector->setCurrentIndex(selector->count() - 1); } } return selector; } -QComboBox* DecodeTrace::create_channel_selector_initial_pin(QWidget *parent, - const shared_ptr &dec, const srd_channel *const pdch) +QComboBox* DecodeTrace::create_channel_selector_init_state(QWidget *parent, + const DecodeChannel *ch) { QComboBox *selector = new QComboBox(parent); @@ -921,63 +894,13 @@ QComboBox* DecodeTrace::create_channel_selector_initial_pin(QWidget *parent, selector->addItem("1", qVariantFromValue((int)SRD_INITIAL_PIN_HIGH)); selector->addItem("X", qVariantFromValue((int)SRD_INITIAL_PIN_SAME_AS_SAMPLE0)); - // Default to index 2 (SRD_INITIAL_PIN_SAME_AS_SAMPLE0). - const int idx = (!dec->initial_pins()) ? 2 : dec->initial_pins()->data[pdch->order]; - selector->setCurrentIndex(idx); + selector->setCurrentIndex(ch->initial_pin_state); selector->setToolTip("Initial (assumed) pin value before the first sample"); return selector; } -void DecodeTrace::commit_decoder_channels(shared_ptr &dec) -{ - assert(dec); - - map > channel_map; - - const unordered_set< shared_ptr > - sigs(session_.signalbases()); - - GArray *const initial_pins = g_array_sized_new(FALSE, TRUE, - sizeof(uint8_t), channel_selectors_.size()); - g_array_set_size(initial_pins, channel_selectors_.size()); - - for (const ChannelSelector &s : channel_selectors_) { - if (s.decoder_ != dec) - break; - - const data::SignalBase *const selection = - (data::SignalBase*)s.combo_->itemData( - s.combo_->currentIndex()).value(); - - for (shared_ptr sig : sigs) - if (sig.get() == selection) { - channel_map[s.pdch_] = sig; - break; - } - - int selection_initial_pin = s.combo_initial_pin_->itemData( - s.combo_initial_pin_->currentIndex()).value(); - - initial_pins->data[s.pdch_->order] = selection_initial_pin; - } - - dec->set_channels(channel_map); - dec->set_initial_pins(initial_pins); -} - -void DecodeTrace::commit_channels() -{ - shared_ptr decoder_stack = base_->decoder_stack(); - - assert(decoder_stack); - for (shared_ptr dec : decoder_stack->stack()) - commit_decoder_channels(dec); - - decoder_stack->begin_decode(); -} - void DecodeTrace::on_new_annotations() { if (owner_) @@ -996,12 +919,35 @@ void DecodeTrace::on_delete() void DecodeTrace::on_channel_selected(int) { - commit_channels(); + QComboBox *cb = qobject_cast(QObject::sender()); + + // Determine signal that was selected + const data::SignalBase *signal = + (data::SignalBase*)cb->itemData(cb->currentIndex()).value(); + + // Determine decode channel ID this combo box is the channel selector for + const uint16_t id = channel_id_map_.at(cb); + + decode_signal_->assign_signal(id, signal); +} + +void DecodeTrace::on_channels_updated() +{ + if (owner_) + owner_->row_item_appearance_changed(false, true); } -void DecodeTrace::on_initial_pin_selected(int) +void DecodeTrace::on_init_state_changed(int) { - commit_channels(); + QComboBox *cb = qobject_cast(QObject::sender()); + + // Determine inital pin state that was selected + int init_state = cb->itemData(cb->currentIndex()).value(); + + // Determine decode channel ID this combo box is the channel selector for + const uint16_t id = init_state_map_.at(cb); + + decode_signal_->set_initial_pin_state(id, init_state); } void DecodeTrace::on_stack_decoder(srd_decoder *decoder) diff --git a/pv/views/trace/decodetrace.hpp b/pv/views/trace/decodetrace.hpp index e53e2b80..da9f56cc 100644 --- a/pv/views/trace/decodetrace.hpp +++ b/pv/views/trace/decodetrace.hpp @@ -27,6 +27,7 @@ #include #include +#include #include #include @@ -51,6 +52,7 @@ class Session; namespace data { class DecoderStack; class SignalBase; +struct DecodeChannel; class DecodeSignal; namespace decode { @@ -71,15 +73,6 @@ class DecodeTrace : public Trace { Q_OBJECT -private: - struct ChannelSelector - { - const QComboBox *combo_; - const QComboBox *combo_initial_pin_; - const shared_ptr decoder_; - const srd_channel *pdch_; - }; - private: static const QColor DecodeColours[4]; static const QColor ErrorBgColour; @@ -99,8 +92,6 @@ public: bool enabled() const; - const shared_ptr& decoder() const; - shared_ptr base() const; /** @@ -181,16 +172,9 @@ private: QWidget *parent, QFormLayout *form); QComboBox* create_channel_selector(QWidget *parent, - const shared_ptr &dec, - const srd_channel *const pdch); - - QComboBox* create_channel_selector_initial_pin(QWidget *parent, - const shared_ptr &dec, - const srd_channel *const pdch); - - void commit_decoder_channels(shared_ptr &dec); - - void commit_channels(); + const data::DecodeChannel *ch); + QComboBox* create_channel_selector_init_state(QWidget *parent, + const data::DecodeChannel *ch); public: void hover_point_changed(); @@ -202,7 +186,9 @@ private Q_SLOTS: void on_channel_selected(int); - void on_initial_pin_selected(int); + void on_channels_updated(); + + void on_init_state_changed(int); void on_stack_decoder(srd_decoder *decoder); @@ -217,9 +203,10 @@ private: vector visible_rows_; uint64_t decode_start_, decode_end_; + map channel_id_map_; // channel selector -> decode channel ID + map init_state_map_; // init state selector -> decode channel ID list< shared_ptr > bindings_; - list channel_selectors_; vector decoder_forms_; map row_title_widths_;