]> sigrok.org Git - pulseview.git/commitdiff
Re-use DecodeTrace::ChannelSelector as DecodeChannel
authorSoeren Apel <redacted>
Tue, 4 Jul 2017 20:17:22 +0000 (22:17 +0200)
committerSoeren Apel <redacted>
Tue, 4 Jul 2017 21:14:36 +0000 (23:14 +0200)
pv/data/decode/decoder.cpp
pv/data/decode/decoder.hpp
pv/data/decodesignal.cpp
pv/data/decodesignal.hpp
pv/views/trace/decodetrace.cpp
pv/views/trace/decodetrace.hpp

index 841d4fd7b874cdf4ba30227beaf862f361d60627..ffdbeb93bc3835eee32594045af1e79f32260467 100644 (file)
@@ -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<const srd_channel*,
        channels_ = channels;
 }
 
-void Decoder::set_initial_pins(GArray *initial_pins)
-{
-       if (initial_pins_)
-               g_array_free(initial_pins_, TRUE);
-       initial_pins_ = initial_pins;
-}
-
-GArray *Decoder::initial_pins() const
-{
-       return initial_pins_;
-}
-
 const map<string, GVariant*>& 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<data::SignalBase> 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;
 }
index eff2367fb3604cf4c76e7e9ca7c9887cf0e741c4..1b655662bcb707dfe5fd83dbc847164e81bc04a2 100644 (file)
@@ -62,10 +62,6 @@ public:
        void set_channels(map<const srd_channel*,
                shared_ptr<data::SignalBase> > channels);
 
-       void set_initial_pins(GArray *initial_pins);
-
-       GArray *initial_pins() const;
-
        const map<string, GVariant*>& options() const;
 
        void set_option(const char *id, GVariant *value);
@@ -82,7 +78,6 @@ private:
        bool shown_;
 
        map<const srd_channel*, shared_ptr<pv::data::SignalBase> > channels_;
-       GArray *initial_pins_;
        map<string, GVariant*> options_;
 };
 
index 253e3a987c6dbeb59e1f6344deff7d76c5aa4692..6bc691abb5d49a29185a6b404c80bb88f22a548f 100644 (file)
@@ -42,6 +42,8 @@ DecodeSignal::DecodeSignal(shared_ptr<pv::data::DecoderStack> 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<data::decode::Decoder>(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<data::DecodeChannel> 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<Row> 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<data::DecodeChannel> prev_channels = channels_;
+       channels_.clear();
+
+       uint16_t id = 0;
+
+       // Copy existing entries, create new as needed
+       for (shared_ptr<Decoder> 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
index 0f3a0330e3ad9029ad742d796294452d091f91ef..f9b866e27e583ce66b593516e6983e55937477ba 100644 (file)
@@ -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<pv::data::decode::Decoder> decoder_;
+       const srd_channel *pdch_;
+};
+
 class DecodeSignal : public SignalBase
 {
        Q_OBJECT
@@ -63,6 +75,11 @@ public:
 
        QString error_message() const;
 
+       const list<data::DecodeChannel> 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<decode::Row> 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<pv::data::DecoderStack> decoder_stack_;
+       list<data::DecodeChannel> channels_;
 };
 
 } // namespace data
index dfc1fe5d321a93d3430cf62529892ea11c36900e..4ea297555260ddd3a2491d554d176b4440c8e72b 100644 (file)
@@ -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<Decoder> >& stack =
@@ -774,7 +780,6 @@ void DecodeTrace::create_decoder_form(int index,
        shared_ptr<data::decode::Decoder> &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<DecodeChannel> 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("<b>%1</b> (%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("<b>%1</b> (%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("<b>%1</b> (%2) %3")
+                       .arg(ch.name, ch.desc, required_flag), hlayout);
        }
 
        shared_ptr<pv::data::DecoderStack> 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<data::decode::Decoder> &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<data::SignalBase> > sig_list(sigs.begin(), sigs.end());
        sort(sig_list.begin(), sig_list.end(),
                [](const shared_ptr<data::SignalBase> &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<data::SignalBase> &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<data::decode::Decoder> &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<data::decode::Decoder> &dec)
-{
-       assert(dec);
-
-       map<const srd_channel*, shared_ptr<data::SignalBase> > channel_map;
-
-       const unordered_set< shared_ptr<data::SignalBase> >
-               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<void*>();
-
-               for (shared_ptr<data::SignalBase> 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<int>();
-
-               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<pv::data::DecoderStack> decoder_stack = base_->decoder_stack();
-
-       assert(decoder_stack);
-       for (shared_ptr<data::decode::Decoder> 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<QComboBox*>(QObject::sender());
+
+       // Determine signal that was selected
+       const data::SignalBase *signal =
+               (data::SignalBase*)cb->itemData(cb->currentIndex()).value<void*>();
+
+       // 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<QComboBox*>(QObject::sender());
+
+       // Determine inital pin state that was selected
+       int init_state = cb->itemData(cb->currentIndex()).value<int>();
+
+       // 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)
index e53e2b802b7585e0b31360c169dd34f2b9b21302..da9f56ccb76d5546e0fc4baccc6413c729b56ab1 100644 (file)
@@ -27,6 +27,7 @@
 #include <memory>
 #include <vector>
 
+#include <QComboBox>
 #include <QSignalMapper>
 
 #include <pv/binding/decoder.hpp>
@@ -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<pv::data::decode::Decoder> 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<pv::data::DecoderStack>& decoder() const;
-
        shared_ptr<data::SignalBase> base() const;
 
        /**
@@ -181,16 +172,9 @@ private:
                QWidget *parent, QFormLayout *form);
 
        QComboBox* create_channel_selector(QWidget *parent,
-               const shared_ptr<pv::data::decode::Decoder> &dec,
-               const srd_channel *const pdch);
-
-       QComboBox* create_channel_selector_initial_pin(QWidget *parent,
-               const shared_ptr<pv::data::decode::Decoder> &dec,
-               const srd_channel *const pdch);
-
-       void commit_decoder_channels(shared_ptr<data::decode::Decoder> &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<data::decode::Row> visible_rows_;
        uint64_t decode_start_, decode_end_;
 
+       map<QComboBox*, uint16_t> channel_id_map_;  // channel selector -> decode channel ID
+       map<QComboBox*, uint16_t> init_state_map_;  // init state selector -> decode channel ID
        list< shared_ptr<pv::binding::Decoder> > bindings_;
 
-       list<ChannelSelector> channel_selectors_;
        vector<pv::widgets::DecoderGroupBox*> decoder_forms_;
 
        map<data::decode::Row, int> row_title_widths_;