{
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()));
}
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();
}
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();
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
using pv::data::decode::Annotation;
using pv::data::decode::Row;
+using pv::data::DecodeChannel;
+using pv::data::DecodeSignal;
namespace pv {
namespace views {
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)),
// 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 =
shared_ptr<data::decode::Decoder> &dec, QWidget *parent,
QFormLayout *form)
{
- const GSList *l;
GlobalSettings settings;
assert(dec);
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();
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,
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) {
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);
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_)
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)
#include <memory>
#include <vector>
+#include <QComboBox>
#include <QSignalMapper>
#include <pv/binding/decoder.hpp>
namespace data {
class DecoderStack;
class SignalBase;
+struct DecodeChannel;
class DecodeSignal;
namespace decode {
{
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;
bool enabled() const;
- const shared_ptr<pv::data::DecoderStack>& decoder() const;
-
shared_ptr<data::SignalBase> base() const;
/**
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();
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);
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_;