From: Soeren Apel Date: Wed, 11 Dec 2019 21:34:19 +0000 (+0100) Subject: Various PD-related changes X-Git-Url: https://sigrok.org/gitweb/?p=pulseview.git;a=commitdiff_plain;h=e77de61fbc19633c77cc196332ae79c26d9ca35d Various PD-related changes 1) Added decoder stack/remove signals 2) Added binary output class handling and refactored the code accordingly 3) Enabled the decoder output view to handle multiple decoders per signal --- diff --git a/pv/data/decode/decoder.cpp b/pv/data/decode/decoder.cpp index 45a33e4a..8e7ffb50 100644 --- a/pv/data/decode/decoder.cpp +++ b/pv/data/decode/decoder.cpp @@ -41,6 +41,14 @@ Decoder::Decoder(const srd_decoder *const dec) : shown_(true), decoder_inst_(nullptr) { + // Query the decoder outputs + uint8_t i = 0; + for (GSList *l = dec->binary; l; l = l->next) { + char **bin_class = (char**)l->data; + char *name = bin_class[0]; + char *desc = bin_class[1]; + bin_classes_.push_back({i++, name, desc}); + } } Decoder::~Decoder() @@ -54,6 +62,11 @@ const srd_decoder* Decoder::decoder() const return decoder_; } +const char* Decoder::name() const +{ + return decoder_->name; +} + bool Decoder::shown() const { return shown_; @@ -171,6 +184,16 @@ void Decoder::invalidate_decoder_inst() decoder_inst_ = nullptr; } +uint8_t Decoder::get_binary_class_count() const +{ + return bin_classes_.size(); +} + +const DecodeBinaryClassInfo* Decoder::get_binary_class(uint8_t id) const +{ + return &(bin_classes_.at(id)); +} + } // namespace decode } // namespace data } // namespace pv diff --git a/pv/data/decode/decoder.hpp b/pv/data/decode/decoder.hpp index b7ef6080..2a7ef11e 100644 --- a/pv/data/decode/decoder.hpp +++ b/pv/data/decode/decoder.hpp @@ -61,6 +61,13 @@ struct DecodeChannel const srd_channel *pdch_; }; +struct DecodeBinaryClassInfo +{ + uint8_t bin_class_id; + char* name; + char* description; +}; + class Decoder { @@ -71,6 +78,8 @@ public: const srd_decoder* decoder() const; + const char* name() const; + bool shown() const; void show(bool show = true); @@ -88,7 +97,8 @@ public: srd_decoder_inst* create_decoder_inst(srd_session *session); void invalidate_decoder_inst(); - + uint8_t get_binary_class_count() const; + const DecodeBinaryClassInfo* get_binary_class(uint8_t id) const; private: const srd_decoder *const decoder_; @@ -96,6 +106,7 @@ private: bool shown_; vector channels_; + vector bin_classes_; map options_; srd_decoder_inst *decoder_inst_; }; diff --git a/pv/data/decodesignal.cpp b/pv/data/decodesignal.cpp index cb16ecb8..6016ff68 100644 --- a/pv/data/decodesignal.cpp +++ b/pv/data/decodesignal.cpp @@ -98,6 +98,9 @@ void DecodeSignal::stack_decoder(const srd_decoder *decoder) stack_config_changed_ = true; auto_assign_signals(dec); commit_decoder_channels(); + + decoder_stacked((void*)dec.get()); + begin_decode(); } @@ -111,6 +114,8 @@ void DecodeSignal::remove_decoder(int index) for (int i = 0; i < index; i++, iter++) assert(iter != stack_.end()); + decoder_removed(iter->get()); + // Delete the element stack_.erase(iter); @@ -529,58 +534,70 @@ void DecodeSignal::get_annotation_subset( delete all_ann_list; } -uint32_t DecodeSignal::get_binary_data_chunk_count(uint32_t segment_id) const +uint32_t DecodeSignal::get_binary_data_chunk_count(uint32_t segment_id, + const Decoder* dec, uint8_t bin_class_id) const { - uint32_t count = 0; - try { const DecodeSegment *segment = &(segments_.at(segment_id)); - count = segment->binary_data.size(); + + for (const DecodeBinaryClass& bc : segment->binary_classes) + if ((bc.decoder == dec) && (bc.info->bin_class_id == bin_class_id)) + return bc.chunks.size(); } catch (out_of_range&) { // Do nothing } - return count; + return 0; } -void DecodeSignal::get_binary_data_chunk(uint32_t segment_id, uint32_t chunk_id, +void DecodeSignal::get_binary_data_chunk(uint32_t segment_id, + const Decoder* dec, uint8_t bin_class_id, uint32_t chunk_id, const vector **dest, uint64_t *size) { try { const DecodeSegment *segment = &(segments_.at(segment_id)); - if (dest) - *dest = &(segment->binary_data.at(chunk_id).data); - if (size) - *size = segment->binary_data.at(chunk_id).data.size(); + + for (const DecodeBinaryClass& bc : segment->binary_classes) + if ((bc.decoder == dec) && (bc.info->bin_class_id == bin_class_id)) { + if (dest) *dest = &(bc.chunks.at(chunk_id).data); + if (size) *size = bc.chunks.at(chunk_id).data.size(); + return; + } } catch (out_of_range&) { // Do nothing } } void DecodeSignal::get_binary_data_chunks_merged(uint32_t segment_id, - uint64_t start_sample, uint64_t end_sample, vector *dest) const + const Decoder* dec, uint8_t bin_class_id, uint64_t start_sample, + uint64_t end_sample, vector *dest) const { assert(dest != nullptr); try { const DecodeSegment *segment = &(segments_.at(segment_id)); + const DecodeBinaryClass* bin_class = nullptr; + for (const DecodeBinaryClass& bc : segment->binary_classes) + if ((bc.decoder == dec) && (bc.info->bin_class_id == bin_class_id)) + bin_class = &bc; + // Determine overall size before copying to resize dest vector only once uint64_t size = 0; uint64_t matches = 0; - for (const DecodeBinaryData& d : segment->binary_data) - if ((d.sample >= start_sample) && (d.sample < end_sample)) { - size += d.data.size(); + for (const DecodeBinaryDataChunk& chunk : bin_class->chunks) + if ((chunk.sample >= start_sample) && (chunk.sample < end_sample)) { + size += chunk.data.size(); matches++; } dest->resize(size); uint64_t offset = 0; uint64_t matches2 = 0; - for (const DecodeBinaryData& d : segment->binary_data) - if ((d.sample >= start_sample) && (d.sample < end_sample)) { - memcpy(dest->data() + offset, d.data.data(), d.data.size()); - offset += d.data.size(); + for (const DecodeBinaryDataChunk& chunk : bin_class->chunks) + if ((chunk.sample >= start_sample) && (chunk.sample < end_sample)) { + memcpy(dest->data() + offset, chunk.data.data(), chunk.data.size()); + offset += chunk.data.size(); matches2++; // Make sure we don't overwrite memory if the array grew in the meanwhile @@ -1312,6 +1329,15 @@ void DecodeSignal::create_decode_segment() decode::RowData(); } } + + // Prepare our binary output classes + for (const shared_ptr& dec : stack_) { + uint8_t n = dec->get_binary_class_count(); + + for (uint8_t i = 0; i < n; i++) + segments_.back().binary_classes.push_back( + {dec.get(), dec->get_binary_class(i), vector()}); + } } void DecodeSignal::annotation_callback(srd_proto_data *pdata, void *decode_signal) @@ -1371,19 +1397,45 @@ void DecodeSignal::binary_callback(srd_proto_data *pdata, void *decode_signal) if (ds->decode_interrupt_) return; + // Get the decoder and the binary data + assert(pdata->pdo); + assert(pdata->pdo->di); + const srd_decoder *const decc = pdata->pdo->di->decoder; + assert(decc); + const srd_proto_data_binary *const pdb = (const srd_proto_data_binary*)pdata->data; assert(pdb); + // Find the matching DecodeBinaryClass DecodeSegment* segment = &(ds->segments_.at(ds->current_segment_id_)); - segment->binary_data.emplace_back(); - DecodeBinaryData* bin_data = &(segment->binary_data.back()); + DecodeBinaryClass* bin_class = nullptr; + for (DecodeBinaryClass& bc : segment->binary_classes) + if ((bc.decoder->decoder() == decc) && (bc.info->bin_class_id == pdb->bin_class)) + bin_class = &bc; - bin_data->sample = pdata->start_sample; - bin_data->data.resize(pdb->size); - memcpy(bin_data->data.data(), pdb->data, pdb->size); + if (!bin_class) { + qWarning() << "Could not find valid DecodeBinaryClass in segment" << + ds->current_segment_id_ << "for binary class ID" << pdb->bin_class << + ", segment only knows" << segment->binary_classes.size() << "classes"; + return; + } - ds->new_binary_data(ds->current_segment_id_); + // Add the data chunk + bin_class->chunks.emplace_back(); + DecodeBinaryDataChunk* chunk = &(bin_class->chunks.back()); + + chunk->sample = pdata->start_sample; + chunk->data.resize(pdb->size); + memcpy(chunk->data.data(), pdb->data, pdb->size); + + // Note: using pdb->bin_class is only unique for each decoder in the stack, + // so if two stacked decoders both emit binary data with the same bin_class, + // we may be triggering unnecessary updates. Should be ok for now as that + // case isn't possible yet. When it is, we might add the decoder's name + // as an additional parameter to the signal, although string comparisons + // are not really fast. + ds->new_binary_data(ds->current_segment_id_, pdb->bin_class); } void DecodeSignal::on_capture_state_changed(int state) diff --git a/pv/data/decodesignal.hpp b/pv/data/decodesignal.hpp index a01ff3ee..94913b9d 100644 --- a/pv/data/decodesignal.hpp +++ b/pv/data/decodesignal.hpp @@ -60,19 +60,26 @@ class LogicSegment; class SignalBase; class SignalData; -struct DecodeBinaryData +struct DecodeBinaryDataChunk { vector data; uint64_t sample; ///< Number of the sample where this data was provided by the PD }; +struct DecodeBinaryClass +{ + const decode::Decoder* decoder; + const decode::DecodeBinaryClassInfo* info; + vector chunks; +}; + struct DecodeSegment { map annotation_rows; pv::util::Timestamp start_time; double samplerate; int64_t samples_decoded_incl, samples_decoded_excl; - vector binary_data; + vector binary_classes; }; class DecodeSignal : public SignalBase @@ -151,11 +158,14 @@ public: vector &dest, uint32_t segment_id, uint64_t start_sample, uint64_t end_sample) const; - uint32_t get_binary_data_chunk_count(uint32_t segment_id) const; - void get_binary_data_chunk(uint32_t segment_id, uint32_t chunk_id, - const vector **dest, uint64_t *size); - void get_binary_data_chunks_merged(uint32_t segment_id, - uint64_t start_sample, uint64_t end_sample, vector *dest) const; + uint32_t get_binary_data_chunk_count(uint32_t segment_id, + const data::decode::Decoder* dec, uint8_t bin_class_id) const; + void get_binary_data_chunk(uint32_t segment_id, const data::decode::Decoder* dec, + uint8_t bin_class_id, uint32_t chunk_id, const vector **dest, + uint64_t *size); + void get_binary_data_chunks_merged(uint32_t segment_id, const data::decode::Decoder* dec, + uint8_t bin_class_id, uint64_t start_sample, uint64_t end_sample, + vector *dest) const; virtual void save_settings(QSettings &settings) const; @@ -193,8 +203,10 @@ private: static void binary_callback(srd_proto_data *pdata, void *decode_signal); Q_SIGNALS: + void decoder_stacked(void* decoder); ///< decoder is of type decode::Decoder* + void decoder_removed(void* decoder); ///< decoder is of type decode::Decoder* void new_annotations(); // TODO Supply segment for which they belong to - void new_binary_data(unsigned int segment_id); + void new_binary_data(unsigned int segment_id, unsigned int bin_class_id); void decode_reset(); void decode_finished(); void channels_updated(); diff --git a/pv/views/decoder_output/view.cpp b/pv/views/decoder_output/view.cpp index 0eda5659..4480211a 100644 --- a/pv/views/decoder_output/view.cpp +++ b/pv/views/decoder_output/view.cpp @@ -33,12 +33,15 @@ #include "pv/session.hpp" #include "pv/util.hpp" +#include "pv/data/decode/decoder.hpp" using pv::data::DecodeSignal; using pv::data::SignalBase; +using pv::data::decode::Decoder; using pv::util::TimeUnit; using pv::util::Timestamp; +using std::dynamic_pointer_cast; using std::numeric_limits; using std::shared_ptr; @@ -50,8 +53,9 @@ View::View(Session &session, bool is_main_view, QMainWindow *parent) : ViewBase(session, is_main_view, parent), // Note: Place defaults in View::reset_view_state(), not here - signal_selector_(new QComboBox()), + decoder_selector_(new QComboBox()), format_selector_(new QComboBox()), + class_selector_(new QComboBox()), stacked_widget_(new QStackedWidget()), hex_view_(new QHexView()), signal_(nullptr), @@ -67,7 +71,8 @@ View::View(Session &session, bool is_main_view, QMainWindow *parent) : // Populate toolbar toolbar->addWidget(new QLabel(tr("Decoder:"))); - toolbar->addWidget(signal_selector_); + toolbar->addWidget(decoder_selector_); + toolbar->addWidget(class_selector_); toolbar->addSeparator(); toolbar->addWidget(new QLabel(tr("Show data as"))); toolbar->addWidget(format_selector_); @@ -80,8 +85,8 @@ View::View(Session &session, bool is_main_view, QMainWindow *parent) : stacked_widget_->addWidget(hex_view_); stacked_widget_->setCurrentIndex(0); - connect(signal_selector_, SIGNAL(currentIndexChanged(int)), - this, SLOT(on_selected_signal_changed(int))); + connect(decoder_selector_, SIGNAL(currentIndexChanged(int)), + this, SLOT(on_selected_decoder_changed(int))); hex_view_->setData(merged_data_); @@ -110,28 +115,54 @@ void View::clear_signals() void View::clear_decode_signals() { - signal_selector_->clear(); + ViewBase::clear_decode_signals(); + + decoder_selector_->clear(); format_selector_->setCurrentIndex(0); signal_ = nullptr; } void View::add_decode_signal(shared_ptr signal) { + ViewBase::add_decode_signal(signal); + connect(signal.get(), SIGNAL(name_changed(const QString&)), this, SLOT(on_signal_name_changed(const QString&))); - - signal_selector_->addItem(signal->name(), QVariant::fromValue((void*)signal.get())); + connect(signal.get(), SIGNAL(decoder_stacked(void*)), + this, SLOT(on_decoder_stacked(void*))); + connect(signal.get(), SIGNAL(decoder_removed(void*)), + this, SLOT(on_decoder_removed(void*))); + + // Add all decoders provided by this signal + auto stack = signal->decoder_stack(); + if (stack.size() > 1) { + for (const shared_ptr& dec : stack) { + QString title = QString("%1 (%2)").arg(signal->name(), dec->name()); + decoder_selector_->addItem(title, QVariant::fromValue((void*)dec.get())); + } + } else + if (!stack.empty()) { + shared_ptr& dec = stack.at(0); + decoder_selector_->addItem(signal->name(), QVariant::fromValue((void*)dec.get())); + } } void View::remove_decode_signal(shared_ptr signal) { - int index = signal_selector_->findData(QVariant::fromValue((void*)signal.get())); + // Remove all decoders provided by this signal + for (const shared_ptr& dec : signal->decoder_stack()) { + int index = decoder_selector_->findData(QVariant::fromValue((void*)dec.get())); - if (index != -1) - signal_selector_->removeItem(index); + if (index != -1) + decoder_selector_->removeItem(index); + } + + ViewBase::remove_decode_signal(signal); if (signal.get() == signal_) { signal_ = nullptr; + decoder_ = nullptr; + bin_class_id_ = 0; update_data(); } } @@ -155,48 +186,114 @@ void View::update_data() return; } - if (signal_->get_binary_data_chunk_count(current_segment_) == 0) { + if (signal_->get_binary_data_chunk_count(current_segment_, decoder_, bin_class_id_) == 0) { merged_data_->clear(); return; } vector data; - signal_->get_binary_data_chunks_merged(current_segment_, 0, - numeric_limits::max(), &data); + signal_->get_binary_data_chunks_merged(current_segment_, decoder_, bin_class_id_, + 0, numeric_limits::max(), &data); merged_data_->resize(data.size()); memcpy(merged_data_->data(), data.data(), data.size()); } -void View::on_selected_signal_changed(int index) +void View::on_selected_decoder_changed(int index) { if (signal_) - disconnect(signal_, SIGNAL(new_binary_data(unsigned int))); + disconnect(signal_, SIGNAL(new_binary_data(unsigned int, unsigned int))); - signal_ = (DecodeSignal*)signal_selector_->itemData(index).value(); - update_data(); + decoder_ = (Decoder*)decoder_selector_->itemData(index).value(); + + // Find the signal that contains the selected decoder + signal_ = nullptr; + + for (const shared_ptr& sb : signalbases_) { + shared_ptr ds = dynamic_pointer_cast(sb); + + if (ds) + for (const shared_ptr& dec : ds->decoder_stack()) + if (decoder_ == dec.get()) + signal_ = ds.get(); + } if (signal_) - connect(signal_, SIGNAL(new_binary_data(unsigned int)), - this, SLOT(on_new_binary_data(unsigned int))); + connect(signal_, SIGNAL(new_binary_data(unsigned int, unsigned int)), + this, SLOT(on_new_binary_data(unsigned int, unsigned int))); + + update_data(); } void View::on_signal_name_changed(const QString &name) { - SignalBase *sb = qobject_cast(QObject::sender()); + (void)name; + + SignalBase* sb = qobject_cast(QObject::sender()); assert(sb); - int index = signal_selector_->findData(QVariant::fromValue(sb)); - if (index != -1) - signal_selector_->setItemText(index, name); + DecodeSignal* signal = dynamic_cast(sb); + assert(signal); + + // Update all decoder entries provided by this signal + auto stack = signal->decoder_stack(); + if (stack.size() > 1) { + for (const shared_ptr& dec : stack) { + QString title = QString("%1 (%2)").arg(signal->name(), dec->name()); + int index = decoder_selector_->findData(QVariant::fromValue((void*)dec.get())); + + if (index != -1) + decoder_selector_->setItemText(index, title); + } + } else + if (!stack.empty()) { + shared_ptr& dec = stack.at(0); + int index = decoder_selector_->findData(QVariant::fromValue((void*)dec.get())); + + if (index != -1) + decoder_selector_->setItemText(index, signal->name()); + } } -void View::on_new_binary_data(unsigned int segment_id) +void View::on_new_binary_data(unsigned int segment_id, unsigned int bin_class_id) { - if (segment_id == current_segment_) + if ((segment_id == current_segment_) && (bin_class_id == bin_class_id_)) update_data(); } +void View::on_decoder_stacked(void* decoder) +{ + // TODO This doesn't change existing entries for the same signal - but it should as the naming scheme may change + + Decoder* d = static_cast(decoder); + + // Find the signal that contains the selected decoder + DecodeSignal* signal = nullptr; + + for (const shared_ptr& ds : decode_signals_) + for (const shared_ptr& dec : ds->decoder_stack()) + if (d == dec.get()) + signal = ds.get(); + + assert(signal); + + // Add the decoder to the list + QString title = QString("%1 (%2)").arg(signal->name(), d->name()); + decoder_selector_->addItem(title, QVariant::fromValue((void*)d)); +} + +void View::on_decoder_removed(void* decoder) +{ + Decoder* d = static_cast(decoder); + + // Remove the decoder from the list + int index = decoder_selector_->findData(QVariant::fromValue((void*)d)); + + if (index != -1) + decoder_selector_->removeItem(index); +} + + } // namespace decoder_output } // namespace views } // namespace pv diff --git a/pv/views/decoder_output/view.hpp b/pv/views/decoder_output/view.hpp index 9f86cfae..4f4bc450 100644 --- a/pv/views/decoder_output/view.hpp +++ b/pv/views/decoder_output/view.hpp @@ -66,16 +66,21 @@ private: void update_data(); private Q_SLOTS: - void on_selected_signal_changed(int index); + void on_selected_decoder_changed(int index); void on_signal_name_changed(const QString &name); - void on_new_binary_data(unsigned int segment_id); + void on_new_binary_data(unsigned int segment_id, unsigned int bin_class_id); + + void on_decoder_stacked(void* decoder); + void on_decoder_removed(void* decoder); private: - QComboBox *signal_selector_, *format_selector_; + QComboBox *decoder_selector_, *format_selector_, *class_selector_; QStackedWidget *stacked_widget_; QHexView *hex_view_; data::DecodeSignal *signal_; + const data::decode::Decoder *decoder_; + uint8_t bin_class_id_; QByteArray *merged_data_; }; diff --git a/pv/views/trace/view.cpp b/pv/views/trace/view.cpp index a3861d1f..80322f9b 100644 --- a/pv/views/trace/view.cpp +++ b/pv/views/trace/view.cpp @@ -324,11 +324,14 @@ void View::add_signal(const shared_ptr signal) #ifdef ENABLE_DECODE void View::clear_decode_signals() { + ViewBase::clear_decode_signals(); decode_traces_.clear(); } void View::add_decode_signal(shared_ptr signal) { + ViewBase::add_decode_signal(signal); + shared_ptr d( new DecodeTrace(session_, signal, decode_traces_.size())); decode_traces_.push_back(d); @@ -348,6 +351,8 @@ void View::remove_decode_signal(shared_ptr signal) signals_changed(); return; } + + ViewBase::remove_decode_signal(signal); } #endif diff --git a/pv/views/viewbase.cpp b/pv/views/viewbase.cpp index 69be61c8..b35e27b9 100644 --- a/pv/views/viewbase.cpp +++ b/pv/views/viewbase.cpp @@ -112,16 +112,17 @@ void ViewBase::add_signalbase(const shared_ptr signalbase) #ifdef ENABLE_DECODE void ViewBase::clear_decode_signals() { + decode_signals_.clear(); } void ViewBase::add_decode_signal(shared_ptr signal) { - (void)signal; + decode_signals_.insert(signal); } void ViewBase::remove_decode_signal(shared_ptr signal) { - (void)signal; + decode_signals_.erase(signal); } #endif diff --git a/pv/views/viewbase.hpp b/pv/views/viewbase.hpp index 7f0a17fd..af885751 100644 --- a/pv/views/viewbase.hpp +++ b/pv/views/viewbase.hpp @@ -128,6 +128,9 @@ protected: util::TimeUnit time_unit_; unordered_set< shared_ptr > signalbases_; +#ifdef ENABLE_DECODE + unordered_set< shared_ptr > decode_signals_; +#endif /// The ID of the currently displayed segment uint32_t current_segment_;