Implemented decoder stacking
authorJoel Holdsworth <joel@airwebreathe.org.uk>
Tue, 29 Oct 2013 18:12:55 +0000 (18:12 +0000)
committerJoel Holdsworth <joel@airwebreathe.org.uk>
Sat, 30 Nov 2013 18:12:58 +0000 (18:12 +0000)
CMakeLists.txt
pv/data/decode/decoder.cpp [new file with mode: 0644]
pv/data/decode/decoder.h [new file with mode: 0644]
pv/data/decoderstack.cpp
pv/data/decoderstack.h
pv/prop/binding/decoderoptions.cpp
pv/prop/binding/decoderoptions.h
pv/sigsession.cpp
pv/view/decodetrace.cpp
pv/view/decodetrace.h
test/CMakeLists.txt

index 0f7502a4e744c11c0390fb589e7b1178a787ddc5..f2159f5ec6049288b3b693c4c532236a1f7d8a64 100644 (file)
@@ -112,6 +112,7 @@ set(pulseview_SOURCES
        pv/data/logicsnapshot.cpp
        pv/data/signaldata.cpp
        pv/data/snapshot.cpp
+       pv/data/decode/decoder.cpp
        pv/dialogs/about.cpp
        pv/dialogs/connect.cpp
        pv/popups/deviceoptions.cpp
diff --git a/pv/data/decode/decoder.cpp b/pv/data/decode/decoder.cpp
new file mode 100644 (file)
index 0000000..77f91cc
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+ * This file is part of the PulseView project.
+ *
+ * Copyright (C) 2013 Joel Holdsworth <joel@airwebreathe.org.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include <libsigrokdecode/libsigrokdecode.h>
+
+#include "decoder.h"
+
+#include <pv/view/logicsignal.h>
+
+using namespace boost;
+using namespace std;
+
+namespace pv {
+namespace data {
+namespace decode {
+
+Decoder::Decoder(const srd_decoder *const dec) :
+       _decoder(dec),
+       _options(g_hash_table_new_full(g_str_hash,
+               g_str_equal, g_free, (GDestroyNotify)g_variant_unref))
+{
+}
+
+Decoder::~Decoder()
+{
+       g_hash_table_destroy(_options);
+}
+
+const srd_decoder* Decoder::decoder() const
+{
+       return _decoder;
+}
+
+const map<const srd_probe*, shared_ptr<view::LogicSignal> >&
+Decoder::probes() const
+{
+       return _probes;
+}
+
+void Decoder::set_probes(std::map<const srd_probe*,
+       boost::shared_ptr<view::LogicSignal> > probes)
+{
+       _probes = probes;
+}
+
+const GHashTable* Decoder::options() const
+{
+       return _options;
+}
+
+void Decoder::set_option(const char *id, GVariant *value)
+{
+       g_variant_ref(value);
+       g_hash_table_replace(_options, (void*)g_strdup(id), value);
+}
+
+srd_decoder_inst* Decoder::create_decoder_inst(
+       srd_session *const session) const
+{
+       // Create the decoder instance
+       srd_decoder_inst *const decoder_inst = srd_inst_new(
+               session, _decoder->id, _options);
+       if(!decoder_inst)
+               return NULL;
+
+       // Setup the probes
+       GHashTable *const probes = g_hash_table_new_full(g_str_hash,
+               g_str_equal, g_free, (GDestroyNotify)g_variant_unref);
+
+       for(map<const srd_probe*, shared_ptr<view::LogicSignal> >::
+               const_iterator i = _probes.begin();
+               i != _probes.end(); i++)
+       {
+               shared_ptr<view::LogicSignal> signal((*i).second);
+               GVariant *const gvar = g_variant_new_int32(
+                       signal->probe()->index);
+               g_variant_ref_sink(gvar);
+               g_hash_table_insert(probes, (*i).first->id, gvar);
+       }
+
+       srd_inst_probe_set_all(decoder_inst, probes);
+
+       return decoder_inst;
+}
+
+} // decode
+} // data
+} // pv
diff --git a/pv/data/decode/decoder.h b/pv/data/decode/decoder.h
new file mode 100644 (file)
index 0000000..e9c5726
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * This file is part of the PulseView project.
+ *
+ * Copyright (C) 2013 Joel Holdsworth <joel@airwebreathe.org.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#ifndef PULSEVIEW_PV_DATA_DECODE_DECODER_H
+#define PULSEVIEW_PV_DATA_DECODE_DECODER_H
+
+#include <map>
+
+#include <boost/shared_ptr.hpp>
+
+#include <glib.h>
+
+struct srd_decoder;
+struct srd_decoder_inst;
+struct srd_probe;
+struct srd_session;
+
+namespace pv {
+
+namespace view {
+class LogicSignal;
+}
+
+namespace data {
+namespace decode {
+
+class Decoder
+{
+public:
+       Decoder(const srd_decoder *const decoder);
+
+       virtual ~Decoder();
+
+       const srd_decoder* decoder() const;
+
+       const std::map<const srd_probe*,
+               boost::shared_ptr<view::LogicSignal> >& probes() const;
+       void set_probes(std::map<const srd_probe*,
+               boost::shared_ptr<view::LogicSignal> > probes);
+
+       const GHashTable* options() const;
+
+       void set_option(const char *id, GVariant *value);
+
+       srd_decoder_inst* create_decoder_inst(
+               srd_session *const session) const;
+
+private:
+       const srd_decoder *const _decoder;
+       std::map<const srd_probe*, boost::shared_ptr<pv::view::LogicSignal> >
+               _probes;
+       GHashTable *_options;
+};
+
+} // namespace decode
+} // namespace data
+} // namespace pv
+
+#endif // PULSEVIEW_PV_DATA_DECODE_DECODER_H
index d56422a9a4f38090069c469d2e2006b13bf29643..2817d29205cc8ee825c72ff049e5775ab6b638cb 100644 (file)
@@ -20,6 +20,7 @@
 
 #include <libsigrokdecode/libsigrokdecode.h>
 
+#include <boost/foreach.hpp>
 #include <boost/thread/thread.hpp>
 
 #include <stdexcept>
@@ -30,6 +31,7 @@
 
 #include <pv/data/logic.h>
 #include <pv/data/logicsnapshot.h>
+#include <pv/data/decode/decoder.h>
 #include <pv/view/logicsignal.h>
 #include <pv/view/decode/annotation.h>
 
@@ -45,49 +47,28 @@ const int64_t DecoderStack::DecodeChunkLength = 4096;
 
 mutex DecoderStack::_global_decode_mutex;
 
-DecoderStack::DecoderStack(const srd_decoder *const dec) :
-       _decoder(dec),
-       _options(g_hash_table_new_full(g_str_hash,
-               g_str_equal, g_free, (GDestroyNotify)g_variant_unref))
+DecoderStack::DecoderStack(const srd_decoder *const dec)
 {
+       _stack.push_back(shared_ptr<decode::Decoder>(
+               new decode::Decoder(dec)));
 }
 
 DecoderStack::~DecoderStack()
 {
        _decode_thread.interrupt();
        _decode_thread.join();
-
-       g_hash_table_destroy(_options);
-}
-
-const srd_decoder* DecoderStack::decoder() const
-{
-       return _decoder;
-}
-
-const map<const srd_probe*, shared_ptr<view::LogicSignal> >&
-DecoderStack::probes() const
-{
-       return _probes;
-}
-
-void DecoderStack::set_probes(std::map<const srd_probe*,
-       boost::shared_ptr<view::LogicSignal> > probes)
-{
-       _probes = probes;
-       begin_decode();
 }
 
-const GHashTable* DecoderStack::options() const
+const std::list< boost::shared_ptr<decode::Decoder> >&
+DecoderStack::stack() const
 {
-       return _options;
+       return _stack;
 }
 
-void DecoderStack::set_option(const char *id, GVariant *value)
+void DecoderStack::push(boost::shared_ptr<decode::Decoder> decoder)
 {
-       g_variant_ref(value);
-       g_hash_table_replace(_options, (void*)g_strdup(id), value);
-       begin_decode();
+       assert(decoder);
+       _stack.push_back(decoder);
 }
 
 const vector< shared_ptr<view::decode::Annotation> >
@@ -105,35 +86,31 @@ QString DecoderStack::error_message()
 
 void DecoderStack::begin_decode()
 {
+       shared_ptr<pv::view::LogicSignal> logic_signal;
+       shared_ptr<pv::data::Logic> data;
+
        _decode_thread.interrupt();
        _decode_thread.join();
 
        _annotations.clear();
 
-       if (_probes.empty())
-               return;
-
-       // Get the samplerate and start time
-       shared_ptr<pv::view::LogicSignal> logic_signal =
-               dynamic_pointer_cast<pv::view::LogicSignal>(
-                       (*_probes.begin()).second);
-       if (logic_signal) {
-               shared_ptr<pv::data::Logic> data(
-                       logic_signal->data());
-               if (data) {
-                       _start_time = data->get_start_time();
-                       _samplerate = data->get_samplerate();
-                       if (_samplerate == 0.0)
-                               _samplerate = 1.0;
-               }
-       }
-
        // We get the logic data of the first probe in the list.
        // This works because we are currently assuming all
        // LogicSignals have the same data/snapshot
-       shared_ptr<pv::view::LogicSignal> sig = (*_probes.begin()).second;
-       assert(sig);
-       shared_ptr<data::Logic> data = sig->data();
+       BOOST_FOREACH (const shared_ptr<decode::Decoder> &dec, _stack)
+               if (dec && !dec->probes().empty() &&
+                       ((logic_signal = (*dec->probes().begin()).second)) &&
+                       ((data = logic_signal->data())))
+                       break;
+
+       if (!data)
+               return;
+
+       // Get the samplerate and start time
+       _start_time = data->get_start_time();
+       _samplerate = data->get_samplerate();
+       if (_samplerate == 0.0)
+               _samplerate = 1.0;
 
        _decode_thread = boost::thread(&DecoderStack::decode_proc, this,
                data);
@@ -147,6 +124,7 @@ void DecoderStack::decode_proc(shared_ptr<data::Logic> data)
 {
        srd_session *session;
        uint8_t chunk[DecodeChunkLength];
+       srd_decoder_inst *prev_di = NULL;
 
        assert(data);
 
@@ -163,38 +141,32 @@ void DecoderStack::decode_proc(shared_ptr<data::Logic> data)
        srd_session_new(&session);
        assert(session);
 
-       srd_session_metadata_set(session, SRD_CONF_SAMPLERATE,
-               g_variant_new_uint64((uint64_t)_samplerate));
 
-       srd_pd_output_callback_add(session, SRD_OUTPUT_ANN,
-               DecoderStack::annotation_callback, this);
+       // Create the decoders
+       BOOST_FOREACH(const shared_ptr<decode::Decoder> &dec, _stack)
+       {
+               srd_decoder_inst *const di = dec->create_decoder_inst(session);
 
-       // Create the decoder instance
-       srd_decoder_inst *const decoder_inst = srd_inst_new(
-               session, _decoder->id, _options);
-       if(!decoder_inst) {
-               _error_message = tr("Failed to initialise decoder");
-               return;
-       }
+               if (!di)
+               {
+                       _error_message = tr("Failed to initialise decoder");
+                       srd_session_destroy(session);
+                       return;
+               }
 
-       // Setup the probes
-       GHashTable *const probes = g_hash_table_new_full(g_str_hash,
-               g_str_equal, g_free, (GDestroyNotify)g_variant_unref);
+               if (prev_di)
+                       srd_inst_stack (session, prev_di, di);
 
-       for(map<const srd_probe*, shared_ptr<view::LogicSignal> >::
-               const_iterator i = _probes.begin();
-               i != _probes.end(); i++)
-       {
-               shared_ptr<view::Signal> signal((*i).second);
-               GVariant *const gvar = g_variant_new_int32(
-                       signal->probe()->index);
-               g_variant_ref_sink(gvar);
-               g_hash_table_insert(probes, (*i).first->id, gvar);
+               prev_di = di;
        }
 
-       srd_inst_probe_set_all(decoder_inst, probes);
-
        // Start the session
+       srd_session_metadata_set(session, SRD_CONF_SAMPLERATE,
+               g_variant_new_uint64((uint64_t)_samplerate));
+
+       srd_pd_output_callback_add(session, SRD_OUTPUT_ANN,
+               DecoderStack::annotation_callback, this);
+
        srd_session_start(session);
 
        for (int64_t i = 0;
index 844a2b547cef8f353007e09029b855024c2a4f44..8b9d29b2bf89e487c31bf12e030b98678d618e2c 100644 (file)
@@ -23,7 +23,7 @@
 
 #include "signaldata.h"
 
-#include <map>
+#include <list>
 
 #include <boost/shared_ptr.hpp>
 #include <boost/thread.hpp>
@@ -31,8 +31,6 @@
 #include <QObject>
 #include <QString>
 
-#include <glib.h>
-
 struct srd_decoder;
 struct srd_probe;
 struct srd_proto_data;
@@ -54,6 +52,10 @@ class Annotation;
 
 namespace data {
 
+namespace decode {
+class Decoder;
+}
+
 class Logic;
 
 class DecoderStack : public QObject, public SignalData
@@ -70,16 +72,8 @@ public:
 
        virtual ~DecoderStack();
 
-       const srd_decoder* decoder() const;
-
-       const std::map<const srd_probe*, boost::shared_ptr<view::LogicSignal> >&
-               probes() const;
-       void set_probes(std::map<const srd_probe*,
-               boost::shared_ptr<view::LogicSignal> > probes);
-
-       const GHashTable* options() const;
-
-       void set_option(const char *id, GVariant *value);
+       const std::list< boost::shared_ptr<decode::Decoder> >& stack() const;
+       void push(boost::shared_ptr<decode::Decoder> decoder);
 
        const std::vector< boost::shared_ptr<pv::view::decode::Annotation> >
                annotations() const;
@@ -88,9 +82,9 @@ public:
 
        void clear_snapshots();
 
-private:
        void begin_decode();
 
+private:
        void decode_proc(boost::shared_ptr<data::Logic> data);
 
        static void annotation_callback(srd_proto_data *pdata,
@@ -109,10 +103,7 @@ private:
         */
        static boost::mutex _global_decode_mutex;
 
-       const srd_decoder *const _decoder;
-       std::map<const srd_probe*, boost::shared_ptr<view::LogicSignal> >
-               _probes;
-       GHashTable *_options;
+       std::list< boost::shared_ptr<decode::Decoder> > _stack;
 
        mutable boost::mutex _mutex;
        std::vector< boost::shared_ptr<pv::view::decode::Annotation> >
index 0a6cd15c998604bdfad8ba9913c1fa640c6793b7..34f1b813a6478012ceec15eaa7f6d704784ab525 100644 (file)
 
 #include "decoderoptions.h"
 
+#include <boost/bind.hpp>
 #include <boost/foreach.hpp>
 #include <boost/none_t.hpp>
 
 #include <pv/data/decoderstack.h>
+#include <pv/data/decode/decoder.h>
 #include <pv/prop/int.h>
 #include <pv/prop/string.h>
 
@@ -36,7 +38,10 @@ namespace pv {
 namespace prop {
 namespace binding {
 
-DecoderOptions::DecoderOptions(shared_ptr<pv::data::DecoderStack> decoder) :
+DecoderOptions::DecoderOptions(
+       shared_ptr<pv::data::DecoderStack> decoder_stack,
+       shared_ptr<data::decode::Decoder> decoder) :
+       _decoder_stack(decoder_stack),
        _decoder(decoder)
 {
        assert(_decoder);
@@ -105,6 +110,9 @@ void DecoderOptions::setter(const char *id, GVariant *value)
 {
        assert(_decoder);
        _decoder->set_option(id, value);
+
+       assert(_decoder_stack);
+       _decoder_stack->begin_decode();
 }
 
 } // binding
index e507e87c3accebafe17d356eace0a52dadc6defe..62f4fe184cb766e51b7affdfeab35ede0ad851fa 100644 (file)
@@ -29,6 +29,9 @@ namespace pv {
 
 namespace data {
 class DecoderStack;
+namespace decode {
+class Decoder;
+}
 }
 
 namespace prop {
@@ -37,7 +40,8 @@ namespace binding {
 class DecoderOptions : public Binding
 {
 public:
-       DecoderOptions(boost::shared_ptr<pv::data::DecoderStack> decoder);
+       DecoderOptions(boost::shared_ptr<pv::data::DecoderStack> decoder_stack,
+               boost::shared_ptr<pv::data::decode::Decoder> decoder);
 
 private:
        GVariant* getter(const char *id);
@@ -45,7 +49,8 @@ private:
        void setter(const char *id, GVariant *value);
 
 private:
-       boost::shared_ptr<pv::data::DecoderStack> _decoder;
+       boost::shared_ptr<pv::data::DecoderStack> _decoder_stack;
+       boost::shared_ptr<pv::data::decode::Decoder> _decoder;
 };
 
 } // binding
index a6a2875e62657ca7dacc458808f854fc6dfbe88c..8936574a4e238c3f9b3fa65afce4a92985bdee8c 100644 (file)
@@ -29,6 +29,7 @@
 #include "data/decoderstack.h"
 #include "data/logic.h"
 #include "data/logicsnapshot.h"
+#include "data/decode/decoder.h"
 
 #include "view/analogsignal.h"
 #include "view/decodetrace.h"
@@ -202,13 +203,15 @@ boost::shared_ptr<data::Logic> SigSession::get_data()
 bool SigSession::add_decoder(srd_decoder *const dec)
 {
        map<const srd_probe*, shared_ptr<view::LogicSignal> > probes;
+       shared_ptr<data::DecoderStack> decoder_stack;
 
        try
        {
                lock_guard<mutex> lock(_signals_mutex);
 
                // Create the decoder
-               shared_ptr<data::DecoderStack> decoder(new data::DecoderStack(dec));
+               decoder_stack = shared_ptr<data::DecoderStack>(
+                       new data::DecoderStack(dec));
 
                // Auto select the initial probes
                for(const GSList *i = dec->probes; i; i = i->next)
@@ -224,11 +227,14 @@ bool SigSession::add_decoder(srd_decoder *const dec)
                        }
                }
 
-               decoder->set_probes(probes);
+               assert(decoder_stack);
+               assert(!decoder_stack->stack().empty());
+               assert(decoder_stack->stack().front());
+               decoder_stack->stack().front()->set_probes(probes);
 
                // Create the decode signal
                shared_ptr<view::DecodeTrace> d(
-                       new view::DecodeTrace(*this, decoder,
+                       new view::DecodeTrace(*this, decoder_stack,
                                _decode_traces.size()));
                _decode_traces.push_back(d);
        }
@@ -239,6 +245,9 @@ bool SigSession::add_decoder(srd_decoder *const dec)
 
        signals_changed();
 
+       // Do an initial decode
+       decoder_stack->begin_decode();
+
        return true;
 }
 
index 51b17e5e14269d236acdde3dba578d39b36c47f5..7e2051a4022202ff77ea496e5259c147f07475e9 100644 (file)
@@ -37,6 +37,7 @@ extern "C" {
 
 #include <pv/sigsession.h>
 #include <pv/data/decoderstack.h>
+#include <pv/data/decode/decoder.h>
 #include <pv/view/logicsignal.h>
 #include <pv/view/view.h>
 #include <pv/view/decode/annotation.h>
@@ -59,9 +60,8 @@ const QColor DecodeTrace::ErrorBgColour = QColor(0xEF, 0x29, 0x29);
 
 DecodeTrace::DecodeTrace(pv::SigSession &session,
        boost::shared_ptr<pv::data::DecoderStack> decoder_stack, int index) :
-       Trace(session, QString(decoder_stack->decoder()->name)),
-       _decoder_stack(decoder_stack),
-       _binding(decoder_stack)
+       Trace(session, QString(decoder_stack->stack().front()->decoder()->name)),
+       _decoder_stack(decoder_stack)
 {
        assert(_decoder_stack);
 
@@ -130,63 +130,32 @@ void DecodeTrace::paint_mid(QPainter &p, int left, int right)
 
 void DecodeTrace::populate_popup_form(QWidget *parent, QFormLayout *form)
 {
-       const GSList *probe;
-
        assert(form);
        assert(parent);
        assert(_decoder_stack);
 
-       const srd_decoder *const decoder = _decoder_stack->decoder();
-
-       assert(decoder);
-
+       // Add the standard options
        Trace::populate_popup_form(parent, form);
 
-       form->addRow(new QLabel(tr("<h3>Probes</h3>"), parent));
-
-       _probe_selector_map.clear();
-
-       // Add the mandatory probes
-       for(probe = decoder->probes; probe; probe = probe->next) {
-               const struct srd_probe *const p =
-                       (struct srd_probe *)probe->data;
-               QComboBox *const combo = create_probe_selector(parent, p);
-               connect(combo, SIGNAL(currentIndexChanged(int)),
-                       this, SLOT(on_probe_selected(int)));
-               form->addRow(tr("<b>%1</b> (%2) *")
-                       .arg(p->name).arg(p->desc), combo);
-
-               _probe_selector_map[p] = combo;
-       }
-
-       // Add the optional probes
-       for(probe = decoder->opt_probes; probe; probe = probe->next) {
-               const struct srd_probe *const p =
-                       (struct srd_probe *)probe->data;
-               QComboBox *const combo = create_probe_selector(parent, p);
-               connect(combo, SIGNAL(currentIndexChanged(int)),
-                       this, SLOT(on_probe_selected(int)));
-               form->addRow(tr("<b>%1</b> (%2)")
-                       .arg(p->name).arg(p->desc), combo);
+       // Add the decoder options
+       _bindings.clear();
+       _probe_selectors.clear();
 
-               _probe_selector_map[p] = combo;
-       }
+       BOOST_FOREACH(shared_ptr<data::decode::Decoder> dec,
+               _decoder_stack->stack())
+               create_decoder_form(dec, parent, form);
 
        form->addRow(new QLabel(
                tr("<i>* Required Probes</i>"), parent));
 
-       // Add the options
-       if (!_binding.properties().empty()) {
-               form->addRow(new QLabel(tr("<h3>Options</h3>"),
-                       parent));
-               _binding.add_properties_to_form(form, true);
-       }
-
        // Add stacking button
-       QPushButton *const stack_button =
-               new QPushButton(tr("Stack DecoderStack"), parent);
        pv::widgets::DecoderMenu *const decoder_menu =
                new pv::widgets::DecoderMenu(parent);
+       connect(decoder_menu, SIGNAL(decoder_selected(srd_decoder*)),
+               this, SLOT(on_stack_decoder(srd_decoder*)));
+
+       QPushButton *const stack_button =
+               new QPushButton(tr("Stack Decoder"), parent);
        stack_button->setMenu(decoder_menu);
 
        QHBoxLayout *stack_button_box = new QHBoxLayout;
@@ -229,21 +198,71 @@ void DecodeTrace::draw_error(QPainter &p, const QString &message,
        p.drawText(text_rect, message);
 }
 
+void DecodeTrace::create_decoder_form(shared_ptr<data::decode::Decoder> &dec,
+       QWidget *parent, QFormLayout *form)
+{
+       const GSList *probe;
+
+       assert(dec);
+       const srd_decoder *const decoder = dec->decoder();
+       assert(decoder);
+
+       form->addRow(new QLabel(tr("<h3>%1</h3>").arg(decoder->name), parent));
+
+       // Add the mandatory probes
+       for(probe = decoder->probes; probe; probe = probe->next) {
+               const struct srd_probe *const p =
+                       (struct srd_probe *)probe->data;
+               QComboBox *const combo = create_probe_selector(parent, dec, p);
+               connect(combo, SIGNAL(currentIndexChanged(int)),
+                       this, SLOT(on_probe_selected(int)));
+               form->addRow(tr("<b>%1</b> (%2) *")
+                       .arg(p->name).arg(p->desc), combo);
+
+               const ProbeSelector s = {combo, dec, p};
+               _probe_selectors.push_back(s);
+       }
+
+       // Add the optional probes
+       for(probe = decoder->opt_probes; probe; probe = probe->next) {
+               const struct srd_probe *const p =
+                       (struct srd_probe *)probe->data;
+               QComboBox *const combo = create_probe_selector(parent, dec, p);
+               connect(combo, SIGNAL(currentIndexChanged(int)),
+                       this, SLOT(on_probe_selected(int)));
+               form->addRow(tr("<b>%1</b> (%2)")
+                       .arg(p->name).arg(p->desc), combo);
+
+               const ProbeSelector s = {combo, dec, p};
+               _probe_selectors.push_back(s);
+       }
+
+       // Add the options
+       shared_ptr<prop::binding::DecoderOptions> binding(
+               new prop::binding::DecoderOptions(_decoder_stack, dec));
+       binding->add_properties_to_form(form, true);
+
+       _bindings.push_back(binding);
+}
+
 QComboBox* DecodeTrace::create_probe_selector(
-       QWidget *parent, const srd_probe *const probe)
+       QWidget *parent, const shared_ptr<data::decode::Decoder> &dec,
+       const srd_probe *const probe)
 {
+       assert(dec);
+
        const vector< shared_ptr<Signal> > sigs = _session.get_signals();
 
        assert(_decoder_stack);
        const map<const srd_probe*,
                shared_ptr<LogicSignal> >::const_iterator probe_iter =
-               _decoder_stack->probes().find(probe);
+               dec->probes().find(probe);
 
        QComboBox *selector = new QComboBox(parent);
 
        selector->addItem("-", qVariantFromValue((void*)NULL));
 
-       if (probe_iter == _decoder_stack->probes().end())
+       if (probe_iter == dec->probes().end())
                selector->setCurrentIndex(0);
 
        for(size_t i = 0; i < sigs.size(); i++) {
@@ -262,31 +281,41 @@ QComboBox* DecodeTrace::create_probe_selector(
        return selector;
 }
 
-void DecodeTrace::commit_probes()
+void DecodeTrace::commit_decoder_probes(shared_ptr<data::decode::Decoder> &dec)
 {
-       assert(_decoder_stack);
+       assert(dec);
 
        map<const srd_probe*, shared_ptr<LogicSignal> > probe_map;
        const vector< shared_ptr<Signal> > sigs = _session.get_signals();
 
-       for(map<const srd_probe*, QComboBox*>::const_iterator i =
-               _probe_selector_map.begin();
-               i != _probe_selector_map.end(); i++)
+       BOOST_FOREACH(const ProbeSelector &s, _probe_selectors)
        {
-               const QComboBox *const combo = (*i).second;
+               if(s._decoder != dec)
+                       break;
+
                const LogicSignal *const selection =
-                       (LogicSignal*)combo->itemData(combo->currentIndex()).
-                       value<void*>();
+                       (LogicSignal*)s._combo->itemData(
+                               s._combo->currentIndex()).value<void*>();
 
-               BOOST_FOREACH(shared_ptr<Signal> s, sigs)
-                       if(s.get() == selection) {
-                               probe_map[(*i).first] =
-                                       dynamic_pointer_cast<LogicSignal>(s);
+               BOOST_FOREACH(shared_ptr<Signal> sig, sigs)
+                       if(sig.get() == selection) {
+                               probe_map[s._probe] =
+                                       dynamic_pointer_cast<LogicSignal>(sig);
                                break;
                        }
        }
 
-       _decoder_stack->set_probes(probe_map);
+       dec->set_probes(probe_map);
+}
+
+void DecodeTrace::commit_probes()
+{
+       assert(_decoder_stack);
+       BOOST_FOREACH(shared_ptr<data::decode::Decoder> dec,
+               _decoder_stack->stack())
+               commit_decoder_probes(dec);
+
+       _decoder_stack->begin_decode();
 }
 
 void DecodeTrace::on_new_decode_data()
@@ -310,5 +339,14 @@ void DecodeTrace::on_probe_selected(int)
        commit_probes();
 }
 
+void DecodeTrace::on_stack_decoder(srd_decoder *decoder)
+{
+       assert(decoder);
+       assert(_decoder_stack);
+       _decoder_stack->push(shared_ptr<data::decode::Decoder>(
+               new data::decode::Decoder(decoder)));
+       _decoder_stack->begin_decode();
+}
+
 } // namespace view
 } // namespace pv
index 229df86d3aaa6756ae20192603ace403ca386b34..c12d5b51314cc5b4c53cb9f05e51bbb28cd198b1 100644 (file)
@@ -23,6 +23,7 @@
 
 #include "trace.h"
 
+#include <list>
 #include <map>
 
 #include <boost/shared_ptr.hpp>
@@ -37,6 +38,10 @@ namespace pv {
 
 namespace data {
 class DecoderStack;
+
+namespace decode {
+class Decoder;
+}
 }
 
 namespace view {
@@ -45,6 +50,14 @@ class DecodeTrace : public Trace
 {
        Q_OBJECT
 
+private:
+       struct ProbeSelector
+       {
+               const QComboBox *_combo;
+               const boost::shared_ptr<pv::data::decode::Decoder> _decoder;
+               const srd_probe *_probe;
+       };
+
 private:
        static const QColor DecodeColours[4];
        static const QColor ErrorBgColour;
@@ -86,8 +99,16 @@ private:
        void draw_error(QPainter &p, const QString &message,
                int left, int right);
 
-       QComboBox* create_probe_selector(
-               QWidget *parent, const srd_probe *const probe);
+       void create_decoder_form(
+               boost::shared_ptr<pv::data::decode::Decoder> &dec,
+               QWidget *parent, QFormLayout *form);
+
+       QComboBox* create_probe_selector(QWidget *parent,
+               const boost::shared_ptr<pv::data::decode::Decoder> &dec,
+               const srd_probe *const probe);
+
+       void commit_decoder_probes(
+               boost::shared_ptr<data::decode::Decoder> &dec);
 
        void commit_probes();
 
@@ -98,14 +119,17 @@ private slots:
 
        void on_probe_selected(int);
 
+       void on_stack_decoder(srd_decoder *decoder);
+
 private:
        boost::shared_ptr<pv::data::DecoderStack> _decoder_stack;
 
        uint64_t _decode_start, _decode_end;
 
-       pv::prop::binding::DecoderOptions _binding;
+       std::list< boost::shared_ptr<pv::prop::binding::DecoderOptions> >
+               _bindings;
 
-       std::map<const srd_probe*, QComboBox*> _probe_selector_map;
+       std::list<ProbeSelector> _probe_selectors;
 };
 
 } // namespace view
index 5cc18c1627de2f737301f5da8002a32fb0e09dc8..18deb63b9201063b4bd8bc7b1a6a83d4ef516886 100644 (file)
@@ -46,6 +46,7 @@ set(pulseview_TEST_SOURCES
        ${PROJECT_SOURCE_DIR}/pv/data/logicsnapshot.cpp
        ${PROJECT_SOURCE_DIR}/pv/data/snapshot.cpp
        ${PROJECT_SOURCE_DIR}/pv/data/signaldata.cpp
+       ${PROJECT_SOURCE_DIR}/pv/data/decode/decoder.cpp
        ${PROJECT_SOURCE_DIR}/pv/prop/int.cpp
        ${PROJECT_SOURCE_DIR}/pv/prop/property.cpp
        ${PROJECT_SOURCE_DIR}/pv/prop/string.cpp